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