[comp.sources.x] v06i025: vine -- grow plants on your workstation., Part01/01

argv%turnpike@Sun.COM (Dan Heller) (03/11/90)

Submitted-by: argv@sun.com  (Dan Heller)
Posting-number: Volume 6, Issue 25
Archive-name: vine/part01

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of shell archive."
# Contents:  README Imakefile version.h vine.c
# Wrapped by argv@turnpike on Sat Mar 10 12:54:46 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(4518 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XVine was written by Dan Heller in Dec 1985 while at SRI International.
XThe Port to X windows done on Friday March 9, 1990 by Dan Heller.
XThis readme has been modified to provide for the latest additions.
X
XThis program draws vines all over your computer.  If you're running X,
Xit writes to the root window.  If you're running on a sun workstation,
Xand *not* using X (e.g. compiled with -lpixrect) it writes directly to
Xthe frame buffer.
X
X"vines" are long stems with leaves on them.
X
XIf you don't get the imakefile to work, try these.
XFor any computer running X11:
X    % cc -DX11 vine.c -lX -lm -o vine
XFor Sun's using pixrects:
X    % cc vine.c -lsunwindow -lpixrect -lm -o vine
X
XHere are the different command line options you can use:
XBy default (e.g. no arguments), -e is used.
X
X    -e      vines grow along the edges of the screen (default; no arguments)
X    -c      vines grow from the center of the screen and spread *quickly*
X    -C      draws leaves in shades of green (default is to use monochrome)
X    -v N    grow N vines from the top of the screen (max: MAXFORKS, see below)
X    -h      program waits for <CR> in which all vines halt (see below)
X    -r      reverse video; black/white is inverted (no color -may be confusing)
X    -f      fall mode.  Used with -C -- shades of brown instead of green.
X    -D      degradee -- leaf colors fade from light to dark shades (use w/ -C)
X    -i [N]  interleaf black/white leaves 1 for each N (-N white/black)
X    -s N    max size of leaves (default: 2)
X    -d device  alternate display (X) or frame buffer (sun: default is /dev/fb)
X    -b N    probability of branching (max 40)
X    -l N    as N increases more leaves grow from each stem (max 35)
X    -R N    360/N different leaf rotations (default 45 degrees)
XFor X only
X    -F      allow forking; off by default because X server gets confused
XFor Sun's only:
X    -w      vines grow around each window on the screen (not icons; no color)
X
XFor best effects try the following:
X
XColor displays:
X% vine -C -c -s3
X
Xsuns:
X% vine -w -i
X
XExperimentation with outrageous values gives other interesting effects, like:
X
X% vine -s10 -c
X
XNotes:
X
XThe X version uses only the following Xlib calls:
X    XOpenDisplay()
X    XSetForeground()/XSetBackground()
X    XDrawLine()
X    XFillPolygon()
X    XCreateGC()
X    XAllocColor()
X    XSetErrorHandler() /* see below */
X    XFlush() /* not really necessary */
X
XColor vines are drawn in shades of green or brown depending on the -f switch.
XShades of these colors are gotten from trying to allocate colors in the
Xcolormap of the root window.  If there are few colors available, then
Xyou'll get fewer shades.  On my sun running MWM, I got 140 colors.  I can't
Xseem to figure out how to get the root window to *keep* the drawing on
Xthe window!  If you move windows around, the background gets repainted to
Xwhatever was there before the vines got written.
X
XMultiple vines grow simultaneously by using fork() and each vine is grown
Xfrom its own process.  However, X gets really confused about this and
Xeventually a protocol error occurs, thus the use of XSetErrorHandler().
XI dump core at the location of the protocol error for debugging purposes,
Xbut the only thing I can think of is that the separate processes are sending
Xrequests to the server at the  same time causing different GC/Window
Xattribute values getting set while another process expects the values
Xto be whatever it set them to first.
X
XAs a result, I don't allow fork()'s in the "default" case.  That is,
X"edge" vines (-e) doesn't fork() unless you give the -F flag to allow
Xforking.  You will probably see the problem here.  The other options
X(-v -c, etc) will fork anyway, and again, you'll see the problem.
X
XDon't try running in "sync" mode or you'll be watching forever... it's
Xawfully slow.  I didn't provide a -sync flag, but you can uncomment
Xthe XSynchronize() line if you like.
X
Xforks are cuaght using a SIGCHLD event handler.  If you're using
XVMS, then remove the #include for signal.h and the signal isn't
Xused.
X
XMAX_FORKS is defined to limit the ability for the vines to runaway
Xwith the CPU and draw vines everywhere preventing you from getting
Xcontrol of your computer back.  If you're not careful, vines start
Xgrowing on the desk top, the floor, furniture, everything.  Altho
Xit's not common, "I heard some guy out in Jersey got it twice."
X
XName the movie that the above quote was taken from and win a Pizza!
X
XThe -h option is provided so that all forked processes can be
Xterminated instantly by hitting "return".
END_OF_FILE
if test 4518 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'Imakefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Imakefile'\"
else
echo shar: Extracting \"'Imakefile'\" \(206 characters\)
sed "s/^X//" >'Imakefile' <<'END_OF_FILE'
X#ifdef BandAidCompiler
X#include BandAidCompiler
X#endif
X
XDEFINES -DX11
XINCLUDES = -I$(TOP) -I$(TOP)/X11
XSYS_LIBRARIES = -lm
XLOCAL_LIBRARIES = $(XLIB)
X
XSRCS = vine.c
XOBJS = vine.o
X
XComplexProgramTarget(vine)
END_OF_FILE
if test 206 -ne `wc -c <'Imakefile'`; then
    echo shar: \"'Imakefile'\" unpacked with wrong size!
