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