http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[xscreensaver] / hacks / glx / flipflop.c
1 /* flipflop, Copyright (c) 2003 Kevin Ogden <kogden1@hotmail.com>
2  *
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
9  * implied warranty.
10  */
11
12 #define BOARDSIZE 9
13 #define NUMSQUARES 76
14 #define HALFTHICK 0.04
15
16 #ifdef STANDALONE
17 #define DEFAULTS       "*delay:       20000       \n" \
18                        "*showFPS:       False       \n" \
19                        "*wireframe:     False     \n"
20
21 # define refresh_flipflop 0
22 # include "xlockmore.h"
23
24 #else
25 # include "xlock.h"
26 #endif
27
28 #ifdef USE_GL
29
30 #include "gltrackball.h"
31
32 #undef countof
33 #define countof(x) (sizeof((x))/sizeof((*x)))
34
35 static XrmOptionDescRec opts[] = {
36   {"+rotate", ".flipflop.rotate", XrmoptionNoArg, "false" },
37   {"-rotate", ".flipflop.rotate", XrmoptionNoArg, "true" },
38 };
39
40
41
42 static int rotate, wire, clearbits;
43
44 static argtype vars[] = {
45   { &rotate, "rotate", "Rotate", "True", t_Bool},
46 };
47
48 ENTRYPOINT ModeSpecOpt flipflop_opts = {countof(opts), opts, countof(vars), vars, NULL};
49
50 #ifdef USE_MODULES
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, "",
55  "Flipflop", 0, NULL};
56
57 #endif
58
59 typedef struct{
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 */
76 } randsheet;
77
78
79 typedef struct {
80   GLXContext *glx_context;
81   Window window;
82   trackball_state *trackball;
83   Bool button_down_p;
84
85   randsheet sheet;
86
87   double theta;
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 */
91
92 } Flipflopcreen;
93
94 static Flipflopcreen *qs = NULL;
95
96
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);
106
107
108 /* configure lighting */
109 static void
110 setup_lights(void)
111 {
112 /*   GLfloat position0[] = { BOARDSIZE*0.5, BOARDSIZE*0.1, BOARDSIZE*0.5, 1.0 }; */
113
114 /*   GLfloat position0[] = { -BOARDSIZE*0.5, 0.2*BOARDSIZE, -BOARDSIZE*0.5, 1.0 }; */
115   GLfloat position0[] = { 0, BOARDSIZE*0.3, 0, 1.0 };
116
117   if (wire) return;
118
119   glEnable(GL_LIGHTING);
120   glLightfv(GL_LIGHT0, GL_POSITION, position0);
121   glEnable(GL_LIGHT0);
122  }
123
124 ENTRYPOINT Bool
125 flipflop_handle_event (ModeInfo *mi, XEvent *event)
126 {
127   Flipflopcreen *c = &qs[MI_SCREEN(mi)];
128
129   if (event->xany.type == ButtonPress &&
130       event->xbutton.button == Button1)
131     {
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));
136       return True;
137     }
138   else if (event->xany.type == ButtonRelease &&
139            event->xbutton.button == Button1)
140     {
141       c->button_down_p = False;
142       return True;
143     }
144   else if (event->xany.type == ButtonPress &&
145            (event->xbutton.button == Button4 ||
146             event->xbutton.button == Button5))
147     {
148       gltrackball_mousewheel (c->trackball, event->xbutton.button, 5,
149                               !event->xbutton.state);
150       return True;
151     }
152   else if (event->xany.type == MotionNotify &&
153            c->button_down_p)
154     {
155       gltrackball_track (c->trackball,
156                          event->xmotion.x, event->xmotion.y,
157                          MI_WIDTH (mi), MI_HEIGHT (mi));
158       return True;
159     }
160
161   return False;
162 }
163
164 /* draw board */
165 static void
166 drawBoard(Flipflopcreen *c)
167 {
168   int i;
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 );
173 }
174
175
176 static void
177 display(Flipflopcreen *c)
178 {
179    GLfloat amb[] = { 0.8, 0.8, 0.8, 1.0 };
180
181
182  glClear(clearbits);
183  glMatrixMode(GL_MODELVIEW);
184  glLoadIdentity();
185
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);
190
191
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);
198
199   drawBoard(c);
200
201   if (!c->button_down_p)
202     c->theta += .001;
203
204 }
205
206 ENTRYPOINT void
207 reshape_flipflop(ModeInfo *mi, int width, int height)
208 {
209   GLfloat h = (GLfloat) height / (GLfloat) width;
210   glViewport(0,0, width, height);
211   glMatrixMode(GL_PROJECTION);
212   glLoadIdentity();
213   gluPerspective(45, 1/h, 1.0, 300.0);
214   glMatrixMode(GL_MODELVIEW);
215 }
216
217 ENTRYPOINT void
218 init_flipflop(ModeInfo *mi)
219 {
220   int screen = MI_SCREEN(mi);
221   Flipflopcreen *c;
222   wire = MI_IS_WIREFRAME(mi);
223
224   if(!qs &&
225      !(qs = (Flipflopcreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Flipflopcreen))))
226     return;
227
228   c = &qs[screen];
229   c->window = MI_WINDOW(mi);
230   c->trackball = gltrackball_init ();
231
232   c->flipspeed = 0.03;
233   c->reldist = 1;
234   c->energy = 40;
235
236   if((c->glx_context = init_GL(mi)))
237     reshape_flipflop(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
238   else
239     MI_CLEARWINDOW(mi);
240
241   glClearColor(0.0, 0.0, 0.0, 0.0);
242
243   clearbits = GL_COLOR_BUFFER_BIT;
244
245   glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
246   glEnable(GL_COLOR_MATERIAL);
247   setup_lights();
248
249   glEnable(GL_DEPTH_TEST);
250   clearbits |= GL_DEPTH_BUFFER_BIT;
251   glEnable(GL_CULL_FACE);
252   glCullFace(GL_BACK);
253   randsheet_initialize( &c->sheet );
254
255
256 }
257
258 ENTRYPOINT void
259 draw_flipflop(ModeInfo *mi)
260 {
261   Flipflopcreen *c = &qs[MI_SCREEN(mi)];
262   Window w = MI_WINDOW(mi);
263   Display *disp = MI_DISPLAY(mi);
264
265   if(!c->glx_context)
266     return;
267
268   glXMakeCurrent(disp, w, *(c->glx_context));
269
270   display(c);
271
272   if(mi->fps_p){
273     do_fps(mi);
274   }
275
276   glFinish();
277   glXSwapBuffers(disp, w);
278
279
280 }
281
282 ENTRYPOINT void
283 release_flipflop(ModeInfo *mi)
284 {
285   if(qs)
286     free((void *) qs);
287   qs = 0;
288
289   FreeAllGL(mi);
290 }
291
292 /*** ADDED RANDSHEET FUNCTIONS ***/
293
294 static void
295 draw_sheet(void)
296 {
297   glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
298
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 );
304
305   if (wire) { glEnd(); glBegin (GL_LINE_LOOP); }
306
307   /* back */
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 );
313
314   if (wire) { glEnd(); return; }
315
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 );
337   glEnd();
338 }
339
340 static void
341 randsheet_initialize( randsheet *rs )
342 {
343   int i, j, index;
344       index = 0;
345       /* put the moving sheets on the board */
346       for( i = 0; i < BOARDSIZE; i++ )
347         {
348           for( j = 0; j < BOARDSIZE; j++ )
349             {
350               /* initially fill up a corner with the moving squares */
351               if( index < NUMSQUARES )
352                 {
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);
360                  ++index;
361                 }
362                 /* leave everything else empty*/
363               else
364                 {
365                   rs->occupied[ i ][ j ] = -1;
366                 }
367             }
368         }
369         /* initially everything is at rest */
370       for( i=0; i<NUMSQUARES; i++ )
371         {
372           rs->direction[ i ] = 0;
373           rs->angle[ i ] = 0;
374         }
375 }
376
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... */
383 static int
384 randsheet_new_move( randsheet* rs )
385 {
386       int i, j;
387       int num, dir;
388       /* pick a random square */
389       num = random( ) % NUMSQUARES;
390       i = rs->xpos[ num ];
391       j = rs->ypos[ num ];
392       /* pick a random direction */
393       dir = ( random( )% 4 ) + 1;
394
395       if( rs->direction[ num ] == 0 )
396         {
397           switch( dir )
398             {
399             case 1:
400               /* move up in x */
401               if( ( i + 1 ) < BOARDSIZE )
402                 {
403                   if( rs->occupied[ i + 1 ][ j ] == -1 )
404                     {
405                       rs->direction[ num ] = dir;
406                       rs->occupied[ i + 1 ][ j ] = num;
407                       rs->occupied[ i ][ j ] = -1;
408                       return 1;
409                     }
410                 }
411               return 0;
412               break;
413             case 2:
414               /* move up in y */
415               if( ( j + 1 ) < BOARDSIZE )
416                 {
417                   if( rs->occupied[ i ][ j + 1 ] == -1 )
418                     {
419                       rs->direction[ num ] = dir;
420                       rs->occupied[ i ][ j + 1 ] = num;
421                       rs->occupied[ i ][ j ] = -1;
422                       return 1;
423                     }
424                 }
425               return 0;
426               break;
427             case 3:
428               /* move down in x */
429               if( ( i - 1 ) >= 0 )
430                 {
431                   if( rs->occupied[ i - 1][ j ] == -1 )
432                     {
433                       rs->direction[ num ] = dir;
434                       rs->occupied[ i - 1][ j ] = num;
435                       rs->occupied[ i ][ j ] = -1;
436                       return 1;
437                     }
438                 }
439               return 0;
440               break;
441             case 4:
442               /* move down in y */
443               if( ( j - 1 ) >= 0 )
444                 {
445                   if( rs->occupied[ i ][ j - 1 ] == -1 )
446                     {
447                       rs->direction[ num ] = dir;
448                       rs->occupied[ i ][ j - 1 ] = num;
449                       rs->occupied[ i ][ j ] = -1;
450                       return 1;
451                     }
452                 }
453               return 0;
454               break;
455             default:
456               break;
457             }
458         }
459       return 0;
460 }
461
462 /*   move a single frame.  */
463 /*   Pass in the angle in rads the square rotates in a frame. */
464 static void
465 randsheet_move( randsheet *rs, float rot )
466 {
467       int i, j, index;
468       for( index = 0 ; index < NUMSQUARES; index++ )
469         {
470           i = rs->xpos[ index ];
471           j = rs->ypos[ index ];
472           switch( rs->direction[ index ] )
473             {
474             case 0:
475               /* not moving */
476               break;
477             case 1:
478             /* move up in x */
479               rs->angle[ index ] += rot;
480               /* check to see if we have finished moving */
481               if( rs->angle[ index ] >= M_PI  )
482                 {
483                   rs->xpos[ index ] += 1;
484                   rs->direction[ index ] = 0;
485                   rs->angle[ index ] = 0;
486                 }
487               break;
488             case 2:
489             /* move up in y */
490               rs->angle[ index ] += rot;
491               /* check to see if we have finished moving */
492               if( rs->angle[ index ] >= M_PI  )
493                 {
494                   rs->ypos[ index ] += 1;
495                   rs->direction[ index ] = 0;
496                   rs->angle[ index ] = 0;
497                 }
498               break;
499             case 3:
500             /* down in x */
501               rs->angle[ index ] += rot;
502               /* check to see if we have finished moving */
503               if( rs->angle[ index ] >= M_PI  )
504                 {
505                   rs->xpos[ index ] -= 1;
506                   rs->direction[ index ] = 0;
507                   rs->angle[ index ] = 0;
508                 }
509               break;
510             case 4:
511             /* up in x */
512               rs->angle[ index ] += rot;
513               /* check to see if we have finished moving */
514               if( rs->angle[ index ] >= M_PI  )
515                 {
516                   rs->ypos[ index ] -= 1;
517                   rs->direction[ index ] = 0;
518                   rs->angle[ index ] = 0;
519                 }
520               break;
521             default:
522               break;
523             }
524         }
525 }
526
527
528     /* draw all the moving squares  */
529 static void
530 randsheet_draw( randsheet *rs )
531 {
532       int i, j;
533       int index;
534       /* for all moving squares ... */
535       for( index = 0; index < NUMSQUARES; index++ )
536         {
537           /* set color */
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 ];
544           glPushMatrix();
545           switch( rs->direction[ index ] )
546             {
547             case 0:
548
549             /* not moving */
550               /* front */
551               glTranslatef( i, 0, j );
552               break;
553             case 1:
554               glTranslatef( i+1, 0, j );
555               glRotatef( 180 - rs->angle[ index ]*180/M_PI, 0, 0, 1 );
556
557               break;
558             case 2:
559               glTranslatef( i, 0, j+1 );
560               glRotatef( 180 - rs->angle[ index ]*180/M_PI, -1, 0, 0 );
561
562               break;
563             case 3:
564               glTranslatef( i, 0, j );
565               glRotatef( rs->angle[ index ]*180/M_PI, 0, 0, 1 );
566               break;
567             case 4:
568               glTranslatef( i, 0, j );
569               glRotatef( rs->angle[ index ]*180/M_PI, -1, 0, 0 );
570               break;
571             default:
572               break;
573             }
574           draw_sheet();
575           glPopMatrix();
576
577         }
578 }
579
580 /**** END RANDSHEET FUNCTIONS ***/
581
582 XSCREENSAVER_MODULE ("Flipflop", flipflop)
583
584 #endif