beta version of squig.c -- graphics hack for Suns
Jef Poskanzer
pokey at well.UUCP
Fri Jun 23 18:09:08 AEST 1989
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 at 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 at 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 );
}
More information about the Alt.sources
mailing list