ftp://ftp.linux.ncsu.edu/mirror/ftp.redhat.com/pub/redhat/linux/enterprise/4/en/os...
[xscreensaver] / hacks / crystal.c
index caab2a894a4849dd8e52ddf0313a0dc161e1891f..15c01ba3ffb718c2fee0622dc668f405d0d6ab4f 100644 (file)
@@ -1,9 +1,8 @@
 /* -*- Mode: C; tab-width: 4 -*- */
 /* crystal --- polygons moving according to plane group rules */
 
-#if !defined( lint ) && !defined( SABER )
-static const char sccsid[] = "@(#)crystal.c    4.07 97/11/24 xlockmore";
-
+#if 0
+static const char sccsid[] = "@(#)crystal.c    4.12 98/09/10 xlockmore";
 #endif
 
 /*-
@@ -27,7 +26,15 @@ static const char sccsid[] = "@(#)crystal.c  4.07 97/11/24 xlockmore";
  *
  * A moving polygon-mode. The polygons obey 2D-planegroup symmetry.
  *
+ * The groupings of the cells fall in 3 categories:
+ *   oblique groups 1 and 2 where the angle gamma ranges from 60 to 120 degrees
+ *   square groups 3 through 11 where the angle gamma is 90 degrees
+ *   hexagonal groups 12 through 17 where the angle gamma is 120 degrees
+ *
  * Revision History:
+ * 03-Dec-98: Random inversion of y-axis included to simulate hexagonal groups
+ *             with an angle of 60 degrees.
+ * 10-Sep-98: new colour scheme
  * 24-Feb-98: added option centre which turns on/off forcing the centre of
  *              the screen to be used
  *            added option maxsize which forces the dimensions to be chasen
@@ -35,7 +42,7 @@ static const char sccsid[] = "@(#)crystal.c   4.07 97/11/24 xlockmore";
  *              used 
  *            When only one unit cell is drawn, it is chosen at random
  * 18-Feb-98: added support for negative numbers with -nx and -ny meaning
- *            "random" choice with geiven maximum
+ *            "random" choice with given maximum
  *            added +/-grid option. If -cell is specified this option
  *            determines if one or all unit cells are drawn.
  *            -batchcount is now a parameter for all the objects on the screen
@@ -70,12 +77,13 @@ static const char sccsid[] = "@(#)crystal.c 4.07 97/11/24 xlockmore";
                                                 "*count:                -500   \n" \
                                                 "*cycles:                200   \n" \
                                                 "*size:                  -15   \n" \
-                                                "*ncolors:               200   \n" \
+                                                "*ncolors:               100   \n" \
                                                 "*fullrandom:   True   \n" \
                                                 "*verbose:             False   \n"
 # include "xlockmore.h"                /* in xscreensaver distribution */
 #else /* STANDALONE */
 # include "xlock.h"                    /* in xlockmore distribution */
+# include "color.h"
 #endif /* STANDALONE */
 
 #define DEF_CELL "True"                /* Draw unit cell */
@@ -86,44 +94,53 @@ static const char sccsid[] = "@(#)crystal.c 4.07 97/11/24 xlockmore";
 #define DEF_NY1 1              /* number of unit cells in y-direction */
 #define DEF_CENTRE "False"
 #define DEF_MAXSIZE "False"
+#define DEF_CYCLE "True"
 
 #define min(a,b) ((a) <= (b) ? (a) : (b))
 
+#ifdef STANDALONE
+void release_crystal(ModeInfo * mi);
+#endif
+
 static int  nx, ny;
 
