[comp.sources.misc] v09i029: PBMPLUS part 13 of 19: ppm.shar3 of 3

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (11/27/89)

Posting-number: Volume 9, Issue 29
Submitted-by: jef@helios.ee.lbl.gov (Jef Poskanzer)
Archive-name: pbmplus/part13

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	ppm/ppmscale.c
#	ppm/ppmscale.1
#	ppm/ppmshear.c
#	ppm/ppmshear.1
#	ppm/ppmpat.c
# This archive created: Wed Nov 22 21:14:00 1989
# By:	Jef Poskanzer (Paratheo-Anametamystikhood Of Eris Esoteric, Ada Lovelace Cabal)
export PATH; PATH=/bin:$PATH
if test ! -d 'ppm'
then
	echo shar: creating directory "'ppm'"
	mkdir 'ppm'
fi
echo shar: extracting "'ppm/ppmscale.c'" '(8732 characters)'
if test -f 'ppm/ppmscale.c'
then
	echo shar: will not over-write existing file "'ppm/ppmscale.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ppm/ppmscale.c'
X/* ppmscale.c - read a portable pixmap and scale it
X**
X** Copyright (C) 1989 by Jef Poskanzer.
X**
X** Permission to use, copy, modify, and distribute this software and its
X** documentation for any purpose and without fee is hereby granted, provided
X** that the above copyright notice appear in all copies and that both that
X** copyright notice and this permission notice appear in supporting
X** documentation.  This software is provided "as is" without express or
X** implied warranty.
X*/
X
X#include <stdio.h>
X#include "ppm.h"
X#ifdef SYSV
X#include <string.h>
X#else /*SYSV*/
X#include <strings.h>
X#endif /*SYSV*/
X
X#define SCALE 4096
X#define HALFSCALE 2048
X
X#define max(a,b) ((a) > (b) ? (a) : (b))
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X    {
X    FILE *ifd;
X    pixel *pixelrow, *temppixelrow, *newpixelrow;
X    register pixel *pP, *npP;
X    int argn, specxscale, specyscale, specxsize, specysize;
X    int rows, cols, rowsread, format, newrows, newcols;
X    register int row, col, needtoreadrow;
X    pixval maxval;
X    float xscale, yscale;
X    long sxscale, syscale;
X    register long fracrowtofill, fracrowleft;
X    long *rs, *gs, *bs;
X    char *usage = "<s> [ppmfile]\n            -xsize|width|-ysize|-height <s> [ppmfile]\n            -xscale|-yscale <s> [ppmfile]\n            -xscale|-xsize|-width <s> -yscale|-ysize|-height <s> [ppmfile]";
X
X    pm_progname = argv[0];
X
X    argn = 1;
X    specxscale = specyscale = specxsize = specysize = 0;
X
X    while ( argn + 1 < argc && argv[argn][0] == '-' )
X	{
X	if ( strncmp(argv[argn],"-xscale",max(strlen(argv[argn]),4)) == 0 )
X	    {
X	    if ( specxsize )
X		pm_error(
X		    "only one of -xsize/-width and -xscale may be specified",
X		    0,0,0,0,0 );
X	    if ( sscanf( argv[argn+1], "%g", &xscale ) != 1 )
X		pm_usage( usage );
X	    if ( xscale <= 0.0 )
X		pm_error( "x scale must be greater than 0", 0,0,0,0,0 );
X	    specxscale = 1;
X	    }
X	else if ( strncmp(argv[argn],"-yscale",max(strlen(argv[argn]),4)) == 0 )
X	    {
X	    if ( specysize )
X		pm_error(
X		    "only one of -ysize/-height and -yscale may be specified",
X		    0,0,0,0,0 );
X	    if ( sscanf( argv[argn+1], "%g", &yscale ) != 1 )
X		pm_usage( usage );
X	    if ( yscale <= 0.0 )
X		pm_error( "y scale must be greater than 0", 0,0,0,0,0 );
X	    specyscale = 1;
X	    }
X	else if ( strncmp(argv[argn],"-xsize",max(strlen(argv[argn]),4)) == 0 ||
X	          strncmp(argv[argn],"-width",max(strlen(argv[argn]),2)) == 0 )
X	    {
X	    if ( specxscale )
X		pm_error(
X		    "only one of -xscale and -xsize/-width may be specified",
X		    0,0,0,0,0 );
X	    if ( sscanf( argv[argn+1], "%d", &newcols ) != 1 )
X		pm_usage( usage );
X	    if ( newcols <= 0 )
X		pm_error( "new width must be greater than 0", 0,0,0,0,0 );
X	    specxsize = 1;
X	    }
X	else if ( strncmp(argv[argn],"-ysize",max(strlen(argv[argn]),4)) == 0 ||
X	          strncmp(argv[argn],"-height",max(strlen(argv[argn]),2)) == 0 )
X	    {
X	    if ( specyscale )
X		pm_error(
X		    "only one of -yscale and -ysize/-height may be specified",
X		    0,0,0,0,0 );
X	    if ( sscanf( argv[argn+1], "%d", &newrows ) != 1 )
X		pm_usage( usage );
X	    if ( newrows <= 0 )
X		pm_error( "new height must be greater than 0", 0,0,0,0,0 );
X	    specysize = 1;
X	    }
X	else
X	    pm_usage( usage );
X	argn += 2;
X	}
X
X    if ( ! ( specxscale || specyscale || specxsize || specysize ) )
X	{
X	/* No flags specified, so a single scale factor is required. */
X	if ( argn == argc )
X	    pm_usage( usage );
X	if ( sscanf( argv[argn], "%g", &xscale ) != 1 )
X	    pm_usage( usage );
X	if ( xscale <= 0.0 )
X	    pm_error( "scale must be greater than 0", 0,0,0,0,0 );
X	argn++;
X	yscale = xscale;
X	specxscale = specyscale = 1;
X	}
X
X    /* Now get input file. */
X    if ( argn != argc )
X	{
X	ifd = pm_openr( argv[argn] );
X	argn++;
X	}
X    else
X	ifd = stdin;
X
X    if ( argn != argc )
X	pm_usage( usage );
X
X    ppm_pbmmaxval = 255;	/* use larger value for better results */
X    ppm_readppminit( ifd, &cols, &rows, &maxval, &format );
X
X    /* Compute all sizes and scales. */
X    if ( specxsize )
X	xscale = (float) newcols / (float) cols;
X    else if ( specxscale )
X	newcols = cols * xscale + 0.999;
X
X    if ( specysize )
X	yscale = (float) newrows / (float) rows;
X    else if ( specyscale )
X	newrows = rows * yscale + 0.999;
X    else
X	if ( specxsize )
X	    {
X	    yscale = xscale;
X	    newrows = rows * yscale + 0.999;
X	    }
X	else
X	    {
X	    yscale = 1.0;
X	    newrows = rows;
X	    }
X    
X    if ( ! ( specxsize || specxscale ) )
X	if ( specysize )
X	    {
X	    xscale = yscale;
X	    newcols = cols * xscale + 0.999;
X	    }
X	else
X	    {
X	    xscale = 1.0;
X	    newcols = cols;
X	    }
X
X    sxscale = xscale * SCALE;
X    syscale = yscale * SCALE;
X
X    pixelrow = ppm_allocrow( cols );
X    if ( newrows == rows )	/* shortcut Y scaling if possible */
X	temppixelrow = pixelrow;
X    else
X	temppixelrow = ppm_allocrow( cols );
X    rs = (long *) pm_allocrow( cols, sizeof(long) );
X    gs = (long *) pm_allocrow( cols, sizeof(long) );
X    bs = (long *) pm_allocrow( cols, sizeof(long) );
X    rowsread = 0;
X    fracrowleft = syscale;
X    needtoreadrow = 1;
X    for ( col = 0; col < cols; col++ )
X	rs[col] = gs[col] = bs[col] = HALFSCALE;
X    fracrowtofill = SCALE;
X
X    ppm_writeppminit( stdout, newcols, newrows, maxval );
X    newpixelrow = ppm_allocrow( newcols );
X
X    for ( row = 0; row < newrows; row++ )
X	{
X	/* First scale Y from pixelrow into temppixelrow. */
X	if ( newrows == rows )	/* shortcut Y scaling if possible */
X	    {
X	    ppm_readppmrow( ifd, pixelrow, cols, maxval, format );
X	    }
X	else
X	    {
X	    while ( fracrowleft < fracrowtofill )
X		{
X		if ( needtoreadrow )
X		    if ( rowsread < rows )
X			{
X			ppm_readppmrow( ifd, pixelrow, cols, maxval, format );
X			rowsread++;
X			/* needtoreadrow = 0; */
X			}
X		for ( col = 0, pP = pixelrow; col < cols; col++, pP++ )
X		    {
X		    rs[col] += fracrowleft * PPM_GETR( *pP );
X		    gs[col] += fracrowleft * PPM_GETG( *pP );
X		    bs[col] += fracrowleft * PPM_GETB( *pP );
X		    }
X		fracrowtofill -= fracrowleft;
X		fracrowleft = syscale;
X		needtoreadrow = 1;
X		}
X	    /* Now fracrowleft is >= fracrowtofill, so we can produce a row. */
X	    if ( needtoreadrow )
X		if ( rowsread < rows )
X		    {
X		    ppm_readppmrow( ifd, pixelrow, cols, maxval, format );
X		    rowsread++;
X		    needtoreadrow = 0;
X		    }
X	    for ( col = 0, pP = pixelrow, npP = temppixelrow;
X		  col < cols; col++, pP++, npP++ )
X		{
X		register long r, g, b;
X
X		r = rs[col] + fracrowtofill * PPM_GETR( *pP );
X		g = gs[col] + fracrowtofill * PPM_GETG( *pP );
X		b = bs[col] + fracrowtofill * PPM_GETB( *pP );
X		r /= SCALE;
X		if ( r > maxval ) r = maxval;
X		g /= SCALE;
X		if ( g > maxval ) g = maxval;
X		b /= SCALE;
X		if ( b > maxval ) b = maxval;
X		PPM_ASSIGN( *npP, r, g, b );
X		rs[col] = gs[col] = bs[col] = HALFSCALE;
X		}
X	    fracrowleft -= fracrowtofill;
X	    if ( fracrowleft == 0 )
X		{
X		fracrowleft = syscale;
X		needtoreadrow = 1;
X		}
X	    fracrowtofill = SCALE;
X	    }
X
X	/* Now scale X from temppixelrow into newpixelrow and write it out. */
X	if ( newcols == cols )	/* shortcut X scaling if possible */
X	    ppm_writeppmrow( stdout, temppixelrow, newcols, maxval );
X	else
X	    {
X	    register long r, g, b;
X	    register long fraccoltofill, fraccolleft;
X	    register int needcol;
X
X	    npP = newpixelrow;
X	    fraccoltofill = SCALE;
X	    r = g = b = HALFSCALE;
X	    needcol = 0;
X	    for ( col = 0, pP = temppixelrow; col < cols; col++, pP++ )
X		{
X		fraccolleft = sxscale;
X		while ( fraccolleft >= fraccoltofill )
X		    {
X		    if ( needcol )
X			{
X			npP++;
X			r = g = b = HALFSCALE;
X			needcol = 0;
X			}
X		    r += fraccoltofill * PPM_GETR( *pP );
X		    g += fraccoltofill * PPM_GETG( *pP );
X		    b += fraccoltofill * PPM_GETB( *pP );
X		    r /= SCALE;
X		    if ( r > maxval ) r = maxval;
X		    g /= SCALE;
X		    if ( g > maxval ) g = maxval;
X		    b /= SCALE;
X		    if ( b > maxval ) b = maxval;
X		    PPM_ASSIGN( *npP, r, g, b );
X		    fraccolleft -= fraccoltofill;
X		    fraccoltofill = SCALE;
X		    needcol = 1;
X		    }
X		if ( fraccolleft > 0 )
X		    {
X		    if ( needcol )
X			{
X			npP++;
X			r = g = b = HALFSCALE;
X			needcol = 0;
X			}
X		    r += fraccolleft * PPM_GETR( *pP );
X		    g += fraccolleft * PPM_GETG( *pP );
X		    b += fraccolleft * PPM_GETB( *pP );
X		    fraccoltofill -= fraccolleft;
X		    }
X		}
X	    if ( fraccoltofill > 0 )
X		{
X		pP--;
X		r += fraccoltofill * PPM_GETR( *pP );
X		g += fraccoltofill * PPM_GETG( *pP );
X		b += fraccoltofill * PPM_GETB( *pP );
X		}
X	    if ( ! needcol )
X		{
X		r /= SCALE;
X		if ( r > maxval ) r = maxval;
X		g /= SCALE;
X		if ( g > maxval ) g = maxval;
X		b /= SCALE;
X		if ( b > maxval ) b = maxval;
X		PPM_ASSIGN( *npP, r, g, b );
X		}
X	    ppm_writeppmrow( stdout, newpixelrow, newcols, maxval );
X	    }
X	}
X
X    pm_close( ifd );
X
X    exit( 0 );
X    }
SHAR_EOF
if test 8732 -ne "`wc -c < 'ppm/ppmscale.c'`"
then
	echo shar: error transmitting "'ppm/ppmscale.c'" '(should have been 8732 characters)'
