Merge branch 'nouveau-import'
[mesa.git] / src / glut / fbdev / gamemode.c
index 3407c6e98871019dc1734356926e253c54243df6..30be36af7af802f6f3a30831be9ee3e2e9cbd32b 100644 (file)
  * Written by Sean D'Epagnier (c) 2006
  */
 
-/* NOTICE: game mode will not be fully implemented until
-   glutReshapeWindow is fully implemented */
-
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include <linux/fb.h>
 
 
 #include "internal.h"
 
-void glutGameModeString(const char *string)
+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 1;
+      return GameMode;
    case GLUT_GAME_MODE_POSSIBLE:
-      return 1;
+      return ModePossible;
+   case GLUT_GAME_MODE_DISPLAY_CHANGED:
+      return DispChanged;
+   }
+
+   if(!ModePossible)
+      return -1;
+   
+   switch(mode) {
    case GLUT_GAME_MODE_WIDTH:
-      return VarInfo.xres;
+      return GameVarInfo.xres;
    case GLUT_GAME_MODE_HEIGHT:
-      return VarInfo.yres;
+      return GameVarInfo.yres;
    case GLUT_GAME_MODE_PIXEL_DEPTH:
-      return VarInfo.bits_per_pixel;
+      return GameVarInfo.bits_per_pixel;
    case GLUT_GAME_MODE_REFRESH_RATE:
-      if(VarInfo.pixclock) {
-        int htotal = VarInfo.left_margin + VarInfo.xres
-           + VarInfo.right_margin + VarInfo.hsync_len;
-        int vtotal = VarInfo.upper_margin + VarInfo.yres
-           + VarInfo.lower_margin + VarInfo.vsync_len;
-        return 1E12/VarInfo.pixclock/htotal/vtotal;
-      }
-      return 0;
-   case GLUT_GAME_MODE_DISPLAY_CHANGED:
-      return 0;
+      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);
    }
 }