summaryrefslogtreecommitdiffstats
path: root/hacks/cynosure.c
diff options
context:
space:
mode:
authorSimon Rettberg2018-10-16 10:08:48 +0200
committerSimon Rettberg2018-10-16 10:08:48 +0200
commitd3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch)
treecbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /hacks/cynosure.c
downloadxscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip
Original 5.40
Diffstat (limited to 'hacks/cynosure.c')
-rw-r--r--hacks/cynosure.c443
1 files changed, 443 insertions, 0 deletions
diff --git a/hacks/cynosure.c b/hacks/cynosure.c
new file mode 100644
index 0000000..8b8b85b
--- /dev/null
+++ b/hacks/cynosure.c
@@ -0,0 +1,443 @@
+/* cynosure --- draw some rectangles
+ *
+ * 01-aug-96: written in Java by ozymandias G desiderata <ogd@organic.com>
+ * 25-dec-97: ported to C and XScreenSaver by Jamie Zawinski <jwz@jwz.org>
+ *
+ * Original version:
+ * http://www.organic.com/staff/ogd/java/cynosure.html
+ * http://www.organic.com/staff/ogd/java/source/cynosure/Cynosure-java.txt
+ *
+ * Original comments and copyright:
+ *
+ * Cynosure.java
+ * A Java implementation of Stephen Linhart's Cynosure screen-saver as a
+ * drop-in class.
+ *
+ * Header: /home/ogd/lib/cvs/aoaioxxysz/graphics/Cynosure.java,v 1.2 1996/08/02 02:41:21 ogd Exp
+ *
+ * ozymandias G desiderata <ogd@organic.com>
+ * Thu Aug 1 1996
+ *
+ * COPYRIGHT NOTICE
+ *
+ * Copyright 1996 ozymandias G desiderata. Title, ownership rights, and
+ * intellectual property rights in and to this software remain with
+ * ozymandias G desiderata. This software may be copied, modified,
+ * or used as long as this copyright is retained. Use this code at your
+ * own risk.
+ *
+ * Revision: 1.2
+ *
+ * Log: Cynosure.java,v
+ * Revision 1.2 1996/08/02 02:41:21 ogd
+ * Added a few more comments, fixed messed-up header.
+ *
+ * Revision 1.1.1.1 1996/08/02 02:30:45 ogd
+ * First version
+ */
+
+#include "screenhack.h"
+
+/* #define DO_STIPPLE */
+
+struct state {
+ Display *dpy;
+ Window window;
+
+ XColor *colors;
+ int ncolors;
+
+#ifndef DO_STIPPLE
+ XColor *colors2;
+ int ncolors2;
+#endif
+
+ int fg_pixel, bg_pixel;
+ GC fg_gc, bg_gc, shadow_gc;
+
+ int curColor;
+ int curBase; /* color progression */
+ int shadowWidth;
+ int elevation; /* offset of dropshadow */
+ int sway; /* time until base color changed */
+ int timeLeft; /* until base color used */
+ int tweak; /* amount of color variance */
+ int gridSize;
+ int iterations, i, delay;
+ XWindowAttributes xgwa;
+};
+
+
+/**
+ * The smallest size for an individual cell.
+ **/
+#define MINCELLSIZE 16
+
+/**
+ * The narrowest a rectangle can be.
+ **/
+#define MINRECTSIZE 6
+
+/**
+ * Every so often genNewColor() generates a completely random
+ * color. This variable sets how frequently that happens. It's
+ * currently set to happen 1% of the time.
+ *
+ * @see #genNewColor
+ **/
+#define THRESHOLD 100 /*0.01*/
+
+static void paint(struct state *st);
+static int genNewColor(struct state *st);
+static int genConstrainedColor(struct state *st, int base, int tweak);
+static int c_tweak(struct state *st, int base, int tweak);
+
+
+static void *
+cynosure_init (Display *d, Window w)
+{
+ struct state *st = (struct state *) calloc (1, sizeof(*st));
+ XGCValues gcv;
+
+ st->dpy = d;
+ st->window = w;
+
+ st->curColor = 0;
+ st->curBase = st->curColor;
+ st->shadowWidth = get_integer_resource (st->dpy, "shadowWidth", "Integer");
+ st->elevation = get_integer_resource (st->dpy, "elevation", "Integer");
+ st->sway = get_integer_resource (st->dpy, "sway", "Integer");
+ st->tweak = get_integer_resource (st->dpy, "tweak", "Integer");
+ st->gridSize = get_integer_resource (st->dpy, "gridSize", "Integer");
+ st->timeLeft = 0;
+
+ XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+
+ st->ncolors = get_integer_resource (st->dpy, "colors", "Colors");
+ if (st->ncolors < 2) st->ncolors = 2;
+ if (st->ncolors <= 2) mono_p = True;
+
+ if (mono_p)
+ st->colors = 0;
+ else
+ st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1));
+
+ if (mono_p)
+ ;
+ else {
+ make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
+ st->colors, &st->ncolors,
+ True, 0, True);
+ if (st->ncolors <= 2) {
+ mono_p = True;
+ st->ncolors = 2;
+ if (st->colors) free(st->colors);
+ st->colors = 0;
+ }
+ }
+
+ st->bg_pixel = get_pixel_resource(st->dpy,
+ st->xgwa.colormap, "background", "Background");
+ st->fg_pixel = get_pixel_resource(st->dpy,
+ st->xgwa.colormap, "foreground", "Foreground");
+
+ gcv.foreground = st->fg_pixel;
+ st->fg_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
+ gcv.foreground = st->bg_pixel;
+ st->bg_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
+
+#ifdef DO_STIPPLE
+ gcv.fill_style = FillStippled;
+ gcv.stipple = XCreateBitmapFromData(st->dpy, st->window, "\125\252", 8, 2);
+ st->shadow_gc = XCreateGC(st->dpy, st->window, GCForeground|GCFillStyle|GCStipple, &gcv);
+ XFreePixmap(st->dpy, gcv.stipple);
+
+#else /* !DO_STIPPLE */
+ st->shadow_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
+
+# ifdef HAVE_JWXYZ /* allow non-opaque alpha components in pixel values */
+ jwxyz_XSetAlphaAllowed (st->dpy, st->shadow_gc, True);
+# endif
+
+ if (st->colors)
+ {
+ int i;
+ st->ncolors2 = st->ncolors;
+ st->colors2 = (XColor *) malloc(sizeof(*st->colors2) * (st->ncolors2+1));
+
+ for (i = 0; i < st->ncolors2; i++)
+ {
+# ifdef HAVE_JWXYZ
+ /* give a non-opaque alpha to the shadow colors */
+ unsigned long pixel = st->colors[i].pixel;
+ unsigned long amask = BlackPixelOfScreen (st->xgwa.screen);
+ unsigned long a = (0x77777777 & amask);
+ pixel = (pixel & (~amask)) | a;
+ st->colors2[i].pixel = pixel;
+# else /* !HAVE_JWXYZ */
+ int h;
+ double s, v;
+ rgb_to_hsv (st->colors[i].red,
+ st->colors[i].green,
+ st->colors[i].blue,
+ &h, &s, &v);
+ v *= 0.4;
+ hsv_to_rgb (h, s, v,
+ &st->colors2[i].red,
+ &st->colors2[i].green,
+ &st->colors2[i].blue);
+ st->colors2[i].pixel = st->colors[i].pixel;
+ XAllocColor (st->dpy, st->xgwa.colormap, &st->colors2[i]);
+# endif /* !HAVE_JWXYZ */
+ }
+ }
+# endif /* !DO_STIPPLE */
+
+ st->delay = get_integer_resource (st->dpy, "delay", "Delay");
+ st->iterations = get_integer_resource (st->dpy, "iterations", "Iterations");
+
+ return st;
+}
+
+static unsigned long
+cynosure_draw (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ if (st->iterations > 0 && ++st->i >= st->iterations)
+ {
+ st->i = 0;
+ if (!mono_p)
+ XSetWindowBackground(st->dpy, st->window,
+ st->colors[random() % st->ncolors].pixel);
+ XClearWindow(st->dpy, st->window);
+ }
+ paint(st);
+
+ return st->delay;
+}
+
+
+/**
+ * paint adds a new layer of multicolored rectangles within a grid of
+ * randomly generated size. Each row of rectangles is the same color,
+ * but colors vary slightly from row to row. Each rectangle is placed
+ * within a regularly-sized cell, but each rectangle is sized and
+ * placed randomly within that cell.
+ *
+ * @param g the Graphics coordinate in which to draw
+ * @see #genNewColor
+ **/
+static void paint(struct state *st)
+{
+ int i;
+ int cellsWide, cellsHigh, cellWidth, cellHeight;
+ int width = st->xgwa.width;
+ int height = st->xgwa.height;
+
+ /* How many cells wide the grid is (equal to gridSize +/- (gridSize / 2))
+ */
+ cellsWide = c_tweak(st, st->gridSize, st->gridSize / 2);
+ /* How many cells high the grid is (equal to gridSize +/- (gridSize / 2))
+ */
+ cellsHigh = c_tweak(st, st->gridSize, st->gridSize / 2);
+ /* How wide each cell in the grid is */
+ cellWidth = width / cellsWide;
+ /* How tall each cell in the grid is */
+ cellHeight = height / cellsHigh;
+
+ /* Ensure that each cell is above a certain minimum size */
+
+ if (cellWidth < MINCELLSIZE) {
+ cellWidth = MINCELLSIZE;
+ cellsWide = width / cellWidth;
+ }
+
+ if (cellHeight < MINCELLSIZE) {
+ cellHeight = MINCELLSIZE;
+ cellsHigh = width / cellWidth;
+ }
+
+ /* fill the grid with randomly-generated cells */
+ for(i = 0; i < cellsHigh; i++) {
+ int j;
+
+ /* Each row is a different color, randomly generated (but constrained) */
+ if (!mono_p)
+ {
+ int c = genNewColor(st);
+ XSetForeground(st->dpy, st->fg_gc, st->colors[c].pixel);
+# ifndef DO_STIPPLE
+ if (st->colors2)
+ XSetForeground(st->dpy, st->shadow_gc, st->colors2[c].pixel);
+# endif
+ }
+
+ for(j = 0; j < cellsWide; j++) {
+ int curWidth, curHeight, curX, curY;
+
+ /* Generate a random height for a rectangle and make sure that */
+ /* it's above a certain minimum size */
+ curHeight = random() % (cellHeight - st->shadowWidth);
+ if (curHeight < MINRECTSIZE)
+ curHeight = MINRECTSIZE;
+ /* Generate a random width for a rectangle and make sure that
+ it's above a certain minimum size */
+ curWidth = random() % (cellWidth - st->shadowWidth);
+ if (curWidth < MINRECTSIZE)
+ curWidth = MINRECTSIZE;
+ /* Figure out a random place to locate the rectangle within the
+ cell */
+ curY = (i * cellHeight) + (random() % ((cellHeight - curHeight) -
+ st->shadowWidth));
+ curX = (j * cellWidth) + (random() % ((cellWidth - curWidth) -
+ st->shadowWidth));
+
+ /* Draw the shadow */
+ if (st->elevation > 0)
+ XFillRectangle(st->dpy, st->window, st->shadow_gc,
+ curX + st->elevation, curY + st->elevation,
+ curWidth, curHeight);
+
+ /* Draw the edge */
+ if (st->shadowWidth > 0)
+ XFillRectangle(st->dpy, st->window, st->bg_gc,
+ curX + st->shadowWidth, curY + st->shadowWidth,
+ curWidth, curHeight);
+
+ XFillRectangle(st->dpy, st->window, st->fg_gc, curX, curY, curWidth, curHeight);
+
+ /* Draw a 1-pixel black border around the rectangle */
+ XDrawRectangle(st->dpy, st->window, st->bg_gc, curX, curY, curWidth, curHeight);
+ }
+
+ }
+}
+
+
+/**
+ * genNewColor returns a new color, gradually mutating the colors and
+ * occasionally returning a totally random color, just for variety.
+ *
+ * @return the new color
+ **/
+static int genNewColor(struct state *st)
+{
+ /* These lines handle "sway", or the gradual random changing of */
+ /* colors. After genNewColor() has been called a given number of */
+ /* times (specified by a random permutation of the tweak variable), */
+ /* take whatever color has been most recently randomly generated and */
+ /* make it the new base color. */
+ if (st->timeLeft == 0) {
+ st->timeLeft = c_tweak(st, st->sway, st->sway / 3);
+ st->curColor = st->curBase;
+ } else {
+ st->timeLeft--;
+ }
+
+ /* If a randomly generated number is less than the threshold value,
+ produce a "sport" color value that is completely unrelated to the
+ current palette. */
+ if (0 == (random() % THRESHOLD)) {
+ return (random() % st->ncolors);
+ } else {
+ st->curBase = genConstrainedColor(st, st->curColor, st->tweak);
+ return st->curBase;
+ }
+
+}
+
+/**
+ * genConstrainedColor creates a random new color within a certain
+ * range of an existing color. Right now this works with RGB color
+ * values, but a future version of the program will most likely use HSV
+ * colors, which should generate a more pleasing progression of values.
+ *
+ * @param base the color on which the new color will be based
+ * @param tweak the amount that the new color can be tweaked
+ * @return a new constrained color
+ * @see #genNewColor
+ **/
+static int genConstrainedColor(struct state *st, int base, int tweak)
+{
+ int i = 1 + (random() % st->tweak);
+ if (random() & 1)
+ i = -i;
+ i = (base + i) % st->ncolors;
+ while (i < 0)
+ i += st->ncolors;
+ return i;
+}
+
+/**
+ * Utility function to generate a tweaked color value
+ *
+ * @param base the byte value on which the color is based
+ * @param tweak the amount the value will be skewed
+ * @see #tweak
+ * @return the tweaked byte
+ **/
+static int c_tweak(struct state *st, int base, int tweak)
+{
+ int ranTweak = (random() % (2 * tweak));
+ int n = (base + (ranTweak - tweak));
+ if (n < 0) n = -n;
+ return (n < 255 ? n : 255);
+}
+
+static void
+cynosure_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
+{
+ struct state *st = (struct state *) closure;
+ st->xgwa.width = w;
+ st->xgwa.height = h;
+}
+
+static Bool
+cynosure_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+ struct state *st = (struct state *) closure;
+ if (screenhack_event_helper (dpy, window, event))
+ {
+ st->i = st->iterations;
+ return True;
+ }
+ return False;
+}
+
+static void
+cynosure_free (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ free (st);
+}
+
+
+static const char *cynosure_defaults [] = {
+ ".background: black",
+ ".foreground: white",
+ ".lowrez: true",
+ "*fpsSolid: true",
+ "*delay: 500000",
+ "*colors: 128",
+ "*iterations: 100",
+ "*shadowWidth: 2",
+ "*elevation: 5",
+ "*sway: 30",
+ "*tweak: 20",
+ "*gridSize: 12",
+#ifdef HAVE_MOBILE
+ "*ignoreRotation: True",
+#endif
+ 0
+};
+
+static XrmOptionDescRec cynosure_options [] = {
+ { "-delay", ".delay", XrmoptionSepArg, 0 },
+ { "-ncolors", ".colors", XrmoptionSepArg, 0 },
+ { "-iterations", ".iterations", XrmoptionSepArg, 0 },
+ { 0, 0, 0, 0 }
+};
+
+
+XSCREENSAVER_MODULE ("Cynosure", cynosure)