http://ftp.aanet.ru/pub/Linux/X11/apps/xscreensaver-2.31.tar.gz
[xscreensaver] / hacks / crystal.c
index caab2a894a4849dd8e52ddf0313a0dc161e1891f..4c4d5fbe61707bd8d44c9e00b1801c3c82560917 100644 (file)
@@ -2,7 +2,7 @@
 /* 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";
+static const char sccsid[] = "@(#)crystal.c    4.12 98/09/10 xlockmore";
 
 #endif
 
@@ -28,6 +28,7 @@ static const char sccsid[] = "@(#)crystal.c   4.07 97/11/24 xlockmore";
  * A moving polygon-mode. The polygons obey 2D-planegroup symmetry.
  *
  * Revision History:
+ * 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 +36,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,7 +71,7 @@ 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 */
@@ -86,12 +87,15 @@ 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))
 
+void release_crystal(ModeInfo * mi);
+
 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[] =
 {
@@ -104,7 +108,9 @@ static XrmOptionDescRec opts[] =
        {"-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"}
+       {"+grid", ".crystal.grid", XrmoptionNoArg, (caddr_t) "off"},
+       {"-shift", ".crystal.shift", XrmoptionNoArg, (caddr_t) "on"},
+       {"+shift", ".crystal.shift", XrmoptionNoArg, (caddr_t) "off"}
 };
 
 static argtype vars[] =
@@ -114,16 +120,18 @@ static argtype vars[] =
        {(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}
+       {(caddr_t *) & grid_cell, "grid", "Grid", DEF_GRID, t_Bool},
+       {(caddr_t *) & 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 +254,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;
 } crystalstruct;
 
 static crystalstruct *crystals = NULL;
@@ -527,13 +541,27 @@ 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);
+               XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
                crystal_drawatom(mi, atom0);
                atom0->velocity[0] += NRAND(3) - 1;
                atom0->velocity[0] = MAX(-20, MIN(20, atom0->velocity[0]));
@@ -640,7 +668,7 @@ refresh_crystal(ModeInfo * mi)
                crystalatom *atom0;
 
                atom0 = &cryst->atom[i];
-               XSetForeground(display, cryst->gc, atom0->colour);
+               XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
                crystal_drawatom(mi, atom0);
        }
        XSetFunction(display, cryst->gc, GXcopy);
@@ -657,6 +685,17 @@ release_crystal(ModeInfo * mi)
                for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
                        crystalstruct *cryst = &crystals[screen];
 
+                       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);
+                       XFreeColormap(display, cryst->cmap);
                        if (cryst->gc != NULL)
                                XFreeGC(display, cryst->gc);
                        if (cryst->atom != NULL)
@@ -687,6 +726,42 @@ init_crystal(ModeInfo * mi)
        cryst = &crystals[MI_SCREEN(mi)];
 
        if (!cryst->gc) {
+#ifndef STANDALONE
+               XColor      color;
+
+               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);
+
+#ifdef STANDALONE
+               cryst->cmap = mi->xgwa.colormap;
+#else /* !STANDALONE */
+               cryst->cmap = XCreateColormap(display, window,
+                                             MI_VISUAL(mi), AllocNone);
+               XSetWindowColormap(display, window, cryst->cmap);
+
+               (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;
+
+               (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 /* !STANDALONE */
+
+               cryst->colors = 0;
+               cryst->ncolors = 0;
                if ((cryst->gc = XCreateGC(display, MI_WINDOW(mi),
                             (unsigned long) 0, (XGCValues *) NULL)) == None)
                        return;
@@ -696,7 +771,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;
@@ -811,7 +888,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));
@@ -896,15 +973,105 @@ init_crystal(ModeInfo * mi)
                                  (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
                }
        }
+/* 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;
+#ifdef STANDALONE
+       cryst->ncolors = get_integer_resource("ncolors", "Integer");
+#else
+       cryst->ncolors = MI_NCOLORS(mi);
+#endif
+       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));
+#ifdef STANDALONE
+       cryst->cycle_p = has_writable_cells(mi->xgwa.screen, mi->xgwa.visual);
+#else
+       cryst->cycle_p = has_writable_cells(mi);
+#endif
+       if (cryst->cycle_p) {
+               if (MI_IS_FULLRANDOM(mi)) {
+                       if (NRAND(8) == 7)
+                               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(
+#ifdef STANDALONE
+                                                                mi->dpy, mi->xgwa.visual,
+#else
+                                                                mi,
+#endif
+                                                                cryst->cmap, cryst->colors, &cryst->ncolors,
+                                                                True, True, &cryst->cycle_p
+#ifdef STANDALONE
+                                                                , False
+#endif
+                                                                );
+               else if (!(LRAND() % 2))
+                       make_uniform_colormap(
+#ifdef STANDALONE
+                                                                 mi->dpy, mi->xgwa.visual,
+#else
+                                                                mi,
+#endif
+                                                                 cryst->cmap, cryst->colors, &cryst->ncolors,
+                                                                 True, &cryst->cycle_p
+#ifdef STANDALONE
+                                                                , False
+#endif
+                                                                );
+               else
+                       make_smooth_colormap(
+#ifdef STANDALONE
+                                                                mi->dpy, mi->xgwa.visual,
+#else
+                                                                mi,
+#endif
+                                                                cryst->cmap, cryst->colors, &cryst->ncolors,
+                                                                True, &cryst->cycle_p
+#ifdef STANDALONE
+                                                                , False
+#endif
+                                                                );
+       }
+       XInstallColormap(display, cryst->cmap);
+       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)));
+               if (cryst->ncolors > 2)
+                       atom0->colour = NRAND(cryst->ncolors - 2) + 2;
                else
                        atom0->colour = 1;      /*Xor'red so WHITE may not be appropriate */
-               XSetForeground(display, cryst->gc, atom0->colour);
+               XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
                atom0->x0 = NRAND(cryst->a);
                atom0->y0 = NRAND(cryst->b);
                atom0->velocity[0] = NRAND(7) - 3;
@@ -926,5 +1093,6 @@ init_crystal(ModeInfo * mi)
                crystal_setupatom(atom0, cryst->gamma);
                crystal_drawatom(mi, atom0);
        }
+       XSync(display, False);
        XSetFunction(display, cryst->gc, GXcopy);
 }