From http://www.jwz.org/xscreensaver/xscreensaver-5.30.tar.gz
[xscreensaver] / hacks / glx / flipflop.c
index 1aadee77de347218b97282688a1375577650b5af..d780348c8c7bdba88417aa1e20984b612f815478 100644 (file)
@@ -1,4 +1,6 @@
 /* flipflop, Copyright (c) 2003 Kevin Ogden <kogden1@hotmail.com>
+ *                     (c) 2006 Sergio GutiĆ©rrez "Sergut" <sergut@gmail.com>
+ *                     (c) 2008 Andrew Galante <a.drew7@gmail.com>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
  * documentation.  No representations are made about the suitability of this
  * software for any purpose.  It is provided "as is" without express or
  * implied warranty.
+ *
+ *
+ * 2003 Kevin Odgen                  First version
+ * 2006 Sergio GutiĆ©rrez "Sergut"    Made several parameters dynamic and selectable
+ *                                   from the command line: size of the board, 
+ *                                   rotation speed and number of free squares; also
+ *                                   added the "sticks" mode.
+ * 2008 Andrew Galante               Added -textured option: textures the board with
+ *                                   an image which gets scrambled as the tiles move
+ *
  */
 
-#include <X11/Intrinsic.h>
+#define DEF_MODE  "tiles" /* Default mode (options: "tiles", "sticks") */
+#define DEF_SIZEX   "9"     /* Default width of the board */
+#define DEF_SIZEY   "9"     /* Default length of the board */
+
+#define DEF_BOARD_SIZE     "0"     /* "0" means "no value selected by user". It is changed */ 
+#define DEF_NUMSQUARES     "0"     /* in function init_flipflop() to its correct value (that */ 
+#define DEF_FREESQUARES    "0"     /* is a function of the size of the board and the mode)*/
+
+#define DEF_SPIN           "0.1"   /* Default angular velocity: PI/10 rads/s    */
 
-#include <math.h>
-#include <sys/time.h>
-#include <stdio.h>
-#include <stdlib.h>
+#define DEF_TEXTURED       "False" /* Default: do not grab an image for texturing */
 
-#define BOARDSIZE 9
-#define NUMSQUARES 76
-#define HALFTHICK 0.04
+#define DEF_STICK_THICK   54       /* Thickness for the sticks mode (over 100)  */
+#define DEF_STICK_RATIO   80       /* Ratio of sticks/total squares (over 100)  */
+#define DEF_TILE_THICK     4       /* Thickness for the tiles mode (over 100)   */
+#define DEF_TILE_RATIO    95       /* Ratio of tiles/total squares (over 100)   */
 
 #ifdef STANDALONE
-# define PROGCLASS        "Flipflop"
-# define HACK_INIT        init_flipflop
-# define HACK_DRAW        draw_flipflop
-# define HACK_RESHAPE     reshape_flipflop
-# define HACK_HANDLE_EVENT flipflop_handle_event
-# define EVENT_MASK       PointerMotionMask
-# define flipflop_opts  xlockmore_opts
-
-#define DEFAULTS       "*delay:       20000       \n" \
-                       "*showFPS:       False       \n" \
-                      "*wireframe:     False     \n"
+#define DEFAULTS       "*delay:     20000     \n" \
+                       "*showFPS:   False     \n" \
+                       "*wireframe: False     \n"
 
+# define refresh_flipflop 0
 # include "xlockmore.h"
 
 #else
 # include "xlock.h"
-#endif
+#endif /* STANDALONE */
 
 #ifdef USE_GL
 
-#include <GL/glu.h>
 #include "gltrackball.h"
 
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
 
 static XrmOptionDescRec opts[] = {
-  {"+rotate", ".flipflop.rotate", XrmoptionNoArg, "false" },
-  {"-rotate", ".flipflop.rotate", XrmoptionNoArg, "true" },
+    {"-sticks",         ".mode",            XrmoptionNoArg,  "sticks"},
+    {"-tiles",          ".mode",            XrmoptionNoArg,  "tiles" },
+    {"-mode",           ".mode",            XrmoptionSepArg, 0       },
+    {"-size",           ".size",            XrmoptionSepArg, 0       },
+    {"-size-x",         ".sizex",           XrmoptionSepArg, 0       },
+    {"-size-y",         ".sizey",           XrmoptionSepArg, 0       },
+    {"-count",          ".numsquares",      XrmoptionSepArg, 0       },
+    {"-free",           ".freesquares",     XrmoptionSepArg, 0       },
+    {"-spin",           ".spin",            XrmoptionSepArg, 0       },
+    {"-texture",        ".textured",        XrmoptionNoArg,  "True"  },
+    {"+texture",        ".textured",        XrmoptionNoArg,  "False" },
 };
 
-
-
-static int rotate, wire, clearbits;
+static int wire, clearbits;
+static int board_x_size, board_y_size, board_avg_size;
+static int numsquares, freesquares;
+static float half_thick;
+static float spin;
+static char* flipflopmode_str="tiles";
+static int textured;
 
 static argtype vars[] = {
-  { &rotate, "rotate", "Rotate", "True", t_Bool},
+    { &flipflopmode_str, "mode",        "Mode",     DEF_MODE,  t_String},
+    { &board_avg_size,   "size",        "Integer",  DEF_BOARD_SIZE,     t_Int},
+    { &board_x_size,     "sizex",       "Integer",  DEF_SIZEX,   t_Int},
+    { &board_y_size,     "sizey",       "Integer",  DEF_SIZEY,   t_Int},
+    { &numsquares,       "numsquares",  "Integer",  DEF_NUMSQUARES,     t_Int},
+    { &freesquares,      "freesquares", "Integer",  DEF_NUMSQUARES,     t_Int},
+    { &spin,             "spin",        "Float",    DEF_SPIN,           t_Float},
+    { &textured,         "textured",    "Bool",     DEF_TEXTURED,       t_Bool},
 };
 
-ModeSpecOpt flipflop_opts = {countof(opts), opts, countof(vars), vars, NULL};
+ENTRYPOINT ModeSpecOpt flipflop_opts = {countof(opts), opts, countof(vars), vars, NULL};
 
 #ifdef USE_MODULES
 ModStruct   flipflop_description =
