1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* hyper --- spinning hypercubes, not just for tesseracts any more */
3 
4 #if 0
5 static const char sccsid[] = "@(#)hyper.c	5.00 2000/11/01 xlockmore";
6 
7 #endif
8 
9 /*-
10  * hyper.c (nee multidico)
11  * Copyright (C) 1992,1998 John Heidemann <johnh AT isi.edu>
12  *
13  * Permission to use, copy, modify, distribute, and sell this software and its
14  * documentation for any purpose is hereby granted without fee, provided that
15  * the above copyright notice appear in all copies and that both that
16  * copyright notice and this permission notice appear in supporting
17  * documentation.  No representations are made about the suitability of this
18  * software for any purpose.  It is provided "as is" without express or
19  * implied warranty.
20  *
21  ***
22  *
23  * hyper (then called multidico) was originally written for
24  * xscreensaver in 1992.  Unfortunately it didn't make it into that
25  * code because Jamie Zawinski was implementing his own tesseract and
26  * preferred his version (optimized for speed) to my version
27  * (with support for more than 4 dimesnions).
28  *
29  * In 1998 I finally got around to porting it to xlockmore and sending
30  * it off.
31  *
32  * (The implementation is independent of jwz's---I started with ico.)
33  *
34  * Editor's Note... (DAB)
35  * Removed all original Color stuff.  Replaced it so it could do xoring
36  * effectively....  Took move_line from jwz's version.... to make it legal...
37  *
38  * Copyright (c) 1992 by Jamie Zawinski
39  *
40  * Permission to use, copy, modify, and distribute this software and its
41  * documentation for any purpose and without fee is hereby granted,
42  * provided that the above copyright notice appear in all copies and that
43  * both that copyright notice and this permission notice appear in
44  * supporting documentation.
45  *
46  * This file is provided AS IS with no warranties of any kind.  The author
47  * shall have no liability with respect to the infringement of copyrights,
48  * trade secrets or any patents by this file or any part thereof.  In no
49  * event will the author be liable for any lost revenue or profits or
50  * other special, indirect and consequential damages.
51  *
52  * Check out A.K. Dewdney's "Computer Recreations", Scientific American
53  * Magazine" Apr 1986 pp 14-25 for more info.
54  * Idea on 3d taken from there but does not work yet.  Also a small number of
55  * random chosen planes drawn may be nice.
56  *
57  * Revision History:
58  * 01-Nov-2000: Added "3d" support from Scientific American
59  * 04-Aug-1998: Added "3d" support from Scientific American
60  */
61 
62 #ifdef STANDALONE
63 #define MODE_hyper
64 #define DEFAULTS "*delay: 100000 \n" \
65 	"*count: -6 \n" \
66 	"*cycles: 300 \n" \
67 	"*ncolors: 200 \n" \
68 	"*use3d: False \n" \
69 	"*delta3d: 1.5 \n" \
70 	"*right3d: red \n" \
71 	"*left3d: blue \n" \
72 	"*both3d: magenta \n" \
73 	"*none3d: black \n" \
74 	"*debug: false \n" \
75 
76 # define free_hyper 0
77 # define reshape_hyper 0
78 # define hyper_handle_event 0
79 #include "xlockmore.h"		/* in xscreensaver distribution */
80 #else /* STANDALONE */
81 #include "xlock.h"		/* in xlockmore distribution */
82 #endif /* STANDALONE */
83 
84 #ifdef MODE_hyper
85 
86 static Bool random_start;
87 static Bool show_axes;
88 static Bool show_planes;
89 static int  spin_delay;
90 
91 extern XFontStruct *getFont(Display * display);
92 
93 static XrmOptionDescRec opts[] =
94 {
95 	{(char *) "-randomstart", (char *) ".hyper.randomStart", XrmoptionNoArg, (caddr_t) "on"},
96 	{(char *) "+randomstart", (char *) ".hyper.randomStart", XrmoptionNoArg, (caddr_t) "off"},
97 	{(char *) "-showaxes", (char *) ".hyper.showAxes", XrmoptionNoArg, (caddr_t) "on"},
98 	{(char *) "+showaxes", (char *) ".hyper.showAxes", XrmoptionNoArg, (caddr_t) "off"},
99 	{(char *) "-showplanes", (char *) ".hyper.showPlanes", XrmoptionNoArg, (caddr_t) "on"},
100 	{(char *) "+showplanes", (char *) ".hyper.showPlanes", XrmoptionNoArg, (caddr_t) "off"},
101 	{(char *) "-spindelay", (char *) ".hyper.spinDelay", XrmoptionSepArg, 0},
102 };
103 static argtype vars[] =
104 {
105 	{(void *) & random_start, (char *) "randomStart", (char *) "RandomStart", (char *) "True", t_Bool},
106 	{(void *) & show_axes, (char *) "showAxes", (char *) "ShowAxes", (char *) "True", t_Bool},
107 	{(void *) & show_planes, (char *) "showPlanes", (char *) "ShowPlanes", (char *) "False", t_Bool},
108 	{(void *) & spin_delay, (char *) "spinDelay", (char *) "SpinDelay", (char *) "2", t_Int},
109 };
110 static OptionStruct desc[] =
111 {
112 	{(char *) "-/+randomstart", (char *) "turn on/off beginning with random rotations"},
113 	{(char *) "-/+showaxes", (char *) "turn on/off showing the axes"},
114 	{(char *) "-/+showplanes", (char *) "turn on/off showing the planes"},
115 	{(char *) "-spindelay num", (char *) "delay in seconds before changing spin speed"},
116 };
117 
118 ENTRYPOINT ModeSpecOpt hyper_opts =
119 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
120 
121 #ifdef USE_MODULES
122 ModStruct   hyper_description =
123 {"hyper", "init_hyper", "draw_hyper", "release_hyper",
124  "refresh_hyper", "change_hyper", (char *) NULL, &hyper_opts,
125  100000, -6, 300, 1, 64, 1.0, "",
126  "Shows spinning n-dimensional hypercubes", 0, NULL};
127 
128 #endif
129 
130 #ifdef DEBUG
131 #include <assert.h>
132 #endif
133 
134 typedef struct {
135 	double      x, y;
136 } dpoint;
137 
138 typedef double vector;		/* Was an array of size (MAX_D + 1) */
139 typedef double matrix;		/* Was a double array of size (MAX_D + 1) ^ 2 */
140 
141 #define MIN_D 2
142 #define MAX_D 10		/* Memory use goes up exponentially */
143 
144 /* Normally DELTA3D is not in degrees, but it works here, so why fight it? */
145 #define DELDEG (MI_DELTA3D(mi)*M_PI/180.0)
146 
147 typedef struct {
148 	int         from, to;
149 	long        color;
150 } line_segment;
151 
152 typedef struct {
153 	int         a, b, c, d;
154 	long        color;
155 } plane_section;
156 
157 
158 typedef struct hyper {
159 	GC          gc;
160 	Bool        redrawing;
161 	Bool        painted;
162 	XFontStruct *font;
163 
164 	int         show_axes;
165 	int         show_planes;
166 
167 	int         maxx, maxy;
168 	int         delay;
169 	int         spinDelay;
170 	Bool        normxor;
171 
172 	/*
173 	 * Data storage.
174 	 */
175 	int         num_d;	/* number of dimensions */
176 	int         num_mat;
177 	int         num_matmat;
178 
179 	/* there are C(num_d,2) planes */
180 	int         num_planes;	/* #define max_planes 40 */
181 	XPoint     *rotation_planes;
182 
183 	/* Formerly max_planes arrays */
184 	double     *rotations;	/* where we are in each dimension */
185 	double     *d_rotations;	/* change in rotation */
186 	double     *dd_rotations;	/* change in change in rotation */
187 	int        *cdd_rotations;	/* how many turns to apply dd_rotations */
188 	matrix     *Trotations;
189 	matrix     *Trotationsleft;
190 
191 	matrix     *Tall;
192 	matrix     *Tallleft;
193 
194 	int         num_points;
195 	vector     *points;
196 	vector     *pointsleft;
197 	int         num_lines;
198 	line_segment *lines;
199 	plane_section *planes;
200 
201 	int         point_set;	/* which bank of points are we using */
202 	XPoint     *xpoints[2];
203 	XPoint     *xpointsleft[2];
204 
205 	int         num_axis_points;
206 
207 	/* Formerly an array of (MAX_D + 1) */
208 	int        *axis_points;
209 
210 	/*
211 	 * Inter-step state:
212 	 */
213 	int         this_set;
214 	Bool        stationary;
215 } hyperstruct;
216 
217 
218 static hyperstruct *hypers = (hyperstruct *) NULL;
219 
220 #define allocarray(P,T,N) if((P=(T*)malloc((N)*sizeof(T)))==NULL) \
221  {free_hyper_screen(display,hp);return False;}
222 #define callocarray(P,T,N) if((P=(T*)calloc(N,sizeof(T)))==NULL) \
223  {free_hyper_screen(display,hp);return False;}
224 
225 /*
226  * Matrix handling & 3d transformation routines
227  */
228 
229 static void
MatMult(matrix * a,matrix * b,matrix * c,int n)230 MatMult(matrix * a, matrix * b, matrix * c, int n)
231 	/* c = a * b  for n x n matricies */
232 {
233 	register int i, j, k;
234 	double      temp;
235 
236 	/* Strassen' method... what's that? */
237 	for (i = 0; i < n; i++)	/* go through a's rows */
238 		for (j = 0; j < n; j++) {	/* go through b's columns */
239 			temp = 0.0;
240 			for (k = 0; k < n; k++)
241 				temp += a[i * n + k] * b[k * n + j];
242 			c[i * n + j] = temp;
243 		}
244 }
245 
246 static void
MatVecMult(matrix * a,vector * b,vector * c,int n)247 MatVecMult(matrix * a, vector * b, vector * c, int n)
248 	/* c = a * b  for a n x n, b&c 1 x n */
249 {
250 	register int i, k;
251 	double      temp;
252 
253 	for (i = 0; i < n; i++) {	/* go through a's rows */
254 		temp = 0.0;
255 		for (k = 0; k < n; k++)
256 			temp += a[i * n + k] * b[k];
257 		c[i] = temp;
258 	}
259 }
260 
261 static void
MatCopy(matrix * a,matrix * b,int n)262 MatCopy(matrix * a, matrix * b, int n)
263 	/* b <- a */
264 {
265 	register int i, j;
266 
267 	for (i = 0; i < n; i++)
268 		for (j = 0; j < n; j++)
269 			b[i * n + j] = a[i * n + j];
270 }
271 
272 static void
MatZero(matrix * a,int n)273 MatZero(matrix * a, int n)
274 	/* a = 0 */
275 {
276 	register int i, j;
277 
278 	for (i = 0; i < n; i++)
279 		for (j = 0; j < n; j++)
280 			a[i * n + j] = 0.0;
281 }
282 
283 static void
MatIdent(matrix * a,int n)284 MatIdent(matrix * a, int n)
285 	/* a = I */
286 {
287 	register int i;
288 
289 	MatZero(a, n);
290 	for (i = 0; i < n; i++)
291 		a[i * n + i] = 1.0;
292 }
293 
294 static void
ZeroMultiCounter(int * c,int n)295 ZeroMultiCounter(int *c, int n)
296 {
297 	int         i;
298 
299 	for (i = 0; i < n; i++)
300 		c[i] = 0;
301 }
302 
303 
304 static int
RealIncMultiCounter(int * c,int n,int place)305 RealIncMultiCounter(int *c, int n, int place)
306 {
307 #define BASE 2
308 	if (place >= n)
309 		return 0;
310 	else if (++c[place] >= BASE) {
311 		c[place] = 0;
312 		return RealIncMultiCounter(c, n, place + 1);
313 	} else
314 		return 1;
315 }
316 
317 
318 static int
IncMultiCounter(int * c,int n)319 IncMultiCounter(int *c, int n)
320 {
321 	return RealIncMultiCounter(c, n, 0);
322 }
323 
324 
325 static int
figure_num_points(int d)326 figure_num_points(int d)
327 {
328 	return 1 << d;		/* (int)pow(2.0, (double)d); */
329 }
330 
331 static int
figure_num_lines(int d)332 figure_num_lines(int d)
333 {
334 	return d * figure_num_points(d - 1);
335 }
336 
337 static int
figure_num_planes(int d)338 figure_num_planes(int d)
339 {
340 	return ((d - 1) * d) / 2;
341 }
342 
343 static void
free_hyper_stuff(hyperstruct * hp)344 free_hyper_stuff(hyperstruct * hp)
345 {
346 	if (hp->axis_points) {
347 		free(hp->axis_points);
348 		hp->axis_points = (int *) NULL;
349 	}
350 	if (hp->points) {
351 		free(hp->points);
352 		hp->points = (vector *) NULL;
353 	}
354 	if (hp->pointsleft) {
355 		free(hp->pointsleft);
356 		hp->pointsleft = (vector *) NULL;
357 	}
358 	if (hp->lines) {
359 		XFree(hp->lines);
360 		hp->lines = (line_segment *) NULL;
361 	}
362 	if (hp->planes) {
363 		XFree(hp->planes);
364 		hp->planes = (plane_section *) NULL;
365 	}
366 	if (hp->rotation_planes) {
367 		XFree(hp->rotation_planes);
368 		hp->rotation_planes = (XPoint *) NULL;
369 	}
370 	if (hp->rotations) {
371 		free(hp->rotations);
372 		hp->rotations = (double *) NULL;
373 	}
374 	if (hp->d_rotations) {
375 		free(hp->d_rotations);
376 		hp->d_rotations = (double *) NULL;
377 	}
378 	if (hp->dd_rotations) {
379 		free(hp->dd_rotations);
380 		hp->dd_rotations = (double *) NULL;
381 	}
382 	if (hp->cdd_rotations) {
383 		free(hp->cdd_rotations);
384 		hp->cdd_rotations = (int *) NULL;
385 	}
386 	if (hp->Trotations) {
387 		free(hp->Trotations);
388 		hp->Trotations = (matrix *) NULL;
389 	}
390 	if (hp->Trotationsleft) {
391 		free(hp->Trotationsleft);
392 		hp->Trotationsleft = (matrix *) NULL;
393 	}
394 	if (hp->Tall) {
395 		free(hp->Tall);
396 		hp->Tall = (matrix *) NULL;
397 	}
398 	if (hp->Tallleft) {
399 		free(hp->Tallleft);
400 		hp->Tallleft = (matrix *) NULL;
401 	}
402 	if (hp->xpoints[0]) {
403 		XFree(hp->xpoints[0]);
404 		hp->xpoints[0] = (XPoint *) NULL;
405 	}
406 	if (hp->xpoints[1]) {
407 		XFree(hp->xpoints[1]);
408 		hp->xpoints[1] = (XPoint *) NULL;
409 	}
410 	if (hp->xpointsleft[0]) {
411 		XFree(hp->xpointsleft[0]);
412 		hp->xpointsleft[0] = (XPoint *) NULL;
413 	}
414 	if (hp->xpointsleft[1]) {
415 		XFree(hp->xpointsleft[1]);
416 		hp->xpointsleft[1] = (XPoint *) NULL;
417 	}
418 }
419 
420 static void
free_hyper_screen(Display * display,hyperstruct * hp)421 free_hyper_screen(Display *display, hyperstruct *hp)
422 {
423 	if (hp == NULL) {
424 		return;
425 	}
426 	if (hp->gc != None) {
427 		XFreeGC(display, hp->gc);
428 		hp->gc = None;
429 	}
430 	if (hp->font != None) {
431 		XFreeFont(display, hp->font);
432 		hp->font = None;
433 	}
434 	free_hyper_stuff(hp);
435 	hp = NULL;
436 }
437 
438 static Bool
figure_points(ModeInfo * mi)439 figure_points(ModeInfo * mi)
440 {
441 	Display *display = MI_DISPLAY(mi);
442 	hyperstruct *hp = &hypers[MI_SCREEN(mi)];
443 	int         i, j, k, n, d, pix = 0;
444 	int        *c;
445 
446 	/*
447 	 * First, figure out the points.
448 	 */
449 	hp->num_points = figure_num_points(hp->num_d);
450 	allocarray(hp->points, vector, hp->num_points * hp->num_mat);
451 	allocarray(hp->xpoints[0], XPoint, hp->num_points);
452 	allocarray(hp->xpoints[1], XPoint, hp->num_points);
453 	if (MI_IS_USE3D(mi)) {
454 		allocarray(hp->pointsleft, vector, hp->num_points * hp->num_mat);
455 		allocarray(hp->xpointsleft[0], XPoint, hp->num_points);
456 		allocarray(hp->xpointsleft[1], XPoint, hp->num_points);
457 	}
458 	allocarray(c, int, hp->num_points);	/* will be lost, sigh */
459 
460 	ZeroMultiCounter(c, hp->num_d);
461 	n = 0;
462 	do {
463 		for (i = 0; i < hp->num_d; i++) {
464 			hp->points[n * hp->num_mat + i] = c[i];
465 			if (MI_IS_USE3D(mi))
466 				hp->pointsleft[n * hp->num_mat + i] = c[i];
467 		}
468 		n++;
469 	} while (IncMultiCounter(c, hp->num_d));
470 	free(c);
471 #ifdef DEBUG
472 	assert(hp->num_points == n);
473 #endif
474 	/*
475 	 * Next connect them.
476 	 * We could do this more intelligently, but why bother?
477 	 *
478 	 * Connect points that differ by only one coordinate.
479 	 */
480 	if (MI_NPIXELS(mi) > 2)
481 		pix = NRAND(MI_NPIXELS(mi));
482 
483 	hp->num_lines = figure_num_lines(hp->num_d);
484 	allocarray(hp->lines, line_segment, hp->num_lines);
485 	for (n = i = 0; i < hp->num_points; i++) {
486 		for (j = i + 1; j < hp->num_points; j++) {
487 			for (d = k = 0; k < hp->num_d; k++) {
488 				if (hp->points[i * hp->num_mat + k] != hp->points[j * hp->num_mat + k])
489 					d++;
490 			}
491 			if (d == 1) {
492 				hp->lines[n].from = i;
493 				hp->lines[n].to = j;
494 				/* (void) printf ("from %x to %x ", i, j); */
495 				if (MI_NPIXELS(mi) > 2) {
496 					hp->lines[n].color = MI_PIXEL(mi, pix);
497 					if (++pix >= MI_NPIXELS(mi))
498 						pix = 0;
499 				} else
500 					hp->lines[n].color = MI_WHITE_PIXEL(mi);
501 				n++;
502 			}
503 		}
504 	}
505 #ifdef DEBUG
506 	assert(hp->num_lines == n);
507 #endif
508 
509 	/*
510 	 * Now determine the planes of rotation.
511 	 */
512 	hp->num_planes = figure_num_planes(hp->num_d);
513 	hp->show_planes = show_planes;
514 
515 	if (hp->show_planes) {
516 		allocarray(hp->planes, plane_section, hp->num_planes);
517 
518 		/* Keeping it simple and just drawing planes that touch the
519 		 * axes.  Still not that simple, have to figure out which pt c is
520 	 	 * furthest away and draw it first... yuck.
521  		 */
522 
523 		for (n = i = 0; i < hp->num_d; i++) {
524 			for (j = i + 1; j < hp->num_d; j++) {
525 				hp->planes[n].a = 0;
526 				hp->planes[n].b = 1 << i;
527 				hp->planes[n].d = 1 << j;
528 				hp->planes[n].c = hp->planes[n].b + hp->planes[n].d;
529 				/*(void) printf ("a %d, b %d, c %d, d %d\n",
530 					0, 1 << i, (1 << i) + (1 << j), 1 << j);*/
531 				if (MI_NPIXELS(mi) > 2) {
532 					hp->planes[n].color = MI_PIXEL(mi, pix);
533 					if (++pix >= MI_NPIXELS(mi))
534 						pix = 0;
535 				} else
536 					hp->planes[n].color = MI_WHITE_PIXEL(mi);
537 				n++;
538 			}
539 		}
540 	}
541 
542 	allocarray(hp->axis_points, int, hp->num_d + 1);
543 
544 	allocarray(hp->rotations, double, hp->num_planes);
545 	callocarray(hp->d_rotations, double, hp->num_planes);
546 	callocarray(hp->dd_rotations, double, hp->num_planes);
547 	callocarray(hp->cdd_rotations, int, hp->num_planes);
548 
549 	allocarray(hp->Trotations, matrix, hp->num_planes * hp->num_matmat);
550 	allocarray(hp->Tall, matrix, hp->num_matmat);
551 
552 	if (MI_IS_USE3D(mi)) {
553 		allocarray(hp->Trotationsleft, matrix, hp->num_planes * hp->num_matmat);
554 		allocarray(hp->Tallleft, matrix, hp->num_matmat);
555 	}
556 	allocarray(hp->rotation_planes, XPoint, hp->num_planes);
557 
558 	for (n = i = 0; i < hp->num_d; i++)
559 		for (j = i + 1; j < hp->num_d; j++) {
560 			hp->rotation_planes[n].x = i;
561 			hp->rotation_planes[n].y = j;
562 			n++;
563 		}
564 #ifdef DEBUG
565 	assert(hp->num_planes == n);
566 #endif
567 	/*
568 	 * Potential random initial rotations.
569 	 */
570 #define FRAC (1024*16)
571 	if (random_start) {
572 		for (i = 0; i < hp->num_planes; i++)
573 			hp->rotations[i] = 2.0 * NRAND(FRAC) * M_PI / FRAC;
574 	}
575 	return True;
576 }
577 
578 static void
figure_axis_points(hyperstruct * hp)579 figure_axis_points(hyperstruct * hp)
580 {
581 	int         i, j, num_set;
582 
583 	hp->show_axes = show_axes;
584 	for (hp->num_axis_points = i = 0; i < hp->num_points; i++) {
585 		for (num_set = j = 0; j < hp->num_d; j++)
586 			if (hp->points[i * hp->num_mat + j] != 0.0)
587 				num_set++;
588 		if (num_set <= 1)
589 			hp->axis_points[hp->num_axis_points++] = i;
590 	}
591 }
592 
593 static Bool
init_x_stuff(ModeInfo * mi)594 init_x_stuff(ModeInfo * mi)
595 {
596 	hyperstruct *hp = &hypers[MI_SCREEN(mi)];
597 	XGCValues   gcv;
598 
599 	hp->maxx = MI_WIDTH(mi);
600 	hp->maxy = MI_HEIGHT(mi);
601 
602 
603 	hp->spinDelay = 10 * spin_delay;
604 	if (hp->spinDelay < 0)
605 		hp->spinDelay = 0;
606 
607 	free_hyper_stuff(hp);
608 	hp->num_d = MI_COUNT(mi);
609 	if (hp->num_d < -MAX_D)
610 		hp->num_d = -MAX_D;
611 	if (hp->num_d > MAX_D)
612 		hp->num_d = MAX_D;
613 	else if (hp->num_d < -MIN_D) {
614 		hp->num_d = NRAND(-hp->num_d - MIN_D + 1) + MIN_D;
615 	} else if (hp->num_d < MIN_D)
616 		hp->num_d = MIN_D;
617 
618 	hp->num_mat = hp->num_d + 1;
619 	hp->num_matmat = hp->num_mat * hp->num_mat;
620 
621 	if (hp->font == None) {
622 		if ((hp->font = getFont(MI_DISPLAY(mi))) == None)
623 			return False;
624 	}
625 	if (MI_NPIXELS(mi) <= 2 || MI_IS_USE3D(mi))
626 		hp->normxor = False;
627 	if ((hp->gc == None) && (MI_NPIXELS(mi) <= 2 || !MI_IS_USE3D(mi))) {
628 		long        options;
629 
630 		if (hp->normxor) {
631 			options = GCForeground | GCFont | GCFunction;
632 			gcv.foreground = MI_WHITE_PIXEL(mi) ^ MI_BLACK_PIXEL(mi);
633 			gcv.function = GXxor;
634 		} else {
635 			options = GCForeground | GCBackground | GCFont;
636 			gcv.foreground = MI_WHITE_PIXEL(mi);
637 			gcv.background = MI_BLACK_PIXEL(mi);
638 		}
639 		gcv.font = hp->font->fid;
640 		if ((hp->gc = XCreateGC(MI_DISPLAY(mi), MI_WINDOW(mi), options,
641 				&gcv)) == None)
642 			return False;
643 	}
644 	return True;
645 }
646 
647 static void
move_line(ModeInfo * mi,int from,int to,int set,long color)648 move_line(ModeInfo * mi, int from, int to, int set, long color)
649 {
650 	Display    *display = MI_DISPLAY(mi);
651 	Window      window = MI_WINDOW(mi);
652 	GC          gc = MI_GC(mi);
653 	hyperstruct *hp = &hypers[MI_SCREEN(mi)];
654 
655 	if (MI_NPIXELS(mi) <= 2 || !MI_IS_USE3D(mi))
656 		gc = hp->gc;
657 	if (hp->normxor) {
658 		XSetForeground(display, gc, color);
659 		if (!hp->redrawing)
660 			XDrawLine(display, window, gc,
661 			hp->xpoints[!set][from].x, hp->xpoints[!set][from].y,
662 			   hp->xpoints[!set][to].x, hp->xpoints[!set][to].y);
663 		XDrawLine(display, window, gc,
664 			  hp->xpoints[set][from].x, hp->xpoints[set][from].y,
665 			  hp->xpoints[set][to].x, hp->xpoints[set][to].y);
666 	} else {
667 		if (!hp->redrawing) {
668 			if (MI_IS_INSTALL(mi) && MI_IS_USE3D(mi))
669 				XSetForeground(display, gc, MI_NONE_COLOR(mi));
670 			else
671 				XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
672 			XDrawLine(display, window, gc,
673 			  hp->xpoints[set][from].x, hp->xpoints[set][from].y,
674 			     hp->xpoints[set][to].x, hp->xpoints[set][to].y);
675 			if (MI_IS_USE3D(mi))
676 				XDrawLine(display, window, gc,
677 					  hp->xpointsleft[set][from].x, hp->xpointsleft[set][from].y,
678 					  hp->xpointsleft[set][to].x, hp->xpointsleft[set][to].y);
679 		}
680 		if (MI_IS_USE3D(mi)) {
681 			if (MI_IS_INSTALL(mi)) {
682 				XSetFunction(display, gc, GXor);
683 			}
684 			XSetForeground(display, gc, MI_LEFT_COLOR(mi));
685 		} else if (MI_NPIXELS(mi) <= 2)
686 			XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
687 		else
688 			XSetForeground(display, gc, color);
689 		XDrawLine(display, window, gc,
690 			hp->xpoints[!set][from].x, hp->xpoints[!set][from].y,
691 			  hp->xpoints[!set][to].x, hp->xpoints[!set][to].y);
692 		if (MI_IS_USE3D(mi)) {
693 			XSetForeground(display, gc, MI_RIGHT_COLOR(mi));
694 			XDrawLine(display, window, gc,
695 				  hp->xpointsleft[!set][from].x, hp->xpointsleft[!set][from].y,
696 				  hp->xpointsleft[!set][to].x, hp->xpointsleft[!set][to].y);
697 			if (MI_IS_INSTALL(mi)) {
698 				XSetFunction(display, gc, GXcopy);
699 			}
700 		}
701 	}
702 }
703 
704 static void
move_plane(ModeInfo * mi,int a,int b,int c,int d,int set,long color)705 move_plane(ModeInfo * mi, int a, int b, int c, int d, int set, long color)
706 {
707 	Display    *display = MI_DISPLAY(mi);
708 	Window      window = MI_WINDOW(mi);
709 	GC          gc = MI_GC(mi);
710 	hyperstruct *hp = &hypers[MI_SCREEN(mi)];
711   XPoint rect[4];
712 
713 	if (MI_NPIXELS(mi) <= 2 || !MI_IS_USE3D(mi))
714 		gc = hp->gc;
715 	if (hp->normxor) {
716 		XSetForeground(display, gc, color);
717 		if (!hp->redrawing) {
718 			rect[0].x = hp->xpoints[!set][a].x;
719 			rect[0].y = hp->xpoints[!set][a].y;
720 			rect[1].x = hp->xpoints[!set][b].x;
721 			rect[1].y = hp->xpoints[!set][b].y;
722 			rect[2].x = hp->xpoints[!set][c].x;
723 			rect[2].y = hp->xpoints[!set][c].y;
724 			rect[3].x = hp->xpoints[!set][d].x;
725 			rect[3].y = hp->xpoints[!set][d].y;
726 			XFillPolygon(display, window, gc, rect, 4, Convex, CoordModeOrigin);
727 		}
728 		rect[0].x = hp->xpoints[set][a].x;
729 		rect[0].y = hp->xpoints[set][a].y;
730 		rect[1].x = hp->xpoints[set][b].x;
731 		rect[1].y = hp->xpoints[set][b].y;
732 		rect[2].x = hp->xpoints[set][c].x;
733 		rect[2].y = hp->xpoints[set][c].y;
734 		rect[3].x = hp->xpoints[set][d].x;
735 		rect[3].y = hp->xpoints[set][d].y;
736 		XFillPolygon(display, window, gc, rect, 4, Convex, CoordModeOrigin);
737 	} else {
738 		if (!hp->redrawing) {
739 			if (MI_IS_INSTALL(mi) && MI_IS_USE3D(mi))
740 				XSetForeground(display, gc, MI_NONE_COLOR(mi));
741 			else
742 				XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
743 			rect[0].x = hp->xpoints[set][a].x;
744 			rect[0].y = hp->xpoints[set][a].y;
745 			rect[1].x = hp->xpoints[set][b].x;
746 			rect[1].y = hp->xpoints[set][b].y;
747 			rect[2].x = hp->xpoints[set][c].x;
748 			rect[2].y = hp->xpoints[set][c].y;
749 			rect[3].x = hp->xpoints[set][d].x;
750 			rect[3].y = hp->xpoints[set][d].y;
751 			XFillPolygon(display, window, gc, rect, 4, Convex, CoordModeOrigin);
752 			if (MI_IS_USE3D(mi)) {
753 				rect[0].x = hp->xpointsleft[set][a].x;
754 				rect[0].y = hp->xpointsleft[set][a].y;
755 				rect[1].x = hp->xpointsleft[set][b].x;
756 				rect[1].y = hp->xpointsleft[set][b].y;
757 				rect[2].x = hp->xpointsleft[set][c].x;
758 				rect[2].y = hp->xpointsleft[set][c].y;
759 				rect[3].x = hp->xpointsleft[set][d].x;
760 				rect[3].y = hp->xpointsleft[set][d].y;
761 				XFillPolygon(display, window, gc, rect, 4, Convex, CoordModeOrigin);
762 			}
763 		}
764 		if (MI_IS_USE3D(mi)) {
765 			if (MI_IS_INSTALL(mi)) {
766 				XSetFunction(display, gc, GXor);
767 			}
768 			XSetForeground(display, gc, MI_LEFT_COLOR(mi));
769 		} else if (MI_NPIXELS(mi) <= 2)
770 			XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
771 		else
772 			XSetForeground(display, gc, color);
773 		rect[0].x = hp->xpoints[!set][a].x;
774 		rect[0].y = hp->xpoints[!set][a].y;
775 		rect[1].x = hp->xpoints[!set][b].x;
776 		rect[1].y = hp->xpoints[!set][b].y;
777 		rect[2].x = hp->xpoints[!set][c].x;
778 		rect[2].y = hp->xpoints[!set][c].y;
779 		rect[3].x = hp->xpoints[!set][d].x;
780 		rect[3].y = hp->xpoints[!set][d].y;
781 		XFillPolygon(display, window, gc, rect, 4, Convex, CoordModeOrigin);
782 		if (MI_IS_USE3D(mi)) {
783 			XSetForeground(display, gc, MI_RIGHT_COLOR(mi));
784 			rect[0].x = hp->xpointsleft[!set][a].x;
785 			rect[0].y = hp->xpointsleft[!set][a].y;
786 			rect[1].x = hp->xpointsleft[!set][b].x;
787 			rect[1].y = hp->xpointsleft[!set][b].y;
788 			rect[2].x = hp->xpointsleft[!set][c].x;
789 			rect[2].y = hp->xpointsleft[!set][c].y;
790 			rect[3].x = hp->xpointsleft[!set][d].x;
791 			rect[3].y = hp->xpointsleft[!set][d].y;
792 			XFillPolygon(display, window, gc, rect, 4, Convex, CoordModeOrigin);
793 			if (MI_IS_INSTALL(mi)) {
794 				XSetFunction(display, gc, GXcopy);
795 			}
796 		}
797 	}
798 }
799 
800 static void
move_number(ModeInfo * mi,int axis,char * string,int set,long color)801 move_number(ModeInfo * mi, int axis, char *string, int set, long color)
802 {
803 	Display    *display = MI_DISPLAY(mi);
804 	Window      window = MI_WINDOW(mi);
805 	GC          gc = MI_GC(mi);
806 	hyperstruct *hp = &hypers[MI_SCREEN(mi)];
807 
808 	if (MI_NPIXELS(mi) <= 2 || !MI_IS_USE3D(mi))
809 		gc = hp->gc;
810 	if (hp->normxor) {
811 		XSetForeground(display, gc, color);
812 		if (!hp->redrawing)
813 			(void) XDrawString(display, window, gc,
814 			hp->xpoints[!set][axis].x, hp->xpoints[!set][axis].y,
815 				    string, strlen(string));
816 		(void) XDrawString(display, window, gc,
817 			  hp->xpoints[set][axis].x, hp->xpoints[set][axis].y,
818 			    string, strlen(string));
819 	} else {
820 		if (!hp->redrawing) {
821 			if (MI_IS_INSTALL(mi) && MI_IS_USE3D(mi))
822 				XSetForeground(display, gc, MI_NONE_COLOR(mi));
823 			else
824 				XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
825 			(void) XDrawString(display, window, gc,
826 			  hp->xpoints[set][axis].x, hp->xpoints[set][axis].y,
827 				    string, strlen(string));
828 			if (MI_IS_USE3D(mi))
829 				(void) XDrawString(display, window, gc,
830 					    hp->xpointsleft[set][axis].x, hp->xpointsleft[set][axis].y,
831 					    string, strlen(string));
832 		}
833 		if (MI_IS_USE3D(mi)) {
834 			if (MI_IS_INSTALL(mi)) {
835 				XSetFunction(display, gc, GXor);
836 			}
837 			XSetForeground(display, gc, MI_LEFT_COLOR(mi));
838 		} else if (MI_NPIXELS(mi) <= 2)
839 			XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
840 		else
841 			XSetForeground(display, gc, color);
842 		(void) XDrawString(display, window, gc,
843 			hp->xpoints[!set][axis].x, hp->xpoints[!set][axis].y,
844 			    string, strlen(string));
845 		if (MI_IS_USE3D(mi)) {
846 			XSetForeground(display, gc, MI_RIGHT_COLOR(mi));
847 			(void) XDrawString(display, window, gc,
848 				    hp->xpointsleft[!set][axis].x, hp->xpointsleft[!set][axis].y,
849 				    string, strlen(string));
850 			if (MI_IS_INSTALL(mi)) {
851 				XSetFunction(display, gc, GXcopy);
852 			}
853 		}
854 	}
855 }
856 
857 static void
draw_hyper_step(ModeInfo * mi,int set)858 draw_hyper_step(ModeInfo * mi, int set)
859 {
860 	hyperstruct *hp = &hypers[MI_SCREEN(mi)];
861 	int         i;
862 	char        tmps[11];
863 
864 	MI_IS_DRAWN(mi) = True;
865 
866 	if (!hp->stationary || hp->redrawing) {
867 		for (i = 0; i < hp->num_lines; i++) {
868 			move_line(mi, hp->lines[i].from, hp->lines[i].to,
869 				set, hp->lines[i].color);
870 		}
871 		if (hp->show_planes) {
872 			for (i = 0; i < hp->num_planes; i++) {
873 				move_plane(mi, hp->planes[i].a, hp->planes[i].b, hp->planes[i].c,
874 					hp->planes[i].d, set, hp->planes[i].color);
875 			}
876 		}
877 		if (hp->show_axes) {
878 			for (i = 0; i < hp->num_axis_points; i++) {
879 				(void) sprintf(tmps, "%d", i);
880 				move_number(mi, hp->axis_points[i], tmps, set, MI_WHITE_PIXEL(mi));
881 			}
882 		}
883 	}
884 }
885 
886 static void
move_hyper(ModeInfo * mi)887 move_hyper(ModeInfo * mi)
888 {
889 	hyperstruct *hp = &hypers[MI_SCREEN(mi)];
890 	int         i;
891 
892 /* NEEDSWORK: These should be resources */
893 #define default_cdd_rotation 10
894 #define default_dd_rotation (M_PI/1024.0)
895 	int         axis;
896 	int         faster;
897 
898 	hp->stationary = False;
899 	if (hp->spinDelay-- <= 0) {
900 
901 		hp->spinDelay = 10 * spin_delay;
902 		/*
903 		 * Change rotation?
904 		 *
905 		 * 66% chance if stationary, 33% if not.
906 		 */
907 		hp->stationary = True;
908 		for (i = 0; i < hp->num_planes; i++)
909 			if (hp->d_rotations[i] != 0.0 || hp->cdd_rotations[i]) {
910 				hp->stationary = False;
911 				break;
912 			}
913 		if (NRAND(3) < 1 + hp->stationary) {
914 			/* Change!  But what? */
915 			axis = NRAND(hp->num_planes);
916 
917 			/*
918 			 * And how much?  33% chance faster, 66% slower.
919 			 * If stopped, slower doesn't start it moving
920 			 * unless we're stationary.
921 			 */
922 			hp->cdd_rotations[axis] = default_cdd_rotation +
923 				NRAND(7) - 3;
924 			faster = (NRAND(3) < 1);
925 			if (faster || hp->dd_rotations[axis] != 0.0 || hp->stationary)
926 				hp->dd_rotations[axis] = default_dd_rotation *
927 					(hp->dd_rotations[axis] >= 0.0 ? 1 : -1) *
928 					(faster ? 1 : -1);
929 			if (MI_IS_DEBUG(mi))
930 				(void) fprintf(stderr,
931 					       "axis %d made %s\n", axis, faster ? "faster" : "slower");
932 		}
933 	}
934 	/*
935 	 * Rotate.
936 	 */
937 	for (i = 0; i < hp->num_planes; i++) {
938 		if (hp->cdd_rotations[i]) {
939 			hp->cdd_rotations[i]--;
940 			hp->d_rotations[i] += hp->dd_rotations[i];
941 		}
942 		hp->rotations[i] += hp->d_rotations[i];
943 	}
944 }
945 
946 static Bool
calc_transformation(ModeInfo * mi)947 calc_transformation(ModeInfo * mi)
948 {
949 	hyperstruct *hp = &hypers[MI_SCREEN(mi)];
950 	double      cosa, sina;
951 	double      cosb = 0.0, sinb = 0.0;
952 	int         p1, p2;
953 	matrix     *Ttmp;
954 	matrix     *Tpre, *Tuser, *Tuserleft = (matrix *) NULL;
955 	matrix     *Tpretranspose, *Tscale, *Tposttranspose;
956 	int         i;
957 	dpoint      scale, range, offset;
958 	double      scale_used;
959 
960 	Ttmp = (matrix *) malloc(hp->num_matmat * sizeof (matrix));
961 	Tpre = (matrix *) malloc(hp->num_matmat * sizeof (matrix));
962 	Tuser = (matrix *) malloc(hp->num_matmat * sizeof (matrix));
963 	Tpretranspose = (matrix *) malloc(hp->num_matmat * sizeof (matrix));
964 	Tscale = (matrix *) malloc(hp->num_matmat * sizeof (matrix));
965 	Tposttranspose = (matrix *) malloc(hp->num_matmat * sizeof (matrix));
966 	if ((Ttmp == NULL) || (Tpre == NULL) || (Tuser == NULL) ||
967 			(Tpretranspose == NULL) || (Tscale == NULL) ||
968 			(Tposttranspose == NULL)) {
969 		if (Ttmp != NULL)
970 			free(Ttmp);
971 		if (Tpre != NULL)
972 			free(Tpre);
973 		if (Tuser != NULL)
974 			free(Tuser);
975 		if (Tpretranspose != NULL)
976 			free(Tpretranspose);
977 		if (Tscale != NULL)
978 			free(Tscale);
979 		if (Tposttranspose != NULL)
980 			free(Tposttranspose);
981 		return False;
982 	}
983 	if (MI_IS_USE3D(mi)) {
984 		if ((Tuserleft = (matrix *) malloc(hp->num_matmat *
985 				sizeof (matrix))) == NULL) {
986 			free(Ttmp);
987 			free(Tpre);
988 			free(Tuser);
989 			free(Tpretranspose);
990 			free(Tscale);
991 			free(Tposttranspose);
992 			return False;
993 		}
994 	}
995 
996 	/*
997 	 * Adjust the data.
998 	 * Since the data goes from 0->1 on each axis,
999 	 * we shift it by -0.5 here to center the figure.
1000 	 */
1001 	MatIdent(Tpre, hp->num_mat);
1002 	for (i = 0; i < hp->num_d; i++) {
1003 		Tpre[i * hp->num_mat + hp->num_d] = -0.5;
1004 	}
1005 
1006 	/*
1007 	 * Figure the rotation.
1008 	 */
1009 	MatIdent(Tuser, hp->num_mat);
1010 	if (MI_IS_USE3D(mi)) {
1011 		MatIdent(Tuserleft, hp->num_mat);
1012 	}
1013 	for (i = 0; i < hp->num_planes; i++) {
1014 		p1 = hp->rotation_planes[i].x;
1015 		p2 = hp->rotation_planes[i].y;
1016 		if (MI_IS_USE3D(mi)) {
1017 			sinb = sin(hp->rotations[i] - DELDEG);
1018 			cosb = cos(hp->rotations[i] - DELDEG);
1019 			sina = sin(hp->rotations[i] + DELDEG);
1020 			cosa = cos(hp->rotations[i] + DELDEG);
1021 		} else {
1022 			sina = sin(hp->rotations[i]);
1023 			cosa = cos(hp->rotations[i]);
1024 		}
1025 
1026 		MatIdent(&hp->Trotations[i * hp->num_matmat], hp->num_mat);
1027 		hp->Trotations[i * hp->num_matmat + p1 * hp->num_mat + p1] =
1028 			hp->Trotations[i * hp->num_matmat + p2 * hp->num_mat + p2] = cosa;
1029 		hp->Trotations[i * hp->num_matmat + p1 * hp->num_mat + p2] = sina;
1030 		hp->Trotations[i * hp->num_matmat + p2 * hp->num_mat + p1] = -sina;
1031 		MatMult(&hp->Trotations[i * hp->num_matmat], Tuser, Ttmp, hp->num_mat);
1032 		MatCopy(Ttmp, Tuser, hp->num_mat);
1033 
1034 		if (MI_IS_USE3D(mi)) {
1035 			MatIdent(&hp->Trotationsleft[i * hp->num_matmat], hp->num_mat);
1036 			hp->Trotationsleft[i * hp->num_matmat + p1 * hp->num_mat + p1] =
1037 				hp->Trotationsleft[i * hp->num_matmat + p2 * hp->num_mat + p2] = cosb;
1038 			hp->Trotationsleft[i * hp->num_matmat + p1 * hp->num_mat + p2] = sinb;
1039 			hp->Trotationsleft[i * hp->num_matmat + p2 * hp->num_mat + p1] = -sinb;
1040 			MatMult(&hp->Trotationsleft[i * hp->num_matmat], Tuserleft, Ttmp, hp->num_mat);
1041 			MatCopy(Ttmp, Tuserleft, hp->num_mat);
1042 		}
1043 	}
1044 
1045 /* Now calculate the scaling matrix */
1046 #if 1
1047 	/*
1048 	 * Calculate the best scale of the two axes.
1049 	 * Multiply by 0.9 to use 90% of the display.
1050 	 * Divide by the sqrt(2.0) because it's biggest when
1051 	 * rotated by 45 degrees.
1052 	 *
1053 	 * This principle generalizes to sqrt(hp->num_d).
1054 	 */
1055 #define border_width (0.05)
1056 	range.x = sqrt((double) hp->num_d);
1057 	range.y = range.x;
1058 	scale.x = (1.0 - 2 * border_width) * hp->maxx / range.x;
1059 	scale.y = (1.0 - 2 * border_width) * hp->maxy / range.y;
1060 	scale_used = ((scale.x < scale.y) ? scale.x : scale.y);
1061 	offset.x = hp->maxx / 2.0;
1062 	offset.y = hp->maxy / 2.0;
1063 
1064 	/*
1065 	 * Setup & compute the matrices.
1066 	 */
1067 	MatIdent(Tpretranspose, hp->num_mat);
1068 	Tpretranspose[0 * hp->num_mat + hp->num_d] = 0;
1069 	Tpretranspose[1 * hp->num_mat + hp->num_d] = 0;
1070 
1071 	MatIdent(Tscale, hp->num_mat);
1072 	Tscale[0 * hp->num_mat + 0] = scale_used;
1073 	Tscale[1 * hp->num_mat + 1] = -scale_used;
1074 
1075 	MatIdent(Tposttranspose, hp->num_mat);
1076 	Tposttranspose[0 * hp->num_mat + hp->num_d] = offset.x;
1077 	Tposttranspose[1 * hp->num_mat + hp->num_d] = offset.y;
1078 
1079 	MatMult(Tscale, Tpretranspose, Ttmp, hp->num_mat);
1080 	MatMult(Tposttranspose, Ttmp, Tscale, hp->num_mat);
1081 #else
1082 	MatIdent(Tscale, hp->num_mat);
1083 #endif
1084 	free(Tpretranspose);
1085 	free(Tposttranspose);
1086 
1087 	/*
1088 	 * Put it all together.
1089 	 */
1090 	MatMult(Tuser, Tpre, Ttmp, hp->num_mat);
1091 	MatMult(Tscale, Ttmp, hp->Tall, hp->num_mat);
1092 	free(Tuser);
1093 	if (MI_IS_USE3D(mi)) {
1094 		MatMult(Tuserleft, Tpre, Ttmp, hp->num_mat);
1095 		MatMult(Tscale, Ttmp, hp->Tallleft, hp->num_mat);
1096 		free(Tuserleft);
1097 	}
1098 	free(Tpre);
1099 	free(Ttmp);
1100 	free(Tscale);
1101 	return True;
1102 }
1103 
1104 
1105 static Bool
translate_point(hyperstruct * hp,matrix * Tall,vector * real,XPoint * screen_image)1106 translate_point(hyperstruct * hp, matrix * Tall, vector * real, XPoint * screen_image)
1107 {
1108 	vector     *image;
1109 
1110 	if ((image = (vector *) malloc(hp->num_mat * sizeof (vector))) == NULL)
1111 		return False;
1112 	MatVecMult(Tall, real, image, hp->num_mat);
1113 	screen_image->x = (short) image[0];
1114 	screen_image->y = (short) image[1];
1115 
1116 	free(image);
1117 	return True;
1118 }
1119 
1120 static Bool
translate_points(ModeInfo * mi,int set)1121 translate_points(ModeInfo * mi, int set)
1122 {
1123 	hyperstruct *hp = &hypers[MI_SCREEN(mi)];
1124 	int         i;
1125 
1126 	if (!calc_transformation(mi))
1127 		return False;
1128 	for (i = 0; i < hp->num_points; i++) {
1129 		if (!translate_point(hp, hp->Tall, &hp->points[i * hp->num_mat],
1130 				&hp->xpoints[set][i]))
1131 			return False;
1132 		if (MI_IS_USE3D(mi)) {
1133 			if (!translate_point(hp, hp->Tallleft,
1134 					&hp->pointsleft[i * hp->num_mat],
1135 					&hp->xpointsleft[set][i]))
1136 				return False;
1137 		}
1138 	}
1139 	return True;
1140 }
1141 
1142 ENTRYPOINT void
refresh_hyper(ModeInfo * mi)1143 refresh_hyper(ModeInfo * mi)
1144 {
1145 	hyperstruct *hp = &hypers[MI_SCREEN(mi)];
1146 
1147 	if (!hp->painted) {
1148 		MI_CLEARWINDOW(mi);
1149 		hp->redrawing = True;
1150 		draw_hyper_step(mi, hp->this_set);
1151 		hp->redrawing = False;
1152 		hp->painted = True;
1153 	}
1154 }
1155 
1156 ENTRYPOINT void
init_hyper(ModeInfo * mi)1157 init_hyper(ModeInfo * mi)
1158 {
1159 	Display *display = MI_DISPLAY(mi);
1160 	int         i;
1161 	hyperstruct *hp;
1162 
1163 	MI_INIT(mi, hypers);
1164 	hp = &hypers[MI_SCREEN(mi)];
1165 
1166 	if (!init_x_stuff(mi)) {
1167 		free_hyper_screen(display, hp);
1168 		return;
1169 	}
1170 
1171 	if (!figure_points(mi)) {
1172 		free_hyper_screen(display, hp);
1173 		return;
1174 	}
1175 
1176 	/*
1177 	 * Fix the d+1 coord of all points.
1178 	 */
1179 	for (i = 0; i < hp->num_points; i++) {
1180 		hp->points[i * hp->num_mat + hp->num_d] = 1;
1181 		if (MI_IS_USE3D(mi))
1182 			hp->pointsleft[i * hp->num_mat + hp->num_d] = 1;
1183 	}
1184 
1185 	figure_axis_points(hp);
1186 
1187 	hp->this_set = 0;
1188 	if (!translate_points(mi, !hp->this_set)) {
1189 		free_hyper_screen(display, hp);
1190 		return;
1191 	}
1192 	if (!translate_points(mi, hp->this_set)) {
1193 		free_hyper_screen(display, hp);
1194 		return;
1195 	}
1196 	refresh_hyper(mi);
1197 	hp->painted = True;
1198 	hp->stationary = True;
1199 }
1200 
1201 
1202 ENTRYPOINT void
draw_hyper(ModeInfo * mi)1203 draw_hyper(ModeInfo * mi)
1204 {
1205 	hyperstruct *hp;
1206 
1207 	if (hypers == NULL)
1208 		return;
1209 	hp = &hypers[MI_SCREEN(mi)];
1210 	if (hp->axis_points == NULL)
1211 		return;
1212 
1213 	hp->painted = False;
1214 	draw_hyper_step(mi, hp->this_set);
1215 
1216 	/* Set up next place */
1217 	move_hyper(mi);
1218 	if (!translate_points(mi, hp->this_set)) {
1219 		free_hyper_screen(MI_DISPLAY(mi), hp);
1220 		return;
1221 	}
1222 	if (!hp->stationary)
1223 		hp->this_set = !hp->this_set;
1224 }
1225 
1226 ENTRYPOINT void
release_hyper(ModeInfo * mi)1227 release_hyper(ModeInfo * mi)
1228 {
1229 	if (hypers != NULL) {
1230 		int         screen;
1231 
1232 		for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1233 			free_hyper_screen(MI_DISPLAY(mi), &hypers[screen]);
1234 		free(hypers);
1235 		hypers = (hyperstruct *) NULL;
1236 	}
1237 }
1238 
1239 
1240 #ifndef STANDALONE
1241 ENTRYPOINT void
change_hyper(ModeInfo * mi)1242 change_hyper(ModeInfo * mi)
1243 {
1244 	hyperstruct *hp = &hypers[MI_SCREEN(mi)];
1245 
1246 	/* make it change */
1247 	hp->spinDelay = 0;
1248 }
1249 #endif
1250 
1251 XSCREENSAVER_MODULE ("Hyper", hyper)
1252 
1253 #endif /* MODE_hyper */
1254