1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* ico --- bouncing polyhedra */
3 
4 #if 0
5 static const char sccsid[] = "@(#)ico.c	5.00 2000/11/01 xlockmore";
6 
7 #endif
8 /*-
9  * Copyright (c) 1987  X Consortium
10  *
11  * Permission to use, copy, modify, and distribute this software and its
12  * documentation for any purpose and without fee is hereby granted,
13  * provided that the above copyright notice appear in all copies and that
14  * both that copyright notice and this permission notice appear in
15  * supporting documentation.
16  *
17  * This file is provided AS IS with no warranties of any kind.  The author
18  * shall have no liability with respect to the infringement of copyrights,
19  * trade secrets or any patents by this file or any part thereof.  In no
20  * event will the author be liable for any lost revenue or profits or
21  * other special, indirect and consequential damages.
22  *
23  * Revision History:
24  * 01-Nov-2000: Allocation checks
25  * 27-Mar-2000: Added double buffering for drawings
26  * 10-May-1997: Compatible with xscreensaver
27  * 25-Mar-1997: David Bagley <bagleyd AT verizon.net>
28  *              Took ico from the X11R6 distribution.  Stripped out
29  *              anything complicated... to be added back in later.
30  *              added dodecahedron, tetrahedron, and star octahedron.
31  * $XConsortium: ico.c,v 1.47 94/04/17 20:45:15 gildea Exp $
32  */
33 
34 /*-
35 original copyright
36 Permission is hereby granted, free of charge, to any person obtaining a copy
37 of this software and associated documentation files (the "Software"), to deal
38 in the Software without restriction, including without limitation the rights
39 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40 copies of the Software, and to permit persons to whom the Software is
41 furnished to do so, subject to the following conditions:
42 
43 The above copyright notice and this permission notice shall be included in
44 all copies or substantial portions of the Software.
45 
46 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
49 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
50 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
51 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 
53 Except as contained in this notice, the name of the X Consortium shall not be
54 used in advertising or otherwise to promote the sale, use or other dealings
55 in this Software without prior written authorization from the X Consortium.
56 
57 
58 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
59 
60                         All Rights Reserved
61 
62 Permission to use, copy, modify, and distribute this software and its
63 documentation for any purpose and without fee is hereby granted,
64 provided that the above copyright notice appear in all copies and that
65 both that copyright notice and this permission notice appear in
66 supporting documentation, and that the name of Digital not be
67 used in advertising or publicity pertaining to distribution of the
68 software without specific, written prior permission.
69 
70 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
71 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
72 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
73 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
74 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
75 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
76 SOFTWARE.
77 
78 ******************************************************************/
79 /******************************************************************************
80  * Description
81  *	Display a wire-frame rotating icosahedron, with hidden lines removed
82  *****************************************************************************/
83 /*-
84  * Additions by jimmc@sci:
85  *  faces and colors
86  *  double buffering on the display
87  *  additional polyhedra
88  *
89  * multi-thread version by Stephen Gildea, January 1992
90  */
91 
92 #ifdef STANDALONE
93 #define MODE_ico
94 #define DEFAULTS "*delay: 100000 \n" \
95 	"*count: 0 \n" \
96 	"*cycles: 300 \n" \
97 	"*ncolors: 200 \n" \
98 
99 # define free_ico 0
100 # define reshape_ico 0
101 # define ico_handle_event 0
102 #define UNIFORM_COLORS
103 #define BRIGHT_COLORS
104 #include "xlockmore.h"		/* in xscreensaver distribution */
105 #else /* STANDALONE */
106 #include "xlock.h"		/* in xlockmore distribution */
107 #define DO_STIPPLE
108 #endif /* STANDALONE */
109 #include "automata.h"
110 
111 #ifdef MODE_ico
112 
113 #define DEF_FACES "True"
114 #define DEF_EDGES "True"
115 #define DEF_OPAQUE "True"
116 
117 static Bool faces;
118 static Bool edges;
119 static Bool opaque;
120 
121 static XrmOptionDescRec opts[] =
122 {
123 	{(char *) "-faces", (char *) ".ico.faces", XrmoptionNoArg, (caddr_t) "on"},
124 	{(char *) "+faces", (char *) ".ico.faces", XrmoptionNoArg, (caddr_t) "off"},
125 	{(char *) "-edges", (char *) ".ico.edges", XrmoptionNoArg, (caddr_t) "on"},
126 	{(char *) "+edges", (char *) ".ico.edges", XrmoptionNoArg, (caddr_t) "off"},
127 	{(char *) "-opaque", (char *) ".ico.opaque", XrmoptionNoArg, (caddr_t) "on"},
128 	{(char *) "+opaque", (char *) ".ico.opaque", XrmoptionNoArg, (caddr_t) "off"}
129 };
130 static argtype vars[] =
131 {
132 	{(void *) & faces, (char *) "faces", (char *) "Faces", (char *) DEF_FACES, t_Bool},
133 	{(void *) & edges, (char *) "edges", (char *) "Edges", (char *) DEF_EDGES, t_Bool},
134 	{(void *) & opaque, (char *) "opaque", (char *) "Opaque", (char *) DEF_OPAQUE, t_Bool}
135 };
136 static OptionStruct desc[] =
137 {
138 	{(char *) "-/+faces", (char *) "turn on/off drawing of faces"},
139 	{(char *) "-/+edges", (char *) "turn on/off drawing of wireframe"},
140 	{(char *) "-/+opaque", (char *) "turn on/off drawing of bottom (unless faces true)"}
141 };
142 
143 ENTRYPOINT ModeSpecOpt ico_opts =
144 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
145 
146 #ifdef USE_MODULES
147 ModStruct   ico_description =
148 {"ico", "init_ico", "draw_ico", "release_ico",
149  "refresh_ico", "change_ico", (char *) NULL, &ico_opts,
150  200000, 0, 400, 0, 64, 1.0, "",
151  "Shows a bouncing polyhedron", 0, NULL};
152 
153 #endif
154 
155 #define MINSIZE 5
156 #define DEFAULT_DELTAX 13
157 #define DEFAULT_DELTAY 9
158 
159 /*-
160  * This is the description of one polyhedron file
161  */
162 
163 #define MAXVERTS 120
164 	/* great rhombicosidodecahedron has 120 vertices */
165 #define MAXNV MAXVERTS
166 #define MAXFACES 30
167 	/* (hexakis icosahedron has 120 faces) */
168 #define MAXEDGES 180
169 	/* great rhombicosidodecahedron has 180 edges */
170 #define MAXEDGESPERPOLY 20
171 
172 typedef struct {
173 	double      x, y, z;
174 } Point3D;
175 
176 /* structure of the include files which define the polyhedra */
177 typedef struct {
178 #ifdef DEFUNCT
179 	char       *longname;	/* long name of object */
180 	char       *shortname;	/* short name of object */
181 	char       *dual;	/* long name of dual */
182 #endif
183 	int         numverts;	/* number of vertices */
184 	int         numedges;	/* number of edges */
185 	int         numfaces;	/* number of faces */
186 	Point3D     v[MAXVERTS];	/* the vertices */
187 	int         f[MAXEDGES * 2 + MAXFACES];		/* the faces */
188 } Polyinfo;
189 
190 /*-
191  *                              faces/edges/vert Vertex Config   Wythoff Symbol
192  * Platonic Solids:
193  * tetrahedron                  4/6/4            {3,3,3}         3|2 3
194  * cube                         6/12/8           {4,4,4}         3|2 4
195  * octahedron                   8/12/6           {3,3,3,3}       4|2 3
196  * dodecahedron                 12/30/20         {5,5,5}         3|2 5
197  * icosahedron                  20/30/12         {3,3,3,3,3}     5|2 3
198  *
199  * Edge Transitive Catalan Solids:
200  * rhombic dodecahedron         12/24/14
201  * rhombic triacontahedron      30/60/32
202  *
203  * Space Filling Archimedean Solid:
204  * truncated octahedron
205  *
206  * Polyhedron Compound:
207  * stella octangula
208  *
209  * Kepler-Poinsot Solids (not added yet):
210  * small stellated dodecahedron 12/30/12      {5/2,5/2,5/2,5/2,5/2}   5|2 5/2
211  * great stellated dodecahedron 12/30/20         {5/2,5/2,5/2}   3|2 5/2
212  * great dodecahedron           12/30/12         {5,5,5,5,5}/2   5/2|2 5
213  * great icosahedron            20/30/12         {3,3,3,3,3}/2   5/2|2 3
214  */
215 
216 static Polyinfo polygons[] =
217 {
218 
219 /* objtetra - structure values for tetrahedron */
220 	{
221 #ifdef DEFUNCT
222 		"tetrahedron", "tetra",		/* long and short names */
223 		"tetrahedron",	/* long name of dual */
224 #endif
225 		4, 6, 4,	/* number of vertices, edges, and faces */
226 		{		/* vertices (x,y,z) */
227 			/* all points must be within radius 1 of the origin */
228 #define T 0.57735
229 			{T, T, T},
230 			{T, -T, -T},
231 			{-T, T, -T},
232 			{-T, -T, T},
233 #undef T
234 		},
235 		{		/* faces (numfaces + indexes into vertices) */
236 		/* faces must be specified clockwise from the outside */
237 			3, 2, 1, 0,
238 			3, 1, 3, 0,
239 			3, 3, 2, 0,
240 			3, 2, 3, 1,
241 		}
242 	},
243 
244 /* objcube - structure values for cube */
245 
246 	{
247 #ifdef DEFUNCT
248 		"hexahedron", "cube",	/* long and short names */
249 		"octahedron",	/* long name of dual */
250 #endif
251 		8, 12, 6,	/* number of vertices, edges, and faces */
252 		{		/* vertices (x,y,z) */
253 			/* all points must be within radius 1 of the origin */
254 #define T 0.57735
255 			{T, T, T},
256 			{T, T, -T},
257 			{T, -T, -T},
258 			{T, -T, T},
259 			{-T, T, T},
260 			{-T, T, -T},
261 			{-T, -T, -T},
262 			{-T, -T, T},
263 #undef T
264 		},
265 		{		/* faces (numfaces + indexes into vertices) */
266 		/* faces must be specified clockwise from the outside */
267 			4, 0, 1, 2, 3,
268 			4, 7, 6, 5, 4,
269 			4, 1, 0, 4, 5,
270 			4, 3, 2, 6, 7,
271 			4, 2, 1, 5, 6,
272 			4, 0, 3, 7, 4,
273 		}
274 	},
275 
276 /* objocta - structure values for octahedron */
277 
278 	{
279 #ifdef DEFUNCT
280 		"octahedron", "octa",	/* long and short names */
281 		"hexahedron",	/* long name of dual */
282 #endif
283 		6, 12, 8,	/* number of vertices, edges, and faces */
284 		{		/* vertices (x,y,z) */
285 			/* all points must be within radius 1 of the origin */
286 #define T 1.0
287 			{T, 0, 0},
288 			{-T, 0, 0},
289 			{0, T, 0},
290 			{0, -T, 0},
291 			{0, 0, T},
292 			{0, 0, -T},
293 #undef T
294 		},
295 		{		/* faces (numfaces + indexes into vertices) */
296 		/* faces must be specified clockwise from the outside */
297 			3, 0, 4, 2,
298 			3, 0, 2, 5,
299 			3, 0, 5, 3,
300 			3, 0, 3, 4,
301 			3, 1, 2, 4,
302 			3, 1, 5, 2,
303 			3, 1, 3, 5,
304 			3, 1, 4, 3,
305 		}
306 	},
307 
308 /* objdodeca - structure values for dodecahedron */
309 
310 	{
311 #ifdef DEFUNCT
312 		"dodecahedron", "dodeca",	/* long and short names */
313 		"icosahedron",	/* long name of dual */
314 #endif
315 		20, 30, 12,	/* number of vertices, edges, and faces */
316 		{		/* vertices (x,y,z) */
317 			/* all points must be within radius 1 of the origin */
318 #define G 0.3090169943749474241 /* cos 72 */
319 #define D 0.8090169943749474241 /* cos 36 */
320 #define H 0.5
321 			{0, G, D},
322 			{0, -G, D},
323 			{0, -G, -D},
324 			{0, G, -D},
325 			{D, 0, G},
326 			{-D, 0, G},
327 			{-D, 0, -G},
328 			{D, 0, -G},
329 			{G, D, 0},
330 			{-G, D, 0},
331 			{-G, -D, 0},
332 			{G, -D, 0},
333 			{H, H, H},
334 			{-H, H, H},
335 			{-H, -H, H},
336 			{H, -H, H},
337 			{H, -H, -H},
338 			{H, H, -H},
339 			{-H, H, -H},
340 			{-H, -H, -H},
341 #undef G
342 #undef D
343 #undef H
344 		},
345 		{		/* faces (numfaces + indexes into vertices) */
346 		/* faces must be specified clockwise from the outside */
347 			5, 12, 8, 17, 7, 4,
348 			5, 5, 6, 18, 9, 13,
349 			5, 14, 10, 19, 6, 5,
350 			5, 12, 4, 15, 1, 0,
351 			5, 13, 9, 8, 12, 0,
352 			5, 1, 14, 5, 13, 0,
353 			5, 16, 7, 17, 3, 2,
354 			5, 19, 10, 11, 16, 2,
355 			5, 3, 18, 6, 19, 2,
356 			5, 15, 11, 10, 14, 1,
357 			5, 3, 17, 8, 9, 18,
358 			5, 4, 7, 16, 11, 15,
359 		}
360 	},
361 
362 /* objicosa - structure values for icosahedron */
363 
364 	{
365 #ifdef DEFUNCT
366 		"icosahedron", "icosa",		/* long and short names */
367 		"dodecahedron",	/* long name of dual */
368 #endif
369 		12, 30, 20,	/* number of vertices, edges, and faces */
370 		{		/* vertices (x,y,z) */
371 			/* all points must be within radius 1 of the origin */
372 #define A 0.26286556
373 #define B 0.42532537
374 #define C 0.68819095
375 #define D 0.8090169943749474241 /* cos 36 */
376 #define E 0.8506508083520399322 /* cossec 36 / 2 */
377 #define F 0.9510565162951535721 /* sin 72 */
378 #define H 0.5
379 			{0, 0, -F},
380 			{0, E, -B},
381 			{D, A, -B},
382 			{H, -C, -B},
383 			{-H, -C, -B},
384 			{-D, A, -B},
385 			{H, C, B},
386 			{D, -A, B},
387 			{0, -E, B},
388 			{-D, -A, B},
389 			{-H, C, B},
390 			{0, 0, F}
391 #undef A
392 #undef B
393 #undef C
394 #undef D
395 #undef E
396 #undef F
397 #undef H
398 		},
399 		{		/* faces (numfaces + indexes into vertices) */
400 		/* faces must be specified clockwise from the outside */
401 			3, 0, 2, 1,
402 			3, 0, 3, 2,
403 			3, 0, 4, 3,
404 			3, 0, 5, 4,
405 			3, 0, 1, 5,
406 			3, 1, 6, 10,
407 			3, 1, 2, 6,
408 			3, 2, 7, 6,
409 			3, 2, 3, 7,
410 			3, 3, 8, 7,
411 			3, 3, 4, 8,
412 			3, 4, 9, 8,
413 			3, 4, 5, 9,
414 			3, 5, 10, 9,
415 			3, 5, 1, 10,
416 			3, 10, 6, 11,
417 			3, 6, 7, 11,
418 			3, 7, 8, 11,
419 			3, 8, 9, 11,
420 			3, 9, 10, 11
421 		}
422 	},
423 
424 /* objrhombicdoeca - structure values for rhombic dodecahedron */
425 
426 	{
427 #ifdef DEFUNCT
428 		"rhombic_dodecahedron", "rhombic",	/* long and short names */
429 		"cubooctahedron",	/* long name of dual */
430 #endif
431 		14, 24, 12,	/* number of vertices, edges, and faces */
432 		{		/* vertices (x,y,z) */
433 			/* all points must be within radius 1 of the origin */
434 #define T 1.0
435 #define H 0.5
436 			{T, 0, 0},
437 			{0, T, 0},
438 			{0, 0, T},
439 			{H, H, H},
440 			{H, H, -H},
441 			{H, -H, H},
442 			{H, -H, -H},
443 			{-H, H, H},
444 			{-H, H, -H},
445 			{-H, -H, H},
446 			{-H, -H, -H},
447 			{-T, 0, 0},
448 			{0, -T, 0},
449 			{0, 0, -T},
450 #undef H
451 #undef T
452 		},
453 		{		/* faces (numfaces + indexes into vertices) */
454 		/* faces must be specified clockwise from the outside */
455 			4, 0, 3, 2, 5,
456 			4, 2, 9, 12, 5,
457 			4, 2, 7, 11, 9,
458 			4, 1, 7, 2, 3,
459 			4, 0, 4, 1, 3,
460 			4, 0, 5, 12, 6,
461 			4, 9, 11, 10, 12,
462 			4, 1, 8, 11, 7,
463 			4, 0, 6, 13, 4,
464 			4, 6, 12, 10, 13,
465 			4, 8, 13, 10, 11,
466 			4, 1, 4, 13, 8,
467 		}
468 	},
469 
470 /* objtriacont - structure values for rhombic triacontahedron */
471 
472 	{
473 #ifdef DEFUNCT
474 		"rhombic_triacontahedron", "triaconta",	/* long and short names */
475 		"icosidodecahedron",	/* long name of dual */
476 #endif
477 		32, 60, 30,	/* number of vertices, edges, and faces */
478 		{		/* vertices (x,y,z) */
479 			/* all points must be within radius 1 of the origin */
480 #define G 0.3090169943749474241 /* cos 72 */
481 #define D 0.8090169943749474241 /* cos 36 */
482 #define H 0.5
483 			{0, G, D},
484 			{0, -G, D},
485 			{0, -G, -D},
486 			{0, G, -D},
487 			{D, 0, G},
488 			{-D, 0, G},
489 			{-D, 0, -G},
490 			{D, 0, -G},
491 			{G, D, 0},
492 			{-G, D, 0},
493 			{-G, -D, 0},
494 			{G, -D, 0},
495 			{H, H, H},
496 			{-H, H, H},
497 			{-H, -H, H},
498 			{H, -H, H},
499 			{H, -H, -H},
500 			{H, H, -H},
501 			{-H, H, -H},
502 			{-H, -H, -H},
503 			{0, D, H},
504 			{0, -D, H},
505 			{0, D, -H},
506 			{0, -D, -H},
507 			{H, 0, D},
508 			{-H, 0, D},
509 			{H, 0, -D},
510 			{-H, 0, -D},
511 			{D, H, 0},
512 			{-D, H, 0},
513 			{D, -H, 0},
514 			{-D, -H, 0},
515 #undef D
516 #undef H
517 #undef G
518 		},
519 		{		/* faces (numfaces + indexes into vertices) */
520 		/* faces must be specified clockwise from the outside */
521 			4, 8, 20, 12, 28,
522 			4, 0, 24, 12, 20,
523 			4, 4, 28, 12, 24,
524 			4, 8, 22, 9, 20,
525 			4, 8, 28, 17, 22,
526 			4, 9, 29, 13, 20,
527 			4, 0, 20, 13, 25,
528 			4, 0, 25, 1, 24,
529 			4, 5, 25, 13, 29,
530 			4, 9, 22, 18, 29,
531 			4, 3, 27, 18, 22,
532 			4, 3, 22, 17, 26,
533 			4, 6, 29, 18, 27,
534 			4, 7, 26, 17, 28,
535 			4, 2, 27, 3, 26,
536 			4, 4, 30, 7, 28,
537 			4, 4, 24, 15, 30,
538 			4, 7, 30, 16, 26,
539 			4, 1, 21, 15, 24,
540 			4, 1, 25, 14, 21,
541 			4, 11, 30, 15, 21,
542 			4, 11, 23, 16, 30,
543 			4, 2, 26, 16, 23,
544 			4, 10, 23, 11, 21,
545 			4, 2, 23, 19, 27,
546 			4, 10, 31, 19, 23,
547 			4, 10, 21, 14, 31,
548 			4, 5, 31, 14, 25,
549 			4, 5, 29, 6, 31,
550 			4, 6, 27, 19, 31,
551 		}
552 	},
553 
554 /* objtruncoct - structure values for truncated octahedron */
555 
556 	{
557 #ifdef DEFUNCT
558 		"truncated_octahedron", "mecon",	/* long and short names */
559 		"tetrakis_hexahedron",	/* long name of dual */
560 #endif
561 		24, 36, 14,	/* number of vertices, edges, and faces */
562 		{		/* vertices (x,y,z) */
563 			/* all points must be within radius 1 of the origin */
564 #define T 0.8506508083520399322 /* cossec 36 / 2 */
565 #define H 0.42532537
566 			{T, H, 0},
567 			{T, -H, 0},
568 			{T, 0, H},
569 			{T, 0, -H},
570 			{-T, H, 0},
571 			{-T, -H, 0},
572 			{-T, 0, H},
573 			{-T, 0, -H},
574 			{H, T, 0},
575 			{-H, T, 0},
576 			{0, T, H},
577 			{0, T, -H},
578 			{H, -T, 0},
579 			{-H, -T, 0},
580 			{0, -T, H},
581 			{0, -T, -H},
582 			{H, 0, T},
583 			{-H, 0, T},
584 			{0, H, T},
585 			{0, -H, T},
586 			{H, 0, -T},
587 			{-H, 0, -T},
588 			{0, H, -T},
589 			{0, -H, -T},
590 #undef H
591 #undef T
592 		},
593 		{		/* faces (numfaces + indexes into vertices) */
594 		/* faces must be specified clockwise from the outside */
595 			4, 0, 2, 1, 3,
596 			4, 4, 7, 5, 6,
597 			4, 8, 11, 9, 10,
598 			4, 12, 14, 13, 15,
599 			4, 16, 18, 17, 19,
600 			4, 20, 23, 21, 22,
601 			6, 2, 0, 8, 10, 18, 16,
602 			6, 0, 3, 20, 22, 11, 8,
603 			6, 1, 2, 16, 19, 14, 12,
604 			6, 3, 1, 12, 15, 23, 20,
605 			6, 4, 6, 17, 18, 10, 9,
606 			6, 7, 4, 9, 11, 22, 21,
607 			6, 6, 5, 13, 14, 19, 17,
608 			6, 5, 7, 21, 23, 15, 13,
609 		}
610 	},
611 
612 /* ico does not draw non-convex polyhedra well. */
613 /* objstar - structure values for octahedron star (stellated octahedron?) */
614 	{
615 #ifdef DEFUNCT
616 		"stella_octangula", "star",	/* long and short names */
617 		"stella_octangula",		/* long name of dual */
618 #endif
619 		14, 36, 24,	/* number of vertices, edges, and faces */
620 		/*8, 12, 8,*/	/* number of real vertices, edges, and faces */
621 		{		/* vertices (x,y,z) */
622 			/* all points must be within radius 1 of the origin */
623 #define T 0.577
624 			{-T, 0, 0},
625 			{0, -T, 0},
626 			{0, 0, -T},
627 			{0, 0, T},
628 			{0, T, 0},
629 			{T, 0, 0},
630 			{-T, -T, -T},
631 			{-T, -T, T},
632 			{-T, T, -T},
633 			{-T, T, T},
634 			{T, -T, -T},
635 			{T, -T, T},
636 			{T, T, -T},
637 			{T, T, T},
638 #undef T
639 /*#define T 0.577
640 			{T, T, T},
641 			{T, -T, -T},
642 			{-T, T, -T},
643 			{-T, -T, T},
644 			{-T, -T, -T},
645 			{-T, T, T},
646 			{T, -T, T},
647 			{T, T, -T},
648 #undef T*/
649 
650 		},
651 		{		/* faces (numfaces + indexes into vertices) */
652 		/* faces must be specified clockwise from the outside */
653 			3, 13, 5, 4,
654 			3, 13, 3, 5,
655 			3, 13, 4, 3,
656 			3, 12, 4, 5,
657 			3, 12, 5, 2,
658 			3, 12, 2, 4,
659 			3, 11, 1, 5,
660 			3, 11, 5, 3,
661 			3, 11, 3, 1,
662 			3, 10, 5, 1,
663 			3, 10, 2, 5,
664 			3, 10, 1, 2,
665 			3, 9, 4, 0,
666 			3, 9, 0, 3,
667 			3, 9, 3, 4,
668 			3, 8, 0, 4,
669 			3, 8, 2, 0,
670 			3, 8, 4, 2,
671 			3, 7, 0, 1,
672 			3, 7, 3, 0,
673 			3, 7, 1, 3,
674 			3, 6, 1, 0,
675 			3, 6, 0, 2,
676 			3, 6, 2, 1,
677 /*
678 			3, 2, 1, 0,
679 			3, 1, 3, 0,
680 			3, 3, 2, 0,
681 			3, 2, 3, 1,
682 			3, 6, 5, 4,
683 			3, 5, 7, 4,
684 			3, 7, 6, 4,
685 			3, 6, 7, 5,
686 */
687 		}
688 	},
689 /* objplane - structure values for plane */
690 
691 	{
692 #ifdef DEFUNCT
693 		"plane", "plane",	/* long and short names */
694 		"plane",	/* long name of dual?? */
695 #endif
696 		4, 4, 1,	/* number of vertices, edges, and faces */
697 		{		/* vertices (x,y,z) */
698 			/* all points must be within radius 1 of the origin */
699 #define T 1.0
700 			{T, 0, 0},
701 			{-T, 0, 0},
702 			{0, T, 0},
703 			{0, -T, 0},
704 #undef T
705 		},
706 		{		/* faces (numfaces + indexes into vertices) */
707 		/* faces must be specified clockwise from the outside */
708 			4, 0, 2, 1, 3,
709 		}
710 	},
711 
712 /* objpyr - structure values for pyramid */
713 
714 	{
715 #ifdef DEFUNCT
716 		"pyramid", "pyramid",	/* long and short names */
717 		"pyramid",	/* long name of dual */
718 #endif
719 		5, 8, 5,	/* number of vertices, edges, and faces */
720 		{		/* vertices (x,y,z) */
721 			/* all points must be within radius 1 of the origin */
722 #define T 1.0
723 			{T, 0, 0},
724 			{-T, 0, 0},
725 			{0, T, 0},
726 			{0, -T, 0},
727 			{0, 0, T},
728 		/* {0, 0, -T }, */
729 #undef T
730 		},
731 		{	/* faces (numfaces + indexes into vertices) */
732 		/* faces must be specified clockwise from the outside */
733 			3, 0, 4, 2,
734 			3, 0, 3, 4,
735 			3, 1, 2, 4,
736 			3, 1, 4, 3,
737 			4, 0, 2, 1, 3,
738 		}
739 	},
740 
741 };
742 
743 static int  polysize = sizeof (polygons) / sizeof (polygons[0]);
744 #define POLYSIZE 8	/* Only the 5 Platonic solids, the 2 edge transitive*/
745 	/* Catalan solids and the space filling Archimedean solid work */
746 
747 #define POLYBITS(n,w,h)\
748   if ((ip->pixmaps[ip->init_bits]=\
749   XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\
750   free_ico_screen(display,ip);return;} else {ip->init_bits++;}
751 
752 typedef double Transform3D[4][4];
753 
754 /* variables that need to be per-thread */
755 
756 typedef struct {
757 	int         loopcount;
758 	int         object;
759 	int         width, height;
760 	int         linewidth;
761 	long        color;
762 	Polyinfo   *poly;
763 	int         polyW, polyH;
764 	int         currX, currY;
765 	int         prevX, prevY;
766 	int         polyDeltaX, polyDeltaY;
767 	int         deltaWidth, deltaHeight;
768 	Bool        faces, edges, opaque;
769 	char        drawnEdges[MAXNV][MAXNV];
770 	char        drawnPoints[MAXNV];
771 	int         xv_buffer;
772 	Transform3D xform;
773 	Point3D     xv[2][MAXNV];
774 	double      wo2, ho2;
775 	Pixmap      dbuf;
776 	GC          dbuf_gc;
777 	int         color_offset;
778 	int         init_bits;
779 	GC          stippledGC;
780 	Pixmap      pixmaps[NUMSTIPPLES - 1];
781 } icostruct;
782 
783 static icostruct *icos = (icostruct *) NULL;
784 
785 /*-
786  * variables that are not set except maybe in initialization before
787  * any additional threads are created
788  */
789 
790 
791 static void
icoClearArea(ModeInfo * mi,int x,int y,int w,int h)792 icoClearArea(ModeInfo * mi, int x, int y, int w, int h)
793 {
794 	Display    *display = MI_DISPLAY(mi);
795 
796 #if 1
797 	/* my monochrome likes this better */
798 	XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
799 	XFillRectangle(display, MI_WINDOW(mi), MI_GC(mi), x, y, w, h);
800 #else
801 	XClearArea(display, MI_WINDOW(mi), x, y, w, h, 0);
802 #endif
803 }
804 
805 /******************************************************************************
806  * Description
807  *	Format a 4x4 identity matrix.
808  *
809  * Output
810  *	*m		Formatted identity matrix
811  *****************************************************************************/
812 static void
IdentMat(register Transform3D m)813 IdentMat(register Transform3D m)
814 {
815 	register int i;
816 	register int j;
817 
818 	for (i = 3; i >= 0; --i) {
819 		for (j = 3; j >= 0; --j)
820 			m[i][j] = 0.0;
821 		m[i][i] = 1.0;
822 	}
823 }
824 
825 
826 
827 /******************************************************************************
828  * Description
829  *	Format a matrix that will perform a rotation transformation
830  *	about the specified axis.  The rotation angle is measured
831  *	counterclockwise about the specified axis when looking
832  *	at the origin from the positive axis.
833  *
834  * Input
835  *	axis		Axis ('x', 'y', 'z') about which to perform rotation
836  *	angle		Angle (in radians) of rotation
837  *	A		Pointer to rotation matrix
838  *
839  * Output
840  *	*m		Formatted rotation matrix
841  *****************************************************************************/
842 
843 static void
FormatRotateMat(char axis,double angle,register Transform3D m)844 FormatRotateMat(char axis, double angle, register Transform3D m)
845 {
846 	double      s, c;
847 
848 	IdentMat(m);
849 
850 	s = sin(angle);
851 	c = cos(angle);
852 
853 	switch (axis) {
854 		case 'x':
855 			m[1][1] = m[2][2] = c;
856 			m[1][2] = s;
857 			m[2][1] = -s;
858 			break;
859 		case 'y':
860 			m[0][0] = m[2][2] = c;
861 			m[2][0] = s;
862 			m[0][2] = -s;
863 			break;
864 		case 'z':
865 			m[0][0] = m[1][1] = c;
866 			m[0][1] = s;
867 			m[1][0] = -s;
868 			break;
869 	}
870 }
871 
872 
873 /******************************************************************************
874  * Description
875  *	Concatenate two 4-by-4 transformation matrices.
876  *
877  * Input
878  *	l		multiplicand (left operand)
879  *	r		multiplier (right operand)
880  *
881  * Output
882  *	*m		Result matrix
883  *****************************************************************************/
884 
885 static void
ConcatMat(register Transform3D l,register Transform3D r,register Transform3D m)886 ConcatMat(register Transform3D l, register Transform3D r,
887 	  register Transform3D m)
888 {
889 	register int i;
890 	register int j;
891 
892 	for (i = 0; i < 4; ++i)
893 		for (j = 0; j < 4; ++j)
894 			m[i][j] = l[i][0] * r[0][j]
895 				+ l[i][1] * r[1][j]
896 				+ l[i][2] * r[2][j]
897 				+ l[i][3] * r[3][j];
898 }
899 
900 /* Set up points, transforms, etc.  */
901 
902 static void
initPoly(ModeInfo * mi,Polyinfo * poly,int polyW,int polyH,Bool init)903 initPoly(ModeInfo * mi, Polyinfo * poly, int polyW, int polyH, Bool init)
904 {
905 	icostruct  *ip = &icos[MI_SCREEN(mi)];
906 	Point3D    *vertices = poly->v;
907 	int         NV = poly->numverts;
908 	Transform3D r1;
909 	Transform3D r2;
910 
911 #define ROLL_DEGREES 5
912 	if ((ip->polyDeltaX < 0 && ip->polyDeltaY < 0) ||
913 	    (ip->polyDeltaX > 0 && ip->polyDeltaY > 0)) {
914 		FormatRotateMat('x', ((ip->polyDeltaX > 0) ?
915 		  -ROLL_DEGREES : ROLL_DEGREES) * M_PI / 180.0, r1);
916 		FormatRotateMat('y', ((ip->polyDeltaY < 0) ?
917 		  -ROLL_DEGREES : ROLL_DEGREES) * M_PI / 180.0, r2);
918 	} else {
919 		FormatRotateMat('x', ((ip->polyDeltaX < 0) ?
920 		  -ROLL_DEGREES : ROLL_DEGREES) * M_PI / 180.0, r1);
921 		FormatRotateMat('y', ((ip->polyDeltaY > 0) ?
922 		  -ROLL_DEGREES : ROLL_DEGREES) * M_PI / 180.0, r2);
923 	}
924 	ConcatMat(r1, r2, ip->xform);
925     if (init) {
926 		(void) memcpy((char *) ip->xv[0], (char *) vertices, NV * sizeof (Point3D));
927 		ip->xv_buffer = 0;
928 		ip->wo2 = polyW / 2.0;
929 		ip->ho2 = polyH / 2.0;
930 	}
931 }
932 
933 /******************************************************************************
934  * Description
935  *	Perform a partial transform on non-homogeneous points.
936  *	Given an array of non-homogeneous (3-coordinate) input points,
937  *	this routine multiplies them by the 3-by-3 upper left submatrix
938  *	of a standard 4-by-4 transform matrix.  The resulting non-homogeneous
939  *	points are returned.
940  *
941  * Input
942  *	n		number of points to transform
943  *	m		4-by-4 transform matrix
944  *	in		array of non-homogeneous input points
945  *
946  * Output
947  *	*out		array of transformed non-homogeneous output points
948  *****************************************************************************/
949 
950 static void
PartialNonHomTransform(int n,register Transform3D m,register Point3D * in,register Point3D * out)951 PartialNonHomTransform(int n, register Transform3D m,
952 		       register Point3D * in, register Point3D * out)
953 {
954 	for (; n > 0; --n, ++in, ++out) {
955 		out->x = in->x * m[0][0] + in->y * m[1][0] + in->z * m[2][0];
956 		out->y = in->x * m[0][1] + in->y * m[1][1] + in->z * m[2][1];
957 		out->z = in->x * m[0][2] + in->y * m[1][2] + in->z * m[2][2];
958 	}
959 }
960 
961 
962 /******************************************************************************
963  * Description
964  *	Undraw previous polyhedron (by erasing its bounding box).
965  *	Rotate and draw the new polyhedron.
966  *
967  * Input
968  *	poly		the polyhedron to draw
969  *	gc		X11 graphics context to be used for drawing
970  *	currX, currY	position of upper left of bounding-box
971  *	polyW, polyH	size of bounding-box
972  *	prevX, prevY	position of previous bounding-box
973  *****************************************************************************/
974 
975 static void
drawPoly(ModeInfo * mi,Polyinfo * poly,GC gc,int currX,int currY,int polyW,int polyH,int prevX,int prevY)976 drawPoly(ModeInfo * mi, Polyinfo * poly, GC gc,
977 	 int currX, int currY, int polyW, int polyH, int prevX, int prevY)
978 {
979 	Display    *display = MI_DISPLAY(mi);
980 	Window      window = MI_WINDOW(mi);
981 	icostruct  *ip = &icos[MI_SCREEN(mi)];
982 	int        *f = poly->f;
983 	int         NV = poly->numverts;
984 	int         NF = poly->numfaces;
985 
986 	register int p0;
987 	register int p1;
988 	register XPoint *pv2;
989 	XSegment   *pe;
990 	XPoint   *pp;
991 	register Point3D *pxv;
992 	XPoint      v2[MAXNV];
993 	XPoint      pts[MAXNV];
994 	XSegment    edge_segs[MAXEDGES];
995 	register int i;
996 	int         j, k;
997 	register int *pf;
998 	int         facecolor;
999 
1000 	int         pcount = 0;
1001 	double      pxvz;
1002 	XPoint      ppts[MAXEDGESPERPOLY];
1003 	Window      lwindow;
1004 	GC          lgc;
1005 
1006 	/* Switch double-buffer and rotate vertices */
1007 
1008 	ip->xv_buffer = !ip->xv_buffer;
1009 	PartialNonHomTransform(NV, ip->xform,
1010 			       ip->xv[!ip->xv_buffer], ip->xv[ip->xv_buffer]);
1011 
1012 
1013 	/* Convert 3D coordinates to 2D window coordinates: */
1014 
1015 	pxv = ip->xv[ip->xv_buffer];
1016 	pv2 = v2;
1017 	for (i = NV - 1; i >= 0; --i) {
1018 		pv2->x = (int) ((pxv->x + 1.0) * ip->wo2) + currX;
1019 		pv2->y = (int) ((pxv->y + 1.0) * ip->ho2) + currY;
1020 		++pxv;
1021 		++pv2;
1022 	}
1023 
1024 
1025 	/* Accumulate edges to be drawn, eliminating duplicates for speed: */
1026 
1027 	pxv = ip->xv[ip->xv_buffer];
1028 	pv2 = v2;
1029 	pf = f;
1030 	pe = edge_segs;
1031 	pp = pts;
1032 	(void) memset(ip->drawnEdges, 0, sizeof (ip->drawnEdges));
1033 	(void) memset(ip->drawnPoints, 0, sizeof (ip->drawnPoints));
1034 
1035 	if (ip->dbuf) {
1036 		XSetForeground(display, ip->dbuf_gc, MI_BLACK_PIXEL(mi));
1037 		XFillRectangle(display, (Drawable) ip->dbuf, ip->dbuf_gc, 0, 0,
1038 			polyW + ip->deltaWidth + ip->linewidth,
1039 			polyH + ip->deltaHeight + ip->linewidth);
1040 		lwindow = (Drawable) ip->dbuf;
1041 		lgc = ip->dbuf_gc;
1042 	} else {
1043 		lwindow = window;
1044 		lgc = gc;
1045 		icoClearArea(mi, prevX, prevY, polyW + 1, polyH + 1);
1046 	}
1047 	for (i = NF - 1; i >= 0; --i, pf += pcount) {
1048 
1049 		pcount = *pf++;	/* number of edges for this face */
1050 		pxvz = 0.0;
1051 		for (j = 0; j < pcount; j++) {
1052 			p0 = pf[j];
1053 			pxvz += pxv[p0].z;
1054 		}
1055 
1056 		/* If facet faces away from viewer, don't consider it: */
1057 		if (pxvz < 0.0 && (ip->faces || ip->opaque))
1058 			continue;
1059 
1060 		if (ip->faces) {
1061 			for (j = 0; j < pcount; j++) {
1062 				p0 = pf[j];
1063 				ppts[j].x = pv2[p0].x;
1064 				ppts[j].y = pv2[p0].y;
1065 				if (ip->dbuf) {
1066 					ppts[j].x -= (currX - ip->deltaWidth / 2 - ip->linewidth / 2);
1067 					ppts[j].y -= (currY - ip->deltaHeight / 2 - ip->linewidth / 2);
1068 				}
1069 			}
1070 			if (MI_NPIXELS(mi) > 2) {
1071 				facecolor = (i * MI_NPIXELS(mi) / NF + ip->color_offset) % MI_NPIXELS(mi);
1072 				XSetForeground(display, lgc, MI_PIXEL(mi, facecolor));
1073 			} else {
1074 				XGCValues   gcv;
1075 				facecolor = (i * (NUMSTIPPLES - 1) / NF + ip->color_offset) % (NUMSTIPPLES - 1);
1076 				gcv.stipple = ip->pixmaps[facecolor];
1077 				gcv.foreground = MI_WHITE_PIXEL(mi);
1078 				gcv.background = MI_BLACK_PIXEL(mi);
1079 				XChangeGC(MI_DISPLAY(mi), ip->stippledGC,
1080 				GCStipple | GCForeground | GCBackground, &gcv);
1081 				lgc = ip->stippledGC;
1082 				/* XSetForeground(display, lgc, MI_WHITE_PIXEL(mi)); */
1083 			}
1084 			XFillPolygon(display, lwindow, lgc,
1085 				ppts, pcount, Convex, CoordModeOrigin);
1086 		}
1087 		if (ip->edges) {
1088 			for (j = 0; j < pcount; j++) {
1089 				if (j < pcount - 1)
1090 					k = j + 1;
1091 				else
1092 					k = 0;
1093 				p0 = pf[j];
1094 				p1 = pf[k];
1095 				if (!ip->drawnEdges[p0][p1]) {
1096 					ip->drawnEdges[p0][p1] = 1;
1097 					ip->drawnEdges[p1][p0] = 1;
1098 					pe->x1 = pv2[p0].x;
1099 					pe->y1 = pv2[p0].y;
1100 					pe->x2 = pv2[p1].x;
1101 					pe->y2 = pv2[p1].y;
1102 					if (ip->dbuf) {
1103 						pe->x1 -= (currX - ip->deltaWidth / 2 - ip->linewidth / 2);
1104 						pe->y1 -= (currY - ip->deltaHeight / 2 - ip->linewidth / 2);
1105 						pe->x2 -= (currX - ip->deltaWidth / 2 - ip->linewidth / 2);
1106 						pe->y2 -= (currY - ip->deltaHeight / 2 - ip->linewidth / 2);
1107 					}
1108 					++pe;
1109 				}
1110 			}
1111 		} else {
1112 			for (j = 0; j < pcount; j++) {
1113 				p0 = pf[j];
1114 				if (!ip->drawnPoints[p0]) {
1115 					ip->drawnPoints[p0] = 1;
1116 					pp->x = pv2[p0].x;
1117 					pp->y = pv2[p0].y;
1118 					if (ip->dbuf) {
1119 						pp->x -= (currX - ip->deltaWidth / 2 - ip->linewidth / 2);
1120 						pp->y -= (currY - ip->deltaHeight / 2 - ip->linewidth / 2);
1121 					}
1122 					++pp;
1123 				}
1124 			}
1125 		}
1126 	}
1127 	/* Erase previous, draw current icosahedrons; sync for smoothness. */
1128 
1129 	if (ip->edges) {
1130 		if (MI_NPIXELS(mi) <= 2)
1131 			if (ip->faces) {
1132 				XSetForeground(display, lgc, ip->color);
1133 			} else {
1134 				XSetForeground(display, lgc, MI_WHITE_PIXEL(mi));
1135 			}
1136 		else {
1137 			ip->color = (ip->color + 1) % MI_NPIXELS(mi);
1138 			XSetForeground(display, lgc, MI_PIXEL(mi, ip->color));
1139 		}
1140 		XSetLineAttributes(display, lgc, ip->linewidth,
1141 			LineSolid, CapRound, JoinRound);
1142 		XDrawSegments(display, lwindow, lgc, edge_segs, pe - edge_segs);
1143 		XSetLineAttributes(display, lgc, 1,
1144 			LineSolid, CapNotLast, JoinRound);
1145 	} else if (!ip->faces) {
1146 		if (MI_NPIXELS(mi) <= 2)
1147 			XSetForeground(display, lgc, MI_WHITE_PIXEL(mi));
1148 		else {
1149 			ip->color = (ip->color + 1) % MI_NPIXELS(mi);
1150 			XSetForeground(display, lgc, MI_PIXEL(mi, ip->color));
1151 		}
1152 #if 0
1153 		/* just does not look that good */
1154 		if (ip->linewidth <= 1)
1155 			XDrawPoints(display, lwindow, lgc, pts, pp - pts, CoordModeOrigin);
1156 		else
1157 #endif
1158 		{
1159 			for (j = 0; j < pp-pts; j++)
1160 			  XFillArc(display, lwindow, lgc,
1161 			    pts[j].x - ip->linewidth / 2, pts[j].y - ip->linewidth / 2, ip->linewidth, ip->linewidth, 0, 23040);
1162 
1163 		}
1164 	}
1165 	if (ip->dbuf) {
1166 		XCopyArea(display, (Drawable) ip->dbuf, window, gc, 0, 0,
1167 			polyW + 1 + ip->deltaWidth + ip->linewidth,
1168 			polyH + 1 + ip->deltaHeight + ip->linewidth,
1169 			currX - ip->deltaWidth / 2 - ip->linewidth / 2,
1170 			currY - ip->deltaHeight / 2 - ip->linewidth / 2);
1171 	}
1172 	XFlush(display);
1173 }
1174 
1175 static void
free_ico_screen(Display * display,icostruct * ip)1176 free_ico_screen(Display *display, icostruct *ip)
1177 {
1178 	int shade;
1179 
1180 	if (ip == NULL) {
1181 		return;
1182 	}
1183 	if (ip->stippledGC != None) {
1184 		XFreeGC(display, ip->stippledGC);
1185 		ip->stippledGC = None;
1186 	}
1187 	for (shade = 0; shade < ip->init_bits; shade++) {
1188 		if (ip->pixmaps[shade] != None) {
1189 			XFreePixmap(display, ip->pixmaps[shade]);
1190 			ip->pixmaps[shade] = None;
1191 		}
1192 	}
1193 	if (ip->dbuf != None) {
1194 		XFreePixmap(display, ip->dbuf);
1195 		ip->dbuf = None;
1196 	}
1197 	if (ip->dbuf_gc != None) {
1198 		XFreeGC(display, ip->dbuf_gc);
1199 		ip->dbuf_gc = None;
1200 	}
1201 	ip = NULL;
1202 }
1203 
1204 ENTRYPOINT void
init_ico(ModeInfo * mi)1205 init_ico(ModeInfo * mi)
1206 {
1207 	Display * display = MI_DISPLAY(mi);
1208 	Window window = MI_WINDOW(mi);
1209 	int         size = MI_SIZE(mi);
1210 	icostruct  *ip;
1211 
1212 	MI_INIT(mi, icos);
1213 	ip = &icos[MI_SCREEN(mi)];
1214 
1215 	ip->width = MI_WIDTH(mi);
1216 	ip->height = MI_HEIGHT(mi);
1217 	ip->linewidth = NRAND((ip->width + ip->height) / 200 + 1) + 2;
1218 
1219 	if (MI_NPIXELS(mi) <= 2) {
1220 		if (ip->stippledGC == None) {
1221 			XGCValues   gcv;
1222 
1223 			gcv.fill_style = FillOpaqueStippled;
1224 			if ((ip->stippledGC = XCreateGC(display, window, GCFillStyle,
1225 					 &gcv)) == None) {
1226 				free_ico_screen(display, ip);
1227 				return;
1228 			}
1229 		}
1230 		if (ip->init_bits == 0) {
1231 			int i;
1232 
1233 			for (i = 1; i < NUMSTIPPLES; i++) {
1234 				POLYBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
1235 			}
1236 		}
1237 	}
1238 
1239 	if (MI_IS_FULLRANDOM(mi)) {
1240 		ip->faces = (Bool) (LRAND() & 1);
1241 		ip->edges = (Bool) (LRAND() & 1);
1242 		ip->opaque = (!(NRAND(4) == 0));
1243 	} else {
1244 		ip->edges = edges;
1245 		ip->faces = faces;
1246 		ip->opaque = opaque;
1247 	}
1248 
1249 	if (size < -MINSIZE)
1250 		ip->polyW = NRAND(MIN(-size, MAX(MINSIZE,
1251 		   MIN(ip->width, ip->height) / 4)) - MINSIZE + 1) + MINSIZE;
1252 	else if (size < MINSIZE) {
1253 		if (!size)
1254 			ip->polyW = MAX(MINSIZE, MIN(ip->width, ip->height) / 4);
1255 		else
1256 			ip->polyW = MINSIZE;
1257 	} else
1258 		ip->polyW = MIN(size, MAX(MINSIZE,
1259 					  MIN(ip->width, ip->height) / 4));
1260 
1261 	ip->polyH = ip->polyW;
1262 	ip->polyDeltaX = ip->polyW / DEFAULT_DELTAY + 1;
1263 	ip->polyDeltaY = ip->polyH / DEFAULT_DELTAX + 1;
1264 	ip->currX = NRAND(ip->width - ip->polyW);
1265 	ip->currY = NRAND(ip->height - ip->polyH);
1266 
1267 	/* Bounce the box in the window */
1268 
1269 	ip->deltaWidth = ip->polyDeltaX * 2;
1270 	ip->deltaHeight = ip->polyDeltaY * 2;
1271 	ip->polyDeltaX *= ((LRAND() & 1) ? 1 : -1);
1272 	ip->polyDeltaY *= ((LRAND() & 1) ? 1 : -1);
1273 
1274 	ip->loopcount = 0;
1275 
1276 	ip->object = MI_COUNT(mi) - 1;
1277 	if (ip->object < 0 || ip->object >= polysize) {
1278 		/* avoid pyramid and star (drawing errors) count = 7 & 8
1279 		   also  avoid plane (boring) count = 6
1280 		   but allow direct access */
1281 		ip->object = NRAND(POLYSIZE);
1282 	}
1283 	ip->poly = polygons + ip->object;
1284 	if (MI_NPIXELS(mi) > 2)
1285 		ip->color = NRAND(MI_NPIXELS(mi));
1286 	else if (ip->faces && ip->edges)
1287 		ip->color = (LRAND() & 1) ? MI_WHITE_PIXEL(mi) : MI_BLACK_PIXEL(mi);
1288 
1289 	ip->color_offset = NRAND(MI_NPIXELS(mi));
1290 #ifndef NO_DBUF
1291 	if (ip->dbuf != None)
1292 		XFreePixmap(display, ip->dbuf);
1293 	ip->dbuf = XCreatePixmap(display, window,
1294 		ip->polyW + ip->deltaWidth + ip->linewidth,
1295 		ip->polyH + ip->deltaHeight + ip->linewidth,
1296 	 	MI_DEPTH(mi));
1297 	/* Allocation checked */
1298 	if (ip->dbuf != None) {
1299 		XGCValues   gcv;
1300 
1301 		gcv.foreground = 0;
1302 		gcv.background = 0;
1303 		gcv.graphics_exposures = False;
1304 		gcv.function = GXcopy;
1305 
1306 		if (ip->dbuf_gc != None)
1307 			XFreeGC(display, ip->dbuf_gc);
1308 		if ((ip->dbuf_gc = XCreateGC(display, (Drawable) ip->dbuf,
1309 				GCForeground | GCBackground | GCGraphicsExposures | GCFunction,
1310 				&gcv)) == None) {
1311 			XFreePixmap(display, ip->dbuf);
1312 			ip->dbuf = None;
1313 		} else {
1314 			XFillRectangle(display, (Drawable) ip->dbuf, ip->dbuf_gc,
1315 				0, 0, ip->polyW + ip->deltaWidth + ip->linewidth,
1316 				ip->polyH + ip->deltaHeight + ip->linewidth);
1317 			/*XSetBackground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
1318 			XSetFunction(display, MI_GC(mi), GXcopy);*/
1319 		}
1320 	}
1321 #endif
1322 
1323 	MI_CLEARWINDOW(mi);
1324 
1325 	/* don't want any exposure events from XCopyPlane */
1326 	XSetGraphicsExposures(display, MI_GC(mi), False);
1327 
1328 
1329 	initPoly(mi, ip->poly, ip->polyW, ip->polyH, True);
1330 }
1331 
1332 ENTRYPOINT void
draw_ico(ModeInfo * mi)1333 draw_ico(ModeInfo * mi)
1334 {
1335 	icostruct  *ip;
1336 
1337 	if (icos == NULL)
1338 		return;
1339 	ip = &icos[MI_SCREEN(mi)];
1340 	if ((MI_NPIXELS(mi) <= 2) && (ip->stippledGC == None))
1341 		return;
1342 
1343 	MI_IS_DRAWN(mi) = True;
1344 	if (++ip->loopcount > MI_CYCLES(mi))
1345 		init_ico(mi);
1346 
1347 	ip->prevX = ip->currX;
1348 	ip->prevY = ip->currY;
1349 
1350 	ip->currX += ip->polyDeltaX;
1351 	if (ip->currX < 0 || ip->currX + ip->polyW > ip->width) {
1352 
1353 		ip->currX -= 2 * ip->polyDeltaX;
1354 		ip->polyDeltaX = -ip->polyDeltaX;
1355 		/* spin should change after hitting wall */
1356 		initPoly(mi, ip->poly, ip->polyW, ip->polyH, False);
1357 	}
1358 	ip->currY += ip->polyDeltaY;
1359 	if (ip->currY < 0 || ip->currY + ip->polyH > ip->height) {
1360 		ip->currY -= 2 * ip->polyDeltaY;
1361 		ip->polyDeltaY = -ip->polyDeltaY;
1362 		/* spin should change after hitting wall */
1363 		initPoly(mi, ip->poly, ip->polyW, ip->polyH, False);
1364 	}
1365 	drawPoly(mi, ip->poly, MI_GC(mi),
1366 	   ip->currX, ip->currY, ip->polyW, ip->polyH, ip->prevX, ip->prevY);
1367 }
1368 ENTRYPOINT void
release_ico(ModeInfo * mi)1369 release_ico(ModeInfo * mi)
1370 {
1371 	if (icos != NULL) {
1372 		int screen;
1373 
1374 		for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1375 			free_ico_screen(MI_DISPLAY(mi), &icos[screen]);
1376 		free(icos);
1377 		icos = (icostruct *) NULL;
1378 	}
1379 }
1380 
1381 #ifndef STANDALONE
1382 ENTRYPOINT void
refresh_ico(ModeInfo * mi)1383 refresh_ico(ModeInfo * mi)
1384 {
1385 	MI_CLEARWINDOW(mi);
1386 }
1387 
1388 ENTRYPOINT void
change_ico(ModeInfo * mi)1389 change_ico(ModeInfo * mi)
1390 {
1391 	icostruct  *ip;
1392 
1393 	if (icos == NULL)
1394 		return;
1395 	ip = &icos[MI_SCREEN(mi)];
1396 	if (MI_NPIXELS(mi) <= 2 && ip->stippledGC == None)
1397 		return;
1398 
1399 	if (MI_COUNT(mi) <= 0 || MI_COUNT(mi) > POLYSIZE) {
1400 		ip->object = (ip->object + 1) % (POLYSIZE);
1401 		ip->poly = polygons + ip->object;
1402 	}
1403 	ip->loopcount = 0;
1404 
1405 	MI_CLEARWINDOWCOLORMAPFAST(mi, MI_GC(mi), MI_BLACK_PIXEL(mi));
1406 
1407 	initPoly(mi, ip->poly, ip->polyW, ip->polyH, True);
1408 }
1409 #endif
1410 
1411 XSCREENSAVER_MODULE ("Ico", ico)
1412 
1413 #endif /* MODE_ico */
1414