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