fi
fi # end of overwriting check
if test ! -d 'ppm'
then
	echo shar: creating directory "'ppm'"
	mkdir 'ppm'
fi
echo shar: extracting "'ppm/ppmscale.1'" '(1309 characters)'
if test -f 'ppm/ppmscale.1'
then
	echo shar: will not over-write existing file "'ppm/ppmscale.1'"
else
sed 's/^X//' << \SHAR_EOF > 'ppm/ppmscale.1'
X.TH ppmscale 1 "01 August 1989"
X.SH NAME
Xppmscale - scale a portable pixmap
X.SH SYNOPSIS
X.nf
Xppmscale <s> [ppmfile]
Xppmscale -xsize|-width|-ysize|-height <s> [ppmfile]
Xppmscale -xscale|-yscale <s> [ppmfile]
Xppmscale -xscale|-xsize|-width <s> -yscale|-ysize|-height <s> [ppmfile]
X.fi
X.SH DESCRIPTION
XReads a portable pixmap as input.
XScales it by the specified factor or factors and produces a portable
Xpixmap as output.
XYou can both enlarge (scale factor > 1) and reduce (scale factor < 1).
XYou can specify one dimension as a pixel size, and the other dimension
Xwill be scaled correspondingly.
XYou can specify one dimension as a scale, and the other dimension
Xwill not be scaled.
XOr, you can specify different scales for each axis, either as scale
Xfactors or as pixel sizes.
X.PP
XAll flags can be abbreviated to their shortest unique prefix.
X.SH "SEE ALSO"
Xpbmreduce(1), pnmenlarge(1), ppm(5)
X.SH AUTHOR
XCopyright (C) 1989 by Jef Poskanzer.
X
XPermission to use, copy, modify, and distribute this software and its
Xdocumentation for any purpose and without fee is hereby granted, provided
Xthat the above copyright notice appear in all copies and that both that
Xcopyright notice and this permission notice appear in supporting
Xdocumentation.  This software is provided "as is" without express or
Ximplied warranty.
SHAR_EOF
if test 1309 -ne "`wc -c < 'ppm/ppmscale.1'`"
then
	echo shar: error transmitting "'ppm/ppmscale.1'" '(should have been 1309 characters)'
