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