From http://www.jwz.org/xscreensaver/xscreensaver-5.22.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 crystal_handle_event 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", "release_crystal",
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 ENTRYPOINT void release_crystal(ModeInfo * mi);
562
563
564 ENTRYPOINT void
565 draw_crystal(ModeInfo * mi)
566 {
567         Display    *display = MI_DISPLAY(mi);
568         crystalstruct *cryst = &crystals[MI_SCREEN(mi)];
569         int         i;
570
571 #ifdef HAVE_COCOA       /* Don't second-guess Quartz's double-buffering */
572     XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
573 #endif
574
575         if (cryst->no_colors) {
576                 release_crystal(mi);
577                 init_crystal(mi);
578                 return;
579         }
580         cryst->painted = True;
581         MI_IS_DRAWN(mi) = True;
582         XSetFunction(display, cryst->gc, GXxor);
583
584 /* Rotate colours */
585         if (cryst->cycle_p) {
586                 rotate_colors(mi->xgwa.screen, cryst->cmap,
587                       cryst->colors, cryst->ncolors,
588                               cryst->direction);
589                 if (!(LRAND() % 1000))
590                         cryst->direction = -cryst->direction;
591         }
592         for (i = 0; i < cryst->num_atom; i++) {
593                 crystalatom *atom0;
594
595                 atom0 = &cryst->atom[i];
596
597                 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
598                         XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
599                 } else {
600                         XSetForeground(display, cryst->gc, atom0->colour);
601                 }
602                 crystal_drawatom(mi, atom0);
603                 atom0->velocity[0] += NRAND(3) - 1;
604                 atom0->velocity[0] = MAX(-20, MIN(20, atom0->velocity[0]));
605                 atom0->velocity[1] += NRAND(3) - 1;
606                 atom0->velocity[1] = MAX(-20, MIN(20, atom0->velocity[1]));
607                 atom0->x0 += atom0->velocity[0];
608                 /*if (cryst->gamma == 90.0) { */
609                 if (atom0->x0 < 0)
610                         atom0->x0 += cryst->a;
611                 else if (atom0->x0 >= cryst->a)
612                         atom0->x0 -= cryst->a;
613                 atom0->y0 += atom0->velocity[1];
614                 if (atom0->y0 < 0)
615                         atom0->y0 += cryst->b;
616                 else if (atom0->y0 >= cryst->b)
617                         atom0->y0 -= cryst->b;
618                 /*} */
619                 atom0->velocity_a += ((float) NRAND(1001) - 500.0) / 2000.0;
620                 atom0->angle += atom0->velocity_a;
621                 crystal_setupatom(atom0, cryst->gamma);
622                 crystal_drawatom(mi, atom0);
623         }
624         XSetFunction(display, cryst->gc, GXcopy);
625 }
626
627 ENTRYPOINT void
628 refresh_crystal(ModeInfo * mi)
629 {
630         Display    *display = MI_DISPLAY(mi);
631         Window      window = MI_WINDOW(mi);
632         crystalstruct *cryst = &crystals[MI_SCREEN(mi)];
633         int         i;
634
635         if (!cryst->painted)
636                 return;
637         MI_CLEARWINDOW(mi);
638         XSetFunction(display, cryst->gc, GXxor);
639
640         if (cryst->unit_cell) {
641            int y_coor1 , y_coor2;
642            
643                 if (MI_NPIXELS(mi) > 2)
644                         XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
645                 else
646                         XSetForeground(display, cryst->gc, MI_WHITE_PIXEL(mi));
647                 if (cryst->grid_cell) {
648                         int         inx, iny;
649
650                    if ( cryst->invert )
651                      y_coor1 = y_coor2 = cryst->win_height - cryst->offset_h;
652                    else
653                      y_coor1 = y_coor2 = cryst->offset_h;
654                         XDrawLine(display, window, cryst->gc, cryst->offset_w,
655                                   y_coor1, cryst->offset_w + cryst->nx * cryst->a,
656                                   y_coor2);
657                    if ( cryst->invert )
658                      {
659                         y_coor1 = cryst->win_height - cryst->offset_h;
660                         y_coor2 = cryst->win_height - (int) (cryst->ny *
661                                                              cryst->b *
662                                          cos((cryst->gamma - 90) * PI_RAD)) -
663                           cryst->offset_h;
664                      }
665                    else
666                      {
667                         y_coor1 = cryst->offset_h;
668                         y_coor2 = (int) (cryst->ny * cryst->b *
669                                          cos((cryst->gamma - 90) * PI_RAD)) +
670                           cryst->offset_h;
671                      }
672                         XDrawLine(display, window, cryst->gc, cryst->offset_w,
673                                   y_coor1, (int) (cryst->offset_w - cryst->ny * cryst->b *
674                                           sin((cryst->gamma - 90) * PI_RAD)),
675                                   y_coor2);
676                         inx = cryst->nx;
677                         for (iny = 1; iny <= cryst->ny; iny++) {
678                    if ( cryst->invert )
679                      {
680                         y_coor1 = cryst->win_height -
681                           (int) (iny * cryst->b * cos((cryst->gamma - 90) *
682                                                   PI_RAD)) - cryst->offset_h;
683                         y_coor2 = cryst->win_height -
684                           (int) (iny * cryst->b * cos((cryst->gamma - 90) *
685                                                       PI_RAD)) -
686                           cryst->offset_h;
687                      }
688                    else
689                      {
690                         y_coor1 = (int) (iny * cryst->b * cos((cryst->gamma - 90) *
691                                                   PI_RAD)) + cryst->offset_h;
692                         y_coor2 = (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
693                                           cryst->offset_h;
694                      }
695                                 XDrawLine(display, window, cryst->gc,
696                                           (int) (cryst->offset_w +
697                                      inx * cryst->a - (int) (iny * cryst->b *
698                                          sin((cryst->gamma - 90) * PI_RAD))),
699                                           y_coor1,
700                                     (int) (cryst->offset_w - iny * cryst->b *
701                                            sin((cryst->gamma - 90) * PI_RAD)),
702                                           y_coor2);
703                         }
704                         iny = cryst->ny;
705                         for (inx = 1; inx <= cryst->nx; inx++) {
706                            if ( cryst->invert )
707                              {
708                                 y_coor1 =cryst->win_height -
709                                   (int) (iny * cryst->b *
710                                                 cos((cryst->gamma - 90) *
711                                                     PI_RAD)) - cryst->offset_h;
712                                 y_coor2 =cryst->win_height - cryst->offset_h;
713                              }
714                            else
715                              {
716                                 y_coor1 =(int) (iny * cryst->b *
717                                                 cos((cryst->gamma - 90) *
718                                                     PI_RAD)) + cryst->offset_h;
719                                 y_coor2 =cryst->offset_h;
720                              }
721                                 XDrawLine(display, window, cryst->gc,
722                                           (int) (cryst->offset_w +
723                                      inx * cryst->a - (int) (iny * cryst->b *
724                                          sin((cryst->gamma - 90) * PI_RAD))),
725                                           y_coor1,
726                                           cryst->offset_w + inx * cryst->a,
727                                           y_coor2);
728                         }
729                 } else {
730                         int         inx, iny;
731
732                         inx = NRAND(cryst->nx);
733                         iny = NRAND(cryst->ny);
734                    if ( cryst->invert )
735                      {
736                         y_coor1 =cryst->win_height -
737                           (int) (iny * cryst->b *
738                                                   cos((cryst->gamma - 90) *
739                                                       PI_RAD)) -
740                           cryst->offset_h;
741                         y_coor2 =cryst->win_height -
742                           (int) ( ( iny + 1 ) * cryst->b *
743                                                   cos((cryst->gamma - 90) *
744                                                       PI_RAD)) -
745                           cryst->offset_h;
746                      }
747                    else
748                      {
749                         y_coor1 =(int) (iny * cryst->b *
750                                                   cos((cryst->gamma - 90) *
751                                                       PI_RAD)) +
752                           cryst->offset_h;
753                         y_coor2 =(int) (( iny + 1 ) * cryst->b *
754                                                   cos((cryst->gamma - 90) *
755                                                       PI_RAD)) +
756                           cryst->offset_h;
757                      }
758                         XDrawLine(display, window, cryst->gc,
759                                   cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
760                                   y_coor1,
761                                   cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
762                                   y_coor1);
763                         XDrawLine(display, window, cryst->gc,
764                                   cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
765                                   y_coor1,
766                                   cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
767                                   y_coor2);
768                         XDrawLine(display, window, cryst->gc,
769                                   cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
770                                   y_coor1,
771                                   cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
772                                   y_coor2);
773                         XDrawLine(display, window, cryst->gc,
774                                   cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
775                                   y_coor2,
776                                   cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
777                                   y_coor2);
778                 }
779         }
780         for (i = 0; i < cryst->num_atom; i++) {
781                 crystalatom *atom0;
782
783                 atom0 = &cryst->atom[i];
784                 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
785                         XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
786                 } else {
787                         XSetForeground(display, cryst->gc, atom0->colour);
788                 }
789                 crystal_drawatom(mi, atom0);
790         }
791         XSetFunction(display, cryst->gc, GXcopy);
792 }
793
794 ENTRYPOINT void
795 release_crystal(ModeInfo * mi)
796 {
797         Display    *display = MI_DISPLAY(mi);
798
799         if (crystals != NULL) {
800                 int         screen;
801
802                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
803                         crystalstruct *cryst = &crystals[screen];
804
805                         if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
806                                 MI_WHITE_PIXEL(mi) = cryst->whitepixel;
807                                 MI_BLACK_PIXEL(mi) = cryst->blackpixel;
808 #ifndef STANDALONE
809                                 MI_FG_PIXEL(mi) = cryst->fg;
810                                 MI_BG_PIXEL(mi) = cryst->bg;
811 #endif
812                                 if (cryst->colors && cryst->ncolors && !cryst->no_colors)
813                                         free_colors(mi->xgwa.screen, cryst->cmap, cryst->colors,
814                                 cryst->ncolors);
815                                 if (cryst->colors)
816                                         (void) free((void *) cryst->colors);
817 #if 0 /* #### wrong! -jwz */
818                                 XFreeColormap(display, cryst->cmap);
819 #endif
820                         }
821                         if (cryst->gc != NULL)
822                                 XFreeGC(display, cryst->gc);
823                         if (cryst->atom != NULL)
824                                 (void) free((void *) cryst->atom);
825                 }
826                 (void) free((void *) crystals);
827                 crystals = NULL;
828         }
829 }
830
831 ENTRYPOINT void
832 init_crystal(ModeInfo * mi)
833 {
834         Display    *display = MI_DISPLAY(mi);
835         Window      window = MI_WINDOW(mi);
836         crystalstruct *cryst;
837         int         i, max_atoms, size_atom, neqv;
838         int         cell_min;
839
840 #define MIN_CELL 200
841
842 /* initialize */
843         if (crystals == NULL) {
844                 if ((crystals = (crystalstruct *) calloc(MI_NUM_SCREENS(mi),
845                                             sizeof (crystalstruct))) == NULL)
846                         return;
847         }
848         cryst = &crystals[MI_SCREEN(mi)];
849
850         if (!cryst->gc) {
851                 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
852                         XColor      color;
853
854 #ifndef STANDALONE
855                         extern char *background;
856                         extern char *foreground;
857
858                         cryst->fg = MI_FG_PIXEL(mi);
859                         cryst->bg = MI_BG_PIXEL(mi);
860 #endif
861                         cryst->blackpixel = MI_BLACK_PIXEL(mi);
862                         cryst->whitepixel = MI_WHITE_PIXEL(mi);
863 #if 0 /* #### wrong! -jwz */
864                         cryst->cmap = XCreateColormap(display, window,
865                                                    MI_VISUAL(mi), AllocNone);
866                         XSetWindowColormap(display, window, cryst->cmap);
867 #else
868             cryst->cmap = mi->xgwa.colormap;
869 #endif
870                         (void) XParseColor(display, cryst->cmap, "black", &color);
871                         (void) XAllocColor(display, cryst->cmap, &color);
872                         MI_BLACK_PIXEL(mi) = color.pixel;
873                         (void) XParseColor(display, cryst->cmap, "white", &color);
874                         (void) XAllocColor(display, cryst->cmap, &color);
875                         MI_WHITE_PIXEL(mi) = color.pixel;
876 #ifndef STANDALONE
877                         (void) XParseColor(display, cryst->cmap, background, &color);
878                         (void) XAllocColor(display, cryst->cmap, &color);
879                         MI_BG_PIXEL(mi) = color.pixel;
880                         (void) XParseColor(display, cryst->cmap, foreground, &color);
881                         (void) XAllocColor(display, cryst->cmap, &color);
882                         MI_FG_PIXEL(mi) = color.pixel;
883 #endif
884                         cryst->colors = 0;
885                         cryst->ncolors = 0;
886                 }
887                 if ((cryst->gc = XCreateGC(display, MI_WINDOW(mi),
888                              (unsigned long) 0, (XGCValues *) NULL)) == None)
889                         return;
890         }
891 /* Clear Display */
892         MI_CLEARWINDOW(mi);
893         cryst->painted = False;
894         XSetFunction(display, cryst->gc, GXxor);
895
896
897 /*Set up crystal data */
898         cryst->direction = (LRAND() & 1) ? 1 : -1;
899         if (MI_IS_FULLRANDOM(mi)) {
900                 if (LRAND() & 1)
901                         cryst->unit_cell = True;
902                 else
903                         cryst->unit_cell = False;
904         } else
905                 cryst->unit_cell = unit_cell;
906         if (cryst->unit_cell) {
907                 if (MI_IS_FULLRANDOM(mi)) {
908                         if (LRAND() & 1)
909                                 cryst->grid_cell = True;
910                         else
911                                 cryst->grid_cell = False;
912                 } else
913                         cryst->grid_cell = grid_cell;
914         }
915         cryst->win_width = MI_WIDTH(mi);
916         cryst->win_height = MI_HEIGHT(mi);
917         cell_min = min(cryst->win_width / 2 + 1, MIN_CELL);
918         cell_min = min(cell_min, cryst->win_height / 2 + 1);
919         cryst->planegroup = NRAND(17);
920         cryst->invert = NRAND(2);
921         if (MI_IS_VERBOSE(mi))
922                 (void) fprintf(stdout, "Selected plane group no %d\n",
923                                cryst->planegroup + 1);
924         if (cryst->planegroup > 11)
925                 cryst->gamma = 120.0;
926         else if (cryst->planegroup < 2)
927                 cryst->gamma = 60.0 + NRAND(60);
928         else
929                 cryst->gamma = 90.0;
930         neqv = numops[2 * cryst->planegroup] - numops[2 * cryst->planegroup + 1];
931         if (centro[cryst->planegroup] == True)
932                 neqv = 2 * neqv;
933         if (primitive[cryst->planegroup] == False)
934                 neqv = 2 * neqv;
935
936
937         if (nx > 0)
938                 cryst->nx = nx;
939         else if (nx < 0)
940                 cryst->nx = NRAND(-nx) + 1;
941         else
942                 cryst->nx = DEF_NX1;
943         if (cryst->planegroup > 8)
944                 cryst->ny = cryst->nx;
945         else if (ny > 0)
946                 cryst->ny = ny;
947         else if (ny < 0)
948                 cryst->ny = NRAND(-ny) + 1;
949         else
950                 cryst->ny = DEF_NY1;
951         neqv = neqv * cryst->nx * cryst->ny;
952
953         cryst->num_atom = MI_COUNT(mi);
954         max_atoms = MI_COUNT(mi);
955         if (cryst->num_atom == 0) {
956                 cryst->num_atom = DEF_NUM_ATOM;
957                 max_atoms = DEF_NUM_ATOM;
958         } else if (cryst->num_atom < 0) {
959                 max_atoms = -cryst->num_atom;
960                 cryst->num_atom = NRAND(-cryst->num_atom) + 1;
961         }
962         if (neqv > 1)
963                 cryst->num_atom = cryst->num_atom / neqv + 1;
964
965         if (cryst->atom == NULL)
966                 cryst->atom = (crystalatom *) calloc(max_atoms, sizeof (
967                                                                crystalatom));
968
969         if (maxsize) {
970                 if (cryst->planegroup < 13) {
971                         cryst->gamma = 90.0;
972                         cryst->offset_w = 0;
973                         cryst->offset_h = 0;
974                         if (cryst->planegroup < 10) {
975                                 cryst->b = cryst->win_height;
976                                 cryst->a = cryst->win_width;
977                         } else {
978                                 cryst->b = min(cryst->win_height, cryst->win_width);
979                                 cryst->a = cryst->b;
980                         }
981                 } else {
982                         cryst->gamma = 120.0;
983                         cryst->a = (int) (cryst->win_width * 2.0 / 3.0);
984                         cryst->b = cryst->a;
985                         cryst->offset_h = (int) (cryst->b * 0.25 *
986                                           cos((cryst->gamma - 90) * PI_RAD));
987                         cryst->offset_w = (int) (cryst->b * 0.5);
988                 }
989         } else {
990                 int max_repeat = 10;
991                 cryst->offset_w = -1;
992                 while (max_repeat-- && 
993                   (cryst->offset_w < 4 || (int) (cryst->offset_w - cryst->b *
994                                     sin((cryst->gamma - 90) * PI_RAD)) < 4)
995                            ) {
996                         cryst->b = NRAND((int) (cryst->win_height / (cos((cryst->gamma - 90) *
997                                             PI_RAD))) - cell_min) + cell_min;
998                         if (cryst->planegroup > 8)
999                                 cryst->a = cryst->b;
1000                         else
1001                                 cryst->a = NRAND(cryst->win_width - cell_min) + cell_min;
1002                         cryst->offset_w = (int) ((cryst->win_width - (cryst->a - cryst->b *
1003                                                     sin((cryst->gamma - 90) *
1004                                                         PI_RAD))) / 2.0);
1005                 }
1006                 cryst->offset_h = (int) ((cryst->win_height - cryst->b * cos((
1007                                         cryst->gamma - 90) * PI_RAD)) / 2.0);
1008                 if (!centre) {
1009                         if (cryst->offset_h > 0)
1010                                 cryst->offset_h = NRAND(2 * cryst->offset_h);
1011                         cryst->offset_w = (int) (cryst->win_width - cryst->a -
1012                                                  cryst->b *
1013                                     fabs(sin((cryst->gamma - 90) * PI_RAD)));
1014                         if (cryst->gamma > 90.0) {
1015                                 if (cryst->offset_w > 0)
1016                                         cryst->offset_w = NRAND(cryst->offset_w) +
1017                                                 (int) (cryst->b * sin((cryst->gamma - 90) * PI_RAD));
1018                                 else
1019                                         cryst->offset_w = (int) (cryst->b * sin((cryst->gamma - 90) *
1020                                                                     PI_RAD));
1021                         } else if (cryst->offset_w > 0)
1022                                 cryst->offset_w = NRAND(cryst->offset_w);
1023                         else
1024                                 cryst->offset_w = 0;
1025                 }
1026         }
1027
1028         size_atom = min((int) ((float) (cryst->a) / 40.) + 1,
1029                         (int) ((float) (cryst->b) / 40.) + 1);
1030         if (MI_SIZE(mi) < size_atom) {
1031                 if (MI_SIZE(mi) < -size_atom)
1032                         size_atom = -size_atom;
1033                 else
1034                         size_atom = MI_SIZE(mi);
1035         }
1036         cryst->a = cryst->a / cryst->nx;
1037         cryst->b = cryst->b / cryst->ny;
1038         if (cryst->unit_cell) {
1039            int y_coor1 , y_coor2;
1040            
1041                 if (MI_NPIXELS(mi) > 2)
1042                         XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
1043                 else
1044                         XSetForeground(display, cryst->gc, MI_WHITE_PIXEL(mi));
1045                 if (cryst->grid_cell) {
1046                         int         inx, iny;
1047
1048                    if ( cryst->invert )
1049                      y_coor1 = y_coor2 = cryst->win_height - cryst->offset_h;
1050                    else
1051                      y_coor1 = y_coor2 = cryst->offset_h;
1052                         XDrawLine(display, window, cryst->gc, cryst->offset_w,
1053                                   y_coor1, cryst->offset_w + cryst->nx * cryst->a,
1054                                   y_coor2);
1055                    if ( cryst->invert )
1056                      {
1057                         y_coor1 = cryst->win_height - cryst->offset_h;
1058                         y_coor2 = cryst->win_height - (int) (cryst->ny *
1059                                                              cryst->b *
1060                                          cos((cryst->gamma - 90) * PI_RAD)) -
1061                           cryst->offset_h;
1062                      }
1063                    else
1064                      {
1065                         y_coor1 = cryst->offset_h;
1066                         y_coor2 = (int) (cryst->ny * cryst->b *
1067                                          cos((cryst->gamma - 90) * PI_RAD)) +
1068                           cryst->offset_h;
1069                      }
1070                         XDrawLine(display, window, cryst->gc, cryst->offset_w,
1071                                   y_coor1, (int) (cryst->offset_w - cryst->ny * cryst->b *
1072                                           sin((cryst->gamma - 90) * PI_RAD)),
1073                                   y_coor2);
1074                         inx = cryst->nx;
1075                         for (iny = 1; iny <= cryst->ny; iny++) {
1076                    if ( cryst->invert )
1077                      {
1078                         y_coor1 = cryst->win_height -
1079                           (int) (iny * cryst->b * cos((cryst->gamma - 90) *
1080                                                   PI_RAD)) - cryst->offset_h;
1081                         y_coor2 = cryst->win_height -
1082                           (int) (iny * cryst->b * cos((cryst->gamma - 90) *
1083                                                       PI_RAD)) -
1084                           cryst->offset_h;
1085                      }
1086                    else
1087                      {
1088                         y_coor1 = (int) (iny * cryst->b * cos((cryst->gamma - 90) *
1089                                                   PI_RAD)) + cryst->offset_h;
1090                         y_coor2 = (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
1091                                           cryst->offset_h;
1092                      }
1093                                 XDrawLine(display, window, cryst->gc,
1094                                           (int) (cryst->offset_w +
1095                                      inx * cryst->a - (int) (iny * cryst->b *
1096                                          sin((cryst->gamma - 90) * PI_RAD))),
1097                                           y_coor1,
1098                                     (int) (cryst->offset_w - iny * cryst->b *
1099                                            sin((cryst->gamma - 90) * PI_RAD)),
1100                                           y_coor2);
1101                         }
1102                         iny = cryst->ny;
1103                         for (inx = 1; inx <= cryst->nx; inx++) {
1104                            if ( cryst->invert )
1105                              {
1106                                 y_coor1 =cryst->win_height -
1107                                   (int) (iny * cryst->b *
1108                                                 cos((cryst->gamma - 90) *
1109                                                     PI_RAD)) - cryst->offset_h;
1110                                 y_coor2 =cryst->win_height - cryst->offset_h;
1111                              }
1112                            else
1113                              {
1114                                 y_coor1 =(int) (iny * cryst->b *
1115                                                 cos((cryst->gamma - 90) *
1116                                                     PI_RAD)) + cryst->offset_h;
1117                                 y_coor2 =cryst->offset_h;
1118                              }
1119                                 XDrawLine(display, window, cryst->gc,
1120                                           (int) (cryst->offset_w +
1121                                      inx * cryst->a - (int) (iny * cryst->b *
1122                                          sin((cryst->gamma - 90) * PI_RAD))),
1123                                           y_coor1,
1124                                           cryst->offset_w + inx * cryst->a,
1125                                           y_coor2);
1126                         }
1127                 } else {
1128                         int         inx, iny;
1129
1130                         inx = NRAND(cryst->nx);
1131                         iny = NRAND(cryst->ny);
1132                    if ( cryst->invert )
1133                      {
1134                         y_coor1 =cryst->win_height -
1135                           (int) (iny * cryst->b *
1136                                                   cos((cryst->gamma - 90) *
1137                                                       PI_RAD)) -
1138                           cryst->offset_h;
1139                         y_coor2 =cryst->win_height -
1140                           (int) ( ( iny + 1 ) * cryst->b *
1141                                                   cos((cryst->gamma - 90) *
1142                                                       PI_RAD)) -
1143                           cryst->offset_h;
1144                      }
1145                    else
1146                      {
1147                         y_coor1 =(int) (iny * cryst->b *
1148                                                   cos((cryst->gamma - 90) *
1149                                                       PI_RAD)) +
1150                           cryst->offset_h;
1151                         y_coor2 =(int) (( iny + 1 ) * cryst->b *
1152                                                   cos((cryst->gamma - 90) *
1153                                                       PI_RAD)) +
1154                           cryst->offset_h;
1155                      }
1156                         XDrawLine(display, window, cryst->gc,
1157                                   cryst->offset_w + inx * 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 * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1160                                   y_coor1);
1161                         XDrawLine(display, window, cryst->gc,
1162                                   cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1163                                   y_coor1,
1164                                   cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1165                                   y_coor2);
1166                         XDrawLine(display, window, cryst->gc,
1167                                   cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1168                                   y_coor1,
1169                                   cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1170                                   y_coor2);
1171                         XDrawLine(display, window, cryst->gc,
1172                                   cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1173                                   y_coor2,
1174                                   cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1175                                   y_coor2);
1176                 }
1177         }
1178         if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
1179 /* Set up colour map */
1180                 if (cryst->colors && cryst->ncolors && !cryst->no_colors)
1181                         free_colors(mi->xgwa.screen, cryst->cmap,
1182                         cryst->colors, cryst->ncolors);
1183                 if (cryst->colors)
1184                         (void) free((void *) cryst->colors);
1185                 cryst->colors = 0;
1186                 cryst->ncolors = MI_NCOLORS(mi);
1187                 if (cryst->ncolors < 2)
1188                         cryst->ncolors = 2;
1189                 if (cryst->ncolors <= 2)
1190                         cryst->mono_p = True;
1191                 else
1192                         cryst->mono_p = False;
1193
1194                 if (cryst->mono_p)
1195                         cryst->colors = 0;
1196                 else
1197                         cryst->colors = (XColor *) malloc(sizeof (*cryst->colors) * (cryst->ncolors + 1));
1198                 cryst->cycle_p = has_writable_cells(mi->xgwa.screen, MI_VISUAL(mi));
1199                 if (cryst->cycle_p) {
1200                         if (MI_IS_FULLRANDOM(mi)) {
1201                                 if (!NRAND(8))
1202                                         cryst->cycle_p = False;
1203                                 else
1204                                         cryst->cycle_p = True;
1205                         } else {
1206                                 cryst->cycle_p = cycle_p;
1207                         }
1208                 }
1209                 if (!cryst->mono_p) {
1210                         if (!(LRAND() % 10))
1211                                 make_random_colormap(mi->xgwa.screen, MI_VISUAL(mi),
1212                                      cryst->cmap, cryst->colors,
1213                                      &cryst->ncolors,
1214                                      True, True, &cryst->cycle_p, True);
1215                         else if (!(LRAND() % 2))
1216                                 make_uniform_colormap(mi->xgwa.screen, MI_VISUAL(mi),
1217                                       cryst->cmap, cryst->colors,
1218                                       &cryst->ncolors, True,
1219                                       &cryst->cycle_p, True);
1220                         else
1221                                 make_smooth_colormap(mi->xgwa.screen, MI_VISUAL(mi),
1222                                      cryst->cmap, cryst->colors,
1223                                      &cryst->ncolors,
1224                                      True, &cryst->cycle_p, True);
1225                 }
1226 #if 0 /* #### wrong! -jwz */
1227                 XInstallColormap(display, cryst->cmap);
1228 #endif
1229                 if (cryst->ncolors < 2) {
1230                         cryst->ncolors = 2;
1231                         cryst->no_colors = True;
1232                 } else
1233                         cryst->no_colors = False;
1234                 if (cryst->ncolors <= 2)
1235                         cryst->mono_p = True;
1236
1237                 if (cryst->mono_p)
1238                         cryst->cycle_p = False;
1239
1240         }
1241         for (i = 0; i < cryst->num_atom; i++) {
1242                 crystalatom *atom0;
1243
1244                 atom0 = &cryst->atom[i];
1245                 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
1246                         if (cryst->ncolors > 2)
1247                                 atom0->colour = NRAND(cryst->ncolors - 2) + 2;
1248                         else
1249                                 atom0->colour = 1;      /* Just in case */
1250                         XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
1251                 } else {
1252                         if (MI_NPIXELS(mi) > 2)
1253                                 atom0->colour = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
1254                         else
1255                                 atom0->colour = 1;      /*Xor'red so WHITE may not be appropriate */
1256                         XSetForeground(display, cryst->gc, atom0->colour);
1257                 }
1258                 atom0->x0 = NRAND(cryst->a);
1259                 atom0->y0 = NRAND(cryst->b);
1260                 atom0->velocity[0] = NRAND(7) - 3;
1261                 atom0->velocity[1] = NRAND(7) - 3;
1262                 atom0->velocity_a = (NRAND(7) - 3) * PI_RAD;
1263                 atom0->angle = NRAND(90) * PI_RAD;
1264                 atom0->at_type = NRAND(3);
1265                 if (size_atom == 0)
1266                         atom0->size_at = DEF_SIZ_ATOM;
1267                 else if (size_atom > 0)
1268                         atom0->size_at = size_atom;
1269                 else
1270                         atom0->size_at = NRAND(-size_atom) + 1;
1271                 atom0->size_at++;
1272                 if (atom0->at_type == 2)
1273                         atom0->num_point = 3;
1274                 else
1275                         atom0->num_point = 4;
1276                 crystal_setupatom(atom0, cryst->gamma);
1277                 crystal_drawatom(mi, atom0);
1278         }
1279         XSetFunction(display, cryst->gc, GXcopy);
1280 }
1281
1282 ENTRYPOINT void
1283 reshape_crystal(ModeInfo * mi, int width, int height)
1284 {
1285   release_crystal(mi);
1286   init_crystal(mi);
1287 }
1288
1289 XSCREENSAVER_MODULE ("Crystal", crystal)