fi
fi # end of overwriting check
if test ! -d 'ppm'
then
	echo shar: creating directory "'ppm'"
	mkdir 'ppm'
fi
echo shar: extracting "'ppm/ppmshear.c'" '(3120 characters)'
if test -f 'ppm/ppmshear.c'
then
	echo shar: will not over-write existing file "'ppm/ppmshear.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ppm/ppmshear.c'
X/* ppmshear.c - read a portable pixmap and shear it by some angle
X**
X** Copyright (C) 1989 by Jef Poskanzer.
X**
X** Permission to use, copy, modify, and distribute this software and its
X** documentation for any purpose and without fee is hereby granted, provided
X** that the above copyright notice appear in all copies and that both that
X** copyright notice and this permission notice appear in supporting
X** documentation.  This software is provided "as is" without express or
X** implied warranty.
X*/
X
X#include <stdio.h>
X#include <math.h>
X#define M_PI	3.14159265358979323846
X#include "ppm.h"
X
X#define SCALE 4096
X#define HALFSCALE 2048
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X    {
X    FILE *ifd;
X    pixel **pixels;
X    register pixel *newpixelrow, *pP, *npP;
X    pixel bgpixel, prevpixel;
X    int argn, rows, cols, newcols, row, col;
X    pixval maxval;
X    float fangle, shearfac, new0;
X    int intnew0;
X    register long fracnew0, omfracnew0;
X    char *usage = "<angle> [ppmfile]";
X
X    pm_progname = argv[0];
X
X    argn = 1;
X
X    if ( argn == argc )
X	pm_usage( usage );
X    if ( sscanf( argv[argn], "%g", &fangle ) != 1 )
X	pm_usage( usage );
X    argn++;
X    if ( fangle <= -90.0 || fangle >= 90.0 )
X	pm_error( "angle must be between -90 and 90", 0,0,0,0,0 );
X    fangle = fangle * M_PI / 180.0;	/* convert to radians */
X    shearfac = tan( fangle );
X    if ( shearfac < 0.0 )
X	shearfac = -shearfac;
X
X    if ( argn != argc )
X	{
X	ifd = pm_openr( argv[argn] );
X	argn++;
X	}
X    else
X	ifd = stdin;
X
X    if ( argn != argc )
X	pm_usage( usage );
X
X    ppm_pbmmaxval = 255;	/* use larger value for better results */
X    pixels = ppm_readppm( ifd, &cols, &rows, &maxval );
X
X    pm_close( ifd );
X
X    newcols = rows * shearfac + cols + 0.999999;
X
X    ppm_writeppminit( stdout, newcols, rows, maxval );
X    newpixelrow = ppm_allocrow( newcols );
X
X    bgpixel = ppm_backgroundpixel( pixels, cols, rows );
X
X    for ( row = 0; row < rows; row++ )
X	{
X	if ( fangle > 0.0 )
X	    new0 = row * shearfac;
X	else
X	    new0 = ( rows - row ) * shearfac;
X	intnew0 = (int) new0;
X	fracnew0 = ( new0 - intnew0 ) * SCALE;
X	omfracnew0 = SCALE - fracnew0;
X
X	for ( col = 0, npP = newpixelrow; col < newcols; col++, npP++ )
X	    *npP = bgpixel;
X
X	prevpixel = bgpixel;
X
X	for ( col = 0, npP = &(newpixelrow[intnew0]), pP = pixels[row]; col < cols; col++, npP++, pP++ )
X	    {
X	    PPM_ASSIGN( *npP,
X		( fracnew0 * PPM_GETR(prevpixel) + omfracnew0 * PPM_GETR(*pP) + HALFSCALE ) / SCALE,
X		( fracnew0 * PPM_GETG(prevpixel) + omfracnew0 * PPM_GETG(*pP) + HALFSCALE ) / SCALE,
X		( fracnew0 * PPM_GETB(prevpixel) + omfracnew0 * PPM_GETB(*pP) + HALFSCALE ) / SCALE );
X	    prevpixel = *pP;
X	    }
X	if ( fracnew0 > 0 )
X	    {
X	    npP = &(newpixelrow[intnew0 + cols]);
X	    PPM_ASSIGN( *npP,
X		( fracnew0 * PPM_GETR(prevpixel) + omfracnew0 * PPM_GETR(bgpixel) + HALFSCALE ) / SCALE,
X		( fracnew0 * PPM_GETG(prevpixel) + omfracnew0 * PPM_GETG(bgpixel) + HALFSCALE ) / SCALE,
X		( fracnew0 * PPM_GETB(prevpixel) + omfracnew0 * PPM_GETB(bgpixel) + HALFSCALE ) / SCALE );
X	    }
X
X	ppm_writeppmrow( stdout, newpixelrow, newcols, maxval );
X	}
X
X    exit( 0 );
X    }
SHAR_EOF
if test 3120 -ne "`wc -c < 'ppm/ppmshear.c'`"
then
	echo shar: error transmitting "'ppm/ppmshear.c'" '(should have been 3120 characters)'
fi
fi # end of overwriting check
if test ! -d 'ppm'
then
	echo shar: creating directory "'ppm'"
	mkdir 'ppm'
fi
echo shar: extracting "'ppm/ppmshear.1'" '(1354 characters)'
if test -f 'ppm/ppmshear.1'
then
	echo shar: will not over-write existing file "'ppm/ppmshear.1'"
else
sed 's/^X//' << \SHAR_EOF > 'ppm/ppmshear.1'
X.TH ppmshear 1 "08 February 1989"
X.SH NAME
Xppmshear - shear a portable pixmap by some angle
X.SH SYNOPSIS
Xppmshear angle [ppmfile]
X.SH DESCRIPTION
XReads a portable pixmap as input.
XShears it by the specified angle and produces a portable
Xpixmap as output.
XThe angle is in degrees (floating point), and measures this:
X.PP
X.nf
X    +-------+  +-------+
X    |       |  |\\       \\
X    |  OLD  |  | \\  NEW  \\
X    |       |  |an\\       \\
X    +-------+  |gle+-------+
X.fi
X.PP
XIf the angle is negative, it shears the other way:
X.PP
X.nf
X    +-------+  |-an+-------+
X    |       |  |gl/       /
X    |  OLD  |  |e/  NEW  /
X    |       |  |/       /
X    +-------+  +-------+
X.fi
X.PP
XThe angle should not get too close to 90 or -90, or the resulting
Xpixmap will be unreasonably wide.
X.PP
XThe shearing is implemented by looping over the source pixels and distributing
Xfractions to each of the destination pixels.
X.SH "SEE ALSO"
Xpnmflip(1), ppm(5)
X.SH AUTHOR
XCopyright (C) 1989 by Jef Poskanzer.
X
XPermission to use, copy, modify, and distribute this software and its
Xdocumentation for any purpose and without fee is hereby granted, provided
Xthat the above copyright notice appear in all copies and that both that
Xcopyright notice and this permission notice appear in supporting
Xdocumentation.  This software is provided "as is" without express or
Ximplied warranty.
SHAR_EOF
if test 1354 -ne "`wc -c < 'ppm/ppmshear.1'`"
then
	echo shar: error transmitting "'ppm/ppmshear.1'" '(should have been 1354 characters)'
