ftp://ftp.krokus.ru/pub/OpenBSD/distfiles/xscreensaver-5.01.tar.gz
[xscreensaver] / hacks / crystal.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* crystal --- polygons moving according to plane group rules */
3
4 #if 0
5 static const char sccsid[] = "@(#)crystal.c     4.12 98/09/10 xlockmore";
6 #endif
7
8 /*-
9  * Copyright (c) 1997 by Jouk Jansen <joukj@crys.chem.uva.nl>
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  * The author should like to be notified if changes have been made to the
24  * routine.  Response will only be guaranteed when a VMS version of the 
25  * program is available.
26  *
27  * A moving polygon-mode. The polygons obey 2D-planegroup symmetry.
28  *
29  * The groupings of the cells fall in 3 categories:
30  *   oblique groups 1 and 2 where the angle gamma ranges from 60 to 120 degrees
31  *   square groups 3 through 11 where the angle gamma is 90 degrees
32  *   hexagonal groups 12 through 17 where the angle gamma is 120 degrees
33  *
34  * Revision History:
35  * 03-Dec-98: Random inversion of y-axis included to simulate hexagonal groups
36  *             with an angle of 60 degrees.
37  * 10-Sep-98: new colour scheme
38  * 24-Feb-98: added option centre which turns on/off forcing the centre of
39  *              the screen to be used
40  *            added option maxsize which forces the dimensions to be chasen
41  *              in such ua way that the largest possible part of the screen is
42  *              used 
43  *            When only one unit cell is drawn, it is chosen at random
44  * 18-Feb-98: added support for negative numbers with -nx and -ny meaning
45  *            "random" choice with given maximum
46  *            added +/-grid option. If -cell is specified this option
47  *            determines if one or all unit cells are drawn.
48  *            -batchcount is now a parameter for all the objects on the screen
49  *            instead of the number of "unique" objects
50  *            The maximum size of the objects now scales with the part
51  *            of the screen used.
52  *            fixed "size" problem. Now very small non-vissable objects
53  *            are not allowed
54  * 13-Feb-98: randomized the unit cell size
55  *            runtime options -/+cell (turn on/off unit cell drawing)
56  *             -nx num (number of translational symmetries in x-direction
57  *             -ny num (idem y-direction but ignored for square and
58  *               hexagonal space groups
59  *               i.e. try xlock -mode crystal -nx 3 -ny 2
60  *            Fullrandom overrules the -/+cell option.
61  * 05-Feb-98: Revision + bug repairs
62  *            shows unit cell
63  *            use part of the screen for unit cell
64  *            in hexagonal and square groups a&b axis forced to be equal
65  *            cell angle for oblique groups randomly chosen between 60 and 120
66  *   bugs solved: planegroups with cell angles <> 90.0 now work properly
67  * 19-Sep-97: Added remaining hexagonal groups
68  * 12-Jun-97: Created
69  */
70
71 #ifdef STANDALONE
72 # define DEFAULTS               "*delay:                60000   \n" \
73                                                  "*count:                -500   \n" \
74                                                  "*cycles:                200   \n" \
75                                                  "*size:                  -15   \n" \
76                                                  "*ncolors:               100   \n"
77 # define reshape_crystal 0
78 # define crystal_handle_event 0
79 # include "xlockmore.h"         /* in xscreensaver distribution */
80 #else /* STANDALONE */
81 # include "xlock.h"                     /* in xlockmore distribution */
82 # include "color.h"
83 #endif /* STANDALONE */
84
85 #define DEF_CELL "True"         /* Draw unit cell */
86 #define DEF_GRID "False"        /* Draw unit all cell if DEF_CELL is True */
87 #define DEF_NX "-3"             /* number of unit cells in x-direction */
88 #define DEF_NX1 1               /* number of unit cells in x-direction */
89 #define DEF_NY "-3"             /* number of unit cells in y-direction */
90 #define DEF_NY1 1               /* number of unit cells in y-direction */
91 #define DEF_CENTRE "False"
92 #define DEF_MAXSIZE "False"
93 #define DEF_CYCLE "True"
94
95 #undef NRAND
96 #define NRAND(n)           ( (n) ? (int) (LRAND() % (n)) : 0)
97
98 #define min(a,b) ((a) <= (b) ? (a) : (b))
99
100 static int  nx, ny;
101
102 static Bool unit_cell, grid_cell, centre, maxsize, cycle_p;
103
104 static XrmOptionDescRec opts[] =
105 {
106         {"-nx", "crystal.nx", XrmoptionSepArg, 0},
107         {"-ny", "crystal.ny", XrmoptionSepArg, 0},
108         {"-centre", ".crystal.centre", XrmoptionNoArg, "on"},
109         {"+centre", ".crystal.centre", XrmoptionNoArg, "off"},
110         {"-maxsize", ".crystal.maxsize", XrmoptionNoArg, "on"},
111         {"+maxsize", ".crystal.maxsize", XrmoptionNoArg, "off"},
112         {"-cell", ".crystal.cell", XrmoptionNoArg, "on"},
113         {"+cell", ".crystal.cell", XrmoptionNoArg, "off"},
114         {"-grid", ".crystal.grid", XrmoptionNoArg, "on"},
115         {"+grid", ".crystal.grid", XrmoptionNoArg, "off"},
116         {"-shift", ".crystal.shift", XrmoptionNoArg, "on"},
117         {"+shift", ".crystal.shift", XrmoptionNoArg, "off"}
118 };
119
120 static argtype vars[] =
121 {
122         {&nx, "nx", "nx", DEF_NX, t_Int},
123         {&ny, "ny", "ny", DEF_NY, t_Int},
124         {&centre, "centre", "Centre", DEF_CENTRE, t_Bool},
125         {&maxsize, "maxsize", "Maxsize", DEF_MAXSIZE, t_Bool},
126         {&unit_cell, "cell", "Cell", DEF_CELL, t_Bool},
127         {&grid_cell, "grid", "Grid", DEF_GRID, t_Bool},
128         {&cycle_p, "shift", "Shift", DEF_CYCLE, t_Bool}
129 };
130 static OptionStruct desc[] =
131 {
132         {"-nx num", "Number of unit cells in x-direction"},
133         {"-ny num", "Number of unit cells in y-direction"},
134         {"-/+centre", "turn on/off centering on screen"},
135         {"-/+maxsize", "turn on/off use of maximum part of screen"},
136         {"-/+cell", "turn on/off drawing of unit cell"},
137    {"-/+grid", "turn on/off drawing of grid of unit cells (if -cell is on)"},
138         {"-/+shift", "turn on/off colour cycling"}
139 };
140
141 ENTRYPOINT ModeSpecOpt crystal_opts =
142 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
143
144 #ifdef USE_MODULES
145 ModStruct   crystal_description =
146 {"crystal", "init_crystal", "draw_crystal", "release_crystal",
147  "refresh_crystal", "init_crystal", NULL, &crystal_opts,
148  60000, -40, 200, -15, 64, 1.0, "",
149  "Shows polygons in 2D plane groups", 0, NULL};
150
151 #endif
152
153 #define DEF_NUM_ATOM 10
154
155 #define DEF_SIZ_ATOM 10
156
157 #define PI_RAD (M_PI / 180.0)
158
159 static Bool centro[17] =
160 {
161         False,
162         True,
163         False,
164         False,
165         False,
166         True,
167         True,
168         True,
169         True,
170         True,
171         True,
172         True,
173         False,
174         False,
175         False,
176         True,
177         True
178 };
179
180 static Bool primitive[17] =
181 {
182         True,
183         True,
184         True,
185         True,
186         False,
187         True,
188         True,
189         True,
190         False,
191         True,
192         True,
193         True,
194         True,
195         True,
196         True,
197         True,
198         True
199 };
200
201 static short numops[34] =
202 {
203         1, 0,
204         1, 0,
205         9, 7,
206         2, 0,
207         9, 7,
208         9, 7,
209         4, 2,
210         5, 3,
211         9, 7,
212         8, 6,
213         10, 6,
214         8, 4,
215         16, 13,
216         19, 13,
217         16, 10,
218         19, 13,
219         19, 13
220 };
221
222 static short operation[114] =
223 {
224         1, 0, 0, 1, 0, 0,
225         -1, 0, 0, 1, 0, 1,
226         -1, 0, 0, 1, 1, 0,
227         1, 0, 0, 1, 0, 0,
228         -1, 0, 0, 1, 1, 1,
229         1, 0, 0, 1, 1, 1,
230         0, -1, 1, 0, 0, 0,
231         1, 0, 0, 1, 0, 0,
232         -1, 0, 0, 1, 0, 0,
233         0, 1, 1, 0, 0, 0,
234         -1, 0, -1, 1, 0, 0,
235         1, -1, 0, -1, 0, 0,
236         0, 1, 1, 0, 0, 0,
237         0, -1, 1, -1, 0, 0,
238         -1, 1, -1, 0, 0, 0,
239         1, 0, 0, 1, 0, 0,
240         0, -1, -1, 0, 0, 0,
241         -1, 1, 0, 1, 0, 0,
242         1, 0, 1, -1, 0, 0
243 };
244
245 typedef struct {
246         unsigned long colour;
247         int         x0, y0, velocity[2];
248         float       angle, velocity_a;
249         int         num_point, at_type, size_at;
250         XPoint      xy[5];
251 } crystalatom;
252
253 typedef struct {
254         Bool        painted;
255         int         win_width, win_height, num_atom;
256         int         planegroup, a, b, offset_w, offset_h, nx, ny;
257         float       gamma;
258         crystalatom *atom;
259         GC          gc;
260         Bool        unit_cell, grid_cell;
261         Colormap    cmap;
262         XColor     *colors;
263         int         ncolors;
264         Bool        cycle_p, mono_p, no_colors;
265         unsigned long blackpixel, whitepixel, fg, bg;
266         int         direction, invert;
267 } crystalstruct;
268
269 static crystalstruct *crystals = NULL;
270
271 static void
272 trans_coor(XPoint * xyp, XPoint * new_xyp, int num_points,
273            float gamma)
274 {
275         int         i;
276
277         for (i = 0; i <= num_points; i++) {
278                 new_xyp[i].x = xyp[i].x +
279                         (int) (xyp[i].y * sin((gamma - 90.0) * PI_RAD));
280                 new_xyp[i].y = (int) (xyp[i].y / cos((gamma - 90.0) * PI_RAD));
281         }
282 }
283
284 static void
285 trans_coor_back(XPoint * xyp, XPoint * new_xyp,
286                 int num_points, float gamma, int offset_w, int offset_h ,
287                 int winheight , int invert )
288 {
289         int         i;
290
291         for (i = 0; i <= num_points; i++) {
292                 new_xyp[i].y = (int) (xyp[i].y * cos((gamma - 90) * PI_RAD)) +
293                         offset_h;
294                 new_xyp[i].x = xyp[i].x - (int) (xyp[i].y * sin((gamma - 90.0)
295                                                        * PI_RAD)) + offset_w;
296            if ( invert ) new_xyp[i].y = winheight - new_xyp[i].y;
297         }
298 }
299
300 static void
301 crystal_setupatom(crystalatom * atom0, float gamma)
302 {
303         XPoint      xy[5];
304         int         x0, y0;
305
306         y0 = (int) (atom0->y0 * cos((gamma - 90) * PI_RAD));
307         x0 = atom0->x0 - (int) (atom0->y0 * sin((gamma - 90.0) * PI_RAD));
308         switch (atom0->at_type) {
309                 case 0: /* rectangles */
310                         xy[0].x = x0 + (int) (2 * atom0->size_at *
311                                               cos(atom0->angle)) +
312                                 (int) (atom0->size_at * sin(atom0->angle));
313                         xy[0].y = y0 + (int) (atom0->size_at *
314                                               cos(atom0->angle)) -
315                                 (int) (2 * atom0->size_at * sin(atom0->angle));
316                         xy[1].x = x0 + (int) (2 * atom0->size_at *
317                                               cos(atom0->angle)) -
318                                 (int) (atom0->size_at * sin(atom0->angle));
319                         xy[1].y = y0 - (int) (atom0->size_at *
320                                               cos(atom0->angle)) -
321                                 (int) (2 * atom0->size_at * sin(atom0->angle));
322                         xy[2].x = x0 - (int) (2 * atom0->size_at *
323                                               cos(atom0->angle)) -
324                                 (int) (atom0->size_at * sin(atom0->angle));
325                         xy[2].y = y0 - (int) (atom0->size_at *
326                                               cos(atom0->angle)) +
327                                 (int) (2 * atom0->size_at * sin(atom0->angle));
328                         xy[3].x = x0 - (int) (2 * atom0->size_at *
329                                               cos(atom0->angle)) +
330                                 (int) (atom0->size_at * sin(atom0->angle));
331                         xy[3].y = y0 + (int) (atom0->size_at *
332                                               cos(atom0->angle)) +
333                                 (int) (2 * atom0->size_at *
334                                        sin(atom0->angle));
335                         xy[4].x = xy[0].x;
336                         xy[4].y = xy[0].y;
337                         trans_coor(xy, atom0->xy, 4, gamma);
338                         return;
339                 case 1: /* squares */
340                         xy[0].x = x0 + (int) (1.5 * atom0->size_at *
341                                               cos(atom0->angle)) +
342                                 (int) (1.5 * atom0->size_at *
343                                        sin(atom0->angle));
344                         xy[0].y = y0 + (int) (1.5 * atom0->size_at *
345                                               cos(atom0->angle)) -
346                                 (int) (1.5 * atom0->size_at *
347                                        sin(atom0->angle));
348                         xy[1].x = x0 + (int) (1.5 * atom0->size_at *
349                                               cos(atom0->angle)) -
350                                 (int) (1.5 * atom0->size_at *
351                                        sin(atom0->angle));
352                         xy[1].y = y0 - (int) (1.5 * atom0->size_at *
353                                               cos(atom0->angle)) -
354                                 (int) (1.5 * atom0->size_at *
355                                        sin(atom0->angle));
356                         xy[2].x = x0 - (int) (1.5 * atom0->size_at *
357                                               cos(atom0->angle)) -
358                                 (int) (1.5 * atom0->size_at *
359                                        sin(atom0->angle));
360                         xy[2].y = y0 - (int) (1.5 * atom0->size_at *
361                                               cos(atom0->angle)) +
362                                 (int) (1.5 * atom0->size_at *
363                                        sin(atom0->angle));
364                         xy[3].x = x0 - (int) (1.5 * atom0->size_at *
365                                               cos(atom0->angle)) +
366                                 (int) (1.5 * atom0->size_at *
367                                        sin(atom0->angle));
368                         xy[3].y = y0 + (int) (1.5 * atom0->size_at *
369                                               cos(atom0->angle)) +
370                                 (int) (1.5 * atom0->size_at *
371                                        sin(atom0->angle));
372                         xy[4].x = xy[0].x;
373                         xy[4].y = xy[0].y;
374                         trans_coor(xy, atom0->xy, 4, gamma);
375                         return;
376                 case 2: /* triangles */
377                         xy[0].x = x0 + (int) (1.5 * atom0->size_at *
378                                               sin(atom0->angle));
379                         xy[0].y = y0 + (int) (1.5 * atom0->size_at *
380                                               cos(atom0->angle));
381                         xy[1].x = x0 + (int) (1.5 * atom0->size_at *
382                                               cos(atom0->angle)) -
383                                 (int) (1.5 * atom0->size_at *
384                                        sin(atom0->angle));
385                         xy[1].y = y0 - (int) (1.5 * atom0->size_at *
386                                               cos(atom0->angle)) -
387                                 (int) (1.5 * atom0->size_at *
388                                        sin(atom0->angle));
389                         xy[2].x = x0 - (int) (1.5 * atom0->size_at *
390                                               cos(atom0->angle)) -
391                                 (int) (1.5 * atom0->size_at *
392                                        sin(atom0->angle));
393                         xy[2].y = y0 - (int) (1.5 * atom0->size_at *
394                                               cos(atom0->angle)) +
395                                 (int) (1.5 * atom0->size_at *
396                                        sin(atom0->angle));
397                         xy[3].x = xy[0].x;
398                         xy[3].y = xy[0].y;
399                         trans_coor(xy, atom0->xy, 3, gamma);
400                         return;
401         }
402 }
403
404 static void
405 crystal_drawatom(ModeInfo * mi, crystalatom * atom0)
406 {
407         crystalstruct *cryst;
408         Display    *display = MI_DISPLAY(mi);
409         Window      window = MI_WINDOW(mi);
410         int         j, k, l, m;
411
412         cryst = &crystals[MI_SCREEN(mi)];
413         for (j = numops[2 * cryst->planegroup + 1];
414              j < numops[2 * cryst->planegroup]; j++) {
415                 XPoint      xy[5], new_xy[5];
416                 XPoint      xy_1[5];
417                 int         xtrans, ytrans;
418
419                 xtrans = operation[j * 6] * atom0->x0 + operation[j * 6 + 1] *
420                         atom0->y0 + (int) (operation[j * 6 + 4] * cryst->a /
421                                            2.0);
422                 ytrans = operation[j * 6 + 2] * atom0->x0 + operation[j * 6 +
423                                3] * atom0->y0 + (int) (operation[j * 6 + 5] *
424                                                        cryst->b / 2.0);
425                 if (xtrans < 0) {
426                         if (xtrans < -cryst->a)
427                                 xtrans = 2 * cryst->a;
428                         else
429                                 xtrans = cryst->a;
430                 } else if (xtrans >= cryst->a)
431                         xtrans = -cryst->a;
432                 else
433                         xtrans = 0;
434                 if (ytrans < 0)
435                         ytrans = cryst->b;
436                 else if (ytrans >= cryst->b)
437                         ytrans = -cryst->b;
438                 else
439                         ytrans = 0;
440                 for (k = 0; k < atom0->num_point; k++) {
441                         xy[k].x = operation[j * 6] * atom0->xy[k].x +
442                                 operation[j * 6 + 1] *
443                                 atom0->xy[k].y + (int) (operation[j * 6 + 4] *
444                                                         cryst->a / 2.0) +
445                                 xtrans;
446                         xy[k].y = operation[j * 6 + 2] * atom0->xy[k].x +
447                                 operation[j * 6 + 3] *
448                                 atom0->xy[k].y + (int) (operation[j * 6 + 5] *
449                                                         cryst->b / 2.0) +
450                                 ytrans;
451                 }
452                 xy[atom0->num_point].x = xy[0].x;
453                 xy[atom0->num_point].y = xy[0].y;
454                 for (l = 0; l < cryst->nx; l++) {
455                         for (m = 0; m < cryst->ny; m++) {
456
457                                 for (k = 0; k <= atom0->num_point; k++) {
458                                         xy_1[k].x = xy[k].x + l * cryst->a;
459                                         xy_1[k].y = xy[k].y + m * cryst->b;
460                                 }
461                                 trans_coor_back(xy_1, new_xy, atom0->num_point,
462                                                 cryst->gamma, cryst->offset_w,
463                                                 cryst->offset_h ,
464                                                 cryst->win_height,
465                                                 cryst->invert);
466                                 XFillPolygon(display, window, cryst->gc, new_xy,
467                                   atom0->num_point, Convex, CoordModeOrigin);
468                         }
469                 }
470                 if (centro[cryst->planegroup] == True) {
471                         for (k = 0; k <= atom0->num_point; k++) {
472                                 xy[k].x = cryst->a - xy[k].x;
473                                 xy[k].y = cryst->b - xy[k].y;
474                         }
475                         for (l = 0; l < cryst->nx; l++) {
476                                 for (m = 0; m < cryst->ny; m++) {
477
478                                         for (k = 0; k <= atom0->num_point; k++) {
479                                                 xy_1[k].x = xy[k].x + l * cryst->a;
480                                                 xy_1[k].y = xy[k].y + m * cryst->b;
481                                         }
482                                         trans_coor_back(xy_1, new_xy, atom0->num_point,
483                                                         cryst->gamma,
484                                                         cryst->offset_w,
485                                                         cryst->offset_h ,
486                                                         cryst->win_height ,
487                                                         cryst->invert);
488                                         XFillPolygon(display, window, cryst->gc,
489                                                      new_xy,
490                                                      atom0->num_point, Convex,
491                                                      CoordModeOrigin);
492                                 }
493                         }
494                 }
495                 if (primitive[cryst->planegroup] == False) {
496                         if (xy[atom0->num_point].x >= (int) (cryst->a / 2.0))
497                                 xtrans = (int) (-cryst->a / 2.0);
498                         else
499                                 xtrans = (int) (cryst->a / 2.0);
500                         if (xy[atom0->num_point].y >= (int) (cryst->b / 2.0))
501                                 ytrans = (int) (-cryst->b / 2.0);
502                         else
503                                 ytrans = (int) (cryst->b / 2.0);
504                         for (k = 0; k <= atom0->num_point; k++) {
505                                 xy[k].x = xy[k].x + xtrans;
506                                 xy[k].y = xy[k].y + ytrans;
507                         }
508                         for (l = 0; l < cryst->nx; l++) {
509                                 for (m = 0; m < cryst->ny; m++) {
510
511                                         for (k = 0; k <= atom0->num_point; k++) {
512                                                 xy_1[k].x = xy[k].x + l * cryst->a;
513                                                 xy_1[k].y = xy[k].y + m * cryst->b;
514                                         }
515                                         trans_coor_back(xy_1, new_xy, atom0->num_point,
516                                                         cryst->gamma,
517                                                         cryst->offset_w,
518                                                         cryst->offset_h ,
519                                                         cryst->win_height,
520                                                         cryst->invert);
521                                         XFillPolygon(display, window, cryst->gc,
522                                                      new_xy,
523                                                      atom0->num_point, Convex,
524                                                      CoordModeOrigin);
525                                 }
526                         }
527                         if (centro[cryst->planegroup] == True) {
528                                 XPoint      xy1[5];
529
530                                 for (k = 0; k <= atom0->num_point; k++) {
531                                         xy1[k].x = cryst->a - xy[k].x;
532                                         xy1[k].y = cryst->b - xy[k].y;
533                                 }
534                                 for (l = 0; l < cryst->nx; l++) {
535                                         for (m = 0; m < cryst->ny; m++) {
536
537                                                 for (k = 0; k <= atom0->num_point; k++) {
538                                                         xy_1[k].x = xy1[k].x + l * cryst->a;
539                                                         xy_1[k].y = xy1[k].y + m * cryst->b;
540                                                 }
541                                                 trans_coor_back(xy_1, new_xy, atom0->num_point,
542                                                                 cryst->gamma,
543                                                                 cryst->offset_w,
544                                                                 cryst->offset_h ,
545                                                                 cryst->win_height,
546                                                                 cryst->invert);
547                                                 XFillPolygon(display, window,
548                                                              cryst->gc,
549                                                     new_xy, atom0->num_point,
550                                                     Convex, CoordModeOrigin);
551                                         }
552                                 }
553                         }
554                 }
555         }
556 }
557
558 ENTRYPOINT void init_crystal(ModeInfo * mi);
559 ENTRYPOINT void release_crystal(ModeInfo * mi);
560
561
562 ENTRYPOINT void
563 draw_crystal(ModeInfo * mi)
564 {
565         Display    *display = MI_DISPLAY(mi);
566         crystalstruct *cryst = &crystals[MI_SCREEN(mi)];
567         int         i;
568
569 #ifdef HAVE_COCOA       /* Don't second-guess Quartz's double-buffering */
570     XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
571 #endif
572
573         if (cryst->no_colors) {
574                 release_crystal(mi);
575                 init_crystal(mi);
576                 return;
577         }
578         cryst->painted = True;
579         MI_IS_DRAWN(mi) = True;
580         XSetFunction(display, cryst->gc, GXxor);
581
582 /* Rotate colours */
583         if (cryst->cycle_p) {
584                 rotate_colors(display, cryst->cmap, cryst->colors, cryst->ncolors,
585                               cryst->direction);
586                 if (!(LRAND() % 1000))
587                         cryst->direction = -cryst->direction;
588         }
589         for (i = 0; i < cryst->num_atom; i++) {
590                 crystalatom *atom0;
591
592                 atom0 = &cryst->atom[i];
593
594                 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
595                         XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
596                 } else {
597                         XSetForeground(display, cryst->gc, atom0->colour);
598                 }
599                 crystal_drawatom(mi, atom0);
600                 atom0->velocity[0] += NRAND(3) - 1;
601                 atom0->velocity[0] = MAX(-20, MIN(20, atom0->velocity[0]));
602                 atom0->velocity[1] += NRAND(3) - 1;
603                 atom0->velocity[1] = MAX(-20, MIN(20, atom0->velocity[1]));
604                 atom0->x0 += atom0->velocity[0];
605                 /*if (cryst->gamma == 90.0) { */
606                 if (atom0->x0 < 0)
607                         atom0->x0 += cryst->a;
608                 else if (atom0->x0 >= cryst->a)
609                         atom0->x0 -= cryst->a;
610                 atom0->y0 += atom0->velocity[1];
611                 if (atom0->y0 < 0)
612                         atom0->y0 += cryst->b;
613                 else if (atom0->y0 >= cryst->b)
614                         atom0->y0 -= cryst->b;
615                 /*} */
616                 atom0->velocity_a += ((float) NRAND(1001) - 500.0) / 2000.0;
617                 atom0->angle += atom0->velocity_a;
618                 crystal_setupatom(atom0, cryst->gamma);
619                 crystal_drawatom(mi, atom0);
620         }
621         XSetFunction(display, cryst->gc, GXcopy);
622 }
623
624 ENTRYPOINT void
625 refresh_crystal(ModeInfo * mi)
626 {
627         Display    *display = MI_DISPLAY(mi);
628         Window      window = MI_WINDOW(mi);
629         crystalstruct *cryst = &crystals[MI_SCREEN(mi)];
630         int         i;
631
632         if (!cryst->painted)
633                 return;
634         MI_CLEARWINDOW(mi);
635         XSetFunction(display, cryst->gc, GXxor);
636
637         if (cryst->unit_cell) {
638            int y_coor1 , y_coor2;
639            
640                 if (MI_NPIXELS(mi) > 2)
641                         XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
642                 else
643                         XSetForeground(display, cryst->gc, MI_WHITE_PIXEL(mi));
644                 if (cryst->grid_cell) {
645                         int         inx, iny;
646
647                    if ( cryst->invert )
648                      y_coor1 = y_coor2 = cryst->win_height - cryst->offset_h;
649                    else
650                      y_coor1 = y_coor2 = cryst->offset_h;
651                         XDrawLine(display, window, cryst->gc, cryst->offset_w,
652                                   y_coor1, cryst->offset_w + cryst->nx * cryst->a,
653                                   y_coor2);
654                    if ( cryst->invert )
655                      {
656                         y_coor1 = cryst->win_height - cryst->offset_h;
657                         y_coor2 = cryst->win_height - (int) (cryst->ny *
658                                                              cryst->b *
659                                          cos((cryst->gamma - 90) * PI_RAD)) -
660                           cryst->offset_h;
661                      }
662                    else
663                      {
664                         y_coor1 = cryst->offset_h;
665                         y_coor2 = (int) (cryst->ny * cryst->b *
666                                          cos((cryst->gamma - 90) * PI_RAD)) +
667                           cryst->offset_h;
668                      }
669                         XDrawLine(display, window, cryst->gc, cryst->offset_w,
670                                   y_coor1, (int) (cryst->offset_w - cryst->ny * cryst->b *
671                                           sin((cryst->gamma - 90) * PI_RAD)),
672                                   y_coor2);
673                         inx = cryst->nx;
674                         for (iny = 1; iny <= cryst->ny; iny++) {
675                    if ( cryst->invert )
676                      {
677                         y_coor1 = cryst->win_height -
678                           (int) (iny * cryst->b * cos((cryst->gamma - 90) *
679                                                   PI_RAD)) - cryst->offset_h;
680                         y_coor2 = cryst->win_height -
681                           (int) (iny * cryst->b * cos((cryst->gamma - 90) *
682                                                       PI_RAD)) -
683                           cryst->offset_h;
684                      }
685                    else
686                      {
687                         y_coor1 = (int) (iny * cryst->b * cos((cryst->gamma - 90) *
688                                                   PI_RAD)) + cryst->offset_h;
689                         y_coor2 = (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
690                                           cryst->offset_h;
691                      }
692                                 XDrawLine(display, window, cryst->gc,
693                                           (int) (cryst->offset_w +
694                                      inx * cryst->a - (int) (iny * cryst->b *
695                                          sin((cryst->gamma - 90) * PI_RAD))),
696                                           y_coor1,
697                                     (int) (cryst->offset_w - iny * cryst->b *
698                                            sin((cryst->gamma - 90) * PI_RAD)),
699                                           y_coor2);
700                         }
701                         iny = cryst->ny;
702                         for (inx = 1; inx <= cryst->nx; inx++) {
703                            if ( cryst->invert )
704                              {
705                                 y_coor1 =cryst->win_height -
706                                   (int) (iny * cryst->b *
707                                                 cos((cryst->gamma - 90) *
708                                                     PI_RAD)) - cryst->offset_h;
709                                 y_coor2 =cryst->win_height - cryst->offset_h;
710                              }
711                            else
712                              {
713                                 y_coor1 =(int) (iny * cryst->b *
714                                                 cos((cryst->gamma - 90) *
715                                                     PI_RAD)) + cryst->offset_h;
716                                 y_coor2 =cryst->offset_h;
717                              }
718                                 XDrawLine(display, window, cryst->gc,
719                                           (int) (cryst->offset_w +
720                                      inx * cryst->a - (int) (iny * cryst->b *
721                                          sin((cryst->gamma - 90) * PI_RAD))),
722                                           y_coor1,
723                                           cryst->offset_w + inx * cryst->a,
724                                           y_coor2);
725                         }
726                 } else {
727                         int         inx, iny;
728
729                         inx = NRAND(cryst->nx);
730                         iny = NRAND(cryst->ny);
731                    if ( cryst->invert )
732                      {
733                         y_coor1 =cryst->win_height -
734                           (int) (iny * cryst->b *
735                                                   cos((cryst->gamma - 90) *
736                                                       PI_RAD)) -
737                           cryst->offset_h;
738                         y_coor2 =cryst->win_height -
739                           (int) ( ( iny + 1 ) * cryst->b *
740                                                   cos((cryst->gamma - 90) *
741                                                       PI_RAD)) -
742                           cryst->offset_h;
743                      }
744                    else
745                      {
746                         y_coor1 =(int) (iny * cryst->b *
747                                                   cos((cryst->gamma - 90) *
748                                                       PI_RAD)) +
749                           cryst->offset_h;
750                         y_coor2 =(int) (( iny + 1 ) * cryst->b *
751                                                   cos((cryst->gamma - 90) *
752                                                       PI_RAD)) +
753                           cryst->offset_h;
754                      }
755                         XDrawLine(display, window, cryst->gc,
756                                   cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
757                                   y_coor1,
758                                   cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
759                                   y_coor1);
760                         XDrawLine(display, window, cryst->gc,
761                                   cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
762                                   y_coor1,
763                                   cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
764                                   y_coor2);
765                         XDrawLine(display, window, cryst->gc,
766                                   cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
767                                   y_coor1,
768                                   cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
769                                   y_coor2);
770                         XDrawLine(display, window, cryst->gc,
771                                   cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
772                                   y_coor2,
773                                   cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
774                                   y_coor2);
775                 }
776         }
777         for (i = 0; i < cryst->num_atom; i++) {
778                 crystalatom *atom0;
779
780                 atom0 = &cryst->atom[i];
781                 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
782                         XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
783                 } else {
784                         XSetForeground(display, cryst->gc, atom0->colour);
785                 }
786                 crystal_drawatom(mi, atom0);
787         }
788         XSetFunction(display, cryst->gc, GXcopy);
789 }
790
791 ENTRYPOINT void
792 release_crystal(ModeInfo * mi)
793 {
794         Display    *display = MI_DISPLAY(mi);
795
796         if (crystals != NULL) {
797                 int         screen;
798
799                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
800                         crystalstruct *cryst = &crystals[screen];
801
802                         if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
803                                 MI_WHITE_PIXEL(mi) = cryst->whitepixel;
804                                 MI_BLACK_PIXEL(mi) = cryst->blackpixel;
805 #ifndef STANDALONE
806                                 MI_FG_PIXEL(mi) = cryst->fg;
807                                 MI_BG_PIXEL(mi) = cryst->bg;
808 #endif
809                                 if (cryst->colors && cryst->ncolors && !cryst->no_colors)
810                                         free_colors(display, cryst->cmap, cryst->colors, cryst->ncolors);
811                                 if (cryst->colors)
812                                         (void) free((void *) cryst->colors);
813 #if 0 /* #### wrong! -jwz */
814                                 XFreeColormap(display, cryst->cmap);
815 #endif
816                         }
817                         if (cryst->gc != NULL)
818                                 XFreeGC(display, cryst->gc);
819                         if (cryst->atom != NULL)
820                                 (void) free((void *) cryst->atom);
821                 }
822                 (void) free((void *) crystals);
823                 crystals = NULL;
824         }
825 }
826
827 ENTRYPOINT void
828 init_crystal(ModeInfo * mi)
829 {
830         Display    *display = MI_DISPLAY(mi);
831         Window      window = MI_WINDOW(mi);
832         crystalstruct *cryst;
833         int         i, max_atoms, size_atom, neqv;
834         int         cell_min;
835
836 #define MIN_CELL 200
837
838 /* initialize */
839         if (crystals == NULL) {
840                 if ((crystals = (crystalstruct *) calloc(MI_NUM_SCREENS(mi),
841                                             sizeof (crystalstruct))) == NULL)
842                         return;
843         }
844         cryst = &crystals[MI_SCREEN(mi)];
845
846         if (!cryst->gc) {
847                 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
848                         XColor      color;
849
850 #ifndef STANDALONE
851                         extern char *background;
852                         extern char *foreground;
853
854                         cryst->fg = MI_FG_PIXEL(mi);
855                         cryst->bg = MI_BG_PIXEL(mi);
856 #endif
857                         cryst->blackpixel = MI_BLACK_PIXEL(mi);
858                         cryst->whitepixel = MI_WHITE_PIXEL(mi);
859 #if 0 /* #### wrong! -jwz */
860                         cryst->cmap = XCreateColormap(display, window,
861                                                    MI_VISUAL(mi), AllocNone);
862                         XSetWindowColormap(display, window, cryst->cmap);
863 #else
864             cryst->cmap = mi->xgwa.colormap;
865 #endif
866                         (void) XParseColor(display, cryst->cmap, "black", &color);
867                         (void) XAllocColor(display, cryst->cmap, &color);
868                         MI_BLACK_PIXEL(mi) = color.pixel;
869                         (void) XParseColor(display, cryst->cmap, "white", &color);
870                         (void) XAllocColor(display, cryst->cmap, &color);
871                         MI_WHITE_PIXEL(mi) = color.pixel;
872 #ifndef STANDALONE
873                         (void) XParseColor(display, cryst->cmap, background, &color);
874                         (void) XAllocColor(display, cryst->cmap, &color);
875                         MI_BG_PIXEL(mi) = color.pixel;
876                         (void) XParseColor(display, cryst->cmap, foreground, &color);
877                         (void) XAllocColor(display, cryst->cmap, &color);
878                         MI_FG_PIXEL(mi) = color.pixel;
879 #endif
880                         cryst->colors = 0;
881                         cryst->ncolors = 0;
882                 }
883                 if ((cryst->gc = XCreateGC(display, MI_WINDOW(mi),
884                              (unsigned long) 0, (XGCValues *) NULL)) == None)
885                         return;
886         }
887 /* Clear Display */
888         MI_CLEARWINDOW(mi);
889         cryst->painted = False;
890         XSetFunction(display, cryst->gc, GXxor);
891
892
893 /*Set up crystal data */
894         cryst->direction = (LRAND() & 1) ? 1 : -1;
895         if (MI_IS_FULLRANDOM(mi)) {
896                 if (LRAND() & 1)
897                         cryst->unit_cell = True;
898                 else
899                         cryst->unit_cell = False;
900         } else
901                 cryst->unit_cell = unit_cell;
902         if (cryst->unit_cell) {
903                 if (MI_IS_FULLRANDOM(mi)) {
904                         if (LRAND() & 1)
905                                 cryst->grid_cell = True;
906                         else
907                                 cryst->grid_cell = False;
908                 } else
909                         cryst->grid_cell = grid_cell;
910         }
911         cryst->win_width = MI_WIDTH(mi);
912         cryst->win_height = MI_HEIGHT(mi);
913         cell_min = min(cryst->win_width / 2 + 1, MIN_CELL);
914         cell_min = min(cell_min, cryst->win_height / 2 + 1);
915         cryst->planegroup = NRAND(17);
916         cryst->invert = NRAND(2);
917         if (MI_IS_VERBOSE(mi))
918                 (void) fprintf(stdout, "Selected plane group no %d\n",
919                                cryst->planegroup + 1);
920         if (cryst->planegroup > 11)
921                 cryst->gamma = 120.0;
922         else if (cryst->planegroup < 2)
923                 cryst->gamma = 60.0 + NRAND(60);
924         else
925                 cryst->gamma = 90.0;
926         neqv = numops[2 * cryst->planegroup] - numops[2 * cryst->planegroup + 1];
927         if (centro[cryst->planegroup] == True)
928                 neqv = 2 * neqv;
929         if (primitive[cryst->planegroup] == False)
930                 neqv = 2 * neqv;
931
932
933         if (nx > 0)
934                 cryst->nx = nx;
935         else if (nx < 0)
936                 cryst->nx = NRAND(-nx) + 1;
937         else
938                 cryst->nx = DEF_NX1;
939         if (cryst->planegroup > 8)
940                 cryst->ny = cryst->nx;
941         else if (ny > 0)
942                 cryst->ny = ny;
943         else if (ny < 0)
944                 cryst->ny = NRAND(-ny) + 1;
945         else
946                 cryst->ny = DEF_NY1;
947         neqv = neqv * cryst->nx * cryst->ny;
948
949         cryst->num_atom = MI_COUNT(mi);
950         max_atoms = MI_COUNT(mi);
951         if (cryst->num_atom == 0) {
952                 cryst->num_atom = DEF_NUM_ATOM;
953                 max_atoms = DEF_NUM_ATOM;
954         } else if (cryst->num_atom < 0) {
955                 max_atoms = -cryst->num_atom;
956                 cryst->num_atom = NRAND(-cryst->num_atom) + 1;
957         }
958         if (neqv > 1)
959                 cryst->num_atom = cryst->num_atom / neqv + 1;
960
961         if (cryst->atom == NULL)
962                 cryst->atom = (crystalatom *) calloc(max_atoms, sizeof (
963                                                                crystalatom));
964
965         if (maxsize) {
966                 if (cryst->planegroup < 13) {
967                         cryst->gamma = 90.0;
968                         cryst->offset_w = 0;
969                         cryst->offset_h = 0;
970                         if (cryst->planegroup < 10) {
971                                 cryst->b = cryst->win_height;
972                                 cryst->a = cryst->win_width;
973                         } else {
974                                 cryst->b = min(cryst->win_height, cryst->win_width);
975                                 cryst->a = cryst->b;
976                         }
977                 } else {
978                         cryst->gamma = 120.0;
979                         cryst->a = (int) (cryst->win_width * 2.0 / 3.0);
980                         cryst->b = cryst->a;
981                         cryst->offset_h = (int) (cryst->b * 0.25 *
982                                           cos((cryst->gamma - 90) * PI_RAD));
983                         cryst->offset_w = (int) (cryst->b * 0.5);
984                 }
985         } else {
986                 int max_repeat = 10;
987                 cryst->offset_w = -1;
988                 while (max_repeat-- && 
989                   (cryst->offset_w < 4 || (int) (cryst->offset_w - cryst->b *
990                                     sin((cryst->gamma - 90) * PI_RAD)) < 4)
991                            ) {
992                         cryst->b = NRAND((int) (cryst->win_height / (cos((cryst->gamma - 90) *
993                                             PI_RAD))) - cell_min) + cell_min;
994                         if (cryst->planegroup > 8)
995                                 cryst->a = cryst->b;
996                         else
997                                 cryst->a = NRAND(cryst->win_width - cell_min) + cell_min;
998                         cryst->offset_w = (int) ((cryst->win_width - (cryst->a - cryst->b *
999                                                     sin((cryst->gamma - 90) *
1000                                                         PI_RAD))) / 2.0);
1001                 }
1002                 cryst->offset_h = (int) ((cryst->win_height - cryst->b * cos((
1003                                         cryst->gamma - 90) * PI_RAD)) / 2.0);
1004                 if (!centre) {
1005                         if (cryst->offset_h > 0)
1006                                 cryst->offset_h = NRAND(2 * cryst->offset_h);
1007                         cryst->offset_w = (int) (cryst->win_width - cryst->a -
1008                                                  cryst->b *
1009                                     fabs(sin((cryst->gamma - 90) * PI_RAD)));
1010                         if (cryst->gamma > 90.0) {
1011                                 if (cryst->offset_w > 0)
1012                                         cryst->offset_w = NRAND(cryst->offset_w) +
1013                                                 (int) (cryst->b * sin((cryst->gamma - 90) * PI_RAD));
1014                                 else
1015                                         cryst->offset_w = (int) (cryst->b * sin((cryst->gamma - 90) *
1016                                                                     PI_RAD));
1017                         } else if (cryst->offset_w > 0)
1018                                 cryst->offset_w = NRAND(cryst->offset_w);
1019                         else
1020                                 cryst->offset_w = 0;
1021                 }
1022         }
1023
1024         size_atom = min((int) ((float) (cryst->a) / 40.) + 1,
1025                         (int) ((float) (cryst->b) / 40.) + 1);
1026         if (MI_SIZE(mi) < size_atom) {
1027                 if (MI_SIZE(mi) < -size_atom)
1028                         size_atom = -size_atom;
1029                 else
1030                         size_atom = MI_SIZE(mi);
1031         }
1032         cryst->a = cryst->a / cryst->nx;
1033         cryst->b = cryst->b / cryst->ny;
1034         if (cryst->unit_cell) {
1035            int y_coor1 , y_coor2;
1036            
1037                 if (MI_NPIXELS(mi) > 2)
1038                         XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
1039                 else
1040                         XSetForeground(display, cryst->gc, MI_WHITE_PIXEL(mi));
1041                 if (cryst->grid_cell) {
1042                         int         inx, iny;
1043
1044                    if ( cryst->invert )
1045                      y_coor1 = y_coor2 = cryst->win_height - cryst->offset_h;
1046                    else
1047                      y_coor1 = y_coor2 = cryst->offset_h;
1048                         XDrawLine(display, window, cryst->gc, cryst->offset_w,
1049                                   y_coor1, cryst->offset_w + cryst->nx * cryst->a,
1050                                   y_coor2);
1051                    if ( cryst->invert )
1052                      {
1053                         y_coor1 = cryst->win_height - cryst->offset_h;
1054                         y_coor2 = cryst->win_height - (int) (cryst->ny *
1055                                                              cryst->b *
1056                                          cos((cryst->gamma - 90) * PI_RAD)) -
1057                           cryst->offset_h;
1058                      }
1059                    else
1060                      {
1061                         y_coor1 = cryst->offset_h;
1062                         y_coor2 = (int) (cryst->ny * cryst->b *
1063                                          cos((cryst->gamma - 90) * PI_RAD)) +
1064                           cryst->offset_h;
1065                      }
1066                         XDrawLine(display, window, cryst->gc, cryst->offset_w,
1067                                   y_coor1, (int) (cryst->offset_w - cryst->ny * cryst->b *
1068                                           sin((cryst->gamma - 90) * PI_RAD)),
1069                                   y_coor2);
1070                         inx = cryst->nx;
1071                         for (iny = 1; iny <= cryst->ny; iny++) {
1072                    if ( cryst->invert )
1073                      {
1074                         y_coor1 = cryst->win_height -
1075                           (int) (iny * cryst->b * cos((cryst->gamma - 90) *
1076                                                   PI_RAD)) - cryst->offset_h;
1077                         y_coor2 = cryst->win_height -
1078                           (int) (iny * cryst->b * cos((cryst->gamma - 90) *
1079                                                       PI_RAD)) -
1080                           cryst->offset_h;
1081                      }
1082                    else
1083                      {
1084                         y_coor1 = (int) (iny * cryst->b * cos((cryst->gamma - 90) *
1085                                                   PI_RAD)) + cryst->offset_h;
1086                         y_coor2 = (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
1087                                           cryst->offset_h;
1088                      }
1089                                 XDrawLine(display, window, cryst->gc,
1090                                           (int) (cryst->offset_w +
1091                                      inx * cryst->a - (int) (iny * cryst->b *
1092                                          sin((cryst->gamma - 90) * PI_RAD))),
1093                                           y_coor1,
1094                                     (int) (cryst->offset_w - iny * cryst->b *
1095                                            sin((cryst->gamma - 90) * PI_RAD)),
1096                                           y_coor2);
1097                         }
1098                         iny = cryst->ny;
1099                         for (inx = 1; inx <= cryst->nx; inx++) {
1100                            if ( cryst->invert )
1101                              {
1102                                 y_coor1 =cryst->win_height -
1103                                   (int) (iny * cryst->b *
1104                                                 cos((cryst->gamma - 90) *
1105                                                     PI_RAD)) - cryst->offset_h;
1106                                 y_coor2 =cryst->win_height - cryst->offset_h;
1107                              }
1108                            else
1109                              {
1110                                 y_coor1 =(int) (iny * cryst->b *
1111                                                 cos((cryst->gamma - 90) *
1112                                                     PI_RAD)) + cryst->offset_h;
1113                                 y_coor2 =cryst->offset_h;
1114                              }
1115                                 XDrawLine(display, window, cryst->gc,
1116                                           (int) (cryst->offset_w +
1117                                      inx * cryst->a - (int) (iny * cryst->b *
1118                                          sin((cryst->gamma - 90) * PI_RAD))),
1119                                           y_coor1,
1120                                           cryst->offset_w + inx * cryst->a,
1121                                           y_coor2);
1122                         }
1123                 } else {
1124                         int         inx, iny;
1125
1126                         inx = NRAND(cryst->nx);
1127                         iny = NRAND(cryst->ny);
1128                    if ( cryst->invert )
1129                      {
1130                         y_coor1 =cryst->win_height -
1131                           (int) (iny * cryst->b *
1132                                                   cos((cryst->gamma - 90) *
1133                                                       PI_RAD)) -
1134                           cryst->offset_h;
1135                         y_coor2 =cryst->win_height -
1136                           (int) ( ( iny + 1 ) * cryst->b *
1137                                                   cos((cryst->gamma - 90) *
1138                                                       PI_RAD)) -
1139                           cryst->offset_h;
1140                      }
1141                    else
1142                      {
1143                         y_coor1 =(int) (iny * cryst->b *
1144                                                   cos((cryst->gamma - 90) *
1145                                                       PI_RAD)) +
1146                           cryst->offset_h;
1147                         y_coor2 =(int) (( iny + 1 ) * cryst->b *
1148                                                   cos((cryst->gamma - 90) *
1149                                                       PI_RAD)) +
1150                           cryst->offset_h;
1151                      }
1152                         XDrawLine(display, window, cryst->gc,
1153                                   cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1154                                   y_coor1,
1155                                   cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1156                                   y_coor1);
1157                         XDrawLine(display, window, cryst->gc,
1158                                   cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1159                                   y_coor1,
1160                                   cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1161                                   y_coor2);
1162                         XDrawLine(display, window, cryst->gc,
1163                                   cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1164                                   y_coor1,
1165                                   cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1166                                   y_coor2);
1167                         XDrawLine(display, window, cryst->gc,
1168                                   cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1169                                   y_coor2,
1170                                   cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1171                                   y_coor2);
1172                 }
1173         }
1174         if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
1175 /* Set up colour map */
1176                 if (cryst->colors && cryst->ncolors && !cryst->no_colors)
1177                         free_colors(display, cryst->cmap, cryst->colors, cryst->ncolors);
1178                 if (cryst->colors)
1179                         (void) free((void *) cryst->colors);
1180                 cryst->colors = 0;
1181                 cryst->ncolors = MI_NCOLORS(mi);
1182                 if (cryst->ncolors < 2)
1183                         cryst->ncolors = 2;
1184                 if (cryst->ncolors <= 2)
1185                         cryst->mono_p = True;
1186                 else
1187                         cryst->mono_p = False;
1188
1189                 if (cryst->mono_p)
1190                         cryst->colors = 0;
1191                 else
1192                         cryst->colors = (XColor *) malloc(sizeof (*cryst->colors) * (cryst->ncolors + 1));
1193                 cryst->cycle_p = has_writable_cells(mi->xgwa.screen, MI_VISUAL(mi));
1194                 if (cryst->cycle_p) {
1195                         if (MI_IS_FULLRANDOM(mi)) {
1196                                 if (!NRAND(8))
1197                                         cryst->cycle_p = False;
1198                                 else
1199                                         cryst->cycle_p = True;
1200                         } else {
1201                                 cryst->cycle_p = cycle_p;
1202                         }
1203                 }
1204                 if (!cryst->mono_p) {
1205                         if (!(LRAND() % 10))
1206                                 make_random_colormap(MI_DISPLAY(mi), MI_VISUAL(mi), cryst->cmap, cryst->colors, &cryst->ncolors,
1207                                                 True, True, &cryst->cycle_p, True);
1208                         else if (!(LRAND() % 2))
1209                                 make_uniform_colormap(MI_DISPLAY(mi), MI_VISUAL(mi), cryst->cmap, cryst->colors, &cryst->ncolors,
1210                                                       True, &cryst->cycle_p, True);
1211                         else
1212                                 make_smooth_colormap(MI_DISPLAY(mi), MI_VISUAL(mi), cryst->cmap, cryst->colors, &cryst->ncolors,
1213                                                      True, &cryst->cycle_p, True);
1214                 }
1215 #if 0 /* #### wrong! -jwz */
1216                 XInstallColormap(display, cryst->cmap);
1217 #endif
1218                 if (cryst->ncolors < 2) {
1219                         cryst->ncolors = 2;
1220                         cryst->no_colors = True;
1221                 } else
1222                         cryst->no_colors = False;
1223                 if (cryst->ncolors <= 2)
1224                         cryst->mono_p = True;
1225
1226                 if (cryst->mono_p)
1227                         cryst->cycle_p = False;
1228
1229         }
1230         for (i = 0; i < cryst->num_atom; i++) {
1231                 crystalatom *atom0;
1232
1233                 atom0 = &cryst->atom[i];
1234                 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
1235                         if (cryst->ncolors > 2)
1236                                 atom0->colour = NRAND(cryst->ncolors - 2) + 2;
1237                         else
1238                                 atom0->colour = 1;      /* Just in case */
1239                         XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
1240                 } else {
1241                         if (MI_NPIXELS(mi) > 2)
1242                                 atom0->colour = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
1243                         else
1244                                 atom0->colour = 1;      /*Xor'red so WHITE may not be appropriate */
1245                         XSetForeground(display, cryst->gc, atom0->colour);
1246                 }
1247                 atom0->x0 = NRAND(cryst->a);
1248                 atom0->y0 = NRAND(cryst->b);
1249                 atom0->velocity[0] = NRAND(7) - 3;
1250                 atom0->velocity[1] = NRAND(7) - 3;
1251                 atom0->velocity_a = (NRAND(7) - 3) * PI_RAD;
1252                 atom0->angle = NRAND(90) * PI_RAD;
1253                 atom0->at_type = NRAND(3);
1254                 if (size_atom == 0)
1255                         atom0->size_at = DEF_SIZ_ATOM;
1256                 else if (size_atom > 0)
1257                         atom0->size_at = size_atom;
1258                 else
1259                         atom0->size_at = NRAND(-size_atom) + 1;
1260                 atom0->size_at++;
1261                 if (atom0->at_type == 2)
1262                         atom0->num_point = 3;
1263                 else
1264                         atom0->num_point = 4;
1265                 crystal_setupatom(atom0, cryst->gamma);
1266                 crystal_drawatom(mi, atom0);
1267         }
1268         XSetFunction(display, cryst->gc, GXcopy);
1269 }
1270
1271 XSCREENSAVER_MODULE ("Crystal", crystal)