-static Bool unit_cell, grid_cell, centre, maxsize;
+static Bool unit_cell, grid_cell, centre, maxsize, cycle_p;
 
 static XrmOptionDescRec opts[] =
 {
-       {"-nx", "crystal.nx", XrmoptionSepArg, (caddr_t) NULL},
-       {"-ny", "crystal.ny", XrmoptionSepArg, (caddr_t) NULL},
-       {"-centre", ".crystal.centre", XrmoptionNoArg, (caddr_t) "on"},
-       {"+centre", ".crystal.centre", XrmoptionNoArg, (caddr_t) "off"},
-       {"-maxsize", ".crystal.maxsize", XrmoptionNoArg, (caddr_t) "on"},
-       {"+maxsize", ".crystal.maxsize", XrmoptionNoArg, (caddr_t) "off"},
-       {"-cell", ".crystal.cell", XrmoptionNoArg, (caddr_t) "on"},
-       {"+cell", ".crystal.cell", XrmoptionNoArg, (caddr_t) "off"},
-       {"-grid", ".crystal.grid", XrmoptionNoArg, (caddr_t) "on"},
-       {"+grid", ".crystal.grid", XrmoptionNoArg, (caddr_t) "off"}
+       {"-nx", "crystal.nx", XrmoptionSepArg, 0},
+       {"-ny", "crystal.ny", XrmoptionSepArg, 0},
+       {"-centre", ".crystal.centre", XrmoptionNoArg, "on"},
+       {"+centre", ".crystal.centre", XrmoptionNoArg, "off"},
+       {"-maxsize", ".crystal.maxsize", XrmoptionNoArg, "on"},
+       {"+maxsize", ".crystal.maxsize", XrmoptionNoArg, "off"},
+       {"-cell", ".crystal.cell", XrmoptionNoArg, "on"},
+       {"+cell", ".crystal.cell", XrmoptionNoArg, "off"},
+       {"-grid", ".crystal.grid", XrmoptionNoArg, "on"},
+       {"+grid", ".crystal.grid", XrmoptionNoArg, "off"},
+       {"-shift", ".crystal.shift", XrmoptionNoArg, "on"},
+       {"+shift", ".crystal.shift", XrmoptionNoArg, "off"}
 };
 
 static argtype vars[] =
 {
-       {(caddr_t *) & nx, "nx", "nx", DEF_NX, t_Int},
-       {(caddr_t *) & ny, "ny", "ny", DEF_NY, t_Int},
-       {(caddr_t *) & centre, "centre", "Centre", DEF_CENTRE, t_Bool},
-       {(caddr_t *) & maxsize, "maxsize", "Maxsize", DEF_MAXSIZE, t_Bool},
-       {(caddr_t *) & unit_cell, "cell", "Cell", DEF_CELL, t_Bool},
-       {(caddr_t *) & grid_cell, "grid", "Grid", DEF_GRID, t_Bool}
+       {&nx, "nx", "nx", DEF_NX, t_Int},
+       {&ny, "ny", "ny", DEF_NY, t_Int},
+       {&centre, "centre", "Centre", DEF_CENTRE, t_Bool},
+       {&maxsize, "maxsize", "Maxsize", DEF_MAXSIZE, t_Bool},
+       {&unit_cell, "cell", "Cell", DEF_CELL, t_Bool},
+       {&grid_cell, "grid", "Grid", DEF_GRID, t_Bool},
+       {&cycle_p, "shift", "Shift", DEF_CYCLE, t_Bool}
 };
 static OptionStruct desc[] =
 {
        {"-nx num", "Number of unit cells in x-direction"},
        {"-ny num", "Number of unit cells in y-direction"},
-       {"-/+centre", "turn on/off cenetering on screen"},
+       {"-/+centre", "turn on/off centering on screen"},
        {"-/+maxsize", "turn on/off use of maximum part of screen"},
        {"-/+cell", "turn on/off drawing of unit cell"},
-    {"-/+grid", "turn on/off drawing of grid of unit cells (if -cell is on)"}
+   {"-/+grid", "turn on/off drawing of grid of unit cells (if -cell is on)"},
+       {"-/+shift", "turn on/off colour cycling"}
 };
 
 ModeSpecOpt crystal_opts =
@@ -246,6 +263,12 @@ typedef struct {
        crystalatom *atom;
        GC          gc;
        Bool        unit_cell, grid_cell;
+       Colormap    cmap;
+       XColor     *colors;
+       int         ncolors;
+       Bool        cycle_p, mono_p, no_colors;
+       unsigned long blackpixel, whitepixel, fg, bg;
+       int         direction, invert;
 } crystalstruct;
 
 static crystalstruct *crystals = NULL;
