1 /* flipflop, Copyright (c) 2003 Kevin Ogden <kogden1@hotmail.com>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
14 #define HALFTHICK 0.04
17 #define DEFAULTS "*delay: 20000 \n" \
18 "*showFPS: False \n" \
19 "*wireframe: False \n"
21 # define refresh_flipflop 0
22 # include "xlockmore.h"
30 #include "gltrackball.h"
33 #define countof(x) (sizeof((x))/sizeof((*x)))
35 static XrmOptionDescRec opts[] = {
36 {"+rotate", ".flipflop.rotate", XrmoptionNoArg, "false" },
37 {"-rotate", ".flipflop.rotate", XrmoptionNoArg, "true" },
42 static int rotate, wire, clearbits;
44 static argtype vars[] = {
45 { &rotate, "rotate", "Rotate", "True", t_Bool},
48 ENTRYPOINT ModeSpecOpt flipflop_opts = {countof(opts), opts, countof(vars), vars, NULL};
51 ModStruct flipflop_description =
52 {"flipflop", "init_flipflop", "draw_flipflop", "release_flipflop",
53 "draw_flipflop", "init_flipflop", NULL, &flipflop_opts,
54 1000, 1, 2, 1, 4, 1.0, "",
60 /* 2D array specifying which squares are where (to avoid collisions) */
61 /* -1 means empty otherwise integer represents square index 0 - n-1 */
62 int occupied[ BOARDSIZE ][ BOARDSIZE ];
63 /* an array of xpositions of the squares */
64 int xpos[ NUMSQUARES ];
65 /* array of y positions of the squares */
66 int ypos[ NUMSQUARES ];
67 /* integer representing the direction of movement of a square */
68 int direction[ NUMSQUARES ]; /* 0 not, 1 x+, 2 y+, 3 x-, 4 y-*/
69 /* angle of moving square (during a flip) */
70 float angle[ NUMSQUARES ];
71 /* array of colors for a square. rgb */
72 /* eg. color[ 4 ][ 0 ] is the red component of square 4 */
73 /* eg. color[ 5 ][ 2 ] is the blue component of square 5 */
74 float color[ NUMSQUARES ][ 3 ];
75 /* n is the number of square */
80 GLXContext *glx_context;
82 trackball_state *trackball;
88 float flipspeed; /* amount of flip. 1 is a entire flip */
89 float reldist; /* relative distace of camera from center */
90 float energy; /* likelehood a square will attempt a move */
94 static Flipflopcreen *qs = NULL;
97 static void randsheet_initialize( randsheet *rs );
98 static int randsheet_new_move( randsheet* rs );
99 static int randsheet_new_move( randsheet* rs );
100 static void randsheet_move( randsheet *rs, float rot );
101 static void randsheet_draw( randsheet *rs );
102 static void setup_lights(void);
103 static void drawBoard(Flipflopcreen *);
104 static void display(Flipflopcreen *c);
105 static void draw_sheet(void);
108 /* configure lighting */
112 /* GLfloat position0[] = { BOARDSIZE*0.5, BOARDSIZE*0.1, BOARDSIZE*0.5, 1.0 }; */
114 /* GLfloat position0[] = { -BOARDSIZE*0.5, 0.2*BOARDSIZE, -BOARDSIZE*0.5, 1.0 }; */
115 GLfloat position0[] = { 0, BOARDSIZE*0.3, 0, 1.0 };
119 glEnable(GL_LIGHTING);
120 glLightfv(GL_LIGHT0, GL_POSITION, position0);
125 flipflop_handle_event (ModeInfo *mi, XEvent *event)
127 Flipflopcreen *c = &qs[MI_SCREEN(mi)];
129 if (event->xany.type == ButtonPress &&
130 event->xbutton.button == Button1)
132 c->button_down_p = True;
133 gltrackball_start (c->trackball,
134 event->xbutton.x, event->xbutton.y,
135 MI_WIDTH (mi), MI_HEIGHT (mi));
138 else if (event->xany.type == ButtonRelease &&
139 event->xbutton.button == Button1)
141 c->button_down_p = False;
144 else if (event->xany.type == ButtonPress &&
145 (event->xbutton.button == Button4 ||
146 event->xbutton.button == Button5))
148 gltrackball_mousewheel (c->trackball, event->xbutton.button, 5,
149 !event->xbutton.state);
152 else if (event->xany.type == MotionNotify &&
155 gltrackball_track (c->trackball,
156 event->xmotion.x, event->xmotion.y,
157 MI_WIDTH (mi), MI_HEIGHT (mi));
166 drawBoard(Flipflopcreen *c)
169 for( i=0; i < (c->energy) ; i++ )
170 randsheet_new_move( &c->sheet );
171 randsheet_move( &c->sheet, c->flipspeed * 3.14159 );
172 randsheet_draw( &c->sheet );
177 display(Flipflopcreen *c)
179 GLfloat amb[] = { 0.8, 0.8, 0.8, 1.0 };
183 glMatrixMode(GL_MODELVIEW);
186 glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.2);
187 glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.15/BOARDSIZE );
188 glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.15/BOARDSIZE );
189 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
192 /** setup perspectif */
193 glTranslatef(0.0, 0.0, -c->reldist*BOARDSIZE);
194 glRotatef(22.5, 1.0, 0.0, 0.0);
195 gltrackball_rotate (c->trackball);
196 glRotatef(c->theta*100, 0.0, 1.0, 0.0);
197 glTranslatef(-0.5*BOARDSIZE, 0.0, -0.5*BOARDSIZE);
201 if (!c->button_down_p)
207 reshape_flipflop(ModeInfo *mi, int width, int height)
209 GLfloat h = (GLfloat) height / (GLfloat) width;
210 glViewport(0,0, width, height);
211 glMatrixMode(GL_PROJECTION);
213 gluPerspective(45, 1/h, 1.0, 300.0);
214 glMatrixMode(GL_MODELVIEW);
218 init_flipflop(ModeInfo *mi)
220 int screen = MI_SCREEN(mi);
222 wire = MI_IS_WIREFRAME(mi);
225 !(qs = (Flipflopcreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Flipflopcreen))))
229 c->window = MI_WINDOW(mi);
230 c->trackball = gltrackball_init ();
236 if((c->glx_context = init_GL(mi)))
237 reshape_flipflop(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
241 glClearColor(0.0, 0.0, 0.0, 0.0);
243 clearbits = GL_COLOR_BUFFER_BIT;
245 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
246 glEnable(GL_COLOR_MATERIAL);
249 glEnable(GL_DEPTH_TEST);
250 clearbits |= GL_DEPTH_BUFFER_BIT;
251 glEnable(GL_CULL_FACE);
253 randsheet_initialize( &c->sheet );
259 draw_flipflop(ModeInfo *mi)
261 Flipflopcreen *c = &qs[MI_SCREEN(mi)];
262 Window w = MI_WINDOW(mi);
263 Display *disp = MI_DISPLAY(mi);
268 glXMakeCurrent(disp, w, *(c->glx_context));
277 glXSwapBuffers(disp, w);
283 release_flipflop(ModeInfo *mi)
292 /*** ADDED RANDSHEET FUNCTIONS ***/
297 glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
299 glNormal3f( 0, -1, 0 );
300 glVertex3f( HALFTHICK, -HALFTHICK, HALFTHICK );
301 glVertex3f( 1-HALFTHICK, -HALFTHICK, HALFTHICK );
302 glVertex3f( 1-HALFTHICK, -HALFTHICK, 1-HALFTHICK);
303 glVertex3f( HALFTHICK, -HALFTHICK, 1-HALFTHICK );
305 if (wire) { glEnd(); glBegin (GL_LINE_LOOP); }
308 glNormal3f( 0, 1, 0 );
309 glVertex3f( HALFTHICK, HALFTHICK, 1-HALFTHICK );
310 glVertex3f( 1-HALFTHICK, HALFTHICK, 1-HALFTHICK);
311 glVertex3f( 1-HALFTHICK, HALFTHICK, HALFTHICK );
312 glVertex3f( HALFTHICK, HALFTHICK, HALFTHICK );
314 if (wire) { glEnd(); return; }
316 /* 4 edges!!! weee.... */
317 glNormal3f( 0, 0, -1 );
318 glVertex3f( HALFTHICK, HALFTHICK, HALFTHICK );
319 glVertex3f( 1-HALFTHICK, HALFTHICK, HALFTHICK );
320 glVertex3f( 1-HALFTHICK, -HALFTHICK, HALFTHICK );
321 glVertex3f( HALFTHICK, -HALFTHICK, HALFTHICK );
322 glNormal3f( 0, 0, 1 );
323 glVertex3f( HALFTHICK, HALFTHICK, 1-HALFTHICK );
324 glVertex3f( HALFTHICK, -HALFTHICK, 1-HALFTHICK );
325 glVertex3f( 1-HALFTHICK, -HALFTHICK, 1-HALFTHICK );
326 glVertex3f( 1-HALFTHICK, HALFTHICK, 1-HALFTHICK );
327 glNormal3f( 1, 0, 0 );
328 glVertex3f( 1-HALFTHICK, HALFTHICK, 1-HALFTHICK );
329 glVertex3f( 1-HALFTHICK, -HALFTHICK, 1-HALFTHICK );
330 glVertex3f( 1-HALFTHICK, -HALFTHICK, HALFTHICK );
331 glVertex3f( 1-HALFTHICK, HALFTHICK, HALFTHICK );
332 glNormal3f( -1, 0, 0 );
333 glVertex3f( HALFTHICK, HALFTHICK, 1-HALFTHICK );
334 glVertex3f( HALFTHICK, HALFTHICK, HALFTHICK );
335 glVertex3f( HALFTHICK, -HALFTHICK, HALFTHICK );
336 glVertex3f( HALFTHICK, -HALFTHICK, 1-HALFTHICK );
341 randsheet_initialize( randsheet *rs )
345 /* put the moving sheets on the board */
346 for( i = 0; i < BOARDSIZE; i++ )
348 for( j = 0; j < BOARDSIZE; j++ )
350 /* initially fill up a corner with the moving squares */
351 if( index < NUMSQUARES )
353 rs->occupied[ i ][ j ] = index;
354 rs->xpos[ index ] = i;
355 rs->ypos[ index ] = j;
356 /* have the square colors start out as a pattern */
357 rs->color[ index ][ 0 ] = ((i+j)%3 == 0)||((i+j+1)%3 == 0);
358 rs->color[ index ][ 1 ] = ((i+j+1)%3 == 0);
359 rs->color[ index ][ 2 ] = ((i+j+2)%3 == 0);
362 /* leave everything else empty*/
365 rs->occupied[ i ][ j ] = -1;
369 /* initially everything is at rest */
370 for( i=0; i<NUMSQUARES; i++ )
372 rs->direction[ i ] = 0;
377 /* Pick and random square and direction and try to move it. */
378 /* May not actually move anything, just attempt a random move. */
379 /* Returns true if move was sucessful. */
380 /* This could probably be implemented faster in a dequeue */
381 /* to avoid trying to move a square which is already moving */
382 /* but speed is most likely bottlenecked by rendering anyway... */
384 randsheet_new_move( randsheet* rs )
388 /* pick a random square */
389 num = random( ) % NUMSQUARES;
392 /* pick a random direction */
393 dir = ( random( )% 4 ) + 1;
395 if( rs->direction[ num ] == 0 )
401 if( ( i + 1 ) < BOARDSIZE )
403 if( rs->occupied[ i + 1 ][ j ] == -1 )
405 rs->direction[ num ] = dir;
406 rs->occupied[ i + 1 ][ j ] = num;
407 rs->occupied[ i ][ j ] = -1;
415 if( ( j + 1 ) < BOARDSIZE )
417 if( rs->occupied[ i ][ j + 1 ] == -1 )
419 rs->direction[ num ] = dir;
420 rs->occupied[ i ][ j + 1 ] = num;
421 rs->occupied[ i ][ j ] = -1;
431 if( rs->occupied[ i - 1][ j ] == -1 )
433 rs->direction[ num ] = dir;
434 rs->occupied[ i - 1][ j ] = num;
435 rs->occupied[ i ][ j ] = -1;
445 if( rs->occupied[ i ][ j - 1 ] == -1 )
447 rs->direction[ num ] = dir;
448 rs->occupied[ i ][ j - 1 ] = num;
449 rs->occupied[ i ][ j ] = -1;
462 /* move a single frame. */
463 /* Pass in the angle in rads the square rotates in a frame. */
465 randsheet_move( randsheet *rs, float rot )
468 for( index = 0 ; index < NUMSQUARES; index++ )
470 i = rs->xpos[ index ];
471 j = rs->ypos[ index ];
472 switch( rs->direction[ index ] )
479 rs->angle[ index ] += rot;
480 /* check to see if we have finished moving */
481 if( rs->angle[ index ] >= M_PI )
483 rs->xpos[ index ] += 1;
484 rs->direction[ index ] = 0;
485 rs->angle[ index ] = 0;
490 rs->angle[ index ] += rot;
491 /* check to see if we have finished moving */
492 if( rs->angle[ index ] >= M_PI )
494 rs->ypos[ index ] += 1;
495 rs->direction[ index ] = 0;
496 rs->angle[ index ] = 0;
501 rs->angle[ index ] += rot;
502 /* check to see if we have finished moving */
503 if( rs->angle[ index ] >= M_PI )
505 rs->xpos[ index ] -= 1;
506 rs->direction[ index ] = 0;
507 rs->angle[ index ] = 0;
512 rs->angle[ index ] += rot;
513 /* check to see if we have finished moving */
514 if( rs->angle[ index ] >= M_PI )
516 rs->ypos[ index ] -= 1;
517 rs->direction[ index ] = 0;
518 rs->angle[ index ] = 0;
528 /* draw all the moving squares */
530 randsheet_draw( randsheet *rs )
534 /* for all moving squares ... */
535 for( index = 0; index < NUMSQUARES; index++ )
538 glColor3f( rs->color[ index ][ 0 ],
539 rs->color[ index ][ 1 ],
540 rs->color[ index ][ 2 ] );
541 /* find x and y position */
542 i = rs->xpos[ index ];
543 j = rs->ypos[ index ];
545 switch( rs->direction[ index ] )
551 glTranslatef( i, 0, j );
554 glTranslatef( i+1, 0, j );
555 glRotatef( 180 - rs->angle[ index ]*180/M_PI, 0, 0, 1 );
559 glTranslatef( i, 0, j+1 );
560 glRotatef( 180 - rs->angle[ index ]*180/M_PI, -1, 0, 0 );
564 glTranslatef( i, 0, j );
565 glRotatef( rs->angle[ index ]*180/M_PI, 0, 0, 1 );
568 glTranslatef( i, 0, j );
569 glRotatef( rs->angle[ index ]*180/M_PI, -1, 0, 0 );
580 /**** END RANDSHEET FUNCTIONS ***/
582 XSCREENSAVER_MODULE ("Flipflop", flipflop)