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