http://ftp.ksu.edu.tw/FTP/FreeBSD/distfiles/xscreensaver-4.20.tar.gz
[xscreensaver] / hacks / glx / boing.c
diff --git a/hacks/glx/boing.c b/hacks/glx/boing.c
new file mode 100644 (file)
index 0000000..b315a64
--- /dev/null
@@ -0,0 +1,674 @@
+/* boing, Copyright (c) 2005 Jamie Zawinski <jwz@jwz.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ *
+ * A clone of the Amiga 1000 "Boing" demo.  This was the first graphics demo
+ * for the Amiga, written by Dale Luck and RJ Mical during a break at the 1984
+ * Consumer Electronics Show (or so the legend goes.)  The boing ball was
+ * briefly the official logo of Amiga Inc., until they were bought by
+ * Commodore later that year.
+ *
+ * With no arguments, this program looks a lot like the original Amiga demo.
+ * With "-smooth -lighting", it looks... less old.
+ *
+ * The amiga version made noise when the ball hit the walls.  This version
+ * does not, obviously.
+ */
+
+#include <X11/Intrinsic.h>
+
+extern XtAppContext app;
+
+#define PROGCLASS      "Boing"
+#define HACK_INIT      init_boing
+#define HACK_DRAW      draw_boing
+#define HACK_RESHAPE   reshape_boing
+#define HACK_HANDLE_EVENT boing_handle_event
+#define EVENT_MASK      PointerMotionMask
+#define sws_opts       xlockmore_opts
+
+#define DEF_SPIN        "True"
+#define DEF_LIGHTING    "False"
+#define DEF_SMOOTH      "False"
+#define DEF_SCANLINES   "False"
+#define DEF_SPEED       "1.0"
+#define DEF_SIZE        "0.5"
+#define DEF_ANGLE       "15"
+#define DEF_MERIDIANS   "16"
+#define DEF_PARALLELS   "8"
+#define DEF_TILES       "12"
+#define DEF_THICKNESS   "0.05"
+
+#define DEF_BALL_COLOR1  "#CC1919"
+#define DEF_BALL_COLOR2  "#F2F2F2"
+#define DEF_GRID_COLOR   "#991999"
+#define DEF_SHADOW_COLOR "#303030"
+#define DEF_BACKGROUND   "#8C8C8C"
+
+#define DEFAULTS       "*delay:        30000            \n" \
+                       "*showFPS:      False            \n" \
+                       "*wireframe:    False            \n" \
+                       "*spin:       " DEF_SPIN        "\n" \
+                       "*lighting:   " DEF_LIGHTING    "\n" \
+                       "*smooth:     " DEF_SMOOTH      "\n" \
+                       "*scanlines:  " DEF_SCANLINES   "\n" \
+                       "*speed:      " DEF_SPEED       "\n" \
+                       "*angle:      " DEF_ANGLE       "\n" \
+                       "*ballSize:   " DEF_SIZE        "\n" \
+                       "*meridians:  " DEF_MERIDIANS   "\n" \
+                       "*parallels:  " DEF_PARALLELS   "\n" \
+                       "*tiles:      " DEF_TILES       "\n" \
+                       "*thickness:  " DEF_THICKNESS   "\n" \
+                       "*ballColor1: " DEF_BALL_COLOR1 "\n" \
+                       "*ballColor2: " DEF_BALL_COLOR2 "\n" \
+                       "*gridColor:  " DEF_GRID_COLOR  "\n" \
+                       "*shadowColor:" DEF_SHADOW_COLOR"\n" \
+                       ".background: " DEF_BACKGROUND  "\n" \
+
+#undef countof
+#define countof(x) (sizeof((x))/sizeof((*x)))
+
+#include "xlockmore.h"
+#include "gltrackball.h"
+#include <ctype.h>
+
+#ifdef USE_GL /* whole file */
+
+#include <GL/glu.h>
+
+typedef struct { GLfloat x, y, z; } XYZ;
+
+typedef struct {
+  GLXContext *glx_context;
+  trackball_state *trackball;
+  Bool button_down_p;
+
+  GLuint ball_list;
+  double ball_x,   ball_y,   ball_z,   ball_th;
+  double ball_dx,  ball_dy,  ball_dz,  ball_dth;
+  double ball_ddx, ball_ddy, ball_ddz;
+
+  GLfloat ball_color1[4], ball_color2[4], grid_color[4];
+  GLfloat bg_color[4], shadow_color[4];
+  GLfloat lightpos[4];
+
+} boing_configuration;
+
+static boing_configuration *bps = NULL;
+
+static Bool spin;
+static Bool lighting_p;
+static Bool smooth_p;
+static Bool scanlines_p;
+static GLfloat speed;
+static int angle;
+static GLfloat ball_size;
+static unsigned int meridians;
+static unsigned int parallels;
+static unsigned int tiles;
+static GLfloat thickness;
+static char *ball_color1_str, *ball_color2_str, *grid_color_str,
+  *shadow_str, *bg_str;
+
+static XrmOptionDescRec opts[] = {
+  { "-spin",       ".spin",      XrmoptionNoArg,  "True"  },
+  { "+spin",       ".spin",      XrmoptionNoArg,  "False" },
+  { "-lighting",   ".lighting",  XrmoptionNoArg,  "True"  },
+  { "+lighting",   ".lighting",  XrmoptionNoArg,  "False" },
+  { "-smooth",     ".smooth",    XrmoptionNoArg,  "True"  },
+  { "+smooth",     ".smooth",    XrmoptionNoArg,  "False" },
+  { "-scanlines",  ".scanlines", XrmoptionNoArg,  "True"  },
+  { "+scanlines",  ".scanlines", XrmoptionNoArg,  "False" },
+  { "-speed",      ".speed",     XrmoptionSepArg, 0 },
+  { "-angle",      ".angle",     XrmoptionSepArg, 0 },
+  { "-size",       ".ballSize",  XrmoptionSepArg, 0 },
+  { "-meridians",  ".meridians", XrmoptionSepArg, 0 },
+  { "-parallels",  ".parallels", XrmoptionSepArg, 0 },
+  { "-tiles",      ".tiles",     XrmoptionSepArg, 0 },
+  { "-thickness",  ".thickness", XrmoptionSepArg, 0 },
+  { "-ball-color1",".ballColor1",XrmoptionSepArg, 0 },
+  { "-ball-color2",".ballColor2",XrmoptionSepArg, 0 },
+  { "-grid-color", ".gridColor", XrmoptionSepArg, 0 },
+  { "-shadow-color",".shadowColor",XrmoptionSepArg, 0 },
+};
+
+static argtype vars[] = {
+  {&spin,      "spin",      "Spin",       DEF_SPIN,      t_Bool},
+  {&lighting_p,"lighting",  "Lighting",   DEF_LIGHTING,  t_Bool},
+  {&smooth_p,  "smooth",    "Smooth",     DEF_SMOOTH,    t_Bool},
+  {&scanlines_p,"scanlines","Scanlines",  DEF_SCANLINES, t_Bool},
+  {&speed,     "speed",     "Speed",      DEF_SPEED,     t_Float},
+  {&angle,     "angle",     "Angle",      DEF_ANGLE,     t_Int},
+  {&ball_size, "ballSize",  "BallSize",   DEF_SIZE,      t_Float},
+  {&meridians, "meridians", "meridians",  DEF_MERIDIANS, t_Int},
+  {&parallels, "parallels", "parallels",  DEF_PARALLELS, t_Int},
+  {&tiles,     "tiles",     "Tiles",      DEF_TILES,     t_Int},
+  {&thickness, "thickness", "Thickness",  DEF_THICKNESS, t_Float},
+  {&ball_color1_str, "ballColor1", "BallColor1", DEF_BALL_COLOR1, t_String},
+  {&ball_color2_str, "ballColor2", "BallColor2", DEF_BALL_COLOR2, t_String},
+  {&grid_color_str,  "gridColor",  "GridColor",  DEF_GRID_COLOR,  t_String},
+  {&shadow_str,      "shadowColor","ShadowColor",DEF_SHADOW_COLOR,t_String},
+  {&bg_str,          "background", "Background", DEF_BACKGROUND,  t_String},
+};
+
+ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
+
+static void
+parse_color (ModeInfo *mi, const char *name, const char *s, GLfloat *a)
+{
+  XColor c;
+  a[3] = 1.0;  /* alpha */
+
+  if (! XParseColor (MI_DISPLAY(mi), MI_COLORMAP(mi), s, &c))
+    {
+      fprintf (stderr, "%s: can't parse %s color %s", progname, name, s);
+      exit (1);
+    }
+  a[0] = c.red   / 65536.0;
+  a[1] = c.green / 65536.0;
+  a[2] = c.blue  / 65536.0;
+}
+
+
+static void
+draw_grid (ModeInfo *mi)
+{
+  boing_configuration *bp = &bps[MI_SCREEN(mi)];
+  int x, y;
+  GLfloat t2  = (GLfloat) tiles / 2;
+  GLfloat s = 1.0 / (tiles + thickness);
+  GLfloat z = 0;
+
+  GLfloat lw = MI_HEIGHT(mi) * 0.06 * thickness;
+
+  glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, bp->grid_color);
+  glColor3fv (bp->grid_color);
+
+  glPushMatrix();
+  glScalef(s, s, s);
+  glTranslatef (-t2, -t2, 0);
+
+  glLineWidth (lw);
+  glBegin (GL_LINES);
+  for (y = 0; y <= tiles; y++)
+    {
+      glVertex3f (0,     y, z);
+      glVertex3f (tiles, y, z);
+      /*mi->polygon_count++;*/
+    }
+  for (x = 0; x <= tiles; x++)
+    {
+      glVertex3f (x, tiles, z);
+      glVertex3f (x, 0,     z);
+      /*mi->polygon_count++;*/
+    }
+
+  glEnd();
+  glPopMatrix();
+}
+
+
+static void
+draw_box (ModeInfo *mi)
+{
+  /* boing_configuration *bp = &bps[MI_SCREEN(mi)]; */
+  glPushMatrix();
+  glTranslatef (0, 0, -0.5);
+  glFrontFace (GL_CCW);
+  draw_grid (mi);
+  glPopMatrix();
+
+  glPushMatrix();
+  glRotatef (90, 1, 0, 0);
+  glTranslatef (0, 0, 0.5);
+  glFrontFace (GL_CW);
+  draw_grid (mi);
+  glPopMatrix();
+}
+
+
+static void
+draw_ball (ModeInfo *mi)
+{
+  boing_configuration *bp = &bps[MI_SCREEN(mi)];
+  int wire = MI_IS_WIREFRAME(mi);
+  int x, y;
+  int xx = meridians;
+  int yy = parallels;
+  int scale = (smooth_p ? 5 : 1);
+
+  if (lighting_p && !wire)
+    glEnable (GL_LIGHTING);
+
+  if (parallels < 3)
+    scale *= 2;
+
+  xx *= scale;
+  yy *= scale;
+
+  glFrontFace (GL_CW);
+
+  glPushMatrix();
+  glTranslatef (bp->ball_x, bp->ball_y, bp->ball_z);
+  glScalef (ball_size, ball_size, ball_size);
+  glRotatef (-angle,      0, 0, 1);
+  glRotatef (bp->ball_th, 0, 1, 0);
+
+  for (y = 0; y < yy; y++)
+    {
+      GLfloat thy0 = y     * (M_PI * 2) / (yy * 2) + M_PI_2;
+      GLfloat thy1 = (y+1) * (M_PI * 2) / (yy * 2) + M_PI_2;
+
+      for (x = 0; x < xx; x++)
+        {
+          GLfloat thx0 = x     * (M_PI * 2) / xx;
+          GLfloat thx1 = (x+1) * (M_PI * 2) / xx;
+          XYZ p;
+          Bool bgp = ((x/scale) & 1) ^ ((y/scale) & 1);
+
+          if (wire && bgp) continue;
+
+          glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
+                        (bgp ? bp->ball_color2 : bp->ball_color1));
+          glColor3fv (bgp ? bp->ball_color2 : bp->ball_color1);
+
+          glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
+
+          if (!smooth_p)
+            {
+              p.x = cos((thy0+thy1)/2) * cos((thx0+thx1)/2);
+              p.y = sin((thy0+thy1)/2);
+              p.z = cos((thy0+thy1)/2) * sin((thx0+thx1)/2);
+              glNormal3f (-p.x, -p.y, -p.z);
+            }
+
+          p.x = cos(thy0) * cos(thx0) / 2;
+          p.y = sin(thy0)             / 2;
+          p.z = cos(thy0) * sin(thx0) / 2;
+          if (smooth_p)
+            glNormal3f (-p.x, -p.y, -p.z);
+          glVertex3f (p.x, p.y, p.z);
+
+          p.x = cos(thy1) * cos(thx0) / 2;
+          p.y = sin(thy1)             / 2;
+          p.z = cos(thy1) * sin(thx0) / 2;
+          if (smooth_p)
+            glNormal3f (-p.x, -p.y, -p.z);
+          glVertex3f (p.x, p.y, p.z);
+
+          p.x = cos(thy1) * cos(thx1) / 2;
+          p.y = sin(thy1)             / 2;
+          p.z = cos(thy1) * sin(thx1) / 2;
+          if (smooth_p)
+            glNormal3f (-p.x, -p.y, -p.z);
+          glVertex3f (p.x, p.y, p.z);
+
+          p.x = cos(thy0) * cos(thx1) / 2;
+          p.y = sin(thy0)             / 2;
+          p.z = cos(thy0) * sin(thx1) / 2;
+          if (smooth_p)
+            glNormal3f (-p.x, -p.y, -p.z);
+          glVertex3f (p.x, p.y, p.z);
+
+          glEnd ();
+          mi->polygon_count++;
+        }
+    }
+
+  glPopMatrix();
+
+  if (lighting_p && !wire)
+    glDisable(GL_LIGHTING);
+}
+
+
+static void
+draw_shadow (ModeInfo *mi)
+{
+  boing_configuration *bp = &bps[MI_SCREEN(mi)];
+  int wire = MI_IS_WIREFRAME(mi);
+  GLfloat xoff = 0.14;
+  GLfloat yoff = 0.07;
+  int y;
+  int yy = parallels;
+  int scale = (smooth_p ? 5 : 1);
+
+  if (lighting_p && !wire)
+    glEnable (GL_BLEND);
+
+  if (parallels < 3)
+    scale *= 2;
+
+  yy *= scale;
+
+  glPushMatrix();
+  glTranslatef (bp->ball_x + xoff, bp->ball_y + yoff, -0.49);
+  glScalef (ball_size, ball_size, ball_size);
+  glRotatef (-angle, 0, 0, 1);
+
+  glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, bp->shadow_color);
+  glColor4fv (bp->shadow_color);
+
+  glFrontFace (GL_CCW);
+  glNormal3f (0, 0, 1);
+  glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLE_FAN);
+  if (!wire) glVertex3f (0, 0, 0);
+
+  for (y = 0; y < yy*2+1; y++)
+    {
+      GLfloat thy0 = y * (M_PI * 2) / (yy * 2) + M_PI_2;
+      glVertex3f (cos(thy0) / 2, sin(thy0) / 2, 0);
+      mi->polygon_count++;
+    }
+
+  glEnd ();
+
+  glPopMatrix();
+
+  if (lighting_p && !wire)
+    glDisable (GL_BLEND);
+}
+
+
+static void
+draw_scanlines (ModeInfo *mi)
+{
+  /* boing_configuration *bp = &bps[MI_SCREEN(mi)]; */
+  int wire = MI_IS_WIREFRAME(mi);
+  int w = MI_WIDTH(mi);
+  int h = MI_HEIGHT(mi);
+
+  if (h <= 300) return;
+
+  if (!wire)
+    {
+      glEnable (GL_BLEND);
+      glDisable (GL_DEPTH_TEST);
+    }
+
+  glMatrixMode(GL_PROJECTION);
+  glPushMatrix();
+  {
+    glLoadIdentity();
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    {
+      int lh, ls;
+      int y;
+      glLoadIdentity();
+      gluOrtho2D (0, w, 0, h);
+
+      if      (h > 500) lh = 4, ls = 4;
+      else if (h > 300) lh = 2, ls = 1;
+      else              lh = 1, ls = 1;
+
+      if (lh == 1)
+        glDisable (GL_BLEND);
+
+      glLineWidth (lh);
+      glColor4f (0, 0, 0, 0.3);
+
+      glBegin(GL_LINES);
+      for (y = 0; y < h; y += lh + ls)
+        {
+          glVertex3f (0, y, 0);
+          glVertex3f (w, y, 0);
+        }
+      glEnd();
+    }
+    glPopMatrix();
+  }
+  glMatrixMode(GL_PROJECTION);
+  glPopMatrix();
+  glMatrixMode(GL_MODELVIEW);
+
+  if (!wire)
+    {
+      glDisable (GL_BLEND);
+      glEnable (GL_DEPTH_TEST);
+    }
+}
+
+
+
+static void
+tick_physics (ModeInfo *mi)
+{
+  boing_configuration *bp = &bps[MI_SCREEN(mi)];
+  GLfloat s2 = ball_size / 2;
+  GLfloat max = 0.5 - s2;
+  GLfloat min = -max;
+
+  bp->ball_th += bp->ball_dth;
+  while (bp->ball_th > 360) bp->ball_th -= 360;
+  while (bp->ball_th < 0)   bp->ball_th += 360;
+
+  bp->ball_dx += bp->ball_ddx;
+  bp->ball_x  += bp->ball_dx;
+  if      (bp->ball_x < min) bp->ball_x = min, bp->ball_dx = -bp->ball_dx,
+    bp->ball_dth = -bp->ball_dth,
+    bp->ball_dx += (frand(speed/2) - speed);
+  else if (bp->ball_x > max) bp->ball_x = max, bp->ball_dx = -bp->ball_dx,
+    bp->ball_dth = -bp->ball_dth,
+    bp->ball_dx += (frand(speed/2) - speed);
+
+  bp->ball_dy += bp->ball_ddy;
+  bp->ball_y  += bp->ball_dy;
+  if      (bp->ball_y < min) bp->ball_y = min, bp->ball_dy = -bp->ball_dy;
+  else if (bp->ball_y > max) bp->ball_y = max, bp->ball_dy = -bp->ball_dy;
+
+  bp->ball_dz += bp->ball_ddz;
+  bp->ball_z  += bp->ball_dz;
+  if      (bp->ball_z < min) bp->ball_z = min, bp->ball_dz = -bp->ball_dz;
+  else if (bp->ball_z > max) bp->ball_z = max, bp->ball_dz = -bp->ball_dz;
+}
+
+
+
+/* Window management, etc
+ */
+void
+reshape_boing (ModeInfo *mi, int width, int height)
+{
+  GLfloat h = (GLfloat) height / (GLfloat) width;
+
+  h *= 4.0 / 3.0;   /* Back in the caveman days we couldn't even afford
+                       square pixels! */
+
+  glViewport (0, 0, (GLint) width, (GLint) height);
+
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  gluPerspective (8.0, 1/h, 1.0, 10.0);
+
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+  gluLookAt (0.0, 0.0, 8.0,
+             0.0, 0.0, 0.0,
+             0.0, 1.0, 0.0);
+
+  glClear(GL_COLOR_BUFFER_BIT);
+}
+
+
+Bool
+boing_handle_event (ModeInfo *mi, XEvent *event)
+{
+  boing_configuration *bp = &bps[MI_SCREEN(mi)];
+
+  if (event->xany.type == ButtonPress &&
+      event->xbutton.button == Button1)
+    {
+      bp->button_down_p = True;
+      gltrackball_start (bp->trackball,
+                         event->xbutton.x, event->xbutton.y,
+                         MI_WIDTH (mi), MI_HEIGHT (mi));
+      return True;
+    }
+  else if (event->xany.type == ButtonRelease &&
+           event->xbutton.button == Button1)
+    {
+      bp->button_down_p = False;
+      return True;
+    }
+  else if (event->xany.type == ButtonPress &&
+           (event->xbutton.button == Button4 ||
+            event->xbutton.button == Button5))
+    {
+      gltrackball_mousewheel (bp->trackball, event->xbutton.button, 10,
+                              !!event->xbutton.state);
+      return True;
+    }
+  else if (event->xany.type == MotionNotify &&
+           bp->button_down_p)
+    {
+      gltrackball_track (bp->trackball,
+                         event->xmotion.x, event->xmotion.y,
+                         MI_WIDTH (mi), MI_HEIGHT (mi));
+      return True;
+    }
+
+  return False;
+}
+
+
+void 
+init_boing (ModeInfo *mi)
+{
+  boing_configuration *bp;
+  int wire = MI_IS_WIREFRAME(mi);
+
+  if (!bps) {
+    bps = (boing_configuration *)
+      calloc (MI_NUM_SCREENS(mi), sizeof (boing_configuration));
+    if (!bps) {
+      fprintf(stderr, "%s: out of memory\n", progname);
+      exit(1);
+    }
+
+    bp = &bps[MI_SCREEN(mi)];
+  }
+
+  bp = &bps[MI_SCREEN(mi)];
+
+  bp->glx_context = init_GL(mi);
+
+  if (tiles < 1) tiles = 1;
+
+  if (smooth_p)
+    {
+      if (meridians < 1) meridians = 1;
+      if (parallels < 1) parallels = 1;
+    }
+  else
+    {
+      if (meridians < 3) meridians = 3;
+      if (parallels < 2) parallels = 2;
+    }
+
+  if (meridians > 1 && meridians & 1) meridians++;  /* odd numbers look bad */
+
+
+  if (thickness <= 0) thickness = 0.001;
+  else if (thickness > 1) thickness = 1;
+
+  reshape_boing (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
+
+  parse_color (mi, "ballColor1",  ball_color1_str,  bp->ball_color1);
+  parse_color (mi, "ballColor2",  ball_color2_str,  bp->ball_color2);
+  parse_color (mi, "gridColor",   grid_color_str,   bp->grid_color);
+  parse_color (mi, "shadowColor", shadow_str,       bp->shadow_color);
+  parse_color (mi, "background",  bg_str,           bp->bg_color);
+
+  bp->shadow_color[3] = 0.9;
+
+  glClearColor (bp->bg_color[0], bp->bg_color[1], bp->bg_color[2], 1);
+
+  if (!wire)
+    {
+      glEnable(GL_DEPTH_TEST);
+      glEnable(GL_CULL_FACE);
+    }
+
+  bp->lightpos[0] = 0.5;
+  bp->lightpos[1] = 0.5;
+  bp->lightpos[2] = -1;
+  bp->lightpos[3] = 0;
+
+  if (lighting_p && !wire)
+    {
+      GLfloat amb[4] = {0, 0, 0, 1};
+      GLfloat dif[4] = {1, 1, 1, 1};
+      GLfloat spc[4] = {1, 1, 1, 1};
+      glEnable(GL_LIGHT0);
+      glLightfv(GL_LIGHT0, GL_AMBIENT,  amb);
+      glLightfv(GL_LIGHT0, GL_DIFFUSE,  dif);
+      glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
+    }
+
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  speed = speed / 800.0;
+
+  bp->ball_dth = (spin ? -speed * 7 * 360 : 0);
+
+  bp->ball_x   = 0.5 - ((ball_size/2) + frand(1-ball_size));
+  bp->ball_y   = 0.2;
+  bp->ball_dx  = speed * 6 + frand(speed);
+  bp->ball_ddy = -speed;
+
+  bp->ball_dz  = speed * 6 + frand(speed);
+
+  bp->trackball = gltrackball_init ();
+}
+
+
+void
+draw_boing (ModeInfo *mi)
+{
+  boing_configuration *bp = &bps[MI_SCREEN(mi)];
+  Display *dpy = MI_DISPLAY(mi);
+  Window window = MI_WINDOW(mi);
+
+  if (!bp->glx_context)
+    return;
+
+  mi->polygon_count = 0;
+
+  glShadeModel(GL_SMOOTH);
+
+  glEnable(GL_NORMALIZE);
+  glEnable(GL_CULL_FACE);
+  glEnable (GL_DEPTH_TEST);
+
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  if (! bp->button_down_p)
+    tick_physics (mi);
+
+  glPushMatrix ();
+  gltrackball_rotate (bp->trackball);
+
+  glLightfv (GL_LIGHT0, GL_POSITION, bp->lightpos);
+
+  draw_box (mi);
+  draw_shadow (mi);
+  draw_ball (mi);
+  if (scanlines_p)
+    draw_scanlines (mi);
+
+  glPopMatrix ();
+
+  if (mi->fps_p) do_fps (mi);
+  glFinish();
+
+  glXSwapBuffers(dpy, window);
+}
+
+#endif /* USE_GL */