@@ -265,7 +288,8 @@ trans_coor(XPoint * xyp, XPoint * new_xyp, int num_points,
 
 static void
 trans_coor_back(XPoint * xyp, XPoint * new_xyp,
-               int num_points, float gamma, int offset_w, int offset_h)
+               int num_points, float gamma, int offset_w, int offset_h ,
+               int winheight , int invert )
 {
        int         i;
 
@@ -274,6 +298,7 @@ trans_coor_back(XPoint * xyp, XPoint * new_xyp,
                        offset_h;
                new_xyp[i].x = xyp[i].x - (int) (xyp[i].y * sin((gamma - 90.0)
                                                       * PI_RAD)) + offset_w;
+          if ( invert ) new_xyp[i].y = winheight - new_xyp[i].y;
        }
 }
 
@@ -439,7 +464,10 @@ crystal_drawatom(ModeInfo * mi, crystalatom * atom0)
                                        xy_1[k].y = xy[k].y + m * cryst->b;
                                }
                                trans_coor_back(xy_1, new_xy, atom0->num_point,
-                                               cryst->gamma, cryst->offset_w, cryst->offset_h);
+                                               cryst->gamma, cryst->offset_w,
+                                               cryst->offset_h ,
+                                               cryst->win_height,
+                                               cryst->invert);
                                XFillPolygon(display, window, cryst->gc, new_xy,
                                  atom0->num_point, Convex, CoordModeOrigin);
                        }
