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 == MotionNotify &&
166 gltrackball_track (c->trackball,
167 event->xmotion.x, event->xmotion.y,
168 MI_WIDTH (mi), MI_HEIGHT (mi));
180 for( i=0; i < (energy) ; i++ )
181 randsheet_new_move( &MyRandSheet );
182 randsheet_move( &MyRandSheet, flipspeed * 3.14159 );
183 randsheet_draw( &MyRandSheet );
188 display(Flipflopcreen *c)
190 GLfloat amb[] = { 0.8, 0.8, 0.8, 1.0 };
194 glMatrixMode(GL_MODELVIEW);
197 glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.2);
198 glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.15/BOARDSIZE );
199 glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.15/BOARDSIZE );
200 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
203 /** setup perspectif */
204 glTranslatef(0.0, 0.0, -reldist*BOARDSIZE);
205 glRotatef(22.5, 1.0, 0.0, 0.0);
206 gltrackball_rotate (c->trackball);
207 glRotatef(theta*100, 0.0, 1.0, 0.0);
208 glTranslatef(-0.5*BOARDSIZE, 0.0, -0.5*BOARDSIZE);
212 if (!c->button_down_p)
218 reshape_flipflop(ModeInfo *mi, int width, int height)
220 GLfloat h = (GLfloat) height / (GLfloat) width;
221 glViewport(0,0, width, height);
222 glMatrixMode(GL_PROJECTION);
224 gluPerspective(45, 1/h, 1.0, 300.0);
225 glMatrixMode(GL_MODELVIEW);
229 init_flipflop(ModeInfo *mi)
231 int screen = MI_SCREEN(mi);
233 wire = MI_IS_WIREFRAME(mi);
236 !(qs = (Flipflopcreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Flipflopcreen))))
240 c->window = MI_WINDOW(mi);
241 c->trackball = gltrackball_init ();
243 if((c->glx_context = init_GL(mi)))
244 reshape_flipflop(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
248 glClearColor(0.0, 0.0, 0.0, 0.0);
250 clearbits = GL_COLOR_BUFFER_BIT;
252 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
253 glEnable(GL_COLOR_MATERIAL);
256 glEnable(GL_DEPTH_TEST);
257 clearbits |= GL_DEPTH_BUFFER_BIT;
258 glEnable(GL_CULL_FACE);
260 randsheet_initialize( &MyRandSheet );
266 draw_flipflop(ModeInfo *mi)
268 Flipflopcreen *c = &qs[MI_SCREEN(mi)];
269 Window w = MI_WINDOW(mi);
270 Display *disp = MI_DISPLAY(mi);
275 glXMakeCurrent(disp, w, *(c->glx_context));
284 glXSwapBuffers(disp, w);
290 release_flipflop(ModeInfo *mi)
298 /*** ADDED RANDSHEET FUNCTIONS ***/
303 glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
305 glNormal3f( 0, -1, 0 );
306 glVertex3f( HALFTHICK, -HALFTHICK, HALFTHICK );
307 glVertex3f( 1-HALFTHICK, -HALFTHICK, HALFTHICK );
308 glVertex3f( 1-HALFTHICK, -HALFTHICK, 1-HALFTHICK);
309 glVertex3f( HALFTHICK, -HALFTHICK, 1-HALFTHICK );
311 if (wire) { glEnd(); glBegin (GL_LINE_LOOP); }
314 glNormal3f( 0, 1, 0 );
315 glVertex3f( HALFTHICK, HALFTHICK, 1-HALFTHICK );
316 glVertex3f( 1-HALFTHICK, HALFTHICK, 1-HALFTHICK);
317 glVertex3f( 1-HALFTHICK, HALFTHICK, HALFTHICK );
318 glVertex3f( HALFTHICK, HALFTHICK, HALFTHICK );
320 if (wire) { glEnd(); return; }
322 /* 4 edges!!! weee.... */
323 glNormal3f( 0, 0, -1 );
324 glVertex3f( HALFTHICK, HALFTHICK, HALFTHICK );
325 glVertex3f( 1-HALFTHICK, HALFTHICK, HALFTHICK );
326 glVertex3f( 1-HALFTHICK, -HALFTHICK, HALFTHICK );
327 glVertex3f( HALFTHICK, -HALFTHICK, HALFTHICK );
328 glNormal3f( 0, 0, 1 );
329 glVertex3f( HALFTHICK, HALFTHICK, 1-HALFTHICK );
330 glVertex3f( HALFTHICK, -HALFTHICK, 1-HALFTHICK );
331 glVertex3f( 1-HALFTHICK, -HALFTHICK, 1-HALFTHICK );
332 glVertex3f( 1-HALFTHICK, HALFTHICK, 1-HALFTHICK );
333 glNormal3f( 1, 0, 0 );
334 glVertex3f( 1-HALFTHICK, HALFTHICK, 1-HALFTHICK );
335 glVertex3f( 1-HALFTHICK, -HALFTHICK, 1-HALFTHICK );
336 glVertex3f( 1-HALFTHICK, -HALFTHICK, HALFTHICK );
337 glVertex3f( 1-HALFTHICK, HALFTHICK, HALFTHICK );
338 glNormal3f( -1, 0, 0 );
339 glVertex3f( HALFTHICK, HALFTHICK, 1-HALFTHICK );
340 glVertex3f( HALFTHICK, HALFTHICK, HALFTHICK );
341 glVertex3f( HALFTHICK, -HALFTHICK, HALFTHICK );
342 glVertex3f( HALFTHICK, -HALFTHICK, 1-HALFTHICK );
347 randsheet_initialize( randsheet *rs )
351 /* put the moving sheets on the board */
352 for( i = 0; i < BOARDSIZE; i++ )
354 for( j = 0; j < BOARDSIZE; j++ )
356 /* initially fill up a corner with the moving squares */
357 if( index < NUMSQUARES )
359 rs->occupied[ i ][ j ] = index;
360 rs->xpos[ index ] = i;
361 rs->ypos[ index ] = j;
362 /* have the square colors start out as a pattern */
363 rs->color[ index ][ 0 ] = ((i+j)%3 == 0)||((i+j+1)%3 == 0);
364 rs->color[ index ][ 1 ] = ((i+j+1)%3 == 0);
365 rs->color[ index ][ 2 ] = ((i+j+2)%3 == 0);
368 /* leave everything else empty*/
371 rs->occupied[ i ][ j ] = -1;
375 /* initially everything is at rest */
376 for( i=0; i<NUMSQUARES; i++ )
378 rs->direction[ i ] = 0;
383 /* Pick and random square and direction and try to move it. */
384 /* May not actually move anything, just attempt a random move. */
385 /* Returns true if move was sucessful. */
386 /* This could probably be implemented faster in a dequeue */
387 /* to avoid trying to move a square which is already moving */
388 /* but speed is most likely bottlenecked by rendering anyway... */
390 randsheet_new_move( randsheet* rs )
394 /* pick a random square */
395 num = random( ) % NUMSQUARES;
398 /* pick a random direction */
399 dir = ( random( )% 4 ) + 1;
401 if( rs->direction[ num ] == 0 )
407 if( ( i + 1 ) < BOARDSIZE )
409 if( rs->occupied[ i + 1 ][ j ] == -1 )
411 rs->direction[ num ] = dir;
412 rs->occupied[ i + 1 ][ j ] = num;
413 rs->occupied[ i ][ j ] = -1;
421 if( ( j + 1 ) < BOARDSIZE )
423 if( rs->occupied[ i ][ j + 1 ] == -1 )
425 rs->direction[ num ] = dir;
426 rs->occupied[ i ][ j + 1 ] = num;
427 rs->occupied[ i ][ j ] = -1;
437 if( rs->occupied[ i - 1][ j ] == -1 )
439 rs->direction[ num ] = dir;
440 rs->occupied[ i - 1][ j ] = num;
441 rs->occupied[ i ][ j ] = -1;
451 if( rs->occupied[ i ][ j - 1 ] == -1 )
453 rs->direction[ num ] = dir;
454 rs->occupied[ i ][ j - 1 ] = num;
455 rs->occupied[ i ][ j ] = -1;
468 /* move a single frame. */
469 /* Pass in the angle in rads the square rotates in a frame. */
471 randsheet_move( randsheet *rs, float rot )
474 for( index = 0 ; index < NUMSQUARES; index++ )
476 i = rs->xpos[ index ];
477 j = rs->ypos[ index ];
478 switch( rs->direction[ index ] )
485 rs->angle[ index ] += rot;
486 /* check to see if we have finished moving */
487 if( rs->angle[ index ] >= M_PI )
489 rs->xpos[ index ] += 1;
490 rs->direction[ index ] = 0;
491 rs->angle[ index ] = 0;
496 rs->angle[ index ] += rot;
497 /* check to see if we have finished moving */
498 if( rs->angle[ index ] >= M_PI )
500 rs->ypos[ index ] += 1;
501 rs->direction[ index ] = 0;
502 rs->angle[ index ] = 0;
507 rs->angle[ index ] += rot;
508 /* check to see if we have finished moving */
509 if( rs->angle[ index ] >= M_PI )
511 rs->xpos[ index ] -= 1;
512 rs->direction[ index ] = 0;
513 rs->angle[ index ] = 0;
518 rs->angle[ index ] += rot;
519 /* check to see if we have finished moving */
520 if( rs->angle[ index ] >= M_PI )
522 rs->ypos[ index ] -= 1;
523 rs->direction[ index ] = 0;
524 rs->angle[ index ] = 0;
534 /* draw all the moving squares */
536 randsheet_draw( randsheet *rs )
540 /* for all moving squares ... */
541 for( index = 0; index < NUMSQUARES; index++ )
544 glColor3f( rs->color[ index ][ 0 ],
545 rs->color[ index ][ 1 ],
546 rs->color[ index ][ 2 ] );
547 /* find x and y position */
548 i = rs->xpos[ index ];
549 j = rs->ypos[ index ];
551 switch( rs->direction[ index ] )
557 glTranslatef( i, 0, j );
560 glTranslatef( i+1, 0, j );
561 glRotatef( 180 - rs->angle[ index ]*180/M_PI, 0, 0, 1 );
565 glTranslatef( i, 0, j+1 );
566 glRotatef( 180 - rs->angle[ index ]*180/M_PI, -1, 0, 0 );
570 glTranslatef( i, 0, j );
571 glRotatef( rs->angle[ index ]*180/M_PI, 0, 0, 1 );
574 glTranslatef( i, 0, j );
575 glRotatef( rs->angle[ index ]*180/M_PI, -1, 0, 0 );
586 /**** END RANDSHEET FUNCTIONS ***/