about summary refs log tree commit diff
path: root/generator
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2021-12-27 17:33:56 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2021-12-27 17:33:56 +0000
commit6e629f983aa205c3eaa5f339f1c71bb5e7938049 (patch)
treea89f594443ac2330138f0bd0f19ee59135c2213f /generator
parentec52f41aabc9de9aac203c2f462252e403c7374a (diff)
downloadnetpbm-mirror-6e629f983aa205c3eaa5f339f1c71bb5e7938049.tar.gz
netpbm-mirror-6e629f983aa205c3eaa5f339f1c71bb5e7938049.tar.xz
netpbm-mirror-6e629f983aa205c3eaa5f339f1c71bb5e7938049.zip
Promote Development to Advanced to make Release 10.97.00
git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@4222 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'generator')
-rw-r--r--generator/Makefile2
-rw-r--r--generator/pbmnoise.c484
-rw-r--r--generator/pbmtext.c2
-rw-r--r--generator/ppmmake.c4
-rw-r--r--generator/ppmpat.c202
5 files changed, 614 insertions, 80 deletions
diff --git a/generator/Makefile b/generator/Makefile
index d54a6cc5..761181bd 100644
--- a/generator/Makefile
+++ b/generator/Makefile
@@ -18,7 +18,7 @@ SUBDIRS = pamtris
 
 PORTBINARIES = pamcrater pamgauss pamgradient \
 	       pamseq pamshadedrelief pamstereogram \
-	       pbmpage pbmmake pbmtext pbmupc \
+	       pbmpage pbmmake pbmnoise pbmtext pbmupc \
 	       pgmkernel pgmmake pgmnoise pgmramp \
 	       ppmcie ppmcolors ppmforge ppmmake ppmpat ppmrough ppmwheel \
 
