http://ftp.ksu.edu.tw/FTP/FreeBSD/distfiles/xscreensaver-4.20.tar.gz
[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 #include <X11/Intrinsic.h>
13
14 #include <math.h>
15 #include <sys/time.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18
19 #define BOARDSIZE 9
20 #define NUMSQUARES 76
21 #define HALFTHICK 0.04
22
23 #ifdef STANDALONE
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
31
32 #define DEFAULTS       "*delay:       20000       \n" \
33                        "*showFPS:       False       \n" \
34                        "*wireframe:     False     \n"
35
36 # include "xlockmore.h"
37
38 #else
39 # include "xlock.h"
40 #endif
41
42 #ifdef USE_GL
43
44 #include <GL/glu.h>
45 #include "gltrackball.h"
46
47 #undef countof
48 #define countof(x) (sizeof((x))/sizeof((*x)))
49
50 static XrmOptionDescRec opts[] = {
51   {"+rotate", ".flipflop.rotate", XrmoptionNoArg, "false" },
52   {"-rotate", ".flipflop.rotate", XrmoptionNoArg, "true" },
53 };
54
55
56
57 static int rotate, wire, clearbits;
58
59 static argtype vars[] = {
60   { &rotate, "rotate", "Rotate", "True", t_Bool},
61 };
62
63 ModeSpecOpt flipflop_opts = {countof(opts), opts, countof(vars), vars, NULL};
64
65 #ifdef USE_MODULES
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, "",
70  "Flipflop", 0, NULL};
71
72 #endif
73
74 typedef struct {
75   GLXContext *glx_context;
76   Window window;
77   trackball_state *trackball;
78   Bool button_down_p;
79 } Flipflopcreen;
80
81 static Flipflopcreen *qs = NULL;
82
83 typedef struct{
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 */
100 } randsheet;
101
102
103 /*** ADDED RANDSHEET VARS ***/
104
105 static randsheet MyRandSheet;
106
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;
114
115
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);
125
126
127 /* configure lighting */
128 static void
129 setup_lights(void)
130 {
131 /*   GLfloat position0[] = { BOARDSIZE*0.5, BOARDSIZE*0.1, BOARDSIZE*0.5, 1.0 }; */
132
133 /*   GLfloat position0[] = { -BOARDSIZE*0.5, 0.2*BOARDSIZE, -BOARDSIZE*0.5, 1.0 }; */
134   GLfloat position0[] = { 0, BOARDSIZE*0.3, 0, 1.0 };
135
136   if (wire) return;
137
138   glEnable(GL_LIGHTING);
139   glLightfv(GL_LIGHT0, GL_POSITION, position0);
140   glEnable(GL_LIGHT0);
141  }
142
143 Bool
144 flipflop_handle_event (ModeInfo *mi, XEvent *event)
145 {
146   Flipflopcreen *c = &qs[MI_SCREEN(mi)];
147
148   if (event->xany.type == ButtonPress &&
149       event->xbutton.button == Button1)
150     {
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));
155       return True;
156     }
157   else if (event->xany.type == ButtonRelease &&
158            event->xbutton.button == Button1)
159     {
160       c->button_down_p = False;
161       return True;
162     }
163   else if (event->xany.type == ButtonPress &&
164            (event->xbutton.button == Button4 ||
165             event->xbutton.button == Button5))
166     {
167       gltrackball_mousewheel (c->trackball, event->xbutton.button, 5,
168                               !event->xbutton.state);
169       return True;
170     }
171   else if (event->xany.type == MotionNotify &&
172            c->button_down_p)
173     {
174       gltrackball_track (c->trackball,
175                          event->xmotion.x, event->xmotion.y,
176                          MI_WIDTH (mi), MI_HEIGHT (mi));
177       return True;
178     }
179
180   return False;
181 }
182
183 /* draw board */
184 static void
185 drawBoard(void)
186 {
187   int i;
188   for( i=0; i < (energy) ; i++ )
189     randsheet_new_move( &MyRandSheet );
190   randsheet_move( &MyRandSheet, flipspeed * 3.14159 );
191   randsheet_draw( &MyRandSheet );
192 }
193
194
195 static void
196 display(Flipflopcreen *c)
197 {
198    GLfloat amb[] = { 0.8, 0.8, 0.8, 1.0 };
199
200
201  glClear(clearbits);
202  glMatrixMode(GL_MODELVIEW);
203  glLoadIdentity();
204
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);
209
210
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);
217
218   drawBoard();
219
220   if (!c->button_down_p)
221     theta += .001;
222
223 }
224
225 void
226 reshape_flipflop(ModeInfo *mi, int width, int height)
227 {
228   GLfloat h = (GLfloat) height / (GLfloat) width;
229   glViewport(0,0, width, height);
230   glMatrixMode(GL_PROJECTION);
231   glLoadIdentity();
232   gluPerspective(45, 1/h, 1.0, 300.0);
233   glMatrixMode(GL_MODELVIEW);
234 }
235
236 void
237 init_flipflop(ModeInfo *mi)
238 {
239   int screen = MI_SCREEN(mi);
240   Flipflopcreen *c;
241   wire = MI_IS_WIREFRAME(mi);
242
243   if(!qs &&
244      !(qs = (Flipflopcreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Flipflopcreen))))
245     return;
246
247   c = &qs[screen];
248   c->window = MI_WINDOW(mi);
249   c->trackball = gltrackball_init ();
250
251   if((c->glx_context = init_GL(mi)))
252     reshape_flipflop(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
253   else
254     MI_CLEARWINDOW(mi);
255
256   glClearColor(0.0, 0.0, 0.0, 0.0);
257
258   clearbits = GL_COLOR_BUFFER_BIT;
259
260   glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
261   glEnable(GL_COLOR_MATERIAL);
262   setup_lights();
263
264   glEnable(GL_DEPTH_TEST);
265   clearbits |= GL_DEPTH_BUFFER_BIT;
266   glEnable(GL_CULL_FACE);
267   glCullFace(GL_BACK);
268   randsheet_initialize( &MyRandSheet );
269
270
271 }
272
273 void
274 draw_flipflop(ModeInfo *mi)
275 {
276   Flipflopcreen *c = &qs[MI_SCREEN(mi)];
277   Window w = MI_WINDOW(mi);
278   Display *disp = MI_DISPLAY(mi);
279
280   if(!c->glx_context)
281     return;
282
283   glXMakeCurrent(disp, w, *(c->glx_context));
284
285   display(c);
286
287   if(mi->fps_p){
288     do_fps(mi);
289   }
290
291   glFinish();
292   glXSwapBuffers(disp, w);
293
294
295 }
296
297 void
298 release_flipflop(ModeInfo *mi)
299 {
300   if(qs)
301     free((void *) qs);
302
303   FreeAllGL(MI);
304 }
305
306 /*** ADDED RANDSHEET FUNCTIONS ***/
307
308 static void
309 draw_sheet(void)
310 {
311   glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
312
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 );
318
319   if (wire) { glEnd(); glBegin (GL_LINE_LOOP); }
320
321   /* back */
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 );
327
328   if (wire) { glEnd(); return; }
329
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 );
351   glEnd();
352 }
353
354 static void
355 randsheet_initialize( randsheet *rs )
356 {
357   int i, j, index;
358       index = 0;
359       /* put the moving sheets on the board */
360       for( i = 0; i < BOARDSIZE; i++ )
361         {
362           for( j = 0; j < BOARDSIZE; j++ )
363             {
364               /* initially fill up a corner with the moving squares */
365               if( index < NUMSQUARES )
366                 {
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);
374                  ++index;
375                 }
376                 /* leave everything else empty*/
377               else
378                 {
379                   rs->occupied[ i ][ j ] = -1;
380                 }
381             }
382         }
383         /* initially everything is at rest */
384       for( i=0; i<NUMSQUARES; i++ )
385         {
386           rs->direction[ i ] = 0;
387           rs->angle[ i ] = 0;
388         }
389 }
390
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... */
397 static int
398 randsheet_new_move( randsheet* rs )
399 {
400       int i, j;
401       int num, dir;
402       /* pick a random square */
403       num = random( ) % NUMSQUARES;
404       i = rs->xpos[ num ];
405       j = rs->ypos[ num ];
406       /* pick a random direction */
407       dir = ( random( )% 4 ) + 1;
408
409       if( rs->direction[ num ] == 0 )
410         {
411           switch( dir )
412             {
413             case 1:
414               /* move up in x */
415               if( ( i + 1 ) < BOARDSIZE )
416                 {
417                   if( rs->occupied[ i + 1 ][ j ] == -1 )
418                     {
419                       rs->direction[ num ] = dir;
420                       rs->occupied[ i + 1 ][ j ] = num;
421                       rs->occupied[ i ][ j ] = -1;
422                       return 1;
423                     }
424                 }
425               return 0;
426               break;
427             case 2:
428               /* move up in y */
429               if( ( j + 1 ) < BOARDSIZE )
430                 {
431                   if( rs->occupied[ i ][ j + 1 ] == -1 )
432                     {
433                       rs->direction[ num ] = dir;
434                       rs->occupied[ i ][ j + 1 ] = num;
435                       rs->occupied[ i ][ j ] = -1;
436                       return 1;
437                     }
438                 }
439               return 0;
440               break;
441             case 3:
442               /* move down in x */
443               if( ( i - 1 ) >= 0 )
444                 {
445                   if( rs->occupied[ i - 1][ j ] == -1 )
446                     {
447                       rs->direction[ num ] = dir;
448                       rs->occupied[ i - 1][ j ] = num;
449                       rs->occupied[ i ][ j ] = -1;
450                       return 1;
451                     }
452                 }
453               return 0;
454               break;
455             case 4:
456               /* move down in y */
457               if( ( j - 1 ) >= 0 )
458                 {
459                   if( rs->occupied[ i ][ j - 1 ] == -1 )
460                     {
461                       rs->direction[ num ] = dir;
462                       rs->occupied[ i ][ j - 1 ] = num;
463                       rs->occupied[ i ][ j ] = -1;
464                       return 1;
465                     }
466                 }
467               return 0;
468               break;
469             default:
470               break;
471             }
472         }
473       return 0;
474 }
475
476 /*   move a single frame.  */
477 /*   Pass in the angle in rads the square rotates in a frame. */
478 static void
479 randsheet_move( randsheet *rs, float rot )
480 {
481       int i, j, index;
482       for( index = 0 ; index < NUMSQUARES; index++ )
483         {
484           i = rs->xpos[ index ];
485           j = rs->ypos[ index ];
486           switch( rs->direction[ index ] )
487             {
488             case 0:
489               /* not moving */
490               break;
491             case 1:
492             /* move up in x */
493               rs->angle[ index ] += rot;
494               /* check to see if we have finished moving */
495               if( rs->angle[ index ] >= M_PI  )
496                 {
497                   rs->xpos[ index ] += 1;
498                   rs->direction[ index ] = 0;
499                   rs->angle[ index ] = 0;
500                 }
501               break;
502             case 2:
503             /* move up in y */
504               rs->angle[ index ] += rot;
505               /* check to see if we have finished moving */
506               if( rs->angle[ index ] >= M_PI  )
507                 {
508                   rs->ypos[ index ] += 1;
509                   rs->direction[ index ] = 0;
510                   rs->angle[ index ] = 0;
511                 }
512               break;
513             case 3:
514             /* down in x */
515               rs->angle[ index ] += rot;
516               /* check to see if we have finished moving */
517               if( rs->angle[ index ] >= M_PI  )
518                 {
519                   rs->xpos[ index ] -= 1;
520                   rs->direction[ index ] = 0;
521                   rs->angle[ index ] = 0;
522                 }
523               break;
524             case 4:
525             /* up in x */
526               rs->angle[ index ] += rot;
527               /* check to see if we have finished moving */
528               if( rs->angle[ index ] >= M_PI  )
529                 {
530                   rs->ypos[ index ] -= 1;
531                   rs->direction[ index ] = 0;
532                   rs->angle[ index ] = 0;
533                 }
534               break;
535             default:
536               break;
537             }
538         }
539 }
540
541
542     /* draw all the moving squares  */
543 static void
544 randsheet_draw( randsheet *rs )
545 {
546       int i, j;
547       int index;
548       /* for all moving squares ... */
549       for( index = 0; index < NUMSQUARES; index++ )
550         {
551           /* set color */
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 ];
558           glPushMatrix();
559           switch( rs->direction[ index ] )
560             {
561             case 0:
562
563             /* not moving */
564               /* front */
565               glTranslatef( i, 0, j );
566               break;
567             case 1:
568               glTranslatef( i+1, 0, j );
569               glRotatef( 180 - rs->angle[ index ]*180/M_PI, 0, 0, 1 );
570
571               break;
572             case 2:
573               glTranslatef( i, 0, j+1 );
574               glRotatef( 180 - rs->angle[ index ]*180/M_PI, -1, 0, 0 );
575
576               break;
577             case 3:
578               glTranslatef( i, 0, j );
579               glRotatef( rs->angle[ index ]*180/M_PI, 0, 0, 1 );
580               break;
581             case 4:
582               glTranslatef( i, 0, j );
583               glRotatef( rs->angle[ index ]*180/M_PI, -1, 0, 0 );
584               break;
585             default:
586               break;
587             }
588           draw_sheet();
589           glPopMatrix();
590
591         }
592 }
593
594 /**** END RANDSHEET FUNCTIONS ***/
595
596 #endif