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