-{"flipflop", "init_flipflop", "draw_flipflop", "release_flipflop",
- "draw_flipflop", "init_flipflop", NULL, &flipflop_opts,
- 1000, 1, 2, 1, 4, 1.0, "",
- "Flipflop", 0, NULL};
+    {"flipflop", "init_flipflop", "draw_flipflop", "release_flipflop",
    "draw_flipflop", "init_flipflop", NULL, &flipflop_opts,
    1000, 1, 2, 1, 4, 1.0, "",
    "Flipflop", 0, NULL};
 
-#endif
+#endif /* USE_MODULES */
 
 typedef struct {
-  GLXContext *glx_context;
-  Window window;
-  trackball_state *trackball;
-  Bool button_down_p;
-} Flipflopcreen;
+    /* array specifying which squares are where (to avoid collisions) */
+    /* -1 means empty otherwise integer represents square index 0 - n-1 */
+       /* occupied[x*board_y_size+y] is the tile [x][y] (i.e. that starts at column x and row y)*/
+    int *occupied; /* size: size_x * size_y */
+    /* an array of xpositions of the squares */
+    int *xpos; /* size: numsquares */
+    /* array of y positions of the squares */
+    int *ypos; /* size: numsquares */
+    /* integer representing the direction of movement of a square */
+    int *direction; /* 0 not, 1 x+, 2 y+, 3 x-, 4 y-*/ /* size: numsquares */
+    /* angle of moving square (during a flip) */
+    float *angle; /* size: numsquares */
+    /* array of colors for a square (RGB) */
+    /* eg. color[ 3*3 + 0 ] is the red   component of square 3 */
+    /* eg. color[ 4*3 + 1 ] is the green component of square 4 */
+    /* eg. color[ 5*3 + 2 ] is the blue  component of square 5 */
+    /*            ^-- n is the number of square */
+    float *color; /* size: numsquares * 3 */
+    /* array of texcoords for each square */
+    /* tex[ n*4 + 0 ] is x texture coordinate of square n's left side */
+    /* tex[ n*4 + 1 ] is y texture coordinate of square n's top side */
+    /* tex[ n*4 + 2 ] is x texture coordinate of square n's right side */
+    /* tex[ n*4 + 3 ] is y texture coordinate of square n's bottom side */
+    float *tex; /* size: numsquares * 4 */
+} randsheet;
 
-static Flipflopcreen *qs = NULL;
+typedef struct {
+    GLXContext *glx_context;
+    Window window;
+    trackball_state *trackball;
+    Bool button_down_p;
 
-typedef struct{
-  /* 2D array specifying which squares are where (to avoid collisions) */
-  /* -1 means empty otherwise integer represents square index 0 - n-1 */
-  int occupied[ BOARDSIZE ][ BOARDSIZE ];
-  /* an array of xpositions of the squares */
-  int xpos[ NUMSQUARES ];
-  /* array of y positions of the squares */
-  int ypos[ NUMSQUARES ];
-  /* integer representing the direction of movement of a square */
-  int direction[ NUMSQUARES ]; /* 0 not, 1 x+, 2 y+, 3 x-, 4 y-*/
-  /* angle of moving square (during a flip) */
-  float angle[ NUMSQUARES ];
-  /* array of colors for a square.  rgb */
-  /* eg. color[ 4 ][ 0 ] is the red component of square 4 */
-  /* eg. color[ 5 ][ 2 ] is the blue component of square 5  */
-  float color[ NUMSQUARES ][ 3 ];
-  /* n is the number of square */
-} randsheet;
+    randsheet *sheet;
 
+    float theta;      /* angle of rotation of the board                */
+    float flipspeed;  /* amount of flip;  1 is a entire flip           */
+    float reldist;    /* relative distace of camera from center        */
+    float energy;     /* likelyhood that a square will attempt to move */
 
-/*** ADDED RANDSHEET VARS ***/
+    /* texture rectangle */
+    float tex_x;
+    float tex_y;
+    float tex_width;
+    float tex_height;
 
-static randsheet MyRandSheet;
+    /* id of texture in use */
+    GLuint texid;
 
-static double theta = 0.0;
-/* amount which the square flips.  1 is a entire flip */
-static float flipspeed = 0.03;
-/* relative distace of camera from center */
-static float reldist = 1;
-/* likelehood a square will attempt a move */
-static float energy = 40;
+    Bool mipmap;
+    Bool got_texture;
 
+    GLfloat anisotropic;
 
+} Flipflopcreen;
+
+static Flipflopcreen *qs = NULL;
+
+#include "grab-ximage.h"
+
+static void randsheet_create( randsheet *rs );
 static void randsheet_initialize( randsheet *rs );
-static int randsheet_new_move( randsheet* rs );
-static int randsheet_new_move( randsheet* rs );
+static void randsheet_free( randsheet *rs );
+static int  randsheet_new_move( randsheet* rs );
 static void randsheet_move( randsheet *rs, float rot );
-static void randsheet_draw( randsheet *rs );
+static int randsheet_draw( randsheet *rs );
 static void setup_lights(void);
-static void drawBoard(void);
-static void display(Flipflopcreen *c);
-static void draw_sheet(void);
+static int drawBoard(Flipflopcreen *);
+static int display(Flipflopcreen *c);
+static int draw_sheet(float *tex);
 
 
 /* configure lighting */
 static void
 setup_lights(void)
 {
-/*   GLfloat position0[] = { BOARDSIZE*0.5, BOARDSIZE*0.1, BOARDSIZE*0.5, 1.0 }; */
+    /*   GLfloat position0[] = { board_avg_size*0.5, board_avg_size*0.1, board_avg_size*0.5, 1.0 }; */
 
-/*   GLfloat position0[] = { -BOARDSIZE*0.5, 0.2*BOARDSIZE, -BOARDSIZE*0.5, 1.0 }; */
-  GLfloat position0[] = { 0, BOARDSIZE*0.3, 0, 1.0 };
+    /*   GLfloat position0[] = { -board_avg_size*0.5, 0.2*board_avg_size, -board_avg_size*0.5, 1.0 }; */
+    GLfloat position0[4];
+    position0[0] = 0;
+    position0[1] = board_avg_size*0.3;
+    position0[2] = 0;
+    position0[3] = 1;
 
-  if (wire) return;
+    if (wire) return;
+
+    glEnable(GL_LIGHTING);
+    glLightfv(GL_LIGHT0, GL_POSITION, position0);
+    glEnable(GL_LIGHT0);
+}
 
