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