pokey@well.UUCP (Jef Poskanzer) (06/23/89)
If you liked the spf3 program I recently posted in comp.sources.sun, then you'll love this. However, I need a little help from the net before I can officially release it. If you have a color Sun with other than a cg2 frame buffer, see below. The other color frame buffer types are cg1, cg3, cg4, cg5, and gp1. I don't know anything about these; no doubt some of them can't handle 8-bit color mode and so can't run this program at all. --- Jef Jef Poskanzer pokey@well.sf.ca.us {ucbvax, apple, hplabs}!well!pokey "Every new technology carries with it an opportunity to invent a new crime." -- Laurence Urgenson /* ** squig.c - draw a squiggley tubular pattern ** ** Version 0.8, 23jun89. ** ** Compile: cc -O squig.c -lpixrect -o squig ** ** Run: ** squig ** It should work on any frame buffer that supports 8-bit color, but it will ** be unacceptably slow on any frame buffer except the cg2. See note below. ** ** Comments to: ** pokey@well.sf.ca.us ** {ucbvax, lll-crg, sun!pacbell, apple, hplabs}!well!pokey ** ** Important Note: ** Because Sun's pr_polypoint routine doesn't take a list of colors as well ** as a list of points, I can't use it here. The only portable alternative ** is to call pr_put for each and every point, which is very slow. The ** non-portable alternative, accessing the frame buffer directly, is nice ** and fast, but must be implemented separately for each different type of ** frame buffer. Currently, only the cg2 has been done. If you have a ** different frame buffer and you would like to get squig going fast, contact ** me and we'll work out the necessary code. ** ** Copyright (C) 1989 by Jef Poskanzer. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #define MIN_CIRCLE_RATIO 40 #define MAX_CIRCLE_RATIO 20 #define SIZE_CYCLES 100 #define COLOR_CYCLES 10 #define MAX_D_COLOR 3 #define MIN_COLOR_OFFSET_CYCLES 3 #define MAX_COLOR_OFFSET_CYCLES 15 #include <stdio.h> #include <sys/file.h> #include <signal.h> #include <sys/types.h> #include <pixrect/pixrect_hs.h> #include <pixrect/memreg.h> #include <pixrect/cg2reg.h> #define max(a,b) ((a) > (b) ? (a) : (b)) #define min(a,b) ((a) < (b) ? (a) : (b)) long random(); Pixrect *disp_pr; int width, height; u_char *fb_base; int fb_linebytes = 0; u_char oldred[256], oldgreen[256], oldblue[256]; int oldplanes; u_char red[254], green[254], blue[254]; int cred[3], cgreen[3], cblue[3]; int dred[3], dgreen[3], dblue[3]; struct circle_point { int x, y; u_char color; int offset; }; struct circle_point **circles; int *circle_counts; int min_circle_radius, max_circle_radius, circle_radii; int circle_index, circle_radius, circle_number, color_offset; int color_offset_cycles; int d_circle_radius, d_color_offset; void count_circle_drawproc( x, y ) int x, y; { circle_counts[circle_radius]++; } void save_circle_drawproc( x, y ) int x, y; { circles[circle_radius][circle_index].x = x; circles[circle_radius][circle_index].y = y; circles[circle_radius][circle_index].color = 254 * circle_index / circle_counts[circle_radius] + 2; if ( fb_linebytes != 0 ) circles[circle_radius][circle_index].offset = y * fb_linebytes + x; circle_index++; } void rainbow_circle_drawproc( x, y ) int x, y; { register long r; register int newcolormap = 0; circle_number++; r = random(); /* Adjust radius. */ if ( circle_number % SIZE_CYCLES == 0 ) { register int t; /* First draw with new position and old size, to avoid gaps. */ draw_rainbow_circle( x, y ); if ( ( r % 46301 ) % ( circle_radii / 2 ) == 0 ) d_circle_radius = random() % 3 - 1; while ( (t = circle_radius + d_circle_radius ) < min_circle_radius || t > max_circle_radius ) d_circle_radius = random() % 3 - 1; circle_radius = t; } /* Adjust color cycles and offsets. */ if ( circle_number % MAX_COLOR_OFFSET_CYCLES == 0 ) { if ( ( r % 46307 ) % ( circle_radii / 2 ) == 0 ) { register int t; t = random() % 2 * 2 - 1; if ( color_offset_cycles == MAX_COLOR_OFFSET_CYCLES ) if ( t > 0 ) d_color_offset = -d_color_offset; else color_offset_cycles += t; else if ( color_offset_cycles == MIN_COLOR_OFFSET_CYCLES ) if ( t < 0 ) ; else color_offset_cycles += t; else color_offset_cycles += t; } } if ( circle_number % color_offset_cycles == 0 ) { color_offset += d_color_offset; if ( color_offset < 0 ) color_offset += 254; /* Got to be careful about staying positive, since % is NOT modulus. */ newcolormap = 1; } /* Adjust colors. */ if ( circle_number % COLOR_CYCLES == 0 ) { register int i, t; for ( i = 0; i < 3; i++ ) { for ( ; ; ) { t = cred[i] + dred[i]; if ( t >= 0 && t < 256 ) break; dred[i] = random() % ( MAX_D_COLOR * 2 ) - MAX_D_COLOR; if ( dred[i] <= 0 ) dred[i]--; } cred[i] = t; for ( ; ; ) { t = cgreen[i] + dgreen[i]; if ( t >= 0 && t < 256 ) break; dgreen[i] = random() % ( MAX_D_COLOR * 2 ) - MAX_D_COLOR; if ( dgreen[i] <= 0 ) dgreen[i]--; } cgreen[i] = t; for ( ; ; ) { t = cblue[i] + dblue[i]; if ( t >= 0 && t < 256 ) break; dblue[i] = random() % ( MAX_D_COLOR * 2 ) - MAX_D_COLOR; if ( dblue[i] <= 0 ) dblue[i]--; } cblue[i] = t; } for ( i = 0; i < 254; i++ ) if ( i < 85 ) { red[i] = cred[0] + ( cred[1] - cred[0] ) * ( i / 85.0 ); blue[i] = cblue[0] + ( cblue[1] - cblue[0] ) * ( i / 85.0 ); green[i] = cgreen[0] + ( cgreen[1] - cgreen[0] ) * ( i / 85.0 ); } else if ( i < 170 ) { red[i] = cred[1] + ( cred[2] - cred[1] ) * ( (i-85) / 85.0 ); blue[i] = cblue[1] + ( cblue[2] - cblue[1] ) * ( (i-85) / 85.0 ); green[i] = cgreen[1] + ( cgreen[2] - cgreen[1] ) * ( (i-85) / 85.0 ); } else { red[i] = cred[2] + ( cred[0] - cred[2] ) * ( (i-170) / 84.0 ); blue[i] = cblue[2] + ( cblue[0] - cblue[2] ) * ( (i-170) / 84.0 ); green[i] = cgreen[2] + ( cgreen[0] - cgreen[2] ) * ( (i-170) / 84.0 ); } newcolormap = 1; } /* Store new colors. */ if ( newcolormap ) putcolormap(); /* And draw circle. */ draw_rainbow_circle( x, y ); } draw_rainbow_circle( x, y ) int x, y; { register int i; register struct circle_point *cp; if ( fb_linebytes != 0 ) { register u_char *center; center = fb_base + y * fb_linebytes + x; for ( i = circle_counts[circle_radius] + 1, cp = circles[circle_radius]; --i; cp++ ) *( center + cp->offset ) = cp->color; } else { /* Fall back on slow but portable method. */ for ( i = circle_counts[circle_radius] + 1, cp = circles[circle_radius]; --i; cp++ ) pr_put( disp_pr, x + cp->x, y + cp->y, cp->color ); } } main( argc, argv ) int argc; char *argv[]; { int i; int thiscx, thiscy, nextcx, nextcy, prevex, prevey, nextex, nextey; #define MAXGROUPS 10 char groups[MAXGROUPS]; Pixrect *my_pr_open(); int terminate(); char *my_malloc(); char *usage = "usage: %s\n"; if ( argc != 1 ) { (void) fprintf( stderr, usage, argv[0] ); exit( 1 ); } if ( (disp_pr = my_pr_open( "/dev/cgfive0" )) == (Pixrect *) 0 ) if ( (disp_pr = my_pr_open( "/dev/cgthree0" )) == (Pixrect *) 0 ) if ( (disp_pr = my_pr_open( "/dev/gpone0a" )) == (Pixrect *) 0 ) if ( (disp_pr = my_pr_open( "/dev/cgtwo0" )) == (Pixrect *) 0 ) if ( (disp_pr = my_pr_open( "/dev/cgfour0" )) == (Pixrect *) 0 ) if ( (disp_pr = my_pr_open( "/dev/cgone0" )) == (Pixrect *) 0 ) if ( (disp_pr = my_pr_open( "/dev/fb" )) == (Pixrect *) 0 ) { (void) fprintf( stderr, "%s: error opening display\n", argv[0] ); exit( 1 ); } srandom( (int) time( 0 ) ); /* Save old state. */ pr_getcolormap( disp_pr, 0, 256, oldred, oldblue, oldgreen ); oldplanes = pr_get_plane_group( disp_pr ); (void) signal( SIGHUP, terminate ); (void) signal( SIGINT, terminate ); (void) signal( SIGTERM, terminate ); /* Set up colormap. */ (void) pr_available_plane_groups( disp_pr, MAXGROUPS, groups ); if ( ! groups[PIXPG_8BIT_COLOR] ) { (void) fprintf( stderr, "%s: display must implement 8-bit color\n", argv[0] ); exit( 1 ); } pr_set_plane_group( disp_pr, PIXPG_8BIT_COLOR ); for ( i = 0; i < 254; i++ ) red[i] = green[i] = blue[i] = 0; for ( i = 0; i < 3; i++ ) { cred[i] = cgreen[i] = cblue[i] = 0; dred[i] = random() % ( MAX_D_COLOR - 1 ) + 1; dgreen[i] = random() % ( MAX_D_COLOR - 1 ) + 1; dblue[i] = random() % ( MAX_D_COLOR - 1 ) + 1; } color_offset = 0; color_offset_cycles = MAX_COLOR_OFFSET_CYCLES; d_color_offset = 1; putcolormap(); width = disp_pr->pr_size.x; height = disp_pr->pr_size.y; if ( disp_pr->pr_ops->pro_put == cg2_put ) { struct cg2pr *cgd = (struct cg2pr *) disp_pr->pr_data; struct cg2fb *fb = (struct cg2fb *) cgd->cgpr_va; fb_base = cg2_roppixaddr( fb, 0, 0 ); fb_linebytes = cg2_roppixaddr( fb, 0, 1 ) - fb_base; } /* Clear to black and sign the corner. */ pr_rop( disp_pr, 0, 0, width, height, PIX_SRC | PIX_COLOR(1), 0, 0, 0 ); signit( disp_pr ); /* Measure circles. */ min_circle_radius = ( width + height ) / 2 / MIN_CIRCLE_RATIO; max_circle_radius = ( width + height ) / 2 / MAX_CIRCLE_RATIO; circle_radii = max_circle_radius - min_circle_radius + 1; circle_counts = (int *) my_malloc( ( max_circle_radius + 1 ) * sizeof(int) ); circles = (struct circle_point **) my_malloc( ( max_circle_radius + 1 ) * sizeof(struct circle_point *) ); for ( circle_radius = min_circle_radius; circle_radius <= max_circle_radius; circle_radius++ ) { circle_counts[circle_radius] = 0; circle( 0, 0, circle_radius, count_circle_drawproc ); circles[circle_radius] = (struct circle_point *) my_malloc( circle_counts[circle_radius] * sizeof(struct circle_point) ); circle_index = 0; circle( 0, 0, circle_radius, save_circle_drawproc ); } /* Initialize spline points. */ thiscx = random() % ( width - 2 * max_circle_radius ) + max_circle_radius; thiscy = random() % ( height - 2 * max_circle_radius ) + max_circle_radius; nextcx = random() % ( width - 2 * max_circle_radius ) + max_circle_radius; nextcy = random() % ( height - 2 * max_circle_radius ) + max_circle_radius; nextex = ( nextcx + thiscx ) / 2; nextey = ( nextcy + thiscy ) / 2; circle_radius = min_circle_radius; d_circle_radius = 1; circle_number = 0; /* Poke the frame buffer once using the "approved" method, to get the ** mode bits set correctly. */ pr_put( disp_pr, 0, 0, 1 ); /* Main loop. */ for ( ; ; ) { thiscx = nextcx; thiscy = nextcy; nextcx = random() % ( width - 2 * max_circle_radius ) + max_circle_radius; nextcy = random() % ( height - 2 * max_circle_radius ) + max_circle_radius; prevex = nextex; prevey = nextey; nextex = ( nextcx + thiscx ) / 2; nextey = ( nextcy + thiscy ) / 2; spline3( prevex, prevey, thiscx, thiscy, nextex, nextey, rainbow_circle_drawproc ); } } int terminate( sig, code, scp ) int sig, code; struct sigcontext *scp; { pr_putcolormap( disp_pr, 0, 256, oldred, oldgreen, oldblue ); pr_set_plane_group( disp_pr, oldplanes ); pr_rop( disp_pr, 0, 0, disp_pr->pr_size.x, disp_pr->pr_size.y, PIX_CLR, 0, 0, 0 ); exit( 0 ); } Pixrect * my_pr_open( fb ) char *fb; { int fd; /* Test with open first, to avoid stupid error messages from pr_open(). */ if ( (fd = open(fb, O_RDWR)) == -1 ) return (Pixrect *) 0; (void) close( fd ); return pr_open( fb ); } char * my_malloc( size ) unsigned size; { char *p, *malloc(); p = malloc( size ); if ( p == (char *) 0 ) { (void) fprintf( stderr, "out of memory\n" ); exit( 1 ); } return p; } putcolormap( ) { register int i; u_char rred[256], rgreen[256], rblue[256]; rred[0] = rgreen[0] = rblue[0] = 255; rred[1] = rgreen[1] = rblue[1] = 0; for ( i = 0; i < 254; i++ ) { rred[i + 2] = red[( i + color_offset ) % 254]; rgreen[i + 2] = green[( i + color_offset ) % 254]; rblue[i + 2] = blue[( i + color_offset ) % 254]; } pr_putcolormap( disp_pr, 0, 256, rred, rgreen, rblue ); } /* Signature stuff. */ static short posk_image[] = { 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, 0xffff,0xffff,0xffff,0xffff,0xffe7,0xcfff,0xffe7,0xcfff, 0xffe7,0x9fff,0xffcf,0xbfff,0xffcf,0x3fff,0xffdf,0x507f, 0xff8e,0x7e3f,0xff6e,0x7e7f,0xffcf,0x7e3f,0xffcf,0x7c7f, 0xffcf,0x067f,0xffcf,0x0e7f,0xffce,0x7e7f,0xffcf,0x7c7f, 0xffce,0x2a7f,0xffcf,0x14ff,0xffcf,0xfcff,0xffcf,0xffff, 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfffc,0x7fff, 0xfffe,0x3fff,0xfffe,0x3fff,0xfffe,0x3fff,0xfffe,0x3fff, 0xffff,0x3fff,0xfffe,0x107f,0xffa0,0x007f,0xfc1e,0x3fff, 0xffff,0x3fff,0xfffe,0x1fff,0xffff,0x3fff,0xfffe,0x3fff, 0xfffe,0x3fff,0xffff,0x3fff,0xfffe,0x2bff,0xffe8,0x01ff, 0xff05,0xd8ff,0xff7f,0xffff,0xffff,0xffff,0xff83,0xfcff, 0xfe67,0xe0ff,0xfe47,0x9dff,0xfe13,0xf9ff,0xfe7b,0xb3ff, 0xfe43,0x87ff,0xfe27,0xc7ff,0xfe65,0xc3ff,0xfc00,0x707f, 0xfe3e,0x7c3f,0xffff,0x3fff,0xffff,0x2fff,0xfff8,0x1fff, 0xfffe,0x2fff,0xffe0,0x01ff,0xff82,0xa8ff,0xffff,0xffff, 0xffff,0xffff,0xffff,0xefff,0xffff,0xe7ff,0xffc7,0xe7ff, 0xfff3,0xe7ff,0xffff,0xe7ff,0xffdf,0x667f,0xff1f,0x263f, 0xffdf,0x27ff,0xffff,0x69ff,0xfffd,0xc1ff,0xfffb,0xe1ff, 0xfffb,0xf1ff,0xfff7,0xf3ff,0xfff7,0xe7ff,0xffe7,0xc7ff, 0xffef,0xcfff,0xffcf,0x9fff,0xff8f,0x3fff,0xff9e,0x7fff, 0xffdc,0xffff,0xfffb,0xffff,0xffff,0xffff,0xffff,0xffff, 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff }; mpr_static( posk, 32, 92, 1, posk_image ); signit( pr ) Pixrect *pr; { #ifdef sun386 pr_flip( &posk ); #endif sun386 pr_rop( pr, pr->pr_size.x - posk.pr_size.x, pr->pr_size.y - posk.pr_size.y, posk.pr_size.x, posk.pr_size.y, PIX_SRC | PIX_COLOR(1), &posk, 0, 0 ); } /* Call-back DDAs taken from libppm. */ #define DDA_SCALE 8192 #define abs(x) ((x) < 0 ? -(x) : (x)) line( x0, y0, x1, y1, drawprocP ) int x0, y0, x1, y1; void (*drawprocP)(); { /* Special case zero-length lines. */ if ( x0 == x1 && y0 == y1 ) { (*drawprocP)( x0, y0 ); return; } /* Draw, using a simple DDA. */ if ( abs( x1 - x0 ) > abs( y1 - y0 ) ) { /* Loop over X domain. */ register long dy, srow; register int dx, col, row, prevrow; if ( x1 > x0 ) dx = 1; else dx = -1; dy = ( y1 - y0 ) * DDA_SCALE / abs( x1 - x0 ); prevrow = row = y0; srow = row * DDA_SCALE + DDA_SCALE / 2; col = x0; for ( ; ; ) { if ( row != prevrow ) { (*drawprocP)( col, prevrow ); prevrow = row; } (*drawprocP)( col, row ); if ( col == x1 ) break; srow += dy; row = srow / DDA_SCALE; col += dx; } } else { /* Loop over Y domain. */ register long dx, scol; register int dy, col, row, prevcol; if ( y1 > y0 ) dy = 1; else dy = -1; dx = ( x1 - x0 ) * DDA_SCALE / abs( y1 - y0 ); row = y0; prevcol = col = x0; scol = col * DDA_SCALE + DDA_SCALE / 2; for ( ; ; ) { if ( col != prevcol ) { (*drawprocP)( prevcol, row ); prevcol = col; } (*drawprocP)( col, row ); if ( row == y1 ) break; row += dy; scol += dx; col = scol / DDA_SCALE; } } } #define SPLINE_THRESH 3 spline3( x0, y0, x1, y1, x2, y2, drawprocP ) int x0, y0, x1, y1, x2, y2; void (*drawprocP)(); { register int xa, ya, xb, yb, xc, yc, xp, yp; xa = ( x0 + x1 ) / 2; ya = ( y0 + y1 ) / 2; xc = ( x1 + x2 ) / 2; yc = ( y1 + y2 ) / 2; xb = ( xa + xc ) / 2; yb = ( ya + yc ) / 2; xp = ( x0 + xb ) / 2; yp = ( y0 + yb ) / 2; if ( abs( xa - xp ) + abs( ya - yp ) > SPLINE_THRESH ) spline3( x0, y0, xa, ya, xb, yb, drawprocP ); else line( x0, y0, xb, yb, drawprocP ); xp = ( x2 + xb ) / 2; yp = ( y2 + yb ) / 2; if ( abs( xc - xp ) + abs( yc - yp ) > SPLINE_THRESH ) spline3( xb, yb, xc, yc, x2, y2, drawprocP ); else line( xb, yb, x2, y2, drawprocP ); } circle( cx, cy, radius, drawprocP ) int cx, cy, radius; void (*drawprocP)(); { register int x0, y0, x, y, prevx, prevy, nopointsyet; register long sx, sy, e; x0 = x = radius; y0 = y = 0; sx = x * DDA_SCALE + DDA_SCALE / 2; sy = y * DDA_SCALE + DDA_SCALE / 2; e = DDA_SCALE / radius; (*drawprocP)( x + cx, y + cy ); nopointsyet = 1; do { prevx = x; prevy = y; sx += e * sy / DDA_SCALE; sy -= e * sx / DDA_SCALE; x = sx / DDA_SCALE; y = sy / DDA_SCALE; if ( x != prevx || y != prevy ) { nopointsyet = 0; (*drawprocP)( x + cx, y + cy ); } } while ( nopointsyet || x != x0 || y != y0 ); }