-  glEnable(GL_LIGHTING);
-  glLightfv(GL_LIGHT0, GL_POSITION, position0);
-  glEnable(GL_LIGHT0);
- }
+static void get_texture(ModeInfo *);
 
-Bool
+
+ENTRYPOINT Bool
 flipflop_handle_event (ModeInfo *mi, XEvent *event)
 {
-  Flipflopcreen *c = &qs[MI_SCREEN(mi)];
+    Flipflopcreen *c = &qs[MI_SCREEN(mi)];
 
-  if (event->xany.type == ButtonPress &&
-      event->xbutton.button & Button1)
-    {
-      c->button_down_p = True;
-      gltrackball_start (c->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)
-    {
-      c->button_down_p = False;
-      return True;
-    }
-  else if (event->xany.type == MotionNotify &&
-           c->button_down_p)
+  if (gltrackball_event_handler (event, c->trackball,
+                                 MI_WIDTH (mi), MI_HEIGHT (mi),
+                                 &c->button_down_p))
+    return True;
+  else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
     {
-      gltrackball_track (c->trackball,
-                         event->xmotion.x, event->xmotion.y,
-                         MI_WIDTH (mi), MI_HEIGHT (mi));
-      return True;
+      if (!textured || c->got_texture)
+        {
+          textured = 1;
+          c->got_texture = False;
+          get_texture (mi);
+          return True;
+        }
     }
 
-  return False;
+    return False;
 }
 
 /* draw board */
-static void
-drawBoard(void)
+static int
+drawBoard(Flipflopcreen *c)
 {
-  int i;
-  for( i=0; i < (energy) ; i++ )
-    randsheet_new_move( &MyRandSheet );
-  randsheet_move( &MyRandSheet, flipspeed * 3.14159 );
-  randsheet_draw( &MyRandSheet );
+    int i;
+    for( i=0; i < (c->energy) ; i++ ) {
+        randsheet_new_move( c->sheet );
+       }
+    randsheet_move( c->sheet, c->flipspeed * 3.14159 );
+    return randsheet_draw( c->sheet );
 }
 
 
-static void
+static int
 display(Flipflopcreen *c)
 {
-   GLfloat amb[] = { 0.8, 0.8, 0.8, 1.0 };
+    GLfloat amb[] = { 0.8, 0.8, 0.8, 1.0 };
+    int polys = 0;
+
 
+    glClear(clearbits);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
 
- glClear(clearbits);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
+    glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.2);
+    glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.15/board_avg_size );
+    glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.15/board_avg_size );
+    glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
 
-  glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.2);
-  glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.15/BOARDSIZE );
-  glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.15/BOARDSIZE );
-   glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
 
+    glRotatef(current_device_rotation(), 0, 0, 1);
 
-  /** setup perspectif */
-  glTranslatef(0.0, 0.0, -reldist*BOARDSIZE);
-  glRotatef(22.5, 1.0, 0.0, 0.0);
-  gltrackball_rotate (c->trackball);
-  glRotatef(theta*100, 0.0, 1.0, 0.0);
-  glTranslatef(-0.5*BOARDSIZE, 0.0, -0.5*BOARDSIZE);
+    /** setup perspectif */
+    glTranslatef(0.0, 0.0, -c->reldist*board_avg_size);
+    glRotatef(22.5, 1.0, 0.0, 0.0);  
+    gltrackball_rotate (c->trackball);
+    glRotatef(c->theta*100, 0.0, 1.0, 0.0);
+    glTranslatef(-0.5*board_x_size, 0.0, -0.5*board_y_size); /* Center the board */
 
-  drawBoard();
+    /* set texture */
+    if(textured)
+      glBindTexture(GL_TEXTURE_2D, c->texid);
 
-  if (!c->button_down_p)
-    theta += .001;
+    polys = drawBoard(c);
 
+    if (!c->button_down_p) {
+        c->theta += .01 * spin;
+    }
+
+    return polys;
 }
 
-void
+ENTRYPOINT void
 reshape_flipflop(ModeInfo *mi, int width, int height)
 {
-  GLfloat h = (GLfloat) height / (GLfloat) width;
-  glViewport(0,0, width, height);
-  glMatrixMode(GL_PROJECTION);
-  glLoadIdentity();
-  gluPerspective(45, 1/h, 1.0, 300.0);
-  glMatrixMode(GL_MODELVIEW);
+    GLfloat h = (GLfloat) height / (GLfloat) width;
+    glViewport(0,0, width, height);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    gluPerspective(45, 1/h, 1.0, 300.0);
+    glMatrixMode(GL_MODELVIEW);
 }
 