diff --git a/generator/pbmnoise.c b/generator/pbmnoise.c
new file mode 100644
index 00000000..9a537d5c
--- /dev/null
+++ b/generator/pbmnoise.c
@@ -0,0 +1,484 @@
+/* pbmnoise.c - create a random bitmap of a specified size
+                with a specified ratio of white/black pixels
+
+   Written by Akira F Urushibata and contributed to the public domain 
+   December 2021
+*/
+
+#include <math.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pm_c_util.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "rand.h"
+#include "nstring.h"
+
+#include "pbm.h"
+
+
+
+static void
+parseFraction(const char *   const fraction,
+              unsigned int * const numeratorP,
+              unsigned int * const precisionP) {
+
+    unsigned int numerator, denominator;
+
+    sscanf(fraction, "%u/%u", &numerator, &denominator);
+
+    if (denominator > 65536)
+        pm_error("Denominator (%u) too large.", denominator);
+    else if (denominator == 0 || (denominator & (denominator - 1)) != 0)
+        pm_error("Denominator must be a power of two.  You specified %u.",
+                 denominator);
+    else if (numerator > denominator)
+        pm_error("Invalid fraction (%s).  Denominator must be larger than "
+                 "numerator.", fraction);
+    else {
+        /* Reduce fraction to lowest terms */
+        unsigned int numerator2, denominator2;
+            /* The fraction reduced to lowest terms */
+        unsigned int precision2;
+
+        if (numerator == 0) { /* all white image */
+            numerator2   = 0;
+            denominator2 = 1;
+            precision2   = 0;
+        } else if (numerator == denominator) { /* all black */
+            numerator2   = 1;
+            denominator2 = 1;
+            precision2   = 0;
+        } else {
+            numerator2   = numerator;   /* initial value */
+            denominator2 = denominator; /* initial value */
+
+            while ((numerator2 & 0x01) != 0x01) {
+                denominator2 /= 2;
+                numerator2   /= 2;
+            }
+            precision2 = 1;
+        }
+
+      if (denominator != denominator2)
+          pm_message("Ratio %u/%u = %u/%u",
+                     numerator, denominator, numerator2, denominator2);
+
+      *precisionP = (precision2 == 0) ? 0 : pm_maxvaltobits(denominator2 - 1);
+          /* pm_maxvaltobits(N):  Max of N is 65535 */
+
+      *numeratorP = numerator2;
+    }
+}
+
+
+
+static void
+setRatio(const char *   const ratioArg,
+         unsigned int * const numeratorP,
+         unsigned int * const precisionP) {
+/*----------------------------------------------------------------------------
+    Convert string "ratioArg" to ratio: numerator / (2 ^ precision) The input
+    string must be in fraction "n/d" form and the denominator must be a power
+    of 2.
+
+    Ratio is the probability of one binary digit being "1".  The ratio of "1"
+    (=PBM black) pixels in the entire output image will be close to this
+    value.
+
+    Most invalid strings are rejected here.
+----------------------------------------------------------------------------*/
+    if (strspn(ratioArg, "0123456789/") == strlen(ratioArg) &&
+             ratioArg[0] != '/' &&
+             ratioArg[strlen(ratioArg) - 1] != '/' &&
+             strchr(ratioArg, '/') != NULL &&
+             strchr(ratioArg, '/') == strrchr(ratioArg, '/'))
+        parseFraction(ratioArg, numeratorP, precisionP);
+    else
+        pm_error("Invalid ratio: '%s'", ratioArg);
+}
+
+
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    unsigned int width;
+    unsigned int height;
+    unsigned int numerator;
+    unsigned int precision;
+    unsigned int randomseed;
+    unsigned int randomseedSpec;
+    unsigned int bswap;   /* boolean */
+    unsigned int pack;    /* boolean */
+};
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry *option_def;
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+    const char * ratioArg;
+    unsigned int ratioSpec;
+    const char * endianArg;
+    unsigned int endianSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "ratio",         OPT_STRING, &ratioArg,
+            &ratioSpec,                     0);
+    OPTENT3(0, "randomseed",    OPT_UINT,   &cmdlineP->randomseed,
+            &cmdlineP->randomseedSpec,      0);
+    OPTENT3(0, "endian",        OPT_STRING, &endianArg,
+            &endianSpec,                    0);
+    OPTENT3(0, "pack",          OPT_FLAG,   NULL,
+            &cmdlineP->pack,                0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+    /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+    free(option_def);
+
+    if (ratioSpec)
+        setRatio(ratioArg, &cmdlineP->numerator, &cmdlineP->precision);
+    else {
+        /* Set ratio to default: 1/2 */
+        cmdlineP->numerator = 1;
+        cmdlineP->precision = 1;
+    }
+
+    if (!endianSpec)
+        cmdlineP->bswap = false;
+    else {
+        if      (streq(endianArg, "native"))
+            cmdlineP->bswap = false;
+        else if (streq(endianArg, "swap"))
+            cmdlineP->bswap = true;
+        else if (streq(endianArg, "big"))
+            cmdlineP->bswap = (BYTE_ORDER == LITTLE_ENDIAN);
+        else if (streq(endianArg, "little"))
+            cmdlineP->bswap = (BYTE_ORDER != LITTLE_ENDIAN);
+        else
+            pm_error("Invalid value '%s' for -endian argument.", endianArg);
+    }
+
+    if (argc-1 != 2)
+        pm_error("Wrong number of arguments (%d).  There are two "
+                 "non-option arguments: width and height in pixels",
+                 argc-1);
+    else {
+        cmdlineP->width  = pm_parse_width (argv[1]);
+        cmdlineP->height = pm_parse_height(argv[2]);
+    }
+}
+
+
+
+static void
+writeSingleColorRaster(unsigned int const cols,
+                       unsigned int const rows,
+                       bit          const color,
+                       FILE *       const ofP) {
+/*-----------------------------------------------------------------------------
+  Generate a single-color raster of color 'color', dimensions
+  'cols' by 'rows', to output file *ofP.
+-----------------------------------------------------------------------------*/
+    unsigned int const lastColChar = (cols - 1) / 8;
+
+    unsigned char * bitrow0;
+    unsigned int i;
+
+    bitrow0 = pbm_allocrow_packed(cols + 32);
+
+    for (i = 0; i <= lastColChar; ++i)
+        bitrow0[i] = color * 0xff;
+
+    if (color != 0)
+        pbm_cleanrowend_packed(bitrow0, cols);
+
+    /* row end trimming, not necessary with white */
+
+    {
+        unsigned int row;
+        for (row = 0; row < rows; ++row)
+            pbm_writepbmrow_packed(ofP, bitrow0, cols, 0);
+    }
+    pbm_freerow(bitrow0);
+}
+
+
+
+static uint32_t
+randombits(unsigned int       const precision,
+           unsigned int       const numerator,
+           struct pm_randSt * const randStP) {
+/*----------------------------------------------------------------------------
+  Generate 32 random bits so that for each bit the probability of "1"
+  being generated is numerator / (2 ^ precision).
+
+  How this works:
+
+  Ratios such as 1/8, 7/8, 1/16, 15/16, 1/32, 31/32 are straightforward.  How
+  do you get intermediate values such as 3/8, 5/8, 3/16, 5/16, 7/16?
+
+  Imagine a set of 10 bits which are 90% 1, 10% 0 and a random number source
+  which produces 1 and 0 in even proportions.
+
+  Conduct "and" and "or" on these bits:
+
+           0011111111 (90%)       0011111111 (90%)
+      and) 0101010101 (50%)   or) 0101010101 (50%)
+      ---------------------   --------------------
+           0001010101 (45%)       0111111111 (95%)
+
+  It can be seen from this example that an "and" operation gives a new ratio
+  which is halfway between the old ratio (90% in this example) and 0%, while
+  "or" gives one at the middle of the old ratio and 100% The corresponding
+  binary operations for fixed-point fractions are: "right-shift by one and
+  insert a 0 behind the fixed point" and "right-shift by one and insert a 1
+  behind the fixed point" respecatbly.
+
+  115/128 = 89.84% (near 90%)  In binary fix-point: 0.1110011
+  0.01110011 = 115/256 = 44.92%
+  0.11110011 = 243/256 = 94.92%
+
+  So to achieve the desired ratio, start at the LSB (right end) of
+  'numerator'.  Initialize the output bits to zero.  Conduct an "and" for each
+  0 and an "or" for each 1 with a freshly drawn random number until the fixed
+  point is reached.
+
+  An "and" operation of a random number and zero always yields zero.  To avoid
+  waste, we reduce terms to eliminate the trailing zeroes in 'numerator' and
+  indicate the fixed point with 'precision'.  Each time the program is
+  executed the location of the fixed point is set anew, but it stays constant
+  until the program exits.
+----------------------------------------------------------------------------*/
+    unsigned int i;
+    uint32_t mask;
+    uint32_t retval;
+
+    for (i = 0, mask = 0x01, retval=0x00000000;
+         i < precision;
+         ++i, mask <<= 1) {
+
+        uint32_t const randval = pm_rand32(randStP);
+
+        if ((numerator & mask) != 0 )
+            retval |= randval;
+        else
+            retval &= randval;
+    }
+    return retval;
+}
+
+
+
+static uint32_t
+swapWord(uint32_t const word) {
+/*----------------------------------------------------------------------------
+  Swap four bytes.
+  This swap method works regardless of native system endianness.
+----------------------------------------------------------------------------*/
+    uint32_t const retval =
+        ((word >> 24) & 0xff) |
+        ((word >>  8) & 0xff00) |
+        ((word <<  8) & 0xff0000) |
+        ((word << 24) & 0xff000000)
+        ;
+
+    return retval;
+}
+
+
+
+static void
+swapBitrow(unsigned char * const bitrow,
+           unsigned int    const words,
+           bool            const bswap) {
+/*----------------------------------------------------------------------------
+  Modify bits in 'bitrow', swapping as indicated.
+----------------------------------------------------------------------------*/
+    uint32_t * const bitrowByWord = (uint32_t *) bitrow;
+
+    unsigned int wordCnt;
+
+    for (wordCnt=0; wordCnt < words; ++wordCnt) {
+        uint32_t const inWord = bitrowByWord[wordCnt];
+
+        bitrowByWord[wordCnt] = bswap ? swapWord(inWord) : inWord;
+    }
+}
+
+
+
+static void
+pbmnoise(FILE *             const ofP,
+         unsigned int       const cols,
+         unsigned int       const rows,
+         unsigned int       const numerator,
+         unsigned int       const precision,
+         bool               const bswap,
+         struct pm_randSt * const randStP) {
+/*----------------------------------------------------------------------------
+  Default method of constructing rows.
+
+  Generate pixels in units of 32 bits.
+
+  If cols is not a multiple of 32, discard pixels beyond row end.
+-----------------------------------------------------------------------------*/
+    unsigned int const words = (cols + 31) / 32;
+
+    unsigned char * bitrow;
+    unsigned int row;
+    unsigned int wordCnt;
+
+    bitrow = pbm_allocrow_packed(cols + 32);
+
+    for (row = 0; row < rows; ++row) {
+        uint32_t * const bitrowByWord = (uint32_t *) bitrow;
+
+        for (wordCnt = 0; wordCnt < words; ++wordCnt)
+            bitrowByWord[wordCnt] = randombits(precision, numerator, randStP);
+
+        if (bswap)
+            swapBitrow(bitrow, words, bswap);
+
+        pbm_cleanrowend_packed(bitrow, cols);
+        pbm_writepbmrow_packed(ofP, bitrow, cols, 0);
+    }
+    pbm_freerow(bitrow);
+}
+
+
+
+static void
+pbmnoise_packed(FILE *             const ofP,
+                unsigned int       const cols,
+                unsigned int       const rows,
+                unsigned int       const numerator,
+                unsigned int       const precision,
+                bool               const bswap,
+                struct pm_randSt * const randStP) {
+/*----------------------------------------------------------------------------
+  Alternate method of constructing rows.
+  Like the default pbmnoise(), generate pixels in units of 32 bits
+  but carry over unused pixel data at row end to the next row.
+-----------------------------------------------------------------------------*/
+    unsigned char * bitrow0;
+    uint32_t * bitrowByWord;
+    unsigned int offset;
+    unsigned int row;
+    uint32_t wordSave;    /* Pixels carried over to next row */
+
+    bitrow0 = pbm_allocrow_packed(cols + 63);
+    bitrowByWord = (uint32_t *) bitrow0;
+
+    for (row = 0, offset = 0; row < rows; ++row) {
+        if (offset == 0) {
+            unsigned int const words = (cols + 31 ) / 32;
+
+            unsigned int wordCnt;
+
+            for (wordCnt = 0; wordCnt< words; ++wordCnt) {
+                bitrowByWord[wordCnt] =
+                    randombits(precision, numerator, randStP);
+            }
+
+            if (bswap)
+                swapBitrow(bitrow0, words, bswap);
+
+            wordSave = bitrowByWord[words - 1];
+
+            pbm_writepbmrow_packed(ofP, bitrow0, cols, 0);
+            offset = cols % 32;
+        } else {
+            unsigned int const wordsToFetch = (cols - (32 - offset) + 31) / 32;
+            unsigned int const lastWord = wordsToFetch;
+
+            unsigned int wordCnt;
+
+            bitrowByWord[0] = wordSave;
+
+            for (wordCnt = 0; wordCnt < wordsToFetch; ++wordCnt) {
+                bitrowByWord[wordCnt + 1] =
+                    randombits(precision, numerator, randStP);
+            }
+
+            if (bswap)
+                swapBitrow((unsigned char *) & bitrowByWord[1],
+                           wordsToFetch, bswap);
+
+            wordSave = bitrowByWord [lastWord];
+
+            pbm_writepbmrow_bitoffset(ofP, bitrow0, cols, 0, offset);
+            offset = (offset + cols) % 32;
+        }
+    }
+    pbm_freerow(bitrow0);
+}
+
+
+int
+main(int argc, const char *argv[]) {
+
+    struct CmdlineInfo cmdline;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    pbm_writepbminit(stdout, cmdline.width, cmdline.height, 0);
+
+    if (cmdline.precision == 0) {
+        bit color;
+
+        if (cmdline.numerator == 0)
+            color = PBM_WHITE;
+        else {
+            assert (cmdline.numerator == 1);
+            color = PBM_BLACK;
+        }
+        writeSingleColorRaster(cmdline.width, cmdline.height, color, stdout);
+    } else if (cmdline.width % 32 == 0 || !cmdline.pack) {
+        struct pm_randSt randSt;
+
+        pm_randinit(&randSt);
+        pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed);
+
+        pbmnoise(stdout, cmdline.width, cmdline.height,
+                 cmdline.numerator, cmdline.precision,
+                 cmdline.bswap, &randSt);
+
+        pm_randterm(&randSt);
+    } else {
+        struct pm_randSt randSt;
+
+        pm_randinit(&randSt);
+        pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed);
+
+        pbmnoise_packed(stdout, cmdline.width, cmdline.height,
+                        cmdline.numerator, cmdline.precision,
+                        cmdline.bswap, &randSt);
+
+        pm_randterm(&randSt);
+    }
+    return 0;
+}
+
+
diff --git a/generator/pbmtext.c b/generator/pbmtext.c
index 7ea64857..a4566d12 100644
--- a/generator/pbmtext.c
+++ b/generator/pbmtext.c
@@ -1282,6 +1282,8 @@ computeImageWidth(struct Text          const formattedText,
                   unsigned int *       const colsP,
                   unsigned int *       const maxleftbP) {
 
+    assert (pbm_maxfontwidth() < (INT_MAX - 10) / LINEBUFSIZE);
+
     if (intercharacterSpace < 0 && fontP->maxwidth < -intercharacterSpace)
         pm_error("negative -space value %.2f exceeds font width",
                  intercharacterSpace);
diff --git a/generator/ppmmake.c b/generator/ppmmake.c
index 7bac9601..b1de7b52 100644
--- a/generator/ppmmake.c
+++ b/generator/ppmmake.c
@@ -31,11 +31,11 @@ static void
 parseCommandLine(int argc, char ** argv,
                  struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
-  Convert program invocation arguments (argc,argv) into a format the 
+  Convert program invocation arguments (argc,argv) into a format the
   program can use easily, struct cmdlineInfo.  Validate arguments along
   the way and exit program with message if invalid.
 
-  Note that some string information we return as *cmdlineP is in the storage 
+  Note that some string information we return as *cmdlineP is in the storage
   argv[] points to.
 -----------------------------------------------------------------------------*/
     optEntry * option_def;
diff --git a/generator/ppmpat.c b/generator/ppmpat.c
index 9473afeb..170bfc58 100644
--- a/generator/ppmpat.c
+++ b/generator/ppmpat.c
@@ -39,9 +39,10 @@ typedef enum {
     PAT_POLES,
     PAT_SQUIG,
     PAT_CAMO,
-    PAT_ANTICAMO,
+    PAT_ANTICAMO
 } Pattern;
 
+
 typedef struct {
 /*----------------------------------------------------------------------------
    An ordered list of colors with a cursor.
@@ -57,16 +58,79 @@ struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    Pattern      basePattern;
-    unsigned int width;
-    unsigned int height;
-    unsigned int colorSpec;
-    ColorTable   colorTable;
-    unsigned int randomseed;
-    unsigned int randomseedSpec;
+    Pattern         basePattern;
+    unsigned int    width;
+    unsigned int    height;
+    unsigned int    colorSpec;
+    ColorTable      colorTable;
+    unsigned int    randomseed;
+    unsigned int    randomseedSpec;
+    ppmd_drawproc * drawProc;
 };
 
 
+
+static pixel
+averageTwoColors(pixel const p1,
+                 pixel const p2) {
+
+    pixel p;
+
+    PPM_ASSIGN(p,
+               (PPM_GETR(p1) + PPM_GETR(p2)) / 2,
+               (PPM_GETG(p1) + PPM_GETG(p2)) / 2,
+               (PPM_GETB(p1) + PPM_GETB(p2)) / 2);
+
+    return p;
+}
+
+
+
+static ppmd_drawproc average_drawproc;
+
+static void
+average_drawproc(pixel **     const pixels,
+                 int          const cols,
+                 int          const rows,
+                 pixval       const maxval,
+                 int          const col,
+                 int          const row,
+                 const void * const clientdata) {
+/*----------------------------------------------------------------------------
+  Reset the pixel's color to the average of the original color and the color
+  indicated by * clientdata.
+-----------------------------------------------------------------------------*/
+
+    if (col >= 0 && col < cols && row >= 0 && row < rows)
+        pixels[row][col] =
+            averageTwoColors(pixels[row][col], *((const pixel*) clientdata));
+}
+
+
+
+static ppmd_drawproc checkerboard_drawproc;
+
+static void
+checkerboard_drawproc(pixel **     const pixels,
+                      int          const cols,
+                      int          const rows,
+                      pixval       const maxval,
+                      int          const col,
+                      int          const row,
+                      const void * const clientdata) {
+/*----------------------------------------------------------------------------
+  If col and row are both even or both odd, do nothing.
+  If one is even and the other is odd, set the pixel's color to that indicated
+  by * clientdata.
+-----------------------------------------------------------------------------*/
+    if (col >= 0 && col < cols && row >= 0 &&
+        row < rows && row % 2 != col % 2)
+
+        pixels[row][col] = *((const pixel*) clientdata);
+}
+
+
+
 static void
 validateColorCount(Pattern      const basePattern,
                    unsigned int const colorCount) {
@@ -182,6 +246,7 @@ parseCommandLine(int argc, const char ** argv,
     unsigned int squig;
     unsigned int camo;
     unsigned int anticamo;
+    unsigned int meshSpec;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
@@ -199,9 +264,9 @@ parseCommandLine(int argc, const char ** argv,
     OPTENT3(0, "tartan",        OPT_FLAG,   NULL,
             &tartan,     0);
     OPTENT3(0, "argyle1",       OPT_FLAG,   NULL,
-            &argyle1,     0);
+            &argyle1,    0);
     OPTENT3(0, "argyle2",       OPT_FLAG,   NULL,
-            &argyle2,     0);
+            &argyle2,    0);
     OPTENT3(0, "poles",         OPT_FLAG,   NULL,
             &poles,      0);
     OPTENT3(0, "squig",         OPT_FLAG,   NULL,
@@ -214,6 +279,8 @@ parseCommandLine(int argc, const char ** argv,
             &cmdlineP->colorSpec,           0);
     OPTENT3(0, "randomseed",    OPT_UINT,       &cmdlineP->randomseed,
             &cmdlineP->randomseedSpec,      0);
+    OPTENT3(0, "mesh",          OPT_FLAG,   NULL,
+            &meshSpec,   0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -265,6 +332,14 @@ parseCommandLine(int argc, const char ** argv,
     } else
         cmdlineP->colorTable.count = 0;
 
+    if (meshSpec) {
+        if (gingham2 + gingham3 + madras + tartan > 0)
+            cmdlineP->drawProc = &checkerboard_drawproc;
+        else
+            pm_message("-mesh ignored (no effect with specified pattern)");
+    } else
+        cmdlineP->drawProc = &average_drawproc;
+
     if (argc-1 != 2)
         pm_error("You must specify 2 non-option arguments: width and height "
                  "in pixels.  You specified %u", argc-1);
@@ -363,37 +438,6 @@ randomDarkColor(struct pm_randSt * const randStP,
 
 
 
-static pixel
-averageTwoColors(pixel const p1,
-                 pixel const p2) {
-
-    pixel p;
-
-    PPM_ASSIGN(p,
-               (PPM_GETR(p1) + PPM_GETR(p2)) / 2,
-               (PPM_GETG(p1) + PPM_GETG(p2)) / 2,
-               (PPM_GETB(p1) + PPM_GETB(p2)) / 2);
-
-    return p;
-}
-
-
-
-static ppmd_drawproc average_drawproc;
-
-static void
-average_drawproc(pixel **     const pixels,
-                 int          const cols,
-                 int          const rows,
-                 pixval       const maxval,
-                 int          const col,
-                 int          const row,
-                 const void * const clientdata) {
-
-    if (col >= 0 && col < cols && row >= 0 && row < rows)
-        pixels[row][col] =
-            averageTwoColors(pixels[row][col], *((const pixel*) clientdata));
-}
 
 
 
@@ -563,7 +607,7 @@ clearBackgroundCamo(pixel **           const pixels,
     } else if (antiflag)
         color = randomAnticamoColor(randStP, maxval);
     else
-        color = randomCamoColor(randStP,maxval);
+        color = randomCamoColor(randStP, maxval);
 
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 0, cols, rows, PPMD_NULLDRAWPROC,
@@ -704,6 +748,7 @@ gingham2(pixel **           const pixels,
          unsigned int       const rows,
          ColorTable         const colorTable,
          struct pm_randSt * const randStP,
+         ppmd_drawproc    * const drawproc,
          pixval             const maxval) {
 
     bool  const colorSpec = (colorTable.count > 0);
@@ -726,11 +771,11 @@ gingham2(pixel **           const pixels,
 
     /* Woof. */
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, 0, cols, rowso2, average_drawproc,
+        pixels, cols, rows, maxval, 0, 0, cols, rowso2, drawproc,
         &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rowso2, cols, rows - rowso2,
-        average_drawproc, &forecolor);
+        drawproc, &forecolor);
 }
 
 
@@ -741,6 +786,7 @@ gingham3(pixel **           const pixels,
          unsigned int       const rows,
          ColorTable         const colorTable,
          struct pm_randSt * const randStP,
+         ppmd_drawproc    * const drawproc,
          pixval             const maxval) {
 
     bool  const colorSpec = (colorTable.count > 0);
@@ -772,17 +818,17 @@ gingham3(pixel **           const pixels,
 
     /* Woof. */
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, 0, cols, rowso4, average_drawproc,
+        pixels, cols, rows, maxval, 0, 0, cols, rowso4, drawproc,
         &backcolor);
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, rowso4, cols, rowso4, average_drawproc,
+        pixels, cols, rows, maxval, 0, rowso4, cols, rowso4, drawproc,
         &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 2 * rowso4, cols, rowso4,
-        average_drawproc, &fore2color);
+        drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 3 * rowso4, cols, rows - rowso4,
-        average_drawproc, &fore1color);
+        drawproc, &fore1color);
 }
 
 
@@ -793,6 +839,7 @@ madras(pixel **           const pixels,
        unsigned int       const rows,
        ColorTable         const colorTable,
        struct pm_randSt * const randStP,
+       ppmd_drawproc    * const drawproc,
        pixval             const maxval) {
 
     bool  const colorSpec = (colorTable.count > 0);
@@ -868,54 +915,54 @@ madras(pixel **           const pixels,
 
     /* Woof. */
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, 0, cols, rows2, average_drawproc,
+        pixels, cols, rows, maxval, 0, 0, cols, rows2, drawproc,
         &backcolor);
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, rows2, cols, rows3, average_drawproc,
+        pixels, cols, rows, maxval, 0, rows2, cols, rows3, drawproc,
         &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows2 + rows3, cols, rows2,
-        average_drawproc, &backcolor);
+        drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 2 * rows2 + rows3, cols, rows2,
-        average_drawproc, &fore1color);
+        drawproc, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 3 * rows2 + rows3, cols, rows2,
-        average_drawproc, &backcolor);
+        drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 4 * rows2 + rows3, cols, rows6a,
-        average_drawproc, &fore2color);
+        drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 4 * rows2 + rows3 + rows6a, cols, rows2,
-        average_drawproc, &backcolor);
+        drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 5 * rows2 + rows3 + rows6a, cols, rows3,
-        average_drawproc, &fore1color);
+        drawproc, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 5 * rows2 + 2 * rows3 + rows6a, cols,
-        rows2, average_drawproc, &backcolor);
+        rows2, drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 6 * rows2 + 2 * rows3 + rows6a, cols,
-        rows3, average_drawproc, &fore1color);
+        rows3, drawproc, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 6 * rows2 + 3 * rows3 + rows6a, cols,
-        rows2, average_drawproc, &backcolor);
+        rows2, drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 7 * rows2 + 3 * rows3 + rows6a, cols,
-        rows6b, average_drawproc, &fore2color);
+        rows6b, drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 7 * rows2 + 3 * rows3 + rows6a + rows6b,
-        cols, rows2, average_drawproc, &backcolor);
+        cols, rows2, drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 8 * rows2 + 3 * rows3 + rows6a + rows6b,
-        cols, rows2, average_drawproc, &fore1color);
+        cols, rows2, drawproc, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 9 * rows2 + 3 * rows3 + rows6a + rows6b,
-        cols, rows2, average_drawproc, &backcolor);
+        cols, rows2, drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0,
         10 * rows2 + 3 * rows3 + rows6a + rows6b,
