r300: Moved the pipeline stages together for readability.
[mesa.git] / progs / xdemos / glxgears.c
index 8475cab07aff7d3d2947dceb34dc2b0aa5e8ae1a..75d63e51a2e4f640f08ec127f35c54b3efc47d2f 100644 (file)
  * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
  * Port by Brian Paul  23 March 2001
  *
- * Modified by Ian Romanick <idr@us.ibm.com> 09 April 2003 to support
- * GLX_{MESA,SGI}_swap_control and GLX_OML_sync_control.
- *
  * Command line options:
- *    -display       Name of the display to use.
- *    -info          print GL implementation information
- *    -swap N        Attempt to set the swap interval to 1/N second
- *    -forcegetrate  Get the display refresh rate even if the required GLX
- *                   extension is not supported.
+ *    -info      print GL implementation information
+ *    -stereo    use stereo enabled GLX visual
+ *
  */
 
 
 #include <string.h>
 #include <X11/Xlib.h>
 #include <X11/keysym.h>
-#ifndef __VMS
-# include <stdint.h>
-#endif
-# define GLX_GLXEXT_PROTOTYPES
 #include <GL/gl.h>
 #include <GL/glx.h>
 
-#ifndef GLX_MESA_swap_control
-typedef GLint ( * PFNGLXSWAPINTERVALMESAPROC) (unsigned interval);
-typedef GLint ( * PFNGLXGETSWAPINTERVALMESAPROC) ( void );
-#endif
-
-#if !defined( GLX_OML_sync_control ) && defined( _STDINT_H )
-#define GLX_OML_sync_control 1
-typedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
-#endif
 
 #define BENCHMARK
 
@@ -67,10 +49,8 @@ typedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, i
 #include <sys/time.h>
 #include <unistd.h>
 
-#define NUL '\0'
-
 /* return current time (in seconds) */
-static int
+static double
 current_time(void)
 {
    struct timeval tv;
@@ -80,16 +60,23 @@ current_time(void)
    struct timezone tz;
    (void) gettimeofday(&tv, &tz);
 #endif
-   return (int) tv.tv_sec;
+   return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
 }
 
 #else /*BENCHMARK*/
 
 /* dummy */
-static int
+static double
 current_time(void)
 {
-   return 0;
+   /* update this function for other platforms! */
+   static double t = 0.0;
+   static int warn = 1;
+   if (warn) {
+      fprintf(stderr, "Warning: current_time() not implemented!!\n");
+      warn = 0;
+   }
+   return t += 1.0;
 }
 
 #endif /*BENCHMARK*/
@@ -105,12 +92,12 @@ static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
 static GLint gear1, gear2, gear3;
 static GLfloat angle = 0.0;
 
-static GLboolean has_OML_sync_control = GL_FALSE;
-static GLboolean has_SGI_swap_control = GL_FALSE;
-static GLboolean has_MESA_swap_control = GL_FALSE;
+static GLboolean fullscreen = GL_FALSE;        /* Create a single fullscreen window */
+static GLboolean stereo = GL_FALSE;    /* Enable stereo.  */
+static GLfloat eyesep = 5.0;           /* Eye separation. */
+static GLfloat fix_point = 40.0;       /* Fixation point distance.  */
+static GLfloat left, right, asp;       /* Stereo frustum params.  */
 
-static char ** extension_table = NULL;
-static unsigned num_extensions;
 
 /*
  *
@@ -252,7 +239,7 @@ gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
 
 
 static void
-draw(void)
+do_draw(void)
 {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
@@ -282,21 +269,69 @@ draw(void)
    glPopMatrix();
 }
 
+static void
+draw(void)
+{
+   if (stereo) {
+      /* First left eye.  */
+      glDrawBuffer(GL_BACK_LEFT);
+
+      glMatrixMode(GL_PROJECTION);
+      glLoadIdentity();
+      glFrustum(left, right, -asp, asp, 5.0, 60.0);
+
+      glMatrixMode(GL_MODELVIEW);
+
+      glPushMatrix();
+      glTranslated(+0.5 * eyesep, 0.0, 0.0);
+      do_draw();
+      glPopMatrix();
+
+      /* Then right eye.  */
+      glDrawBuffer(GL_BACK_RIGHT);
+
+      glMatrixMode(GL_PROJECTION);
+      glLoadIdentity();
+      glFrustum(-right, -left, -asp, asp, 5.0, 60.0);
+
+      glMatrixMode(GL_MODELVIEW);
+
+      glPushMatrix();
+      glTranslated(-0.5 * eyesep, 0.0, 0.0);
+      do_draw();
+      glPopMatrix();
+   } else
+      do_draw();
+}
+
 
 /* new window size or exposure */
 static void
 reshape(int width, int height)
 {
-   GLfloat h = (GLfloat) height / (GLfloat) width;
-
    glViewport(0, 0, (GLint) width, (GLint) height);
-   glMatrixMode(GL_PROJECTION);
-   glLoadIdentity();
-   glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
+
+   if (stereo) {
+      GLfloat w;
+
+      asp = (GLfloat) height / (GLfloat) width;
+      w = fix_point * (1.0 / 5.0);
+
+      left = -5.0 * ((w - 0.5 * eyesep) / fix_point);
+      right = 5.0 * ((w + 0.5 * eyesep) / fix_point);
+   } else {
+      GLfloat h = (GLfloat) height / (GLfloat) width;
+
+      glMatrixMode(GL_PROJECTION);
+      glLoadIdentity();
+      glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
+   }
+   
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -40.0);
 }