-void
-init_flipflop(ModeInfo *mi)
+static void
+image_loaded_cb (const char *filename, XRectangle *geometry,
+                 int image_width, int image_height, 
+                 int texture_width, int texture_height,
+                 void *closure)
 {
-  int screen = MI_SCREEN(mi);
-  Flipflopcreen *c;
-  wire = MI_IS_WIREFRAME(mi);
-
-  if(!qs &&
-     !(qs = (Flipflopcreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Flipflopcreen))))
-    return;
-
-  c = &qs[screen];
-  c->window = MI_WINDOW(mi);
-  c->trackball = gltrackball_init ();
-
-  if((c->glx_context = init_GL(mi)))
-    reshape_flipflop(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
-  else
-    MI_CLEARWINDOW(mi);
+    Flipflopcreen *c = (Flipflopcreen *)closure;
+    int i, j;
+    int index = 0;
+    randsheet *rs = c->sheet;
+
+    c->tex_x = (float)geometry->x / (float)texture_width;
+    c->tex_y = (float)geometry->y / (float)texture_height;
+    c->tex_width = (float)geometry->width / (float)texture_width; 
+    c->tex_height = (float)geometry->height / (float)texture_height;
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+        (c->mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
+
+    if(c->anisotropic >= 1)
+        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, c->anisotropic);
+
+    glEnable(GL_TEXTURE_2D);
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    for(i = 0; i < board_x_size && index < numsquares; i++)
+        for(j = 0; j < board_y_size && index < numsquares; j++)
+        {
+            /* arrange squares to form loaded image */
+            rs->tex[ index*4 + 0 ] = c->tex_x + c->tex_width  / board_x_size * (i + 0);
+            rs->tex[ index*4 + 1 ] = c->tex_y + c->tex_height / board_y_size * (j + 1);
+            rs->tex[ index*4 + 2 ] = c->tex_x + c->tex_width  / board_x_size * (i + 1);
+            rs->tex[ index*4 + 3 ] = c->tex_y + c->tex_height / board_y_size * (j + 0);
+            rs->color[ index*3 + 0 ] = 1;
+            rs->color[ index*3 + 1 ] = 1;
+            rs->color[ index*3 + 2 ] = 1;
+            index++;
+        }
+
+    c->got_texture = True;
+}
 
-  glClearColor(0.0, 0.0, 0.0, 0.0);
+static void
+get_texture(ModeInfo *modeinfo)
+{
+    Flipflopcreen *c = &qs[MI_SCREEN(modeinfo)];
 
-  clearbits = GL_COLOR_BUFFER_BIT;
+    c->got_texture = False;
+    c->mipmap = True;
+    load_texture_async (modeinfo->xgwa.screen, modeinfo->window,
+                      *c->glx_context, 0, 0, c->mipmap, c->texid,
+                      image_loaded_cb, c);
+}
 
-  glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
-  glEnable(GL_COLOR_MATERIAL);
-  setup_lights();
+ENTRYPOINT void
+init_flipflop(ModeInfo *mi)
+{
+    int screen; 
+    Flipflopcreen *c;
 
-  glEnable(GL_DEPTH_TEST);
-  clearbits |= GL_DEPTH_BUFFER_BIT;
-  glEnable(GL_CULL_FACE);
-  glCullFace(GL_BACK);
-  randsheet_initialize( &MyRandSheet );
+    if (MI_IS_WIREFRAME(mi)) textured = 0;
 
+    /* Set all constants to their correct values */
+    if (board_avg_size != 0) {  /* general size specified by user */
+        board_x_size = board_avg_size;
+        board_y_size = board_avg_size;
+    } else {
+        board_avg_size = (board_x_size + board_y_size) / 2;
+    }
+    if ((numsquares == 0) && (freesquares != 0)) {
+        numsquares = board_x_size * board_y_size - freesquares; 
+    }
+    if (strcmp(flipflopmode_str, "tiles")) {
+      textured = 0;  /* textures look dumb in stick mode */
+        half_thick = 1.0 * DEF_STICK_THICK / 100.0; 
+        if (numsquares == 0) {  /* No value defined by user */
+            numsquares = board_x_size * board_y_size * DEF_STICK_RATIO / 100;
+        }
+    } else {
+        half_thick = 1.0 * DEF_TILE_THICK / 100.0; 
+        if (numsquares == 0) {  /* No value defined by user */
+            numsquares = board_x_size * board_y_size * DEF_TILE_RATIO/ 100;;
+        }
+    }
+    if (board_avg_size < 2) {
+        fprintf (stderr,"%s: the board must be at least 2x2.\n", progname);
+        exit(1);
+    }
+    if ((board_x_size < 1) || (board_y_size < 1) ||    (numsquares < 1)) {
+        fprintf (stderr,"%s: the number of elements ('-count') and the dimensions of the board ('-size-x', '-size-y') must be positive integers.\n", progname);
+        exit(1);
+    }
+    if (board_x_size * board_y_size <= numsquares) {
+        fprintf (stderr,"%s: the number of elements ('-count') that you specified is too big \n for the dimensions of the board ('-size-x', '-size-y'). Nothing will move.\n", progname);
+    }
 
+    screen = MI_SCREEN(mi);
+    wire = MI_IS_WIREFRAME(mi);
+
+    if(!qs &&
+       !(qs = (Flipflopcreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Flipflopcreen))))
+        return;
+
+    c = &qs[screen];
+    c->window = MI_WINDOW(mi);
+    c->trackball = gltrackball_init (False);
+
+    c->flipspeed = 0.03;
+    c->reldist = 1;
+    c->energy = 40;
+
+    if((c->glx_context = init_GL(mi)))
+        reshape_flipflop(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
+    else
+        MI_CLEARWINDOW(mi);
+
+       /* At this point, all the constants have already been set, */
+       /* so we can create the board */
+    c->sheet = (randsheet*) malloc(sizeof(randsheet)); 
+    randsheet_create( c->sheet ); 
+
+    clearbits = GL_COLOR_BUFFER_BIT;
+
+    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
+    glEnable(GL_COLOR_MATERIAL);
+    setup_lights();
+
+    glEnable(GL_DEPTH_TEST);
+    clearbits |= GL_DEPTH_BUFFER_BIT;
+    glEnable(GL_CULL_FACE);
+    glCullFace(GL_BACK);
+
+    randsheet_initialize( c->sheet );
+    if( textured ){
+        /* check for anisotropic filtering */
+        if(strstr((char *)glGetString(GL_EXTENSIONS),
+            "GL_EXT_texture_filter_anisotropic"))
+            glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &c->anisotropic);
+        else
+            c->anisotropic = 0;
+
+        /* allocate a new texture and get it */
+        glGenTextures(1, &c->texid);
+        get_texture(mi);
+    }
 }
 
