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