0d534e53785b81fc5bb92cf48fb35acdcc3fbaa9
[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 ENTRYPOINT Bool
197 flipflop_handle_event (ModeInfo *mi, XEvent *event)
198 {
199     Flipflopcreen *c = &qs[MI_SCREEN(mi)];
200
201     if (event->xany.type == ButtonPress &&
202         event->xbutton.button == Button1)
203         {
204             c->button_down_p = True;
205             gltrackball_start (c->trackball,
206                                event->xbutton.x, event->xbutton.y,
207                                MI_WIDTH (mi), MI_HEIGHT (mi));
208             return True;
209         }
210     else if (event->xany.type == ButtonRelease &&
211              event->xbutton.button == Button1)
212         {
213             c->button_down_p = False;
214             return True;
215         }
216     else if (event->xany.type == ButtonPress &&
217              (event->xbutton.button == Button4 ||
218               event->xbutton.button == Button5 ||
219               event->xbutton.button == Button6 ||
220               event->xbutton.button == Button7))
221         {
222             gltrackball_mousewheel (c->trackball, event->xbutton.button, 5,
223                                     !event->xbutton.state);
224             return True;
225         }
226     else if (event->xany.type == MotionNotify &&
227              c->button_down_p)
228         {
229             gltrackball_track (c->trackball,
230                                event->xmotion.x, event->xmotion.y,
231                                MI_WIDTH (mi), MI_HEIGHT (mi));
232             return True;
233         }
234
235     return False;
236 }
237
238 /* draw board */
239 static int
240 drawBoard(Flipflopcreen *c)
241 {
242     int i;
243     for( i=0; i < (c->energy) ; i++ ) {
244         randsheet_new_move( c->sheet );
245         }
246     randsheet_move( c->sheet, c->flipspeed * 3.14159 );
247     return randsheet_draw( c->sheet );
248 }
249
250
251 static int
252 display(Flipflopcreen *c)
253 {
254     GLfloat amb[] = { 0.8, 0.8, 0.8, 1.0 };
255     int polys = 0;
256
257
258     glClear(clearbits);
259     glMatrixMode(GL_MODELVIEW);
260     glLoadIdentity();
261
262     glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.2);
263     glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.15/board_avg_size );
264     glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.15/board_avg_size );
265     glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
266
267
268     glRotatef(current_device_rotation(), 0, 0, 1);
269
270     /** setup perspectif */
271     glTranslatef(0.0, 0.0, -c->reldist*board_avg_size);
272     glRotatef(22.5, 1.0, 0.0, 0.0);  
273     glRotatef(-current_device_rotation(), 0, 0, 1);
274     gltrackball_rotate (c->trackball);
275     glRotatef(current_device_rotation(), 0, 0, 1);
276     glRotatef(c->theta*100, 0.0, 1.0, 0.0);
277     glTranslatef(-0.5*board_x_size, 0.0, -0.5*board_y_size); /* Center the board */
278
279     /* set texture */
280     if(textured)
281       glBindTexture(GL_TEXTURE_2D, c->texid);
282
283     polys = drawBoard(c);
284
285     if (!c->button_down_p) {
286         c->theta += .01 * spin;
287     }
288
289     return polys;
290 }
291
292 ENTRYPOINT void
293 reshape_flipflop(ModeInfo *mi, int width, int height)
294 {
295     GLfloat h = (GLfloat) height / (GLfloat) width;
296     glViewport(0,0, width, height);
297     glMatrixMode(GL_PROJECTION);
298     glLoadIdentity();
299     gluPerspective(45, 1/h, 1.0, 300.0);
300     glMatrixMode(GL_MODELVIEW);
301 }
302
303 static void
304 image_loaded_cb (const char *filename, XRectangle *geometry,
305                  int image_width, int image_height, 
306                  int texture_width, int texture_height,
307                  void *closure)
308 {
309     Flipflopcreen *c = (Flipflopcreen *)closure;
310     int i, j;
311     int index = 0;
312     randsheet *rs = c->sheet;
313
314     c->tex_x = (float)geometry->x / (float)texture_width;
315     c->tex_y = (float)geometry->y / (float)texture_height;
316     c->tex_width = (float)geometry->width / (float)texture_width; 
317     c->tex_height = (float)geometry->height / (float)texture_height;
318
319     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
320     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
321         (c->mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
322
323     if(c->anisotropic >= 1)
324         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, c->anisotropic);
325
326     glEnable(GL_TEXTURE_2D);
327     glEnable(GL_BLEND);
328     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
329
330     for(i = 0; i < board_x_size && index < numsquares; i++)
331         for(j = 0; j < board_y_size && index < numsquares; j++)
332         {
333             /* arrange squares to form loaded image */
334             rs->tex[ index*4 + 0 ] = c->tex_x + c->tex_width  / board_x_size * (i + 0);
335             rs->tex[ index*4 + 1 ] = c->tex_y + c->tex_height / board_y_size * (j + 1);
336             rs->tex[ index*4 + 2 ] = c->tex_x + c->tex_width  / board_x_size * (i + 1);
337             rs->tex[ index*4 + 3 ] = c->tex_y + c->tex_height / board_y_size * (j + 0);
338             rs->color[ index*3 + 0 ] = 1;
339             rs->color[ index*3 + 1 ] = 1;
340             rs->color[ index*3 + 2 ] = 1;
341             index++;
342         }
343
344     c->got_texture = True;
345 }
346
347 static void
348 get_texture(ModeInfo *modeinfo)
349 {
350     Flipflopcreen *c = &qs[MI_SCREEN(modeinfo)];
351
352     c->got_texture = False;
353     c->mipmap = True;
354     load_texture_async (modeinfo->xgwa.screen, modeinfo->window,
355                       *c->glx_context, 0, 0, c->mipmap, c->texid,
356                       image_loaded_cb, c);
357 }
358
359 ENTRYPOINT void
360 init_flipflop(ModeInfo *mi)
361 {
362     int screen; 
363     Flipflopcreen *c;
364
365     if (MI_IS_WIREFRAME(mi)) textured = 0;
366
367     /* Set all constants to their correct values */
368     if (board_avg_size != 0) {  /* general size specified by user */
369         board_x_size = board_avg_size;
370         board_y_size = board_avg_size;
371     } else {
372         board_avg_size = (board_x_size + board_y_size) / 2;
373     }
374     if ((numsquares == 0) && (freesquares != 0)) {
375         numsquares = board_x_size * board_y_size - freesquares; 
376     }
377     if (strcmp(flipflopmode_str, "tiles")) {
378       textured = 0;  /* textures look dumb in stick mode */
379         half_thick = 1.0 * DEF_STICK_THICK / 100.0; 
380         if (numsquares == 0) {  /* No value defined by user */
381             numsquares = board_x_size * board_y_size * DEF_STICK_RATIO / 100;
382         }
383     } else {
384         half_thick = 1.0 * DEF_TILE_THICK / 100.0; 
385         if (numsquares == 0) {  /* No value defined by user */
386             numsquares = board_x_size * board_y_size * DEF_TILE_RATIO/ 100;;
387         }
388     }
389     if (board_avg_size < 2) {
390         fprintf (stderr,"%s: the board must be at least 2x2.\n", progname);
391         exit(1);
392     }
393     if ((board_x_size < 1) || (board_y_size < 1) ||     (numsquares < 1)) {
394         fprintf (stderr,"%s: the number of elements ('-count') and the dimensions of the board ('-size-x', '-size-y') must be positive integers.\n", progname);
395         exit(1);
396     }
397     if (board_x_size * board_y_size <= numsquares) {
398         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);
399     }
400
401     screen = MI_SCREEN(mi);
402     wire = MI_IS_WIREFRAME(mi);
403
404     if(!qs &&
405        !(qs = (Flipflopcreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Flipflopcreen))))
406         return;
407
408     c = &qs[screen];
409     c->window = MI_WINDOW(mi);
410     c->trackball = gltrackball_init ();
411
412     c->flipspeed = 0.03;
413     c->reldist = 1;
414     c->energy = 40;
415
416     if((c->glx_context = init_GL(mi)))
417         reshape_flipflop(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
418     else
419         MI_CLEARWINDOW(mi);
420
421         /* At this point, all the constants have already been set, */
422         /* so we can create the board */
423     c->sheet = (randsheet*) malloc(sizeof(randsheet)); 
424     randsheet_create( c->sheet ); 
425
426     clearbits = GL_COLOR_BUFFER_BIT;
427
428     glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
429     glEnable(GL_COLOR_MATERIAL);
430     setup_lights();
431
432     glEnable(GL_DEPTH_TEST);
433     clearbits |= GL_DEPTH_BUFFER_BIT;
434     glEnable(GL_CULL_FACE);
435     glCullFace(GL_BACK);
436
437     randsheet_initialize( c->sheet );
438     if( textured ){
439         /* check for anisotropic filtering */
440         if(strstr((char *)glGetString(GL_EXTENSIONS),
441             "GL_EXT_texture_filter_anisotropic"))
442             glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &c->anisotropic);
443         else
444             c->anisotropic = 0;
445
446         /* allocate a new texture and get it */
447         glGenTextures(1, &c->texid);
448         get_texture(mi);
449     }
450 }
451
452 ENTRYPOINT void
453 draw_flipflop(ModeInfo *mi)
454 {
455     Flipflopcreen *c = &qs[MI_SCREEN(mi)];
456     Window w = MI_WINDOW(mi);
457     Display *disp = MI_DISPLAY(mi);
458
459     if(!c->glx_context || (textured && !c->got_texture))
460         return;
461
462     glXMakeCurrent(disp, w, *(c->glx_context));
463
464     mi->polygon_count = display(c);
465
466     if(mi->fps_p){
467         do_fps(mi);
468     }
469
470     glFinish();
471     glXSwapBuffers(disp, w);
472
473
474 }
475
476 ENTRYPOINT void
477 release_flipflop(ModeInfo *mi)
478 {
479   if(qs) {
480     int screen;
481
482     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
483     {
484       Flipflopcreen *c = &qs[MI_SCREEN(mi)];
485       if (c->glx_context)
486         c->glx_context = 0;
487       if (c->sheet) {
488         randsheet_free(c->sheet);
489         free (c->sheet);
490         c->sheet = 0;
491       }
492     }
493     free(qs);
494     qs = 0;
495   }
496
497   FreeAllGL(mi);
498 }
499
500 /*** ADDED RANDSHEET FUNCTIONS ***/
501
502 static int
503 draw_sheet(float *tex)
504 {
505     int polys = 0;
506     glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
507
508     glNormal3f( 0, -1, 0 );
509     glTexCoord2f(tex[0], tex[3]);
510     glVertex3f( half_thick,  -half_thick,  half_thick );
511     glTexCoord2f(tex[2], tex[3]);
512     glVertex3f( 1-half_thick,   -half_thick, half_thick );
513     glTexCoord2f(tex[2], tex[1]);
514     glVertex3f( 1-half_thick, -half_thick,  1-half_thick);
515     glTexCoord2f(tex[0], tex[1]);
516     glVertex3f( half_thick, -half_thick, 1-half_thick );
517     polys++;
518
519     if (wire) { glEnd(); glBegin (GL_LINE_LOOP); }
520
521     /* back */
522     glNormal3f( 0, 1, 0 );
523     glTexCoord2f(tex[0], tex[1]);
524     glVertex3f( half_thick, half_thick, 1-half_thick );
525     glTexCoord2f(tex[2], tex[1]);
526     glVertex3f( 1-half_thick, half_thick,  1-half_thick);
527     glTexCoord2f(tex[2], tex[3]);
528     glVertex3f( 1-half_thick,   half_thick, half_thick );
529     glTexCoord2f(tex[0], tex[3]);
530     glVertex3f( half_thick,  half_thick,  half_thick );
531     polys++;
532
533     if (wire) { glEnd(); return polys; }
534
535     /* 4 edges!!! weee.... */
536     glNormal3f( 0, 0, -1 );
537     glTexCoord2f(tex[0], tex[3]);
538     glVertex3f( half_thick, half_thick, half_thick );
539     glTexCoord2f(tex[2], tex[3]);
540     glVertex3f( 1-half_thick, half_thick, half_thick );
541     glTexCoord2f(tex[2], tex[3]);
542     glVertex3f( 1-half_thick, -half_thick, half_thick );
543     glTexCoord2f(tex[0], tex[3]);
544     glVertex3f( half_thick, -half_thick, half_thick );
545     polys++;
546     glNormal3f( 0, 0, 1 );
547     glTexCoord2f(tex[0], tex[1]);
548     glVertex3f( half_thick, half_thick, 1-half_thick );
549     glTexCoord2f(tex[0], tex[1]);
550     glVertex3f( half_thick, -half_thick, 1-half_thick );
551     glTexCoord2f(tex[2], tex[1]);
552     glVertex3f( 1-half_thick, -half_thick, 1-half_thick );
553     glTexCoord2f(tex[2], tex[1]);
554     glVertex3f( 1-half_thick, half_thick, 1-half_thick );
555     polys++;
556     glNormal3f( 1, 0, 0 );
557     glTexCoord2f(tex[2], tex[1]);
558     glVertex3f( 1-half_thick, half_thick, 1-half_thick );
559     glTexCoord2f(tex[2], tex[1]);
560     glVertex3f( 1-half_thick, -half_thick, 1-half_thick );
561     glTexCoord2f(tex[2], tex[3]);
562     glVertex3f( 1-half_thick, -half_thick, half_thick );
563     glTexCoord2f(tex[2], tex[3]);
564     glVertex3f( 1-half_thick, half_thick, half_thick );
565     polys++;
566     glNormal3f( -1, 0, 0 );
567     glTexCoord2f(tex[0], tex[1]);
568     glVertex3f( half_thick, half_thick, 1-half_thick );
569     glTexCoord2f(tex[0], tex[3]);
570     glVertex3f( half_thick, half_thick, half_thick );
571     glTexCoord2f(tex[0], tex[3]);
572     glVertex3f( half_thick, -half_thick, half_thick );
573     glTexCoord2f(tex[0], tex[1]);
574     glVertex3f( half_thick, -half_thick, 1-half_thick );
575     polys++;
576     glEnd();
577
578     return polys;
579 }
580
581 /* Reserve memory for the randsheet */
582 static void
583 randsheet_create( randsheet *rs )
584 {
585         rs -> occupied  = (int*) malloc(board_x_size*board_y_size * sizeof(int));
586         rs -> xpos      = (int*) malloc(numsquares * sizeof(int));
587         rs -> ypos      = (int*) malloc(numsquares * sizeof(int));
588         rs -> direction = (int*) malloc(numsquares * sizeof(int));
589         rs -> angle     = (float*) malloc(numsquares * sizeof(float));
590         rs -> color     = (float*) malloc(numsquares*3 * sizeof(float));
591         rs -> tex       = (float*) malloc(numsquares*4 * sizeof(float));
592 }
593
594 /* Free reserved memory for the randsheet */
595 static void
596 randsheet_free( randsheet *rs )
597 {
598         free(rs->occupied);
599         free(rs->xpos);
600         free(rs->ypos);
601         free(rs->direction);
602         free(rs->angle);
603         free(rs->color);
604         free(rs->tex);
605 }
606
607 static void
608 randsheet_initialize( randsheet *rs )
609 {
610     int i, j, index;
611     index = 0;
612     /* put the moving sheets on the board */
613     for( i = 0; i < board_x_size; i++ )
614         {
615             for( j = 0; j < board_y_size; j++ )
616                 {
617                     /* initially fill up a corner with the moving squares */
618                     if( index < numsquares )
619                         {
620                             rs->occupied[ i * board_y_size + j ] = index;
621                             rs->xpos[ index ] = i;
622                             rs->ypos[ index ] = j;
623                                                         /* have the square colors start out as a pattern */
624                                                         rs->color[ index*3 + 0 ] = ((i+j)%3 == 0)||((i+j+1)%3 == 0);
625                                                         rs->color[ index*3 + 1 ] = ((i+j+1)%3 == 0);
626                                                         rs->color[ index*3 + 2 ] = ((i+j+2)%3 == 0);
627                             index++;
628                         }
629                     /* leave everything else empty*/
630                     else
631                         {
632                             rs->occupied[ i * board_y_size + j ] = -1;
633                         }
634                 }
635         }
636     /* initially everything is at rest */
637     for( i=0; i<numsquares; i++ )
638         {
639             rs->direction[ i ] = 0;
640             rs->angle[ i ] = 0;
641         }
642 }
643
644 /* Pick and random square and direction and try to move it. */
645 /* May not actually move anything, just attempt a random move. */
646 /* Returns true if move was sucessful. */
647 /* This could probably be implemented faster in a dequeue */
648 /* to avoid trying to move a square which is already moving */
649 /* but speed is most likely bottlenecked by rendering anyway... */
650 static int
651 randsheet_new_move( randsheet* rs )
652 {
653     int i, j;
654     int num, dir;
655     /* pick a random square */
656     num = random( ) % numsquares;
657     i = rs->xpos[ num ];
658     j = rs->ypos[ num ];
659     /* pick a random direction */
660     dir = ( random( )% 4 ) + 1;
661
662     if( rs->direction[ num ] == 0 )
663         {
664             switch( dir )
665                 {
666                 case 1:
667                     /* move up in x */
668                     if( ( i + 1 ) < board_x_size )
669                         {
670                             if( rs->occupied[ (i + 1) * board_y_size + j ] == -1 )
671                                 {
672                                     rs->direction[ num ] = dir;
673                                     rs->occupied[ (i + 1) * board_y_size + j ] = num;
674                                     rs->occupied[ i * board_y_size + j ] = -1;
675                                     return 1;
676                                 }
677                         }
678                     return 0;
679                     break;
680                 case 2:
681                     /* move up in y */
682                     if( ( j + 1 ) < board_y_size )
683                         {
684                             if( rs->occupied[ i * board_y_size + (j + 1) ] == -1 )
685                                 {
686                                     rs->direction[ num ] = dir;
687                                     rs->occupied[ i * board_y_size + (j + 1) ] = num;
688                                     rs->occupied[ i * board_y_size + j ] = -1;
689                                     return 1;
690                                 }
691                         }
692                     return 0;
693                     break;
694                 case 3:
695                     /* move down in x */
696                     if( ( i - 1 ) >= 0 )
697                         {
698                             if( rs->occupied[ (i - 1) * board_y_size + j ] == -1 )
699                                 {
700                                     rs->direction[ num ] = dir;
701                                     rs->occupied[ (i - 1) * board_y_size + j ] = num;
702                                     rs->occupied[ i * board_y_size + j ] = -1;
703                                     return 1;
704                                 }
705                         }
706                     return 0;
707                     break;
708                 case 4:
709                     /* move down in y */
710                     if( ( j - 1 ) >= 0 )
711                         {
712                             if( rs->occupied[ i * board_y_size + (j - 1) ] == -1 )
713                                 {
714                                     rs->direction[ num ] = dir;
715                                     rs->occupied[ i * board_y_size + (j - 1) ] = num;
716                                     rs->occupied[ i * board_y_size + j ] = -1;
717                                     return 1;
718                                 }
719                         }
720                     return 0;
721                     break;
722                 default:
723                     break;
724                 }
725         }
726     return 0;
727 }
728
729 /*   move a single frame.  */
730 /*   Pass in the angle in rads the square rotates in a frame. */
731 static void
732 randsheet_move( randsheet *rs, float rot )
733 {
734     int index;
735     float tmp;
736     for( index = 0 ; index < numsquares; index++ )
737         {
738             switch( rs->direction[ index ] )
739                 {
740                 case 0:
741                     /* not moving */
742                     break;
743                 case 1:
744                     /* move up in x */
745                     if( textured && rs->angle[ index ] == 0 )
746                         {
747                             tmp = rs->tex[ index * 4 + 0 ];
748                             rs->tex[ index * 4 + 0 ] = rs->tex[ index * 4 + 2 ];
749                             rs->tex[ index * 4 + 2 ] = tmp;
750                         }
751                     rs->angle[ index ] += rot;
752                     /* check to see if we have finished moving */
753                     if( rs->angle[ index ] >= M_PI  )
754                         {
755                             rs->xpos[ index ] += 1;
756                             rs->direction[ index ] = 0;
757                             rs->angle[ index ] = 0;
758                         }
759                     break;
760                 case 2:
761                     /* move up in y */
762                     if( textured && rs->angle[ index ] == 0 )
763                         {
764                             tmp = rs->tex[ index * 4 + 1 ];
765                             rs->tex[ index * 4 + 1 ] = rs->tex[ index * 4 + 3 ];
766                             rs->tex[ index * 4 + 3 ] = tmp;
767                         }
768                     rs->angle[ index ] += rot;
769                     /* check to see if we have finished moving */
770                     if( rs->angle[ index ] >= M_PI  )
771                         {
772                             rs->ypos[ index ] += 1;
773                             rs->direction[ index ] = 0;
774                             rs->angle[ index ] = 0;
775                         }
776                     break;
777                 case 3:
778                     /* down in x */
779                     rs->angle[ index ] += rot;
780                     /* check to see if we have finished moving */
781                     if( rs->angle[ index ] >= M_PI  )
782                         {
783                             rs->xpos[ index ] -= 1;
784                             rs->direction[ index ] = 0;
785                             rs->angle[ index ] = 0;
786                             if( textured )
787                             {
788                                                             tmp = rs->tex[ index * 4 + 0 ];
789                                                             rs->tex[ index * 4 + 0 ] = rs->tex[ index * 4 + 2 ];
790                                                             rs->tex[ index * 4 + 2 ] = tmp;
791                             }
792                         }
793                     break;
794                 case 4:
795                     /* down in y */
796                     rs->angle[ index ] += rot;
797                     /* check to see if we have finished moving */
798                     if( rs->angle[ index ] >= M_PI  )
799                         {
800                             rs->ypos[ index ] -= 1;
801                             rs->direction[ index ] = 0;
802                             rs->angle[ index ] = 0;
803                             if( textured )
804                             {
805                                 tmp = rs->tex[ index * 4 + 1 ];
806                                 rs->tex[ index * 4 + 1 ] = rs->tex[ index * 4 + 3 ];
807                                 rs->tex[ index * 4 + 3 ] = tmp;
808                             }
809                         }
810                     break;
811                 default:
812                     break;
813                 }
814         }
815 }
816
817
818 /* draw all the moving squares  */
819 static int
820 randsheet_draw( randsheet *rs )
821 {
822     int i, j, polys = 0;
823     int index;
824
825     /* for all moving squares ... */
826     for( index = 0; index < numsquares; index++ )
827         {
828             /* set color */
829             glColor3f( rs->color[ index*3 + 0 ],
830                        rs->color[ index*3 + 1 ],
831                        rs->color[ index*3 + 2 ] );
832             /* find x and y position */
833             i = rs->xpos[ index ];
834             j = rs->ypos[ index ];
835             glPushMatrix();
836             switch( rs->direction[ index ] )
837                 {
838                 case 0:
839
840                     /* not moving */
841                     /* front */
842                     glTranslatef( i, 0, j );
843                     break;
844                 case 1:
845                     glTranslatef( i+1, 0, j );
846                     glRotatef( 180 - rs->angle[ index ]*180/M_PI, 0, 0, 1 );
847
848                     break;
849                 case 2:
850                     glTranslatef( i, 0, j+1 );
851                     glRotatef( 180 - rs->angle[ index ]*180/M_PI, -1, 0, 0 );
852
853                     break;
854                 case 3:
855                     glTranslatef( i, 0, j );
856                     glRotatef( rs->angle[ index ]*180/M_PI, 0, 0, 1 );
857                     break;
858                 case 4:
859                     glTranslatef( i, 0, j );
860                     glRotatef( rs->angle[ index ]*180/M_PI, -1, 0, 0 );
861                     break;
862                 default:
863                     break;
864                 }
865             polys += draw_sheet( rs->tex + index*4 );
866             glPopMatrix();
867
868         }
869     return polys;
870 }
871
872 /**** END RANDSHEET_BAK FUNCTIONS ***/
873
874 XSCREENSAVER_MODULE ("FlipFlop", flipflop)
875
876 #endif /* USE_GL */