http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[xscreensaver] / hacks / glx / gleidescope.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2
3 #if !defined( lint ) && !defined( SABER )
4 /*static const char sccsid[] = "@(#)gleidescope.c       1.0 03/06/27 xlockmore";*/
5 #endif
6
7 /* enable -grab switch */
8 /*#define       GRAB*/
9
10 /*-
11  * Permission to use, copy, modify, and distribute this software and its
12  * documentation for any purpose and without fee is hereby granted,
13  * provided that the above copyright notice appear in all copies and that
14  * both that copyright notice and this permission notice appear in
15  * supporting documentation.
16  *
17  * This file is provided AS IS with no warranties of any kind.  The author
18  * shall have no liability with respect to the infringement of copyrights,
19  * trade secrets or any patents by this file or any part thereof.  In no
20  * event will the author be liable for any lost revenue or profits or
21  * other special, indirect and consequential damages.
22  *
23  *      Revision History:
24  *
25  *      20030627        1.0             acd             First Release.
26  *                                                              Texture loading code from 'glplanet'
27  *                                                                      by Jamie Zawinski <jwz@jwz.org>
28  *      20030810        1.1             acd             Added size flag.
29  *                                                              Now grabs screen / video / picture
30  *                                                                      (uses code from 'glslideshow' by
31  *                                                                      Mike Oliphant, Ben Buxton, Jamie Zawinski).
32  *                                                              Added -duration.
33  *                                                              Added mouse code.
34  *                                                              Added fade code (also from glslideshow).
35  *      20031013        1.2             acd             Migrated to compile without warnings under
36  *                                                                      xscreensaver 4.13.
37  *      20031023        1.3             acd             Better code to limit twisting speeds.
38  *                                                              Tweaked initial rotation values.
39  *                                                              Move, Rotate, Zoom now chosen at random if
40  *                                                                      no preference is given.
41  *                                                              Made grid slightly bigger so you can't see
42  *                                                                      the edge when zooming and moving.
43  */
44
45 /*
46 **----------------------------------------------------------------------------
47 ** Defines
48 **----------------------------------------------------------------------------
49 */
50
51 #ifdef STANDALONE
52 # define DEFAULTS \
53                 "*delay:                20000           \n"     \
54                 "*showFPS:              False           \n"     \
55                 "*size:                 -1                      \n"     \
56                 "*useSHM:               True            \n"
57
58 # define refresh_gleidescope 0
59 # include "xlockmore.h"                         /* from the xscreensaver distribution */
60 #else  /* !STANDALONE */
61 # include "xlock.h"                                     /* from the xlockmore distribution */
62 #endif /* !STANDALONE */
63
64 #ifdef USE_GL
65
66 #include "colors.h"
67 #include "xpm-ximage.h"
68 #include "grab-ximage.h"
69
70 /* acd TODO should all these be in gleidestruct? */
71 /* they can't be, because of the idiotic way the xlockmore "argtype vars"
72    interface works. -jwz */
73 #ifdef GRAB
74 static Bool             grab;                   /* grab images */
75 #endif
76 static Bool             move;                   /* moving camera */
77 static Bool             nomove;                 /* no moving camera */
78 static Bool             rotate;                 /* rotate in place */
79 static Bool             norotate;               /* no rotate in place */
80 static Bool             zoom;                   /* zooming camera */
81 static Bool             nozoom;                 /* no zooming camera */
82 static char             *image;                 /* name of texture to load */
83 static int              duration;               /* length of time to display grabbed image */
84
85 #define MAX_TANGLE_VEL  2.0
86 #define MAX_RANGLE_VEL  1.5
87
88 static XrmOptionDescRec opts[] =
89 {
90 #ifdef GRAB
91         {"-grab",               ".gleidescope.grab",            XrmoptionNoArg,         "true"},
92 #endif
93         {"-move",               ".gleidescope.move",            XrmoptionNoArg,         "true"},
94         {"-no-move",    ".gleidescope.nomove",          XrmoptionNoArg,         "true"},
95         {"-rotate",             ".gleidescope.rotate",          XrmoptionNoArg,         "true"},
96         {"-no-rotate",  ".gleidescope.norotate",        XrmoptionNoArg,         "true"},
97         /*{"-size",             ".gleidescope.size",            XrmoptionNoArg,         "-1"},*/
98         {"-zoom",               ".gleidescope.zoom",            XrmoptionNoArg,         "true"},
99         {"-no-zoom",    ".gleidescope.nozoom",          XrmoptionNoArg,         "true"},
100         {"-image",              ".gleidescope.image",           XrmoptionSepArg,        "DEFAULT"},
101         {"-duration",   ".gleidescope.duration",        XrmoptionSepArg,        "30"},
102 };
103
104
105 static argtype vars[] = {
106 #ifdef GRAB
107         {&grab,                 "grab",         "Grab",         "False",        t_Bool},
108 #endif
109         {&move,                 "move",         "Move",         "False",        t_Bool},
110         {&nomove,               "nomove",       "noMove",       "False",        t_Bool},
111         {&rotate,               "rotate",       "Rotate",       "False",        t_Bool},
112         {&norotate,             "norotate",     "noRotate",     "False",        t_Bool},
113         /*{&size,               "size",         "Size",         "-1",           t_Int},*/
114         {&zoom,                 "zoom",         "Zoom",         "False",        t_Bool},
115         {&nozoom,               "nozoom",       "noZoom",       "False",        t_Bool},
116         {&image,                "image",        "Image",        "DEFAULT",      t_String},
117         {&duration,             "duration",     "Duration",     "30",           t_Int},
118 };
119
120 static OptionStruct desc[] = {
121 #ifdef GRAB
122         {"-grab",               "grab images to create animation"},
123 #endif
124         {"-move",               "camera will move"},
125         {"-no-move",    "camera won't move"},
126         {"-rotate",             "camera will rotate"},
127         {"-no-rotate",  "camera won't rotate"},
128         /*{"-size",             "size of the hexagons (1-10)"},*/
129         {"-zoom",               "camera will zoom"},
130         {"-no-zoom",    "camera won't zoom"},
131         {"-image",              "xpm / xbm image file to use for texture"},
132         {"-duration",   "length of time texture will be used"},
133 };
134
135 ENTRYPOINT ModeSpecOpt gleidescope_opts = {
136         sizeof opts / sizeof opts[0], opts,
137         sizeof vars / sizeof vars[0], vars,
138         desc
139 };
140
141 #ifdef USE_MODULES
142 ModStruct   gleidescope_description = { 
143      "gleidescope", "init_gleidescope", "draw_gleidescope", "release_gleidescope",
144      "draw_gleidescope", "init_gleidescope", NULL, &gleidescope_opts,
145      1000, 1, 2, 1, 4, 1.0, "",
146      "GL Kaleidescope", 0, NULL};
147 #endif
148
149 /*
150 **-----------------------------------------------------------------------------
151 **      Typedefs
152 **-----------------------------------------------------------------------------
153 */
154
155 typedef struct hex_s {
156         GLfloat x, y, z;                /* position */
157 } hex_t;
158
159 typedef struct {
160         GLfloat x;
161         GLfloat y;
162         GLfloat z;
163 } vectorf;
164
165 #define MAX_FADE        500     /* number of fade cycles */
166
167 typedef struct {
168         float                   cam_x_speed, cam_z_speed, cam_y_speed;
169         int                             cam_x_phase, cam_z_phase, cam_y_phase;
170         float                   tic;
171         GLXContext              *glx_context;
172         Window                  window;
173         GLfloat                 max_tx, max_ty; /* maximum texture sizes */
174         GLuint                  textures[2];    /* texture handles */
175         GLuint                  visible;                /* texture handle for new texture */
176         GLint                   fade;
177         time_t                  start_time;
178         Bool                    button_down_p;
179
180     int         size;
181
182     float       tangle;         /* texture angle */
183     float       tangle_vel;     /* texture velocity */
184     float       tangle_acc;     /* texture acceleration */
185
186     float       rangle;         /* rotate angle */
187     float       rangle_vel;     /* rotate velocity */
188     float       rangle_acc;     /* rotate acceleration */
189
190     /* mouse */
191     int xstart;
192     int ystart;
193     double xmouse;
194     double ymouse;
195
196     Bool mipmap_p;
197     Bool waiting_for_image_p;
198
199 } gleidestruct;
200
201 #define XOFFSET (0.8660254f)    /* sin 60' */
202 #define YOFFSET (1.5000000f)    /* cos 60' + 1 */
203
204 #if 0
205
206 #define SIZE    3
207
208 /* generates a grid with edges of given size */
209 /* acd TODO - replace hex[] with this and allow size and distance as parameters */
210
211 int
212 generate_grid(int size)
213
214         int     i, x, y;
215
216         gp->size--;
217
218         i = gp->size;
219         for (y = -size ; y <= size ; y++) {
220                 for (x = -i ; x <= i ; x += 2) {
221                         printf("{XOFFSET * %d, YOFFSET * %d, 0},\n", x, y);
222                 }
223                 printf("\n");
224                 if (y < 0) {
225                         i++;
226                 } else {
227                         i--;
228                 }
229         }
230         return 0;
231 }
232 #endif
233
234 static const hex_t hex[] = {
235         /* edges of size 7 */
236         /* number of hexagons required to cover screen depends on camera distance */
237         /* at a distance of 10 this is just about enough. */
238         {XOFFSET * -6, YOFFSET * -6, 0},
239         {XOFFSET * -4, YOFFSET * -6, 0},
240         {XOFFSET * -2, YOFFSET * -6, 0},
241         {XOFFSET * 0, YOFFSET * -6, 0},
242         {XOFFSET * 2, YOFFSET * -6, 0},
243         {XOFFSET * 4, YOFFSET * -6, 0},
244         {XOFFSET * 6, YOFFSET * -6, 0},
245
246         {XOFFSET * -7, YOFFSET * -5, 0},
247         {XOFFSET * -5, YOFFSET * -5, 0},
248         {XOFFSET * -3, YOFFSET * -5, 0},
249         {XOFFSET * -1, YOFFSET * -5, 0},
250         {XOFFSET * 1, YOFFSET * -5, 0},
251         {XOFFSET * 3, YOFFSET * -5, 0},
252         {XOFFSET * 5, YOFFSET * -5, 0},
253         {XOFFSET * 7, YOFFSET * -5, 0},
254
255         {XOFFSET * -8, YOFFSET * -4, 0},
256         {XOFFSET * -6, YOFFSET * -4, 0},
257         {XOFFSET * -4, YOFFSET * -4, 0},
258         {XOFFSET * -2, YOFFSET * -4, 0},
259         {XOFFSET * 0, YOFFSET * -4, 0},
260         {XOFFSET * 2, YOFFSET * -4, 0},
261         {XOFFSET * 4, YOFFSET * -4, 0},
262         {XOFFSET * 6, YOFFSET * -4, 0},
263         {XOFFSET * 8, YOFFSET * -4, 0},
264
265         {XOFFSET * -9, YOFFSET * -3, 0},
266         {XOFFSET * -7, YOFFSET * -3, 0},
267         {XOFFSET * -5, YOFFSET * -3, 0},
268         {XOFFSET * -3, YOFFSET * -3, 0},
269         {XOFFSET * -1, YOFFSET * -3, 0},
270         {XOFFSET * 1, YOFFSET * -3, 0},
271         {XOFFSET * 3, YOFFSET * -3, 0},
272         {XOFFSET * 5, YOFFSET * -3, 0},
273         {XOFFSET * 7, YOFFSET * -3, 0},
274         {XOFFSET * 9, YOFFSET * -3, 0},
275
276         {XOFFSET * -10, YOFFSET * -2, 0},
277         {XOFFSET * -8, YOFFSET * -2, 0},
278         {XOFFSET * -6, YOFFSET * -2, 0},
279         {XOFFSET * -4, YOFFSET * -2, 0},
280         {XOFFSET * -2, YOFFSET * -2, 0},
281         {XOFFSET * 0, YOFFSET * -2, 0},
282         {XOFFSET * 2, YOFFSET * -2, 0},
283         {XOFFSET * 4, YOFFSET * -2, 0},
284         {XOFFSET * 6, YOFFSET * -2, 0},
285         {XOFFSET * 8, YOFFSET * -2, 0},
286         {XOFFSET * 10, YOFFSET * -2, 0},
287
288         {XOFFSET * -11, YOFFSET * -1, 0},
289         {XOFFSET * -9, YOFFSET * -1, 0},
290         {XOFFSET * -7, YOFFSET * -1, 0},
291         {XOFFSET * -5, YOFFSET * -1, 0},
292         {XOFFSET * -3, YOFFSET * -1, 0},
293         {XOFFSET * -1, YOFFSET * -1, 0},
294         {XOFFSET * 1, YOFFSET * -1, 0},
295         {XOFFSET * 3, YOFFSET * -1, 0},
296         {XOFFSET * 5, YOFFSET * -1, 0},
297         {XOFFSET * 7, YOFFSET * -1, 0},
298         {XOFFSET * 9, YOFFSET * -1, 0},
299         {XOFFSET * 11, YOFFSET * -1, 0},
300
301         {XOFFSET * -12, YOFFSET * 0, 0},
302         {XOFFSET * -10, YOFFSET * 0, 0},
303         {XOFFSET * -8, YOFFSET * 0, 0},
304         {XOFFSET * -6, YOFFSET * 0, 0},
305         {XOFFSET * -4, YOFFSET * 0, 0},
306         {XOFFSET * -2, YOFFSET * 0, 0},
307         {XOFFSET * 0, YOFFSET * 0, 0},
308         {XOFFSET * 2, YOFFSET * 0, 0},
309         {XOFFSET * 4, YOFFSET * 0, 0},
310         {XOFFSET * 6, YOFFSET * 0, 0},
311         {XOFFSET * 8, YOFFSET * 0, 0},
312         {XOFFSET * 10, YOFFSET * 0, 0},
313         {XOFFSET * 12, YOFFSET * 0, 0},
314
315         {XOFFSET * -11, YOFFSET * 1, 0},
316         {XOFFSET * -9, YOFFSET * 1, 0},
317         {XOFFSET * -7, YOFFSET * 1, 0},
318         {XOFFSET * -5, YOFFSET * 1, 0},
319         {XOFFSET * -3, YOFFSET * 1, 0},
320         {XOFFSET * -1, YOFFSET * 1, 0},
321         {XOFFSET * 1, YOFFSET * 1, 0},
322         {XOFFSET * 3, YOFFSET * 1, 0},
323         {XOFFSET * 5, YOFFSET * 1, 0},
324         {XOFFSET * 7, YOFFSET * 1, 0},
325         {XOFFSET * 9, YOFFSET * 1, 0},
326         {XOFFSET * 11, YOFFSET * 1, 0},
327
328         {XOFFSET * -10, YOFFSET * 2, 0},
329         {XOFFSET * -8, YOFFSET * 2, 0},
330         {XOFFSET * -6, YOFFSET * 2, 0},
331         {XOFFSET * -4, YOFFSET * 2, 0},
332         {XOFFSET * -2, YOFFSET * 2, 0},
333         {XOFFSET * 0, YOFFSET * 2, 0},
334         {XOFFSET * 2, YOFFSET * 2, 0},
335         {XOFFSET * 4, YOFFSET * 2, 0},
336         {XOFFSET * 6, YOFFSET * 2, 0},
337         {XOFFSET * 8, YOFFSET * 2, 0},
338         {XOFFSET * 10, YOFFSET * 2, 0},
339
340         {XOFFSET * -9, YOFFSET * 3, 0},
341         {XOFFSET * -7, YOFFSET * 3, 0},
342         {XOFFSET * -5, YOFFSET * 3, 0},
343         {XOFFSET * -3, YOFFSET * 3, 0},
344         {XOFFSET * -1, YOFFSET * 3, 0},
345         {XOFFSET * 1, YOFFSET * 3, 0},
346         {XOFFSET * 3, YOFFSET * 3, 0},
347         {XOFFSET * 5, YOFFSET * 3, 0},
348         {XOFFSET * 7, YOFFSET * 3, 0},
349         {XOFFSET * 9, YOFFSET * 3, 0},
350
351         {XOFFSET * -8, YOFFSET * 4, 0},
352         {XOFFSET * -6, YOFFSET * 4, 0},
353         {XOFFSET * -4, YOFFSET * 4, 0},
354         {XOFFSET * -2, YOFFSET * 4, 0},
355         {XOFFSET * 0, YOFFSET * 4, 0},
356         {XOFFSET * 2, YOFFSET * 4, 0},
357         {XOFFSET * 4, YOFFSET * 4, 0},
358         {XOFFSET * 6, YOFFSET * 4, 0},
359         {XOFFSET * 8, YOFFSET * 4, 0},
360
361         {XOFFSET * -7, YOFFSET * 5, 0},
362         {XOFFSET * -5, YOFFSET * 5, 0},
363         {XOFFSET * -3, YOFFSET * 5, 0},
364         {XOFFSET * -1, YOFFSET * 5, 0},
365         {XOFFSET * 1, YOFFSET * 5, 0},
366         {XOFFSET * 3, YOFFSET * 5, 0},
367         {XOFFSET * 5, YOFFSET * 5, 0},
368         {XOFFSET * 7, YOFFSET * 5, 0},
369
370         {XOFFSET * -6, YOFFSET * 6, 0},
371         {XOFFSET * -4, YOFFSET * 6, 0},
372         {XOFFSET * -2, YOFFSET * 6, 0},
373         {XOFFSET * 0, YOFFSET * 6, 0},
374         {XOFFSET * 2, YOFFSET * 6, 0},
375         {XOFFSET * 4, YOFFSET * 6, 0},
376         {XOFFSET * 6, YOFFSET * 6, 0},
377 };
378
379 /*
380 **----------------------------------------------------------------------------
381 ** Local Variables
382 **----------------------------------------------------------------------------
383 */
384
385 static  gleidestruct *gleidescope = NULL;
386
387 #if 0
388 /*
389  *load defaults in config structure
390  */
391 static void setdefaultconfig(void)
392 {
393 #ifdef GRAB
394         grab = False;
395 #endif
396         move = False;
397         rotate = False;
398         zoom = False;
399         image = NULL;
400 }
401 #endif
402
403 ENTRYPOINT Bool
404 gleidescope_handle_event(ModeInfo *mi, XEvent *event)
405 {
406         gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
407
408         /*
409         printf("event:%d\n", event->xany.type);
410         printf("button:%d\n", event->xbutton.button);
411         */
412         switch(event->xany.type)
413         {
414                 case ButtonPress:
415
416                         if (event->xbutton.button == Button1 ||
417                 event->xbutton.button == Button3)
418                         {
419                                 /* store initial values of mouse */
420                                 gp->xstart = event->xbutton.x;
421                                 gp->ystart = event->xbutton.y;
422
423                                 /* button is down */
424                                 gp->button_down_p = True;
425                                 return True;
426                         }
427 #if 0   /* TODO */
428                         else if (event->xbutton.button == Button4)
429                         {
430                                 /* zoom in */
431                                 return True;
432                         }
433                         else if (event->xbutton.button == Button5)
434                         {
435                                 /* zoom out */
436                                 return True;
437                         }
438 #endif
439                         break;
440
441                 case ButtonRelease:
442
443                         if (event->xbutton.button == Button1 ||
444                 event->xbutton.button == Button3)
445                         {
446                                 /* button is up */
447                                 gp->button_down_p = False;
448                                 return True;
449                         }
450                         break;
451
452                 case MotionNotify:
453
454                         if (gp->button_down_p)
455                         {
456                                 /* update mouse position */
457                                 gp->xmouse += (double)(event->xmotion.x - gp->xstart) / MI_WIDTH(mi);
458                                 gp->ymouse += (double)(event->xmotion.y - gp->ystart) / MI_HEIGHT(mi);
459                                 gp->xstart = event->xmotion.x;
460                                 gp->ystart = event->xmotion.y;
461
462                                 return True;
463                         }
464                         break;
465         }
466
467         return False;
468 }
469
470
471 static void
472 image_loaded_cb (const char *filename, XRectangle *geometry,
473                  int image_width, int image_height, 
474                  int texture_width, int texture_height,
475                  void *closure)
476 {
477   gleidestruct *gp = (gleidestruct *) closure;
478
479   gp->max_tx = (GLfloat) image_width  / texture_width;
480   gp->max_ty = (GLfloat) image_height / texture_height;
481
482   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
483   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
484                    (gp->mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
485
486   gp->waiting_for_image_p = False;
487   gp->start_time = time ((time_t *) 0);
488 }
489
490
491 static void
492 getSnapshot(ModeInfo *mi, GLuint name)
493 {
494         gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
495
496         if (MI_IS_WIREFRAME(mi))
497                 return;
498
499     gp->mipmap_p = True;
500     load_texture_async (mi->xgwa.screen, mi->window,
501                         *gp->glx_context, 0, 0, gp->mipmap_p, 
502                         name, image_loaded_cb, gp);
503 }
504
505
506 static void
507 setup_file_texture (ModeInfo *mi, char *filename, GLuint name)
508 {
509         Display *dpy = mi->dpy;
510         Visual *visual = mi->xgwa.visual;
511         char buf[1024];
512
513         Colormap cmap = mi->xgwa.colormap;
514         XImage *image = xpm_file_to_ximage (dpy, visual, cmap, filename);
515
516         /* use this texture */
517         glBindTexture(GL_TEXTURE_2D, name);
518
519         clear_gl_error();
520         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
521                         image->width, image->height, 0,
522                         GL_RGBA, GL_UNSIGNED_BYTE, image->data);
523         sprintf (buf, "texture: %.100s (%dx%d)",
524                         filename, image->width, image->height);
525         check_gl_error(buf);
526
527         /* setup parameters for texturing */
528         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
529         glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
530
531         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
532         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
533         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
534         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
535         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
536 }
537
538 static void
539 setup_texture(ModeInfo * mi, GLuint id)
540 {
541         gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
542
543         if (!image || !*image || !strcmp(image, "DEFAULT")) {
544                 /* no image specified - grab screen */
545                 getSnapshot(mi, id);
546                 /* max_tx and max_ty set in getSnapshot() */
547         } else {
548                 /* use supplied image file */
549                 setup_file_texture(mi, image, id);
550
551                 /* set tx params to use whole image */
552                 gp->max_tx = 1.0f;
553                 gp->max_ty = 1.0f;
554         }
555
556         check_gl_error("texture initialization");
557
558         /* Need to flip the texture top for bottom for some reason. */
559         glMatrixMode (GL_TEXTURE);
560         glScalef (1, -1, 1);
561         glMatrixMode (GL_MODELVIEW);
562 }
563
564 #define VERTEX0 glVertex3f( 0.0000f,  0.000f, 0.0f);
565 #define VERTEX1 glVertex3f( 0.0000f,  1.000f, 0.0f);
566 #define VERTEX2 glVertex3f( XOFFSET,  0.500f, 0.0f);
567 #define VERTEX3 glVertex3f( XOFFSET, -0.500f, 0.0f);
568 #define VERTEX4 glVertex3f( 0.0000f, -1.000f, 0.0f);
569 #define VERTEX5 glVertex3f(-XOFFSET, -0.500f, 0.0f);
570 #define VERTEX6 glVertex3f(-XOFFSET,  0.500f, 0.0f);
571
572 static void
573 draw_hexagons(ModeInfo *mi, int translucency, GLuint texture)
574 {
575         int             i;
576         GLfloat col[4];
577         GLfloat t1x, t1y, t2x, t2y, t3x, t3y;
578         gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
579         GLfloat tangle2;
580
581         col[0] = 1.0;
582         col[1] = 1.0;
583         col[2] = 1.0;
584         col[3] = (float)translucency / MAX_FADE;
585
586         /* calculate vertices of equilateral triangle within image. */
587         /* t1 is always in centre */
588         t1x = gp->max_tx / 2;
589         t1y = gp->max_ty / 2;
590         /* t2 rotates */
591         t2x = (gp->max_tx / 2) * (1 + cos((gp->ymouse * 2 * M_PI) + (gp->tangle * M_PI / 180)));
592         t2y = (gp->max_ty / 2) * (1 + sin((gp->ymouse * 2 * M_PI) + (gp->tangle * M_PI / 180)));
593         /* t3 is always 60' further around than t2 */
594         tangle2 = (gp->ymouse * 2 * M_PI) + (gp->tangle * M_PI / 180) + (M_PI * 2 / 6);
595         t3x = (gp->max_tx / 2) * (1 + (cos(tangle2)));
596         t3y = (gp->max_ty / 2) * (1 + (sin(tangle2)));
597         /* NB image is flipped vertically hence: */
598         t1y = 1 - t1y;
599         t2y = 1 - t2y;
600         t3y = 1 - t3y;
601         /*printf("texcoords:[%f,%f]->[%f,%f](%f,%f)\n", t1x, t1y, t2x, t2y, gp->max_tx, gp->max_ty);*/
602
603         glColor4f(1.0, 1.0, 1.0, (float)translucency / MAX_FADE);
604         glEnable(GL_TEXTURE_2D);
605         glEnable(GL_BLEND);
606         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
607         glDepthMask(GL_FALSE);
608         glBindTexture(GL_TEXTURE_2D, gp->textures[texture]);
609
610         for (i = 0 ; i < sizeof(hex) / sizeof(hex[0]) ; i++) {
611
612                 glPushMatrix();
613
614                 glTranslatef(hex[i].x, hex[i].y, 0.0);
615
616                 glBegin(GL_TRIANGLES);
617
618                 /*
619                 ** six triangles to each hexagon
620                 */
621
622                 glTexCoord2f(t1x, t1y);
623                 VERTEX0;
624                 glTexCoord2f(t2x, t2y);
625                 VERTEX1;
626                 glTexCoord2f(t3x, t3y);
627                 VERTEX6;
628
629                 glTexCoord2f(t1x, t1y);
630                 VERTEX0;
631                 glTexCoord2f(t3x, t3y);
632                 VERTEX6;
633                 glTexCoord2f(t2x, t2y);
634                 VERTEX5;
635
636                 glTexCoord2f(t1x, t1y);
637                 VERTEX0;
638                 glTexCoord2f(t2x, t2y);
639                 VERTEX5;
640                 glTexCoord2f(t3x, t3y);
641                 VERTEX4;
642
643                 glTexCoord2f(t1x, t1y);
644                 VERTEX0;
645                 glTexCoord2f(t3x, t3y);
646                 VERTEX4;
647                 glTexCoord2f(t2x, t2y);
648                 VERTEX3;
649
650                 glTexCoord2f(t1x, t1y);
651                 VERTEX0;
652                 glTexCoord2f(t2x, t2y);
653                 VERTEX3;
654                 glTexCoord2f(t3x, t3y);
655                 VERTEX2;
656
657                 glTexCoord2f(t1x, t1y);
658                 VERTEX0;
659                 glTexCoord2f(t3x, t3y);
660                 VERTEX2;
661                 glTexCoord2f(t2x, t2y);
662                 VERTEX1;
663
664                 glEnd();
665
666                 glPopMatrix();
667         }
668         
669 #ifdef DISPLAY_TEXTURE
670         glPushMatrix();
671         /* acd debug - display (bigger, centred) texture */
672         glScalef(2.0, 2.0, 2.0);
673         glTranslatef(-0.5, -0.5, 0.0);
674         glBegin(GL_QUADS);
675         glTexCoord2f(0.0, 0.0);
676         glVertex3f(0.0, 0.0, -0.1);
677         glTexCoord2f(1.0, 0.0);
678         glVertex3f(1.0, 0.0, -0.1);
679         glTexCoord2f(1.0, 1.0);
680         glVertex3f(1.0, 1.0, -0.1);
681         glTexCoord2f(0.0, 1.0);
682         glVertex3f(0.0, 1.0, -0.1);
683         glEnd();
684         /* acd debug - display texture triangle */
685         glColor4f(1.0, 1.0, 1.0, 1.0);
686         glBegin(GL_LINE_LOOP);
687         glVertex3f(t1x, t1y, -0.11);
688         glVertex3f(t2x, t2y, -0.11);
689         glVertex3f(t3x, t3y, -0.11);
690         glEnd();
691         glPopMatrix();
692 #endif
693
694         glDisable(GL_TEXTURE_2D);
695         glDepthMask(GL_TRUE);
696         glDisable(GL_BLEND);
697 }
698
699 /*
700  * main rendering loop
701  */
702 static void
703 draw(ModeInfo * mi)
704 {
705         GLfloat x_angle, y_angle, z_angle;
706         gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
707         vectorf v1;
708         GLfloat pos[4];
709
710         glClearColor(0.5, 0.5, 0.5, 1.0);
711         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
712         glLoadIdentity();
713
714         gp->tic += 0.005f;
715
716         x_angle = gp->cam_x_phase + gp->tic * gp->cam_x_speed;
717         y_angle = gp->cam_y_phase + gp->tic * gp->cam_y_speed;
718         z_angle = gp->cam_z_phase + gp->tic * gp->cam_z_speed;
719
720         if (move) {
721                 v1.x = 2 * sin(x_angle);
722                 v1.y = 2 * sin(y_angle);
723         } else {
724                 v1.x = 0;
725                 v1.y = 0;
726         }
727
728         /* size is changed in pinit() to be distance from plane */
729         gp->size = MI_SIZE(mi);
730         if (gp->size > 10) {
731                 gp->size = 10;
732         }
733         if (gp->size < -1) {
734                 gp->size = -1;
735         }
736         if (gp->size != -1) {
737                 /* user defined size */
738                 v1.z = gp->size;
739         } else if (zoom) {
740                 /* max distance given by adding the constant and the multiplier */
741                 v1.z = 5.0 + 4.0 * sin(z_angle);
742         } else {
743                 /* default */
744                 v1.z = 7.0;
745         }
746
747         /* update rotation angle (but not if mouse button down) */
748         if (rotate && !gp->button_down_p)
749         {
750                 float   new_rangle_vel = 0.0;
751
752                 /* update camera rotation angle and velocity */
753                 gp->rangle += gp->rangle_vel;
754                 new_rangle_vel = gp->rangle_vel + gp->rangle_acc;
755                 if (new_rangle_vel > -MAX_RANGLE_VEL && new_rangle_vel < MAX_RANGLE_VEL)
756                 {
757                         /* new velocity is within limits */
758                         gp->rangle_vel = new_rangle_vel;
759                 }
760
761                 /* randomly change twisting speed */
762                 if ((random() % 1000) < 1)
763                 {
764                         gp->rangle_acc = frand(0.002) - 0.001;
765                 }
766         }
767
768 #ifdef WOBBLE
769         /* this makes the image wobble - requires -move and a larger grid */
770         gluLookAt(0, 0, v1.z, v1.x, v1.y, 0.0, 0.0, 1.0, 0.0);
771 #else
772         /* no wobble - camera always perpendicular to grid */
773
774         /* rotating camera rather than entire space - smoother */
775         gluLookAt(
776                         v1.x, v1.y, v1.z,
777                         v1.x, v1.y, 0.0,
778                         sin((gp->xmouse * M_PI * 2) + gp->rangle * M_PI / 180),
779                         cos((gp->xmouse * M_PI * 2) + gp->rangle * M_PI / 180),
780                         0.0);
781 #endif
782
783         /* light position same as camera */
784         pos[0] = v1.x;
785         pos[1] = v1.y;
786         pos[2] = v1.z;
787         pos[3] = 0;
788
789         if (gp->fade == 0)
790         {
791                 /* not fading */
792                 draw_hexagons(mi, MAX_FADE, gp->visible);
793         }
794         else
795         {
796                 /* fading - show both textures with alpha */
797                 draw_hexagons(mi, MAX_FADE - gp->fade, gp->visible);
798                 draw_hexagons(mi, gp->fade, 1 - gp->visible);
799
800                 /* fade some more */
801                 gp->fade++;
802
803                 /* have we faded enough? */
804                 if (gp->fade > MAX_FADE)
805                 {
806                         /* stop fading */
807                         gp->fade = 0;
808                         gp->visible = 1 - gp->visible;
809                 }
810         }
811
812         /* increment texture angle based on time, velocity etc */
813         /* but only if button is not down */
814         if (!gp->button_down_p)
815         {
816                 float           new_tangle_vel = 0.0;
817
818                 gp->tangle += gp->tangle_vel;
819
820                 /* work out new texture angle velocity */
821                 new_tangle_vel = gp->tangle_vel + gp->tangle_acc;
822                 if (new_tangle_vel > -MAX_TANGLE_VEL && new_tangle_vel < MAX_TANGLE_VEL)
823                 {
824                         /* new velocity is inside limits */
825                         gp->tangle_vel = new_tangle_vel;
826                 }
827
828                 /* randomly change texture angle acceleration */
829                 if ((random() % 1000) < 1)
830                 {
831                         gp->tangle_acc = frand(0.002) - 0.001;
832                 }
833         }
834
835         glFlush();
836 }
837
838 /* 
839  * new window size or exposure 
840  */
841 ENTRYPOINT void reshape_gleidescope(ModeInfo *mi, int width, int height)
842 {
843         GLfloat         h = (GLfloat) height / (GLfloat) width;
844
845         glViewport(0, 0, (GLint) width, (GLint) height);
846         glMatrixMode(GL_PROJECTION);
847         glLoadIdentity();
848         gluPerspective(50.0, 1/h, 0.1, 2000.0);
849         glMatrixMode (GL_MODELVIEW);
850
851         glLineWidth(1);
852         glPointSize(1);   
853 }
854
855 static void
856 pinit(ModeInfo * mi)
857 {
858         gleidestruct    *gp = &gleidescope[MI_SCREEN(mi)];
859
860         /* set start time - star_time = 0 implies non-dynamic texture */
861         gp->start_time = (time_t)0;
862
863         /* set the texture size to default */
864         gp->max_tx = 1.0;
865         gp->max_ty = 1.0;
866
867         /* no fading */
868         gp->fade = 0;
869
870         glShadeModel(GL_SMOOTH);
871         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
872         glEnable(GL_DEPTH_TEST);
873         glEnable(GL_CULL_FACE);
874         glDisable(GL_LIGHTING);
875
876         /* space for textures */
877         glGenTextures(1, &gp->textures[0]);
878         glGenTextures(1, &gp->textures[1]);
879         gp->visible = 0;
880
881         setup_texture(mi, gp->textures[gp->visible]);
882
883         /*
884         **      want to choose a value for arg randomly if neither -arg nor -no-arg
885         **      is specified. xscreensaver libraries don't seem to let you do this -
886         **      if something isn't true then it is false (pesky two-state boolean values).
887         **      so, i've defined both -arg and -no-arg to arguments and added the 
888         **      following logic.
889         **      (btw if both -arg and -no-arg are defined then arg is set to False)
890         */
891         if (zoom == False && nozoom == False)
892         {
893                 /* no zoom preference - randomise */
894                 zoom = (((random() & 0x1) == 0x1) ? True : False);
895         }
896         else if (nozoom == True)
897         {
898                 /* definately no zoom */
899                 zoom = False;
900         }
901
902         if (move == False && nomove == False)
903         {
904                 /* no move preference - randomise */
905                 move = (((random() & 0x1) == 0x1) ? True : False);
906         }
907         else if (nomove == True)
908         {
909                 /* definately no move */
910                 move = False;
911         }
912
913         if (rotate == False && norotate == False)
914         {
915                 /* no rotate preference - randomise */
916                 rotate = (((random() & 0x1) == 0x1) ? True : False);
917         }
918         else if (norotate == True)
919         {
920                 /* definately no rotate */
921                 rotate = False;
922         }
923
924         /* define cam variables */
925         gp->cam_x_speed = frand(3.0) - 1.5;
926         gp->cam_x_phase = random() % 360;
927         gp->cam_y_speed = frand(3.0) - 1.5;
928         gp->cam_y_phase = random() % 360;
929         gp->cam_z_speed = frand(3.0) - 1.5;
930         gp->cam_z_phase = random() % 360;
931
932         /* initial angular speeds */
933         gp->rangle_vel = frand(0.2) - 0.1;
934         gp->tangle_vel = frand(0.2) - 0.1;
935         gp->rangle_acc = frand(0.002) - 0.001;
936         gp->tangle_acc = frand(0.002) - 0.001;
937
938     /* jwz */
939     {
940       GLfloat speed = 15;
941       gp->rangle_vel *= speed;
942       gp->tangle_vel *= speed;
943       gp->rangle_acc *= speed;
944       gp->tangle_acc *= speed;
945     }
946
947         /* distance is 11 - size */
948         if (gp->size != -1) {
949                 if (zoom) {
950                         fprintf(stderr, "-size given. ignoring -zoom.\n");
951                         zoom = False;
952                 }
953                 if (gp->size < 1) {
954                         gp->size = 1;
955                 } else if (gp->size >= 10) {
956                         gp->size = 10;
957                 }
958                 gp->size = 11 - gp->size;
959         }
960
961 #ifdef DEBUG
962 printf("phases [%d, %d, %d]\n", gp->cam_x_phase, gp->cam_y_phase, gp->cam_z_phase);
963 #endif
964 }
965
966 ENTRYPOINT void
967 init_gleidescope(ModeInfo * mi)
968 {
969         gleidestruct *gp;
970         int screen = MI_SCREEN(mi);
971
972
973         if (gleidescope == NULL) {
974                 gleidescope = (gleidestruct *) calloc(MI_NUM_SCREENS(mi), sizeof (gleidestruct));
975                 if (gleidescope == NULL) {
976                         return;
977                 }
978         }
979         gp = &gleidescope[screen];
980         gp->window = MI_WINDOW(mi);
981     gp->size = -1;
982
983         if ((gp->glx_context = init_GL(mi)) != NULL) {
984
985                 reshape_gleidescope(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
986
987                 glDrawBuffer(GL_BACK);
988
989                 /* do initialisation */
990                 pinit(mi);
991
992         } else {
993                 MI_CLEARWINDOW(mi);
994         }
995 }
996
997 ENTRYPOINT void
998 draw_gleidescope(ModeInfo * mi)
999 {
1000         gleidestruct    *gp = &gleidescope[MI_SCREEN(mi)];
1001         Display         *display = MI_DISPLAY(mi);
1002         Window          window = MI_WINDOW(mi);
1003
1004
1005         if (!gp->glx_context)
1006                 return;
1007
1008     /* Just keep running before the texture has come in. */
1009     /* if (gp->waiting_for_image_p) return; */
1010
1011         glDrawBuffer(GL_BACK);
1012
1013         glXMakeCurrent(display, window, *(gp->glx_context));
1014         draw(mi);
1015
1016         if (mi->fps_p) {
1017                 do_fps (mi);
1018         }
1019
1020         glFinish();
1021         glXSwapBuffers(display, window);
1022
1023 #ifdef GRAB
1024         if (grab) {
1025                 grab_frame(mi);
1026         }
1027 #endif
1028
1029         /* need to change texture? */
1030         if ((gp->start_time != 0) && (duration != -1) && gp->fade == 0) {
1031                 if (gp->start_time + duration <= time((time_t *)0)) {
1032                         /* get new snapshot (into back buffer) and start fade count */
1033                         getSnapshot(mi, gp->textures[1 - gp->visible]);
1034                         gp->fade = 1;
1035                 }
1036         }
1037 }
1038
1039 ENTRYPOINT void
1040 release_gleidescope(ModeInfo * mi)
1041 {
1042         if (gleidescope != NULL) {
1043                 int screen;
1044
1045                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1046                         gleidestruct *gp = &gleidescope[screen];
1047
1048                         /* acd -  is this needed? */
1049                         if (gp->glx_context) {
1050                                 /* Display lists MUST be freed while their glXContext is current. */
1051                                 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
1052
1053                                 /* acd - was code here for freeing things that are no longer in struct */
1054                         }
1055                 }
1056                 (void) free((void *) gleidescope);
1057                 gleidescope = NULL;
1058         }
1059         
1060         FreeAllGL(mi);
1061 }
1062
1063 XSCREENSAVER_MODULE ("Gleidescope", gleidescope)
1064
1065 #endif