fi
fi # end of overwriting check
if test ! -d 'ppm'
then
	echo shar: creating directory "'ppm'"
	mkdir 'ppm'
fi
echo shar: extracting "'ppm/ppmpat.c'" '(27285 characters)'
if test -f 'ppm/ppmpat.c'
then
	echo shar: will not over-write existing file "'ppm/ppmpat.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ppm/ppmpat.c'
X/* ppmpat.c - make a pixmap
X**
X** Copyright (C) 1989 by Jef Poskanzer.
X**
X** Permission to use, copy, modify, and distribute this software and its
X** documentation for any purpose and without fee is hereby granted, provided
X** that the above copyright notice appear in all copies and that both that
X** copyright notice and this permission notice appear in supporting
X** documentation.  This software is provided "as is" without express or
X** implied warranty.
X*/
X
X#include <stdio.h>
X#include <math.h>
X#define M_PI	3.14159265358979323846
X#include "ppm.h"
X#include "ppmdraw.h"
X#ifdef SYSV
X#include <string.h>
X#define srandom srand
X#define random rand
X#else /*SYSV*/
X#include <strings.h>
X#endif /*SYSV*/
X
X#define max(a,b) ((a) > (b) ? (a) : (b))
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X    {
X    pixel **pixels;
X    int argn, pattern, cols, rows;
X#define PAT_NONE 0
X#define PAT_GINGHAM2 1
X#define PAT_GINGHAM3 2
X#define PAT_MADRAS 3
X#define PAT_TARTAN 4
X#define PAT_POLES 5
X#define PAT_SQUIG 6
X#define PAT_CAMO 7
X#define PAT_ANTICAMO 8
X#define PAT_TEST 9
X    char *usage = "-gingham|-g2|-gingham3|-g3|-madras|-tartan|-poles|-squig|-camo|-anticamo <width> <height>";
X
X    pm_progname = argv[0];
X
X    argn = 1;
X    pattern = PAT_NONE;
X
X    while ( argn < argc && argv[argn][0] == '-' )
X	{
X	if ( strncmp(argv[argn],"-gingham2",max(strlen(argv[argn]),9)) == 0 ||
X	     strncmp(argv[argn],"-g2",max(strlen(argv[argn]),3)) == 0 )
X	    {
X	    if ( pattern != PAT_NONE )
X		pm_error( "only one base pattern may be specified", 0,0,0,0,0 );
X	    pattern = PAT_GINGHAM2;
X	    }
X	else if ( strncmp(argv[argn],"-gingham3",max(strlen(argv[argn]),9)) == 0 ||
X	     strncmp(argv[argn],"-g3",max(strlen(argv[argn]),3)) == 0 )
X	    {
X	    if ( pattern != PAT_NONE )
X		pm_error( "only one base pattern may be specified", 0,0,0,0,0 );
X	    pattern = PAT_GINGHAM3;
X	    }
X	else if ( strncmp(argv[argn],"-madras",max(strlen(argv[argn]),2)) == 0 )
X	    {
X	    if ( pattern != PAT_NONE )
X		pm_error( "only one base pattern may be specified", 0,0,0,0,0 );
X	    pattern = PAT_MADRAS;
X	    }
X	else if ( strncmp(argv[argn],"-tartan",max(strlen(argv[argn]),2)) == 0 )
X	    {
X	    if ( pattern != PAT_NONE )
X		pm_error( "only one base pattern may be specified", 0,0,0,0,0 );
X	    pattern = PAT_TARTAN;
X	    }
X	else if ( strncmp(argv[argn],"-poles",max(strlen(argv[argn]),2)) == 0 )
X	    {
X	    if ( pattern != PAT_NONE )
X		pm_error( "only one base pattern may be specified", 0,0,0,0,0 );
X	    pattern = PAT_POLES;
X	    }
X	else if ( strncmp(argv[argn],"-squig",max(strlen(argv[argn]),2)) == 0 )
X	    {
X	    if ( pattern != PAT_NONE )
X		pm_error( "only one base pattern may be specified", 0,0,0,0,0 );
X	    pattern = PAT_SQUIG;
X	    }
X	else if ( strncmp(argv[argn],"-camo",max(strlen(argv[argn]),2)) == 0 )
X	    {
X	    if ( pattern != PAT_NONE )
X		pm_error( "only one base pattern may be specified", 0,0,0,0,0 );
X	    pattern = PAT_CAMO;
X	    }
X	else if (strncmp(argv[argn],"-anticamo",max(strlen(argv[argn]),2)) == 0)
X	    {
X	    if ( pattern != PAT_NONE )
X		pm_error( "only one base pattern may be specified", 0,0,0,0,0 );
X	    pattern = PAT_ANTICAMO;
X	    }
X	else if ( strncmp(argv[argn],"-test",max(strlen(argv[argn]),3)) == 0 )
X	    {
X	    if ( pattern != PAT_NONE )
X		pm_error( "only one base pattern may be specified", 0,0,0,0,0 );
X	    pattern = PAT_TEST;
X	    }
X	else
X	    pm_usage( usage );
X	argn++;
X	}
X    if ( pattern == PAT_NONE )
X	pm_error( "a base pattern must be specified", 0,0,0,0,0 );
X
X    if ( argn == argc )
X	pm_usage( usage);
X    if ( sscanf( argv[argn], "%d", &cols ) != 1 )
X	pm_usage( usage );
X    argn++;
X    if ( argn == argc )
X	pm_usage( usage);
X    if ( sscanf( argv[argn], "%d", &rows ) != 1 )
X	pm_usage( usage );
X    argn++;
X
X    if ( argn != argc )
X	pm_usage( usage);
X
X    srandom( (int) time( 0 ) );
X    pixels = ppm_allocarray( cols, rows );
X
X    switch ( pattern )
X	{
X	case PAT_GINGHAM2:
X	gingham2( pixels, cols, rows, PPM_MAXMAXVAL );
X	break;
X
X	case PAT_GINGHAM3:
X	gingham3( pixels, cols, rows, PPM_MAXMAXVAL );
X	break;
X
X	case PAT_MADRAS:
X	madras( pixels, cols, rows, PPM_MAXMAXVAL );
X	break;
X
X	case PAT_TARTAN:
X	tartan( pixels, cols, rows, PPM_MAXMAXVAL );
X	break;
X
X	case PAT_POLES:
X	poles( pixels, cols, rows, PPM_MAXMAXVAL );
X	break;
X
X	case PAT_SQUIG:
X	squig( pixels, cols, rows, PPM_MAXMAXVAL );
X	break;
X
X	case PAT_CAMO:
X	camo( pixels, cols, rows, PPM_MAXMAXVAL, 0 );
X	break;
X
X	case PAT_ANTICAMO:
X	camo( pixels, cols, rows, PPM_MAXMAXVAL, 1 );
X	break;
X
X	case PAT_TEST:
X	test( pixels, cols, rows, PPM_MAXMAXVAL );
X	break;
X
X	default:
X	pm_error( "can't happen!", 0,0,0,0,0 );
X	}
X
X    /* All done, write it out. */
X    ppm_writeppm( stdout, pixels, cols, rows, PPM_MAXMAXVAL );
X
X    exit( 0 );
X    }
X
Xpixel
Xrandom_color( maxval )
Xpixval maxval;
X    {
X    pixel p;
X
X    PPM_ASSIGN(
X	p, random() % ( maxval + 1 ), random() % ( maxval + 1 ),
X	random() % ( maxval + 1 ) );
X
X    return p;
X    }
X
X#define DARK_THRESH 0.25
X
Xpixel
Xrandom_bright_color( maxval )
Xpixval maxval;
X    {
X    pixel p;
X
X    do
X	{
X	p = random_color( maxval );
X	}
X    while ( PPM_LUMIN( p ) <= maxval * DARK_THRESH );
X
X    return p;
X    }
X
Xpixel
Xrandom_dark_color( maxval )
Xpixval maxval;
X    {
X    pixel p;
X
X    do
X	{
X	p = random_color( maxval );
X	}
X    while ( PPM_LUMIN( p ) > maxval * DARK_THRESH );
X
X    return p;
X    }
X
Xpixel
Xaverage_two_colors( p1, p2 )
Xpixel p1, p2;
X    {
X    pixel p;
X
X    PPM_ASSIGN(
X	p, ( (int) PPM_GETR(p1) + (int) PPM_GETR(p2) ) / 2,
X	( (int) PPM_GETG(p1) + (int) PPM_GETG(p2) ) / 2,
X	( (int) PPM_GETB(p1) + (int) PPM_GETB(p2) ) / 2 );
X
X    return p;
X    }
X
Xvoid
Xaverage_drawproc( pixels, cols, rows, maxval, col, row, clientdata )
Xpixel **pixels;
Xint cols, rows, col, row;
Xpixval maxval;
Xchar *clientdata;
X    {
X    if ( col >= 0 && col < cols && row >= 0 && row < rows )
X	pixels[row][col] =
X	    average_two_colors( pixels[row][col], *( (pixel *) clientdata ) );
X    }
X
X/* Gingham stuff. */
X
Xgingham2( pixels, cols, rows, maxval )
Xpixel **pixels;
Xint cols, rows;
Xpixval maxval;
X    {
X    int colso2, rowso2;
X    pixel backcolor, forecolor;
X
X    colso2 = cols / 2;
X    rowso2 = rows / 2;
X    backcolor = random_dark_color( maxval );
X    forecolor = random_bright_color( maxval );
X
X    /* Warp. */
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 0, colso2, rows, PPMD_NULLDRAWPROC,
X	&backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, colso2, 0, cols - colso2, rows,
X	PPMD_NULLDRAWPROC, &forecolor );
X
X    /* Woof. */
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 0, cols, rowso2, average_drawproc,
X	&backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, rowso2, cols, rows - rowso2,
X	average_drawproc, &forecolor );
X    }
X
Xgingham3( pixels, cols, rows, maxval )
Xpixel **pixels;
Xint cols, rows;
Xpixval maxval;
X    {
X    int colso4, rowso4;
X    pixel backcolor, fore1color, fore2color;
X
X    colso4 = cols / 4;
X    rowso4 = rows / 4;
X    backcolor = random_dark_color( maxval );
X    fore1color = random_bright_color( maxval );
X    fore2color = random_bright_color( maxval );
X
X    /* Warp. */
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 0, colso4, rows, PPMD_NULLDRAWPROC,
X	&backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, colso4, 0, colso4, rows, PPMD_NULLDRAWPROC,
X	&fore1color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 2 * colso4, 0, colso4, rows,
X	PPMD_NULLDRAWPROC, &fore2color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 3 * colso4, 0, cols - colso4, rows,
X	PPMD_NULLDRAWPROC, &fore1color );
X
X    /* Woof. */
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 0, cols, rowso4, average_drawproc,
X	&backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, rowso4, cols, rowso4, average_drawproc,
X	&fore1color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 2 * rowso4, cols, rowso4,
X	average_drawproc, &fore2color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 3 * rowso4, cols, rows - rowso4,
X	average_drawproc, &fore1color );
X    }
X
Xmadras( pixels, cols, rows, maxval )
Xpixel **pixels;
Xint cols, rows;
Xpixval maxval;
X    {
X    int cols2, rows2, cols3, rows3, cols12, rows12, cols6a, rows6a, cols6b,
X	rows6b;
X    pixel backcolor, fore1color, fore2color;
X
X    cols2 = cols * 2 / 44;
X    rows2 = rows * 2 / 44;
X    cols3 = cols * 3 / 44;
X    rows3 = rows * 3 / 44;
X    cols12 = cols - 10 * cols2 - 4 * cols3;
X    rows12 = rows - 10 * rows2 - 4 * rows3;
X    cols6a = cols12 / 2;
X    rows6a = rows12 / 2;
X    cols6b = cols12 - cols6a;
X    rows6b = rows12 - rows6a;
X    backcolor = random_dark_color( maxval );
X    fore1color = random_bright_color( maxval );
X    fore2color = random_bright_color( maxval );
X
X    /* Warp. */
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 0, cols2, rows, PPMD_NULLDRAWPROC,
X	&backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, cols2, 0, cols3, rows, PPMD_NULLDRAWPROC,
X	&fore1color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, cols2 + cols3, 0, cols2, rows,
X	PPMD_NULLDRAWPROC,
X	&backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 2 * cols2 + cols3, 0, cols2, rows,
X	PPMD_NULLDRAWPROC, &fore2color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 3 * cols2 + cols3, 0, cols2, rows,
X	PPMD_NULLDRAWPROC, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 4 * cols2 + cols3, 0, cols6a, rows,
X	PPMD_NULLDRAWPROC, &fore1color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 4 * cols2 + cols3 + cols6a, 0, cols2, rows,
X	PPMD_NULLDRAWPROC, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 5 * cols2 + cols3 + cols6a, 0, cols3, rows,
X	PPMD_NULLDRAWPROC, &fore2color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 5 * cols2 + 2 * cols3 + cols6a, 0, cols2,
X	rows, PPMD_NULLDRAWPROC, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 6 * cols2 + 2 * cols3 + cols6a, 0, cols3,
X	rows, PPMD_NULLDRAWPROC, &fore2color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 6 * cols2 + 3 * cols3 + cols6a, 0, cols2,
X	rows, PPMD_NULLDRAWPROC, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 7 * cols2 + 3 * cols3 + cols6a, 0, cols6b,
X	rows, PPMD_NULLDRAWPROC, &fore1color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 7 * cols2 + 3 * cols3 + cols6a + cols6b, 0,
X	cols2, rows, PPMD_NULLDRAWPROC, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 8 * cols2 + 3 * cols3 + cols6a + cols6b, 0,
X	cols2, rows, PPMD_NULLDRAWPROC, &fore2color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 9 * cols2 + 3 * cols3 + cols6a + cols6b, 0,
X	cols2, rows, PPMD_NULLDRAWPROC, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 10 * cols2 + 3 * cols3 + cols6a + cols6b, 0,
X	cols3, rows, PPMD_NULLDRAWPROC, &fore1color );
X
X    /* Woof. */
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 0, cols, rows2, average_drawproc,
X	&backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, rows2, cols, rows3, average_drawproc,
X	&fore2color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, rows2 + rows3, cols, rows2,
X	average_drawproc, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 2 * rows2 + rows3, cols, rows2,
X	average_drawproc, &fore1color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 3 * rows2 + rows3, cols, rows2,
X	average_drawproc, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 4 * rows2 + rows3, cols, rows6a,
X	average_drawproc, &fore2color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 4 * rows2 + rows3 + rows6a, cols, rows2,
X	average_drawproc, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 5 * rows2 + rows3 + rows6a, cols, rows3,
X	average_drawproc, &fore1color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 5 * rows2 + 2 * rows3 + rows6a, cols,
X	rows2, average_drawproc, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 6 * rows2 + 2 * rows3 + rows6a, cols,
X	rows3, average_drawproc, &fore1color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 6 * rows2 + 3 * rows3 + rows6a, cols,
X	rows2, average_drawproc, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 7 * rows2 + 3 * rows3 + rows6a, cols,
X	rows6b, average_drawproc, &fore2color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 7 * rows2 + 3 * rows3 + rows6a + rows6b,
X	cols, rows2, average_drawproc, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 8 * rows2 + 3 * rows3 + rows6a + rows6b,
X	cols, rows2, average_drawproc, &fore1color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 9 * rows2 + 3 * rows3 + rows6a + rows6b,
X	cols, rows2, average_drawproc, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 10 * rows2 + 3 * rows3 + rows6a + rows6b,
X	cols, rows3, average_drawproc, &fore2color );
X    }
X
Xtartan( pixels, cols, rows, maxval )
Xpixel **pixels;
Xint cols, rows;
Xpixval maxval;
X    {
X    int cols1, rows1, cols3, rows3, cols10, rows10, cols5a, rows5a, cols5b,
X	rows5b;
X    pixel backcolor, fore1color, fore2color;
X
X    cols1 = cols / 22;
X    rows1 = rows / 22;
X    cols3 = cols * 3 / 22;
X    rows3 = rows * 3 / 22;
X    cols10 = cols - 3 * cols1 - 3 * cols3;
X    rows10 = rows - 3 * rows1 - 3 * rows3;
X    cols5a = cols10 / 2;
X    rows5a = rows10 / 2;
X    cols5b = cols10 - cols5a;
X    rows5b = rows10 - rows5a;
X    backcolor = random_dark_color( maxval );
X    fore1color = random_bright_color( maxval );
X    fore2color = random_bright_color( maxval );
X
X    /* Warp. */
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 0, cols5a, rows, PPMD_NULLDRAWPROC,
X	&backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, cols5a, 0, cols1, rows, PPMD_NULLDRAWPROC,
X	&fore1color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, cols5a + cols1, 0, cols5b, rows,
X	PPMD_NULLDRAWPROC, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, cols10 + cols1, 0, cols3, rows,
X	PPMD_NULLDRAWPROC, &fore2color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, cols10 + cols1 + cols3, 0, cols1, rows,
X	PPMD_NULLDRAWPROC, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, cols10 + 2 * cols1 + cols3, 0, cols3, rows,
X	PPMD_NULLDRAWPROC, &fore2color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, cols10 + 2 * cols1 + 2 * cols3, 0, cols1,
X	rows, PPMD_NULLDRAWPROC, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, cols10 + 3 * cols1 + 2 * cols3, 0, cols3,
X	rows, PPMD_NULLDRAWPROC, &fore2color );
X
X    /* Woof. */
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 0, cols, rows5a, average_drawproc,
X	&backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, rows5a, cols, rows1, average_drawproc,
X	&fore1color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, rows5a + rows1, cols, rows5b,
X	average_drawproc, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, rows10 + rows1, cols, rows3,
X	average_drawproc, &fore2color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, rows10 + rows1 + rows3, cols, rows1,
X	average_drawproc, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, rows10 + 2 * rows1 + rows3, cols, rows3,
X	average_drawproc, &fore2color );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, rows10 + 2 * rows1 + 2 * rows3, cols,
X	rows1, average_drawproc, &backcolor );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, rows10 + 3 * rows1 + 2 * rows3, cols,
X	rows3, average_drawproc, &fore2color );
X    }
X
X/* Poles stuff. */
X
X#define MAXPOLES 500
X
Xpoles( pixels, cols, rows, maxval )
Xpixel **pixels;
Xint cols, rows;
Xpixval maxval;
X    {
X    int poles, i, xs[MAXPOLES], ys[MAXPOLES], col, row;
X    pixel colors[MAXPOLES];
X
X    poles = cols * rows / 30000;
X
X    /* Place and color poles randomly. */
X    for ( i = 0; i < poles; i++ )
X	{
X	xs[i] = random() % cols;
X	ys[i] = random() % rows;
X	colors[i] = random_bright_color( maxval );
X	}
X
X    /* Now interpolate points. */
X    for ( row = 0; row < rows; row++ )
X	for ( col = 0; col < cols; col++ )
X	    {
X	    register long dist1, dist2, newdist, r, g, b;
X	    pixel color1, color2;
X
X	    /* Find two closest poles. */
X	    dist1 = dist2 = 2000000000;
X	    for ( i = 0; i < poles; i++ )
X		{
X		newdist = ( col - xs[i] ) * ( col - xs[i] ) +
X			  ( row - ys[i] ) * ( row - ys[i] );
X		if ( newdist < dist1 )
X		    {
X		    dist1 = newdist;
X		    color1 = colors[i];
X		    }
X		else if ( newdist < dist2 )
X		    {
X		    dist2 = newdist;
X		    color2 = colors[i];
X		    }
X		}
X
X	    /* And assign interpolated color. */
X	    newdist = dist1 + dist2;
X	    r = PPM_GETR(color1)*dist2/newdist + PPM_GETR(color2)*dist1/newdist;
X	    g = PPM_GETG(color1)*dist2/newdist + PPM_GETG(color2)*dist1/newdist;
X	    b = PPM_GETB(color1)*dist2/newdist + PPM_GETB(color2)*dist1/newdist;
X	    PPM_ASSIGN( pixels[row][col], r, g, b );
X	    }
X    }
X
X/* Squig stuff. */
X
X#define SQUIGS 5
X#define SQ_POINTS 7
X#define SQ_MAXCIRCLE_POINTS 5000
X
Xint sq_radius, sq_circlecount;
Xpixel sq_colors[SQ_MAXCIRCLE_POINTS];
Xint sq_xoffs[SQ_MAXCIRCLE_POINTS], sq_yoffs[SQ_MAXCIRCLE_POINTS];
X
Xvoid
Xsq_measurecircle_drawproc( pixels, cols, rows, maxval, col, row, clientdata )
Xpixel **pixels;
Xint cols, rows, col, row;
Xpixval maxval;
Xchar *clientdata;
X    {
X    sq_xoffs[sq_circlecount] = col;
X    sq_yoffs[sq_circlecount] = row;
X    sq_circlecount++;
X    }
X
Xvoid
Xsq_rainbowcircle_drawproc( pixels, cols, rows, maxval, col, row, clientdata )
Xpixel **pixels;
Xint cols, rows, col, row;
Xpixval maxval;
Xchar *clientdata;
X    {
X    int i;
X
X    for ( i = 0; i < sq_circlecount; i++ )
X	ppmd_point_drawproc(
X	    pixels, cols, rows, maxval, col + sq_xoffs[i], row + sq_yoffs[i],
X	    &(sq_colors[i]) );
X    }
X
Xsquig( pixels, cols, rows, maxval )
Xpixel **pixels;
Xint cols, rows;
Xpixval maxval;
X    {
X    pixel color;
X    int i, j, xc[SQ_POINTS], yc[SQ_POINTS], x0, y0, x1, y1, x2, y2, x3, y3;
X
X    /* Clear image to black. */
X    PPM_ASSIGN( color, 0, 0, 0 );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 0, cols, rows, PPMD_NULLDRAWPROC,
X	&color );
X
X    /* Draw the squigs. */
X    (void) ppmd_setlinetype( PPMD_LINETYPE_NODIAGS );
X    (void) ppmd_setlineclip( 0 );
X    for ( i = SQUIGS; i > 0; i-- )
X	{
X	/* Measure circle. */
X	sq_radius = ( cols + rows ) / 2 / ( 25 + i * 2 );
X	sq_circlecount = 0;
X	ppmd_circle(
X	    pixels, cols, rows, maxval, 0, 0, sq_radius,
X	    sq_measurecircle_drawproc, 0 );
X	sq_assign_colors( sq_circlecount, maxval, sq_colors );
X
X	/* Choose wrap-around point. */
X	switch ( random() % 4 )
X	    {
X	    case 0:
X	    x1 = random() % cols;
X	    y1 = 0;
X	    if ( x1 < cols / 2 )
X		xc[0] = random() % ( x1 * 2 );
X	    else
X		xc[0] = cols - 1 - random() % ( ( cols - x1 ) * 2 );
X	    yc[0] = random() % rows;
X	    x2 = x1;
X	    y2 = rows - 1;
X	    xc[SQ_POINTS - 1] = 2 * x2 - xc[0];
X	    yc[SQ_POINTS - 1] = y2 - yc[0];
X	    x0 = xc[SQ_POINTS - 1];
X	    y0 = yc[SQ_POINTS - 1] - rows;
X	    x3 = xc[0];
X	    y3 = yc[0] + rows;
X	    break;
X
X	    case 1:
X	    x2 = random() % cols;
X	    y2 = 0;
X	    if ( x2 < cols / 2 )
X		xc[SQ_POINTS - 1] = random() % ( x2 * 2 );
X	    else
X		xc[SQ_POINTS - 1] = cols - 1 - random() % ( ( cols - x2 ) * 2 );
X	    yc[SQ_POINTS - 1] = random() % rows;
X	    x1 = x2;
X	    y1 = rows - 1;
X	    xc[0] = 2 * x1 - xc[SQ_POINTS - 1];
X	    yc[0] = y1 - yc[SQ_POINTS - 1];
X	    x0 = xc[SQ_POINTS - 1];
X	    y0 = yc[SQ_POINTS - 1] + rows;
X	    x3 = xc[0];
X	    y3 = yc[0] - rows;
X	    break;
X
X	    case 2:
X	    x1 = 0;
X	    y1 = random() % rows;
X	    xc[0] = random() % cols;
X	    if ( y1 < rows / 2 )
X		yc[0] = random() % ( y1 * 2 );
X	    else
X		yc[0] = rows - 1 - random() % ( ( rows - y1 ) * 2 );
X	    x2 = cols - 1;
X	    y2 = y1;
X	    xc[SQ_POINTS - 1] = x2 - xc[0];
X	    yc[SQ_POINTS - 1] = 2 * y2 - yc[0];
X	    x0 = xc[SQ_POINTS - 1] - cols;
X	    y0 = yc[SQ_POINTS - 1];
X	    x3 = xc[0] + cols;
X	    y3 = yc[0];
X	    break;
X
X	    case 3:
X	    x2 = 0;
X	    y2 = random() % rows;
X	    xc[SQ_POINTS - 1] = random() % cols;
X	    if ( y2 < rows / 2 )
X		yc[SQ_POINTS - 1] = random() % ( y2 * 2 );
X	    else
X		yc[SQ_POINTS - 1] = rows - 1 - random() % ( ( rows - y2 ) * 2 );
X	    x1 = cols - 1;
X	    y1 = y2;
X	    xc[0] = x1 - xc[SQ_POINTS - 1];
X	    yc[0] = 2 * y1 - yc[SQ_POINTS - 1];
X	    x0 = xc[SQ_POINTS - 1] + cols;
X	    y0 = yc[SQ_POINTS - 1];
X	    x3 = xc[0] - cols;
X	    y3 = yc[0];
X	    break;
X	    }
X
X	for ( j = 1; j < SQ_POINTS - 1; j++ )
X	    {
X	    xc[j] = ( random() % ( cols - 2 * sq_radius ) ) + sq_radius;
X	    yc[j] = ( random() % ( rows - 2 * sq_radius ) ) + sq_radius;
X	    }
X
X	ppmd_line(
X	    pixels, cols, rows, maxval, x0, y0, x1, y1,
X	    sq_rainbowcircle_drawproc, 0 );
X	ppmd_polyspline(
X	    pixels, cols, rows, maxval, x1, y1, SQ_POINTS, xc, yc, x2, y2,
X	    sq_rainbowcircle_drawproc, 0 );
X	ppmd_line(
X	    pixels, cols, rows, maxval, x2, y2, x3, y3,
X	    sq_rainbowcircle_drawproc, 0 );
X	}
X    }
X
Xsq_assign_colors( circlecount, maxval, colors )
Xint circlecount;
Xpixval maxval;
Xpixel *colors;
X    {
X    pixel rc1, rc2, rc3;
X    float cco3;
X    int i;
X
X    rc1 = random_bright_color( maxval );
X    rc2 = random_bright_color( maxval );
X    rc3 = random_bright_color( maxval );
X    cco3 = ( circlecount - 1 ) / 3.0;
X
X    for ( i = 0; i < circlecount ; i++ )
X	{
X	if ( i < cco3 )
X	    PPM_ASSIGN(
X		colors[i],
X		(float) PPM_GETR(rc1) +
X		    ( (float) PPM_GETR(rc2) - (float) PPM_GETR(rc1) ) *
X		    (float) i / cco3,
X		(float) PPM_GETG(rc1) +
X		    ( (float) PPM_GETG(rc2) - (float) PPM_GETG(rc1) ) *
X		    (float) i / cco3,
X		(float) PPM_GETB(rc1) +
X		    ( (float) PPM_GETB(rc2) - (float) PPM_GETB(rc1) ) *
X		    (float) i / cco3 );
X	else if ( i < 2.0 * cco3 )
X	    PPM_ASSIGN(
X		colors[i],
X		(float) PPM_GETR(rc2) +
X		    ( (float) PPM_GETR(rc3) - (float) PPM_GETR(rc2) ) *
X		    ( (float) i / cco3 - 1.0 ),
X		(float) PPM_GETG(rc2) +
X		    ( (float) PPM_GETG(rc3) - (float) PPM_GETG(rc2) ) *
X		    ( (float) i / cco3 - 1.0 ),
X		(float) PPM_GETB(rc2) +
X		    ( (float) PPM_GETB(rc3) - (float) PPM_GETB(rc2) ) *
X		    ( (float) i / cco3 - 1.0 ) );
X	else
X	    PPM_ASSIGN(
X		colors[i],
X		(float) PPM_GETR(rc3) +
X		    ( (float) PPM_GETR(rc1) - (float) PPM_GETR(rc3) ) *
X		    ( (float) i / cco3 - 2.0 ),
X		(float) PPM_GETG(rc3) +
X		    ( (float) PPM_GETG(rc1) - (float) PPM_GETG(rc3) ) *
X		    ( (float) i / cco3 - 2.0 ),
X		(float) PPM_GETB(rc3) +
X		    ( (float) PPM_GETB(rc1) - (float) PPM_GETB(rc3) ) *
X		    ( (float) i / cco3 - 2.0 ) );
X	}
X    }
X
X/* Camouflage stuff. */
X
Xpixel
Xrandom_camo_color( maxval )
Xpixval maxval;
X    {
X    int v1, v2, v3;
X    pixel p;
X
X    v1 = ( (int) maxval + 1 ) / 8;
X    v2 = ( (int) maxval + 1 ) / 4;
X    v3 = ( (int) maxval + 1 ) / 2;
X
X    switch ( random() % 10 )
X	{
X	case 0:	case 1: case 2: /* light brown */
X	PPM_ASSIGN(
X	    p, random() % v3 + v3, random() % v3 + v2, random() % v3 + v2 );
X	break;
X
X	case 3:	case 4: case 5: /* dark green */
X	PPM_ASSIGN( p, random() % v2, random() % v2 + 3 * v1, random() % v2 );
X	break;
X
X	case 6:	case 7: /* brown */
X	PPM_ASSIGN( p, random() % v2 + v2, random() % v2, random() % v2 );
X	break;
X
X	case 8:	case 9: /* dark brown */
X	PPM_ASSIGN( p, random() % v1 + v1, random() % v1, random() % v1 );
X	break;
X	}
X
X    return p;
X    }
X
Xpixel
Xrandom_anticamo_color( maxval )
Xpixval maxval;
X    {
X    int v1, v2, v3;
X    pixel p;
X
X    v1 = ( (int) maxval + 1 ) / 4;
X    v2 = ( (int) maxval + 1 ) / 2;
X    v3 = 3 * v1;
X
X    switch ( random() % 15 )
X	{
X	case 0: case 1:
X	PPM_ASSIGN( p, random() % v1 + v3, random() % v2, random() % v2 );
X	break;
X
X	case 2: case 3:
X	PPM_ASSIGN( p, random() % v2, random() % v1 + v3, random() % v2 );
X	break;
X
X	case 4: case 5:
X	PPM_ASSIGN( p, random() % v2, random() % v2, random() % v1 + v3 );
X	break;
X
X	case 6: case 7: case 8:
X	PPM_ASSIGN( p, random() % v2, random() % v1 + v3, random() % v1 + v3 );
X	break;
X
X	case 9: case 10: case 11:
X	PPM_ASSIGN( p, random() % v1 + v3, random() % v2, random() % v1 + v3 );
X	break;
X
X	case 12: case 13: case 14:
X	PPM_ASSIGN( p, random() % v1 + v3, random() % v1 + v3, random() % v2 );
X	break;
X
X	}
X
X    return p;
X    }
X
Xfloat
Xrnduni( )
X    {
X    return random() % 1000000L / 1000000.0;
X    }
X
X#define BLOBRAD 50
X
X#define MIN_POINTS 7
X#define MAX_POINTS 13
X
X#define MIN_ELLIPSE_FACTOR 0.5
X#define MAX_ELLIPSE_FACTOR 2.0
X
X#define MIN_POINT_FACTOR 0.5
X#define MAX_POINT_FACTOR 2.0
X
Xcamo( pixels, cols, rows, maxval, antiflag )
Xpixel **pixels;
Xint cols, rows, antiflag;
Xpixval maxval;
X    {
X    pixel color;
X    int n, i, cx, cy;
X    char *fh;
X
X    /* Clear background. */
X    if ( antiflag )
X	color = random_anticamo_color( maxval );
X    else
X	color = random_camo_color( maxval );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 0, cols, rows, PPMD_NULLDRAWPROC,
X	&color );
X
X    n = ( rows * cols ) / ( BLOBRAD * BLOBRAD ) * 5;
X    for ( i = 0; i < n; i++ )
X	{
X	int points, p, xs[MAX_POINTS], ys[MAX_POINTS], x0, y0;
X	float a, b, c, theta, tang, tx, ty;
X
X	cx = random() % cols;
X	cy = random() % rows;
X
X	points = random() % ( MAX_POINTS - MIN_POINTS + 1 ) + MIN_POINTS;
X	a = rnduni() * ( MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR ) +
X	    MIN_ELLIPSE_FACTOR;
X	b = rnduni() * ( MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR ) +
X	    MIN_ELLIPSE_FACTOR;
X	theta = rnduni() * 2.0 * M_PI;
X	for ( p = 0; p < points; p++ )
X	    {
X	    tx = a * sin( p * 2.0 * M_PI / points );
X	    ty = b * cos( p * 2.0 * M_PI / points );
X	    tang = atan2( ty, tx ) + theta;
X	    c = rnduni() * ( MAX_POINT_FACTOR - MIN_POINT_FACTOR ) +
X		MIN_POINT_FACTOR;
X	    xs[p] = cx + BLOBRAD * c * sin( tang );
X	    ys[p] = cy + BLOBRAD * c * cos( tang );
X	    }
X	x0 = ( xs[0] + xs[points - 1] ) / 2;
X	y0 = ( ys[0] + ys[points - 1] ) / 2;
X
X	fh = ppmd_fill_init();
X
X	ppmd_polyspline(
X	    pixels, cols, rows, maxval, x0, y0, points, xs, ys, x0, y0,
X	    ppmd_fill_drawproc, fh );
X
X	if ( antiflag )
X	    color = random_anticamo_color( maxval );
X	else
X	    color = random_camo_color( maxval );
X	ppmd_fill( pixels, cols, rows, maxval, fh, PPMD_NULLDRAWPROC, &color );
X	}
X    }
X
X/* Test pattern.  Just a place to put ppmdraw exercises. */
X
Xtest( pixels, cols, rows, maxval )
Xpixel **pixels;
Xint cols, rows;
Xpixval maxval;
X    {
X    pixel color;
X    char *fh;
X
X    /* Clear image to black. */
X    PPM_ASSIGN( color, 0, 0, 0 );
X    ppmd_filledrectangle(
X	pixels, cols, rows, maxval, 0, 0, cols, rows, PPMD_NULLDRAWPROC,
X	&color );
X
X    fh = ppmd_fill_init();
X
X    ppmd_line( pixels, cols, rows, maxval, cols/8, rows/8, cols-cols/8, rows/4, ppmd_fill_drawproc, fh );
X    ppmd_line( pixels, cols, rows, maxval, cols-cols/8, rows/4, cols/2, rows/2, ppmd_fill_drawproc, fh );
X    ppmd_spline3( pixels, cols, rows, maxval, cols/2, rows/2, cols/2-cols/16, rows/2-rows/10, cols/2-cols/8, rows/2, ppmd_fill_drawproc, fh );
X    ppmd_spline3( pixels, cols, rows, maxval, cols/2-cols/8, rows/2, cols/4+cols/16, rows/2+rows/10, cols/4, rows/2, ppmd_fill_drawproc, fh );
X    ppmd_line( pixels, cols, rows, maxval, cols/4, rows/2, cols/8, rows/2, ppmd_fill_drawproc, fh );
X    ppmd_line( pixels, cols, rows, maxval, cols/8, rows/2, cols/8, rows/8, ppmd_fill_drawproc, fh );
X
X    PPM_ASSIGN( color, maxval, maxval, maxval );
X    ppmd_fill( pixels, cols, rows, maxval, fh, PPMD_NULLDRAWPROC, &color );
X    }
SHAR_EOF
if test 27285 -ne "`wc -c < 'ppm/ppmpat.c'`"
then
	echo shar: error transmitting "'ppm/ppmpat.c'" '(should have been 27285 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0