-void
+ENTRYPOINT void
 draw_flipflop(ModeInfo *mi)
 {
-  Flipflopcreen *c = &qs[MI_SCREEN(mi)];
-  Window w = MI_WINDOW(mi);
-  Display *disp = MI_DISPLAY(mi);
+    Flipflopcreen *c = &qs[MI_SCREEN(mi)];
+    Window w = MI_WINDOW(mi);
+    Display *disp = MI_DISPLAY(mi);
 
-  if(!c->glx_context)
-    return;
+    if(!c->glx_context || (textured && !c->got_texture))
+        return;
 
-  glXMakeCurrent(disp, w, *(c->glx_context));
+    glXMakeCurrent(disp, w, *(c->glx_context));
 
-  display(c);
+    mi->polygon_count = display(c);
 
-  if(mi->fps_p){
-    do_fps(mi);
-  }
+    if(mi->fps_p){
+        do_fps(mi);
+    }
 
-  glFinish();
-  glXSwapBuffers(disp, w);
+    glFinish();
+    glXSwapBuffers(disp, w);
 
 
 }
 
-void
+ENTRYPOINT void
 release_flipflop(ModeInfo *mi)
 {
-  if(qs)
-    free((void *) qs);
+  if(qs) {
+    int screen;
+
+    for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
+    {
+      Flipflopcreen *c = &qs[MI_SCREEN(mi)];
+      if (c->glx_context)
+        c->glx_context = 0;
+      if (c->sheet) {
+        randsheet_free(c->sheet);
+        free (c->sheet);
+        c->sheet = 0;
+      }
+    }
+    free(qs);
+    qs = 0;
+  }
 
-  FreeAllGL(MI);
+  FreeAllGL(mi);
 }
 
 /*** ADDED RANDSHEET FUNCTIONS ***/
 
+static int
+draw_sheet(float *tex)
+{
+    int polys = 0;
+    glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
+
+    glNormal3f( 0, -1, 0 );
+    glTexCoord2f(tex[0], tex[3]);
+    glVertex3f( half_thick,  -half_thick,  half_thick );
+    glTexCoord2f(tex[2], tex[3]);
+    glVertex3f( 1-half_thick,   -half_thick, half_thick );
+    glTexCoord2f(tex[2], tex[1]);
+    glVertex3f( 1-half_thick, -half_thick,  1-half_thick);
+    glTexCoord2f(tex[0], tex[1]);
+    glVertex3f( half_thick, -half_thick, 1-half_thick );
+    polys++;
+
+    if (wire) { glEnd(); glBegin (GL_LINE_LOOP); }
+
+    /* back */
+    glNormal3f( 0, 1, 0 );
+    glTexCoord2f(tex[0], tex[1]);
+    glVertex3f( half_thick, half_thick, 1-half_thick );
+    glTexCoord2f(tex[2], tex[1]);
+    glVertex3f( 1-half_thick, half_thick,  1-half_thick);
+    glTexCoord2f(tex[2], tex[3]);
+    glVertex3f( 1-half_thick,   half_thick, half_thick );
+    glTexCoord2f(tex[0], tex[3]);
+    glVertex3f( half_thick,  half_thick,  half_thick );
+    polys++;
+
+    if (wire) { glEnd(); return polys; }
+
+    /* 4 edges!!! weee.... */
+    glNormal3f( 0, 0, -1 );
+    glTexCoord2f(tex[0], tex[3]);
+    glVertex3f( half_thick, half_thick, half_thick );
+    glTexCoord2f(tex[2], tex[3]);
+    glVertex3f( 1-half_thick, half_thick, half_thick );
+    glTexCoord2f(tex[2], tex[3]);
+    glVertex3f( 1-half_thick, -half_thick, half_thick );
+    glTexCoord2f(tex[0], tex[3]);
+    glVertex3f( half_thick, -half_thick, half_thick );
+    polys++;
+    glNormal3f( 0, 0, 1 );
+    glTexCoord2f(tex[0], tex[1]);
+    glVertex3f( half_thick, half_thick, 1-half_thick );
+    glTexCoord2f(tex[0], tex[1]);
+    glVertex3f( half_thick, -half_thick, 1-half_thick );
+    glTexCoord2f(tex[2], tex[1]);
+    glVertex3f( 1-half_thick, -half_thick, 1-half_thick );
+    glTexCoord2f(tex[2], tex[1]);
+    glVertex3f( 1-half_thick, half_thick, 1-half_thick );
+    polys++;
+    glNormal3f( 1, 0, 0 );
+    glTexCoord2f(tex[2], tex[1]);
+    glVertex3f( 1-half_thick, half_thick, 1-half_thick );
+    glTexCoord2f(tex[2], tex[1]);
+    glVertex3f( 1-half_thick, -half_thick, 1-half_thick );
+    glTexCoord2f(tex[2], tex[3]);
+    glVertex3f( 1-half_thick, -half_thick, half_thick );
+    glTexCoord2f(tex[2], tex[3]);
+    glVertex3f( 1-half_thick, half_thick, half_thick );
+    polys++;
+    glNormal3f( -1, 0, 0 );
+    glTexCoord2f(tex[0], tex[1]);
+    glVertex3f( half_thick, half_thick, 1-half_thick );
+    glTexCoord2f(tex[0], tex[3]);
+    glVertex3f( half_thick, half_thick, half_thick );
+    glTexCoord2f(tex[0], tex[3]);
+    glVertex3f( half_thick, -half_thick, half_thick );
+    glTexCoord2f(tex[0], tex[1]);
+    glVertex3f( half_thick, -half_thick, 1-half_thick );
+    polys++;
+    glEnd();
+
+    return polys;
+}
+
+/* Reserve memory for the randsheet */
+static void
+randsheet_create( randsheet *rs )
+{
+       rs -> occupied  = (int*) malloc(board_x_size*board_y_size * sizeof(int));
+       rs -> xpos      = (int*) malloc(numsquares * sizeof(int));
+       rs -> ypos      = (int*) malloc(numsquares * sizeof(int));
+       rs -> direction = (int*) malloc(numsquares * sizeof(int));
+       rs -> angle     = (float*) malloc(numsquares * sizeof(float));
+       rs -> color     = (float*) malloc(numsquares*3 * sizeof(float));
+       rs -> tex       = (float*) malloc(numsquares*4 * sizeof(float));
+}
+
+/* Free reserved memory for the randsheet */
 static void
