1 /* flipflop, Copyright (c) 2003 Kevin Ogden <kogden1@hotmail.com>
2 * (c) 2006 Sergio GutiƩrrez "Sergut" <sergut@gmail.com>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
13 * 2003 Kevin Odgen First version
14 * 2006 Sergio GutiƩrrez "Sergut" Made several parameters dynamic and selectable
15 * from the command line: size of the board,
16 * rotation speed and number of free squares; also
17 * added the "sticks" mode.
21 #define DEF_FLIPFLOP_MODE "tiles" /* Default mode (options: "tiles", "sticks") */
22 #define DEF_BOARD_X_SIZE "9" /* Default width of the board */
23 #define DEF_BOARD_Y_SIZE "9" /* Default length of the board */
25 #define DEF_BOARD_SIZE "0" /* "0" means "no value selected by user". It is changed */
26 #define DEF_NUMSQUARES "0" /* in function init_flipflop() to its correct value (that */
27 #define DEF_FREESQUARES "0" /* is a function of the size of the board and the mode)*/
29 #define DEF_SPIN "0.1" /* Default angular velocity: PI/10 rads/s */
31 #define DEF_STICK_THICK 54 /* Thickness for the sticks mode (over 100) */
32 #define DEF_STICK_RATIO 80 /* Ratio of sticks/total squares (over 100) */
33 #define DEF_TILE_THICK 4 /* Thickness for the tiles mode (over 100) */
34 #define DEF_TILE_RATIO 95 /* Ratio of tiles/total squares (over 100) */
37 #define DEFAULTS "*delay: 20000 \n" \
38 "*showFPS: False \n" \
39 "*wireframe: False \n"
41 # define refresh_flipflop 0
42 # include "xlockmore.h"
46 #endif /* STANDALONE */
50 #include "gltrackball.h"
53 #define countof(x) (sizeof((x))/sizeof((*x)))
55 static XrmOptionDescRec opts[] = {
56 {"-sticks", ".mode", XrmoptionNoArg, "sticks"},
57 {"-tiles", ".mode", XrmoptionNoArg, "tiles" },
58 {"-mode", ".mode", XrmoptionSepArg, 0 },
59 {"-size", ".size", XrmoptionSepArg, 0 },
60 {"-size-x", ".size_x", XrmoptionSepArg, 0 },
61 {"-size-y", ".size_y", XrmoptionSepArg, 0 },
62 {"-count", ".numsquares", XrmoptionSepArg, 0 },
63 {"-free", ".freesquares", XrmoptionSepArg, 0 },
64 {"-spin", ".spin", XrmoptionSepArg, 0 },
67 static int wire, clearbits;
68 static int board_x_size, board_y_size, board_avg_size;
69 static int numsquares, freesquares;
70 static float half_thick;
72 static char* flipflopmode_str="tiles";
74 static argtype vars[] = {
75 { &flipflopmode_str, "mode", "Mode", DEF_FLIPFLOP_MODE, t_String},
76 { &board_avg_size, "size", "Integer", DEF_BOARD_SIZE, t_Int},
77 { &board_x_size, "size_x", "Integer", DEF_BOARD_X_SIZE, t_Int},
78 { &board_y_size, "size_y", "Integer", DEF_BOARD_Y_SIZE, t_Int},
79 { &numsquares, "numsquares", "Integer", DEF_NUMSQUARES, t_Int},
80 { &freesquares, "freesquares", "Integer", DEF_NUMSQUARES, t_Int},
81 { &spin, "spin", "Float", DEF_SPIN, t_Float},
84 ENTRYPOINT ModeSpecOpt flipflop_opts = {countof(opts), opts, countof(vars), vars, NULL};
87 ModStruct flipflop_description =
88 {"flipflop", "init_flipflop", "draw_flipflop", "release_flipflop",
89 "draw_flipflop", "init_flipflop", NULL, &flipflop_opts,
90 1000, 1, 2, 1, 4, 1.0, "",
93 #endif /* USE_MODULES */
96 /* array specifying which squares are where (to avoid collisions) */
97 /* -1 means empty otherwise integer represents square index 0 - n-1 */
98 /* occupied[x*board_y_size+y] is the tile [x][y] (i.e. that starts at column x and row y)*/
99 int *occupied; /* size: size_x * size_y */
100 /* an array of xpositions of the squares */
101 int *xpos; /* size: numsquares */
102 /* array of y positions of the squares */
103 int *ypos; /* size: numsquares */
104 /* integer representing the direction of movement of a square */
105 int *direction; /* 0 not, 1 x+, 2 y+, 3 x-, 4 y-*/ /* size: numsquares */
106 /* angle of moving square (during a flip) */
107 float *angle; /* size: numsquares */
108 /* array of colors for a square (RGB) */
109 /* eg. color[ 3*3 + 0 ] is the red component of square 3 */
110 /* eg. color[ 4*3 + 1 ] is the green component of square 4 */
111 /* eg. color[ 5*3 + 2 ] is the blue component of square 5 */
112 /* ^-- n is the number of square */
113 float *color; /* size: numsquares * 3 */
117 GLXContext *glx_context;
119 trackball_state *trackball;
124 float theta; /* angle of rotation of the board */
125 float flipspeed; /* amount of flip; 1 is a entire flip */
126 float reldist; /* relative distace of camera from center */
127 float energy; /* likelyhood that a square will attempt to move */
131 static Flipflopcreen *qs = NULL;
133 static void randsheet_create( randsheet *rs );
134 static void randsheet_initialize( randsheet *rs );
135 static void randsheet_free( randsheet *rs );
136 static int randsheet_new_move( randsheet* rs );
137 static void randsheet_move( randsheet *rs, float rot );
138 static void randsheet_draw( randsheet *rs );
139 static void setup_lights(void);
140 static void drawBoard(Flipflopcreen *);
141 static void display(Flipflopcreen *c);
142 static void draw_sheet(void);
145 /* configure lighting */
149 /* GLfloat position0[] = { board_avg_size*0.5, board_avg_size*0.1, board_avg_size*0.5, 1.0 }; */
151 /* GLfloat position0[] = { -board_avg_size*0.5, 0.2*board_avg_size, -board_avg_size*0.5, 1.0 }; */
152 GLfloat position0[4];
154 position0[1] = board_avg_size*0.3;
160 glEnable(GL_LIGHTING);
161 glLightfv(GL_LIGHT0, GL_POSITION, position0);
166 flipflop_handle_event (ModeInfo *mi, XEvent *event)
168 Flipflopcreen *c = &qs[MI_SCREEN(mi)];
170 if (event->xany.type == ButtonPress &&
171 event->xbutton.button == Button1)
173 c->button_down_p = True;
174 gltrackball_start (c->trackball,
175 event->xbutton.x, event->xbutton.y,
176 MI_WIDTH (mi), MI_HEIGHT (mi));
179 else if (event->xany.type == ButtonRelease &&
180 event->xbutton.button == Button1)
182 c->button_down_p = False;
185 else if (event->xany.type == ButtonPress &&
186 (event->xbutton.button == Button4 ||
187 event->xbutton.button == Button5))
189 gltrackball_mousewheel (c->trackball, event->xbutton.button, 5,
190 !event->xbutton.state);
193 else if (event->xany.type == MotionNotify &&
196 gltrackball_track (c->trackball,
197 event->xmotion.x, event->xmotion.y,
198 MI_WIDTH (mi), MI_HEIGHT (mi));
207 drawBoard(Flipflopcreen *c)
210 for( i=0; i < (c->energy) ; i++ ) {
211 randsheet_new_move( c->sheet );
213 randsheet_move( c->sheet, c->flipspeed * 3.14159 );
214 randsheet_draw( c->sheet );
219 display(Flipflopcreen *c)
221 GLfloat amb[] = { 0.8, 0.8, 0.8, 1.0 };
225 glMatrixMode(GL_MODELVIEW);
228 glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.2);
229 glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.15/board_avg_size );
230 glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.15/board_avg_size );
231 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
234 /** setup perspectif */
235 glTranslatef(0.0, 0.0, -c->reldist*board_avg_size);
236 glRotatef(22.5, 1.0, 0.0, 0.0);
237 gltrackball_rotate (c->trackball);
238 glRotatef(c->theta*100, 0.0, 1.0, 0.0);
239 glTranslatef(-0.5*board_x_size, 0.0, -0.5*board_y_size); /* Center the board */
243 if (!c->button_down_p) {
244 c->theta += .01 * spin;
250 reshape_flipflop(ModeInfo *mi, int width, int height)
252 GLfloat h = (GLfloat) height / (GLfloat) width;
253 glViewport(0,0, width, height);
254 glMatrixMode(GL_PROJECTION);
256 gluPerspective(45, 1/h, 1.0, 300.0);
257 glMatrixMode(GL_MODELVIEW);
261 init_flipflop(ModeInfo *mi)
266 /* Set all constants to their correct values */
267 if (board_avg_size != 0) { /* general size specified by user */
268 board_x_size = board_avg_size;
269 board_y_size = board_avg_size;
271 board_avg_size = (board_x_size + board_y_size) / 2;
273 if ((numsquares == 0) && (freesquares != 0)) {
274 numsquares = board_x_size * board_y_size - freesquares;
276 if (strcmp(flipflopmode_str, "tiles")) {
277 half_thick = 1.0 * DEF_STICK_THICK / 100.0;
278 if (numsquares == 0) { /* No value defined by user */
279 numsquares = board_x_size * board_y_size * DEF_STICK_RATIO / 100;
282 half_thick = 1.0 * DEF_TILE_THICK / 100.0;
283 if (numsquares == 0) { /* No value defined by user */
284 numsquares = board_x_size * board_y_size * DEF_TILE_RATIO/ 100;;
287 if (board_avg_size < 2) {
288 fprintf (stderr,"%s: the board must be at least 2x2.\n", progname);
291 if ((board_x_size < 1) || (board_y_size < 1) || (numsquares < 1)) {
292 fprintf (stderr,"%s: the number of elements ('-count') and the dimensions of the board ('-size-x', '-size-y') must be positive integers.\n", progname);
295 if (board_x_size * board_y_size <= numsquares) {
296 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);
299 screen = MI_SCREEN(mi);
300 wire = MI_IS_WIREFRAME(mi);
303 !(qs = (Flipflopcreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Flipflopcreen))))
307 c->window = MI_WINDOW(mi);
308 c->trackball = gltrackball_init ();
314 if((c->glx_context = init_GL(mi)))
315 reshape_flipflop(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
319 /* At this point, all the constants have already been set, */
320 /* so we can create the board */
321 c->sheet = (randsheet*) malloc(sizeof(randsheet));
322 randsheet_create( c->sheet );
324 glClearColor(0.0, 0.0, 0.0, 0.0);
326 clearbits = GL_COLOR_BUFFER_BIT;
328 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
329 glEnable(GL_COLOR_MATERIAL);
332 glEnable(GL_DEPTH_TEST);
333 clearbits |= GL_DEPTH_BUFFER_BIT;
334 glEnable(GL_CULL_FACE);
336 randsheet_initialize( c->sheet );
340 draw_flipflop(ModeInfo *mi)
342 Flipflopcreen *c = &qs[MI_SCREEN(mi)];
343 Window w = MI_WINDOW(mi);
344 Display *disp = MI_DISPLAY(mi);
349 glXMakeCurrent(disp, w, *(c->glx_context));
358 glXSwapBuffers(disp, w);
364 release_flipflop(ModeInfo *mi)
369 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
371 Flipflopcreen *c = &qs[MI_SCREEN(mi)];
375 randsheet_free(c->sheet);
387 /*** ADDED RANDSHEET FUNCTIONS ***/
392 glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
394 glNormal3f( 0, -1, 0 );
395 glVertex3f( half_thick, -half_thick, half_thick );
396 glVertex3f( 1-half_thick, -half_thick, half_thick );
397 glVertex3f( 1-half_thick, -half_thick, 1-half_thick);
398 glVertex3f( half_thick, -half_thick, 1-half_thick );
400 if (wire) { glEnd(); glBegin (GL_LINE_LOOP); }
403 glNormal3f( 0, 1, 0 );
404 glVertex3f( half_thick, half_thick, 1-half_thick );
405 glVertex3f( 1-half_thick, half_thick, 1-half_thick);
406 glVertex3f( 1-half_thick, half_thick, half_thick );
407 glVertex3f( half_thick, half_thick, half_thick );
409 if (wire) { glEnd(); return; }
411 /* 4 edges!!! weee.... */
412 glNormal3f( 0, 0, -1 );
413 glVertex3f( half_thick, half_thick, half_thick );
414 glVertex3f( 1-half_thick, half_thick, half_thick );
415 glVertex3f( 1-half_thick, -half_thick, half_thick );
416 glVertex3f( half_thick, -half_thick, half_thick );
417 glNormal3f( 0, 0, 1 );
418 glVertex3f( half_thick, half_thick, 1-half_thick );
419 glVertex3f( half_thick, -half_thick, 1-half_thick );
420 glVertex3f( 1-half_thick, -half_thick, 1-half_thick );
421 glVertex3f( 1-half_thick, half_thick, 1-half_thick );
422 glNormal3f( 1, 0, 0 );
423 glVertex3f( 1-half_thick, half_thick, 1-half_thick );
424 glVertex3f( 1-half_thick, -half_thick, 1-half_thick );
425 glVertex3f( 1-half_thick, -half_thick, half_thick );
426 glVertex3f( 1-half_thick, half_thick, half_thick );
427 glNormal3f( -1, 0, 0 );
428 glVertex3f( half_thick, half_thick, 1-half_thick );
429 glVertex3f( half_thick, half_thick, half_thick );
430 glVertex3f( half_thick, -half_thick, half_thick );
431 glVertex3f( half_thick, -half_thick, 1-half_thick );
435 /* Reserve memory for the randsheet */
437 randsheet_create( randsheet *rs )
439 rs -> occupied = (int*) malloc(board_x_size*board_y_size * sizeof(int));
440 rs -> xpos = (int*) malloc(numsquares * sizeof(int));
441 rs -> ypos = (int*) malloc(numsquares * sizeof(int));
442 rs -> direction = (int*) malloc(numsquares * sizeof(int));
443 rs -> angle = (float*) malloc(numsquares * sizeof(float));
444 rs -> color = (float*) malloc(numsquares*3 * sizeof(float));
447 /* Free reserved memory for the randsheet */
449 randsheet_free( randsheet *rs )
460 randsheet_initialize( randsheet *rs )
464 /* put the moving sheets on the board */
465 for( i = 0; i < board_x_size; i++ )
467 for( j = 0; j < board_y_size; j++ )
469 /* initially fill up a corner with the moving squares */
470 if( index < numsquares )
472 rs->occupied[ i * board_y_size + j ] = index;
473 rs->xpos[ index ] = i;
474 rs->ypos[ index ] = j;
475 /* have the square colors start out as a pattern */
476 rs->color[ index*3 + 0 ] = ((i+j)%3 == 0)||((i+j+1)%3 == 0);
477 rs->color[ index*3 + 1 ] = ((i+j+1)%3 == 0);
478 rs->color[ index*3 + 2 ] = ((i+j+2)%3 == 0);
481 /* leave everything else empty*/
484 rs->occupied[ i * board_y_size + j ] = -1;
488 /* initially everything is at rest */
489 for( i=0; i<numsquares; i++ )
491 rs->direction[ i ] = 0;
496 /* Pick and random square and direction and try to move it. */
497 /* May not actually move anything, just attempt a random move. */
498 /* Returns true if move was sucessful. */
499 /* This could probably be implemented faster in a dequeue */
500 /* to avoid trying to move a square which is already moving */
501 /* but speed is most likely bottlenecked by rendering anyway... */
503 randsheet_new_move( randsheet* rs )
507 /* pick a random square */
508 num = random( ) % numsquares;
511 /* pick a random direction */
512 dir = ( random( )% 4 ) + 1;
514 if( rs->direction[ num ] == 0 )
520 if( ( i + 1 ) < board_x_size )
522 if( rs->occupied[ (i + 1) * board_y_size + j ] == -1 )
524 rs->direction[ num ] = dir;
525 rs->occupied[ (i + 1) * board_y_size + j ] = num;
526 rs->occupied[ i * board_y_size + j ] = -1;
534 if( ( j + 1 ) < board_y_size )
536 if( rs->occupied[ i * board_y_size + (j + 1) ] == -1 )
538 rs->direction[ num ] = dir;
539 rs->occupied[ i * board_y_size + (j + 1) ] = num;
540 rs->occupied[ i * board_y_size + j ] = -1;
550 if( rs->occupied[ (i - 1) * board_y_size + j ] == -1 )
552 rs->direction[ num ] = dir;
553 rs->occupied[ (i - 1) * board_y_size + j ] = num;
554 rs->occupied[ i * board_y_size + j ] = -1;
564 if( rs->occupied[ i * board_y_size + (j - 1) ] == -1 )
566 rs->direction[ num ] = dir;
567 rs->occupied[ i * board_y_size + (j - 1) ] = num;
568 rs->occupied[ i * board_y_size + j ] = -1;
581 /* move a single frame. */
582 /* Pass in the angle in rads the square rotates in a frame. */
584 randsheet_move( randsheet *rs, float rot )
587 for( index = 0 ; index < numsquares; index++ )
589 i = rs->xpos[ index ];
590 j = rs->ypos[ index ];
591 switch( rs->direction[ index ] )
598 rs->angle[ index ] += rot;
599 /* check to see if we have finished moving */
600 if( rs->angle[ index ] >= M_PI )
602 rs->xpos[ index ] += 1;
603 rs->direction[ index ] = 0;
604 rs->angle[ index ] = 0;
609 rs->angle[ index ] += rot;
610 /* check to see if we have finished moving */
611 if( rs->angle[ index ] >= M_PI )
613 rs->ypos[ index ] += 1;
614 rs->direction[ index ] = 0;
615 rs->angle[ index ] = 0;
620 rs->angle[ index ] += rot;
621 /* check to see if we have finished moving */
622 if( rs->angle[ index ] >= M_PI )
624 rs->xpos[ index ] -= 1;
625 rs->direction[ index ] = 0;
626 rs->angle[ index ] = 0;
631 rs->angle[ index ] += rot;
632 /* check to see if we have finished moving */
633 if( rs->angle[ index ] >= M_PI )
635 rs->ypos[ index ] -= 1;
636 rs->direction[ index ] = 0;
637 rs->angle[ index ] = 0;
647 /* draw all the moving squares */
649 randsheet_draw( randsheet *rs )
653 /* for all moving squares ... */
654 for( index = 0; index < numsquares; index++ )
657 glColor3f( rs->color[ index*3 + 0 ],
658 rs->color[ index*3 + 1 ],
659 rs->color[ index*3 + 2 ] );
660 /* find x and y position */
661 i = rs->xpos[ index ];
662 j = rs->ypos[ index ];
664 switch( rs->direction[ index ] )
670 glTranslatef( i, 0, j );
673 glTranslatef( i+1, 0, j );
674 glRotatef( 180 - rs->angle[ index ]*180/M_PI, 0, 0, 1 );
678 glTranslatef( i, 0, j+1 );
679 glRotatef( 180 - rs->angle[ index ]*180/M_PI, -1, 0, 0 );
683 glTranslatef( i, 0, j );
684 glRotatef( rs->angle[ index ]*180/M_PI, 0, 0, 1 );
687 glTranslatef( i, 0, j );
688 glRotatef( rs->angle[ index ]*180/M_PI, -1, 0, 0 );
699 /**** END RANDSHEET_BAK FUNCTIONS ***/
701 XSCREENSAVER_MODULE ("Flipflop", flipflop)