-        cols, rows3, average_drawproc, &fore2color);
+        cols, rows3, drawproc, &fore2color);
 }
 
 
@@ -926,6 +973,7 @@ tartan(pixel **           const pixels,
        unsigned int       const rows,
        ColorTable         const colorTable,
        struct pm_randSt * const randStP,
+       ppmd_drawproc    * const drawproc,
        pixval             const maxval) {
 
     bool  const colorSpec = (colorTable.count > 0);
@@ -977,29 +1025,29 @@ tartan(pixel **           const pixels,
 
     /* Woof. */
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, 0, cols, rows5a, average_drawproc,
+        pixels, cols, rows, maxval, 0, 0, cols, rows5a, drawproc,
         &backcolor);
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, rows5a, cols, rows1, average_drawproc,
+        pixels, cols, rows, maxval, 0, rows5a, cols, rows1, drawproc,
         &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows5a + rows1, cols, rows5b,
-        average_drawproc, &backcolor);
+        drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + rows1, cols, rows3,
-        average_drawproc, &fore2color);
+        drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + rows1 + rows3, cols, rows1,
-        average_drawproc, &backcolor);
+        drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + 2 * rows1 + rows3, cols, rows3,
-        average_drawproc, &fore2color);
+        drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + 2 * rows1 + 2 * rows3, cols,
-        rows1, average_drawproc, &backcolor);
+        rows1, drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + 3 * rows1 + 2 * rows3, cols,
-        rows3, average_drawproc, &fore2color);
+        rows3, drawproc, &fore2color);
 }
 
 
