1 /* -*- Mode: C; tab-width: 4 -*- */
3 #if !defined( lint ) && !defined( SABER )
4 static const char sccsid[] = "@(#)gleidescope.c 1.0 03/06/27 xlockmore";
7 /* enable -grab switch */
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.
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.
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).
34 * Added fade code (also from glslideshow).
35 * 20031013 1.2 acd Migrated to compile without warnings under
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.
45 #include <X11/Intrinsic.h>
48 #include "xpm-ximage.h"
51 **----------------------------------------------------------------------------
53 **----------------------------------------------------------------------------
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
66 "*showFPS: False \n" \
70 "*image: DEFAULT \n" \
74 # include "xlockmore.h" /* from the xscreensaver distribution */
75 #else /* !STANDALONE */
76 # include "xlock.h" /* from the xlockmore distribution */
77 #endif /* !STANDALONE */
83 /* acd TODO should all these be in gleidestruct? */
85 static Bool grab; /* grab images */
87 static Bool move; /* moving camera */
88 static Bool nomove; /* no moving camera */
89 static Bool rotate; /* rotate in place */
90 static Bool norotate; /* no rotate in place */
91 static int size = -1; /* size */
92 static Bool zoom; /* zooming camera */
93 static Bool nozoom; /* no zooming camera */
94 static char *image; /* name of texture to load */
95 static int duration; /* length of time to display grabbed image */
97 #define MAX_TANGLE_VEL 2.0
99 static float tangle = 0; /* texture angle */
100 static float tangle_vel = 0.0; /* texture velocity */
101 static float tangle_acc = 0.0; /* texture acceleration */
103 #define MAX_RANGLE_VEL 1.5
105 static float rangle = 0; /* rotate angle */
106 static float rangle_vel = 0.0; /* rotate velocity */
107 static float rangle_acc = 0.0; /* rotate acceleration */
109 static XrmOptionDescRec opts[] =
112 {"-grab", ".gleidescope.grab", XrmoptionNoArg, "true"},
114 {"-move", ".gleidescope.move", XrmoptionNoArg, "true"},
115 {"-no-move", ".gleidescope.nomove", XrmoptionNoArg, "true"},
116 {"-rotate", ".gleidescope.rotate", XrmoptionNoArg, "true"},
117 {"-no-rotate", ".gleidescope.norotate", XrmoptionNoArg, "true"},
118 /*{"-size", ".gleidescope.size", XrmoptionNoArg, "-1"},*/
119 {"-zoom", ".gleidescope.zoom", XrmoptionNoArg, "true"},
120 {"-no-zoom", ".gleidescope.nozoom", XrmoptionNoArg, "true"},
121 {"-image", ".gleidescope.image", XrmoptionSepArg, "DEFAULT"},
122 {"-duration", ".gleidescope.duration", XrmoptionSepArg, "30"},
126 static argtype vars[] = {
128 {&grab, "grab", "Grab", "False", t_Bool},
130 {&move, "move", "Move", "False", t_Bool},
131 {&nomove, "nomove", "noMove", "False", t_Bool},
132 {&rotate, "rotate", "Rotate", "False", t_Bool},
133 {&norotate, "norotate", "noRotate", "False", t_Bool},
134 /*{&size, "size", "Size", "-1", t_Int},*/
135 {&zoom, "zoom", "Zoom", "False", t_Bool},
136 {&nozoom, "nozoom", "noZoom", "False", t_Bool},
137 {&image, "image", "Image", "DEFAULT", t_String},
138 {&duration, "duration", "Duration", "30", t_Int},
141 static OptionStruct desc[] = {
143 {"-grab", "grab images to create animation"},
145 {"-move", "camera will move"},
146 {"-no-move", "camera won't move"},
147 {"-rotate", "camera will rotate"},
148 {"-no-rotate", "camera won't rotate"},
149 /*{"-size", "size of the hexagons (1-10)"},*/
150 {"-zoom", "camera will zoom"},
151 {"-no-zoom", "camera won't zoom"},
152 {"-image", "xpm / xbm image file to use for texture"},
153 {"-duration", "length of time texture will be used"},
156 ModeSpecOpt gleidescope_opts = {
157 sizeof opts / sizeof opts[0], opts,
158 sizeof vars / sizeof vars[0], vars,
163 ModStruct gleidescope_description = {
164 "gleidescope", "init_gleidescope", "draw_gleidescope", "release_gleidescope",
165 "draw_gleidescope", "init_gleidescope", NULL, &gleidescope_opts,
166 1000, 1, 2, 1, 4, 1.0, "",
167 "GL Kaleidescope", 0, NULL};
171 **-----------------------------------------------------------------------------
173 **-----------------------------------------------------------------------------
176 typedef struct hex_s {
177 GLfloat x, y, z; /* position */
186 #define MAX_FADE 500 /* number of fade cycles */
189 float cam_x_speed, cam_z_speed, cam_y_speed;
190 int cam_x_phase, cam_z_phase, cam_y_phase;
192 GLXContext *glx_context;
194 GLfloat max_tx, max_ty; /* maximum texture sizes */
195 GLuint textures[2]; /* texture handles */
196 GLuint visible; /* texture handle for new texture */
202 #define XOFFSET (0.8660254f) /* sin 60' */
203 #define YOFFSET (1.5000000f) /* cos 60' + 1 */
209 /* generates a grid with edges of given size */
210 /* acd TODO - replace hex[] with this and allow size and distance as parameters */
213 generate_grid(int size)
220 for (y = -size ; y <= size ; y++) {
221 for (x = -i ; x <= i ; x += 2) {
222 printf("{XOFFSET * %d, YOFFSET * %d, 0},\n", x, y);
236 /* edges of size 7 */
237 /* number of hexagons required to cover screen depends on camera distance */
238 /* at a distance of 10 this is just about enough. */
239 {XOFFSET * -6, YOFFSET * -6, 0},
240 {XOFFSET * -4, YOFFSET * -6, 0},
241 {XOFFSET * -2, YOFFSET * -6, 0},
242 {XOFFSET * 0, YOFFSET * -6, 0},
243 {XOFFSET * 2, YOFFSET * -6, 0},
244 {XOFFSET * 4, YOFFSET * -6, 0},
245 {XOFFSET * 6, YOFFSET * -6, 0},
247 {XOFFSET * -7, YOFFSET * -5, 0},
248 {XOFFSET * -5, YOFFSET * -5, 0},
249 {XOFFSET * -3, YOFFSET * -5, 0},
250 {XOFFSET * -1, YOFFSET * -5, 0},
251 {XOFFSET * 1, YOFFSET * -5, 0},
252 {XOFFSET * 3, YOFFSET * -5, 0},
253 {XOFFSET * 5, YOFFSET * -5, 0},
254 {XOFFSET * 7, YOFFSET * -5, 0},
256 {XOFFSET * -8, YOFFSET * -4, 0},
257 {XOFFSET * -6, YOFFSET * -4, 0},
258 {XOFFSET * -4, YOFFSET * -4, 0},
259 {XOFFSET * -2, YOFFSET * -4, 0},
260 {XOFFSET * 0, YOFFSET * -4, 0},
261 {XOFFSET * 2, YOFFSET * -4, 0},
262 {XOFFSET * 4, YOFFSET * -4, 0},
263 {XOFFSET * 6, YOFFSET * -4, 0},
264 {XOFFSET * 8, YOFFSET * -4, 0},
266 {XOFFSET * -9, YOFFSET * -3, 0},
267 {XOFFSET * -7, YOFFSET * -3, 0},
268 {XOFFSET * -5, YOFFSET * -3, 0},
269 {XOFFSET * -3, YOFFSET * -3, 0},
270 {XOFFSET * -1, YOFFSET * -3, 0},
271 {XOFFSET * 1, YOFFSET * -3, 0},
272 {XOFFSET * 3, YOFFSET * -3, 0},
273 {XOFFSET * 5, YOFFSET * -3, 0},
274 {XOFFSET * 7, YOFFSET * -3, 0},
275 {XOFFSET * 9, YOFFSET * -3, 0},
277 {XOFFSET * -10, YOFFSET * -2, 0},
278 {XOFFSET * -8, YOFFSET * -2, 0},
279 {XOFFSET * -6, YOFFSET * -2, 0},
280 {XOFFSET * -4, YOFFSET * -2, 0},
281 {XOFFSET * -2, YOFFSET * -2, 0},
282 {XOFFSET * 0, YOFFSET * -2, 0},
283 {XOFFSET * 2, YOFFSET * -2, 0},
284 {XOFFSET * 4, YOFFSET * -2, 0},
285 {XOFFSET * 6, YOFFSET * -2, 0},
286 {XOFFSET * 8, YOFFSET * -2, 0},
287 {XOFFSET * 10, YOFFSET * -2, 0},
289 {XOFFSET * -11, YOFFSET * -1, 0},
290 {XOFFSET * -9, YOFFSET * -1, 0},
291 {XOFFSET * -7, YOFFSET * -1, 0},
292 {XOFFSET * -5, YOFFSET * -1, 0},
293 {XOFFSET * -3, YOFFSET * -1, 0},
294 {XOFFSET * -1, YOFFSET * -1, 0},
295 {XOFFSET * 1, YOFFSET * -1, 0},
296 {XOFFSET * 3, YOFFSET * -1, 0},
297 {XOFFSET * 5, YOFFSET * -1, 0},
298 {XOFFSET * 7, YOFFSET * -1, 0},
299 {XOFFSET * 9, YOFFSET * -1, 0},
300 {XOFFSET * 11, YOFFSET * -1, 0},
302 {XOFFSET * -12, YOFFSET * 0, 0},
303 {XOFFSET * -10, YOFFSET * 0, 0},
304 {XOFFSET * -8, YOFFSET * 0, 0},
305 {XOFFSET * -6, YOFFSET * 0, 0},
306 {XOFFSET * -4, YOFFSET * 0, 0},
307 {XOFFSET * -2, YOFFSET * 0, 0},
308 {XOFFSET * 0, YOFFSET * 0, 0},
309 {XOFFSET * 2, YOFFSET * 0, 0},
310 {XOFFSET * 4, YOFFSET * 0, 0},
311 {XOFFSET * 6, YOFFSET * 0, 0},
312 {XOFFSET * 8, YOFFSET * 0, 0},
313 {XOFFSET * 10, YOFFSET * 0, 0},
314 {XOFFSET * 12, YOFFSET * 0, 0},
316 {XOFFSET * -11, YOFFSET * 1, 0},
317 {XOFFSET * -9, YOFFSET * 1, 0},
318 {XOFFSET * -7, YOFFSET * 1, 0},
319 {XOFFSET * -5, YOFFSET * 1, 0},
320 {XOFFSET * -3, YOFFSET * 1, 0},
321 {XOFFSET * -1, YOFFSET * 1, 0},
322 {XOFFSET * 1, YOFFSET * 1, 0},
323 {XOFFSET * 3, YOFFSET * 1, 0},
324 {XOFFSET * 5, YOFFSET * 1, 0},
325 {XOFFSET * 7, YOFFSET * 1, 0},
326 {XOFFSET * 9, YOFFSET * 1, 0},
327 {XOFFSET * 11, YOFFSET * 1, 0},
329 {XOFFSET * -10, YOFFSET * 2, 0},
330 {XOFFSET * -8, YOFFSET * 2, 0},
331 {XOFFSET * -6, YOFFSET * 2, 0},
332 {XOFFSET * -4, YOFFSET * 2, 0},
333 {XOFFSET * -2, YOFFSET * 2, 0},
334 {XOFFSET * 0, YOFFSET * 2, 0},
335 {XOFFSET * 2, YOFFSET * 2, 0},
336 {XOFFSET * 4, YOFFSET * 2, 0},
337 {XOFFSET * 6, YOFFSET * 2, 0},
338 {XOFFSET * 8, YOFFSET * 2, 0},
339 {XOFFSET * 10, YOFFSET * 2, 0},
341 {XOFFSET * -9, YOFFSET * 3, 0},
342 {XOFFSET * -7, YOFFSET * 3, 0},
343 {XOFFSET * -5, YOFFSET * 3, 0},
344 {XOFFSET * -3, YOFFSET * 3, 0},
345 {XOFFSET * -1, YOFFSET * 3, 0},
346 {XOFFSET * 1, YOFFSET * 3, 0},
347 {XOFFSET * 3, YOFFSET * 3, 0},
348 {XOFFSET * 5, YOFFSET * 3, 0},
349 {XOFFSET * 7, YOFFSET * 3, 0},
350 {XOFFSET * 9, YOFFSET * 3, 0},
352 {XOFFSET * -8, YOFFSET * 4, 0},
353 {XOFFSET * -6, YOFFSET * 4, 0},
354 {XOFFSET * -4, YOFFSET * 4, 0},
355 {XOFFSET * -2, YOFFSET * 4, 0},
356 {XOFFSET * 0, YOFFSET * 4, 0},
357 {XOFFSET * 2, YOFFSET * 4, 0},
358 {XOFFSET * 4, YOFFSET * 4, 0},
359 {XOFFSET * 6, YOFFSET * 4, 0},
360 {XOFFSET * 8, YOFFSET * 4, 0},
362 {XOFFSET * -7, YOFFSET * 5, 0},
363 {XOFFSET * -5, YOFFSET * 5, 0},
364 {XOFFSET * -3, YOFFSET * 5, 0},
365 {XOFFSET * -1, YOFFSET * 5, 0},
366 {XOFFSET * 1, YOFFSET * 5, 0},
367 {XOFFSET * 3, YOFFSET * 5, 0},
368 {XOFFSET * 5, YOFFSET * 5, 0},
369 {XOFFSET * 7, YOFFSET * 5, 0},
371 {XOFFSET * -6, YOFFSET * 6, 0},
372 {XOFFSET * -4, YOFFSET * 6, 0},
373 {XOFFSET * -2, YOFFSET * 6, 0},
374 {XOFFSET * 0, YOFFSET * 6, 0},
375 {XOFFSET * 2, YOFFSET * 6, 0},
376 {XOFFSET * 4, YOFFSET * 6, 0},
377 {XOFFSET * 6, YOFFSET * 6, 0},
381 **----------------------------------------------------------------------------
383 **----------------------------------------------------------------------------
386 static gleidestruct *gleidescope = NULL;
389 *load defaults in config structure
391 void setdefaultconfig(void)
404 static double xmouse = 0.0;
405 static double ymouse = 0.0;
408 gleidescope_handle_event(ModeInfo *mi, XEvent *event)
410 gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
413 printf("event:%d\n", event->xany.type);
414 printf("button:%d\n", event->xbutton.button);
416 switch(event->xany.type)
420 if (event->xbutton.button == Button1 || event->xbutton.button == Button3)
422 /* store initial values of mouse */
423 xstart = event->xbutton.x;
424 ystart = event->xbutton.y;
427 gp->button_down_p = True;
431 else if (event->xbutton.button == Button4)
436 else if (event->xbutton.button == Button5)
446 if (event->xbutton.button == Button1 || event->xbutton.button == Button3)
449 gp->button_down_p = False;
456 if (gp->button_down_p)
458 /* update mouse position */
459 xmouse += (double)(event->xmotion.x - xstart) / MI_WIDTH(mi);
460 ymouse += (double)(event->xmotion.y - ystart) / MI_HEIGHT(mi);
461 xstart = event->xmotion.x;
462 ystart = event->xmotion.y;
472 #include "grab-ximage.h"
475 getSnapshot(ModeInfo *mi, GLuint name)
480 gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
482 if (MI_IS_WIREFRAME(mi))
485 ximage = screen_to_ximage(mi->xgwa.screen, mi->window, 0);
488 th = mi->xgwa.height;
490 gp->max_tx = (GLfloat) tw / (GLfloat) ximage->width;
491 gp->max_ty = (GLfloat) th / (GLfloat) ximage->height;
493 glBindTexture (GL_TEXTURE_2D, name);
495 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
496 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
497 GL_LINEAR_MIPMAP_LINEAR);
500 status = gluBuild2DMipmaps(GL_TEXTURE_2D, 3,
501 ximage->width, ximage->height,
502 GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
504 if (!status && glGetError())
505 /* Some implementations of gluBuild2DMipmaps(), but set a GL error anyway.
506 ** We could just call check_gl_error(), but that would exit. */
511 const GLubyte *s = gluErrorString (status);
514 fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
515 progname, ximage->width, ximage->height, s);
519 fprintf (stderr, "%s: error mipmapping %dx%d texture: (unknown)\n",
520 progname, ximage->width, ximage->height);
524 check_gl_error("mipmapping"); /* should get a return code instead of a
525 GL error, but just in case... */
529 XDestroyImage (ximage);
531 /* remember time of last image change */
532 gp->start_time = time ((time_t *) 0);
536 setup_file_texture (ModeInfo *mi, char *filename, GLuint name)
538 Display *dpy = mi->dpy;
539 Visual *visual = mi->xgwa.visual;
542 Colormap cmap = mi->xgwa.colormap;
543 XImage *image = xpm_file_to_ximage (dpy, visual, cmap, filename);
545 /* use this texture */
546 glBindTexture(GL_TEXTURE_2D, name);
549 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
550 image->width, image->height, 0,
551 GL_RGBA, GL_UNSIGNED_BYTE, image->data);
552 sprintf (buf, "texture: %.100s (%dx%d)",
553 filename, image->width, image->height);
556 /* setup parameters for texturing */
557 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
558 glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
560 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
561 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
562 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
563 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
564 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
568 setup_texture(ModeInfo * mi, GLuint id)
570 gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
572 if (!image || !*image || !strcmp(image, "DEFAULT")) {
573 /* no image specified - grab screen */
575 /* max_tx and max_ty set in getSnapshot() */
577 /* use supplied image file */
578 setup_file_texture(mi, image, id);
580 /* set tx params to use whole image */
585 check_gl_error("texture initialization");
587 /* Need to flip the texture top for bottom for some reason. */
588 glMatrixMode (GL_TEXTURE);
590 glMatrixMode (GL_MODELVIEW);
593 #define VERTEX0 glVertex3f( 0.0000f, 0.000f, 0.0f);
594 #define VERTEX1 glVertex3f( 0.0000f, 1.000f, 0.0f);
595 #define VERTEX2 glVertex3f( XOFFSET, 0.500f, 0.0f);
596 #define VERTEX3 glVertex3f( XOFFSET, -0.500f, 0.0f);
597 #define VERTEX4 glVertex3f( 0.0000f, -1.000f, 0.0f);
598 #define VERTEX5 glVertex3f(-XOFFSET, -0.500f, 0.0f);
599 #define VERTEX6 glVertex3f(-XOFFSET, 0.500f, 0.0f);
602 draw_hexagons(ModeInfo *mi, int translucency, GLuint texture)
606 GLfloat t1x, t1y, t2x, t2y, t3x, t3y;
607 gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
613 col[3] = (float)translucency / MAX_FADE;
615 /* calculate vertices of equilateral triangle within image. */
616 /* t1 is always in centre */
617 t1x = gp->max_tx / 2;
618 t1y = gp->max_ty / 2;
620 t2x = (gp->max_tx / 2) * (1 + cos((ymouse * 2 * M_PI) + (tangle * M_PI / 180)));
621 t2y = (gp->max_ty / 2) * (1 + sin((ymouse * 2 * M_PI) + (tangle * M_PI / 180)));
622 /* t3 is always 60' further around than t2 */
623 tangle2 = (ymouse * 2 * M_PI) + (tangle * M_PI / 180) + (M_PI * 2 / 6);
624 t3x = (gp->max_tx / 2) * (1 + (cos(tangle2)));
625 t3y = (gp->max_ty / 2) * (1 + (sin(tangle2)));
626 /* NB image is flipped vertically hence: */
630 /*printf("texcoords:[%f,%f]->[%f,%f](%f,%f)\n", t1x, t1y, t2x, t2y, gp->max_tx, gp->max_ty);*/
632 glColor4f(1.0, 1.0, 1.0, (float)translucency / MAX_FADE);
633 glEnable(GL_TEXTURE_2D);
635 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
636 glDepthMask(GL_FALSE);
637 glBindTexture(GL_TEXTURE_2D, gp->textures[texture]);
639 for (i = 0 ; i < sizeof(hex) / sizeof(hex[0]) ; i++) {
643 glTranslatef(hex[i].x, hex[i].y, 0.0);
645 glBegin(GL_TRIANGLES);
648 ** six triangles to each hexagon
651 glTexCoord2f(t1x, t1y);
653 glTexCoord2f(t2x, t2y);
655 glTexCoord2f(t3x, t3y);
658 glTexCoord2f(t1x, t1y);
660 glTexCoord2f(t3x, t3y);
662 glTexCoord2f(t2x, t2y);
665 glTexCoord2f(t1x, t1y);
667 glTexCoord2f(t2x, t2y);
669 glTexCoord2f(t3x, t3y);
672 glTexCoord2f(t1x, t1y);
674 glTexCoord2f(t3x, t3y);
676 glTexCoord2f(t2x, t2y);
679 glTexCoord2f(t1x, t1y);
681 glTexCoord2f(t2x, t2y);
683 glTexCoord2f(t3x, t3y);
686 glTexCoord2f(t1x, t1y);
688 glTexCoord2f(t3x, t3y);
690 glTexCoord2f(t2x, t2y);
698 #ifdef DISPLAY_TEXTURE
700 /* acd debug - display (bigger, centred) texture */
701 glScalef(2.0, 2.0, 2.0);
702 glTranslatef(-0.5, -0.5, 0.0);
704 glTexCoord2f(0.0, 0.0);
705 glVertex3f(0.0, 0.0, -0.1);
706 glTexCoord2f(1.0, 0.0);
707 glVertex3f(1.0, 0.0, -0.1);
708 glTexCoord2f(1.0, 1.0);
709 glVertex3f(1.0, 1.0, -0.1);
710 glTexCoord2f(0.0, 1.0);
711 glVertex3f(0.0, 1.0, -0.1);
713 /* acd debug - display texture triangle */
714 glColor4f(1.0, 1.0, 1.0, 1.0);
715 glBegin(GL_LINE_LOOP);
716 glVertex3f(t1x, t1y, -0.11);
717 glVertex3f(t2x, t2y, -0.11);
718 glVertex3f(t3x, t3y, -0.11);
723 glDisable(GL_TEXTURE_2D);
724 glDepthMask(GL_TRUE);
729 * main rendering loop
734 GLfloat x_angle, y_angle, z_angle;
735 gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
739 glClearColor(0.5, 0.5, 0.5, 1.0);
740 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
745 x_angle = gp->cam_x_phase + gp->tic * gp->cam_x_speed;
746 y_angle = gp->cam_y_phase + gp->tic * gp->cam_y_speed;
747 z_angle = gp->cam_z_phase + gp->tic * gp->cam_z_speed;
750 v1.x = 2 * sin(x_angle);
751 v1.y = 2 * sin(y_angle);
757 /* size is changed in pinit() to be distance from plane */
766 /* user defined size */
769 /* max distance given by adding the constant and the multiplier */
770 v1.z = 5.0 + 4.0 * sin(z_angle);
776 /* update rotation angle (but not if mouse button down) */
777 if (rotate && !gp->button_down_p)
779 float new_rangle_vel = 0.0;
781 /* update camera rotation angle and velocity */
782 rangle += rangle_vel;
783 new_rangle_vel = rangle_vel + rangle_acc;
784 if (new_rangle_vel > -MAX_RANGLE_VEL && new_rangle_vel < MAX_RANGLE_VEL)
786 /* new velocity is within limits */
787 rangle_vel = new_rangle_vel;
790 /* randomly change twisting speed */
791 if ((random() % 1000) < 1)
793 rangle_acc = frand(0.002) - 0.001;
798 /* this makes the image wobble - requires -move and a larger grid */
799 gluLookAt(0, 0, v1.z, v1.x, v1.y, 0.0, 0.0, 1.0, 0.0);
801 /* no wobble - camera always perpendicular to grid */
803 /* rotating camera rather than entire space - smoother */
807 sin((xmouse * M_PI * 2) + rangle * M_PI / 180),
808 cos((xmouse * M_PI * 2) + rangle * M_PI / 180),
812 /* light position same as camera */
821 draw_hexagons(mi, MAX_FADE, gp->visible);
825 /* fading - show both textures with alpha */
826 draw_hexagons(mi, MAX_FADE - gp->fade, gp->visible);
827 draw_hexagons(mi, gp->fade, 1 - gp->visible);
832 /* have we faded enough? */
833 if (gp->fade > MAX_FADE)
837 gp->visible = 1 - gp->visible;
841 /* increment texture angle based on time, velocity etc */
842 /* but only if button is not down */
843 if (!gp->button_down_p)
845 float new_tangle_vel = 0.0;
847 tangle += tangle_vel;
849 /* work out new texture angle velocity */
850 new_tangle_vel = tangle_vel + tangle_acc;
851 if (new_tangle_vel > -MAX_TANGLE_VEL && new_tangle_vel < MAX_TANGLE_VEL)
853 /* new velocity is inside limits */
854 tangle_vel = new_tangle_vel;
857 /* randomly change texture angle acceleration */
858 if ((random() % 1000) < 1)
860 tangle_acc = frand(0.002) - 0.001;
868 * new window size or exposure
870 void reshape_gleidescope(ModeInfo *mi, int width, int height)
872 GLfloat h = (GLfloat) height / (GLfloat) width;
874 glViewport(0, 0, (GLint) width, (GLint) height);
875 glMatrixMode(GL_PROJECTION);
877 gluPerspective(50.0, 1/h, 0.1, 2000.0);
878 glMatrixMode (GL_MODELVIEW);
887 gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
889 /* set start time - star_time = 0 implies non-dynamic texture */
890 gp->start_time = (time_t)0;
892 /* set the texture size to default */
899 glShadeModel(GL_SMOOTH);
900 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
901 glEnable(GL_DEPTH_TEST);
902 glEnable(GL_CULL_FACE);
903 glDisable(GL_LIGHTING);
905 /* space for textures */
906 glGenTextures(1, &gp->textures[0]);
907 glGenTextures(1, &gp->textures[1]);
910 setup_texture(mi, gp->textures[gp->visible]);
913 ** want to choose a value for arg randomly if neither -arg nor -no-arg
914 ** is specified. xscreensaver libraries don't seem to let you do this -
915 ** if something isn't true then it is false (pesky two-state boolean values).
916 ** so, i've defined both -arg and -no-arg to arguments and added the
918 ** (btw if both -arg and -no-arg are defined then arg is set to False)
920 if (zoom == False && nozoom == False)
922 /* no zoom preference - randomise */
923 zoom = (((random() & 0x1) == 0x1) ? True : False);
925 else if (nozoom == True)
927 /* definately no zoom */
931 if (move == False && nomove == False)
933 /* no move preference - randomise */
934 move = (((random() & 0x1) == 0x1) ? True : False);
936 else if (nomove == True)
938 /* definately no move */
942 if (rotate == False && norotate == False)
944 /* no rotate preference - randomise */
945 rotate = (((random() & 0x1) == 0x1) ? True : False);
947 else if (norotate == True)
949 /* definately no rotate */
953 /* define cam variables */
954 gp->cam_x_speed = frand(3.0) - 1.5;
955 gp->cam_x_phase = random() % 360;
956 gp->cam_y_speed = frand(3.0) - 1.5;
957 gp->cam_y_phase = random() % 360;
958 gp->cam_z_speed = frand(3.0) - 1.5;
959 gp->cam_z_phase = random() % 360;
961 /* initial angular speeds */
962 rangle_vel = frand(0.2) - 0.1;
963 tangle_vel = frand(0.2) - 0.1;
964 rangle_acc = frand(0.002) - 0.001;
965 tangle_acc = frand(0.002) - 0.001;
976 /* distance is 11 - size */
979 fprintf(stderr, "-size given. ignoring -zoom.\n");
984 } else if (size >= 10) {
991 printf("phases [%d, %d, %d]\n", gp->cam_x_phase, gp->cam_y_phase, gp->cam_z_phase);
996 init_gleidescope(ModeInfo * mi)
999 int screen = MI_SCREEN(mi);
1002 if (gleidescope == NULL) {
1003 gleidescope = (gleidestruct *) calloc(MI_NUM_SCREENS(mi), sizeof (gleidestruct));
1004 if (gleidescope == NULL) {
1008 gp = &gleidescope[screen];
1009 gp->window = MI_WINDOW(mi);
1011 if ((gp->glx_context = init_GL(mi)) != NULL) {
1013 reshape_gleidescope(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1015 glDrawBuffer(GL_BACK);
1017 /* do initialisation */
1026 draw_gleidescope(ModeInfo * mi)
1028 gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
1029 Display *display = MI_DISPLAY(mi);
1030 Window window = MI_WINDOW(mi);
1033 if (!gp->glx_context)
1036 glDrawBuffer(GL_BACK);
1038 glXMakeCurrent(display, window, *(gp->glx_context));
1046 glXSwapBuffers(display, window);
1054 /* need to change texture? */
1055 if ((gp->start_time != 0) && (duration != -1) && gp->fade == 0) {
1056 if (gp->start_time + duration <= time((time_t *)0)) {
1057 /* get new snapshot (into back buffer) and start fade count */
1058 getSnapshot(mi, gp->textures[1 - gp->visible]);
1065 release_gleidescope(ModeInfo * mi)
1067 if (gleidescope != NULL) {
1070 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1071 gleidestruct *gp = &gleidescope[screen];
1073 /* acd - is this needed? */
1074 if (gp->glx_context) {
1075 /* Display lists MUST be freed while their glXContext is current. */
1076 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
1078 /* acd - was code here for freeing things that are no longer in struct */
1081 (void) free((void *) gleidescope);