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