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