X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fdeco.c;h=69085525a029f9ece95185a471c761628e6b7a95;hp=6e3612fa23ef11a8c92e81037b07e817a3176c6e;hb=488f2fa8fbdbc77e91a70da2962d73af49e6cace;hpb=c8c6deae79b408cffbc88043c766b3bc12cf0f13 diff --git a/hacks/deco.c b/hacks/deco.c index 6e3612fa..69085525 100644 --- a/hacks/deco.c +++ b/hacks/deco.c @@ -11,6 +11,15 @@ * * Concept snarfed from Michael D. Bayne in * http://www.go2net.com/internet/deep/1997/04/16/body.html + * + * Changes by Lars Huttar, http://www.huttar.net: + * - allow use of golden ratio for dividing rectangles instead of 1/2. + * - allow smooth colors instead of random + * - added line thickness setting + * - added "Mondrian" mode + * Other ideas: + * - allow recomputing the colormap on each new frame (especially useful + * when ncolors is low) */ #include "screenhack.h" @@ -22,12 +31,131 @@ struct state { int max_depth; int min_height; int min_width; + int line_width; + int old_line_width; + Bool goldenRatio; + Bool mondrian; + Bool smoothColors; + int delay; XWindowAttributes xgwa; GC fgc, bgc; int current_color; }; +/* Golden Ratio + * Suppose you're dividing a rectangle of length A+B + * into two parts, of length A and B respectively. You want the ratio of + * A to B to be the same as the ratio of the whole (A+B) to A. The golden + * ratio (phi) is that ratio. Supposed to be visually pleasing. */ +#define PHI 1.61803 +#define PHI1 (1.0/PHI) +#define PHI2 (1.0 - PHI1) + +/* copied from make_random_colormap in colors.c */ +static void +make_mondrian_colormap (Display *dpy, Visual *visual, Colormap cmap, + XColor *colors, int *ncolorsP, + Bool allocate_p, + Bool *writable_pP, + Bool verbose_p) +{ + Bool wanted_writable = (allocate_p && writable_pP && *writable_pP); + int ncolors = 8; + int i; + Screen *screen = (dpy ? DefaultScreenOfDisplay(dpy) : 0); /* #### WRONG! */ + + if (*ncolorsP <= 0) return; + + /* If this visual doesn't support writable cells, don't bother trying. */ + if (wanted_writable && !has_writable_cells(screen, visual)) + *writable_pP = False; + + for (i = 0; i < ncolors; i++) + { + colors[i].flags = DoRed|DoGreen|DoBlue; + colors[i].red = 0; + colors[i].green = 0; + colors[i].blue = 0; + + switch(i) { + case 0: case 1: case 2: case 3: case 7: /* white */ + colors[i].red = 0xE800; + colors[i].green = 0xE800; + colors[i].blue = 0xE800; + break; + case 4: + colors[i].red = 0xCFFF; break; /* red */ + case 5: + colors[i].red = 0x2000; + colors[i].blue = 0xCFFF; break; /* blue */ + case 6: + colors[i].red = 0xDFFF; /* yellow */ + colors[i].green = 0xCFFF; break; + } + } + + if (!allocate_p) + return; + + RETRY_NON_WRITABLE: + if (writable_pP && *writable_pP) + { + unsigned long *pixels = (unsigned long *) + malloc(sizeof(*pixels) * (ncolors + 1)); + + allocate_writable_colors (dpy, cmap, pixels, &ncolors); + if (ncolors > 0) + for (i = 0; i < ncolors; i++) + colors[i].pixel = pixels[i]; + free (pixels); + if (ncolors > 0) + XStoreColors (dpy, cmap, colors, ncolors); + } + else + { + for (i = 0; i < ncolors; i++) + { + XColor color; + color = colors[i]; + if (!XAllocColor (dpy, cmap, &color)) + break; + colors[i].pixel = color.pixel; + } + ncolors = i; + } + + /* If we tried for writable cells and got none, try for non-writable. */ + if (allocate_p && ncolors == 0 && writable_pP && *writable_pP) + { + ncolors = *ncolorsP; + *writable_pP = False; + goto RETRY_NON_WRITABLE; + } + +#if 0 + /* I don't think we need to bother copying or linking to the complain + function. */ + if (verbose_p) + complain(*ncolorsP, ncolors, wanted_writable, + wanted_writable && *writable_pP); +#endif + + *ncolorsP = ncolors; +} + +static void +mondrian_set_sizes (struct state *st, int w, int h) +{ + if (w > h) { + st->line_width = w/50; + st->min_height = st->min_width = w/8; + } else { + st->line_width = h/50; + st->min_height = st->min_width = h/8; + } +} + static void deco (Display *dpy, Window window, struct state *st, int x, int y, int w, int h, int depth) @@ -45,15 +173,17 @@ deco (Display *dpy, Window window, struct state *st, } else { - if (random() & 1) - { - deco (dpy, window, st, x, y, w/2, h, depth+1); - deco (dpy, window, st, x+w/2, y, w/2, h, depth+1); + if ((st->goldenRatio || st->mondrian) ? (w > h) : (random() & 1)) + { /* Divide the rectangle side-by-side */ + int wnew = (st->goldenRatio ? (w * (random() & 1 ? PHI1 : PHI2)) : w/2); + deco (dpy, window, st, x, y, wnew, h, depth+1); + deco (dpy, window, st, x+wnew, y, w-wnew, h, depth+1); } else - { - deco (dpy, window, st, x, y, w, h/2, depth+1); - deco (dpy, window, st, x, y+h/2, w, h/2, depth+1); + { /* Divide the rectangle top-to-bottom */ + int hnew = (st->goldenRatio ? (h * (random() & 1 ? PHI1 : PHI2)) : h/2); + deco (dpy, window, st, x, y, w, hnew, depth+1); + deco (dpy, window, st, x, y+hnew, w, h-hnew, depth+1); } } } @@ -66,6 +196,11 @@ deco_init (Display *dpy, Window window) st->delay = get_integer_resource (dpy, "delay", "Integer"); + st->smoothColors = get_boolean_resource(dpy, "smoothColors", "Boolean"); + st->old_line_width = 1; + + st->goldenRatio = get_boolean_resource (dpy, "goldenRatio", "Boolean"); + st->max_depth = get_integer_resource (dpy, "maxDepth", "Integer"); if (st->max_depth < 1) st->max_depth = 1; else if (st->max_depth > 1000) st->max_depth = 1000; @@ -75,8 +210,12 @@ deco_init (Display *dpy, Window window) st->min_height = get_integer_resource (dpy, "minHeight", "Integer"); if (st->min_height < 2) st->min_height = 2; + st->line_width = get_integer_resource (dpy, "lineWidth", "Integer"); + XGetWindowAttributes (dpy, window, &st->xgwa); + st->ncolors = get_integer_resource (dpy, "ncolors", "Integer"); + gcv.foreground = get_pixel_resource(dpy, st->xgwa.colormap, "foreground", "Foreground"); st->fgc = XCreateGC (dpy, window, GCForeground, &gcv); @@ -85,11 +224,6 @@ deco_init (Display *dpy, Window window) "background", "Background"); st->bgc = XCreateGC (dpy, window, GCForeground, &gcv); - st->ncolors = get_integer_resource (dpy, "ncolors", "Integer"); - - make_random_colormap (dpy, st->xgwa.visual, st->xgwa.colormap, st->colors, &st->ncolors, - False, True, 0, True); - if (st->ncolors <= 2) mono_p = True; @@ -100,6 +234,28 @@ deco_init (Display *dpy, Window window) st->bgc = tmp; } + st->mondrian = get_boolean_resource(dpy, "mondrian", "Boolean"); + if (st->mondrian) { + /* Mondrian, if true, overrides several other options. */ + mondrian_set_sizes(st, st->xgwa.width, st->xgwa.height); + + /** set up red-yellow-blue-black-white colormap and fgc **/ + make_mondrian_colormap(dpy, st->xgwa.visual, st->xgwa.colormap, + st->colors, &st->ncolors, True, 0, True); + + /** put white in several cells **/ + /** set min-height and min-width to about 10% of total w/h **/ + } + else if (st->smoothColors) + make_smooth_colormap (dpy, st->xgwa.visual, st->xgwa.colormap, + st->colors, &st->ncolors, True, 0, True); + else + make_random_colormap (dpy, st->xgwa.visual, st->xgwa.colormap, + st->colors, &st->ncolors, False, True, 0, True); + + gcv.line_width = st->old_line_width = st->line_width; + XChangeGC(dpy, st->fgc, GCLineWidth, &gcv); + return st; } @@ -108,6 +264,14 @@ deco_draw (Display *dpy, Window window, void *closure) { struct state *st = (struct state *) closure; XFillRectangle (dpy, window, st->bgc, 0, 0, st->xgwa.width, st->xgwa.height); + if (st->mondrian) { + mondrian_set_sizes(st, st->xgwa.width, st->xgwa.height); + if (st->line_width != st->old_line_width) { + XSetLineAttributes(dpy, st->fgc, st->line_width, + LineSolid, CapButt, JoinBevel); + st->old_line_width = st->line_width; + } + } deco (dpy, window, st, 0, 0, st->xgwa.width, st->xgwa.height, 0); return 1000000 * st->delay; } @@ -141,8 +305,12 @@ static const char *deco_defaults [] = { "*maxDepth: 12", "*minWidth: 20", "*minHeight: 20", + "*lineWidth: 1", "*delay: 5", "*ncolors: 64", + "*goldenRatio: False", + "*smoothColors: False", + "*mondrian: False", 0 }; @@ -150,8 +318,15 @@ static XrmOptionDescRec deco_options [] = { { "-max-depth", ".maxDepth", XrmoptionSepArg, 0 }, { "-min-width", ".minWidth", XrmoptionSepArg, 0 }, { "-min-height", ".minHeight", XrmoptionSepArg, 0 }, + { "-line-width", ".lineWidth", XrmoptionSepArg, 0 }, { "-delay", ".delay", XrmoptionSepArg, 0 }, { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, + { "-golden-ratio", ".goldenRatio", XrmoptionNoArg, "True" }, + { "-no-golden-ratio", ".goldenRatio", XrmoptionNoArg, "False" }, + { "-smooth-colors", ".smoothColors",XrmoptionNoArg, "True" }, + { "-no-smooth-colors",".smoothColors",XrmoptionNoArg, "False" }, + { "-mondrian", ".mondrian", XrmoptionNoArg, "True" }, + { "-no-mondrian", ".mondrian", XrmoptionNoArg, "False" }, { 0, 0, 0, 0 } };