-draw_sheet(void)
+randsheet_free( randsheet *rs )
 {
-  glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
-
-  glNormal3f( 0, -1, 0 );
-  glVertex3f( HALFTHICK,  -HALFTHICK,  HALFTHICK );
-  glVertex3f( 1-HALFTHICK,   -HALFTHICK, HALFTHICK );
-  glVertex3f( 1-HALFTHICK, -HALFTHICK,  1-HALFTHICK);
-  glVertex3f( HALFTHICK, -HALFTHICK, 1-HALFTHICK );
-
-  if (wire) { glEnd(); glBegin (GL_LINE_LOOP); }
-
-  /* back */
-  glNormal3f( 0, 1, 0 );
-  glVertex3f( HALFTHICK, HALFTHICK, 1-HALFTHICK );
-  glVertex3f( 1-HALFTHICK, HALFTHICK,  1-HALFTHICK);
-  glVertex3f( 1-HALFTHICK,   HALFTHICK, HALFTHICK );
-  glVertex3f( HALFTHICK,  HALFTHICK,  HALFTHICK );
-
-  if (wire) { glEnd(); return; }
-
-  /* 4 edges!!! weee.... */
-  glNormal3f( 0, 0, -1 );
-  glVertex3f( HALFTHICK, HALFTHICK, HALFTHICK );
-  glVertex3f( 1-HALFTHICK, HALFTHICK, HALFTHICK );
-  glVertex3f( 1-HALFTHICK, -HALFTHICK, HALFTHICK );
-  glVertex3f( HALFTHICK, -HALFTHICK, HALFTHICK );
-  glNormal3f( 0, 0, 1 );
-  glVertex3f( HALFTHICK, HALFTHICK, 1-HALFTHICK );
-  glVertex3f( HALFTHICK, -HALFTHICK, 1-HALFTHICK );
-  glVertex3f( 1-HALFTHICK, -HALFTHICK, 1-HALFTHICK );
-  glVertex3f( 1-HALFTHICK, HALFTHICK, 1-HALFTHICK );
-  glNormal3f( 1, 0, 0 );
-  glVertex3f( 1-HALFTHICK, HALFTHICK, 1-HALFTHICK );
-  glVertex3f( 1-HALFTHICK, -HALFTHICK, 1-HALFTHICK );
-  glVertex3f( 1-HALFTHICK, -HALFTHICK, HALFTHICK );
-  glVertex3f( 1-HALFTHICK, HALFTHICK, HALFTHICK );
-  glNormal3f( -1, 0, 0 );
-  glVertex3f( HALFTHICK, HALFTHICK, 1-HALFTHICK );
-  glVertex3f( HALFTHICK, HALFTHICK, HALFTHICK );
-  glVertex3f( HALFTHICK, -HALFTHICK, HALFTHICK );
-  glVertex3f( HALFTHICK, -HALFTHICK, 1-HALFTHICK );
-  glEnd();
+       free(rs->occupied);
+       free(rs->xpos);
+       free(rs->ypos);
+       free(rs->direction);
+       free(rs->angle);
+       free(rs->color);
+       free(rs->tex);
 }
 
 static void
 randsheet_initialize( randsheet *rs )
 {
-  int i, j, index;
-      index = 0;
-      /* put the moving sheets on the board */
-      for( i = 0; i < BOARDSIZE; i++ )
-       {
-         for( j = 0; j < BOARDSIZE; j++ )
-           {
-             /* initially fill up a corner with the moving squares */
-             if( index < NUMSQUARES )
-               {
-                 rs->occupied[ i ][ j ] = index;
-                 rs->xpos[ index ] = i;
-                 rs->ypos[ index ] = j;
-                 /* have the square colors start out as a pattern */
-                 rs->color[ index ][ 0 ] = ((i+j)%3 == 0)||((i+j+1)%3 == 0);
-                 rs->color[ index ][ 1 ] = ((i+j+1)%3 == 0);
-                 rs->color[ index ][ 2 ] = ((i+j+2)%3 == 0);
-                ++index;
-               }
-               /* leave everything else empty*/
-             else
-               {
-                 rs->occupied[ i ][ j ] = -1;
-               }
-           }
-       }
-       /* initially everything is at rest */
-      for( i=0; i<NUMSQUARES; i++ )
-       {
-         rs->direction[ i ] = 0;
-         rs->angle[ i ] = 0;
-       }
+    int i, j, index;
+    index = 0;
+    /* put the moving sheets on the board */
+    for( i = 0; i < board_x_size; i++ )
+        {
+            for( j = 0; j < board_y_size; j++ )
+                {
+                    /* initially fill up a corner with the moving squares */
+                    if( index < numsquares )
+                        {
+                            rs->occupied[ i * board_y_size + j ] = index;
+                            rs->xpos[ index ] = i;
+                            rs->ypos[ index ] = j;
+                                                       /* have the square colors start out as a pattern */
+                                                       rs->color[ index*3 + 0 ] = ((i+j)%3 == 0)||((i+j+1)%3 == 0);
+                                                       rs->color[ index*3 + 1 ] = ((i+j+1)%3 == 0);
+                                                       rs->color[ index*3 + 2 ] = ((i+j+2)%3 == 0);
+                            index++;
+                        }
+                    /* leave everything else empty*/
+                    else
+                        {
+                            rs->occupied[ i * board_y_size + j ] = -1;
+                        }
+                }
+        }
+    /* initially everything is at rest */
+    for( i=0; i<numsquares; i++ )
+        {
+            rs->direction[ i ] = 0;
+            rs->angle[ i ] = 0;
+        }
 }
 
 /* Pick and random square and direction and try to move it. */
