news@sun.Eng.Sun.COM (news) (08/31/90)
Submitted-by: reed!news Posting-number: Volume 9, Issue 12 Archive-name: dlaf/part01 #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -s ./README` then echo "writing ./README" cat > ./README << '\End\Of\Shar\' This generates a "Diffusion Limited Aggregate Fractal", as described in some issue of Scientific American last year or so. Lots of silly features have been added, and there are some optimizations for the default case (instead of letting the new particle wander all over an empty screen, we contrain it to a vicinity of the existing mass of particles). Other than being a memory pig and being poorly documented, it's a rather nice program. The -shape flag doesn't seem to work correctly -- something change after keith@expo made a few changes, and I haven't bothered to track it down. (Gee, that was great! I haven't been able to blame Keith for something in years. :-) ) Let's see... -lifetime sets the lifetime of a moving particle, -decay sets the lifetime of all the other particles. -expire is a synonym for one of these. -border controls the border around the already existing mass (the optimization I mentioned). -flash and -lightning are synonyms as well. Oh yeah, "q" lets you quit if you aren't running it in the root window. Comments, problems, and code to trost%reed@cse.ogi.edu. I haven't touched the code in months, though, so I'm not certain what the state of the internals is. Enjoy! \End\Of\Shar\ else echo "will not over write ./README" fi if [ `wc -c ./README | awk '{printf $1}'` -ne 1214 ] then echo `wc -c ./README | awk '{print "Got " $1 ", Expected " 1214}'` fi if `test ! -s ./Imakefile` then echo "writing ./Imakefile" cat > ./Imakefile << '\End\Of\Shar\' DEFINES = INCLUDES = -I$(TOP) -I$(TOP)/X11 DEPLIBS = $(DEPXLIB) LOCAL_LIBRARIES = $(XLIB) SYS_LIBRARIES = SRCS = addpoint.c args.c assert.c bits.c flags.c main.c usage.c OBJS = addpoint.o args.o assert.o bits.o flags.o main.o usage.o ComplexProgramTarget(xdla) \End\Of\Shar\ else echo "will not over write ./Imakefile" fi if [ `wc -c ./Imakefile | awk '{printf $1}'` -ne 263 ] then echo `wc -c ./Imakefile | awk '{print "Got " $1 ", Expected " 263}'` fi if `test ! -s ./Makefile.simple` then echo "writing ./Makefile.simple" cat > ./Makefile.simple << '\End\Of\Shar\' SRCS = addpoint.c args.c assert.c bits.c flags.c main.c usage.c OBJS = addpoint.o args.o assert.o bits.o flags.o main.o usage.o XLIB = -lX11 xdla: $(OBJS) $(CC) $(CFLAGS) -o $@ $(OBJS) $(XLIB) clean: rm -f $(OBJS) xdla addpoint.o: main.h args.o: main.h assert.o: bits.o: main.h flags.o: main.h main.o: main.h usage.o: main.h \End\Of\Shar\ else echo "will not over write ./Makefile.simple" fi if [ `wc -c ./Makefile.simple | awk '{printf $1}'` -ne 353 ] then echo `wc -c ./Makefile.simple | awk '{print "Got " $1 ", Expected " 353}'` fi if `test ! -s ./addpoint.c` then echo "writing ./addpoint.c" cat > ./addpoint.c << '\End\Of\Shar\' #include "main.h" static void DrawLightning(np) int np; { if (useroot) XLowerWindow(dpy, lightningWindow); XMapWindow(dpy, lightningWindow); XDrawPoints(dpy, lightningWindow, lgc, pl, np, CoordModeOrigin); } int AddPoint() { int x, y, dx = 0, dy = 0; int top_area, middle_area, bottom_area; int total_area; int a; int i; int np = 0; top_area = (curright - curleft) * curtop; middle_area = dla_width * (curbottom - curtop); bottom_area = (curright - curleft) * (dla_height - curbottom); total_area = top_area + middle_area + bottom_area; do { a = random() % total_area; if (a < top_area) { y = a / (curright - curleft); x = a % (curright - curleft) + curleft; } else if ((a -= top_area) < middle_area) { y = a / dla_width + curtop; x = a % dla_width; } else { a -= middle_area; y = a / (curright - curleft) + curbottom; x = a % (curright - curleft) + curleft; } } while (GetBit(x, y)); for (i = 0; (life == 0 || i < life) && !GetBit(x + dx, y + dy); i++) { if (lightning && np > 16000) { DrawLightning(np); np = 0; } if (lightning && (np == 0 || pl[np - 1].x != x || pl[np - 1].y != y)) { pl[np].x = x; pl[np++].y = y; } if ((x += dx) < curleft) x = curleft; else if (x > curright) x = curright; if ((y += dy) < curtop) y = curtop; else if (y > curbottom) y = curbottom; do { a = random () % 9; dx = (a % 3) - 1; dy = (a / 3) - 1; } while (folds == 4 && dx && dy); if (folds == 6 && dx) dy = 0; } SetBit(x, y); if (lightning) { DrawLightning(np); XFlush(dpy); XUnmapWindow(dpy, lightningWindow); } if (expire) { /* yes, this misses the corner, but close enough */ if (oldpoint[last].x != 0 || oldpoint[last].y != 0) { ResetBit(oldpoint[last].x, oldpoint[last].y); XClearArea(dpy, win, oldpoint[last].x - BORDER, oldpoint[last].y - BORDER, 1, 1, 0); } oldpoint[last].x = x; oldpoint[last++].y = y; last %= expire; } XDrawPoint(dpy, win, gc, x - BORDER, y - BORDER); /* compute new bounds */ if (x - BORDER < curleft) { curleft = x - BORDER; if (curleft <= 0) { curleft = 1; return 0; } } else if (x + BORDER > curright) { curright = x + BORDER; if (curright >= dla_width + 2 * BORDER - 1) { curright = dla_width + 2 * BORDER - 2; return 0; } } if (y - BORDER < curtop) { curtop = y - BORDER; if (curtop <= 0) { curtop = 1; return 0; } } else if (y + BORDER > curbottom) { curbottom = y + BORDER; if (curbottom >= dla_height + 2 * BORDER - 1) { curbottom = dla_height + 2 * BORDER - 2; return 0; } } return 1; } char* Bounds(n) int n; { static char buf[256]; int i, l = pl[0].x, r = pl[0].x, t = pl[0].y, b = pl[0].y; for (i = 1; i < n; i++) { if (pl[i].x < l) l = pl[i].x; else if (pl[i].x > r) r = pl[i].x; if (pl[i].y < t) t = pl[i].y; else if (pl[i].y > b) b = pl[i].y; } sprintf(buf, "(%d, %d, %d, %d)", l, r, t, b); return buf; } \End\Of\Shar\ else echo "will not over write ./addpoint.c" fi if [ `wc -c ./addpoint.c | awk '{printf $1}'` -ne 3236 ] then echo `wc -c ./addpoint.c | awk '{print "Got " $1 ", Expected " 3236}'` fi if `test ! -s ./args.c` then echo "writing ./args.c" cat > ./args.c << '\End\Of\Shar\' #include "main.h" void ParseArgs(argc, argv) int argc; char** argv; { for (progname = *argv++, argc--; argc; argv++, argc--) { Argassoc* a; for (a = map; a->name; a++) if (**argv == '-' && strcmp(a->name, *argv + 1) == 0) { switch (a->type) { case Boolean: *((int *) a->ref) = (int) a->value; break; case String: *((char **) a->ref) = *++argv; --argc; break; case Integer: *((int *) a->ref) = atoi(*++argv); --argc; break; case Function: (*(void (*)()) a->ref)(); break; } break; } if (!a->name) Usage(); } } int ParseShape(s) char* s; { static struct { char* s; int i; } tbl[] = { "dot", DOT, "point", DOT, "line", LINE, 0, 0 }, *here; for (here = tbl; here->s; here++) if (strcmp(here->s, s) == 0) return here->i; fprintf (stderr, "valid shape types are:"); for (here = tbl; here->s; here++) fprintf (stderr, " %s", here->s); fprintf (stderr, "\n"); return -1; } \End\Of\Shar\ else echo "will not over write ./args.c" fi if [ `wc -c ./args.c | awk '{printf $1}'` -ne 1340 ] then echo `wc -c ./args.c | awk '{print "Got " $1 ", Expected " 1340}'` fi if `test ! -s ./assert.c` then echo "writing ./assert.c" cat > ./assert.c << '\End\Of\Shar\' #include <stdio.h> #include <varargs.h> /* * error routines */ void complain(cond, fmt, args) int cond; char* fmt; va_list args; { if (cond) _doprnt(fmt, &args, stderr); } void assert(cond, fmt, args) int cond; char* fmt; va_list args; { if (!cond) { _doprnt(fmt, &args, stderr); exit(1); } } void panic(cond, fmt, args) int cond; char* fmt; va_list args; { if (cond) { _doprnt(fmt, &args, stderr); abort(); } } \End\Of\Shar\ else echo "will not over write ./assert.c" fi if [ `wc -c ./assert.c | awk '{printf $1}'` -ne 540 ] then echo `wc -c ./assert.c | awk '{print "Got " $1 ", Expected " 540}'` fi if `test ! -s ./bits.c` then echo "writing ./bits.c" cat > ./bits.c << '\End\Of\Shar\' #include "main.h" #ifndef SetBit void SetBit(x, y) int x, y; { char* line = bits[y]; if (line == 0) line = bits[y] = (char *) calloc(dpywidth / 8 + 1, sizeof(char)); line[x / 8] |= 1 << (x & 7); } #endif #ifndef ResetBit void ResetBit(x, y) int x, y; { bits[y][x / 8] &= ~(1 << (x & 7)); } #endif #ifndef GetBit int GetBit(x, y) int x, y; { char* line = bits[y]; if (line == 0) return 0; return line[x / 8] & (1 << (x & 7)); } #endif \End\Of\Shar\ else echo "will not over write ./bits.c" fi if [ `wc -c ./bits.c | awk '{printf $1}'` -ne 496 ] then echo `wc -c ./bits.c | awk '{print "Got " $1 ", Expected " 496}'` fi if `test ! -s ./flags.c` then echo "writing ./flags.c" cat > ./flags.c << '\End\Of\Shar\' #include "main.h" Argassoc map[] = { { String, "display", (char *) &displayname }, { String, "fg", (char *) &foreground }, { String, "bg", (char *) &background }, { Integer, "border", (char *) &BORDER }, { Integer, "decay", (char*) &expire }, { Integer, "expire", (char *) &expire }, { Integer, "folds", (char *) &folds }, { Boolean, "flash", (char *) &lightning, (char *) 1}, { Integer, "lifetime", (char *) &life }, { Boolean, "lightning", (char *) &lightning, (char *) 1}, { String, "lightningcolor", (char *) &lightningColor }, { String, "shape", (char *) &shape }, { Boolean, "root", (char *) &useroot, (char*) 1 }, { Function, "help", (char *) Usage }, { Integer, "update", (char *) &update }, { String, "geometry", (char *) &geometry }, { Boolean, 0, 0 }, }; \End\Of\Shar\ else echo "will not over write ./flags.c" fi if [ `wc -c ./flags.c | awk '{printf $1}'` -ne 841 ] then echo `wc -c ./flags.c | awk '{print "Got " $1 ", Expected " 841}'` fi if `test ! -s ./main.c` then echo "writing ./main.c" cat > ./main.c << '\End\Of\Shar\' #include "main.h" #include <X11/keysym.h> int screen; unsigned dla_width, dla_height; unsigned curleft, curright, curbottom, curtop; Display* dpy; Window win; char** bits; unsigned long fg, bg; char* displayname = 0; char* progname; char* foreground; char* background; char* foldstr = 0; char* shape = "dot"; char* geometry = "500x500"; int useroot = 0; int BORDER; int folds; int life; int lightning; Window lightningWindow; XPoint pl[32767]; char* lightningColor; int update = 20; GC gc, lgc; Pixmap pic; XGCValues gcv; int expire, last; XPoint* oldpoint; main(argc, argv) int argc; char* argv[]; { int noquit; int mask; int screen; int x, y; int i; Window gunk, parent; XColor cdef; Colormap dcm; XSizeHints xsh; unsigned int width, height; XSetWindowAttributes attrs; ParseArgs(argc, argv); if (BORDER <= 0) BORDER = 10; /* very arbitrary */ assert(dpy = XOpenDisplay(displayname), "unable to open display \"%s\".\n", XDisplayName (displayname)); screen = XDefaultScreen (dpy); dcm = DefaultColormap(dpy, screen); if (background && XParseColor(dpy, dcm, background, &cdef) && XAllocColor(dpy, dcm, &cdef)) bg = cdef.pixel; else bg = BlackPixel(dpy, screen); if (foreground && XParseColor(dpy, dcm, foreground, &cdef) && XAllocColor(dpy, dcm, &cdef)) fg = cdef.pixel; else fg = WhitePixel(dpy, screen); if (useroot) { win = XRootWindow(dpy, screen); width = DisplayWidth (dpy, screen); height = DisplayHeight (dpy, screen); } else { mask = XParseGeometry (geometry, &x, &y, &width, &height); xsh.flags = PSize; xsh.width = width; xsh.height = height; parent = XCreateSimpleWindow(dpy, XRootWindow(dpy, screen), x, y, width, height, 1, fg, bg); win = XCreateSimpleWindow(dpy, parent, 0, 0, width, height, 0, fg, bg); XSetStandardProperties (dpy, parent, "Diffusion Limited Aggregates", "xdla", None, argv, argc, &xsh); XSelectInput (dpy, win, KeyPressMask|KeyReleaseMask); } dla_width = width + 2 * BORDER; dla_height = height + 2 * BORDER; attrs.backing_store = Always; attrs.win_gravity = CenterGravity; XChangeWindowAttributes (dpy, win, CWBackingStore|CWWinGravity, &attrs); gcv.foreground = fg; gc = XCreateGC(dpy, win, GCForeground, &gcv); if (lightningColor) lightning = 1; if (lightning) { attrs.override_redirect = 1; lightningWindow = XCreateWindow(dpy, win, -BORDER, -BORDER, width, height, 0, CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect, &attrs); if (lightningColor && XParseColor(dpy, dcm, lightningColor, &cdef) && XAllocColor(dpy, dcm, &cdef)) gcv.foreground = cdef.pixel; lgc = XCreateGC(dpy, lightningWindow, GCForeground, &gcv); } if (expire) { noquit = 1; oldpoint = (XPoint*) calloc(expire, sizeof(oldpoint[0])); } srandom(getpid()); bits = (char **) calloc(dla_height, sizeof(*bits)); switch (ParseShape(shape)) { case -1: Usage (); break; case DOT: (void) SetBit(dla_width / 2, dla_height / 2); (void) XDrawPoint(dpy, win, gc, dla_width / 2 - BORDER, dla_height / 2 - BORDER); if (life) { curleft = curtop = 1; curright = width - 1; curbottom = height - 1; } else { curleft = dla_width / 2 - BORDER; curright = dla_width / 2 + BORDER; curtop = dla_height / 2 - BORDER; curbottom = dla_height / 2 + BORDER; } break; case LINE: noquit = 1; for (i = 0; i < dla_width; i++) { SetBit(i, dla_height - 1); XDrawPoint(dpy, win, gc, i, dla_height - 1 - BORDER); } curleft = 0; curright = dla_width; curbottom = dla_height - 1; curtop = dla_height - BORDER - 1; break; } if (folds == 0) folds = 8; assert(folds == 4 || folds == 6 || folds == 8, "folds must be one of 4, 6, or 8, not %d.\n", folds); if (useroot) { XSetWindowBackground (dpy, win, bg); XClearWindow(dpy, win); } else { XMapWindow(dpy, win); XMapWindow (dpy, parent); } if (life) noquit = 1; i = 0; while (AddPoint() || noquit) { if (++i >= update) { XEvent ev; i = XEventsQueued (dpy, QueuedAfterFlush); while (i--) { XNextEvent (dpy, &ev); Dispatch (&ev); } } } for (;;) { XEvent ev; XNextEvent (dpy, &ev); Dispatch (&ev); } } Dispatch (ev) XEvent *ev; { switch (ev->type) { case KeyPress: switch (XLookupKeysym (ev, 0)) { case XK_Q: case XK_q: case XK_Cancel: case XK_Break: exit (0); } } } \End\Of\Shar\ else echo "will not over write ./main.c" fi if [ `wc -c ./main.c | awk '{printf $1}'` -ne 4659 ] then echo `wc -c ./main.c | awk '{print "Got " $1 ", Expected " 4659}'` fi if `test ! -s ./main.h` then echo "writing ./main.h" cat > ./main.h << '\End\Of\Shar\' #include <X11/X.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xatom.h> #include <stdio.h> #define DOT 0 #define LINE 1 typedef enum { Boolean, String, Integer, Function } ArgType; typedef struct { ArgType type; char* name; char* ref; char* value; /* wildcard thingie */ } Argassoc; extern int screen; extern unsigned dla_width, dla_height; extern unsigned curleft, curright, curbottom, curtop; extern Display* dpy; extern Window win; extern char** bits; extern unsigned long fg; extern char* displayname; extern char* progname; extern char* foreground; extern char* background; extern char* foldstr; extern char* shape; extern char* geometry; extern int useroot; extern int BORDER; extern int folds; extern int life; extern int lightning; extern Window lightningWindow; extern XPoint pl[]; extern char* lightningColor; extern int update; extern GC gc, gcr, lgc; extern Pixmap pic; extern XGCValues gcv; extern Argassoc map[]; extern int expire, last; extern XPoint* oldpoint; int AddPoint(); void ParseArgs(); void SetBit(); void Usage(); char* calloc(); char* getenv(); #define SetBit(x,y) (\ (bits[y] ? 0 : (bits[y] = (char *) calloc (dla_width / 8 + 1,sizeof (char)))),\ (bits[y][(x)>>3] |= 1 << (x & 7))\ ) #define ResetBit(x,y) (bits[y][x / 8] &= ~(1 << (x & 7))) #define GetBit(x,y) (bits[y] ? bits[y][(x) >> 3] & (1 << (x & 7)) : 0) \End\Of\Shar\ else echo "will not over write ./main.h" fi if [ `wc -c ./main.h | awk '{printf $1}'` -ne 1442 ] then echo `wc -c ./main.h | awk '{print "Got " $1 ", Expected " 1442}'` fi if `test ! -s ./patchlevel.h` then echo "writing ./patchlevel.h" cat > ./patchlevel.h << '\End\Of\Shar\' #define PATCHLEVEL 0 \End\Of\Shar\ else echo "will not over write ./patchlevel.h" fi if [ `wc -c ./patchlevel.h | awk '{printf $1}'` -ne 21 ] then echo `wc -c ./patchlevel.h | awk '{print "Got " $1 ", Expected " 21}'` fi if `test ! -s ./usage.c` then echo "writing ./usage.c" cat > ./usage.c << '\End\Of\Shar\' #include "main.h" extern char *progname; void Usage() { Argassoc* here; fprintf(stderr, "usage: %s", progname); for (here = map; here->name; here++) { fprintf(stderr, " [-%s", here->name); switch (here->type) { case String: case Integer: fprintf(stderr, " %s", here->name); break; } fprintf(stderr, "]"); } fprintf(stderr, "\n"); exit(1); } \End\Of\Shar\ else echo "will not over write ./usage.c" fi if [ `wc -c ./usage.c | awk '{printf $1}'` -ne 433 ] then echo `wc -c ./usage.c | awk '{print "Got " $1 ", Expected " 433}'` fi echo "Finished archive 1 of 1" exit dan ---------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com Opinions expressed reflect those of the author only.