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