@@ -389,80 +632,80 @@ randsheet_initialize( randsheet *rs )
 static int
 randsheet_new_move( randsheet* rs )
 {
-      int i, j;
-      int num, dir;
-      /* pick a random square */
-      num = random( ) % NUMSQUARES;
-      i = rs->xpos[ num ];
-      j = rs->ypos[ num ];
-      /* pick a random direction */
-      dir = ( random( )% 4 ) + 1;
-
-      if( rs->direction[ num ] == 0 )
-       {
-         switch( dir )
-           {
-           case 1:
-             /* move up in x */
-             if( ( i + 1 ) < BOARDSIZE )
-               {
-                 if( rs->occupied[ i + 1 ][ j ] == -1 )
-                   {
-                     rs->direction[ num ] = dir;
-                     rs->occupied[ i + 1 ][ j ] = num;
-                     rs->occupied[ i ][ j ] = -1;
-                     return 1;
-                   }
-               }
-             return 0;
-             break;
-           case 2:
-             /* move up in y */
-             if( ( j + 1 ) < BOARDSIZE )
-               {
-                 if( rs->occupied[ i ][ j + 1 ] == -1 )
-                   {
-                     rs->direction[ num ] = dir;
-                     rs->occupied[ i ][ j + 1 ] = num;
-                     rs->occupied[ i ][ j ] = -1;
-                     return 1;
-                   }
-               }
-             return 0;
-             break;
-           case 3:
-             /* move down in x */
-             if( ( i - 1 ) >= 0 )
-               {
-                 if( rs->occupied[ i - 1][ j ] == -1 )
-                   {
-                     rs->direction[ num ] = dir;
-                     rs->occupied[ i - 1][ j ] = num;
-                     rs->occupied[ i ][ j ] = -1;
-                     return 1;
-                   }
-               }
-             return 0;
-             break;
-           case 4:
-             /* move down in y */
-             if( ( j - 1 ) >= 0 )
-               {
-                 if( rs->occupied[ i ][ j - 1 ] == -1 )
-                   {
-                     rs->direction[ num ] = dir;
-                     rs->occupied[ i ][ j - 1 ] = num;
-                     rs->occupied[ i ][ j ] = -1;
-                     return 1;
-                   }
-               }
-             return 0;
-             break;
-           default:
-             break;
-           }
-       }
-      return 0;
+    int i, j;
+    int num, dir;
+    /* pick a random square */
+    num = random( ) % numsquares;
+    i = rs->xpos[ num ];
+    j = rs->ypos[ num ];
+    /* pick a random direction */
+    dir = ( random( )% 4 ) + 1;
+
+    if( rs->direction[ num ] == 0 )
+        {
+            switch( dir )
+                {
+                case 1:
+                    /* move up in x */
+                    if( ( i + 1 ) < board_x_size )
+                        {
+                            if( rs->occupied[ (i + 1) * board_y_size + j ] == -1 )
+                                {
+                                    rs->direction[ num ] = dir;
+                                    rs->occupied[ (i + 1) * board_y_size + j ] = num;
+                                    rs->occupied[ i * board_y_size + j ] = -1;
+                                    return 1;
+                                }
+                        }
+                    return 0;
+                    break;
+                case 2:
+                    /* move up in y */
+                    if( ( j + 1 ) < board_y_size )
+                        {
+                            if( rs->occupied[ i * board_y_size + (j + 1) ] == -1 )
+                                {
+                                    rs->direction[ num ] = dir;
+                                    rs->occupied[ i * board_y_size + (j + 1) ] = num;
+                                    rs->occupied[ i * board_y_size + j ] = -1;
+                                    return 1;
+                                }
+                        }
+                    return 0;
+                    break;
+                case 3:
+                    /* move down in x */
+                    if( ( i - 1 ) >= 0 )
+                        {
+                            if( rs->occupied[ (i - 1) * board_y_size + j ] == -1 )
+                                {
+                                    rs->direction[ num ] = dir;
+                                    rs->occupied[ (i - 1) * board_y_size + j ] = num;
+                                    rs->occupied[ i * board_y_size + j ] = -1;
+                                    return 1;
+                                }
+                        }
+                    return 0;
+                    break;
+                case 4:
+                    /* move down in y */
+                    if( ( j - 1 ) >= 0 )
+                        {
+                            if( rs->occupied[ i * board_y_size + (j - 1) ] == -1 )
+                                {
+                                    rs->direction[ num ] = dir;
+                                    rs->occupied[ i * board_y_size + (j - 1) ] = num;
+                                    rs->occupied[ i * board_y_size + j ] = -1;
+                                    return 1;
+                                }
+                        }
+                    return 0;
+                    break;
+                default:
+                    break;
+                }
+        }
+    return 0;
 }
 
 /*   move a single frame.  */