@@ -1077,7 +1125,7 @@ argyle(pixel **     const pixels,
 
 
 
-static unsigned int const MAXPOLES = 500;
+#define MAXPOLES 500
 
 
 
@@ -1541,22 +1589,22 @@ main(int argc, const char ** argv) {
     switch (cmdline.basePattern) {
     case PAT_GINGHAM2:
         gingham2(pixels, cmdline.width, cmdline.height,
-                 cmdline.colorTable, &randSt, PPM_MAXMAXVAL);
+                 cmdline.colorTable, &randSt, cmdline.drawProc, PPM_MAXMAXVAL);
         break;
 
     case PAT_GINGHAM3:
         gingham3(pixels, cmdline.width, cmdline.height,
-                 cmdline.colorTable, &randSt, PPM_MAXMAXVAL);
+                 cmdline.colorTable, &randSt, cmdline.drawProc, PPM_MAXMAXVAL);
         break;
 
     case PAT_MADRAS:
         madras(pixels, cmdline.width, cmdline.height,
-               cmdline.colorTable, &randSt, PPM_MAXMAXVAL);
+               cmdline.colorTable, &randSt, cmdline.drawProc, PPM_MAXMAXVAL);
         break;
 
     case PAT_TARTAN:
         tartan(pixels, cmdline.width, cmdline.height,
-               cmdline.colorTable, &randSt, PPM_MAXMAXVAL);
+               cmdline.colorTable, &randSt, cmdline.drawProc, PPM_MAXMAXVAL);
         break;
 
     case PAT_ARGYLE1: