http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.06.tar.gz
[xscreensaver] / hacks / glx / gleidescope.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* vim: set ai ts=4 sw=4: */
3
4 #if !defined( lint ) && !defined( SABER )
5 /*static const char sccsid[] = "@(#)gleidescope.c       1.0 03/06/27 xlockmore";*/
6 #endif
7
8 /* enable -grab switch for animations */
9 #undef  GRAB
10
11 #undef DISPLAY_TEXTURE
12
13 /*-
14  * Permission to use, copy, modify, and distribute this software and its
15  * documentation for any purpose and without fee is hereby granted,
16  * provided that the above copyright notice appear in all copies and that
17  * both that copyright notice and this permission notice appear in
18  * supporting documentation.
19  *
20  * This file is provided AS IS with no warranties of any kind.  The author
21  * shall have no liability with respect to the infringement of copyrights,
22  * trade secrets or any patents by this file or any part thereof.  In no
23  * event will the author be liable for any lost revenue or profits or
24  * other special, indirect and consequential damages.
25  *
26  *      Revision History:
27  *
28  *      20030627        1.0             acd             First Release.
29  *                                                              Texture loading code from 'glplanet'
30  *                                                                      by Jamie Zawinski <jwz@jwz.org>
31  *      20030810        1.1             acd             Added size flag.
32  *                                                              Now grabs screen / video / picture
33  *                                                                      (uses code from 'glslideshow' by
34  *                                                                      Mike Oliphant, Ben Buxton, Jamie Zawinski).
35  *                                                              Added -duration.
36  *                                                              Added mouse code.
37  *                                                              Added fade code (also from glslideshow).
38  *      20031013        1.2             acd             Migrated to compile without warnings under
39  *                                                                      xscreensaver 4.13.
40  *      20031023        1.3             acd             Better code to limit twisting speeds.
41  *                                                              Tweaked initial rotation values.
42  *                                                              Move, Rotate, Zoom now chosen at random if
43  *                                                                      no preference is given.
44  *                                                              Made grid slightly bigger so you can't see
45  *                                                                      the edge when zooming and moving.
46  *      20061226        1.4             acd             Now uses GL Display Lists.
47  *      20070318        1.5             acd             Generates textures.
48  *                                                              Fixed texture size problem (and introduced another).
49  *      20070412        1.6             acd             Textures now have independant sizes.
50  *      20070413        1.7             acd             Added Lissajous movement pattern.
51  *      20070414        1.8             acd             Added corners movement pattern.
52  *      20080319        1.9             acd             Changes to arguments for saner gleidescope.xml.
53  *
54  * TODO
55  * generate textures myself - render random shapes to 256x256 texture. (done)
56  * lower res for checks and random - use 256 and 4x4 or 8x8 pixels. (disabled for now)
57  * gnome-saver doesn't let you specify source directory so add that to this.
58  * image loading routine is too slow - rotation grinds to a halt - stop using it. (better in version 5)
59  * image loading also looks bad for non-square images - edges are black. (fixed)
60  * possible to see edge of the world on widescreen terminals - use larger grid and hidden hex removal?
61  * fading textures may have different max_tx - use two sets. (done)
62  * choice of movement patterns. (3 implemented, chooseable at compile time)
63  * look into rangle and tangle.
64  */
65
66 /*
67 **----------------------------------------------------------------------------
68 ** Defines
69 **----------------------------------------------------------------------------
70 */
71
72 #ifdef STANDALONE
73 # define DEFAULTS \
74                 "*delay:                20000           \n"     \
75                 "*showFPS:              False           \n"     \
76                 "*size:                 -1                      \n"     \
77                 "*useSHM:               True            \n"
78
79 # define refresh_gleidescope 0
80 # include "xlockmore.h"                         /* from the xscreensaver distribution */
81 #else  /* !STANDALONE */
82 # include "xlock.h"                                     /* from the xlockmore distribution */
83 #endif /* !STANDALONE */
84
85 #ifdef USE_GL
86
87 #include "colors.h"
88 #include "xpm-ximage.h"
89 #include "grab-ximage.h"
90
91 #ifdef GRAB
92 void grab_frame(Display *display, Window window);
93 #endif
94
95 /* acd TODO should all these be in gleidestruct? */
96 /* they can't be, because of the idiotic way the xlockmore "argtype vars"
97    interface works. -jwz */
98 #ifdef GRAB
99 static Bool             grab;                   /* grab images */
100 #endif
101 static Bool             move;                   /* moving camera */
102 static Bool             nomove;                 /* no moving camera */
103 static Bool             rotate;                 /* rotate in place */
104 static Bool             norotate;               /* no rotate in place */
105 static Bool             zoom;                   /* zooming camera */
106 static Bool             nozoom;                 /* no zooming camera */
107 static char             *image;                 /* name of texture to load */
108 static int              duration;               /* length of time to display grabbed image */
109
110 #define MAX_CAM_SPEED                   1.0
111 #define MAX_ANGLE_VEL                   1.0
112 #define INITIAL_ANGLE_VEL               0.2
113 #define INITIAL_ANGLE_ACC               0.001
114 #define TWISTING_PROBABILITY    1000    /* 1 in ... of change of acceleration */
115
116 #define RADIANS (M_PI / 180)
117 #define ANGLE_120       (M_PI * 2 / 3)
118 #define ANGLE_240       (M_PI * 4 / 3)
119
120 static XrmOptionDescRec opts[] =
121 {
122 #ifdef GRAB
123         {"-grab",               ".gleidescope.grab",            XrmoptionNoArg,         "true"},
124 #endif
125         {"-move",               ".gleidescope.move",            XrmoptionNoArg,         "true"},
126         {"-no-move",    ".gleidescope.nomove",          XrmoptionNoArg,         "true"},
127         {"-rotate",             ".gleidescope.rotate",          XrmoptionNoArg,         "true"},
128         {"-no-rotate",  ".gleidescope.norotate",        XrmoptionNoArg,         "true"},
129         /*{"-size",             ".gleidescope.size",            XrmoptionNoArg,         "-1"},*/
130         {"-zoom",               ".gleidescope.zoom",            XrmoptionNoArg,         "true"},
131         {"-no-zoom",    ".gleidescope.nozoom",          XrmoptionNoArg,         "true"},
132         {"-image",              ".gleidescope.image",           XrmoptionSepArg,        "DEFAULT"},
133         {"-duration",   ".gleidescope.duration",        XrmoptionSepArg,        "30"},
134 };
135
136
137 static argtype vars[] = {
138 #ifdef GRAB
139         {&grab,                 "grab",         "Grab",         "False",        t_Bool},
140 #endif
141         {&move,                 "move",         "Move",         "False",        t_Bool},
142         {&nomove,               "nomove",       "noMove",       "False",        t_Bool},
143         {&rotate,               "rotate",       "Rotate",       "False",        t_Bool},
144         {&norotate,             "norotate",     "noRotate",     "False",        t_Bool},
145         /*{&size,               "size",         "Size",         "-1",           t_Int},*/
146         {&zoom,                 "zoom",         "Zoom",         "False",        t_Bool},
147         {&nozoom,               "nozoom",       "noZoom",       "False",        t_Bool},
148         {&image,                "image",        "Image",        "DEFAULT",      t_String},
149         {&duration,             "duration",     "Duration",     "30",           t_Int},
150 };
151
152 static OptionStruct desc[] = {
153 #ifdef GRAB
154         {"-grab",               "grab images to create animation"},
155 #endif
156         {"-move",               "camera will move"},
157         {"-no-move",    "camera won't move"},
158         {"-rotate",             "camera will rotate"},
159         {"-no-rotate",  "camera won't rotate"},
160         /*{"-size",             "size of the hexagons (1-10)"},*/
161         {"-zoom",               "camera will zoom"},
162         {"-no-zoom",    "camera won't zoom"},
163         {"-image",              "xpm / xbm image file to use for texture"},
164         {"-duration",   "length of time texture will be used"},
165 };
166
167 ENTRYPOINT ModeSpecOpt gleidescope_opts = {
168         sizeof opts / sizeof opts[0], opts,
169         sizeof vars / sizeof vars[0], vars,
170         desc
171 };
172
173 #ifdef USE_MODULES
174 ModStruct   gleidescope_description = { 
175      "gleidescope", "init_gleidescope", "draw_gleidescope", "release_gleidescope",
176      "draw_gleidescope", "init_gleidescope", NULL, &gleidescope_opts,
177      1000, 1, 2, 1, 4, 1.0, "",
178      "GL Kaleidescope", 0, NULL};
179 #endif
180
181 /*
182 **-----------------------------------------------------------------------------
183 **      Typedefs
184 **-----------------------------------------------------------------------------
185 */
186
187 typedef struct hex_s {
188         GLfloat x, y, z;                /* position */
189 } hex_t;
190
191 typedef struct {
192         GLfloat x;
193         GLfloat y;
194         GLfloat z;
195 } vectorf;
196
197 typedef struct {
198         GLfloat x;
199         GLfloat y;
200 } vector2f;
201
202 typedef struct {
203         GLuint                  id;                             /* opengl texture id */
204         GLfloat                 width, height;  /* texture width and height */
205         GLfloat                 min_tx, min_ty; /* minimum texture sizes */
206         GLfloat                 max_tx, max_ty; /* maximum texture sizes */
207         time_t                  start_time;
208         Bool                    button_down_p;
209     Bool                        mipmap_p;
210     Bool                        waiting_for_image_p;
211         /* r_phase is for triangle rotation speed */
212         GLfloat                 x_period, y_period, r_period;
213         GLfloat                 x_phase, y_phase, r_phase;
214 } texture;
215
216 #define MAX_FADE        500     /* number of fade cycles */
217
218 typedef struct {
219         float                   cam_x_speed, cam_z_speed, cam_y_speed;
220         int                             cam_x_phase, cam_z_phase, cam_y_phase;
221         float                   tic;
222         GLXContext              *glx_context;
223         Window                  window;
224         texture                 textures[2];    /* texture handles */
225         GLuint                  visible;                /* index for current texture */
226         GLint                   fade;
227         time_t                  start_time;
228         Bool                    button_down_p;
229
230     int         size;
231         int             list;
232
233     float       tangle;         /* texture angle (degrees) */
234     float       tangle_vel;     /* texture velocity */
235     float       tangle_acc;     /* texture acceleration */
236
237     float       rangle;         /* rotate angle */
238     float       rangle_vel;     /* rotate velocity */
239     float       rangle_acc;     /* rotate acceleration */
240
241     /* mouse */
242     int xstart;
243     int ystart;
244     double xmouse;
245     double ymouse;
246
247     Bool mipmap_p;
248     Bool waiting_for_image_p;
249
250 } gleidestruct;
251
252 #define frandrange(x, y)        (x + frand(y - x))
253
254 #define XOFFSET (0.8660254f)    /* sin 60' */
255 #define YOFFSET (1.5000000f)    /* cos 60' + 1 */
256
257 #if 0
258
259 #define SIZE    3
260
261 /* generates a grid with edges of given size */
262 /* acd TODO - replace hex[] with this and allow size and distance as parameters */
263
264 int
265 generate_grid(int size)
266
267         int     i, x, y;
268
269         gp->size--;
270
271         i = gp->size;
272         for (y = -size ; y <= size ; y++) {
273                 for (x = -i ; x <= i ; x += 2) {
274                         printf("{XOFFSET * %d, YOFFSET * %d, 0},\n", x, y);
275                 }
276                 printf("\n");
277                 if (y < 0) {
278                         i++;
279                 } else {
280                         i--;
281                 }
282         }
283         return 0;
284 }
285 #endif
286
287 /* acd - this is terrible - 120+ hexes */
288 static const hex_t hex[] = {
289         /* edges of size 7 */
290         /* number of hexagons required to cover screen depends on camera distance */
291         /* at a distance of 10 this is just about enough. */
292         {XOFFSET * -6, YOFFSET * -6, 0},
293         {XOFFSET * -4, YOFFSET * -6, 0},
294         {XOFFSET * -2, YOFFSET * -6, 0},
295         {XOFFSET * 0, YOFFSET * -6, 0},
296         {XOFFSET * 2, YOFFSET * -6, 0},
297         {XOFFSET * 4, YOFFSET * -6, 0},
298         {XOFFSET * 6, YOFFSET * -6, 0},
299
300         {XOFFSET * -7, YOFFSET * -5, 0},
301         {XOFFSET * -5, YOFFSET * -5, 0},
302         {XOFFSET * -3, YOFFSET * -5, 0},
303         {XOFFSET * -1, YOFFSET * -5, 0},
304         {XOFFSET * 1, YOFFSET * -5, 0},
305         {XOFFSET * 3, YOFFSET * -5, 0},
306         {XOFFSET * 5, YOFFSET * -5, 0},
307         {XOFFSET * 7, YOFFSET * -5, 0},
308
309         {XOFFSET * -8, YOFFSET * -4, 0},
310         {XOFFSET * -6, YOFFSET * -4, 0},
311         {XOFFSET * -4, YOFFSET * -4, 0},
312         {XOFFSET * -2, YOFFSET * -4, 0},
313         {XOFFSET * 0, YOFFSET * -4, 0},
314         {XOFFSET * 2, YOFFSET * -4, 0},
315         {XOFFSET * 4, YOFFSET * -4, 0},
316         {XOFFSET * 6, YOFFSET * -4, 0},
317         {XOFFSET * 8, YOFFSET * -4, 0},
318
319         {XOFFSET * -9, YOFFSET * -3, 0},
320         {XOFFSET * -7, YOFFSET * -3, 0},
321         {XOFFSET * -5, YOFFSET * -3, 0},
322         {XOFFSET * -3, YOFFSET * -3, 0},
323         {XOFFSET * -1, YOFFSET * -3, 0},
324         {XOFFSET * 1, YOFFSET * -3, 0},
325         {XOFFSET * 3, YOFFSET * -3, 0},
326         {XOFFSET * 5, YOFFSET * -3, 0},
327         {XOFFSET * 7, YOFFSET * -3, 0},
328         {XOFFSET * 9, YOFFSET * -3, 0},
329
330         {XOFFSET * -10, YOFFSET * -2, 0},
331         {XOFFSET * -8, YOFFSET * -2, 0},
332         {XOFFSET * -6, YOFFSET * -2, 0},
333         {XOFFSET * -4, YOFFSET * -2, 0},
334         {XOFFSET * -2, YOFFSET * -2, 0},
335         {XOFFSET * 0, YOFFSET * -2, 0},
336         {XOFFSET * 2, YOFFSET * -2, 0},
337         {XOFFSET * 4, YOFFSET * -2, 0},
338         {XOFFSET * 6, YOFFSET * -2, 0},
339         {XOFFSET * 8, YOFFSET * -2, 0},
340         {XOFFSET * 10, YOFFSET * -2, 0},
341
342         {XOFFSET * -11, YOFFSET * -1, 0},
343         {XOFFSET * -9, YOFFSET * -1, 0},
344         {XOFFSET * -7, YOFFSET * -1, 0},
345         {XOFFSET * -5, YOFFSET * -1, 0},
346         {XOFFSET * -3, YOFFSET * -1, 0},
347         {XOFFSET * -1, YOFFSET * -1, 0},
348         {XOFFSET * 1, YOFFSET * -1, 0},
349         {XOFFSET * 3, YOFFSET * -1, 0},
350         {XOFFSET * 5, YOFFSET * -1, 0},
351         {XOFFSET * 7, YOFFSET * -1, 0},
352         {XOFFSET * 9, YOFFSET * -1, 0},
353         {XOFFSET * 11, YOFFSET * -1, 0},
354
355         {XOFFSET * -12, YOFFSET * 0, 0},
356         {XOFFSET * -10, YOFFSET * 0, 0},
357         {XOFFSET * -8, YOFFSET * 0, 0},
358         {XOFFSET * -6, YOFFSET * 0, 0},
359         {XOFFSET * -4, YOFFSET * 0, 0},
360         {XOFFSET * -2, YOFFSET * 0, 0},
361         {XOFFSET * 0, YOFFSET * 0, 0},
362         {XOFFSET * 2, YOFFSET * 0, 0},
363         {XOFFSET * 4, YOFFSET * 0, 0},
364         {XOFFSET * 6, YOFFSET * 0, 0},
365         {XOFFSET * 8, YOFFSET * 0, 0},
366         {XOFFSET * 10, YOFFSET * 0, 0},
367         {XOFFSET * 12, YOFFSET * 0, 0},
368
369         {XOFFSET * -11, YOFFSET * 1, 0},
370         {XOFFSET * -9, YOFFSET * 1, 0},
371         {XOFFSET * -7, YOFFSET * 1, 0},
372         {XOFFSET * -5, YOFFSET * 1, 0},
373         {XOFFSET * -3, YOFFSET * 1, 0},
374         {XOFFSET * -1, YOFFSET * 1, 0},
375         {XOFFSET * 1, YOFFSET * 1, 0},
376         {XOFFSET * 3, YOFFSET * 1, 0},
377         {XOFFSET * 5, YOFFSET * 1, 0},
378         {XOFFSET * 7, YOFFSET * 1, 0},
379         {XOFFSET * 9, YOFFSET * 1, 0},
380         {XOFFSET * 11, YOFFSET * 1, 0},
381
382         {XOFFSET * -10, YOFFSET * 2, 0},
383         {XOFFSET * -8, YOFFSET * 2, 0},
384         {XOFFSET * -6, YOFFSET * 2, 0},
385         {XOFFSET * -4, YOFFSET * 2, 0},
386         {XOFFSET * -2, YOFFSET * 2, 0},
387         {XOFFSET * 0, YOFFSET * 2, 0},
388         {XOFFSET * 2, YOFFSET * 2, 0},
389         {XOFFSET * 4, YOFFSET * 2, 0},
390         {XOFFSET * 6, YOFFSET * 2, 0},
391         {XOFFSET * 8, YOFFSET * 2, 0},
392         {XOFFSET * 10, YOFFSET * 2, 0},
393
394         {XOFFSET * -9, YOFFSET * 3, 0},
395         {XOFFSET * -7, YOFFSET * 3, 0},
396         {XOFFSET * -5, YOFFSET * 3, 0},
397         {XOFFSET * -3, YOFFSET * 3, 0},
398         {XOFFSET * -1, YOFFSET * 3, 0},
399         {XOFFSET * 1, YOFFSET * 3, 0},
400         {XOFFSET * 3, YOFFSET * 3, 0},
401         {XOFFSET * 5, YOFFSET * 3, 0},
402         {XOFFSET * 7, YOFFSET * 3, 0},
403         {XOFFSET * 9, YOFFSET * 3, 0},
404
405         {XOFFSET * -8, YOFFSET * 4, 0},
406         {XOFFSET * -6, YOFFSET * 4, 0},
407         {XOFFSET * -4, YOFFSET * 4, 0},
408         {XOFFSET * -2, YOFFSET * 4, 0},
409         {XOFFSET * 0, YOFFSET * 4, 0},
410         {XOFFSET * 2, YOFFSET * 4, 0},
411         {XOFFSET * 4, YOFFSET * 4, 0},
412         {XOFFSET * 6, YOFFSET * 4, 0},
413         {XOFFSET * 8, YOFFSET * 4, 0},
414
415         {XOFFSET * -7, YOFFSET * 5, 0},
416         {XOFFSET * -5, YOFFSET * 5, 0},
417         {XOFFSET * -3, YOFFSET * 5, 0},
418         {XOFFSET * -1, YOFFSET * 5, 0},
419         {XOFFSET * 1, YOFFSET * 5, 0},
420         {XOFFSET * 3, YOFFSET * 5, 0},
421         {XOFFSET * 5, YOFFSET * 5, 0},
422         {XOFFSET * 7, YOFFSET * 5, 0},
423
424         {XOFFSET * -6, YOFFSET * 6, 0},
425         {XOFFSET * -4, YOFFSET * 6, 0},
426         {XOFFSET * -2, YOFFSET * 6, 0},
427         {XOFFSET * 0, YOFFSET * 6, 0},
428         {XOFFSET * 2, YOFFSET * 6, 0},
429         {XOFFSET * 4, YOFFSET * 6, 0},
430         {XOFFSET * 6, YOFFSET * 6, 0},
431 };
432
433 /*
434 **----------------------------------------------------------------------------
435 ** Local Variables
436 **----------------------------------------------------------------------------
437 */
438
439 static  gleidestruct *gleidescope = NULL;
440
441 #if 0
442 /*
443  *load defaults in config structure
444  */
445 static void setdefaultconfig(void)
446 {
447 #ifdef GRAB
448         grab = False;
449 #endif
450         move = False;
451         rotate = False;
452         zoom = False;
453         image = NULL;
454 }
455 #endif
456
457 ENTRYPOINT Bool
458 gleidescope_handle_event(ModeInfo *mi, XEvent *event)
459 {
460         gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
461
462         /*
463         printf("event:%d\n", event->xany.type);
464         printf("button:%d\n", event->xbutton.button);
465         */
466         switch(event->xany.type)
467         {
468                 case ButtonPress:
469
470                         if (event->xbutton.button == Button1 ||
471                 event->xbutton.button == Button3)
472                         {
473                                 /* store initial values of mouse */
474                                 gp->xstart = event->xbutton.x;
475                                 gp->ystart = event->xbutton.y;
476
477                                 /* button is down */
478                                 gp->button_down_p = True;
479                                 return True;
480                         }
481 #if 0   /* TODO */
482                         else if (event->xbutton.button == Button4)
483                         {
484                                 /* zoom in */
485                                 return True;
486                         }
487                         else if (event->xbutton.button == Button5)
488                         {
489                                 /* zoom out */
490                                 return True;
491                         }
492 #endif
493                         break;
494
495                 case ButtonRelease:
496
497                         if (event->xbutton.button == Button1 ||
498                 event->xbutton.button == Button3)
499                         {
500                                 /* button is up */
501                                 gp->button_down_p = False;
502                                 return True;
503                         }
504                         break;
505
506                 case MotionNotify:
507
508                         if (gp->button_down_p)
509                         {
510                                 /* update mouse position */
511                                 gp->xmouse += (double)(event->xmotion.x - gp->xstart) / MI_WIDTH(mi);
512                                 gp->ymouse += (double)(event->xmotion.y - gp->ystart) / MI_HEIGHT(mi);
513                                 gp->xstart = event->xmotion.x;
514                                 gp->ystart = event->xmotion.y;
515
516                                 return True;
517                         }
518                         break;
519         }
520
521         return False;
522 }
523
524
525 static void
526 image_loaded_cb (const char *filename, XRectangle *geometry,
527                  int image_width, int image_height, 
528                  int texture_width, int texture_height,
529                  void *closure)
530 {
531         texture *tp = (texture *) closure;
532
533 #if 0
534         gp->max_tx = (GLfloat) image_width  / texture_width;
535         gp->max_ty = (GLfloat) image_height / texture_height;
536 #endif
537
538         /* new - taken from flipscreen */
539         tp->width = texture_width;
540         tp->height = texture_height;
541         tp->min_tx = (GLfloat) geometry->x / tp->width;
542         tp->min_ty = (GLfloat) geometry->y / tp->height;
543         tp->max_tx = (GLfloat) (geometry->x + geometry->width)  / tp->width;
544         tp->max_ty = (GLfloat) (geometry->y + geometry->height) / tp->height;
545
546 #ifdef DEBUG
547         printf("Image w,h: (%d, %d)\n", image_width, image_height);
548         printf("Texture w,h: (%d, %d)\n", texture_width, texture_height);
549         printf("Geom x,y: (%d, %d)\n", geometry->x, geometry->y);
550         printf("Geom w,h: (%d, %d)\n", geometry->width, geometry->height);
551         printf("Max Tx,Ty: (%f, %f)\n", tp->max_tx, tp->max_ty);
552 #endif
553
554         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
555         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
556                         (tp->mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
557
558         tp->waiting_for_image_p = False;
559         tp->start_time = time ((time_t *) 0);
560 }
561
562 static void
563 getSnapshot(ModeInfo *mi, texture *texture)
564 {
565         gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
566
567 #ifdef DEBUG
568         printf("getSnapshot");
569 #endif
570
571         if (MI_IS_WIREFRAME(mi))
572                 return;
573
574     gp->mipmap_p = True;
575     load_texture_async (mi->xgwa.screen, mi->window,
576                         *gp->glx_context, 0, 0, gp->mipmap_p, 
577                         texture->id, image_loaded_cb, texture);
578         texture->start_time = time((time_t *)0);
579 }
580
581 #define TEXTURE_SIZE    256
582
583 static void
584 plot(unsigned char *buffer, int x, int y, int r, int g, int b, int a) {
585         int c;
586         if (x < 0 || x >= TEXTURE_SIZE || y < 0 || y >= TEXTURE_SIZE) {
587                 return;
588         }
589         c = ((x * TEXTURE_SIZE) + y) * 4;
590         /*printf("(%d,%d)[%d]\n", x, y, c);*/
591         buffer[c + 0] = r;
592         buffer[c + 1] = g;
593         buffer[c + 2] = b;
594         buffer[c + 3] = a;
595 }
596
597 #if 0
598 static void
599 plot2(unsigned char *buffer, int x, int y, int r, int g, int b, int a) {
600         int c;
601         if (x < 0 || x >= TEXTURE_SIZE || y < 0 || y >= TEXTURE_SIZE) {
602                 return;
603         }
604         c = ((x * TEXTURE_SIZE) + y) * 4;
605         /*printf("(%d,%d)[%d]\n", x, y, c);*/
606         buffer[c + 0] = r;
607         buffer[c + 1] = g;
608         buffer[c + 2] = b;
609         buffer[c + 3] = a;
610         
611         if (y + 1 < TEXTURE_SIZE) {
612                 buffer[c + 4] = r;
613                 buffer[c + 5] = g;
614                 buffer[c + 6] = b;
615                 buffer[c + 7] = a;
616         }
617
618         if (x + 1 < TEXTURE_SIZE) {
619                 c += (TEXTURE_SIZE * 4);
620                 buffer[c + 0] = r;
621                 buffer[c + 1] = g;
622                 buffer[c + 2] = b;
623                 buffer[c + 3] = a;
624                 if (y + 1 < TEXTURE_SIZE) {
625                         buffer[c + 4] = r;
626                         buffer[c + 5] = g;
627                         buffer[c + 6] = b;
628                         buffer[c + 7] = a;
629                 }
630         }
631 }
632 #endif
633
634 /* draw geometric shapes to texture */
635 /* modifies passed in buffer */
636 static void
637 draw_shapes (unsigned char *buffer) {
638         int a = 0xff;
639         int x, y, w, h;
640         int i, j;
641         int s;
642         float left, right;
643
644         for (i = 0 ; i < TEXTURE_SIZE * TEXTURE_SIZE * 4 ; i += 4) {
645                 buffer[i + 0] = 0x00;
646                 buffer[i + 1] = 0x00;
647                 buffer[i + 2] = 0x00;
648                 buffer[i + 3] = 0xff;
649         }
650
651         for (s = 0 ; s < 25 ; s++) {
652                 int shape = random() % 3;
653
654                 /* 8 bits */
655                 int r = (random() & 0xff);
656                 int g = (random() & 0xff);
657                 int b = (random() & 0xff);
658
659                 switch (shape) {
660                         case 0:
661                                 /* rectangle */
662                                 x = (random() % TEXTURE_SIZE) - (TEXTURE_SIZE / 4);     /* top left */
663                                 y = (random() % TEXTURE_SIZE) - (TEXTURE_SIZE / 4);
664                                 w = 10 + random() % (TEXTURE_SIZE / 4); /* size */
665                                 h = 10 + random() % (TEXTURE_SIZE / 4);
666 #ifdef DEBUG
667                                 printf("Rectangle: (%d, %d)(%d, %d)\n", x, y, w, h);
668 #endif
669                                 if (x < 0) {
670                                         x = 0;
671                                 }
672                                 if (y < 0) {
673                                         y = 0;
674                                 }
675                                 for (i = x ; i < x + w && i < TEXTURE_SIZE; i++) {
676                                         for (j = y ; j < y + h && j < TEXTURE_SIZE; j++) {
677                                                 plot(buffer, i, j, r, g, b, a);
678                                         }
679                                 }
680                                 break;
681
682                         case 1:
683                                 /* circle */
684                                 x = random() % TEXTURE_SIZE;    /* centre */
685                                 y = random() % TEXTURE_SIZE;
686                                 h = 10 + random() % (TEXTURE_SIZE / 8); /* radius */
687 #ifdef DEBUG
688                                 printf("Circle: %d, %d, %d\n", x, y, h);
689 #endif
690                                 for (i = 0 ; i < h ; i++) {
691                                         int xdist = i * i;
692                                         for (j = 0 ; j < h ; j++) {
693                                                 int ydist = j * j;
694                                                 /*
695                                                 printf("xdist: %d\n", xdist);
696                                                 printf("ydist: %d\n", ydist);
697                                                 printf("radius: %d\n", h * h);
698                                                 */
699                                                 if ((xdist + ydist) < (h * h)) {
700                                                         plot(buffer, x + i, y + j, r, b, g, a);
701                                                         /* check we haven't already done these */
702                                                         if (j != 0) {
703                                                                 plot(buffer, x + i, y - j, r, b, g, a);
704                                                         }
705                                                         if (i != 0) {
706                                                                 plot(buffer, x - i, y + j, r, b, g, a);
707                                                                 if (j != 0) {
708                                                                 plot(buffer, x - i, y - j, r, b, g, a);
709                                                                 }
710                                                         }
711                                                 }
712                                         }
713                                 }
714                                 break;
715
716                         case 2:
717                                 /* triangle */
718                                 x = random() % TEXTURE_SIZE;    /* top */
719                                 y = random() % TEXTURE_SIZE;
720                                 h = 10 + random() % (TEXTURE_SIZE / 4); /* height */
721 #ifdef DEBUG
722                                 printf("Triangle: %d, %d, %d\n", x, y, h);
723 #endif
724                                 left = x;
725                                 right = x;
726                                 for (i = 0 ; i < h ; i++) {
727                                         for (j = left ; j < right ; j++) {
728                                                 plot(buffer, j, y + i, r, g, b, a);
729                                         }
730                                         left -= .5;
731                                         right += .5;
732                                 }
733                                 break;
734                 }
735         }
736 }
737
738 static void
739 setup_random_texture (ModeInfo *mi, texture *texture)
740 {
741         int width = 0, height = 0;
742         char buf[1024];
743         unsigned char *my_data = NULL;
744 #if 0
745         int i, j, c;
746         int style;
747         int r0, g0, b0, a0, r1, g1, b1, a1;
748 #endif
749
750 #ifdef DEBUG
751         printf("RandomTexture\n");
752 #endif
753
754         /* use this texture */
755         glBindTexture(GL_TEXTURE_2D, texture->id);
756
757         clear_gl_error();
758
759         /*
760          * code for various generated patterns - noise, stripes, checks etc.
761          * random geometric shapes looked the best.
762          */
763
764 #if 0
765         style = random() & 0x3;
766         r0 = random() & 0xff; 
767         g0 = random() & 0xff; 
768         b0 = random() & 0xff; 
769         a0 = 0xff;
770         r1 = random() & 0xff; 
771         g1 = random() & 0xff; 
772         b1 = random() & 0xff; 
773         a1 = 0xff;
774
775         switch (style) {
776                 case 0: /* random */
777                         printf("Random0\n");
778                         height = width = TEXTURE_SIZE;
779                         my_data = (void *)malloc(width * height * 4);
780                         for (i = 0 ; i < width ; i += 2) {
781                                 for (j = 0 ; j < height ; j += 2) {
782                                         r0 = random() & 0xff; 
783                                         g0 = random() & 0xff; 
784                                         b0 = random() & 0xff; 
785                                         a0 = 0xff;
786                                         plot2(my_data, i, j, r0, g0, b0, a0);
787                                 }
788                         }
789                         break;
790
791                 case 1: /* shapes */
792 #endif
793 #ifdef DEBUG
794                         printf("Shapes\n");
795 #endif
796                         height = width = TEXTURE_SIZE;
797                         my_data = (void *)malloc(width * height * 4);
798                         draw_shapes(my_data);
799 #if 0
800                         break;
801
802                 case 2: /* check */
803                         printf("Check\n");
804                         height = width = TEXTURE_SIZE;
805                         my_data = (void *)malloc(width * height * 4);
806                         for (i = 0 ; i < height ; i += 2) {
807                                 for (j = 0 ; j < width ; j += 2) {
808                                         if (((i + j) & 0x3) == 0) {
809                                                 plot2(my_data, i, j, r0, g0, b0, a0);
810                                         } else {
811                                                 plot2(my_data, i, j, r1, g1, b1, a1);
812                                         }
813                                 }
814                         }
815                         break;
816
817                 case 3: /* random stripes */
818                         printf("Stripes 2\n");
819                         height = width = TEXTURE_SIZE;
820                         my_data = (void *)malloc(width * height * 4);
821                         for (i = 0 ; i < height ; i += 2) {
822                                 r0 = random() & 0xff; 
823                                 g0 = random() & 0xff; 
824                                 b0 = random() & 0xff; 
825                                 a0 = 0xff;
826                                 for (j = 0 ; j < width ; j += 2) {
827                                         plot2(my_data, i, j, r0, g0, b0, a0);
828                                 }
829                         }
830                         break;
831         }
832 #endif
833
834         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
835                         width, height, 0,
836                         GL_RGBA, GL_UNSIGNED_BYTE, my_data);
837         sprintf (buf, "random texture: (%dx%d)",
838                         width, height);
839         check_gl_error(buf);
840
841         /* setup parameters for texturing */
842         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
843         glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
844
845         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
846         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
847         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
848         if (random() & 0x1) {
849                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
850                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
851         } else {
852                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
853                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
854         }
855
856         if (my_data != NULL) {
857                 free(my_data);
858                 my_data = NULL;
859         }
860
861         /* use full texture */
862         /* acd - was 1.0 */
863         texture->min_tx = 0.0;
864         texture->max_tx = 2.0;
865         texture->min_ty = 0.0;
866         texture->max_ty = 2.0;
867         texture->start_time = time((time_t *)0);
868 }
869
870 static void
871 setup_file_texture (ModeInfo *mi, char *filename, texture *texture)
872 {
873         Display *dpy = mi->dpy;
874         Visual *visual = mi->xgwa.visual;
875         char buf[1024];
876
877         Colormap cmap = mi->xgwa.colormap;
878         XImage *image = xpm_file_to_ximage (dpy, visual, cmap, filename);
879
880 #ifdef DEBUG
881         printf("FileTexture\n");
882 #endif
883
884         /* use this texture */
885         glBindTexture(GL_TEXTURE_2D, texture->id);
886
887         clear_gl_error();
888         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
889                         image->width, image->height, 0,
890                         GL_RGBA, GL_UNSIGNED_BYTE, image->data);
891         sprintf (buf, "texture: %.100s (%dx%d)",
892                         filename, image->width, image->height);
893         check_gl_error(buf);
894
895         /* setup parameters for texturing */
896         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
897         glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
898
899         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
900         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
901         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
902         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
903         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
904
905         /* use full texture */
906         texture->min_tx = 0.0;
907         texture->max_tx = 1.0;
908         texture->min_ty = 0.0;
909         texture->max_ty = 1.0;
910         texture->start_time = time((time_t *)0);
911 }
912
913 static void
914 setup_texture(ModeInfo * mi, texture *texture)
915 {
916         gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
917
918         if (!image || !*image || !strcmp(image, "DEFAULT")) {
919                 /* no image specified - use system settings */
920 #ifdef DEBUG
921                 printf("SetupTexture: get_snapshot\n");
922 #endif
923                 getSnapshot(mi, texture);
924         } else {
925                 if (strcmp(image, "GENERATE") == 0) {
926 #ifdef DEBUG
927                         printf("SetupTexture: random_texture\n");
928 #endif
929                         setup_random_texture(mi, texture);
930                 } else {
931                         /* use supplied image file */
932 #ifdef DEBUG
933                         printf("SetupTexture: file_texture\n");
934 #endif
935                         setup_file_texture(mi, image, texture);
936                 }
937         }
938         /* copy start time from texture */
939         gp->start_time = texture->start_time;
940
941         check_gl_error("texture initialization");
942
943         /* acd 
944          * resultant loaded image is upside down BUT
945          * it's a kaledescope and half of the hexagon is backwards anyway...
946          */
947
948         /* TODO: values for lissajous movement */
949         texture->x_period = frandrange(-2.0, 2.0);
950         texture->y_period = frandrange(-2.0, 2.0);
951         texture->r_period = frandrange(-2.0, 2.0);
952         texture->x_phase = frand(M_PI * 2);
953         texture->y_phase = frand(M_PI * 2);
954         texture->r_phase = frand(M_PI * 2);
955 #ifdef DEBUG
956         printf("XPeriod %f XPhase %f\n", texture->x_period, texture->x_phase);
957         printf("YPeriod %f YPhase %f\n", texture->y_period, texture->y_phase);
958         printf("RPeriod %f RPhase %f\n", texture->r_period, texture->r_phase);
959 #endif
960 }
961
962 #define VERTEX0 glVertex3f( 0.0000f,  0.000f, 0.0f);
963 #define VERTEX1 glVertex3f( 0.0000f,  1.000f, 0.0f);
964 #define VERTEX2 glVertex3f( XOFFSET,  0.500f, 0.0f);
965 #define VERTEX3 glVertex3f( XOFFSET, -0.500f, 0.0f);
966 #define VERTEX4 glVertex3f( 0.0000f, -1.000f, 0.0f);
967 #define VERTEX5 glVertex3f(-XOFFSET, -0.500f, 0.0f);
968 #define VERTEX6 glVertex3f(-XOFFSET,  0.500f, 0.0f);
969
970 /*
971 ** Three different functions for calculating texture coordinates
972 ** which modify how the texture triangle moves over the source image.
973 ** Choose one.
974 */
975
976 #if 0
977 /* the classic equilateral triangle rotating around centre */
978 static void
979 calculate_texture_coords(ModeInfo *mi, texture *texture, vector2f t[3]) {
980
981         gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
982         GLfloat centre_x = 0.5;
983         GLfloat centre_y = 0.5;
984         GLfloat radius_x = (texture->max_tx - texture->min_tx) / 2;
985         GLfloat radius_y = (texture->max_ty - texture->min_ty) / 2;
986         GLfloat tangle2;
987         t[0].x = centre_x;
988         t[0].y = centre_y;
989
990         /* t[1] */
991         t[1].x = centre_x + .95 * radius_x * cos((gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS));
992         t[1].y = centre_y + .95 * radius_y * sin((gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS));
993
994         /* t[2] is always 60' further around than t2 */
995         tangle2 = (gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS) + (M_PI * 2 / 6);
996         t[2].x = centre_x + .95 * radius_x * cos(tangle2);
997         t[2].y = centre_y + .95 * radius_y * sin(tangle2);
998 #if 0
999         printf("texcoords:[%f,%f]->[%f,%f](%f,%f)\n", t[0].x, t[0].y, t[1].x, t[1].y, texture->max_tx, texture->max_ty);
1000 #endif
1001 }
1002 #endif
1003
1004 #if 1
1005 /* new lissajous movement pattern */
1006 static void
1007 calculate_texture_coords(ModeInfo *mi, texture *texture, vector2f t[3]) {
1008
1009         /* equilateral triangle rotating around centre */
1010         gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
1011         GLfloat width = texture->max_tx - texture->min_tx;
1012         GLfloat height = texture->max_ty - texture->min_ty;
1013         /* centre */
1014         GLfloat centre_x = texture->min_tx + (width * .5);
1015         GLfloat centre_y = texture->min_ty + (height * .5);
1016         /* m radius and t radius should be = .5 */
1017         /* triangle radius is 30% available space */
1018         GLfloat t_radius_x = width * .3;
1019         GLfloat t_radius_y = height * .3;
1020         /* movement radius is 30% available space */
1021         GLfloat m_radius_x = width * .2;
1022         GLfloat m_radius_y = height * .2;
1023         GLfloat angle2;
1024
1025         /* centre of triangle */
1026         GLfloat angle = (gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS);       /* to radians */
1027         GLfloat t_centre_x = centre_x + m_radius_x * cos(texture->x_period * angle + texture->x_phase);
1028         GLfloat t_centre_y = centre_y + m_radius_y * sin(texture->y_period * angle + texture->y_phase);
1029
1030 #if 0
1031         printf("WH: %f, %f - tWH: %f, %f\n", width, height, texture->width, texture->height);
1032         printf("size: (%f, %f)\n", width, height);
1033         printf("centre: (%f, %f)\n", centre_x, centre_y);
1034 #endif
1035
1036         angle2 = texture->r_period * angle + texture->r_phase;
1037         t[0].x = t_centre_x + t_radius_x * cos(angle2);
1038         t[0].y = t_centre_y + t_radius_y * sin(angle2);
1039         t[1].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_120);
1040         t[1].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_120);
1041         t[2].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_240);
1042         t[2].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_240);
1043
1044 #if 0
1045         printf("texcoords:[%f,%f]->[%f,%f](%f,%f)\n", t[0].x, t[0].y, t[1].x, t[1].y, texture->max_tx, texture->max_ty);
1046 #endif
1047 }
1048 #endif
1049  
1050 #if 0
1051 /* corners into corners - meant to maximise coverage */
1052 static void
1053 calculate_texture_coords(ModeInfo *mi, texture *texture, vector2f t[3]) {
1054
1055         /* equilateral triangle rotating around centre */
1056         gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
1057         GLfloat width = texture->max_tx - texture->min_tx;
1058         GLfloat height = texture->max_ty - texture->min_ty;
1059         /* centre */
1060         GLfloat centre_x = texture->min_tx + (width * .5);
1061         GLfloat centre_y = texture->min_ty + (height * .5);
1062         /* m radius and t radius should be = .5 */
1063         /* triangle radius calculated using maths 8) */
1064 #define TRADIUS (M_SQRT2 - 1.0)
1065 #define MRADIUS (1.0 - (M_SQRT2 / 2.0))
1066         GLfloat t_radius_x = width * TRADIUS * .95;
1067         GLfloat t_radius_y = height * TRADIUS * .95;
1068         /* movement radius also calculated using maths */
1069         GLfloat m_radius_x = width * MRADIUS * .95;
1070         GLfloat m_radius_y = height * MRADIUS * .95;
1071         GLfloat angle, angle2;
1072         GLfloat t_centre_x, t_centre_y;
1073
1074         /* centre of triangle */
1075         angle = gp->tangle * RADIANS;   /* to radians */
1076         t_centre_x = centre_x + m_radius_x * cos(angle);
1077         t_centre_y = centre_y + m_radius_y * sin(angle);
1078 #if 0
1079         printf("angle: %f, %f\n", angle, gp->tangle);
1080         printf("tcentre: %f,%f\n", t_centre_x, t_centre_y);
1081         printf("tradius: %f,%f\n", t_radius_x, t_radius_y);
1082
1083         printf("size: (%f, %f)\n", width, height);
1084         printf("centre: (%f, %f)\n", centre_x, centre_y);
1085         printf("centre: (%f, %f)\n", centre_x, centre_y);
1086         printf("TRADIUS: %f\n", TRADIUS);
1087         printf("MRADIUS: %f\n", MRADIUS);
1088 #endif
1089
1090         /* angle2 is tied to tangle */
1091         angle2 = (180.0 - ((30.0 / 90.0) * gp->tangle)) * RADIANS; 
1092 #if 0
1093         printf("Angle1: %f\tAngle2: %f\n", angle / RADIANS, angle2 / RADIANS);
1094 #endif
1095         t[0].x = t_centre_x + t_radius_x * cos(angle2);
1096         t[0].y = t_centre_y + t_radius_y * sin(angle2);
1097         t[1].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_120);
1098         t[1].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_120);
1099         t[2].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_240);
1100         t[2].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_240);
1101
1102 #if 0
1103         printf("texcoords:[%f,%f][%f,%f][%f,%f]\n", t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y);
1104 #endif
1105 }
1106 #endif
1107
1108 static void
1109 draw_hexagons(ModeInfo *mi, int translucency, texture *texture)
1110 {
1111         int             i;
1112         GLfloat col[4];
1113         vector2f t[3];
1114         gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
1115
1116         col[0] = 1.0;
1117         col[1] = 1.0;
1118         col[2] = 1.0;
1119         col[3] = (float)translucency / MAX_FADE;
1120
1121         calculate_texture_coords(mi, texture, t);
1122
1123         glColor4f(1.0, 1.0, 1.0, (float)translucency / MAX_FADE);
1124         glEnable(GL_TEXTURE_2D);
1125         glEnable(GL_BLEND);
1126         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1127         glDepthMask(GL_FALSE);
1128         glBindTexture(GL_TEXTURE_2D, texture->id);
1129
1130         if (gp->list == -1) {
1131                 gp->list = glGenLists(1);
1132         }
1133
1134         /* compile new list */
1135         glNewList(gp->list, GL_COMPILE);
1136         glBegin(GL_TRIANGLES);
1137
1138         /*
1139         ** six triangles to each hexagon
1140         */
1141
1142         glTexCoord2f(t[0].x, t[0].y);
1143         VERTEX0;
1144         glTexCoord2f(t[1].x, t[1].y);
1145         VERTEX1;
1146         glTexCoord2f(t[2].x, t[2].y);
1147         VERTEX6;
1148
1149         glTexCoord2f(t[0].x, t[0].y);
1150         VERTEX0;
1151         glTexCoord2f(t[2].x, t[2].y);
1152         VERTEX6;
1153         glTexCoord2f(t[1].x, t[1].y);
1154         VERTEX5;
1155
1156         glTexCoord2f(t[0].x, t[0].y);
1157         VERTEX0;
1158         glTexCoord2f(t[1].x, t[1].y);
1159         VERTEX5;
1160         glTexCoord2f(t[2].x, t[2].y);
1161         VERTEX4;
1162
1163         glTexCoord2f(t[0].x, t[0].y);
1164         VERTEX0;
1165         glTexCoord2f(t[2].x, t[2].y);
1166         VERTEX4;
1167         glTexCoord2f(t[1].x, t[1].y);
1168         VERTEX3;
1169
1170         glTexCoord2f(t[0].x, t[0].y);
1171         VERTEX0;
1172         glTexCoord2f(t[1].x, t[1].y);
1173         VERTEX3;
1174         glTexCoord2f(t[2].x, t[2].y);
1175         VERTEX2;
1176
1177         glTexCoord2f(t[0].x, t[0].y);
1178         VERTEX0;
1179         glTexCoord2f(t[2].x, t[2].y);
1180         VERTEX2;
1181         glTexCoord2f(t[1].x, t[1].y);
1182         VERTEX1;
1183
1184         glEnd();
1185         glEndList();
1186
1187         /* call the list n times */
1188         for (i = 0 ; i < sizeof(hex) / sizeof(hex[0]) ; i++) {
1189
1190                 glPushMatrix();
1191
1192                 glTranslatef(hex[i].x, hex[i].y, 0.0);
1193                 glCallList(gp->list);
1194
1195                 glPopMatrix();
1196         }
1197         
1198 #ifdef DISPLAY_TEXTURE
1199         glPushMatrix();
1200         /* acd debug - display (bigger, centred) texture */
1201         glScalef(2.0, 2.0, 2.0);
1202         glTranslatef(-0.5, -0.5, 0.0);
1203         glBegin(GL_QUADS);
1204         glTexCoord2f(0.0, 0.0);
1205         glVertex3f(0.0, 0.0, -0.1);
1206         glTexCoord2f(1.0, 0.0);
1207         glVertex3f(1.0, 0.0, -0.1);
1208         glTexCoord2f(1.0, 1.0);
1209         glVertex3f(1.0, 1.0, -0.1);
1210         glTexCoord2f(0.0, 1.0);
1211         glVertex3f(0.0, 1.0, -0.1);
1212         glEnd();
1213         /* acd debug - display texture triangle */
1214         glColor4f(1.0, 0.5, 1.0, 1.0);
1215         glBegin(GL_LINE_LOOP);
1216         glVertex3f(t[0].x, t[0].y, -0.11);
1217         glVertex3f(t[1].x, t[1].y, -0.11);
1218         glVertex3f(t[2].x, t[2].y, -0.11);
1219         glEnd();
1220         glPopMatrix();
1221 #endif
1222
1223         glDisable(GL_TEXTURE_2D);
1224         glDepthMask(GL_TRUE);
1225         glDisable(GL_BLEND);
1226 }
1227
1228 /*
1229  * main rendering loop
1230  */
1231 static void
1232 draw(ModeInfo * mi)
1233 {
1234         GLfloat x_angle, y_angle, z_angle;
1235         gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
1236         vectorf v1;
1237         GLfloat pos[4];
1238
1239         glClearColor(0.5, 0.5, 0.5, 1.0);
1240         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1241         glLoadIdentity();
1242
1243         gp->tic += 0.005f;
1244
1245         x_angle = gp->cam_x_phase + gp->tic * gp->cam_x_speed;
1246         y_angle = gp->cam_y_phase + gp->tic * gp->cam_y_speed;
1247         z_angle = gp->cam_z_phase + gp->tic * gp->cam_z_speed;
1248
1249         if (move) {
1250                 v1.x = 1 * sin(x_angle);
1251                 v1.y = 1 * sin(y_angle);
1252         } else {
1253                 v1.x = 0;
1254                 v1.y = 0;
1255         }
1256
1257         /* size is changed in pinit() to be distance from plane */
1258         gp->size = MI_SIZE(mi);
1259         if (gp->size > 10) {
1260                 gp->size = 10;
1261         }
1262         if (gp->size < -1) {
1263                 gp->size = -1;
1264         }
1265         if (gp->size != -1) {
1266                 /* user defined size */
1267                 v1.z = gp->size;
1268         } else if (zoom) {
1269                 /* max distance given by adding the constant and the multiplier */
1270                 v1.z = 5.0 + 3.0 * sin(z_angle);
1271         } else {
1272                 /* default */
1273                 v1.z = 7.0;
1274         }
1275
1276         /* update rotation angle (but not if mouse button down) */
1277         if (rotate && !gp->button_down_p)
1278         {
1279                 float   new_rangle_vel = 0.0;
1280
1281                 /* update camera rotation angle and velocity */
1282                 gp->rangle += gp->rangle_vel;
1283                 new_rangle_vel = gp->rangle_vel + gp->rangle_acc;
1284                 if (new_rangle_vel > -MAX_ANGLE_VEL && new_rangle_vel < MAX_ANGLE_VEL)
1285                 {
1286                         /* new velocity is within limits */
1287                         gp->rangle_vel = new_rangle_vel;
1288                 }
1289
1290                 /* randomly change twisting speed - 3ff = 1024 */
1291                 if ((random() % TWISTING_PROBABILITY) < 1.0) {
1292                         gp->rangle_acc = INITIAL_ANGLE_ACC * frand(1.0);
1293                         if (gp->rangle_vel > 0.0) {
1294                                 gp->rangle_acc = -gp->rangle_acc;
1295                         }
1296                 }
1297         }
1298 #if 0
1299         printf("Rangle: %f : %f : %f\n", gp->rangle, gp->rangle_vel, gp->rangle_acc);
1300         printf("Tangle: %f : %f : %f\n", gp->tangle, gp->tangle_vel, gp->tangle_acc);
1301 #endif
1302
1303 #ifdef WOBBLE
1304         /* this makes the image wobble - requires -move and a larger grid */
1305         gluLookAt(0, 0, v1.z, v1.x, v1.y, 0.0, 0.0, 1.0, 0.0);
1306 #else
1307         /* no wobble - camera always perpendicular to grid */
1308
1309         /* rotating camera rather than entire space - smoother */
1310         gluLookAt(
1311                         v1.x, v1.y, v1.z,
1312                         v1.x, v1.y, 0.0,
1313                         sin((gp->xmouse * M_PI * 2) + gp->rangle * RADIANS),
1314                         cos((gp->xmouse * M_PI * 2) + gp->rangle * RADIANS),
1315                         0.0);
1316 #endif
1317
1318         /* light position same as camera */
1319         pos[0] = v1.x;
1320         pos[1] = v1.y;
1321         pos[2] = v1.z;
1322         pos[3] = 0;
1323
1324         if (gp->fade == 0)
1325         {
1326                 /* not fading */
1327                 draw_hexagons(mi, MAX_FADE, &gp->textures[gp->visible]);
1328         }
1329         else
1330         {
1331                 /* fading - show both textures with alpha
1332                 NB first is always max alpha */
1333                 draw_hexagons(mi, MAX_FADE, &gp->textures[1 - gp->visible]);
1334                 draw_hexagons(mi, MAX_FADE - gp->fade, &gp->textures[gp->visible]);
1335
1336                 /* fade some more */
1337                 gp->fade++;
1338
1339                 /* have we faded enough? */
1340                 if (gp->fade > MAX_FADE)
1341                 {
1342                         /* stop fading */
1343                         gp->fade = 0;
1344                         gp->visible = 1 - gp->visible;
1345                 }
1346         }
1347
1348         /* increment texture angle based on time, velocity etc */
1349         /* but only if button is not down */
1350         if (!gp->button_down_p)
1351         {
1352                 float           new_tangle_vel = 0.0;
1353
1354                 gp->tangle += gp->tangle_vel;
1355
1356                 /* work out new texture angle velocity */
1357                 new_tangle_vel = gp->tangle_vel + gp->tangle_acc;
1358                 if (new_tangle_vel > -MAX_ANGLE_VEL && new_tangle_vel < MAX_ANGLE_VEL)
1359                 {
1360                         /* new velocity is inside limits */
1361                         gp->tangle_vel = new_tangle_vel;
1362                 }
1363
1364                 /* randomly change twisting speed - 3ff = 1024 */
1365                 if ((random() % TWISTING_PROBABILITY) < 1.0) {
1366                         gp->tangle_acc = INITIAL_ANGLE_ACC * frand(1.0);
1367                         if (gp->tangle_vel > 0.0) {
1368                                 gp->tangle_acc = -gp->tangle_acc;
1369                         }
1370                 }
1371         }
1372
1373         glFlush();
1374 }
1375
1376 /* 
1377  * new window size or exposure 
1378  */
1379 ENTRYPOINT void reshape_gleidescope(ModeInfo *mi, int width, int height)
1380 {
1381         GLfloat         h = (GLfloat) height / (GLfloat) width;
1382
1383         glViewport(0, 0, (GLint) width, (GLint) height);
1384         glMatrixMode(GL_PROJECTION);
1385         glLoadIdentity();
1386         gluPerspective(50.0, 1/h, 0.1, 2000.0);
1387         glMatrixMode (GL_MODELVIEW);
1388
1389         glLineWidth(1);
1390         glPointSize(1);   
1391 }
1392
1393 static void
1394 pinit(ModeInfo * mi)
1395 {
1396         gleidestruct    *gp = &gleidescope[MI_SCREEN(mi)];
1397
1398         /* set start time - star_time = 0 implies non-dynamic texture */
1399         gp->start_time = (time_t)0;
1400
1401         /* set the texture size to default */
1402         /*
1403         gp->max_tx = 1.0;
1404         gp->max_ty = 1.0;
1405         */
1406
1407         /* no fading */
1408         gp->fade = 0;
1409
1410         glShadeModel(GL_SMOOTH);
1411         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1412         glEnable(GL_DEPTH_TEST);
1413         glEnable(GL_CULL_FACE);
1414         glDisable(GL_LIGHTING);
1415
1416         /* space for textures */
1417         glGenTextures(1, &gp->textures[0].id);
1418         glGenTextures(1, &gp->textures[1].id);
1419         gp->visible = 0;
1420
1421         setup_texture(mi, &gp->textures[gp->visible]);
1422
1423         /*
1424         **      want to choose a value for arg randomly if neither -arg nor -no-arg
1425         **      is specified. xscreensaver libraries don't seem to let you do this -
1426         **      if something isn't true then it is false (pesky two-state boolean values).
1427         **      so, i've defined both -arg and -no-arg to arguments and added the 
1428         **      following logic.
1429         **      (btw if both -arg and -no-arg are defined then arg is set to False)
1430         */
1431         if (zoom == False && nozoom == False)
1432         {
1433                 /* no zoom preference - randomise */
1434                 zoom = (((random() & 0x1) == 0x1) ? True : False);
1435         }
1436         else if (nozoom == True)
1437         {
1438                 /* definately no zoom */
1439                 zoom = False;
1440         }
1441
1442         if (move == False && nomove == False)
1443         {
1444                 /* no move preference - randomise */
1445                 move = (((random() & 0x1) == 0x1) ? True : False);
1446         }
1447         else if (nomove == True)
1448         {
1449                 /* definately no move */
1450                 move = False;
1451         }
1452
1453         if (rotate == False && norotate == False)
1454         {
1455                 /* no rotate preference - randomise */
1456                 rotate = (((random() & 0x1) == 0x1) ? True : False);
1457         }
1458         else if (norotate == True)
1459         {
1460                 /* definately no rotate */
1461                 rotate = False;
1462         }
1463
1464         /* define cam variables */
1465         gp->cam_x_speed = MAX_CAM_SPEED * frandrange(-.5, 0.5);
1466         gp->cam_x_phase = random() % 360;
1467         gp->cam_y_speed = MAX_CAM_SPEED * frandrange(-.5, 0.5);
1468         gp->cam_y_phase = random() % 360;
1469         gp->cam_z_speed = MAX_CAM_SPEED * frandrange(-.5, 0.5);
1470         gp->cam_z_phase = random() % 360;
1471
1472         /* initial angular speeds */
1473         gp->rangle_vel = INITIAL_ANGLE_VEL * frandrange(-.5, 0.5);
1474         gp->tangle_vel = INITIAL_ANGLE_VEL * frandrange(-.5, 0.5);
1475         gp->rangle_acc = INITIAL_ANGLE_ACC * frandrange(-.5, 0.5);
1476         gp->tangle_acc = INITIAL_ANGLE_ACC * frandrange(-.5, 0.5);
1477
1478     /* jwz */
1479 #if 0
1480     {
1481       GLfloat speed = 15;
1482       gp->rangle_vel *= speed;
1483       gp->tangle_vel *= speed;
1484       gp->rangle_acc *= speed;
1485       gp->tangle_acc *= speed;
1486     }
1487 #endif
1488
1489         /* distance is 11 - size */
1490         if (gp->size != -1) {
1491                 if (zoom) {
1492                         fprintf(stderr, "-size given. ignoring -zoom.\n");
1493                         zoom = False;
1494                 }
1495                 if (gp->size < 1) {
1496                         gp->size = 1;
1497                 } else if (gp->size >= 10) {
1498                         gp->size = 10;
1499                 }
1500                 gp->size = 11 - gp->size;
1501         }
1502
1503 #ifdef DEBUG
1504 printf("phases [%d, %d, %d]\n", gp->cam_x_phase, gp->cam_y_phase, gp->cam_z_phase);
1505 #endif
1506 }
1507
1508 ENTRYPOINT void
1509 init_gleidescope(ModeInfo * mi)
1510 {
1511         gleidestruct *gp;
1512         int screen = MI_SCREEN(mi);
1513
1514         if (gleidescope == NULL) {
1515                 gleidescope = (gleidestruct *) calloc(MI_NUM_SCREENS(mi), sizeof (gleidestruct));
1516                 if (gleidescope == NULL) {
1517                         return;
1518                 }
1519         }
1520         gp = &gleidescope[screen];
1521         gp->window = MI_WINDOW(mi);
1522     gp->size = -1;
1523     gp->list = -1;
1524
1525         if ((gp->glx_context = init_GL(mi)) != NULL) {
1526
1527                 reshape_gleidescope(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1528
1529                 glDrawBuffer(GL_BACK);
1530
1531                 /* do initialisation */
1532                 pinit(mi);
1533
1534         } else {
1535                 MI_CLEARWINDOW(mi);
1536         }
1537 }
1538
1539 ENTRYPOINT void
1540 draw_gleidescope(ModeInfo * mi)
1541 {
1542         gleidestruct    *gp = &gleidescope[MI_SCREEN(mi)];
1543         Display         *display = MI_DISPLAY(mi);
1544         Window          window = MI_WINDOW(mi);
1545
1546
1547         if (!gp->glx_context)
1548                 return;
1549
1550     /* Just keep running before the texture has come in. */
1551     /* if (gp->waiting_for_image_p) return; */
1552
1553         glDrawBuffer(GL_BACK);
1554
1555         glXMakeCurrent(display, window, *(gp->glx_context));
1556         draw(mi);
1557
1558         if (mi->fps_p) {
1559                 do_fps (mi);
1560         }
1561
1562         glFinish();
1563         glXSwapBuffers(display, window);
1564
1565 #ifdef GRAB
1566         if (grab) {
1567                 grab_frame(display, window);
1568         }
1569 #endif
1570
1571         /* need to change texture? */
1572         if ((gp->start_time != 0) && (duration != -1) && gp->fade == 0) {
1573                 if (gp->start_time + duration <= time((time_t *)0)) {
1574 #ifdef DEBUG
1575                         printf("Start Time: %lu - Current Time: %lu\n", (unsigned long)gp->start_time, (unsigned long)time((time_t *)0));
1576                         printf("Changing Texture\n");
1577 #endif
1578                         /* get new snapshot (into back buffer) and start fade count */
1579                         setup_texture(mi, &gp->textures[1 - gp->visible]);
1580                         /* restart fading */
1581                         gp->fade = 1;
1582                 }
1583         }
1584 }
1585
1586 ENTRYPOINT void
1587 release_gleidescope(ModeInfo * mi)
1588 {
1589         if (gleidescope != NULL) {
1590                 int screen;
1591
1592                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1593                         gleidestruct *gp = &gleidescope[screen];
1594
1595                         /* acd -  is this needed? */
1596                         if (gp->glx_context) {
1597                                 /* Display lists MUST be freed while their glXContext is current. */
1598                                 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
1599
1600                                 /* acd - was code here for freeing things that are no longer in struct */
1601                         }
1602                 }
1603                 (void) free((void *) gleidescope);
1604                 gleidescope = NULL;
1605         }
1606         
1607         FreeAllGL(mi);
1608 }
1609
1610 XSCREENSAVER_MODULE ("Gleidescope", gleidescope)
1611
1612 #endif