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
12 #include <X11/Intrinsic.h>
21 #define HALFTHICK 0.04
24 # define PROGCLASS "Flipflop"
25 # define HACK_INIT init_flipflop
26 # define HACK_DRAW draw_flipflop
27 # define HACK_RESHAPE reshape_flipflop
28 # define HACK_HANDLE_EVENT flipflop_handle_event
29 # define EVENT_MASK PointerMotionMask
30 # define flipflop_opts xlockmore_opts
32 #define DEFAULTS "*delay: 20000 \n" \
33 "*showFPS: False \n" \
34 "*wireframe: False \n"
36 # include "xlockmore.h"
45 #include "gltrackball.h"
48 #define countof(x) (sizeof((x))/sizeof((*x)))
50 static XrmOptionDescRec opts[] = {
51 {"+rotate", ".flipflop.rotate", XrmoptionNoArg, "false" },
52 {"-rotate", ".flipflop.rotate", XrmoptionNoArg, "true" },
57 static int rotate, wire, clearbits;
59 static argtype vars[] = {
60 { &rotate, "rotate", "Rotate", "True", t_Bool},
63 ModeSpecOpt flipflop_opts = {countof(opts), opts, countof(vars), vars, NULL};
66 ModStruct flipflop_description =
67 {"flipflop", "init_flipflop", "draw_flipflop", "release_flipflop",
68 "draw_flipflop", "init_flipflop", NULL, &flipflop_opts,
69 1000, 1, 2, 1, 4, 1.0, "",
75 GLXContext *glx_context;
77 trackball_state *trackball;
81 static Flipflopcreen *qs = NULL;
84 /* 2D array specifying which squares are where (to avoid collisions) */
85 /* -1 means empty otherwise integer represents square index 0 - n-1 */
86 int occupied[ BOARDSIZE ][ BOARDSIZE ];
87 /* an array of xpositions of the squares */
88 int xpos[ NUMSQUARES ];
89 /* array of y positions of the squares */
90 int ypos[ NUMSQUARES ];
91 /* integer representing the direction of movement of a square */
92 int direction[ NUMSQUARES ]; /* 0 not, 1 x+, 2 y+, 3 x-, 4 y-*/
93 /* angle of moving square (during a flip) */
94 float angle[ NUMSQUARES ];
95 /* array of colors for a square. rgb */
96 /* eg. color[ 4 ][ 0 ] is the red component of square 4 */
97 /* eg. color[ 5 ][ 2 ] is the blue component of square 5 */
98 float color[ NUMSQUARES ][ 3 ];
99 /* n is the number of square */
103 /*** ADDED RANDSHEET VARS ***/
105 static randsheet MyRandSheet;
107 static double theta = 0.0;
108 /* amount which the square flips. 1 is a entire flip */
109 static float flipspeed = 0.03;
110 /* relative distace of camera from center */
111 static float reldist = 1;
112 /* likelehood a square will attempt a move */
113 static float energy = 40;
116 static void randsheet_initialize( randsheet *rs );
117 static int randsheet_new_move( randsheet* rs );
118 static int randsheet_new_move( randsheet* rs );
119 static void randsheet_move( randsheet *rs, float rot );
120 static void randsheet_draw( randsheet *rs );
121 static void setup_lights(void);
122 static void drawBoard(void);
123 static void display(Flipflopcreen *c);
124 static void draw_sheet(void);
127 /* configure lighting */
131 /* GLfloat position0[] = { BOARDSIZE*0.5, BOARDSIZE*0.1, BOARDSIZE*0.5, 1.0 }; */
133 /* GLfloat position0[] = { -BOARDSIZE*0.5, 0.2*BOARDSIZE, -BOARDSIZE*0.5, 1.0 }; */
134 GLfloat position0[] = { 0, BOARDSIZE*0.3, 0, 1.0 };
138 glEnable(GL_LIGHTING);
139 glLightfv(GL_LIGHT0, GL_POSITION, position0);
144 flipflop_handle_event (ModeInfo *mi, XEvent *event)
146 Flipflopcreen *c = &qs[MI_SCREEN(mi)];
148 if (event->xany.type == ButtonPress &&
149 event->xbutton.button == Button1)
151 c->button_down_p = True;
152 gltrackball_start (c->trackball,
153 event->xbutton.x, event->xbutton.y,
154 MI_WIDTH (mi), MI_HEIGHT (mi));
157 else if (event->xany.type == ButtonRelease &&
158 event->xbutton.button == Button1)
160 c->button_down_p = False;
163 else if (event->xany.type == ButtonPress &&
164 (event->xbutton.button == Button4 ||
165 event->xbutton.button == Button5))
167 gltrackball_mousewheel (c->trackball, event->xbutton.button, 5,
168 !event->xbutton.state);
171 else if (event->xany.type == MotionNotify &&
174 gltrackball_track (c->trackball,
175 event->xmotion.x, event->xmotion.y,
176 MI_WIDTH (mi), MI_HEIGHT (mi));
188 for( i=0; i < (energy) ; i++ )
189 randsheet_new_move( &MyRandSheet );
190 randsheet_move( &MyRandSheet, flipspeed * 3.14159 );
191 randsheet_draw( &MyRandSheet );
196 display(Flipflopcreen *c)
198 GLfloat amb[] = { 0.8, 0.8, 0.8, 1.0 };
202 glMatrixMode(GL_MODELVIEW);
205 glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.2);
206 glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.15/BOARDSIZE );
207 glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.15/BOARDSIZE );
208 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
211 /** setup perspectif */
212 glTranslatef(0.0, 0.0, -reldist*BOARDSIZE);
213 glRotatef(22.5, 1.0, 0.0, 0.0);
214 gltrackball_rotate (c->trackball);
215 glRotatef(theta*100, 0.0, 1.0, 0.0);
216 glTranslatef(-0.5*BOARDSIZE, 0.0, -0.5*BOARDSIZE);
220 if (!c->button_down_p)
226 reshape_flipflop(ModeInfo *mi, int width, int height)
228 GLfloat h = (GLfloat) height / (GLfloat) width;
229 glViewport(0,0, width, height);
230 glMatrixMode(GL_PROJECTION);
232 gluPerspective(45, 1/h, 1.0, 300.0);
233 glMatrixMode(GL_MODELVIEW);
237 init_flipflop(ModeInfo *mi)
239 int screen = MI_SCREEN(mi);
241 wire = MI_IS_WIREFRAME(mi);
244 !(qs = (Flipflopcreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Flipflopcreen))))
248 c->window = MI_WINDOW(mi);
249 c->trackball = gltrackball_init ();
251 if((c->glx_context = init_GL(mi)))
252 reshape_flipflop(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
256 glClearColor(0.0, 0.0, 0.0, 0.0);
258 clearbits = GL_COLOR_BUFFER_BIT;
260 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
261 glEnable(GL_COLOR_MATERIAL);
264 glEnable(GL_DEPTH_TEST);
265 clearbits |= GL_DEPTH_BUFFER_BIT;
266 glEnable(GL_CULL_FACE);
268 randsheet_initialize( &MyRandSheet );
274 draw_flipflop(ModeInfo *mi)
276 Flipflopcreen *c = &qs[MI_SCREEN(mi)];
277 Window w = MI_WINDOW(mi);
278 Display *disp = MI_DISPLAY(mi);
283 glXMakeCurrent(disp, w, *(c->glx_context));
292 glXSwapBuffers(disp, w);
298 release_flipflop(ModeInfo *mi)
306 /*** ADDED RANDSHEET FUNCTIONS ***/
311 glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
313 glNormal3f( 0, -1, 0 );
314 glVertex3f( HALFTHICK, -HALFTHICK, HALFTHICK );
315 glVertex3f( 1-HALFTHICK, -HALFTHICK, HALFTHICK );
316 glVertex3f( 1-HALFTHICK, -HALFTHICK, 1-HALFTHICK);
317 glVertex3f( HALFTHICK, -HALFTHICK, 1-HALFTHICK );
319 if (wire) { glEnd(); glBegin (GL_LINE_LOOP); }
322 glNormal3f( 0, 1, 0 );
323 glVertex3f( HALFTHICK, HALFTHICK, 1-HALFTHICK );
324 glVertex3f( 1-HALFTHICK, HALFTHICK, 1-HALFTHICK);
325 glVertex3f( 1-HALFTHICK, HALFTHICK, HALFTHICK );
326 glVertex3f( HALFTHICK, HALFTHICK, HALFTHICK );
328 if (wire) { glEnd(); return; }
330 /* 4 edges!!! weee.... */
331 glNormal3f( 0, 0, -1 );
332 glVertex3f( HALFTHICK, HALFTHICK, HALFTHICK );
333 glVertex3f( 1-HALFTHICK, HALFTHICK, HALFTHICK );
334 glVertex3f( 1-HALFTHICK, -HALFTHICK, HALFTHICK );
335 glVertex3f( HALFTHICK, -HALFTHICK, HALFTHICK );
336 glNormal3f( 0, 0, 1 );
337 glVertex3f( HALFTHICK, HALFTHICK, 1-HALFTHICK );
338 glVertex3f( HALFTHICK, -HALFTHICK, 1-HALFTHICK );
339 glVertex3f( 1-HALFTHICK, -HALFTHICK, 1-HALFTHICK );
340 glVertex3f( 1-HALFTHICK, HALFTHICK, 1-HALFTHICK );
341 glNormal3f( 1, 0, 0 );
342 glVertex3f( 1-HALFTHICK, HALFTHICK, 1-HALFTHICK );
343 glVertex3f( 1-HALFTHICK, -HALFTHICK, 1-HALFTHICK );
344 glVertex3f( 1-HALFTHICK, -HALFTHICK, HALFTHICK );
345 glVertex3f( 1-HALFTHICK, HALFTHICK, HALFTHICK );
346 glNormal3f( -1, 0, 0 );
347 glVertex3f( HALFTHICK, HALFTHICK, 1-HALFTHICK );
348 glVertex3f( HALFTHICK, HALFTHICK, HALFTHICK );
349 glVertex3f( HALFTHICK, -HALFTHICK, HALFTHICK );
350 glVertex3f( HALFTHICK, -HALFTHICK, 1-HALFTHICK );
355 randsheet_initialize( randsheet *rs )
359 /* put the moving sheets on the board */
360 for( i = 0; i < BOARDSIZE; i++ )
362 for( j = 0; j < BOARDSIZE; j++ )
364 /* initially fill up a corner with the moving squares */
365 if( index < NUMSQUARES )
367 rs->occupied[ i ][ j ] = index;
368 rs->xpos[ index ] = i;
369 rs->ypos[ index ] = j;
370 /* have the square colors start out as a pattern */
371 rs->color[ index ][ 0 ] = ((i+j)%3 == 0)||((i+j+1)%3 == 0);
372 rs->color[ index ][ 1 ] = ((i+j+1)%3 == 0);
373 rs->color[ index ][ 2 ] = ((i+j+2)%3 == 0);
376 /* leave everything else empty*/
379 rs->occupied[ i ][ j ] = -1;
383 /* initially everything is at rest */
384 for( i=0; i<NUMSQUARES; i++ )
386 rs->direction[ i ] = 0;
391 /* Pick and random square and direction and try to move it. */
392 /* May not actually move anything, just attempt a random move. */
393 /* Returns true if move was sucessful. */
394 /* This could probably be implemented faster in a dequeue */
395 /* to avoid trying to move a square which is already moving */
396 /* but speed is most likely bottlenecked by rendering anyway... */
398 randsheet_new_move( randsheet* rs )
402 /* pick a random square */
403 num = random( ) % NUMSQUARES;
406 /* pick a random direction */
407 dir = ( random( )% 4 ) + 1;
409 if( rs->direction[ num ] == 0 )
415 if( ( i + 1 ) < BOARDSIZE )
417 if( rs->occupied[ i + 1 ][ j ] == -1 )
419 rs->direction[ num ] = dir;
420 rs->occupied[ i + 1 ][ j ] = num;
421 rs->occupied[ i ][ j ] = -1;
429 if( ( j + 1 ) < BOARDSIZE )
431 if( rs->occupied[ i ][ j + 1 ] == -1 )
433 rs->direction[ num ] = dir;
434 rs->occupied[ i ][ j + 1 ] = num;
435 rs->occupied[ i ][ j ] = -1;
445 if( rs->occupied[ i - 1][ j ] == -1 )
447 rs->direction[ num ] = dir;
448 rs->occupied[ i - 1][ j ] = num;
449 rs->occupied[ i ][ j ] = -1;
459 if( rs->occupied[ i ][ j - 1 ] == -1 )
461 rs->direction[ num ] = dir;
462 rs->occupied[ i ][ j - 1 ] = num;
463 rs->occupied[ i ][ j ] = -1;
476 /* move a single frame. */
477 /* Pass in the angle in rads the square rotates in a frame. */
479 randsheet_move( randsheet *rs, float rot )
482 for( index = 0 ; index < NUMSQUARES; index++ )
484 i = rs->xpos[ index ];
485 j = rs->ypos[ index ];
486 switch( rs->direction[ index ] )
493 rs->angle[ index ] += rot;
494 /* check to see if we have finished moving */
495 if( rs->angle[ index ] >= M_PI )
497 rs->xpos[ index ] += 1;
498 rs->direction[ index ] = 0;
499 rs->angle[ index ] = 0;
504 rs->angle[ index ] += rot;
505 /* check to see if we have finished moving */
506 if( rs->angle[ index ] >= M_PI )
508 rs->ypos[ index ] += 1;
509 rs->direction[ index ] = 0;
510 rs->angle[ index ] = 0;
515 rs->angle[ index ] += rot;
516 /* check to see if we have finished moving */
517 if( rs->angle[ index ] >= M_PI )
519 rs->xpos[ index ] -= 1;
520 rs->direction[ index ] = 0;
521 rs->angle[ index ] = 0;
526 rs->angle[ index ] += rot;
527 /* check to see if we have finished moving */
528 if( rs->angle[ index ] >= M_PI )
530 rs->ypos[ index ] -= 1;
531 rs->direction[ index ] = 0;
532 rs->angle[ index ] = 0;
542 /* draw all the moving squares */
544 randsheet_draw( randsheet *rs )
548 /* for all moving squares ... */
549 for( index = 0; index < NUMSQUARES; index++ )
552 glColor3f( rs->color[ index ][ 0 ],
553 rs->color[ index ][ 1 ],
554 rs->color[ index ][ 2 ] );
555 /* find x and y position */
556 i = rs->xpos[ index ];
557 j = rs->ypos[ index ];
559 switch( rs->direction[ index ] )
565 glTranslatef( i, 0, j );
568 glTranslatef( i+1, 0, j );
569 glRotatef( 180 - rs->angle[ index ]*180/M_PI, 0, 0, 1 );
573 glTranslatef( i, 0, j+1 );
574 glRotatef( 180 - rs->angle[ index ]*180/M_PI, -1, 0, 0 );
578 glTranslatef( i, 0, j );
579 glRotatef( rs->angle[ index ]*180/M_PI, 0, 0, 1 );
582 glTranslatef( i, 0, j );
583 glRotatef( rs->angle[ index ]*180/M_PI, -1, 0, 0 );
594 /**** END RANDSHEET FUNCTIONS ***/