fi
# end of 'Imakefile'
fi
if test -f 'version.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'version.h'\"
else
echo shar: Extracting \"'version.h'\" \(47 characters\)
sed "s/^X//" >'version.h' <<'END_OF_FILE'
X#define PATCHLEVEL 0
X#define PATCHDATE  3/9/90
END_OF_FILE
if test 47 -ne `wc -c <'version.h'`; then
    echo shar: \"'version.h'\" unpacked with wrong size!
fi
# end of 'version.h'
fi
if test -f 'vine.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'vine.c'\"
else
echo shar: Extracting \"'vine.c'\" \(21303 characters\)
sed "s/^X//" >'vine.c' <<'END_OF_FILE'
X/*
X *  vine.c
X *  Written by Dan Heller one fine winter week in the spirit of the
X *  coming holidays, 1985.  Works on Sun versions 1.4 and up.
X *
X *  compile: cc -O -s vine.c -lsunwindow -lpixrect -lm -o vine
X *
X * The way vines works is a "stem" grows and leaves grow from that stem.
X * The stem and the leaf are arrays of "points" (struct pr_pos).  You can
X * add your own images (like flowers or something) with the -S and -L
X * flags.  The usages for these flags are:
X * 
X * -S file
X * -L file
X * 
X * These files are opened and pairs of points are read in place of the
X * Stems and Leaves respectively.  The end of an image is represented
X * by the coordinate pair 0,0.
X * 
X * For each coordinate pair read, pr_vectors are drawn from 0,0 to the
X * first point, then to the second and so on till the final 0,0 and then
X * a pr_polygon2 routine is called to fill in the image.
X *
X * Because there is an extra line in the middle of leaves, some of the code
X * around pr_polygon2() is added to continue drawing the leaves.  Unless your
X * own images are simple, you're probably going to have to do the same thing
X * in that same area (search for pr_polygon2 for where I'm talking about).
X *
X * If you do anything interesting to this code, I would GREATLY appreciate
X * knowing what you did.  Please send any hacks or comments/flames to:
X *
X *    argv@sun.com
X */
X
Xchar *err_msg[] = {
X    "usages for %s:\n",
X    "-c:  vines grow from the center of the screen",
X    "-e:  vines grow along the edges of the screen (default)",
X    "-D:  degradee the color down the colormap",
X    "-f:  fall season (brown leaves: color only)",
X    "-h:  vines halt upon RETURN",
X    "-r:  reverse video; leafs are inverted",
X    "-C:  clears the screen and prepares for color display (-w not allowed)",
X    "-b N: probability of branching (max 40)",
X    "-i N: interleaf black/white leaves 1 for each N (-N white/black)",
X    "-l N: as N increases, more leaves grow from each stem (max 35)",
X    "-s N: max size of leaves (default: 2)",
X    "-v N: grow N vines from the top of the screen. (default 4)",
X    "-R N: have N different leaf rotations (max 360)",
X#ifdef X11
X    "-d display: use display:server[.screen]",
X    "-F: allow forking; off by default because X server gets confused",
X#else /* X11 */
X    "-d device: use alternate frame buffer; default is /dev/fb",
X    "-w:  vines grow around each window on the screen (not icons; no color)",
X#endif /* X11 */
X    "-L file: use leaf defined in file as x,y coordinate pairs",
X    "-S file: use stem defined in file as x,y coordinate pairs",
X    0
X};
X
X#define MAX_FORKS 6
X
X#include <stdio.h>
X#include <sys/file.h>
X#include <ctype.h>
X#include <signal.h>
X
X#define when break;case
X
X#ifdef X11
X#include <X11/Xos.h>
X#include <X11/Xatom.h>
X#include <X11/Xlib.h>
X#include <X11/Xutil.h>
Xstruct pr_pos {
X    short x, y;
X};
Xstruct rect {
X    int	r_left, r_top, r_width, r_height;
X};
X#else /* X11 */
X#include <suntool/tool_hs.h>
X#include <pixrect/pixrect_hs.h>
X#include <suntool/wmgr.h>
X#include <sunwindow/cms_mono.h>
X#define DefaultDepthOfScreen(s) s->pr_depth
X#define WidthOfScreen(s) s->pr_size.x
X#define HeightOfScreen(s) s->pr_size.y
X#define WUF_WMGR1 0x10
X#endif /* X11 */
X
X#include <sys/wait.h>
X#include <sys/resource.h>
X#include <math.h>
X
X#define UP 			001  /* turn object up-side down */
X#define MIRROR 			002  /* mirror the object */
X#define FLIP			004  /* rotate object 90 deg. */
X#define FLOP			010  /* rotate object -90 deg. */
X#define DEG_TO_RADS 		57.295779513
X#ifdef X11
X#define SetBlack() intensity = (is_color || !reverse)? \
X    BlackPixelOfScreen(screen) : WhitePixelOfScreen(screen); \
X    XSetForeground(dpy, gc, intensity)
X#define SetColor(color) intensity = is_color? color : \
X    reverse? WhitePixelOfScreen(screen) : BlackPixelOfScreen(screen); \
X    XSetForeground(dpy, gc, intensity)
X#define draw(x1,y1,x2,y2) XDrawLine(dpy,win,gc,(int)x1,(int)y1,(int)x2,(int)y2)
X#else /* X11 */
X#define SetBlack() (intensity = (is_color || !reverse)? \
X    BLACK : is_color? 255 : WHITE)
X#define SetColor(color)         if (is_color) intensity = color; else SetBlack()
X#define RAS_OP			PIX_COLOR(intensity)|PIX_SRC	
X#define draw(x1,y1,x2,y2) 	pr_vector(screen,x1,y1,x2,y2,RAS_OP,1)
X#endif /* X11 */
X
X/*
X * each {x,y} is a relative point to 0,0. End is {0,0} pair
X */
Xstruct pr_pos leaf[] = {
X    {-4,4}, {-9,6}, {-13,9}, {-15,11}, {-16,14}, {-17,16}, {-17,20},
X    {-16,24}, {-13,28}, {-11,30}, {-9,32}, {-4,36}, {-1,38}, {4,39}, {6,37},
X    {4,37}, {3,34}, {3,31}, {4,29}, {6,25}, {9,20}, {10,16}, {10,12},
X    {8,8}, {7,7}, {4,6}, {2,4}, {1,0}, {0,2}, {-1,4}, {-3,8},
X    {-5,12}, {-6,16}, {-6,20}, {-5,24}, {-3,27}, {0,0}
X};
Xint leafsize = sizeof (leaf) / sizeof (struct pr_pos);
X
Xstruct pr_pos stem[50] = {
X    {0,7}, {1,8}, {2,7}, {1,12}, {0,11}, {-1,12}, {-3,15}, {-3,19}, {-2,22},
X    {-1,24}, {1,26}, {3,28}, {4,30}, {5,32}, {5,36}, {7,40}, {8,42}, {9,43},
X    {8,49}, {5,51}, {2,54}, {0,60}, {0,0}
X};
Xint stemsize = sizeof (stem) / sizeof (struct pr_pos);
Xstruct pr_pos leaves[360][sizeof(leaf) / sizeof(struct pr_pos)];
Xstruct rect win_rects[32];
X
Xint reverse;          /*  -r:  reverse video */
Xint rot_increment=45; /*  -R:  rotation increment... upto 360 degrees */
Xint interleaf;        /*  -i:  interleaf black and white leaves */
Xint lsize = 2;        /*  -s:  max magnification variable for leaves */
Xint leaf_freq = 30;   /*  -l:  frequency of leafs per stem */
Xint do_halt;	      /*  -h:  program halts on RETURN */
Xint branch_freq = 5;  /*  -b:  how often to branch off a new vine */
Xint n_vines = 4;      /*  -v:  4 is default */
Xint from_center;      /*  -c:  start at the center of screen */
Xint is_color;	      /*  -C:  user is running from a color monitor */
Xint dbug;	      /*  -g:  debug mode, inspired by cc's -g flag for dbx */
Xint do_edges;	      /*  -e:  just traverse the edges of the screen */
Xint do_windows;       /*  -w:  grow around each open window in suntools */
Xint season;	      /*  -f:  fall season */
Xint do_fork;          /*  -F:  allow forking -- off for X */
Xint fade;	      /*  -D:  fade the color down the colormap */
X
Xunsigned long colors[256];
Xint max_color;        /* maximum number of colors available */
Xint win_no, my_win;   /* number of windows running / which win we are */
Xint total_forks;      /* the total number of forks we've done so far */
X
X#ifdef X11
Xunsigned long intensity;        /* shade of color to paint */
XDisplay *dpy; /* display */
XScreen *screen;
XWindow win; /* root window */
XGC gc; /* points to default GC of screen */
Xchar *device; /* default screen == default to NULL (see XOpenDisplay below) */
X#else /* X11 */
Xint intensity;        /* shade of color to paint */
Xstruct pixrect *screen;   /*  our screen's frame buffer */
Xchar *device = "/dev/fb"; /* default frame buffer */
X#endif /* X11 */
Xchar *leaf_file;      /*  files for alternate leaf and stem images */
Xchar *stem_file;
XFILE *f;
X
X#ifndef X11
X#include <pixrect/pr_planegroups.h>
X#endif /* X11 */
X
Xmain(argc, argv)
Xchar **argv;
X{
X    register int count, x, y = 1;
X    int c;
X    int dead_kids();
X
X    if (argc > 1)
X	parse_args(argc, argv);
X    else
X	do_edges = 1, interleaf = 3;
X
X    if (leaf_file) {
X        if (!(f = fopen(leaf_file,"r")))
X	    perror(leaf_file), exit(1);
X	for (c = 0; c < leafsize; ++c)
X	    if (fscanf(f,"%d,%d", &leaf[c].x, &leaf[c].y) < 2)
X	        break;
X	(void) fclose(f);
X	if (leaf[c - 1].y || leaf[c - 1].x) {
X	    if (c == leafsize)
X	        fprintf(stderr, "%s: too many points (limit is %d)\n",
X			leaf_file, c);
X	    else
X	        fprintf(stderr, "%s: last coordinate pair must be 0,0\n",
X		      leaf_file);
X	    exit(1);
X	}
X	leafsize = c - 1;
X    }
X
X    if (stem_file) {
X        if (!(f = fopen(stem_file,"r")))
X	    perror(stem_file), exit(1);
X	for (c = 0; c < stemsize; ++c)
X	    if (fscanf(f,"%d,%d", &stem[c].x, &stem[c].y) < 2)
X	        break;
X	(void) fclose(f);
X	if (stem[c - 1].y || stem[c - 1].x) {
X	    if (c == stemsize)
X	        fprintf(stderr, "%s: too many points (limit is %d)\n",
X			stem_file, c);
X	    else
X	        fprintf(stderr, "%s: last coordinate pair must be 0,0\n",
X			stem_file);
X	    exit(1);
X	}
X    }
X
X#ifdef X11
X{
X    void x_error();
X    char *getenv(), *p = getenv("DISPLAY");
X    if (!(dpy = XOpenDisplay(device? device : p? p : ""))) {
X	fprintf(stderr, "%s: unable to open display '%s'\n",
X	    argv[0], XDisplayName(p));
X	exit(1);
X    }
X    /* XSynchronize(dpy, 1); */
X    XSetErrorHandler(x_error);
X    screen = ScreenOfDisplay(dpy, DefaultScreen(dpy));
X    win = RootWindowOfScreen(screen);
X    gc = XCreateGC(dpy, win, 0L, NULL);
X}
X#else /* X11 */
X{
X    char groups[PIXPG_OVERLAY+1];
X    if (!(screen = pr_open(device)))
X	exit(1); /* pr_open prints its own error messages (bad idea) */
X
X    pr_available_plane_groups(screen, sizeof(groups), groups);
X
X    if (groups[PIXPG_OVERLAY] && groups[PIXPG_OVERLAY_ENABLE] && !is_color) {
X	pr_set_plane_group(screen, PIXPG_OVERLAY_ENABLE);
X	pr_rop(screen, 0,0, WidthOfScreen(screen), HeightOfScreen(screen),
X	    PIX_SET, (Pixrect *) 0,0,0);
X	pr_set_plane_group(screen, PIXPG_OVERLAY);
X    }
X    do_fork++;
X}
X#endif /* X11 */
X
X    if (do_halt || from_center)
X	/* don't count this fork ... */
X	if (fork())
X	    getchar(), kill(0, 9);
X    if (interleaf < 0)
X	reverse = !reverse, interleaf *= -1;
X    setbuf(stdout, NULL);
X    printf("growing leaves ");
X    for (x = 0, y = 0; x < 360; x += rot_increment) {
X	rotate_obj(leaf, leaves[y++], leafsize, x/DEG_TO_RADS);
X	if (!(y % 10))
X	    putchar('.');
X    }
X    puts(" done.");
X    if (is_color)
X	initialize_color();
X    else if (do_windows) {
X	if (!get_windows())
X	    puts("No windows!");
X
X	for (my_win = 0; my_win < win_no-1 && fork(); my_win++)
X	    ;
X
X	if (fork())
X	    edge_vines(win_rects[my_win].r_left + win_rects[my_win].r_width / 2,
X			    win_rects[my_win].r_top, FLIP);
X	else
X	    edge_vines(win_rects[my_win].r_left + win_rects[my_win].r_width / 2,
X			    win_rects[my_win].r_top, FLOP);
X	exit(0);
X    }
X    y = 1;
X    if (do_edges) {
X	if (do_fork) {
X	    if (!fork()) {
X		edge_vines(WidthOfScreen(screen) / 2, 10, FLIP);
X		exit(0);
X	    }
X	} else
X	    edge_vines(WidthOfScreen(screen) / 2, 10, FLIP);
X	edge_vines(WidthOfScreen(screen) / 2, 10, FLOP);
X	exit(0);
X    }
X#ifdef SIGCHLD
X    (void) signal(SIGCHLD, dead_kids);
X#endif /* SIGCHLD */
X    for (count = 0, x = WidthOfScreen(screen) / (n_vines+1); count < n_vines;
X			     x += WidthOfScreen(screen) / (n_vines+1), count++)
X	if (from_center)
X	    random_vines(WidthOfScreen(screen)/2, HeightOfScreen(screen)/2);
X	else
X	    random_vines(x, y);
X#ifdef X11
X    XFlush(dpy);
X#endif /* X11 */
X}
X
X#ifdef SIGCHLD
X/* catch exited forked processes and decrement number of total_forks avail */
Xdead_kids()
X{
X    union wait status;
X
X    while (wait3(&status, WNOHANG, (struct rusage *) 0))
X        total_forks--;
X}
X#endif /* SIGCHLD */
X
Xextern long time();
Xextern long random();
X
Xedge_vines(x, y, which_way)
X{
X    register int stop_l, stop_r, y_stop;
X    if (do_windows) {
X	stop_l = win_rects[my_win].r_left;
X	stop_r = stop_l + win_rects[my_win].r_width;
X	y_stop = y + win_rects[my_win].r_height;
X    } else {
X	stop_r = WidthOfScreen(screen) - 60;
X	stop_l = 60;
X	y_stop = HeightOfScreen(screen) - 60;
X    }
X    /* srandom must be here for recursive calls from new forked procs */
X    srandom((int) (getpid() * time((long *)0)));
X
X    leaf_freq = 34;  /* edge vines have constant leaf frequency */
X
X    while(x > stop_l && x < stop_r)
X	draw_stem(&x, &y, which_way | ((random() % 2) * UP));
X    while(y < y_stop)
X	draw_stem(&x, &y, (random() % 2) * MIRROR);
X    /* draw along the bottom
X    while(x < stop_r)
X	draw_stem(&x, &y,
X	    (random() % 2) * UP | ((which_way == FLIP) ? FLOP : FLIP));
X    */
X}
X
Xrandom_vines(xstart, ystart)
X{
X    /* parent returns */
X    if(total_forks < MAX_FORKS && fork()) {
X	total_forks++;
X	return;
X    }
X    /* make the child think there are too many forks */
X    total_forks = MAX_FORKS;
X    srandom((int) (getpid() * time((long *) 0)));
X    while(ystart && ystart < HeightOfScreen(screen) &&
X	  xstart && xstart < WidthOfScreen(screen)) {
X	do_stem(&xstart, &ystart);
X	if (!(random() % (1 + (40 - branch_freq))))
X	    random_vines(xstart, ystart);
X    }
X    exit(0);
X}
X
Xdo_stem(x,y)
Xint *x,*y;
X{
X    long dir = 0;
X    if (!(random() % (from_center ? 2 : 20)))
X	dir |= UP;
X    if (random() % 2)
X	dir |= MIRROR;
X    if (random() % 2)
X	dir |= (random() % 2) ? FLIP : FLOP;
X    draw_stem(x, y, dir);
X}
X
Xdraw_stem(x,y,dir)
Xregister int *x, *y;
Xlong dir;
X{
X    /* ox,oy are old x and y; nx,ny are new x and new y coords */
X
X    register int tmp, ox = *x, oy = *y, nx, ny;
X    for(tmp = 0; stem[tmp].y || stem[tmp].x; tmp++) {
X	if (dir & FLIP) {
X	    ny = *y + (stem[tmp].x * ((dir & UP) ? -1 : 1));
X	    nx = *x + (stem[tmp].y * ((dir & MIRROR) ? -1 : 1));
X	} else if (dir & FLOP) {
X	    ny = *y + (stem[tmp].x * ((dir & UP) ? -1 : 1));
X	    nx = *x - (stem[tmp].y * ((dir & MIRROR) ? -1 : 1));
X	} else {
X	    ny = *y + (stem[tmp].y * ((dir & UP) ? -1 : 1));
X	    nx = *x + (stem[tmp].x * ((dir & MIRROR) ? -1 : 1));
X	}
X	if (!do_windows || check_rects(nx, ny)) {
X	    SetBlack();
X	    draw(ox, oy, nx, ny);
X	    if(!(random() % (1 + (35 - leaf_freq))))
X		do_leaf(nx, ny);
X	}
X	ox = nx, oy = ny;
X    }
X    *x = ox, *y = oy;
X}
X
Xdo_leaf(x,y)
X{
X    int reverse_it;
X    if (interleaf && (reverse_it = !(random() % interleaf)))
X	reverse = !reverse;
X    /* start at x,y and rotate */
X    draw_leaf(x, y, random() % (360/rot_increment),
X		(double)(.6 + (random() % (10 * lsize)) / 20.0),  /* magnify */
X		(long) random() % 2 ? -1 : 1); /* mirror image */
X    if (interleaf && reverse_it)
X	reverse = !reverse;
X}
X
Xdraw_leaf(x,y,rotation,magnification,mirror)
Xlong rotation;
Xdouble magnification;
Xlong mirror;
X{
X    static col;
X    int tmp, ox = x, oy = y, nx, ny, npts[1];
X    struct pr_pos leaf2[sizeof(leaf) / sizeof(struct pr_pos)];
X
X    /* magnify, move leaf into position, and mirror, if necessary */
X    for(tmp = 0; tmp < leafsize; tmp++) {
X	ny = y + magnification * leaves[rotation][tmp].y;
X	nx = x + magnification * leaves[rotation][tmp].x * mirror;
X	leaf2[tmp].y = oy, leaf2[tmp].x = ox;
X	ox = nx, oy = ny;
X    }
X    /* paint leaf before drawing outline */
X    reverse = !reverse;
X    if (is_color)
X	if (fade) {
X	    col += fade;
X	    if (!col || col == max_color-1)
X		fade = -fade;
X	} else
X	    col = random() % max_color;
X	    /* col = 80 + random() % 165; */
X    SetColor(colors[col]); /* for black and white: intensity has no meaning */
X    reverse = !reverse;
X#ifdef X11
X    XFillPolygon(dpy, win, gc, leaf2, 28, Nonconvex, CoordModeOrigin);
X    XFlush(dpy);
X#else /* X11 */
X    npts[0] = 28;   /* kludge for middle line of leaf! */
X    pr_polygon_2(screen, 0, 0, 1, npts, leaf2, RAS_OP, (Pixrect *) 0,0,0);
X#endif /* X11 */
X
X    SetBlack();
X    /* now draw the outline of the leaf */
X    for (tmp -= 2; tmp; tmp--)
X	draw(leaf2[tmp].x, leaf2[tmp].y, leaf2[tmp-1].x, leaf2[tmp-1].y);
X}
X
X/* check to see if we're insdie the rect of another window.  The win_rects
X * array has the oldest children (windows sitting "under" other windows)
X * first in the array.  So, we only check windows higher than us in the array
X * since we know we overlay the other windows.
X */
Xcheck_rects(x,y)
Xregister int x,y;
X{
X    register int win;
X    static lastwin = -1;
X    for (win = my_win+1; win < win_no; win++)
X	if (x > win_rects[win].r_left &&
X	    x < win_rects[win].r_left + win_rects[win].r_width &&
X	    y > win_rects[win].r_top &&
X	    y < win_rects[win].r_top + win_rects[win].r_height) {
X		if (dbug && win != lastwin)
X		    printf("win %d ran into win %d at %d,%d\n",
X			my_win, (lastwin = win), x,y);
X		return 0;
X	    }
X    return 1;
X}
X
X/* foreach pt in object, rotate_pt() */
Xrotate_obj(object, newobject, npts, rotation)
Xstruct pr_pos object[], newobject[];
Xdouble rotation;
X{
X    int i;
X    for(i = 0; i < npts; i++)
X	rotate_pt(&object[i], &newobject[i], rotation);
X}
X
X/* matrix multiplication */
Xrotate_pt(oldpt,newpt,rot)
Xstruct pr_pos *oldpt, *newpt;
Xdouble rot;
X{
X    /* temp storage -- might want to copy to itself */
X    register double tx = (double)oldpt->x, ty = (double)oldpt->y, X,Y;
X    X = tx * cos(rot) - ty * sin(rot);
X    Y = tx * sin(rot) + ty * cos(rot);
X    newpt->x = (int)X + ((X * 10.0 - (int)X * 10) >= 5); /* round up */
X    newpt->y = (int)Y + ((Y * 10.0 - (int)Y * 10) >= 5); /* round up */
X    if (dbug == 2)
X	printf("%g,%g --> %g,%g --> %d,%d\n", tx, ty, X, Y, newpt->x, newpt->y);
X}
X
Xparse_args(argc, argv)
Xchar **argv;
X{
X    register int c;
X    extern int optind;
X    extern char *optarg;
X
X    int errors = 0;
X
X    while ((c = getopt(argc, argv, "DefFhrgwcCb:d:i:l:s:v:R:L:S:?")) != EOF)
X	switch (c) {
X	    when 'c':
X		from_center = 1, branch_freq = 20;
X	    when 'e':
X		do_edges = 1;
X	    when 'D':
X		fade = 1;
X	    when 'f':
X		season = 1;
X	    when 'h':
X		do_halt = 1;
X	    when 'r':
X		reverse = 1;
X	    when 'g':
X		dbug = 1;
X#ifndef X11
X	    when 'w':
X		if (is_color)
X		    fputs("ignoring -w after -C\n", stderr);
X		else
X		    do_windows = 1;
X#endif /* X11 */
X	    when 'C':
X		if (do_windows)
X		    fputs("ignoring -C after -w\n", stderr);
X		else
X		    is_color = 1;
X	    when 'b':
X		branch_freq = atoi(optarg);
X		if (branch_freq > 40)
X		    fprintf(stderr, "maximum branch frequency is 40\n"),
X		    errors = 1;
X	    when 'd':
X		device = optarg;
X	    when 'i':
X		interleaf = atoi(optarg);
X	    when 'l':
X		if (do_edges)
X		    fputs("warning: edge vines have constant leaf frequency\n", stderr);
X		else {
X		    leaf_freq = atoi(optarg);
X		    if (leaf_freq > 40)
X			fprintf(stderr, "maximum leaf frequency is 40\n"), errors = 1;
X		}
X	    when 's':
X		lsize = atoi(optarg);	
X		if (lsize <= 0)
X		    fprintf(stderr, "bad leaf size: %d\n", lsize), errors = 1;
X	    when 'v':
X		n_vines = atoi(optarg);
X	    when 'R':
X		rot_increment = atoi(optarg);
X		if (rot_increment <= 0 || rot_increment > 360)
X		    fprintf(stderr, "bad leaf rotation: %d\n", rot_increment),
X		    errors = 1;
X	    when 'L':
X		leaf_file = optarg;
X	    when 'S':
X		stem_file = optarg;
X	    when 'F':
X		do_fork = 1;
X	    when '?':
X		errors = 1;
X	}
X
X    if (errors) {
X	fprintf(stderr, err_msg[0], argv[0]);
X        for (c = 1; err_msg[c]; c++)
X	    fprintf(stderr, "%s\n", err_msg[c]);
X	exit(1);
X    }
X}
X
X#ifdef X11
Xget_windows(){}
Xinitialize_color()
X{
X    u_char red[256], green[256], blue[256];
X    XColor color;
X    Colormap cm = DefaultColormapOfScreen(screen);
X
X    color.flags = DoRed | DoGreen | DoBlue;
X    for (max_color = 0; max_color < 256; max_color++) {
X	if (season) {
X	    color.green = (255 - max_color)<<8;
X	    color.red = (255 - max_color/3)<<8;
X	} else {
X	    color.red = (255 - max_color)<<8;
X	    color.green = (255 - max_color/3)<<8;
X	}
X	color.blue = (max_color/5)<<8;
X	if (!XAllocColor(dpy, cm, &color)) {
X	    printf("ran out of colors at index %d\n", max_color--);
X	    break;
X	}
X	colors[max_color] = color.pixel;
X    }
X}
X
Xvoid
Xx_error(display, error)
XDisplay	*display;
XXErrorEvent	*error;
X{
X    char	buffer[BUFSIZ];
X    char	num[10];
X    static int	count;		/* cumulative error total */
X
X    /* get and print major error problem */
X    XGetErrorText(display, error->error_code, buffer, BUFSIZ);
X
X    fprintf(stderr, "x_error(%d): <%s>", ++count, buffer);
X    /* print the request name that caused the error -- from X Database */
X    /* internally this expects a numeric string (I peeked!) */
X    sprintf(num, "%d", error->request_code );
X    XGetErrorDatabaseText(display, "XRequest", num, num, buffer, BUFSIZ);
X    fprintf(stderr, " %s\n", buffer);
X
X    /* abort to core dump or global debug flag set.. */
X    abort(0);
X}
X
X#else /* X11 */
Xget_windows()
X{
X    char name[WIN_NAMESIZE];
X    int toolfd, wfd, link;
X    struct screen screen;
X
X    /*
X     * Determine parent and get root fd
X     */
X    if (we_getparentwindow(name)) {
X	perror(name);
X	puts("You need to be running suntools to do the -w option");
X	exit(1);
X    }
X    if ((wfd = open(name, O_RDONLY, 0)) < 0)
X	perror(name);
X    win_screenget(wfd, &screen);
X    close(wfd);
X    if ((wfd = open(screen.scr_rootname, O_RDONLY, 0)) < 0)
X	perror(screen.scr_rootname);
X
X    link = win_getlink(wfd, WL_OLDESTCHILD);
X    while (link != WIN_NULLLINK) {
X	win_numbertoname(link, name);
X	if ((toolfd = open(name, O_RDONLY, 0)) < 0)
X	    perror(name), exit(1);
X	if (!(win_getuserflags(toolfd) & WMGR_ICONIC))
X	    win_getrect(toolfd, &win_rects[win_no++]);
X	link = win_getlink(toolfd, WL_YOUNGERSIB); /* Next */
X	close(toolfd);
X    }
X    close(wfd);
X    if (dbug) {
X	int i;
X	puts("windows at:");
X	for (i = 0; i < win_no; i++) {
X	    printf("%d,%d size: %d,%d\n",
X		win_rects[i].r_left, win_rects[i].r_top,
X		win_rects[i].r_width, win_rects[i].r_height);
X	}
X    }
X    return win_no;
X}
X
Xinitialize_color()
X{
X    u_char red[256], green[256], blue[256];
X
X    if (!is_color) {
X        cms_monochromeload(red, green, blue);
X        pr_putcolormap(screen, 0, 1, red, green, blue);
X        max_color = 1;
X    } else {
X	for (max_color = 0; max_color < 256; max_color++) {
X	    red[max_color] = 255 - max_color;
X	    green[max_color] = 255 - max_color/3;
X	    blue[max_color] = max_color/5;
X	    colors[max_color] = max_color;
X	}
X	if (!season)
X	    pr_putcolormap(screen, 0, 255, red, green, blue);
X	else /* swapping red and green maps makes shades of brown */
X	    pr_putcolormap(screen, 0, 255, green, red, blue);
X    }
X}
X#endif /* X11 */
END_OF_FILE
if test 21303 -ne `wc -c <'vine.c'`; then
    echo shar: \"'vine.c'\" unpacked with wrong size!
fi
# end of 'vine.c'
fi
echo shar: End of shell archive.
exit 0
dan
-----------------------------------------------------------
		    O'Reilly && Associates
		argv@sun.com / argv@ora.com
	   632 Petaluma Ave, Sebastopol, CA 95472 
     800-338-NUTS, in CA: 800-533-NUTS, FAX 707-829-0104
    Opinions expressed reflect those of the author only.