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