@@ -470,119 +713,146 @@ randsheet_new_move( randsheet* rs )
 static void
 randsheet_move( randsheet *rs, float rot )
 {
-      int i, j, index;
-      for( index = 0 ; index < NUMSQUARES; index++ )
-       {
-         i = rs->xpos[ index ];
-         j = rs->ypos[ index ];
-         switch( rs->direction[ index ] )
-           {
-           case 0:
-             /* not moving */
-             break;
-           case 1:
-           /* move up in x */
-             rs->angle[ index ] += rot;
-             /* check to see if we have finished moving */
-             if( rs->angle[ index ] >= M_PI  )
-               {
-                 rs->xpos[ index ] += 1;
-                 rs->direction[ index ] = 0;
-                 rs->angle[ index ] = 0;
-               }
-             break;
-           case 2:
-           /* move up in y */
-             rs->angle[ index ] += rot;
-             /* check to see if we have finished moving */
-             if( rs->angle[ index ] >= M_PI  )
-               {
-                 rs->ypos[ index ] += 1;
-                 rs->direction[ index ] = 0;
-                 rs->angle[ index ] = 0;
-               }
-             break;
-           case 3:
-           /* down in x */
-             rs->angle[ index ] += rot;
-             /* check to see if we have finished moving */
-             if( rs->angle[ index ] >= M_PI  )
-               {
-                 rs->xpos[ index ] -= 1;
-                 rs->direction[ index ] = 0;
-                 rs->angle[ index ] = 0;
-               }
-             break;
-           case 4:
-           /* up in x */
-             rs->angle[ index ] += rot;
-             /* check to see if we have finished moving */
-             if( rs->angle[ index ] >= M_PI  )
-               {
-                 rs->ypos[ index ] -= 1;
-                 rs->direction[ index ] = 0;
-                 rs->angle[ index ] = 0;
-               }
-             break;
-           default:
-             break;
-           }
-       }
+    int index;
+    float tmp;
+    for( index = 0 ; index < numsquares; index++ )
+        {
+            switch( rs->direction[ index ] )
+                {
+                case 0:
+                    /* not moving */
+                    break;
+                case 1:
+                    /* move up in x */
+                    if( textured && rs->angle[ index ] == 0 )
+                        {
+                            tmp = rs->tex[ index * 4 + 0 ];
+                            rs->tex[ index * 4 + 0 ] = rs->tex[ index * 4 + 2 ];
+                            rs->tex[ index * 4 + 2 ] = tmp;
+                        }
+                    rs->angle[ index ] += rot;
+                    /* check to see if we have finished moving */
+                    if( rs->angle[ index ] >= M_PI  )
+                        {
+                            rs->xpos[ index ] += 1;
+                            rs->direction[ index ] = 0;
+                            rs->angle[ index ] = 0;
+                        }
+                    break;
+                case 2:
+                    /* move up in y */
+                    if( textured && rs->angle[ index ] == 0 )
+                        {
+                            tmp = rs->tex[ index * 4 + 1 ];
+                            rs->tex[ index * 4 + 1 ] = rs->tex[ index * 4 + 3 ];
+                            rs->tex[ index * 4 + 3 ] = tmp;
+                        }
+                    rs->angle[ index ] += rot;
+                    /* check to see if we have finished moving */
+                    if( rs->angle[ index ] >= M_PI  )
+                        {
+                            rs->ypos[ index ] += 1;
+                            rs->direction[ index ] = 0;
+                            rs->angle[ index ] = 0;
+                        }
+                    break;
+                case 3:
+                    /* down in x */
+                    rs->angle[ index ] += rot;
+                    /* check to see if we have finished moving */
+                    if( rs->angle[ index ] >= M_PI  )
+                        {
+                            rs->xpos[ index ] -= 1;
+                            rs->direction[ index ] = 0;
+                            rs->angle[ index ] = 0;
+                            if( textured )
+                            {
+                                                           tmp = rs->tex[ index * 4 + 0 ];
+                                                           rs->tex[ index * 4 + 0 ] = rs->tex[ index * 4 + 2 ];
+                                                           rs->tex[ index * 4 + 2 ] = tmp;
+                            }
+                        }
+                    break;
+                case 4:
+                    /* down in y */
+                    rs->angle[ index ] += rot;
+                    /* check to see if we have finished moving */
+                    if( rs->angle[ index ] >= M_PI  )
+                        {
+                            rs->ypos[ index ] -= 1;
+                            rs->direction[ index ] = 0;
+                            rs->angle[ index ] = 0;
+                            if( textured )
+                            {
+                                tmp = rs->tex[ index * 4 + 1 ];
+                                rs->tex[ index * 4 + 1 ] = rs->tex[ index * 4 + 3 ];
+                                rs->tex[ index * 4 + 3 ] = tmp;
+                            }
+                        }
+                    break;
+                default:
+                    break;
+                }
+        }
 }
 
 
-    /* draw all the moving squares  */
-static void
+/* draw all the moving squares  */
+static int
 randsheet_draw( randsheet *rs )
 {
-      int i, j;
-      int index;
-      /* for all moving squares ... */
-      for( index = 0; index < NUMSQUARES; index++ )
-       {
-         /* set color */
-         glColor3f( rs->color[ index ][ 0 ],
-                    rs->color[ index ][ 1 ],
-                    rs->color[ index ][ 2 ] );
-                    /* find x and y position */
-         i = rs->xpos[ index ];
-         j = rs->ypos[ index ];
-         glPushMatrix();
-         switch( rs->direction[ index ] )
-           {
-           case 0:
-
-           /* not moving */
-             /* front */
-             glTranslatef( i, 0, j );
-             break;
-           case 1:
-             glTranslatef( i+1, 0, j );
-             glRotatef( 180 - rs->angle[ index ]*180/M_PI, 0, 0, 1 );
-
-             break;
-           case 2:
-             glTranslatef( i, 0, j+1 );
-             glRotatef( 180 - rs->angle[ index ]*180/M_PI, -1, 0, 0 );
-
-             break;
-           case 3:
-             glTranslatef( i, 0, j );
-             glRotatef( rs->angle[ index ]*180/M_PI, 0, 0, 1 );
-             break;
-           case 4:
-             glTranslatef( i, 0, j );
-             glRotatef( rs->angle[ index ]*180/M_PI, -1, 0, 0 );
-             break;
-           default:
-             break;
-           }
-         draw_sheet();
-         glPopMatrix();
-
-       }
+    int i, j, polys = 0;
+    int index;
+
+    /* for all moving squares ... */
+    for( index = 0; index < numsquares; index++ )
+        {
+            /* set color */
+            glColor3f( rs->color[ index*3 + 0 ],
+                       rs->color[ index*3 + 1 ],
+                       rs->color[ index*3 + 2 ] );
+            /* find x and y position */
+            i = rs->xpos[ index ];
+            j = rs->ypos[ index ];
+            glPushMatrix();
+            switch( rs->direction[ index ] )
+                {
+                case 0:
+
+                    /* not moving */
+                    /* front */
+                    glTranslatef( i, 0, j );
+                    break;
+                case 1:
+                    glTranslatef( i+1, 0, j );
+                    glRotatef( 180 - rs->angle[ index ]*180/M_PI, 0, 0, 1 );
+
+                    break;
+                case 2:
+                    glTranslatef( i, 0, j+1 );
+                    glRotatef( 180 - rs->angle[ index ]*180/M_PI, -1, 0, 0 );
+
+                    break;
+                case 3:
+                    glTranslatef( i, 0, j );
+                    glRotatef( rs->angle[ index ]*180/M_PI, 0, 0, 1 );
+                    break;
+                case 4:
+                    glTranslatef( i, 0, j );
+                    glRotatef( rs->angle[ index ]*180/M_PI, -1, 0, 0 );
+                    break;
+                default:
+                    break;
+                }
+            polys += draw_sheet( rs->tex + index*4 );
+            glPopMatrix();
+
+        }
+    return polys;
 }
 
-/**** END RANDSHEET FUNCTIONS ***/
+/**** END RANDSHEET_BAK FUNCTIONS ***/
+
+XSCREENSAVER_MODULE ("FlipFlop", flipflop)
 
-#endif
+#endif /* USE_GL */