From http://www.jwz.org/xscreensaver/xscreensaver-5.30.tar.gz
[xscreensaver] / hacks / glx / flipflop.c
1 /* flipflop, Copyright (c) 2003 Kevin Ogden <kogden1@hotmail.com>
2  *                     (c) 2006 Sergio GutiĆ©rrez "Sergut" <sergut@gmail.com>
3  *                     (c) 2008 Andrew Galante <a.drew7@gmail.com>
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation.  No representations are made about the suitability of this
10  * software for any purpose.  It is provided "as is" without express or
11  * implied warranty.
12  *
13  *
14  * 2003 Kevin Odgen                  First version
15  * 2006 Sergio GutiĆ©rrez "Sergut"    Made several parameters dynamic and selectable
16  *                                   from the command line: size of the board, 
17  *                                   rotation speed and number of free squares; also
18  *                                   added the "sticks" mode.
19  * 2008 Andrew Galante               Added -textured option: textures the board with
20  *                                   an image which gets scrambled as the tiles move
21  *
22  */
23
24 #define DEF_MODE  "tiles" /* Default mode (options: "tiles", "sticks") */
25 #define DEF_SIZEX   "9"     /* Default width of the board */
26 #define DEF_SIZEY   "9"     /* Default length of the board */
27
28 #define DEF_BOARD_SIZE     "0"     /* "0" means "no value selected by user". It is changed */ 
29 #define DEF_NUMSQUARES     "0"     /* in function init_flipflop() to its correct value (that */ 
30 #define DEF_FREESQUARES    "0"     /* is a function of the size of the board and the mode)*/
31
32 #define DEF_SPIN           "0.1"   /* Default angular velocity: PI/10 rads/s    */
33
34 #define DEF_TEXTURED       "False" /* Default: do not grab an image for texturing */
35
36 #define DEF_STICK_THICK   54       /* Thickness for the sticks mode (over 100)  */
37 #define DEF_STICK_RATIO   80       /* Ratio of sticks/total squares (over 100)  */
38 #define DEF_TILE_THICK     4       /* Thickness for the tiles mode (over 100)   */
39 #define DEF_TILE_RATIO    95       /* Ratio of tiles/total squares (over 100)   */
40
41 #ifdef STANDALONE
42 #define DEFAULTS       "*delay:     20000     \n" \
43                        "*showFPS:   False     \n" \
44                        "*wireframe: False     \n"
45
46 # define refresh_flipflop 0
47 # include "xlockmore.h"
48
49 #else
50 # include "xlock.h"
51 #endif /* STANDALONE */
52
53 #ifdef USE_GL
54
55 #include "gltrackball.h"
56
57 #undef countof
58 #define countof(x) (sizeof((x))/sizeof((*x)))
59
60 static XrmOptionDescRec opts[] = {
61     {"-sticks",         ".mode",            XrmoptionNoArg,  "sticks"},
62     {"-tiles",          ".mode",            XrmoptionNoArg,  "tiles" },
63     {"-mode",           ".mode",            XrmoptionSepArg, 0       },
64     {"-size",           ".size",            XrmoptionSepArg, 0       },
65     {"-size-x",         ".sizex",           XrmoptionSepArg, 0       },
66     {"-size-y",         ".sizey",           XrmoptionSepArg, 0       },
67     {"-count",          ".numsquares",      XrmoptionSepArg, 0       },
68     {"-free",           ".freesquares",     XrmoptionSepArg, 0       },
69     {"-spin",           ".spin",            XrmoptionSepArg, 0       },
70     {"-texture",        ".textured",        XrmoptionNoArg,  "True"  },
71     {"+texture",        ".textured",        XrmoptionNoArg,  "False" },
72 };
73
74 static int wire, clearbits;
75 static int board_x_size, board_y_size, board_avg_size;
76 static int numsquares, freesquares;
77 static float half_thick;
78 static float spin;
79 static char* flipflopmode_str="tiles";
80 static int textured;
81
82 static argtype vars[] = {
83     { &flipflopmode_str, "mode",        "Mode",     DEF_MODE,  t_String},
84     { &board_avg_size,   "size",        "Integer",  DEF_BOARD_SIZE,     t_Int},
85     { &board_x_size,     "sizex",       "Integer",  DEF_SIZEX,   t_Int},
86     { &board_y_size,     "sizey",       "Integer",  DEF_SIZEY,   t_Int},
87     { &numsquares,       "numsquares",  "Integer",  DEF_NUMSQUARES,     t_Int},
88     { &freesquares,      "freesquares", "Integer",  DEF_NUMSQUARES,     t_Int},
89     { &spin,             "spin",        "Float",    DEF_SPIN,           t_Float},
90     { &textured,         "textured",    "Bool",     DEF_TEXTURED,       t_Bool},
91 };
92
93 ENTRYPOINT ModeSpecOpt flipflop_opts = {countof(opts), opts, countof(vars), vars, NULL};
94
95 #ifdef USE_MODULES
96 ModStruct   flipflop_description =
97     {"flipflop", "init_flipflop", "draw_flipflop", "release_flipflop",
98      "draw_flipflop", "init_flipflop", NULL, &flipflop_opts,
99      1000, 1, 2, 1, 4, 1.0, "",
100      "Flipflop", 0, NULL};
101
102 #endif /* USE_MODULES */
103
104 typedef struct {
105     /* array specifying which squares are where (to avoid collisions) */
106     /* -1 means empty otherwise integer represents square index 0 - n-1 */
107         /* occupied[x*board_y_size+y] is the tile [x][y] (i.e. that starts at column x and row y)*/
108     int *occupied; /* size: size_x * size_y */
109     /* an array of xpositions of the squares */
110     int *xpos; /* size: numsquares */
111     /* array of y positions of the squares */
112     int *ypos; /* size: numsquares */
113     /* integer representing the direction of movement of a square */
114     int *direction; /* 0 not, 1 x+, 2 y+, 3 x-, 4 y-*/ /* size: numsquares */
115     /* angle of moving square (during a flip) */
116     float *angle; /* size: numsquares */
117     /* array of colors for a square (RGB) */
118     /* eg. color[ 3*3 + 0 ] is the red   component of square 3 */
119     /* eg. color[ 4*3 + 1 ] is the green component of square 4 */
120     /* eg. color[ 5*3 + 2 ] is the blue  component of square 5 */
121     /*            ^-- n is the number of square */
122     float *color; /* size: numsquares * 3 */
123     /* array of texcoords for each square */
124     /* tex[ n*4 + 0 ] is x texture coordinate of square n's left side */
125     /* tex[ n*4 + 1 ] is y texture coordinate of square n's top side */
126     /* tex[ n*4 + 2 ] is x texture coordinate of square n's right side */
127     /* tex[ n*4 + 3 ] is y texture coordinate of square n's bottom side */
128     float *tex; /* size: numsquares * 4 */
129 } randsheet;
130
131 typedef struct {
132     GLXContext *glx_context;
133     Window window;
134     trackball_state *trackball;
135     Bool button_down_p;
136
137     randsheet *sheet;
138
139     float theta;      /* angle of rotation of the board                */
140     float flipspeed;  /* amount of flip;  1 is a entire flip           */
141     float reldist;    /* relative distace of camera from center        */
142     float energy;     /* likelyhood that a square will attempt to move */
143
144     /* texture rectangle */
145     float tex_x;
146     float tex_y;
147     float tex_width;
148     float tex_height;
149
150     /* id of texture in use */
151     GLuint texid;
152
153     Bool mipmap;
154     Bool got_texture;
155
156     GLfloat anisotropic;
157
158 } Flipflopcreen;
159
160 static Flipflopcreen *qs = NULL;
161
162 #include "grab-ximage.h"
163
164 static void randsheet_create( randsheet *rs );
165 static void randsheet_initialize( randsheet *rs );
166 static void randsheet_free( randsheet *rs );
167 static int  randsheet_new_move( randsheet* rs );
168 static void randsheet_move( randsheet *rs, float rot );
169 static int randsheet_draw( randsheet *rs );
170 static void setup_lights(void);
171 static int drawBoard(Flipflopcreen *);
172 static int display(Flipflopcreen *c);
173 static int draw_sheet(float *tex);
174
175
176 /* configure lighting */
177 static void
178 setup_lights(void)
179 {
180     /*   GLfloat position0[] = { board_avg_size*0.5, board_avg_size*0.1, board_avg_size*0.5, 1.0 }; */
181
182     /*   GLfloat position0[] = { -board_avg_size*0.5, 0.2*board_avg_size, -board_avg_size*0.5, 1.0 }; */
183     GLfloat position0[4];
184     position0[0] = 0;
185     position0[1] = board_avg_size*0.3;
186     position0[2] = 0;
187     position0[3] = 1;
188
189     if (wire) return;
190
191     glEnable(GL_LIGHTING);
192     glLightfv(GL_LIGHT0, GL_POSITION, position0);
193     glEnable(GL_LIGHT0);
194 }
195
196 static void get_texture(ModeInfo *);
197
198
199 ENTRYPOINT Bool
200 flipflop_handle_event (ModeInfo *mi, XEvent *event)
201 {
202     Flipflopcreen *c = &qs[MI_SCREEN(mi)];
203
204   if (gltrackball_event_handler (event, c->trackball,
205                                  MI_WIDTH (mi), MI_HEIGHT (mi),
206                                  &c->button_down_p))
207     return True;
208   else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
209     {
210       if (!textured || c->got_texture)
211         {
212           textured = 1;
213           c->got_texture = False;
214           get_texture (mi);
215           return True;
216         }
217     }
218
219     return False;
220 }
221
222 /* draw board */
223 static int
224 drawBoard(Flipflopcreen *c)
225 {
226     int i;
227     for( i=0; i < (c->energy) ; i++ ) {
228         randsheet_new_move( c->sheet );
229         }
230     randsheet_move( c->sheet, c->flipspeed * 3.14159 );
231     return randsheet_draw( c->sheet );
232 }
233
234
235 static int
236 display(Flipflopcreen *c)
237 {
238     GLfloat amb[] = { 0.8, 0.8, 0.8, 1.0 };
239     int polys = 0;
240
241
242     glClear(clearbits);
243     glMatrixMode(GL_MODELVIEW);
244     glLoadIdentity();
245
246     glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.2);
247     glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.15/board_avg_size );
248     glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.15/board_avg_size );
249     glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
250
251
252     glRotatef(current_device_rotation(), 0, 0, 1);
253
254     /** setup perspectif */
255     glTranslatef(0.0, 0.0, -c->reldist*board_avg_size);
256     glRotatef(22.5, 1.0, 0.0, 0.0);  
257     gltrackball_rotate (c->trackball);
258     glRotatef(c->theta*100, 0.0, 1.0, 0.0);
259     glTranslatef(-0.5*board_x_size, 0.0, -0.5*board_y_size); /* Center the board */
260
261     /* set texture */
262     if(textured)
263       glBindTexture(GL_TEXTURE_2D, c->texid);
264
265     polys = drawBoard(c);
266
267     if (!c->button_down_p) {
268         c->theta += .01 * spin;
269     }
270
271     return polys;
272 }
273
274 ENTRYPOINT void
275 reshape_flipflop(ModeInfo *mi, int width, int height)
276 {
277     GLfloat h = (GLfloat) height / (GLfloat) width;
278     glViewport(0,0, width, height);
279     glMatrixMode(GL_PROJECTION);
280     glLoadIdentity();
281     gluPerspective(45, 1/h, 1.0, 300.0);
282     glMatrixMode(GL_MODELVIEW);
283 }
284
285 static void
286 image_loaded_cb (const char *filename, XRectangle *geometry,
287                  int image_width, int image_height, 
288                  int texture_width, int texture_height,
289                  void *closure)
290 {
291     Flipflopcreen *c = (Flipflopcreen *)closure;
292     int i, j;
293     int index = 0;
294     randsheet *rs = c->sheet;
295
296     c->tex_x = (float)geometry->x / (float)texture_width;
297     c->tex_y = (float)geometry->y / (float)texture_height;
298     c->tex_width = (float)geometry->width / (float)texture_width; 
299     c->tex_height = (float)geometry->height / (float)texture_height;
300
301     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
302     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
303         (c->mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
304
305     if(c->anisotropic >= 1)
306         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, c->anisotropic);
307
308     glEnable(GL_TEXTURE_2D);
309     glEnable(GL_BLEND);
310     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
311
312     for(i = 0; i < board_x_size && index < numsquares; i++)
313         for(j = 0; j < board_y_size && index < numsquares; j++)
314         {
315             /* arrange squares to form loaded image */
316             rs->tex[ index*4 + 0 ] = c->tex_x + c->tex_width  / board_x_size * (i + 0);
317             rs->tex[ index*4 + 1 ] = c->tex_y + c->tex_height / board_y_size * (j + 1);
318             rs->tex[ index*4 + 2 ] = c->tex_x + c->tex_width  / board_x_size * (i + 1);
319             rs->tex[ index*4 + 3 ] = c->tex_y + c->tex_height / board_y_size * (j + 0);
320             rs->color[ index*3 + 0 ] = 1;
321             rs->color[ index*3 + 1 ] = 1;
322             rs->color[ index*3 + 2 ] = 1;
323             index++;
324         }
325
326     c->got_texture = True;
327 }
328
329 static void
330 get_texture(ModeInfo *modeinfo)
331 {
332     Flipflopcreen *c = &qs[MI_SCREEN(modeinfo)];
333
334     c->got_texture = False;
335     c->mipmap = True;
336     load_texture_async (modeinfo->xgwa.screen, modeinfo->window,
337                       *c->glx_context, 0, 0, c->mipmap, c->texid,
338                       image_loaded_cb, c);
339 }
340
341 ENTRYPOINT void
342 init_flipflop(ModeInfo *mi)
343 {
344     int screen; 
345     Flipflopcreen *c;
346
347     if (MI_IS_WIREFRAME(mi)) textured = 0;
348
349     /* Set all constants to their correct values */
350     if (board_avg_size != 0) {  /* general size specified by user */
351         board_x_size = board_avg_size;
352         board_y_size = board_avg_size;
353     } else {
354         board_avg_size = (board_x_size + board_y_size) / 2;
355     }
356     if ((numsquares == 0) && (freesquares != 0)) {
357         numsquares = board_x_size * board_y_size - freesquares; 
358     }
359     if (strcmp(flipflopmode_str, "tiles")) {
360       textured = 0;  /* textures look dumb in stick mode */
361         half_thick = 1.0 * DEF_STICK_THICK / 100.0; 
362         if (numsquares == 0) {  /* No value defined by user */
363             numsquares = board_x_size * board_y_size * DEF_STICK_RATIO / 100;
364         }
365     } else {
366         half_thick = 1.0 * DEF_TILE_THICK / 100.0; 
367         if (numsquares == 0) {  /* No value defined by user */
368             numsquares = board_x_size * board_y_size * DEF_TILE_RATIO/ 100;;
369         }
370     }
371     if (board_avg_size < 2) {
372         fprintf (stderr,"%s: the board must be at least 2x2.\n", progname);
373         exit(1);
374     }
375     if ((board_x_size < 1) || (board_y_size < 1) ||     (numsquares < 1)) {
376         fprintf (stderr,"%s: the number of elements ('-count') and the dimensions of the board ('-size-x', '-size-y') must be positive integers.\n", progname);
377         exit(1);
378     }
379     if (board_x_size * board_y_size <= numsquares) {
380         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);
381     }
382
383     screen = MI_SCREEN(mi);
384     wire = MI_IS_WIREFRAME(mi);
385
386     if(!qs &&
387        !(qs = (Flipflopcreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Flipflopcreen))))
388         return;
389
390     c = &qs[screen];
391     c->window = MI_WINDOW(mi);
392     c->trackball = gltrackball_init (False);
393
394     c->flipspeed = 0.03;
395     c->reldist = 1;
396     c->energy = 40;
397
398     if((c->glx_context = init_GL(mi)))
399         reshape_flipflop(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
400     else
401         MI_CLEARWINDOW(mi);
402
403         /* At this point, all the constants have already been set, */
404         /* so we can create the board */
405     c->sheet = (randsheet*) malloc(sizeof(randsheet)); 
406     randsheet_create( c->sheet ); 
407
408     clearbits = GL_COLOR_BUFFER_BIT;
409
410     glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
411     glEnable(GL_COLOR_MATERIAL);
412     setup_lights();
413
414     glEnable(GL_DEPTH_TEST);
415     clearbits |= GL_DEPTH_BUFFER_BIT;
416     glEnable(GL_CULL_FACE);
417     glCullFace(GL_BACK);
418
419     randsheet_initialize( c->sheet );
420     if( textured ){
421         /* check for anisotropic filtering */
422         if(strstr((char *)glGetString(GL_EXTENSIONS),
423             "GL_EXT_texture_filter_anisotropic"))
424             glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &c->anisotropic);
425         else
426             c->anisotropic = 0;
427
428         /* allocate a new texture and get it */
429         glGenTextures(1, &c->texid);
430         get_texture(mi);
431     }
432 }
433
434 ENTRYPOINT void
435 draw_flipflop(ModeInfo *mi)
436 {
437     Flipflopcreen *c = &qs[MI_SCREEN(mi)];
438     Window w = MI_WINDOW(mi);
439     Display *disp = MI_DISPLAY(mi);
440
441     if(!c->glx_context || (textured && !c->got_texture))
442         return;
443
444     glXMakeCurrent(disp, w, *(c->glx_context));
445
446     mi->polygon_count = display(c);
447
448     if(mi->fps_p){
449         do_fps(mi);
450     }
451
452     glFinish();
453     glXSwapBuffers(disp, w);
454
455
456 }
457
458 ENTRYPOINT void
459 release_flipflop(ModeInfo *mi)
460 {
461   if(qs) {
462     int screen;
463
464     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
465     {
466       Flipflopcreen *c = &qs[MI_SCREEN(mi)];
467       if (c->glx_context)
468         c->glx_context = 0;
469       if (c->sheet) {
470         randsheet_free(c->sheet);
471         free (c->sheet);
472         c->sheet = 0;
473       }
474     }
475     free(qs);
476     qs = 0;
477   }
478
479   FreeAllGL(mi);
480 }
481
482 /*** ADDED RANDSHEET FUNCTIONS ***/
483
484 static int
485 draw_sheet(float *tex)
486 {
487     int polys = 0;
488     glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
489
490     glNormal3f( 0, -1, 0 );
491     glTexCoord2f(tex[0], tex[3]);
492     glVertex3f( half_thick,  -half_thick,  half_thick );
493     glTexCoord2f(tex[2], tex[3]);
494     glVertex3f( 1-half_thick,   -half_thick, half_thick );
495     glTexCoord2f(tex[2], tex[1]);
496     glVertex3f( 1-half_thick, -half_thick,  1-half_thick);
497     glTexCoord2f(tex[0], tex[1]);
498     glVertex3f( half_thick, -half_thick, 1-half_thick );
499     polys++;
500
501     if (wire) { glEnd(); glBegin (GL_LINE_LOOP); }
502
503     /* back */
504     glNormal3f( 0, 1, 0 );
505     glTexCoord2f(tex[0], tex[1]);
506     glVertex3f( half_thick, half_thick, 1-half_thick );
507     glTexCoord2f(tex[2], tex[1]);
508     glVertex3f( 1-half_thick, half_thick,  1-half_thick);
509     glTexCoord2f(tex[2], tex[3]);
510     glVertex3f( 1-half_thick,   half_thick, half_thick );
511     glTexCoord2f(tex[0], tex[3]);
512     glVertex3f( half_thick,  half_thick,  half_thick );
513     polys++;
514
515     if (wire) { glEnd(); return polys; }
516
517     /* 4 edges!!! weee.... */
518     glNormal3f( 0, 0, -1 );
519     glTexCoord2f(tex[0], tex[3]);
520     glVertex3f( half_thick, half_thick, half_thick );
521     glTexCoord2f(tex[2], tex[3]);
522     glVertex3f( 1-half_thick, half_thick, half_thick );
523     glTexCoord2f(tex[2], tex[3]);
524     glVertex3f( 1-half_thick, -half_thick, half_thick );
525     glTexCoord2f(tex[0], tex[3]);
526     glVertex3f( half_thick, -half_thick, half_thick );
527     polys++;
528     glNormal3f( 0, 0, 1 );
529     glTexCoord2f(tex[0], tex[1]);
530     glVertex3f( half_thick, half_thick, 1-half_thick );
531     glTexCoord2f(tex[0], tex[1]);
532     glVertex3f( half_thick, -half_thick, 1-half_thick );
533     glTexCoord2f(tex[2], tex[1]);
534     glVertex3f( 1-half_thick, -half_thick, 1-half_thick );
535     glTexCoord2f(tex[2], tex[1]);
536     glVertex3f( 1-half_thick, half_thick, 1-half_thick );
537     polys++;
538     glNormal3f( 1, 0, 0 );
539     glTexCoord2f(tex[2], tex[1]);
540     glVertex3f( 1-half_thick, half_thick, 1-half_thick );
541     glTexCoord2f(tex[2], tex[1]);
542     glVertex3f( 1-half_thick, -half_thick, 1-half_thick );
543     glTexCoord2f(tex[2], tex[3]);
544     glVertex3f( 1-half_thick, -half_thick, half_thick );
545     glTexCoord2f(tex[2], tex[3]);
546     glVertex3f( 1-half_thick, half_thick, half_thick );
547     polys++;
548     glNormal3f( -1, 0, 0 );
549     glTexCoord2f(tex[0], tex[1]);
550     glVertex3f( half_thick, half_thick, 1-half_thick );
551     glTexCoord2f(tex[0], tex[3]);
552     glVertex3f( half_thick, half_thick, half_thick );
553     glTexCoord2f(tex[0], tex[3]);
554     glVertex3f( half_thick, -half_thick, half_thick );
555     glTexCoord2f(tex[0], tex[1]);
556     glVertex3f( half_thick, -half_thick, 1-half_thick );
557     polys++;
558     glEnd();
559
560     return polys;
561 }
562
563 /* Reserve memory for the randsheet */
564 static void
565 randsheet_create( randsheet *rs )
566 {
567         rs -> occupied  = (int*) malloc(board_x_size*board_y_size * sizeof(int));
568         rs -> xpos      = (int*) malloc(numsquares * sizeof(int));
569         rs -> ypos      = (int*) malloc(numsquares * sizeof(int));
570         rs -> direction = (int*) malloc(numsquares * sizeof(int));
571         rs -> angle     = (float*) malloc(numsquares * sizeof(float));
572         rs -> color     = (float*) malloc(numsquares*3 * sizeof(float));
573         rs -> tex       = (float*) malloc(numsquares*4 * sizeof(float));
574 }
575
576 /* Free reserved memory for the randsheet */
577 static void
578 randsheet_free( randsheet *rs )
579 {
580         free(rs->occupied);
581         free(rs->xpos);
582         free(rs->ypos);
583         free(rs->direction);
584         free(rs->angle);
585         free(rs->color);
586         free(rs->tex);
587 }
588
589 static void
590 randsheet_initialize( randsheet *rs )
591 {
592     int i, j, index;
593     index = 0;
594     /* put the moving sheets on the board */
595     for( i = 0; i < board_x_size; i++ )
596         {
597             for( j = 0; j < board_y_size; j++ )
598                 {
599                     /* initially fill up a corner with the moving squares */
600                     if( index < numsquares )
601                         {
602                             rs->occupied[ i * board_y_size + j ] = index;
603                             rs->xpos[ index ] = i;
604                             rs->ypos[ index ] = j;
605                                                         /* have the square colors start out as a pattern */
606                                                         rs->color[ index*3 + 0 ] = ((i+j)%3 == 0)||((i+j+1)%3 == 0);
607                                                         rs->color[ index*3 + 1 ] = ((i+j+1)%3 == 0);
608                                                         rs->color[ index*3 + 2 ] = ((i+j+2)%3 == 0);
609                             index++;
610                         }
611                     /* leave everything else empty*/
612                     else
613                         {
614                             rs->occupied[ i * board_y_size + j ] = -1;
615                         }
616                 }
617         }
618     /* initially everything is at rest */
619     for( i=0; i<numsquares; i++ )
620         {
621             rs->direction[ i ] = 0;
622             rs->angle[ i ] = 0;
623         }
624 }
625
626 /* Pick and random square and direction and try to move it. */
627 /* May not actually move anything, just attempt a random move. */
628 /* Returns true if move was sucessful. */
629 /* This could probably be implemented faster in a dequeue */
630 /* to avoid trying to move a square which is already moving */
631 /* but speed is most likely bottlenecked by rendering anyway... */
632 static int
633 randsheet_new_move( randsheet* rs )
634 {
635     int i, j;
636     int num, dir;
637     /* pick a random square */
638     num = random( ) % numsquares;
639     i = rs->xpos[ num ];
640     j = rs->ypos[ num ];
641     /* pick a random direction */
642     dir = ( random( )% 4 ) + 1;
643
644     if( rs->direction[ num ] == 0 )
645         {
646             switch( dir )
647                 {
648                 case 1:
649                     /* move up in x */
650                     if( ( i + 1 ) < board_x_size )
651                         {
652                             if( rs->occupied[ (i + 1) * board_y_size + j ] == -1 )
653                                 {
654                                     rs->direction[ num ] = dir;
655                                     rs->occupied[ (i + 1) * board_y_size + j ] = num;
656                                     rs->occupied[ i * board_y_size + j ] = -1;
657                                     return 1;
658                                 }
659                         }
660                     return 0;
661                     break;
662                 case 2:
663                     /* move up in y */
664                     if( ( j + 1 ) < board_y_size )
665                         {
666                             if( rs->occupied[ i * board_y_size + (j + 1) ] == -1 )
667                                 {
668                                     rs->direction[ num ] = dir;
669                                     rs->occupied[ i * board_y_size + (j + 1) ] = num;
670                                     rs->occupied[ i * board_y_size + j ] = -1;
671                                     return 1;
672                                 }
673                         }
674                     return 0;
675                     break;
676                 case 3:
677                     /* move down in x */
678                     if( ( i - 1 ) >= 0 )
679                         {
680                             if( rs->occupied[ (i - 1) * board_y_size + j ] == -1 )
681                                 {
682                                     rs->direction[ num ] = dir;
683                                     rs->occupied[ (i - 1) * board_y_size + j ] = num;
684                                     rs->occupied[ i * board_y_size + j ] = -1;
685                                     return 1;
686                                 }
687                         }
688                     return 0;
689                     break;
690                 case 4:
691                     /* move down in y */
692                     if( ( j - 1 ) >= 0 )
693                         {
694                             if( rs->occupied[ i * board_y_size + (j - 1) ] == -1 )
695                                 {
696                                     rs->direction[ num ] = dir;
697                                     rs->occupied[ i * board_y_size + (j - 1) ] = num;
698                                     rs->occupied[ i * board_y_size + j ] = -1;
699                                     return 1;
700                                 }
701                         }
702                     return 0;
703                     break;
704                 default:
705                     break;
706                 }
707         }
708     return 0;
709 }
710
711 /*   move a single frame.  */
712 /*   Pass in the angle in rads the square rotates in a frame. */
713 static void
714 randsheet_move( randsheet *rs, float rot )
715 {
716     int index;
717     float tmp;
718     for( index = 0 ; index < numsquares; index++ )
719         {
720             switch( rs->direction[ index ] )
721                 {
722                 case 0:
723                     /* not moving */
724                     break;
725                 case 1:
726                     /* move up in x */
727                     if( textured && rs->angle[ index ] == 0 )
728                         {
729                             tmp = rs->tex[ index * 4 + 0 ];
730                             rs->tex[ index * 4 + 0 ] = rs->tex[ index * 4 + 2 ];
731                             rs->tex[ index * 4 + 2 ] = tmp;
732                         }
733                     rs->angle[ index ] += rot;
734                     /* check to see if we have finished moving */
735                     if( rs->angle[ index ] >= M_PI  )
736                         {
737                             rs->xpos[ index ] += 1;
738                             rs->direction[ index ] = 0;
739                             rs->angle[ index ] = 0;
740                         }
741                     break;
742                 case 2:
743                     /* move up in y */
744                     if( textured && rs->angle[ index ] == 0 )
745                         {
746                             tmp = rs->tex[ index * 4 + 1 ];
747                             rs->tex[ index * 4 + 1 ] = rs->tex[ index * 4 + 3 ];
748                             rs->tex[ index * 4 + 3 ] = tmp;
749                         }
750                     rs->angle[ index ] += rot;
751                     /* check to see if we have finished moving */
752                     if( rs->angle[ index ] >= M_PI  )
753                         {
754                             rs->ypos[ index ] += 1;
755                             rs->direction[ index ] = 0;
756                             rs->angle[ index ] = 0;
757                         }
758                     break;
759                 case 3:
760                     /* down in x */
761                     rs->angle[ index ] += rot;
762                     /* check to see if we have finished moving */
763                     if( rs->angle[ index ] >= M_PI  )
764                         {
765                             rs->xpos[ index ] -= 1;
766                             rs->direction[ index ] = 0;
767                             rs->angle[ index ] = 0;
768                             if( textured )
769                             {
770                                                             tmp = rs->tex[ index * 4 + 0 ];
771                                                             rs->tex[ index * 4 + 0 ] = rs->tex[ index * 4 + 2 ];
772                                                             rs->tex[ index * 4 + 2 ] = tmp;
773                             }
774                         }
775                     break;
776                 case 4:
777                     /* down in y */
778                     rs->angle[ index ] += rot;
779                     /* check to see if we have finished moving */
780                     if( rs->angle[ index ] >= M_PI  )
781                         {
782                             rs->ypos[ index ] -= 1;
783                             rs->direction[ index ] = 0;
784                             rs->angle[ index ] = 0;
785                             if( textured )
786                             {
787                                 tmp = rs->tex[ index * 4 + 1 ];
788                                 rs->tex[ index * 4 + 1 ] = rs->tex[ index * 4 + 3 ];
789                                 rs->tex[ index * 4 + 3 ] = tmp;
790                             }
791                         }
792                     break;
793                 default:
794                     break;
795                 }
796         }
797 }
798
799
800 /* draw all the moving squares  */
801 static int
802 randsheet_draw( randsheet *rs )
803 {
804     int i, j, polys = 0;
805     int index;
806
807     /* for all moving squares ... */
808     for( index = 0; index < numsquares; index++ )
809         {
810             /* set color */
811             glColor3f( rs->color[ index*3 + 0 ],
812                        rs->color[ index*3 + 1 ],
813                        rs->color[ index*3 + 2 ] );
814             /* find x and y position */
815             i = rs->xpos[ index ];
816             j = rs->ypos[ index ];
817             glPushMatrix();
818             switch( rs->direction[ index ] )
819                 {
820                 case 0:
821
822                     /* not moving */
823                     /* front */
824                     glTranslatef( i, 0, j );
825                     break;
826                 case 1:
827                     glTranslatef( i+1, 0, j );
828                     glRotatef( 180 - rs->angle[ index ]*180/M_PI, 0, 0, 1 );
829
830                     break;
831                 case 2:
832                     glTranslatef( i, 0, j+1 );
833                     glRotatef( 180 - rs->angle[ index ]*180/M_PI, -1, 0, 0 );
834
835                     break;
836                 case 3:
837                     glTranslatef( i, 0, j );
838                     glRotatef( rs->angle[ index ]*180/M_PI, 0, 0, 1 );
839                     break;
840                 case 4:
841                     glTranslatef( i, 0, j );
842                     glRotatef( rs->angle[ index ]*180/M_PI, -1, 0, 0 );
843                     break;
844                 default:
845                     break;
846                 }
847             polys += draw_sheet( rs->tex + index*4 );
848             glPopMatrix();
849
850         }
851     return polys;
852 }
853
854 /**** END RANDSHEET_BAK FUNCTIONS ***/
855
856 XSCREENSAVER_MODULE ("FlipFlop", flipflop)
857
858 #endif /* USE_GL */