1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* crystal --- polygons moving according to plane group rules */
5 static const char sccsid[] = "@(#)crystal.c 4.12 98/09/10 xlockmore";
9 * Copyright (c) 1997 by Jouk Jansen <joukj@crys.chem.uva.nl>
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.
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.
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.
27 * A moving polygon-mode. The polygons obey 2D-planegroup symmetry.
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
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
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
52 * fixed "size" problem. Now very small non-vissable objects
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
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
72 # define DEFAULTS "*delay: 60000 \n" \
77 "*fpsSolid: True \n" \
78 "*ignoreRotation: True \n" \
80 # include "xlockmore.h" /* in xscreensaver distribution */
81 #else /* STANDALONE */
82 # include "xlock.h" /* in xlockmore distribution */
84 #endif /* STANDALONE */
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"
97 #define NRAND(n) ( (n) ? (int) (LRAND() % (n)) : 0)
99 #define min(a,b) ((a) <= (b) ? (a) : (b))
103 static Bool unit_cell, grid_cell, centre, maxsize, cycle_p;
105 static XrmOptionDescRec opts[] =
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"}
121 static argtype vars[] =
123 {&nx, "nx", "nx", DEF_NX, t_Int},
124 {&ny, "ny", "ny", DEF_NY, t_Int},
125 {¢re, "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}
131 static OptionStruct desc[] =
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"}
142 ENTRYPOINT ModeSpecOpt crystal_opts =
143 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
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};
154 #define DEF_NUM_ATOM 10
156 #define DEF_SIZ_ATOM 10
158 #define PI_RAD (M_PI / 180.0)
160 static Bool centro[17] =
181 static Bool primitive[17] =
202 static short numops[34] =
223 static short operation[114] =
247 unsigned long colour;
248 int x0, y0, velocity[2];
249 float angle, velocity_a;
250 int num_point, at_type, size_at;
256 int win_width, win_height, num_atom;
257 int planegroup, a, b, offset_w, offset_h, nx, ny;
261 Bool unit_cell, grid_cell;
265 Bool cycle_p, mono_p, no_colors;
266 unsigned long blackpixel, whitepixel, fg, bg;
267 int direction, invert;
270 static crystalstruct *crystals = NULL;
273 trans_coor(XPoint * xyp, XPoint * new_xyp, int num_points,
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));
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 )
292 for (i = 0; i <= num_points; i++) {
293 new_xyp[i].y = (int) (xyp[i].y * cos((gamma - 90) * PI_RAD)) +
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;
302 crystal_setupatom(crystalatom * atom0, float gamma)
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 *
313 (int) (atom0->size_at * sin(atom0->angle));
314 xy[0].y = y0 + (int) (atom0->size_at *
316 (int) (2 * atom0->size_at * sin(atom0->angle));
317 xy[1].x = x0 + (int) (2 * atom0->size_at *
319 (int) (atom0->size_at * sin(atom0->angle));
320 xy[1].y = y0 - (int) (atom0->size_at *
322 (int) (2 * atom0->size_at * sin(atom0->angle));
323 xy[2].x = x0 - (int) (2 * atom0->size_at *
325 (int) (atom0->size_at * sin(atom0->angle));
326 xy[2].y = y0 - (int) (atom0->size_at *
328 (int) (2 * atom0->size_at * sin(atom0->angle));
329 xy[3].x = x0 - (int) (2 * atom0->size_at *
331 (int) (atom0->size_at * sin(atom0->angle));
332 xy[3].y = y0 + (int) (atom0->size_at *
334 (int) (2 * atom0->size_at *
338 trans_coor(xy, atom0->xy, 4, gamma);
340 case 1: /* squares */
341 xy[0].x = x0 + (int) (1.5 * atom0->size_at *
343 (int) (1.5 * atom0->size_at *
345 xy[0].y = y0 + (int) (1.5 * atom0->size_at *
347 (int) (1.5 * atom0->size_at *
349 xy[1].x = x0 + (int) (1.5 * atom0->size_at *
351 (int) (1.5 * atom0->size_at *
353 xy[1].y = y0 - (int) (1.5 * atom0->size_at *
355 (int) (1.5 * atom0->size_at *
357 xy[2].x = x0 - (int) (1.5 * atom0->size_at *
359 (int) (1.5 * atom0->size_at *
361 xy[2].y = y0 - (int) (1.5 * atom0->size_at *
363 (int) (1.5 * atom0->size_at *
365 xy[3].x = x0 - (int) (1.5 * atom0->size_at *
367 (int) (1.5 * atom0->size_at *
369 xy[3].y = y0 + (int) (1.5 * atom0->size_at *
371 (int) (1.5 * atom0->size_at *
375 trans_coor(xy, atom0->xy, 4, gamma);
377 case 2: /* triangles */
378 xy[0].x = x0 + (int) (1.5 * atom0->size_at *
380 xy[0].y = y0 + (int) (1.5 * atom0->size_at *
382 xy[1].x = x0 + (int) (1.5 * atom0->size_at *
384 (int) (1.5 * atom0->size_at *
386 xy[1].y = y0 - (int) (1.5 * atom0->size_at *
388 (int) (1.5 * atom0->size_at *
390 xy[2].x = x0 - (int) (1.5 * atom0->size_at *
392 (int) (1.5 * atom0->size_at *
394 xy[2].y = y0 - (int) (1.5 * atom0->size_at *
396 (int) (1.5 * atom0->size_at *
400 trans_coor(xy, atom0->xy, 3, gamma);
406 crystal_drawatom(ModeInfo * mi, crystalatom * atom0)
408 crystalstruct *cryst;
409 Display *display = MI_DISPLAY(mi);
410 Window window = MI_WINDOW(mi);
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];
420 xtrans = operation[j * 6] * atom0->x0 + operation[j * 6 + 1] *
421 atom0->y0 + (int) (operation[j * 6 + 4] * cryst->a /
423 ytrans = operation[j * 6 + 2] * atom0->x0 + operation[j * 6 +
424 3] * atom0->y0 + (int) (operation[j * 6 + 5] *
427 if (xtrans < -cryst->a)
428 xtrans = 2 * cryst->a;
431 } else if (xtrans >= cryst->a)
437 else if (ytrans >= cryst->b)
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] *
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] *
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++) {
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;
462 trans_coor_back(xy_1, new_xy, atom0->num_point,
463 cryst->gamma, cryst->offset_w,
467 XFillPolygon(display, window, cryst->gc, new_xy,
468 atom0->num_point, Convex, CoordModeOrigin);
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;
476 for (l = 0; l < cryst->nx; l++) {
477 for (m = 0; m < cryst->ny; m++) {
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;
483 trans_coor_back(xy_1, new_xy, atom0->num_point,
489 XFillPolygon(display, window, cryst->gc,
491 atom0->num_point, Convex,
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);
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);
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;
509 for (l = 0; l < cryst->nx; l++) {
510 for (m = 0; m < cryst->ny; m++) {
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;
516 trans_coor_back(xy_1, new_xy, atom0->num_point,
522 XFillPolygon(display, window, cryst->gc,
524 atom0->num_point, Convex,
528 if (centro[cryst->planegroup] == True) {
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;
535 for (l = 0; l < cryst->nx; l++) {
536 for (m = 0; m < cryst->ny; m++) {
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;
542 trans_coor_back(xy_1, new_xy, atom0->num_point,
548 XFillPolygon(display, window,
550 new_xy, atom0->num_point,
551 Convex, CoordModeOrigin);
559 ENTRYPOINT void init_crystal(ModeInfo * mi);
560 ENTRYPOINT void release_crystal(ModeInfo * mi);
564 draw_crystal(ModeInfo * mi)
566 Display *display = MI_DISPLAY(mi);
567 crystalstruct *cryst = &crystals[MI_SCREEN(mi)];
570 #ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */
571 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
574 if (cryst->no_colors) {
579 cryst->painted = True;
580 MI_IS_DRAWN(mi) = True;
581 XSetFunction(display, cryst->gc, GXxor);
584 if (cryst->cycle_p) {
585 rotate_colors(mi->xgwa.screen, cryst->cmap,
586 cryst->colors, cryst->ncolors,
588 if (!(LRAND() % 1000))
589 cryst->direction = -cryst->direction;
591 for (i = 0; i < cryst->num_atom; i++) {
594 atom0 = &cryst->atom[i];
596 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
597 XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
599 XSetForeground(display, cryst->gc, atom0->colour);
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) { */
609 atom0->x0 += cryst->a;
610 else if (atom0->x0 >= cryst->a)
611 atom0->x0 -= cryst->a;
612 atom0->y0 += atom0->velocity[1];
614 atom0->y0 += cryst->b;
615 else if (atom0->y0 >= cryst->b)
616 atom0->y0 -= cryst->b;
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);
623 XSetFunction(display, cryst->gc, GXcopy);
627 refresh_crystal(ModeInfo * mi)
629 Display *display = MI_DISPLAY(mi);
630 Window window = MI_WINDOW(mi);
631 crystalstruct *cryst = &crystals[MI_SCREEN(mi)];
637 XSetFunction(display, cryst->gc, GXxor);
639 if (cryst->unit_cell) {
640 int y_coor1 , y_coor2;
642 if (MI_NPIXELS(mi) > 2)
643 XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
645 XSetForeground(display, cryst->gc, MI_WHITE_PIXEL(mi));
646 if (cryst->grid_cell) {
650 y_coor1 = y_coor2 = cryst->win_height - cryst->offset_h;
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,
658 y_coor1 = cryst->win_height - cryst->offset_h;
659 y_coor2 = cryst->win_height - (int) (cryst->ny *
661 cos((cryst->gamma - 90) * PI_RAD)) -
666 y_coor1 = cryst->offset_h;
667 y_coor2 = (int) (cryst->ny * cryst->b *
668 cos((cryst->gamma - 90) * PI_RAD)) +
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)),
676 for (iny = 1; iny <= cryst->ny; iny++) {
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) *
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)) +
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))),
699 (int) (cryst->offset_w - iny * cryst->b *
700 sin((cryst->gamma - 90) * PI_RAD)),
704 for (inx = 1; inx <= cryst->nx; inx++) {
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;
715 y_coor1 =(int) (iny * cryst->b *
716 cos((cryst->gamma - 90) *
717 PI_RAD)) + cryst->offset_h;
718 y_coor2 =cryst->offset_h;
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))),
725 cryst->offset_w + inx * cryst->a,
731 inx = NRAND(cryst->nx);
732 iny = NRAND(cryst->ny);
735 y_coor1 =cryst->win_height -
736 (int) (iny * cryst->b *
737 cos((cryst->gamma - 90) *
740 y_coor2 =cryst->win_height -
741 (int) ( ( iny + 1 ) * cryst->b *
742 cos((cryst->gamma - 90) *
748 y_coor1 =(int) (iny * cryst->b *
749 cos((cryst->gamma - 90) *
752 y_coor2 =(int) (( iny + 1 ) * cryst->b *
753 cos((cryst->gamma - 90) *
757 XDrawLine(display, window, cryst->gc,
758 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
760 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
762 XDrawLine(display, window, cryst->gc,
763 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
765 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
767 XDrawLine(display, window, cryst->gc,
768 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
770 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
772 XDrawLine(display, window, cryst->gc,
773 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
775 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
779 for (i = 0; i < cryst->num_atom; i++) {
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);
786 XSetForeground(display, cryst->gc, atom0->colour);
788 crystal_drawatom(mi, atom0);
790 XSetFunction(display, cryst->gc, GXcopy);
794 release_crystal(ModeInfo * mi)
796 Display *display = MI_DISPLAY(mi);
798 if (crystals != NULL) {
801 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
802 crystalstruct *cryst = &crystals[screen];
804 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
805 MI_WHITE_PIXEL(mi) = cryst->whitepixel;
806 MI_BLACK_PIXEL(mi) = cryst->blackpixel;
808 MI_FG_PIXEL(mi) = cryst->fg;
809 MI_BG_PIXEL(mi) = cryst->bg;
811 if (cryst->colors && cryst->ncolors && !cryst->no_colors)
812 free_colors(mi->xgwa.screen, cryst->cmap, cryst->colors,
815 (void) free((void *) cryst->colors);
816 #if 0 /* #### wrong! -jwz */
817 XFreeColormap(display, cryst->cmap);
820 if (cryst->gc != NULL)
821 XFreeGC(display, cryst->gc);
822 if (cryst->atom != NULL)
823 (void) free((void *) cryst->atom);
825 (void) free((void *) crystals);
831 init_crystal(ModeInfo * mi)
833 Display *display = MI_DISPLAY(mi);
834 Window window = MI_WINDOW(mi);
835 crystalstruct *cryst;
836 int i, max_atoms, size_atom, neqv;
842 if (crystals == NULL) {
843 if ((crystals = (crystalstruct *) calloc(MI_NUM_SCREENS(mi),
844 sizeof (crystalstruct))) == NULL)
847 cryst = &crystals[MI_SCREEN(mi)];
850 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
854 extern char *background;
855 extern char *foreground;
857 cryst->fg = MI_FG_PIXEL(mi);
858 cryst->bg = MI_BG_PIXEL(mi);
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);
867 cryst->cmap = mi->xgwa.colormap;
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;
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;
886 if ((cryst->gc = XCreateGC(display, MI_WINDOW(mi),
887 (unsigned long) 0, (XGCValues *) NULL)) == None)
892 cryst->painted = False;
893 XSetFunction(display, cryst->gc, GXxor);
896 /*Set up crystal data */
897 cryst->direction = (LRAND() & 1) ? 1 : -1;
898 if (MI_IS_FULLRANDOM(mi)) {
900 cryst->unit_cell = True;
902 cryst->unit_cell = False;
904 cryst->unit_cell = unit_cell;
905 if (cryst->unit_cell) {
906 if (MI_IS_FULLRANDOM(mi)) {
908 cryst->grid_cell = True;
910 cryst->grid_cell = False;
912 cryst->grid_cell = grid_cell;
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);
929 neqv = numops[2 * cryst->planegroup] - numops[2 * cryst->planegroup + 1];
930 if (centro[cryst->planegroup] == True)
932 if (primitive[cryst->planegroup] == False)
939 cryst->nx = NRAND(-nx) + 1;
942 if (cryst->planegroup > 8)
943 cryst->ny = cryst->nx;
947 cryst->ny = NRAND(-ny) + 1;
950 neqv = neqv * cryst->nx * cryst->ny;
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;
962 cryst->num_atom = cryst->num_atom / neqv + 1;
964 if (cryst->atom == NULL)
965 cryst->atom = (crystalatom *) calloc(max_atoms, sizeof (
969 if (cryst->planegroup < 13) {
973 if (cryst->planegroup < 10) {
974 cryst->b = cryst->win_height;
975 cryst->a = cryst->win_width;
977 cryst->b = min(cryst->win_height, cryst->win_width);
981 cryst->gamma = 120.0;
982 cryst->a = (int) (cryst->win_width * 2.0 / 3.0);
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);
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)
995 cryst->b = NRAND((int) (cryst->win_height / (cos((cryst->gamma - 90) *
996 PI_RAD))) - cell_min) + cell_min;
997 if (cryst->planegroup > 8)
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) *
1005 cryst->offset_h = (int) ((cryst->win_height - cryst->b * cos((
1006 cryst->gamma - 90) * PI_RAD)) / 2.0);
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 -
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));
1018 cryst->offset_w = (int) (cryst->b * sin((cryst->gamma - 90) *
1020 } else if (cryst->offset_w > 0)
1021 cryst->offset_w = NRAND(cryst->offset_w);
1023 cryst->offset_w = 0;
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;
1033 size_atom = MI_SIZE(mi);
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;
1040 if (MI_NPIXELS(mi) > 2)
1041 XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
1043 XSetForeground(display, cryst->gc, MI_WHITE_PIXEL(mi));
1044 if (cryst->grid_cell) {
1047 if ( cryst->invert )
1048 y_coor1 = y_coor2 = cryst->win_height - cryst->offset_h;
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,
1054 if ( cryst->invert )
1056 y_coor1 = cryst->win_height - cryst->offset_h;
1057 y_coor2 = cryst->win_height - (int) (cryst->ny *
1059 cos((cryst->gamma - 90) * PI_RAD)) -
1064 y_coor1 = cryst->offset_h;
1065 y_coor2 = (int) (cryst->ny * cryst->b *
1066 cos((cryst->gamma - 90) * PI_RAD)) +
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)),
1074 for (iny = 1; iny <= cryst->ny; iny++) {
1075 if ( cryst->invert )
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) *
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)) +
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))),
1097 (int) (cryst->offset_w - iny * cryst->b *
1098 sin((cryst->gamma - 90) * PI_RAD)),
1102 for (inx = 1; inx <= cryst->nx; inx++) {
1103 if ( cryst->invert )
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;
1113 y_coor1 =(int) (iny * cryst->b *
1114 cos((cryst->gamma - 90) *
1115 PI_RAD)) + cryst->offset_h;
1116 y_coor2 =cryst->offset_h;
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))),
1123 cryst->offset_w + inx * cryst->a,
1129 inx = NRAND(cryst->nx);
1130 iny = NRAND(cryst->ny);
1131 if ( cryst->invert )
1133 y_coor1 =cryst->win_height -
1134 (int) (iny * cryst->b *
1135 cos((cryst->gamma - 90) *
1138 y_coor2 =cryst->win_height -
1139 (int) ( ( iny + 1 ) * cryst->b *
1140 cos((cryst->gamma - 90) *
1146 y_coor1 =(int) (iny * cryst->b *
1147 cos((cryst->gamma - 90) *
1150 y_coor2 =(int) (( iny + 1 ) * cryst->b *
1151 cos((cryst->gamma - 90) *
1155 XDrawLine(display, window, cryst->gc,
1156 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1158 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1160 XDrawLine(display, window, cryst->gc,
1161 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1163 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1165 XDrawLine(display, window, cryst->gc,
1166 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1168 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1170 XDrawLine(display, window, cryst->gc,
1171 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1173 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
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);
1183 (void) free((void *) cryst->colors);
1185 cryst->ncolors = MI_NCOLORS(mi);
1186 if (cryst->ncolors < 2)
1188 if (cryst->ncolors <= 2)
1189 cryst->mono_p = True;
1191 cryst->mono_p = False;
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)) {
1201 cryst->cycle_p = False;
1203 cryst->cycle_p = True;
1205 cryst->cycle_p = cycle_p;
1208 if (!cryst->mono_p) {
1209 if (!(LRAND() % 10))
1210 make_random_colormap(mi->xgwa.screen, MI_VISUAL(mi),
1211 cryst->cmap, cryst->colors,
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);
1220 make_smooth_colormap(mi->xgwa.screen, MI_VISUAL(mi),
1221 cryst->cmap, cryst->colors,
1223 True, &cryst->cycle_p, True);
1225 #if 0 /* #### wrong! -jwz */
1226 XInstallColormap(display, cryst->cmap);
1228 if (cryst->ncolors < 2) {
1230 cryst->no_colors = True;
1232 cryst->no_colors = False;
1233 if (cryst->ncolors <= 2)
1234 cryst->mono_p = True;
1237 cryst->cycle_p = False;
1240 for (i = 0; i < cryst->num_atom; i++) {
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;
1248 atom0->colour = 1; /* Just in case */
1249 XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
1251 if (MI_NPIXELS(mi) > 2)
1252 atom0->colour = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
1254 atom0->colour = 1; /*Xor'red so WHITE may not be appropriate */
1255 XSetForeground(display, cryst->gc, atom0->colour);
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);
1265 atom0->size_at = DEF_SIZ_ATOM;
1266 else if (size_atom > 0)
1267 atom0->size_at = size_atom;
1269 atom0->size_at = NRAND(-size_atom) + 1;
1271 if (atom0->at_type == 2)
1272 atom0->num_point = 3;
1274 atom0->num_point = 4;
1275 crystal_setupatom(atom0, cryst->gamma);
1276 crystal_drawatom(mi, atom0);
1278 XSetFunction(display, cryst->gc, GXcopy);
1282 reshape_crystal(ModeInfo * mi, int width, int height)
1284 release_crystal(mi);
1289 crystal_handle_event (ModeInfo *mi, XEvent *event)
1291 if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
1293 reshape_crystal (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1299 XSCREENSAVER_MODULE ("Crystal", crystal)