+   
 
 
 static void
@@ -345,13 +380,21 @@ make_window( Display *dpy, const char *name,
              int x, int y, int width, int height,
              Window *winRet, GLXContext *ctxRet)
 {
-   int attrib[] = { GLX_RGBA,
-                   GLX_RED_SIZE, 1,
-                   GLX_GREEN_SIZE, 1,
-                   GLX_BLUE_SIZE, 1,
-                   GLX_DOUBLEBUFFER,
-                   GLX_DEPTH_SIZE, 1,
-                   None };
+   int attribs[] = { GLX_RGBA,
+                     GLX_RED_SIZE, 1,
+                     GLX_GREEN_SIZE, 1,
+                     GLX_BLUE_SIZE, 1,
+                     GLX_DOUBLEBUFFER,
+                     GLX_DEPTH_SIZE, 1,
+                     None };
+   int stereoAttribs[] = { GLX_RGBA,
+                           GLX_RED_SIZE, 1,
+                           GLX_GREEN_SIZE, 1,
+                           GLX_BLUE_SIZE, 1,
+                           GLX_DOUBLEBUFFER,
+                           GLX_DEPTH_SIZE, 1,
+                           GLX_STEREO,
+                           None };
    int scrnum;
    XSetWindowAttributes attr;
    unsigned long mask;
@@ -363,9 +406,22 @@ make_window( Display *dpy, const char *name,
    scrnum = DefaultScreen( dpy );
    root = RootWindow( dpy, scrnum );
 
-   visinfo = glXChooseVisual( dpy, scrnum, attrib );
+   if (fullscreen) {
+      x = 0; y = 0;
+      width = DisplayWidth( dpy, scrnum );
+      height = DisplayHeight( dpy, scrnum );
+   }
+
+   if (stereo)
+      visinfo = glXChooseVisual( dpy, scrnum, stereoAttribs );
+   else
+      visinfo = glXChooseVisual( dpy, scrnum, attribs );
    if (!visinfo) {
-      printf("Error: couldn't get an RGB, Double-buffered visual\n");
+      if (stereo) {
+         printf("Error: couldn't get an RGB, "
+                "Double-buffered, Stereo visual\n");
+      } else
+         printf("Error: couldn't get an RGB, Double-buffered visual\n");
       exit(1);
    }
 
@@ -374,7 +430,8 @@ make_window( Display *dpy, const char *name,
    attr.border_pixel = 0;
    attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
    attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
-   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+   attr.override_redirect = fullscreen;
+   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
 
    win = XCreateWindow( dpy, root, 0, 0, width, height,
                        0, visinfo->depth, InputOutput,
@@ -449,29 +506,33 @@ event_loop(Display *dpy, Window win)
          }
       }
 
-      /* next frame */
-      angle += 2.0;
-
-      draw();
-      glXSwapBuffers(dpy, win);
-
-      /* calc framerate */
       {
-         static int t0 = -1;
          static int frames = 0;
-         int t = current_time();
+         static double tRot0 = -1.0, tRate0 = -1.0;
+         double dt, t = current_time();
+         if (tRot0 < 0.0)
+            tRot0 = t;
+         dt = t - tRot0;
+         tRot0 = t;
+
+         /* advance rotation for next frame */
+         angle += 70.0 * dt;  /* 70 degrees per second */
+         if (angle > 3600.0)
+             angle -= 3600.0;
 
-         if (t0 < 0)
-            t0 = t;
+         draw();
+         glXSwapBuffers(dpy, win);
 
          frames++;
 
-         if (t - t0 >= 5.0) {
-            GLfloat seconds = t - t0;
+         if (tRate0 < 0.0)
+            tRate0 = t;
+         if (t - tRate0 >= 5.0) {
+            GLfloat seconds = t - tRate0;
             GLfloat fps = frames / seconds;
             printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
                    fps);
-            t0 = t;
+            tRate0 = t;
             frames = 0;
          }
       }
@@ -479,245 +540,79 @@ event_loop(Display *dpy, Window win)
 }
 
 
-/**
- * Display the refresh rate of the display using the GLX_OML_sync_control
- * extension.
- */
-
-static void
-show_refresh_rate( Display * dpy )
-{
-#ifdef GLX_OML_sync_control
-   PFNGLXGETMSCRATEOMLPROC  get_msc_rate;
-   int32_t  n;
-   int32_t  d;
-
-   get_msc_rate = (PFNGLXGETMSCRATEOMLPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetMscRateOML" );
-   if ( get_msc_rate != NULL ) {
-      (*get_msc_rate)( dpy, glXGetCurrentDrawable(), &n, &d );
-      printf( "refresh rate: %.1fHz\n", (float) n / d );
-      return;
-   }
-#endif
-   printf( "glXGetMscRateOML not supported.\n" );
-}
-
-
-/**
- * Fill in the table of extension strings from a supplied extensions string
- * (as returned by glXQueryExtensionsString).
- *
- * \param string   String of GLX extensions.
- * \sa is_extension_supported
- */
-
 static void
-make_extension_table( const char * string )
+usage(void)
 {
-   char ** string_tab;
-   unsigned  num_strings;
-   unsigned  base;
-   unsigned  idx;
-   unsigned  i;
-      
-   /* Count the number of spaces in the string.  That gives a base-line
-    * figure for the number of extension in the string.
-    */
-   
-   num_strings = 1;
-   for ( i = 0 ; string[i] != NUL ; i++ ) {
-      if ( string[i] == ' ' ) {
-        num_strings++;
-      }
-   }
-   
-   string_tab = (char **) malloc( sizeof( char * ) * num_strings );
-   if ( string_tab == NULL ) {
-      return;
-   }
-
-   base = 0;
-   idx = 0;
-
-   while ( string[ base ] != NUL ) {
-      /* Determine the length of the next extension string.
-       */
-
-      for ( i = 0 
-           ; (string[ base + i ] != NUL) && (string[ base + i ] != ' ')
-           ; i++ ) {
-        /* empty */ ;
-      }
-
-      if ( i > 0 ) {
-        /* If the string was non-zero length, add it to the table.  We
-         * can get zero length strings if there is a space at the end of
-         * the string or if there are two (or more) spaces next to each
-         * other in the string.
-         */
-
-        string_tab[ idx ] = malloc( sizeof( char ) * (i + 1) );
-        if ( string_tab[ idx ] == NULL ) {
-           return;
-        }
-
-        (void) memcpy( string_tab[ idx ], & string[ base ], i );
-        string_tab[ idx ][i] = NUL;
-        idx++;
-      }
-
-
-      /* Skip to the start of the next extension string.
-       */
-
-      for ( base += i
-           ; (string[ base ] == ' ') && (string[ base ] != NUL) 
-           ; base++ ) {
-        /* empty */ ;
-      }
-   }
-
-   extension_table = string_tab;
-   num_extensions = idx;
+   printf("Usage:\n");
+   printf("  -display <displayname>  set the display to run on\n");
+   printf("  -stereo                 run in stereo mode\n");
+   printf("  -fullscreen             run in fullscreen mode\n");
+   printf("  -info                   display OpenGL renderer info\n");
 }
-
-    
-/**
- * Determine of an extension is supported.  The extension string table
- * must have already be initialized by calling \c make_extension_table.
- * 
- * \praram ext  Extension to be tested.
- * \return GL_TRUE of the extension is supported, GL_FALSE otherwise.
- * \sa make_extension_table
- */
-
-static GLboolean
-is_extension_supported( const char * ext )
-{
-   unsigned   i;
-   
-   for ( i = 0 ; i < num_extensions ; i++ ) {
-      if ( strcmp( ext, extension_table[i] ) == 0 ) {
-        return GL_TRUE;
-      }
-   }
-   
-   return GL_FALSE;
-}
-
 
 int
 main(int argc, char *argv[])
 {
+   const int winWidth = 300, winHeight = 300;
    Display *dpy;
    Window win;
    GLXContext ctx;
-   char *dpyName = ":0";
-   int swap_interval = 1;
-   GLboolean do_swap_interval = GL_FALSE;
-   GLboolean force_get_rate = GL_FALSE;
+   char *dpyName = NULL;
    GLboolean printInfo = GL_FALSE;
    int i;
-   PFNGLXSWAPINTERVALMESAPROC set_swap_interval = NULL;
-   PFNGLXGETSWAPINTERVALMESAPROC get_swap_interval = NULL;
-
 
    for (i = 1; i < argc; i++) {
-      if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
+      if (strcmp(argv[i], "-display") == 0) {
          dpyName = argv[i+1];
          i++;
       }
       else if (strcmp(argv[i], "-info") == 0) {
          printInfo = GL_TRUE;
       }
-      else if (strcmp(argv[i], "-swap") == 0 && i + 1 < argc) {
-        swap_interval = atoi( argv[i+1] );
-        do_swap_interval = GL_TRUE;
-        i++;
+      else if (strcmp(argv[i], "-stereo") == 0) {
+         stereo = GL_TRUE;
       }
-      else if (strcmp(argv[i], "-forcegetrate") == 0) {
-        /* This option was put in because some DRI drivers don't support the
-         * full GLX_OML_sync_control extension, but they do support
-         * glXGetMscRateOML.
-         */
-        force_get_rate = GL_TRUE;
+      else if (strcmp(argv[i], "-fullscreen") == 0) {
+         fullscreen = GL_TRUE;
       }
-      else if (strcmp(argv[i], "-help") == 0) {
-         printf("Usage:\n");
-         printf("  gears [options]\n");
-         printf("Options:\n");
-         printf("  -help                   Print this information\n");
-         printf("  -display displayName    Specify X display\n");
-         printf("  -info                   Display GL information\n");
-         printf("  -swap N                 Swap no more than once per N vertical refreshes\n");
-         printf("  -forcegetrate           Try to use glXGetMscRateOML function\n");
-         return 0;
+      else {
+         usage();
+         return -1;
       }
    }
 
    dpy = XOpenDisplay(dpyName);
    if (!dpy) {
-      printf("Error: couldn't open display %s\n", dpyName);
+      printf("Error: couldn't open display %s\n",
+            dpyName ? dpyName : getenv("DISPLAY"));
       return -1;
    }
 
-   make_window(dpy, "glxgears", 0, 0, 300, 300, &win, &ctx);
+   make_window(dpy, "glxgears", 0, 0, winWidth, winHeight, &win, &ctx);
    XMapWindow(dpy, win);
    glXMakeCurrent(dpy, win, ctx);
 
-   make_extension_table( (char *) glXQueryExtensionsString(dpy,DefaultScreen(dpy)) );
-   has_OML_sync_control = is_extension_supported( "GLX_OML_sync_control" );
-   has_SGI_swap_control = is_extension_supported( "GLX_SGI_swap_control" );
-   has_MESA_swap_control = is_extension_supported( "GLX_MESA_swap_control" );
-
-   if ( has_MESA_swap_control ) {
-      set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalMESA" );
-      get_swap_interval = (PFNGLXGETSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetSwapIntervalMESA" );
-   }
-   else if ( has_SGI_swap_control ) {
-      set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalSGI" );
-   }
-
-
    if (printInfo) {
       printf("GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
       printf("GL_VERSION    = %s\n", (char *) glGetString(GL_VERSION));
       printf("GL_VENDOR     = %s\n", (char *) glGetString(GL_VENDOR));
       printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
-      if ( has_OML_sync_control || force_get_rate ) {
-        show_refresh_rate( dpy );
-      }
-
-      if ( get_swap_interval != NULL ) {
-        printf("Default swap interval = %d\n", (*get_swap_interval)() );
-      }
-   }
-
-   if ( do_swap_interval ) {
-      if ( set_swap_interval != NULL ) {
-        if ( ((swap_interval == 0) && !has_MESA_swap_control)
-             || (swap_interval < 0) ) {
-           printf( "Swap interval must be non-negative or greater than zero "
-                   "if GLX_MESA_swap_control is not supported.\n" );
-        }
-        else {
-           (*set_swap_interval)( swap_interval );
-        }
-
-        if ( printInfo && (get_swap_interval != NULL) ) {
-           printf("Current swap interval = %d\n", (*get_swap_interval)() );
-        }
-      }
-      else {
-        printf("Unable to set swap-interval.  Neither GLX_SGI_swap_control "
-               "nor GLX_MESA_swap_control are supported.\n" );
-      }
    }
 
    init();
 
+   /* Set initial projection/viewing transformation.
+    * We can't be sure we'll get a ConfigureNotify event when the window
+    * first appears.
+    */
+   reshape(winWidth, winHeight);
+
    event_loop(dpy, win);
 
+   glDeleteLists(gear1, 1);
+   glDeleteLists(gear2, 1);
+   glDeleteLists(gear3, 1);
    glXDestroyContext(dpy, ctx);
    XDestroyWindow(dpy, win);
    XCloseDisplay(dpy);