@@ -457,7 +485,11 @@ crystal_drawatom(ModeInfo * mi, crystalatom * atom0)
                                                xy_1[k].y = xy[k].y + m * cryst->b;
                                        }
                                        trans_coor_back(xy_1, new_xy, atom0->num_point,
-                                                       cryst->gamma, cryst->offset_w, cryst->offset_h);
+                                                       cryst->gamma,
+                                                       cryst->offset_w,
+                                                       cryst->offset_h ,
+                                                       cryst->win_height ,
+                                                       cryst->invert);
                                        XFillPolygon(display, window, cryst->gc,
                                                     new_xy,
                                                     atom0->num_point, Convex,
@@ -486,7 +518,11 @@ crystal_drawatom(ModeInfo * mi, crystalatom * atom0)
                                                xy_1[k].y = xy[k].y + m * cryst->b;
                                        }
                                        trans_coor_back(xy_1, new_xy, atom0->num_point,
-                                                       cryst->gamma, cryst->offset_w, cryst->offset_h);
+                                                       cryst->gamma,
+                                                       cryst->offset_w,
+                                                       cryst->offset_h ,
+                                                       cryst->win_height,
+                                                       cryst->invert);
                                        XFillPolygon(display, window, cryst->gc,
                                                     new_xy,
                                                     atom0->num_point, Convex,
@@ -508,7 +544,11 @@ crystal_drawatom(ModeInfo * mi, crystalatom * atom0)
                                                        xy_1[k].y = xy1[k].y + m * cryst->b;
                                                }
                                                trans_coor_back(xy_1, new_xy, atom0->num_point,
-                                                               cryst->gamma, cryst->offset_w, cryst->offset_h);
+                                                               cryst->gamma,
+                                                               cryst->offset_w,
+                                                               cryst->offset_h ,
+                                                               cryst->win_height,
+                                                               cryst->invert);
                                                XFillPolygon(display, window,
                                                             cryst->gc,
                                                    new_xy, atom0->num_point,
@@ -527,13 +567,32 @@ draw_crystal(ModeInfo * mi)
        crystalstruct *cryst = &crystals[MI_SCREEN(mi)];
        int         i;
 
+       if (cryst->no_colors) {
+               release_crystal(mi);
+               init_crystal(mi);
+               return;
+       }
        cryst->painted = True;
+       MI_IS_DRAWN(mi) = True;
        XSetFunction(display, cryst->gc, GXxor);
+
+/* Rotate colours */
+       if (cryst->cycle_p) {
+               rotate_colors(display, cryst->cmap, cryst->colors, cryst->ncolors,
+                             cryst->direction);
+               if (!(LRAND() % 1000))
+                       cryst->direction = -cryst->direction;
+       }
        for (i = 0; i < cryst->num_atom; i++) {
                crystalatom *atom0;
 
                atom0 = &cryst->atom[i];
-               XSetForeground(display, cryst->gc, atom0->colour);
+
+               if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
+                       XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
+               } else {
+                       XSetForeground(display, cryst->gc, atom0->colour);
+               }
                crystal_drawatom(mi, atom0);
                atom0->velocity[0] += NRAND(3) - 1;
                atom0->velocity[0] = MAX(-20, MIN(20, atom0->velocity[0]));
@@ -573,74 +632,154 @@ refresh_crystal(ModeInfo * mi)
        XSetFunction(display, cryst->gc, GXxor);
 
        if (cryst->unit_cell) {
+          int y_coor1 , y_coor2;
+          
                if (MI_NPIXELS(mi) > 2)
                        XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
                else
-                       XSetForeground(display, cryst->gc, MI_BLACK_PIXEL(mi));
+                       XSetForeground(display, cryst->gc, MI_WHITE_PIXEL(mi));
                if (cryst->grid_cell) {
                        int         inx, iny;
 
+                  if ( cryst->invert )
+                    y_coor1 = y_coor2 = cryst->win_height - cryst->offset_h;
+                  else
+                    y_coor1 = y_coor2 = cryst->offset_h;
                        XDrawLine(display, window, cryst->gc, cryst->offset_w,
-                                 cryst->offset_h, cryst->offset_w + cryst->nx * cryst->a,
-                                 cryst->offset_h);
+                                 y_coor1, cryst->offset_w + cryst->nx * cryst->a,
+                                 y_coor2);
+                  if ( cryst->invert )
+                    {
+                       y_coor1 = cryst->win_height - cryst->offset_h;
+                       y_coor2 = cryst->win_height - (int) (cryst->ny *
+                                                            cryst->b *
+                                        cos((cryst->gamma - 90) * PI_RAD)) -
+                         cryst->offset_h;
+                    }
+                  else
+                    {
+                       y_coor1 = cryst->offset_h;
+                       y_coor2 = (int) (cryst->ny * cryst->b *
+                                        cos((cryst->gamma - 90) * PI_RAD)) +
+                         cryst->offset_h;
+                    }
                        XDrawLine(display, window, cryst->gc, cryst->offset_w,
-                                 cryst->offset_h, (int) (cryst->offset_w - cryst->ny * cryst->b *
+                                 y_coor1, (int) (cryst->offset_w - cryst->ny * cryst->b *
                                          sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) (cryst->ny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
+                                 y_coor2);
                        inx = cryst->nx;
                        for (iny = 1; iny <= cryst->ny; iny++) {
+                  if ( cryst->invert )
+                    {
+                       y_coor1 = cryst->win_height -
+                         (int) (iny * cryst->b * cos((cryst->gamma - 90) *
+                                                 PI_RAD)) - cryst->offset_h;
+                       y_coor2 = cryst->win_height -
+                         (int) (iny * cryst->b * cos((cryst->gamma - 90) *
+                                                     PI_RAD)) -
+                         cryst->offset_h;
+                    }
+                  else
+                    {
+                       y_coor1 = (int) (iny * cryst->b * cos((cryst->gamma - 90) *
+                                                 PI_RAD)) + cryst->offset_h;
+                       y_coor2 = (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
+                                         cryst->offset_h;
+                    }
                                XDrawLine(display, window, cryst->gc,
                                          (int) (cryst->offset_w +
                                     inx * cryst->a - (int) (iny * cryst->b *
                                         sin((cryst->gamma - 90) * PI_RAD))),
-                                         (int) (iny * cryst->b * cos((cryst->gamma - 90) *
-                                                 PI_RAD)) + cryst->offset_h,
+                                         y_coor1,
                                    (int) (cryst->offset_w - iny * cryst->b *
                                           sin((cryst->gamma - 90) * PI_RAD)),
-                                         (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
-                                         cryst->offset_h);
+                                         y_coor2);
                        }
                        iny = cryst->ny;
                        for (inx = 1; inx <= cryst->nx; inx++) {
+                          if ( cryst->invert )
+                            {
+                               y_coor1 =cryst->win_height -
+                                 (int) (iny * cryst->b *
+                                               cos((cryst->gamma - 90) *
+                                                   PI_RAD)) - cryst->offset_h;
+                               y_coor2 =cryst->win_height - cryst->offset_h;
+                            }
+                          else
+                            {
+                               y_coor1 =(int) (iny * cryst->b *
+                                               cos((cryst->gamma - 90) *
+                                                   PI_RAD)) + cryst->offset_h;
+                               y_coor2 =cryst->offset_h;
+                            }
                                XDrawLine(display, window, cryst->gc,
                                          (int) (cryst->offset_w +
                                     inx * cryst->a - (int) (iny * cryst->b *
                                         sin((cryst->gamma - 90) * PI_RAD))),
-                                         (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
-                                         cryst->offset_w + inx * cryst->a, cryst->offset_h);
+                                         y_coor1,
+                                         cryst->offset_w + inx * cryst->a,
+                                         y_coor2);
                        }
                } else {
                        int         inx, iny;
 
                        inx = NRAND(cryst->nx);
                        iny = NRAND(cryst->ny);
+                  if ( cryst->invert )
+                    {
+                       y_coor1 =cryst->win_height -
+                         (int) (iny * cryst->b *
+                                                 cos((cryst->gamma - 90) *
+                                                     PI_RAD)) -
+                         cryst->offset_h;
+                       y_coor2 =cryst->win_height -
+                         (int) ( ( iny + 1 ) * cryst->b *
+                                                 cos((cryst->gamma - 90) *
+                                                     PI_RAD)) -
+                         cryst->offset_h;
+                    }
+                  else
+                    {
+                       y_coor1 =(int) (iny * cryst->b *
+                                                 cos((cryst->gamma - 90) *
+                                                     PI_RAD)) +
+                         cryst->offset_h;
+                       y_coor2 =(int) (( iny + 1 ) * cryst->b *
+                                                 cos((cryst->gamma - 90) *
+                                                     PI_RAD)) +
+                         cryst->offset_h;
+                    }
                        XDrawLine(display, window, cryst->gc,
                                  cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
+                                 y_coor1,
                                  cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
+                                 y_coor1);
                        XDrawLine(display, window, cryst->gc,
                                  cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
+                                 y_coor1,
                                  cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
+                                 y_coor2);
                        XDrawLine(display, window, cryst->gc,
                                  cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
+                                 y_coor1,
                                  cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
+                                 y_coor2);
                        XDrawLine(display, window, cryst->gc,
                                  cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
+                                 y_coor2,
                                  cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
+                                 y_coor2);
                }
        }
        for (i = 0; i < cryst->num_atom; i++) {
                crystalatom *atom0;
 
                atom0 = &cryst->atom[i];
-               XSetForeground(display, cryst->gc, atom0->colour);
+               if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
+                       XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
+               } else {
+                       XSetForeground(display, cryst->gc, atom0->colour);
+               }
                crystal_drawatom(mi, atom0);
        }
        XSetFunction(display, cryst->gc, GXcopy);
@@ -657,6 +796,21 @@ release_crystal(ModeInfo * mi)
                for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
                        crystalstruct *cryst = &crystals[screen];
 
+                       if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
+                               MI_WHITE_PIXEL(mi) = cryst->whitepixel;
+                               MI_BLACK_PIXEL(mi) = cryst->blackpixel;
+#ifndef STANDALONE
+                               MI_FG_PIXEL(mi) = cryst->fg;
+                               MI_BG_PIXEL(mi) = cryst->bg;
+#endif
+                               if (cryst->colors && cryst->ncolors && !cryst->no_colors)
+                                       free_colors(display, cryst->cmap, cryst->colors, cryst->ncolors);
+                               if (cryst->colors)
+                                       (void) free((void *) cryst->colors);
+#if 0 /* #### wrong! -jwz */
+                               XFreeColormap(display, cryst->cmap);
+#endif
+                       }
                        if (cryst->gc != NULL)
                                XFreeGC(display, cryst->gc);
                        if (cryst->atom != NULL)
@@ -687,6 +841,42 @@ init_crystal(ModeInfo * mi)
        cryst = &crystals[MI_SCREEN(mi)];
 
        if (!cryst->gc) {
+               if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
+                       XColor      color;
+
+#ifndef STANDALONE
+                       extern char *background;
+                       extern char *foreground;
+
+                       cryst->fg = MI_FG_PIXEL(mi);
+                       cryst->bg = MI_BG_PIXEL(mi);
+#endif
+                       cryst->blackpixel = MI_BLACK_PIXEL(mi);
+                       cryst->whitepixel = MI_WHITE_PIXEL(mi);
+#if 0 /* #### wrong! -jwz */
+                       cryst->cmap = XCreateColormap(display, window,
+                                                  MI_VISUAL(mi), AllocNone);
+                       XSetWindowColormap(display, window, cryst->cmap);
+#else
+            cryst->cmap = mi->xgwa.colormap;
+#endif
+                       (void) XParseColor(display, cryst->cmap, "black", &color);
+                       (void) XAllocColor(display, cryst->cmap, &color);
+                       MI_BLACK_PIXEL(mi) = color.pixel;
+                       (void) XParseColor(display, cryst->cmap, "white", &color);
+                       (void) XAllocColor(display, cryst->cmap, &color);
+                       MI_WHITE_PIXEL(mi) = color.pixel;
+#ifndef STANDALONE
+                       (void) XParseColor(display, cryst->cmap, background, &color);
+                       (void) XAllocColor(display, cryst->cmap, &color);
+                       MI_BG_PIXEL(mi) = color.pixel;
+                       (void) XParseColor(display, cryst->cmap, foreground, &color);
+                       (void) XAllocColor(display, cryst->cmap, &color);
+                       MI_FG_PIXEL(mi) = color.pixel;
+#endif
+                       cryst->colors = 0;
+                       cryst->ncolors = 0;
+               }
                if ((cryst->gc = XCreateGC(display, MI_WINDOW(mi),
                             (unsigned long) 0, (XGCValues *) NULL)) == None)
                        return;
@@ -696,7 +886,9 @@ init_crystal(ModeInfo * mi)
        cryst->painted = False;
        XSetFunction(display, cryst->gc, GXxor);
 
+
 /*Set up crystal data */
+       cryst->direction = (LRAND() & 1) ? 1 : -1;
        if (MI_IS_FULLRANDOM(mi)) {
                if (LRAND() & 1)
                        cryst->unit_cell = True;
@@ -718,6 +910,7 @@ init_crystal(ModeInfo * mi)
        cell_min = min(cryst->win_width / 2 + 1, MIN_CELL);
        cell_min = min(cell_min, cryst->win_height / 2 + 1);
        cryst->planegroup = NRAND(17);
+        cryst->invert = NRAND(2);
        if (MI_IS_VERBOSE(mi))
                (void) fprintf(stdout, "Selected plane group no %d\n",
                               cryst->planegroup + 1);
@@ -811,7 +1004,7 @@ init_crystal(ModeInfo * mi)
                        if (cryst->gamma > 90.0) {
                                if (cryst->offset_w > 0)
                                        cryst->offset_w = NRAND(cryst->offset_w) +
-                                               cryst->b * sin((cryst->gamma - 90) * PI_RAD);
+                                               (int) (cryst->b * sin((cryst->gamma - 90) * PI_RAD));
                                else
                                        cryst->offset_w = (int) (cryst->b * sin((cryst->gamma - 90) *
                                                                    PI_RAD));
@@ -833,78 +1026,218 @@ init_crystal(ModeInfo * mi)
        cryst->a = cryst->a / cryst->nx;
        cryst->b = cryst->b / cryst->ny;
        if (cryst->unit_cell) {
+          int y_coor1 , y_coor2;
+          
                if (MI_NPIXELS(mi) > 2)
                        XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
                else
-                       XSetForeground(display, cryst->gc, MI_BLACK_PIXEL(mi));
+                       XSetForeground(display, cryst->gc, MI_WHITE_PIXEL(mi));
                if (cryst->grid_cell) {
                        int         inx, iny;
 
+                  if ( cryst->invert )
+                    y_coor1 = y_coor2 = cryst->win_height - cryst->offset_h;
+                  else
+                    y_coor1 = y_coor2 = cryst->offset_h;
                        XDrawLine(display, window, cryst->gc, cryst->offset_w,
-                                 cryst->offset_h, cryst->offset_w + cryst->nx * cryst->a,
-                                 cryst->offset_h);
+                                 y_coor1, cryst->offset_w + cryst->nx * cryst->a,
+                                 y_coor2);
+                  if ( cryst->invert )
+                    {
+                       y_coor1 = cryst->win_height - cryst->offset_h;
+                       y_coor2 = cryst->win_height - (int) (cryst->ny *
+                                                            cryst->b *
+                                        cos((cryst->gamma - 90) * PI_RAD)) -
+                         cryst->offset_h;
+                    }
+                  else
+                    {
+                       y_coor1 = cryst->offset_h;
+                       y_coor2 = (int) (cryst->ny * cryst->b *
+                                        cos((cryst->gamma - 90) * PI_RAD)) +
+                         cryst->offset_h;
+                    }
                        XDrawLine(display, window, cryst->gc, cryst->offset_w,
-                                 cryst->offset_h, (int) (cryst->offset_w - cryst->ny * cryst->b *
+                                 y_coor1, (int) (cryst->offset_w - cryst->ny * cryst->b *
                                          sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) (cryst->ny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
+                                 y_coor2);
                        inx = cryst->nx;
                        for (iny = 1; iny <= cryst->ny; iny++) {
+                  if ( cryst->invert )
+                    {
+                       y_coor1 = cryst->win_height -
+                         (int) (iny * cryst->b * cos((cryst->gamma - 90) *
+                                                 PI_RAD)) - cryst->offset_h;
+                       y_coor2 = cryst->win_height -
+                         (int) (iny * cryst->b * cos((cryst->gamma - 90) *
+                                                     PI_RAD)) -
+                         cryst->offset_h;
+                    }
+                  else
+                    {
+                       y_coor1 = (int) (iny * cryst->b * cos((cryst->gamma - 90) *
+                                                 PI_RAD)) + cryst->offset_h;
+                       y_coor2 = (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
+                                         cryst->offset_h;
+                    }
                                XDrawLine(display, window, cryst->gc,
                                          (int) (cryst->offset_w +
                                     inx * cryst->a - (int) (iny * cryst->b *
                                         sin((cryst->gamma - 90) * PI_RAD))),
-                                         (int) (iny * cryst->b * cos((cryst->gamma - 90) *
-                                                 PI_RAD)) + cryst->offset_h,
+                                         y_coor1,
                                    (int) (cryst->offset_w - iny * cryst->b *
                                           sin((cryst->gamma - 90) * PI_RAD)),
-                                         (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
-                                         cryst->offset_h);
+                                         y_coor2);
                        }
                        iny = cryst->ny;
                        for (inx = 1; inx <= cryst->nx; inx++) {
+                          if ( cryst->invert )
+                            {
+                               y_coor1 =cryst->win_height -
+                                 (int) (iny * cryst->b *
+                                               cos((cryst->gamma - 90) *
+                                                   PI_RAD)) - cryst->offset_h;
+                               y_coor2 =cryst->win_height - cryst->offset_h;
+                            }
+                          else
+                            {
+                               y_coor1 =(int) (iny * cryst->b *
+                                               cos((cryst->gamma - 90) *
+                                                   PI_RAD)) + cryst->offset_h;
+                               y_coor2 =cryst->offset_h;
+                            }
                                XDrawLine(display, window, cryst->gc,
                                          (int) (cryst->offset_w +
                                     inx * cryst->a - (int) (iny * cryst->b *
                                         sin((cryst->gamma - 90) * PI_RAD))),
-                                         (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
-                                         cryst->offset_w + inx * cryst->a, cryst->offset_h);
+                                         y_coor1,
+                                         cryst->offset_w + inx * cryst->a,
+                                         y_coor2);
                        }
                } else {
                        int         inx, iny;
 
                        inx = NRAND(cryst->nx);
                        iny = NRAND(cryst->ny);
+                  if ( cryst->invert )
+                    {
+                       y_coor1 =cryst->win_height -
+                         (int) (iny * cryst->b *
+                                                 cos((cryst->gamma - 90) *
+                                                     PI_RAD)) -
+                         cryst->offset_h;
+                       y_coor2 =cryst->win_height -
+                         (int) ( ( iny + 1 ) * cryst->b *
+                                                 cos((cryst->gamma - 90) *
+                                                     PI_RAD)) -
+                         cryst->offset_h;
+                    }
+                  else
+                    {
+                       y_coor1 =(int) (iny * cryst->b *
+                                                 cos((cryst->gamma - 90) *
+                                                     PI_RAD)) +
+                         cryst->offset_h;
+                       y_coor2 =(int) (( iny + 1 ) * cryst->b *
+                                                 cos((cryst->gamma - 90) *
+                                                     PI_RAD)) +
+                         cryst->offset_h;
+                    }
                        XDrawLine(display, window, cryst->gc,
                                  cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
+                                 y_coor1,
                                  cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
+                                 y_coor1);
                        XDrawLine(display, window, cryst->gc,
                                  cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
+                                 y_coor1,
                                  cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
+                                 y_coor2);
                        XDrawLine(display, window, cryst->gc,
                                  cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
+                                 y_coor1,
                                  cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
+                                 y_coor2);
                        XDrawLine(display, window, cryst->gc,
                                  cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
+                                 y_coor2,
                                  cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
-                                 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
+                                 y_coor2);
+               }
+       }
+       if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
+/* Set up colour map */
+               if (cryst->colors && cryst->ncolors && !cryst->no_colors)
+                       free_colors(display, cryst->cmap, cryst->colors, cryst->ncolors);
+               if (cryst->colors)
+                       (void) free((void *) cryst->colors);
+               cryst->colors = 0;
+               cryst->ncolors = MI_NCOLORS(mi);
+               if (cryst->ncolors < 2)
+                       cryst->ncolors = 2;
+               if (cryst->ncolors <= 2)
+                       cryst->mono_p = True;
+               else
+                       cryst->mono_p = False;
+
+               if (cryst->mono_p)
+                       cryst->colors = 0;
+               else
+                       cryst->colors = (XColor *) malloc(sizeof (*cryst->colors) * (cryst->ncolors + 1));
+               cryst->cycle_p = has_writable_cells(mi->xgwa.screen, MI_VISUAL(mi));
+               if (cryst->cycle_p) {
+                       if (MI_IS_FULLRANDOM(mi)) {
+                               if (!NRAND(8))
+                                       cryst->cycle_p = False;
+                               else
+                                       cryst->cycle_p = True;
+                       } else {
+                               cryst->cycle_p = cycle_p;
+                       }
+               }
+               if (!cryst->mono_p) {
+                       if (!(LRAND() % 10))
+                               make_random_colormap(MI_DISPLAY(mi), MI_VISUAL(mi), cryst->cmap, cryst->colors, &cryst->ncolors,
+                                               True, True, &cryst->cycle_p, True);
+                       else if (!(LRAND() % 2))
+                               make_uniform_colormap(MI_DISPLAY(mi), MI_VISUAL(mi), cryst->cmap, cryst->colors, &cryst->ncolors,
+                                                     True, &cryst->cycle_p, True);
+                       else
+                               make_smooth_colormap(MI_DISPLAY(mi), MI_VISUAL(mi), cryst->cmap, cryst->colors, &cryst->ncolors,
+                                                    True, &cryst->cycle_p, True);
                }
+#if 0 /* #### wrong! -jwz */
+               XInstallColormap(display, cryst->cmap);
+#endif
+               if (cryst->ncolors < 2) {
+                       cryst->ncolors = 2;
+                       cryst->no_colors = True;
+               } else
+                       cryst->no_colors = False;
+               if (cryst->ncolors <= 2)
+                       cryst->mono_p = True;
+
+               if (cryst->mono_p)
+                       cryst->cycle_p = False;
+
        }
        for (i = 0; i < cryst->num_atom; i++) {
                crystalatom *atom0;
 
                atom0 = &cryst->atom[i];
-               if (MI_NPIXELS(mi) > 2)
-                       atom0->colour = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
-               else
-                       atom0->colour = 1;      /*Xor'red so WHITE may not be appropriate */
-               XSetForeground(display, cryst->gc, atom0->colour);
+               if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
+                       if (cryst->ncolors > 2)
+                               atom0->colour = NRAND(cryst->ncolors - 2) + 2;
+                       else
+                               atom0->colour = 1;      /* Just in case */
+                       XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
+               } else {
+                       if (MI_NPIXELS(mi) > 2)
+                               atom0->colour = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
+                       else
+                               atom0->colour = 1;      /*Xor'red so WHITE may not be appropriate */
+                       XSetForeground(display, cryst->gc, atom0->colour);
+               }
                atom0->x0 = NRAND(cryst->a);
                atom0->y0 = NRAND(cryst->b);
                atom0->velocity[0] = NRAND(7) - 3;
@@ -926,5 +1259,6 @@ init_crystal(ModeInfo * mi)
                crystal_setupatom(atom0, cryst->gamma);
                crystal_drawatom(mi, atom0);
        }
+       XSync(display, False);
        XSetFunction(display, cryst->gc, GXcopy);
 }