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