diff options
Diffstat (limited to 'generator')
-rw-r--r-- | generator/pamcrater.c | 60 | ||||
-rw-r--r-- | generator/pamstereogram.c | 116 | ||||
-rwxr-xr-x | generator/pgmcrater | 12 | ||||
-rw-r--r-- | generator/pgmnoise.c | 118 | ||||
-rw-r--r-- | generator/ppmforge.c | 173 | ||||
-rw-r--r-- | generator/ppmpat.c | 460 | ||||
-rwxr-xr-x | generator/ppmrainbow | 30 | ||||
-rw-r--r-- | generator/ppmrough.c | 507 |
8 files changed, 890 insertions, 586 deletions
diff --git a/generator/pamcrater.c b/generator/pamcrater.c index 43c27dbc..b8ceafa5 100644 --- a/generator/pamcrater.c +++ b/generator/pamcrater.c @@ -48,6 +48,7 @@ #include "pm_c_util.h" #include "mallocvar.h" +#include "rand.h" #include "shhopt.h" #include "nstring.h" #include "pam.h" @@ -169,11 +170,12 @@ static double const DepthBias2 = 0.5; /* Square of depth bias */ static double const -cast(double const high) { +cast(double const high, + struct pm_randSt * const randStP) { /*---------------------------------------------------------------------------- A random number in the range [0, 'high']. -----------------------------------------------------------------------------*/ - return high * ((rand() & 0x7FFF) / arand); + return high * ((pm_rand(randStP) & 0x7FFF) / arand); } @@ -252,11 +254,12 @@ setElev(struct pam * const pamP, static void -smallCrater(struct pam * const pamP, - tuple ** const terrain, - int const cx, - int const cy, - double const radius) { +smallCrater(struct pam * const pamP, + tuple ** const terrain, + int const cx, + int const cy, + double const radius, + struct pm_randSt * const randStP) { /*---------------------------------------------------------------------------- Generate a crater with a special method for tiny craters. @@ -283,10 +286,10 @@ smallCrater(struct pam * const pamP, /* The mean elevation of the Moore neighborhood (9 pixels centered on the crater location). */ - + /* Perturb the mean elevation by a small random factor. */ - int const x = radius >= 1 ? ((rand() >> 8) & 0x3) - 1 : 0; + int const x = radius >= 1 ? ((pm_rand(randStP) >> 8) & 0x3) - 1 : 0; assert(axelev > 0); @@ -374,7 +377,7 @@ normalCrater(struct pam * const pamP, av = (axelev + cz) * (1 - roll) + (terrainMod(pamP, terrain, x, y) + cz) * roll; av = MAX(1000, MIN(64000, av)); - + setElev(pamP, terrain, x, y, av); } } @@ -388,19 +391,20 @@ normalCrater(struct pam * const pamP, static void -plopCrater(struct pam * const pamP, - tuple ** const terrain, - int const cx, - int const cy, - double const radius, - bool const verbose) { +plopCrater(struct pam * const pamP, + tuple ** const terrain, + int const cx, + int const cy, + double const radius, + bool const verbose, + struct pm_randSt * const randStP) { if (verbose && pm_have_float_format()) pm_message("Plopping crater at (%4d, %4d) with radius %g", cx, cy, radius); if (radius < 3) - smallCrater (pamP, terrain, cx, cy, radius); + smallCrater (pamP, terrain, cx, cy, radius, randStP); else normalCrater(pamP, terrain, cx, cy, radius); } @@ -448,6 +452,7 @@ genCraters(struct CmdlineInfo const cmdline) { -----------------------------------------------------------------------------*/ tuple ** terrain; /* elevation array */ struct pam pam; + struct pm_randSt randSt; /* Allocate the elevation array and initialize it to mean surface elevation. @@ -455,18 +460,22 @@ genCraters(struct CmdlineInfo const cmdline) { initCanvas(cmdline.width, cmdline.height, &pam, &terrain); + pm_randinit(&randSt); + pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed); + if (cmdline.test) plopCrater(&pam, terrain, pam.width/2 + cmdline.offset, pam.height/2 + cmdline.offset, - (double) cmdline.radius, cmdline.verbose); + (double) cmdline.radius, cmdline.verbose, + &randSt); else { unsigned int const ncraters = cmdline.number; /* num of craters */ unsigned int l; for (l = 0; l < ncraters; ++l) { - int const cx = cast((double) pam.width - 1); - int const cy = cast((double) pam.height - 1); + int const cx = cast((double) pam.width - 1, &randSt); + int const cy = cast((double) pam.height - 1, &randSt); /* Thanks, Rudy, for this equation that maps the uniformly distributed numbers from cast() into an area-law distribution @@ -475,9 +484,11 @@ genCraters(struct CmdlineInfo const cmdline) { Produces values within the interval: 0.56419 <= radius <= 56.419 */ - double const radius = sqrt(1 / (M_PI * (1 - cast(0.9999)))); + double const radius = + sqrt(1 / (M_PI * (1 - cast(0.9999, &randSt)))); - plopCrater(&pam, terrain, cx, cy, radius, cmdline.verbose); + plopCrater(&pam, terrain, cx, cy, radius, + cmdline.verbose, &randSt); if (((l + 1) % 100000) == 0) pm_message("%u craters generated of %u (%u%% done)", @@ -485,6 +496,8 @@ genCraters(struct CmdlineInfo const cmdline) { } } + pm_randterm(&randSt); + pnm_writepam(&pam, terrain); pnm_freepamarray(terrain, &pam); @@ -503,12 +516,9 @@ main(int argc, const char ** argv) { parseCommandLine(argc, argv, &cmdline); - srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed()); - genCraters(cmdline); return 0; } - diff --git a/generator/pamstereogram.c b/generator/pamstereogram.c index 9b861b51..6e64b127 100644 --- a/generator/pamstereogram.c +++ b/generator/pamstereogram.c @@ -16,7 +16,7 @@ * * ---------------------------------------------------------------------- * - * Copyright (C) 2006-2020 Scott Pakin <scott+pbm@pakin.org> + * Copyright (C) 2006-2021 Scott Pakin <scott+pbm@pakin.org> * * All rights reserved. * @@ -58,11 +58,12 @@ #include "pm_c_util.h" #include "mallocvar.h" #include "nstring.h" +#include "rand.h" #include "shhopt.h" #include "pam.h" -enum outputType {OUTPUT_BW, OUTPUT_GRAYSCALE, OUTPUT_COLOR}; +enum OutputType {OUTPUT_BW, OUTPUT_GRAYSCALE, OUTPUT_COLOR}; /* ---------------------------------------------------------------------- */ @@ -85,13 +86,14 @@ struct cmdlineInfo { unsigned int magnifypat; /* -magnifypat option */ int xshift; /* -xshift option */ int yshift; /* -yshift option */ + int yfillshift; /* -yfillshift option */ const char * patfile; /* -patfile option. Null if none */ const char * texfile; /* -texfile option. Null if none */ const char * bgcolor; /* -bgcolor option */ unsigned int smoothing; /* -smoothing option */ unsigned int randomseed; /* -randomseed option */ unsigned int randomseedSpec; /* -randomseed option count */ - enum outputType outputType; /* Type of output file */ + enum OutputType outputType; /* Type of output file */ unsigned int xbegin; /* -xbegin option */ unsigned int xbeginSpec; /* -xbegin option count */ unsigned int tileable; /* -tileable option */ @@ -153,8 +155,8 @@ parseCommandLine(int argc, unsigned int option_def_index; unsigned int patfileSpec, texfileSpec, dpiSpec, eyesepSpec, depthSpec, - guidesizeSpec, magnifypatSpec, xshiftSpec, yshiftSpec, - bgcolorSpec, smoothingSpec, planesSpec; + guidesizeSpec, magnifypatSpec, xshiftSpec, yshiftSpec, yfillshiftSpec, + bgcolorSpec, smoothingSpec, planesSpec; unsigned int blackandwhite, grayscale, color; const char ** planes; @@ -194,6 +196,8 @@ parseCommandLine(int argc, &xshiftSpec, 0); OPTENT3(0, "yshift", OPT_INT, &cmdlineP->yshift, &yshiftSpec, 0); + OPTENT3(0, "yfillshift", OPT_INT, &cmdlineP->yfillshift, + &yfillshiftSpec, 0); OPTENT3(0, "patfile", OPT_STRING, &cmdlineP->patfile, &patfileSpec, 0); OPTENT3(0, "texfile", OPT_STRING, &cmdlineP->texfile, @@ -282,9 +286,10 @@ parseCommandLine(int argc, if (!xshiftSpec) cmdlineP->xshift = 0; - if (!yshiftSpec) cmdlineP->yshift = 0; + if (!yfillshiftSpec) + cmdlineP->yfillshift = 0; if (xshiftSpec && !cmdlineP->patfile) pm_error("-xshift is valid only with -patfile"); @@ -402,11 +407,12 @@ typedef struct outGenerator { -struct randomState { +struct RandomState { /* The state of a randomColor generator. */ unsigned int magnifypat; tuple * currentRow; unsigned int prevy; + struct pm_randSt * randStP; }; @@ -421,7 +427,7 @@ randomColor(outGenerator * const outGenP, /*---------------------------------------------------------------------------- Return a random RGB value. -----------------------------------------------------------------------------*/ - struct randomState * const stateP = outGenP->stateP; + struct RandomState * const stateP = outGenP->stateP; /* Every time we start a new row, we select a new sequence of random colors. @@ -436,7 +442,7 @@ randomColor(outGenerator * const outGenP, unsigned int plane; for (plane = 0; plane < outGenP->pam.depth; ++plane) { - unsigned int const randval = rand(); + unsigned int const randval = pm_rand(stateP->randStP); thisTuple[plane] = randval % modulus; } } @@ -456,9 +462,13 @@ static outGenStateTerm termRandomColor; static void termRandomColor(outGenerator * const outGenP) { - struct randomState * const stateP = outGenP->stateP; + struct RandomState * const stateP = outGenP->stateP; pnm_freepamrow(stateP->currentRow); + + pm_randterm(stateP->randStP); + + free(stateP->randStP); } @@ -468,7 +478,7 @@ initRandomColor(outGenerator * const outGenP, const struct pam * const inPamP, struct cmdlineInfo const cmdline) { - struct randomState * stateP; + struct RandomState * stateP; outGenP->pam.format = PAM_FORMAT; outGenP->pam.plainformat = 0; @@ -499,6 +509,10 @@ initRandomColor(outGenerator * const outGenP, stateP->magnifypat = cmdline.magnifypat; stateP->prevy = (unsigned int)(-cmdline.magnifypat); + MALLOCVAR_NOFAIL(stateP->randStP); + pm_randinit(stateP->randStP); + pm_srand2(stateP->randStP, cmdline.randomseedSpec, cmdline.randomseed); + outGenP->stateP = stateP; outGenP->getTuple = &randomColor; outGenP->terminateState = &termRandomColor; @@ -1178,6 +1192,8 @@ static void makeImageRow(outGenerator * const outGenP, unsigned int const row, unsigned int const xbegin, + unsigned int const farWidth, + int const yfillshift, const unsigned int * const sameL, const unsigned int * const sameR, const tuple * const outRow) { @@ -1200,20 +1216,26 @@ makeImageRow(outGenerator * const outGenP, sameL[N] > N is not allowed. -----------------------------------------------------------------------------*/ - int col; + unsigned int const width = outGenP->pam.width; + unsigned int const height = outGenP->pam.height; + + unsigned int col; int lastLinked; - for (col = (int)xbegin, lastLinked = INT_MIN; - col < outGenP->pam.width; - ++col) { + for (col = xbegin, lastLinked = -1; col < width; ++col) { tuple newtuple; - if (sameL[col] == col || sameL[col] < (int)xbegin) { + if (sameL[col] == col || sameL[col] < xbegin) { if (lastLinked == col - 1) newtuple = outRow[col - 1]; - else - newtuple = outGenP->getTuple(outGenP, col, row); + else { + if (col < xbegin + farWidth) + newtuple = outGenP->getTuple(outGenP, col, row); + else + newtuple = outGenP->getTuple( + outGenP, col, (row + height - yfillshift) % height); + } } else { newtuple = outRow[sameL[col]]; lastLinked = col; @@ -1222,20 +1244,25 @@ makeImageRow(outGenerator * const outGenP, pnm_assigntuple(&outGenP->pam, outRow[col], newtuple); } - for (col = (int)xbegin - 1, lastLinked = INT_MIN; col >= 0; --col) { + for (col = xbegin, lastLinked = -1; col > 0; --col) { tuple newtuple; - if (sameR[col] == col) { - if (lastLinked == col + 1) - newtuple = outRow[col + 1]; - else - newtuple = outGenP->getTuple(outGenP, col, row); + if (sameR[col-1] == col-1) { + if (lastLinked == col) + newtuple = outRow[col]; + else { + if (col > xbegin - farWidth) + newtuple = outGenP->getTuple(outGenP, col-1, row); + else + newtuple = outGenP->getTuple( + outGenP, col-1, (row + height - yfillshift) % height); + } } else { - newtuple = outRow[sameR[col]]; - lastLinked = col; + newtuple = outRow[sameR[col-1]]; + lastLinked = col-1; /* Keep track of the last pixel to be constrained. */ } - pnm_assigntuple(&outGenP->pam, outRow[col], newtuple); + pnm_assigntuple(&outGenP->pam, outRow[col-1], newtuple); } } @@ -1261,6 +1288,8 @@ makeOneImageRow(unsigned int const row, const unsigned int * const sameR, unsigned int * const colNumBuffer, unsigned int const xbegin, + unsigned int const farWidth, + int const yfillshift, tuple * const rowBuffer, tuple * const outRow) { @@ -1272,7 +1301,7 @@ makeOneImageRow(unsigned int const row, rowBuffer, outRow); else makeImageRow(outputGeneratorP, row, - xbegin, sameL, sameR, outRow); + xbegin, farWidth, yfillshift, sameL, sameR, outRow); } } @@ -1284,6 +1313,8 @@ constructRowTileable(const struct pam * const inPamP, bool const makeMask, const unsigned int * const sameL, const unsigned int * const sameR, + unsigned int const farWidth, + int const yfillshift, unsigned int const row, tuple * const outRow, tuple * const outRowBuf1, @@ -1300,10 +1331,10 @@ constructRowTileable(const struct pam * const inPamP, xbegin=maximum case. */ makeOneImageRow(row, outputGeneratorP, makeMask, sameL, sameR, colNumBuf2, - 0, outRowBuf2, outRow); + farWidth, yfillshift, 0, outRowBuf2, outRow); makeOneImageRow(row, outputGeneratorP, makeMask, sameL, sameR, colNumBuf2, - inPamP->width - 1, outRowBuf2, outRowMax); + farWidth, yfillshift, inPamP->width - 1, outRowBuf2, outRowMax); for (col = 0; col < inPamP->width; ++col) { unsigned int plane; @@ -1362,6 +1393,8 @@ doRow(const struct pam * const inPamP, unsigned int const magnifypat, unsigned int const smoothing, unsigned int const xbegin, + unsigned int const farWidth, + int const yfillshift, unsigned int const row, tuple * const inRow, tuple * const outRowBuf0, @@ -1397,13 +1430,16 @@ doRow(const struct pam * const inPamP, /* Construct a single row. */ if (tileable) { constructRowTileable(inPamP, outputGeneratorP, makeMask, - sameL, sameR, row, outRow, + sameL, sameR, + farWidth, yfillshift, + row, outRow, outRowBuf1, outRowBuf2, colNumBuf2); } else { makeOneImageRow(row, outputGeneratorP, makeMask, sameL, sameR, colNumBuf2, - xbegin, outRowBuf1, outRow); + xbegin, farWidth, yfillshift, + outRowBuf1, outRow); } /* Write the resulting row. */ @@ -1423,7 +1459,8 @@ makeImageRows(const struct pam * const inPamP, bool const tileable, unsigned int const magnifypat, unsigned int const smoothing, - unsigned int const xbegin) { + unsigned int const xbegin, + int const yfillshift) { tuple * inRow; /* Buffer for use in reading from the height-map image */ tuple * outRowBuf0; /* Buffer for use in generating output rows */ @@ -1433,6 +1470,8 @@ makeImageRows(const struct pam * const inPamP, unsigned int * colNumBuf1; unsigned int * colNumBuf2; unsigned int row; /* Current row in the input and output files */ + unsigned int pixelEyesep; + unsigned int farWidth; inRow = pnm_allocpamrow(inPamP); outRowBuf0 = pnm_allocpamrow(&outputGeneratorP->pam); @@ -1451,10 +1490,13 @@ makeImageRows(const struct pam * const inPamP, pm_error("Unable to allocate space for %u column buffer", inPamP->width); + pixelEyesep = ROUNDU(eyesep * dpi); + farWidth = pixelEyesep/(magnifypat * 2); + for (row = 0; row < inPamP->height; ++row) { doRow(inPamP, outputGeneratorP, depthOfField, eyesep, dpi, crossEyed, makeMask, tileable, magnifypat, smoothing, xbegin, - row, + farWidth, yfillshift, row, inRow, outRowBuf0, outRowBuf1, outRowBuf2, colNumBuf0, colNumBuf1, colNumBuf2); } @@ -1510,7 +1552,8 @@ produceStereogram(FILE * const ifP, makeImageRows(&inPam, outputGeneratorP, cmdline.depth, cmdline.eyesep, cmdline.dpi, cmdline.crosseyed, cmdline.makemask, cmdline.tileable, - cmdline.magnifypat, cmdline.smoothing, xbegin); + cmdline.magnifypat, cmdline.smoothing, xbegin, + cmdline.yfillshift); if (cmdline.guidebottom) drawguides(cmdline.guidesize, &outputGeneratorP->pam, @@ -1567,8 +1610,6 @@ main(int argc, const char *argv[]) { if (cmdline.verbose) reportParameters(cmdline); - srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed()); - ifP = pm_openr(cmdline.inputFilespec); /* Produce a stereogram. */ @@ -1580,4 +1621,3 @@ main(int argc, const char *argv[]) { } - diff --git a/generator/pgmcrater b/generator/pgmcrater index c66f5576..6d81df39 100755 --- a/generator/pgmcrater +++ b/generator/pgmcrater @@ -36,6 +36,16 @@ exec perl -w -x -S -- "$0" "$@" use strict; use Getopt::Long; +use IO::Handle; + + + +sub pm_message($) { + STDERR->print("pgmcrater: $_[0]\n"); +} + + + sub doVersionHack($) { my ($argvR) = @_; @@ -69,7 +79,7 @@ my $validOptions = GetOptions( 'randomseed=i' => \my $randomseedOpt); if (!$validOptions) { - print STDERR "Invalid syntax\n"; + pm_message("Invalid syntax"); exit(100); } diff --git a/generator/pgmnoise.c b/generator/pgmnoise.c index e3e4eca6..ea35956b 100644 --- a/generator/pgmnoise.c +++ b/generator/pgmnoise.c @@ -7,12 +7,17 @@ #include "pm_c_util.h" #include "mallocvar.h" #include "nstring.h" +#include "rand.h" #include "shhopt.h" #include "pgm.h" +/* constants */ +static unsigned long int const ceil31bits = 0x7fffffffUL; +static unsigned long int const ceil32bits = 0xffffffffUL; -struct cmdlineInfo { + +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -21,13 +26,15 @@ struct cmdlineInfo { unsigned int maxval; unsigned int randomseed; unsigned int randomseedSpec; + unsigned int verbose; }; static void -parseCommandLine(int argc, const char ** const argv, - struct cmdlineInfo * const cmdlineP) { +parseCommandLine(int argc, + const char ** const 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. @@ -46,6 +53,8 @@ parseCommandLine(int argc, const char ** const argv, &cmdlineP->randomseedSpec, 0); OPTENT3(0, "maxval", OPT_UINT, &cmdlineP->maxval, &maxvalSpec, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ @@ -57,7 +66,7 @@ parseCommandLine(int argc, const char ** const argv, if (maxvalSpec) { if (cmdlineP->maxval > PGM_OVERALLMAXVAL) - pm_error("Maxval too large: %u. Maximu is %u", + pm_error("Maxval too large: %u. Maximum is %u", cmdlineP->maxval, PGM_OVERALLMAXVAL); else if (cmdlineP->maxval == 0) pm_error("Maxval must not be zero"); @@ -95,38 +104,43 @@ parseCommandLine(int argc, const char ** const argv, static unsigned int -randPool(unsigned int const digits) { +randPool(unsigned int const nDigits, + struct pm_randSt * const randStP) { /*---------------------------------------------------------------------------- - Draw 'digits' bits from pool of random bits. If the number of random bits - in pool is insufficient, call rand() and add 31 bits to it. + Draw 'nDigits' bits from pool of random bits. If the number of random bits + in pool is insufficient, call pm_rand() and add N bits to it. + + N is 31 or 32. In raw mode we use N = 32 regardless of the actual number of + available bits. If there are only 31 available, we use zero for the MSB. - 'digits' must be at most 16. + 'nDigits' must be at most 16. - We assume that each call to rand() generates 31 bits, or RAND_MAX == - 2147483647. + We assume that each call to pm_rand() generates 31 or 32 bits, or + randStP->max == 2147483647 or 4294967295. - The underlying logic is flexible and endian-free. The above conditions - can be relaxed. + The underlying logic is flexible and endian-free. The above conditions can + be relaxed. -----------------------------------------------------------------------------*/ static unsigned long int hold=0; /* entropy pool */ static unsigned int len=0; /* number of valid bits in pool */ - unsigned int const mask = (1 << digits) - 1; - + unsigned int const mask = (1 << nDigits) - 1; + unsigned int const randbits = (randStP->max == ceil31bits) ? 31 : 32; unsigned int retval; - assert(RAND_MAX == 2147483647 && digits <= 16); + assert(randStP->max == ceil31bits || randStP->max == ceil32bits); + assert(nDigits <= 16); retval = hold; /* initial value */ - if (len > digits) { /* Enough bits in hold to satisfy request */ - hold >>= digits; - len -= digits; - } else { /* Load another 31 bits into hold */ - hold = rand(); + if (len > nDigits) { /* Enough bits in hold to satisfy request */ + hold >>= nDigits; + len -= nDigits; + } else { /* Load another 31 or 32 bits into hold */ + hold = pm_rand(randStP); retval |= (hold << len); - hold >>= (digits - len); - len = 31 - digits + len; + hold >>= (nDigits - len); + len = randbits - nDigits + len; } return (retval & mask); } @@ -134,36 +148,61 @@ randPool(unsigned int const digits) { static void -pgmnoise(FILE * const ofP, - unsigned int const cols, - unsigned int const rows, - gray const maxval) { +reportVerbose(struct pm_randSt * const randStP, + gray const maxval, + bool const usingPool) { + + pm_message("random seed: %u", randStP->seed); + pm_message("random max: %u maxval: %u", randStP->max, maxval); + pm_message("method: %s", usingPool ? "pool" : "modulo"); +} + + - bool const usingPool = !(RAND_MAX==2147483647 && (maxval & (maxval+1))); +static void +pgmnoise(FILE * const ofP, + unsigned int const cols, + unsigned int const rows, + gray const maxval, + bool const verbose, + struct pm_randSt * const randStP) { + + bool const usingPool = + (randStP->max==ceil31bits || randStP->max==ceil32bits) && + !(maxval & (maxval+1)); unsigned int const bitLen = pm_maxvaltobits(maxval); unsigned int row; gray * destrow; /* If maxval is 2^n-1, we draw exactly n bits from the pool. - Otherwise call rand() and determine gray value by modulo. + Otherwise call pm_rand() and determine gray value by modulo. In the latter case, there is a minuscule skew toward 0 (=black) because smaller numbers are produced more frequently by modulo. Thus we employ the pool method only when it is certain that no - skew will ensue. + skew will result. To illustrate the point, consider converting the outcome of one roll of a fair, six-sided die to 5 values (0 to 4) by N % 5. The - probability for values 1, 2, 3, 4 are 1/6, but 0 alone is 2/6. + probability for values 1, 2, 3, 4 is 1/6, but 0 alone is 2/6. Average is 10/6 or 1.6667, compared to 2.0 from an ideal generator which produces exactly 5 values. With two dice average improves to 70/36 or 1.9444. The more (distinct) dice we roll, or the more binary digits we draw, the smaller the skew. + + The pool method is economical. But there is an additional merit: + No bits are lost this way. This gives us a means to check the + integrity of the random number generator. + + - Akira Urushibata, March 2021 */ + if (verbose) + reportVerbose(randStP, maxval, usingPool); + destrow = pgm_allocrow(cols); pgm_writepgminit(ofP, cols, rows, maxval, 0); @@ -172,12 +211,11 @@ pgmnoise(FILE * const ofP, if (usingPool) { unsigned int col; for (col = 0; col < cols; ++col) - destrow[col] = randPool(bitLen); - } - else { + destrow[col] = randPool(bitLen, randStP); + } else { unsigned int col; for (col = 0; col < cols; ++col) - destrow[col] = rand() % (maxval + 1); + destrow[col] = pm_rand(randStP) % (maxval + 1); } pgm_writepgmrow(ofP, destrow, cols, maxval, 0); } @@ -191,18 +229,22 @@ int main(int argc, const char * argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; + struct pm_randSt randSt; pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed()); + pm_randinit(&randSt); + pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed); + + pgmnoise(stdout, cmdline.width, cmdline.height, cmdline.maxval, + cmdline.verbose, &randSt); - pgmnoise(stdout, cmdline.width, cmdline.height, cmdline.maxval); + pm_randterm(&randSt); return 0; } - diff --git a/generator/ppmforge.c b/generator/ppmforge.c index 114f7f18..7cef571f 100644 --- a/generator/ppmforge.c +++ b/generator/ppmforge.c @@ -34,12 +34,14 @@ #define _XOPEN_SOURCE 500 /* get M_PI in math.h */ #include <math.h> +#include <float.h> #include <assert.h> #include "pm_c_util.h" -#include "ppm.h" #include "mallocvar.h" +#include "rand.h" #include "shhopt.h" +#include "ppm.h" static double const hugeVal = 1e50; @@ -59,12 +61,8 @@ typedef struct { /* Definition for obtaining random numbers. */ -#define nrand 4 /* Gauss() sample count */ -#define Cast(low, high) ((low)+(((high)-(low)) * ((rand() & 0x7FFF) / arand))) - /* Local variables */ -static double arand, gaussadd, gaussfac; /* Gaussian random parameters */ static double fracdim; /* Fractal dimension */ static double powscale; /* Power law scaling exponent */ static int meshsize = 256; /* FFT mesh size */ @@ -172,6 +170,11 @@ parseCommandLine(int argc, const char **argv, if (cmdlineP->dimension <= 0.0) pm_error("-dimension must be greater than zero. " "You specified %f", cmdlineP->dimension); + else if (cmdlineP->dimension > 5.0 + FLT_EPSILON) + pm_error("-dimension must not be greater than 5. " + "Results are not interesting with higher numbers, so " + "we assume it is a mistake. " + "You specified %f", cmdlineP->dimension); } else cmdlineP->dimension = cmdlineP->clouds ? 2.15 : 2.4; @@ -335,45 +338,73 @@ fourn(float * const data, #undef SWAP +struct Gauss { + struct pm_randSt randSt; + unsigned int nrand; /* Gauss() sample count */ + double arand; + double gaussadd; + double gaussfac; +}; + + static void -initgauss(unsigned int const seed) { +initgauss(struct Gauss * const gaussP, + unsigned int const seed) { /*---------------------------------------------------------------------------- Initialize random number generators. As given in Peitgen & Saupe, page 77. -----------------------------------------------------------------------------*/ + gaussP->nrand = 4; + /* Range of random generator */ - arand = pow(2.0, 15.0) - 1.0; - gaussadd = sqrt(3.0 * nrand); - gaussfac = 2 * gaussadd / (nrand * arand); - srand(seed); + gaussP->arand = pow(2.0, 15.0) - 1.0; + gaussP->gaussadd = sqrt(3.0 * gaussP->nrand); + gaussP->gaussfac = 2 * gaussP->gaussadd / (gaussP->nrand * gaussP->arand); + + pm_randinit(&gaussP->randSt); + pm_srand(&gaussP->randSt, seed); } static double -gauss() { +gauss(struct Gauss * const gaussP) { /*---------------------------------------------------------------------------- A Gaussian random number. As given in Peitgen & Saupe, page 77. -----------------------------------------------------------------------------*/ - int i; + unsigned int i; double sum; - for (i = 1, sum = 0.0; i <= nrand; ++i) { - sum += (rand() & 0x7FFF); + for (i = 1, sum = 0.0; i <= gaussP->nrand; ++i) { + sum += (pm_rand(&gaussP->randSt) & 0x7FFF); } - return gaussfac * sum - gaussadd; + return gaussP->gaussfac * sum - gaussP->gaussadd; +} + + + +static double +cast(double const low, + double const high, + struct Gauss * const gaussP) { + + return + low + + ((high-low) * ((pm_rand(&gaussP->randSt) & 0x7FFF) / gaussP->arand)); + } static void -spectralsynth(float ** const x, - unsigned int const n, - double const h) { +spectralsynth(float ** const x, + unsigned int const n, + double const h, + struct Gauss * const gaussP) { /*---------------------------------------------------------------------------- Spectrally synthesized fractal motion in two dimensions. @@ -395,9 +426,10 @@ spectralsynth(float ** const x, for (i = 0; i <= n / 2; i++) { for (j = 0; j <= n / 2; j++) { - phase = 2 * M_PI * ((rand() & 0x7FFF) / arand); + phase = 2 * M_PI * ((pm_rand(&gaussP->randSt) & 0x7FFF) / + gaussP->arand); if (i != 0 || j != 0) { - rad = pow((double) (i * i + j * j), -(h + 1) / 2) * gauss(); + rad = pow((double) (i*i + j*j), -(h + 1) / 2) * gauss(gaussP); } else { rad = 0; } @@ -416,8 +448,9 @@ spectralsynth(float ** const x, Imag(a, n / 2, n / 2) = 0; for (i = 1; i <= n / 2 - 1; i++) { for (j = 1; j <= n / 2 - 1; j++) { - phase = 2 * M_PI * ((rand() & 0x7FFF) / arand); - rad = pow((double) (i * i + j * j), -(h + 1) / 2) * gauss(); + phase = 2 * M_PI * ((pm_rand(&gaussP->randSt) & 0x7FFF) / + gaussP->arand); + rad = pow((double) (i * i + j * j), -(h + 1) / 2) * gauss(gaussP); rcos = rad * cos(phase); rsin = rad * sin(phase); Real(a, i, n - j) = rcos; @@ -469,22 +502,22 @@ temprgb(double const temp, static void -etoile(pixel * const pix) { +etoile(pixel * const pix, + struct Gauss * const gaussP) { /*---------------------------------------------------------------------------- Set a pixel in the starry sky. -----------------------------------------------------------------------------*/ - if ((rand() % 1000) < starfraction) { -#define StarQuality 0.5 /* Brightness distribution exponent */ -#define StarIntensity 8 /* Brightness scale factor */ -#define StarTintExp 0.5 /* Tint distribution exponent */ - double v = StarIntensity * pow(1 / (1 - Cast(0, 0.9999)), - (double) StarQuality), - temp, - r, g, b; - - if (v > 255) { - v = 255; - } + if ((pm_rand(&gaussP->randSt) % 1000) < starfraction) { + double const starQuality = 0.5; + /* Brightness distribution exponent */ + double const starIntensity = 8; + /* Brightness scale factor */ + double const starTintExp = 0.5; + /* Tint distribution exponent */ + double const v = + MIN(255.0, + starIntensity * pow(1 / (1 - cast(0, 0.9999, gaussP)), + (double) starQuality)); /* We make a special case for star color of zero in order to prevent floating point roundoff which would otherwise @@ -493,13 +526,17 @@ etoile(pixel * const pix) { 256 shades in the image. */ if (starcolor == 0) { - int vi = v; + pixval const vi = v; PPM_ASSIGN(*pix, vi, vi, vi); } else { + double temp; + double r, g, b; + temp = 5500 + starcolor * - pow(1 / (1 - Cast(0, 0.9999)), StarTintExp) * - ((rand() & 7) ? -1 : 1); + pow(1 / (1 - cast(0, 0.9999, gaussP)), starTintExp) * + ((pm_rand(&gaussP->randSt) & 7) ? -1 : 1); + /* Constrain temperature to a reasonable value: >= 2600K (S Cephei/R Andromedae), <= 28,000 (Spica). */ temp = MAX(2600, MIN(28000, temp)); @@ -575,7 +612,8 @@ createPlanetStuff(bool const clouds, unsigned char ** const cpP, Vector * const sunvecP, unsigned int const cols, - pixval const maxval) { + pixval const maxval, + struct Gauss * const gaussP) { double *u, *u1; unsigned int *bxf, *bxc; @@ -585,8 +623,8 @@ createPlanetStuff(bool const clouds, /* Compute incident light direction vector. */ - shang = hourspec ? hourangle : Cast(0, 2 * M_PI); - siang = inclspec ? inclangle : Cast(-M_PI * 0.12, M_PI * 0.12); + shang = hourspec ? hourangle : cast(0, 2 * M_PI, gaussP); + siang = inclspec ? inclangle : cast(-M_PI * 0.12, M_PI * 0.12, gaussP); sunvecP->x = sin(shang) * cos(siang); sunvecP->y = sin(siang); @@ -594,7 +632,7 @@ createPlanetStuff(bool const clouds, /* Allow only 25% of random pictures to be crescents */ - if (!hourspec && ((rand() % 100) < 75)) { + if (!hourspec && ((pm_rand(&gaussP->randSt) % 100) < 75)) { flipped = (sunvecP->z < 0); sunvecP->z = fabs(sunvecP->z); } else @@ -634,7 +672,7 @@ createPlanetStuff(bool const clouds, pm_error("Cannot allocate %u element interpolation tables.", cols); { unsigned int j; - for (j = 0; j < cols; j++) { + for (j = 0; j < cols; ++j) { double const bx = (n - 1) * uprj(j, cols); bxf[j] = floor(bx); @@ -651,8 +689,9 @@ createPlanetStuff(bool const clouds, static void -generateStarrySkyRow(pixel * const pixels, - unsigned int const cols) { +generateStarrySkyRow(pixel * const pixels, + unsigned int const cols, + struct Gauss * const gaussP) { /*---------------------------------------------------------------------------- Generate a starry sky. Note that no FFT is performed; the output is generated directly from a power law @@ -660,8 +699,8 @@ generateStarrySkyRow(pixel * const pixels, -----------------------------------------------------------------------------*/ unsigned int j; - for (j = 0; j < cols; j++) - etoile(pixels + j); + for (j = 0; j < cols; ++j) + etoile(pixels + j, gaussP); } @@ -881,7 +920,8 @@ generatePlanetRow(pixel * const pixelrow, int const byc, int const byf, Vector const sunvec, - pixval const maxval) { + pixval const maxval, + struct Gauss * const gaussP) { unsigned int const StarClose = 2; @@ -924,24 +964,25 @@ generatePlanetRow(pixel * const pixelrow, /* Left stars */ for (col = 0; (int)col < (int)(cols/2 - (lcos + StarClose)); ++col) - etoile(&pixelrow[col]); + etoile(&pixelrow[col], gaussP); /* Right stars */ for (col = cols/2 + (lcos + StarClose); col < cols; ++col) - etoile(&pixelrow[col]); + etoile(&pixelrow[col], gaussP); } static void -genplanet(bool const stars, - bool const clouds, - float * const a, - unsigned int const cols, - unsigned int const rows, - unsigned int const n, - unsigned int const rseed) { +genplanet(bool const stars, + bool const clouds, + float * const a, + unsigned int const cols, + unsigned int const rows, + unsigned int const n, + unsigned int const rseed, + struct Gauss * const gaussP) { /*---------------------------------------------------------------------------- Generate planet from elevation array. @@ -971,13 +1012,13 @@ genplanet(bool const stars, clouds ? "clouds" : "planet", rseed, fracdim, powscale, meshsize); createPlanetStuff(clouds, a, n, &u, &u1, &bxf, &bxc, &cp, &sunvec, - cols, maxval); + cols, maxval, gaussP); } pixelrow = ppm_allocrow(cols); for (row = 0; row < rows; ++row) { if (stars) - generateStarrySkyRow(pixelrow, cols); + generateStarrySkyRow(pixelrow, cols, gaussP); else { double const by = (n - 1) * uprj(row, rows); int const byf = floor(by) * n; @@ -993,7 +1034,8 @@ genplanet(bool const stars, generatePlanetRow(pixelrow, row, rows, cols, t, t1, u, u1, cp, bxc, bxf, byc, byf, sunvec, - maxval); + maxval, + gaussP); } ppm_writeppmrow(stdout, pixelrow, cols, maxval, FALSE); } @@ -1098,14 +1140,15 @@ planet(unsigned int const cols, -----------------------------------------------------------------------------*/ float * a; bool error; + struct Gauss gauss; - initgauss(rseed); + initgauss(&gauss, rseed); if (stars) { a = NULL; error = FALSE; } else { - spectralsynth(&a, meshsize, 3.0 - fracdim); + spectralsynth(&a, meshsize, 3.0 - fracdim, &gauss); if (a == NULL) { error = TRUE; } else { @@ -1117,7 +1160,7 @@ planet(unsigned int const cols, } } if (!error) - genplanet(stars, clouds, a, cols, rows, meshsize, rseed); + genplanet(stars, clouds, a, cols, rows, meshsize, rseed, &gauss); if (a != NULL) free(a); @@ -1159,10 +1202,10 @@ main(int argc, const char ** argv) { cols = (MAX(cmdline.height, cmdline.width) + 1) & (~1); rows = cmdline.height; - success = planet(cols, rows, cmdline.night, cmdline.clouds, cmdline.seed); + success = planet(cols, rows, cmdline.night, + cmdline.clouds, cmdline.seed); exit(success ? 0 : 1); } - diff --git a/generator/ppmpat.c b/generator/ppmpat.c index 908c200f..9473afeb 100644 --- a/generator/ppmpat.c +++ b/generator/ppmpat.c @@ -14,7 +14,6 @@ #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ /* get M_PI in math.h */ #define _BSD_SOURCE /* Make sure strdup() is in <string.h> */ -#define SPIROGRAPHS 0 /* Spirograph to be added soon */ #include <assert.h> #include <math.h> @@ -23,8 +22,9 @@ #include "pm_c_util.h" #include "mallocvar.h" -#include "shhopt.h" #include "nstring.h" +#include "rand.h" +#include "shhopt.h" #include "ppm.h" #include "ppmdraw.h" @@ -40,9 +40,6 @@ typedef enum { PAT_SQUIG, PAT_CAMO, PAT_ANTICAMO, - PAT_SPIRO1, - PAT_SPIRO2, - PAT_SPIRO3 } Pattern; typedef struct { @@ -80,7 +77,6 @@ validateColorCount(Pattern const basePattern, switch (basePattern) { case PAT_GINGHAM2: case PAT_ARGYLE1: - case PAT_SPIRO1: if (colorCount != 2) pm_error("Wrong number of colors: %u. " "2 colors are required for the specified pattern.", @@ -112,8 +108,6 @@ validateColorCount(Pattern const basePattern, colorCount); break; - case PAT_SPIRO2: - case PAT_SPIRO3: default: pm_error("INTERNAL ERROR."); } @@ -188,9 +182,6 @@ parseCommandLine(int argc, const char ** argv, unsigned int squig; unsigned int camo; unsigned int anticamo; - unsigned int spiro1; - unsigned int spiro2; - unsigned int spiro3; MALLOCARRAY_NOFAIL(option_def, 100); @@ -219,16 +210,6 @@ parseCommandLine(int argc, const char ** argv, &camo, 0); OPTENT3(0, "anticamo", OPT_FLAG, NULL, &anticamo, 0); -#if SPIROGRAPHS != 0 - OPTENT3(0, "spiro1", OPT_FLAG, NULL, - &spiro1, 0); - OPTENT3(0, "spiro2", OPT_FLAG, NULL, - &spiro1, 0); - OPTENT3(0, "spiro3", OPT_FLAG, NULL, - &spiro1, 0); -#else - spiro1 = spiro2 = spiro3 = 0; -#endif OPTENT3(0, "color", OPT_STRINGLIST, &colorText, &cmdlineP->colorSpec, 0); OPTENT3(0, "randomseed", OPT_UINT, &cmdlineP->randomseed, @@ -246,8 +227,7 @@ parseCommandLine(int argc, const char ** argv, gingham2 + gingham3 + madras + tartan + argyle1 + argyle2 + poles + squig + - camo + anticamo + - spiro1 + spiro2 + spiro3; + camo + anticamo; if (basePatternCount < 1) pm_error("You must specify a base pattern option such as -gingham2"); @@ -275,12 +255,6 @@ parseCommandLine(int argc, const char ** argv, cmdlineP->basePattern = PAT_CAMO; else if (anticamo) cmdlineP->basePattern = PAT_ANTICAMO; - else if (spiro1) - cmdlineP->basePattern = PAT_SPIRO1; - else if (spiro2) - cmdlineP->basePattern = PAT_SPIRO2; - else if (spiro3) - cmdlineP->basePattern = PAT_SPIRO3; else assert(false); /* Every possibility is accounted for */ } @@ -339,14 +313,15 @@ validateComputableDimensions(unsigned int const cols, static pixel -randomColor(pixval const maxval) { +randomColor(struct pm_randSt * const randStP, + pixval const maxval) { pixel p; PPM_ASSIGN(p, - rand() % (maxval + 1), - rand() % (maxval + 1), - rand() % (maxval + 1) + pm_rand(randStP) % (maxval + 1), + pm_rand(randStP) % (maxval + 1), + pm_rand(randStP) % (maxval + 1) ); return p; @@ -354,15 +329,18 @@ randomColor(pixval const maxval) { -#define DARK_THRESH 0.25 +static double const DARK_THRESH = 0.25; + + static pixel -randomBrightColor(pixval const maxval) { +randomBrightColor(struct pm_randSt * const randStP, + pixval const maxval) { pixel p; do { - p = randomColor(maxval); + p = randomColor(randStP, maxval); } while (PPM_LUMIN(p) <= maxval * DARK_THRESH); return p; @@ -371,12 +349,13 @@ randomBrightColor(pixval const maxval) { static pixel -randomDarkColor(pixval const maxval) { +randomDarkColor(struct pm_randSt * const randStP, + pixval const maxval) { pixel p; do { - p = randomColor(maxval); + p = randomColor(randStP, maxval); } while (PPM_LUMIN(p) > maxval * DARK_THRESH); return p; @@ -448,7 +427,8 @@ nextColorBg(ColorTable * const colorTableP) { static pixel -randomAnticamoColor(pixval const maxval) { +randomAnticamoColor(struct pm_randSt * const randStP, + pixval const maxval) { int v1, v2, v3; pixel p; @@ -457,37 +437,49 @@ randomAnticamoColor(pixval const maxval) { v2 = (maxval + 1) / 2; v3 = 3 * v1; - switch (rand() % 15) { + switch (pm_rand(randStP) % 15) { case 0: case 1: - PPM_ASSIGN(p, rand() % v1 + v3, rand() % v2, rand() % v2); + PPM_ASSIGN(p, pm_rand(randStP) % v1 + v3, + pm_rand(randStP) % v2, + pm_rand(randStP) % v2); break; case 2: case 3: - PPM_ASSIGN(p, rand() % v2, rand() % v1 + v3, rand() % v2); + PPM_ASSIGN(p, pm_rand(randStP) % v2, + pm_rand(randStP) % v1 + v3, + pm_rand(randStP) % v2); break; case 4: case 5: - PPM_ASSIGN(p, rand() % v2, rand() % v2, rand() % v1 + v3); + PPM_ASSIGN(p, pm_rand(randStP) % v2, + pm_rand(randStP) % v2, + pm_rand(randStP) % v1 + v3); break; case 6: case 7: case 8: - PPM_ASSIGN(p, rand() % v2, rand() % v1 + v3, rand() % v1 + v3); + PPM_ASSIGN(p, pm_rand(randStP) % v2, + pm_rand(randStP) % v1 + v3, + pm_rand(randStP) % v1 + v3); break; case 9: case 10: case 11: - PPM_ASSIGN(p, rand() % v1 + v3, rand() % v2, rand() % v1 + v3); + PPM_ASSIGN(p, pm_rand(randStP) % v1 + v3, + pm_rand(randStP) % v2, + pm_rand(randStP) % v1 + v3); break; case 12: case 13: case 14: - PPM_ASSIGN(p, rand() % v1 + v3, rand() % v1 + v3, rand() % v2); + PPM_ASSIGN(p, pm_rand(randStP) % v1 + v3, + pm_rand(randStP) % v1 + v3, + pm_rand(randStP) % v2); break; } @@ -497,7 +489,8 @@ randomAnticamoColor(pixval const maxval) { static pixel -randomCamoColor(pixval const maxval) { +randomCamoColor(struct pm_randSt * const randStP, + pixval const maxval) { int const v1 = (maxval + 1 ) / 8; int const v2 = (maxval + 1 ) / 4; @@ -505,31 +498,39 @@ randomCamoColor(pixval const maxval) { pixel p; - switch (rand() % 10) { + switch (pm_rand(randStP) % 10) { case 0: case 1: case 2: /* light brown */ - PPM_ASSIGN(p, rand() % v3 + v3, rand() % v3 + v2, rand() % v3 + v2); + PPM_ASSIGN(p, pm_rand(randStP) % v3 + v3, + pm_rand(randStP) % v3 + v2, + pm_rand(randStP) % v3 + v2); break; case 3: case 4: case 5: /* dark green */ - PPM_ASSIGN(p, rand() % v2, rand() % v2 + 3 * v1, rand() % v2); + PPM_ASSIGN(p, pm_rand(randStP) % v2, + pm_rand(randStP) % v2 + 3 * v1, + pm_rand(randStP) % v2); break; case 6: case 7: /* brown */ - PPM_ASSIGN(p, rand() % v2 + v2, rand() % v2, rand() % v2); + PPM_ASSIGN(p, pm_rand(randStP) % v2 + v2, + pm_rand(randStP) % v2, + pm_rand(randStP) % v2); break; case 8: case 9: /* dark brown */ - PPM_ASSIGN(p, rand() % v1 + v1, rand() % v1, rand() % v1); + PPM_ASSIGN(p, pm_rand(randStP) % v1 + v1, + pm_rand(randStP) % v1, + pm_rand(randStP) % v1); break; } @@ -539,28 +540,30 @@ randomCamoColor(pixval const maxval) { static float -rnduni(void) { - return rand() % 32767 / 32767.0; +rnduni(struct pm_randSt * const randStP) { + + return pm_rand(randStP) % 32767 / 32767.0; } static void -clearBackgroundCamo(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - pixval const maxval, - ColorTable * const colorTableP, - bool const antiflag) { +clearBackgroundCamo(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + pixval const maxval, + ColorTable * const colorTableP, + struct pm_randSt * const randStP, + bool const antiflag) { pixel color; if (colorTableP->count > 0) { color = colorTableP->color[0]; } else if (antiflag) - color = randomAnticamoColor(maxval); + color = randomAnticamoColor(randStP, maxval); else - color = randomCamoColor(maxval); + color = randomCamoColor(randStP,maxval); ppmd_filledrectangle( pixels, cols, rows, maxval, 0, 0, cols, rows, PPMD_NULLDRAWPROC, @@ -570,13 +573,14 @@ clearBackgroundCamo(pixel ** const pixels, static void -camoFill(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - pixval const maxval, - struct fillobj * const fh, - ColorTable * const colorTableP, - bool const antiflag) { +camoFill(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + pixval const maxval, + struct fillobj * const fh, + ColorTable * const colorTableP, + struct pm_randSt * const randStP, + bool const antiflag) { pixel color; @@ -585,9 +589,9 @@ camoFill(pixel ** const pixels, color = colorTableP->color[colorTableP->index]; nextColorBg(colorTableP); } else if (antiflag) - color = randomAnticamoColor(maxval); + color = randomAnticamoColor(randStP, maxval); else - color = randomCamoColor(maxval); + color = randomCamoColor(randStP, maxval); ppmd_fill(pixels, cols, rows, maxval, fh, PPMD_NULLDRAWPROC, &color); } @@ -608,25 +612,29 @@ camoFill(pixel ** const pixels, static void -computeXsYs(int * const xs, - int * const ys, - unsigned int const cols, - unsigned int const rows, - unsigned int const pointCt) { - - unsigned int const cx = rand() % cols; - unsigned int const cy = rand() % rows; - double const a = rnduni() * (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) + - MIN_ELLIPSE_FACTOR; - double const b = rnduni() * (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) + - MIN_ELLIPSE_FACTOR; - double const theta = rnduni() * 2.0 * M_PI; +computeXsYs(int * const xs, + int * const ys, + unsigned int const cols, + unsigned int const rows, + unsigned int const pointCt, + struct pm_randSt * const randStP) { + + unsigned int const cx = pm_rand(randStP) % cols; + unsigned int const cy = pm_rand(randStP) % rows; + double const a = rnduni(randStP) * + (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) + + MIN_ELLIPSE_FACTOR; + double const b = rnduni(randStP) * + (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) + + MIN_ELLIPSE_FACTOR; + double const theta = rnduni(randStP) * 2.0 * M_PI; unsigned int p; for (p = 0; p < pointCt; ++p) { - double const c = rnduni() * (MAX_POINT_FACTOR - MIN_POINT_FACTOR) + - MIN_POINT_FACTOR; + double const c = rnduni(randStP) * + (MAX_POINT_FACTOR - MIN_POINT_FACTOR) + + MIN_POINT_FACTOR; double const tx = a * sin(p * 2.0 * M_PI / pointCt); double const ty = b * cos(p * 2.0 * M_PI / pointCt); double const tang = atan2(ty, tx) + theta; @@ -638,18 +646,20 @@ computeXsYs(int * const xs, static void -camo(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable * const colorTableP, - pixval const maxval, - bool const antiflag) { +camo(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable * const colorTableP, + struct pm_randSt * const randStP, + pixval const maxval, + bool const antiflag) { unsigned int const n = (rows * cols) / SQR(BLOBRAD) * 5; unsigned int i; - clearBackgroundCamo(pixels, cols, rows, maxval, colorTableP, antiflag); + clearBackgroundCamo(pixels, cols, rows, maxval, + colorTableP, randStP, antiflag); if (colorTableP->count > 0) { assert(colorTableP->count > 1); @@ -658,13 +668,13 @@ camo(pixel ** const pixels, for (i = 0; i < n; ++i) { unsigned int const pointCt = - rand() % (MAX_POINTS - MIN_POINTS + 1) + MIN_POINTS; + pm_rand(randStP) % (MAX_POINTS - MIN_POINTS + 1) + MIN_POINTS; int xs[MAX_POINTS], ys[MAX_POINTS]; int x0, y0; struct fillobj * fh; - computeXsYs(xs, ys, cols, rows, pointCt); + computeXsYs(xs, ys, cols, rows, pointCt, randStP); x0 = (xs[0] + xs[pointCt - 1]) / 2; y0 = (ys[0] + ys[pointCt - 1]) / 2; @@ -675,7 +685,8 @@ camo(pixel ** const pixels, pixels, cols, rows, maxval, x0, y0, pointCt, xs, ys, x0, y0, ppmd_fill_drawproc, fh); - camoFill(pixels, cols, rows, maxval, fh, colorTableP, antiflag); + camoFill(pixels, cols, rows, maxval, fh, + colorTableP, randStP, antiflag); ppmd_fill_destroy(fh); } @@ -688,17 +699,20 @@ camo(pixel ** const pixels, -----------------------------------------------------------------------------*/ static void -gingham2(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable const colorTable, - pixval const maxval) { +gingham2(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable const colorTable, + struct pm_randSt * const randStP, + pixval const maxval) { bool const colorSpec = (colorTable.count > 0); pixel const backcolor = colorSpec ? - colorTable.color[0] : randomDarkColor(maxval); + colorTable.color[0] : + randomDarkColor(randStP, maxval); pixel const forecolor = colorSpec ? - colorTable.color[1] : randomBrightColor(maxval); + colorTable.color[1] : + randomBrightColor(randStP, maxval); unsigned int const colso2 = cols / 2; unsigned int const rowso2 = rows / 2; @@ -722,19 +736,23 @@ gingham2(pixel ** const pixels, static void -gingham3(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable const colorTable, - pixval const maxval) { +gingham3(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable const colorTable, + struct pm_randSt * const randStP, + pixval const maxval) { bool const colorSpec = (colorTable.count > 0); - pixel const backcolor = colorSpec ? - colorTable.color[0] : randomDarkColor(maxval); + pixel const backcolor = colorSpec ? + colorTable.color[0] : + randomDarkColor(randStP, maxval); pixel const fore1color = colorSpec ? - colorTable.color[1] : randomBrightColor(maxval); + colorTable.color[1] : + randomBrightColor(randStP, maxval); pixel const fore2color = colorSpec ? - colorTable.color[2] : randomBrightColor(maxval); + colorTable.color[2] : + randomBrightColor(randStP, maxval); unsigned int const colso4 = cols / 4; unsigned int const rowso4 = rows / 4; @@ -770,19 +788,23 @@ gingham3(pixel ** const pixels, static void -madras(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable const colorTable, - pixval const maxval) { +madras(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable const colorTable, + struct pm_randSt * const randStP, + pixval const maxval) { bool const colorSpec = (colorTable.count > 0); - pixel const backcolor = colorSpec ? - colorTable.color[0] : randomDarkColor(maxval); + pixel const backcolor = colorSpec ? + colorTable.color[0] : + randomDarkColor(randStP, maxval); pixel const fore1color = colorSpec ? - colorTable.color[1] : randomBrightColor(maxval); + colorTable.color[1] : + randomBrightColor(randStP, maxval); pixel const fore2color = colorSpec ? - colorTable.color[2] : randomBrightColor(maxval); + colorTable.color[2] : + randomBrightColor(randStP, maxval); unsigned int const cols2 = cols * 2 / 44; unsigned int const rows2 = rows * 2 / 44; unsigned int const cols3 = cols * 3 / 44; @@ -899,19 +921,23 @@ madras(pixel ** const pixels, static void -tartan(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable const colorTable, - pixval const maxval) { +tartan(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable const colorTable, + struct pm_randSt * const randStP, + pixval const maxval) { bool const colorSpec = (colorTable.count > 0); - pixel const backcolor = colorSpec ? - colorTable.color[0] : randomDarkColor(maxval); + pixel const backcolor = colorSpec ? + colorTable.color[0] : + randomDarkColor(randStP, maxval); pixel const fore1color = colorSpec ? - colorTable.color[1] : randomBrightColor(maxval); + colorTable.color[1] : + randomBrightColor(randStP, maxval); pixel const fore2color = colorSpec ? - colorTable.color[2] : randomBrightColor(maxval); + colorTable.color[2] : + randomBrightColor(randStP, maxval); unsigned int const cols1 = cols / 22; unsigned int const rows1 = rows / 22; unsigned int const cols3 = cols * 3 / 22; @@ -1013,14 +1039,15 @@ argyle(pixel ** const pixels, unsigned int const cols, unsigned int const rows, ColorTable const colorTable, + struct pm_randSt * const randStP, pixval const maxval, bool const stripes) { bool const colorSpec = (colorTable.count > 0); pixel const backcolor = colorSpec ? - colorTable.color[0] : randomDarkColor(maxval); + colorTable.color[0] : randomDarkColor(randStP, maxval); pixel const forecolor = colorSpec ? - colorTable.color[1] : randomBrightColor(maxval); + colorTable.color[1] : randomBrightColor(randStP, maxval); /* Fill canvas with background to start */ ppmd_filledrectangle( @@ -1032,7 +1059,8 @@ argyle(pixel ** const pixels, if (stripes) { /* Connect corners with thin stripes */ pixel const stripecolor = - colorSpec ? colorTable.color[2] : randomBrightColor(maxval); + colorSpec ? colorTable.color[2] : + randomBrightColor(randStP, maxval); ppmd_line(pixels, cols, rows, maxval, 0, 0, cols-1, rows-1, PPMD_NULLDRAWPROC, (char *) &stripecolor); @@ -1049,32 +1077,33 @@ argyle(pixel ** const pixels, -#define MAXPOLES 500 +static unsigned int const MAXPOLES = 500; static void -placeAndColorPolesRandomly(int * const xs, - int * const ys, - pixel * const colors, - unsigned int const cols, - unsigned int const rows, - pixval const maxval, - ColorTable * const colorTableP, - unsigned int const poleCt) { +placeAndColorPolesRandomly(int * const xs, + int * const ys, + pixel * const colors, + unsigned int const cols, + unsigned int const rows, + pixval const maxval, + ColorTable * const colorTableP, + struct pm_randSt * const randStP, + unsigned int const poleCt) { unsigned int i; for (i = 0; i < poleCt; ++i) { - xs[i] = rand() % cols; - ys[i] = rand() % rows; + xs[i] = pm_rand(randStP) % cols; + ys[i] = pm_rand(randStP) % rows; if (colorTableP->count > 0) { colors[i] = colorTableP->color[colorTableP->index]; nextColor(colorTableP); } else - colors[i] = randomBrightColor(maxval); + colors[i] = randomBrightColor(randStP, maxval); } } @@ -1104,11 +1133,12 @@ assignInterpolatedColor(pixel * const resultP, static void -poles(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable * const colorTableP, - pixval const maxval) { +poles(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable * const colorTableP, + struct pm_randSt * const randStP, + pixval const maxval) { unsigned int const poleCt = MAX(2, MIN(MAXPOLES, cols * rows / 30000)); @@ -1117,7 +1147,7 @@ poles(pixel ** const pixels, unsigned int row; placeAndColorPolesRandomly(xs, ys, colors, cols, rows, maxval, - colorTableP, poleCt); + colorTableP, randStP, poleCt); /* Interpolate points */ @@ -1236,11 +1266,12 @@ sqRainbowCircleDrawproc(pixel ** const pixels, static void -chooseSqPoleColors(ColorTable * const colorTableP, - pixval const maxval, - pixel * const color1P, - pixel * const color2P, - pixel * const color3P) { +chooseSqPoleColors(ColorTable * const colorTableP, + pixval const maxval, + pixel * const color1P, + pixel * const color2P, + pixel * const color3P, + struct pm_randSt * const randStP) { if (colorTableP->count > 0) { *color1P = colorTableP->color[colorTableP->index]; @@ -1250,19 +1281,20 @@ chooseSqPoleColors(ColorTable * const colorTableP, *color3P = colorTableP->color[colorTableP->index]; nextColor(colorTableP); } else { - *color1P = randomBrightColor(maxval); - *color2P = randomBrightColor(maxval); - *color3P = randomBrightColor(maxval); + *color1P = randomBrightColor(randStP, maxval); + *color2P = randomBrightColor(randStP, maxval); + *color3P = randomBrightColor(randStP, maxval); } } static void -sqAssignColors(unsigned int const circlecount, - pixval const maxval, - ColorTable * const colorTableP, - pixel * const colors) { +sqAssignColors(unsigned int const circlecount, + pixval const maxval, + ColorTable * const colorTableP, + pixel * const colors, + struct pm_randSt * const randStP) { float const cco3 = (circlecount - 1) / 3.0; @@ -1271,7 +1303,7 @@ sqAssignColors(unsigned int const circlecount, pixel rc3; unsigned int i; - chooseSqPoleColors(colorTableP, maxval, &rc1, &rc2, &rc3); + chooseSqPoleColors(colorTableP, maxval, &rc1, &rc2, &rc3, randStP); for (i = 0; i < circlecount; ++i) { if (i < cco3) { @@ -1333,24 +1365,25 @@ clearBackgroundSquig(pixel ** const pixels, static void -chooseWrapAroundPoint(unsigned int const cols, - unsigned int const rows, - ppmd_point * const pFirstP, - ppmd_point * const pLastP, - ppmd_point * const p0P, - ppmd_point * const p1P, - ppmd_point * const p2P, - ppmd_point * const p3P) { - - switch (rand() % 4) { +chooseWrapAroundPoint(unsigned int const cols, + unsigned int const rows, + ppmd_point * const pFirstP, + ppmd_point * const pLastP, + ppmd_point * const p0P, + ppmd_point * const p1P, + ppmd_point * const p2P, + ppmd_point * const p3P, + struct pm_randSt * const randStP) { + + switch (pm_rand(randStP) % 4) { case 0: - p1P->x = rand() % cols; + p1P->x = pm_rand(randStP) % cols; p1P->y = 0; if (p1P->x < cols / 2) - pFirstP->x = rand() % (p1P->x * 2 + 1); + pFirstP->x = pm_rand(randStP) % (p1P->x * 2 + 1); else - pFirstP->x = cols - 1 - rand() % ((cols - p1P->x) * 2); - pFirstP->y = rand() % rows; + pFirstP->x = cols - 1 - pm_rand(randStP) % ((cols - p1P->x) * 2); + pFirstP->y = pm_rand(randStP) % rows; p2P->x = p1P->x; p2P->y = rows - 1; pLastP->x = 2 * p2P->x - pFirstP->x; @@ -1362,13 +1395,13 @@ chooseWrapAroundPoint(unsigned int const cols, break; case 1: - p2P->x = rand() % cols; + p2P->x = pm_rand(randStP) % cols; p2P->y = 0; if (p2P->x < cols / 2) - pLastP->x = rand() % (p2P->x * 2 + 1); + pLastP->x = pm_rand(randStP) % (p2P->x * 2 + 1); else - pLastP->x = cols - 1 - rand() % ((cols - p2P->x) * 2); - pLastP->y = rand() % rows; + pLastP->x = cols - 1 - pm_rand(randStP) % ((cols - p2P->x) * 2); + pLastP->y = pm_rand(randStP) % rows; p1P->x = p2P->x; p1P->y = rows - 1; pFirstP->x = 2 * p1P->x - pLastP->x; @@ -1381,12 +1414,12 @@ chooseWrapAroundPoint(unsigned int const cols, case 2: p1P->x = 0; - p1P->y = rand() % rows; - pFirstP->x = rand() % cols; + p1P->y = pm_rand(randStP) % rows; + pFirstP->x = pm_rand(randStP) % cols; if (p1P->y < rows / 2) - pFirstP->y = rand() % (p1P->y * 2 + 1); + pFirstP->y = pm_rand(randStP) % (p1P->y * 2 + 1); else - pFirstP->y = rows - 1 - rand() % ((rows - p1P->y) * 2); + pFirstP->y = rows - 1 - pm_rand(randStP) % ((rows - p1P->y) * 2); p2P->x = cols - 1; p2P->y = p1P->y; pLastP->x = p2P->x - pFirstP->x; @@ -1399,12 +1432,12 @@ chooseWrapAroundPoint(unsigned int const cols, case 3: p2P->x = 0; - p2P->y = rand() % rows; - pLastP->x = rand() % cols; + p2P->y = pm_rand(randStP) % rows; + pLastP->x = pm_rand(randStP) % cols; if (p2P->y < rows / 2) - pLastP->y = rand() % (p2P->y * 2 + 1); + pLastP->y = pm_rand(randStP) % (p2P->y * 2 + 1); else - pLastP->y = rows - 1 - rand() % ((rows - p2P->y) * 2); + pLastP->y = rows - 1 - pm_rand(randStP) % ((rows - p2P->y) * 2); p1P->x = cols - 1; p1P->y = p2P->y; pFirstP->x = p1P->x - pLastP->x; @@ -1420,11 +1453,12 @@ chooseWrapAroundPoint(unsigned int const cols, static void -squig(pixel ** const pixels, - unsigned int const cols, - unsigned int const rows, - ColorTable * const colorTableP, - pixval const maxval) { +squig(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + ColorTable * const colorTableP, + struct pm_randSt * const randStP, + pixval const maxval) { int i; @@ -1453,10 +1487,11 @@ squig(pixel ** const pixels, ppmd_circlep(pixels, cols, rows, maxval, ppmd_makePoint(0, 0), radius, sqMeasureCircleDrawproc, &sqClientData); - sqAssignColors(squig.circleCt, maxval, colorTableP, squig.color); + sqAssignColors(squig.circleCt, maxval, colorTableP, squig.color, + randStP); chooseWrapAroundPoint(cols, rows, &c[0], &c[SQ_POINTS-1], - &p0, &p1, &p2, &p3); + &p0, &p1, &p2, &p3, randStP); { /* Do the middle points */ @@ -1466,8 +1501,8 @@ squig(pixel ** const pixels, /* validateSquigAspect() assures that cols - 2 * radius, rows -2 * radius are positive */ - c[j].x = (rand() % (cols - 2 * radius)) + radius; - c[j].y = (rand() % (rows - 2 * radius)) + radius; + c[j].x = (pm_rand(randStP) % (cols - 2 * radius)) + radius; + c[j].y = (pm_rand(randStP) % (rows - 2 * radius)) + radius; } } @@ -1490,6 +1525,7 @@ main(int argc, const char ** argv) { struct CmdlineInfo cmdline; pixel ** pixels; + struct pm_randSt randSt; pm_proginit(&argc, argv); @@ -1497,65 +1533,68 @@ main(int argc, const char ** argv) { validateComputableDimensions(cmdline.width, cmdline.height); - srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed()); + pm_randinit(&randSt); + pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed); pixels = ppm_allocarray(cmdline.width, cmdline.height); switch (cmdline.basePattern) { case PAT_GINGHAM2: gingham2(pixels, cmdline.width, cmdline.height, - cmdline.colorTable, PPM_MAXMAXVAL); + cmdline.colorTable, &randSt, PPM_MAXMAXVAL); break; case PAT_GINGHAM3: gingham3(pixels, cmdline.width, cmdline.height, - cmdline.colorTable, PPM_MAXMAXVAL); + cmdline.colorTable, &randSt, PPM_MAXMAXVAL); break; case PAT_MADRAS: madras(pixels, cmdline.width, cmdline.height, - cmdline.colorTable, PPM_MAXMAXVAL); + cmdline.colorTable, &randSt, PPM_MAXMAXVAL); break; case PAT_TARTAN: tartan(pixels, cmdline.width, cmdline.height, - cmdline.colorTable, PPM_MAXMAXVAL); + cmdline.colorTable, &randSt, PPM_MAXMAXVAL); break; case PAT_ARGYLE1: argyle(pixels, cmdline.width, cmdline.height, - cmdline.colorTable, PPM_MAXMAXVAL, FALSE); + cmdline.colorTable, &randSt, PPM_MAXMAXVAL, FALSE); break; case PAT_ARGYLE2: argyle(pixels, cmdline.width, cmdline.height, - cmdline.colorTable, PPM_MAXMAXVAL, TRUE); + cmdline.colorTable, &randSt, PPM_MAXMAXVAL, TRUE); break; case PAT_POLES: poles(pixels, cmdline.width, cmdline.height, - &cmdline.colorTable, PPM_MAXMAXVAL); + &cmdline.colorTable, &randSt, PPM_MAXMAXVAL); break; case PAT_SQUIG: squig(pixels, cmdline.width, cmdline.height, - &cmdline.colorTable, PPM_MAXMAXVAL); + &cmdline.colorTable, &randSt, PPM_MAXMAXVAL); break; case PAT_CAMO: camo(pixels, cmdline.width, cmdline.height, - &cmdline.colorTable, PPM_MAXMAXVAL, 0); + &cmdline.colorTable, &randSt, PPM_MAXMAXVAL, 0); break; case PAT_ANTICAMO: camo(pixels, cmdline.width, cmdline.height, - &cmdline.colorTable, PPM_MAXMAXVAL, 1); + &cmdline.colorTable, &randSt, PPM_MAXMAXVAL, 1); break; default: pm_error("can't happen!"); } + pm_randterm(&randSt); + ppm_writeppm(stdout, pixels, cmdline.width, cmdline.height, PPM_MAXMAXVAL, 0); @@ -1567,4 +1606,3 @@ main(int argc, const char ** argv) { } - diff --git a/generator/ppmrainbow b/generator/ppmrainbow index e8a329ff..a5c2689d 100755 --- a/generator/ppmrainbow +++ b/generator/ppmrainbow @@ -26,6 +26,19 @@ exec perl -w -x -S -- "$0" "$@" use strict; use Getopt::Long; use File::Temp; +use IO::Handle; + + + +sub pm_message($) { + STDERR->print("ppmrainbow: $_[0]\n"); +} + +sub pm_error($) { + pm_message($_[0]); + exit(1); +} + my ($FALSE, $TRUE) = (0,1); @@ -46,15 +59,6 @@ sub doVersionHack($) { -sub fatal($) { - my ($msg) = @_; - - print(STDERR "ppmrainbow: $msg\n"); - exit(1); -} - - - ############################################################################## # # MAINLINE @@ -79,14 +83,14 @@ GetOptions("width=i" => \$Twid, "verbose!" => \$verbose); if ($Twid < 1 || $Thgt < 1) { - fatal("invalid width and/or height"); + pm_error("invalid width and/or height"); } my $verboseCommand = $verbose ? "set -x;" : ""; if (@ARGV < 1) { - fatal("You must specify at least one color as an argument"); + pm_error("You must specify at least one color as an argument"); } elsif (@ARGV < 2 && ! $repeat) { - fatal("With the -norepeat option, you must specify at least two colors " . + pm_error("With the -norepeat option, you must specify at least two colors " . "as arguments."); } @@ -115,7 +119,7 @@ while (@colorlist >= 2) { my $rc = system("$verboseCommand pgmramp -lr $w $Thgt | " . "pgmtoppm \"$colorlist[0]-$colorlist[1]\" >$outfile"); if ($rc != 0) { - fatal("pgmramp|pgmtoppm pipe failed."); + pm_error("pgmramp|pgmtoppm pipe failed."); } $widthRemaining -= $w; $n++; diff --git a/generator/ppmrough.c b/generator/ppmrough.c index c87a0364..a4a1f14d 100644 --- a/generator/ppmrough.c +++ b/generator/ppmrough.c @@ -16,11 +16,10 @@ #include "pm_c_util.h" #include "mallocvar.h" +#include "rand.h" #include "shhopt.h" #include "ppm.h" -static pixel** PIX; -static pixval BG_RED, BG_GREEN, BG_BLUE; struct CmdlineInfo { @@ -28,9 +27,12 @@ struct CmdlineInfo { in a form easy for the program to use. */ unsigned int left, right, top, bottom; - unsigned int width, height, var; - const char * bg_rgb; - const char * fg_rgb; + unsigned int leftSpec, rightSpec, topSpec, bottomSpec; + unsigned int width; + unsigned int height; + unsigned int var; + const char * bg; /* Null if not specified */ + const char * fg; /* Null if not specified */ unsigned int randomseed; unsigned int randomseedSpec; unsigned int verbose; @@ -42,6 +44,8 @@ static void parseCommandLine(int argc, const char ** argv, struct CmdlineInfo * const cmdlineP) { + unsigned int widthSpec, heightSpec, bgSpec, fgSpec, varSpec; + optEntry * option_def; /* Instructions to OptParseOptions2 on how to parse our options. */ optStruct3 opt; @@ -51,28 +55,30 @@ parseCommandLine(int argc, const char ** argv, MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENTRY */ - OPTENT3(0, "width", OPT_UINT, &cmdlineP->width, NULL, 0); - OPTENT3(0, "height", OPT_UINT, &cmdlineP->height, NULL, 0); - OPTENT3(0, "left", OPT_UINT, &cmdlineP->left, NULL, 0); - OPTENT3(0, "right", OPT_UINT, &cmdlineP->right, NULL, 0); - OPTENT3(0, "top", OPT_UINT, &cmdlineP->top, NULL, 0); - OPTENT3(0, "bottom", OPT_UINT, &cmdlineP->bottom, NULL, 0); - OPTENT3(0, "bg", OPT_STRING, &cmdlineP->bg_rgb, NULL, 0); - OPTENT3(0, "fg", OPT_STRING, &cmdlineP->fg_rgb, NULL, 0); - OPTENT3(0, "var", OPT_UINT, &cmdlineP->var, NULL, 0); + OPTENT3(0, "width", OPT_UINT, &cmdlineP->width, + &widthSpec, 0); + OPTENT3(0, "height", OPT_UINT, &cmdlineP->height, + &heightSpec, 0); + OPTENT3(0, "left", OPT_UINT, &cmdlineP->left, + &cmdlineP->leftSpec, 0); + OPTENT3(0, "right", OPT_UINT, &cmdlineP->right, + &cmdlineP->rightSpec, 0); + OPTENT3(0, "top", OPT_UINT, &cmdlineP->top, + &cmdlineP->topSpec, 0); + OPTENT3(0, "bottom", OPT_UINT, &cmdlineP->bottom, + &cmdlineP->bottomSpec, 0); + OPTENT3(0, "bg", OPT_STRING, &cmdlineP->bg, + &bgSpec, 0); + OPTENT3(0, "fg", OPT_STRING, &cmdlineP->fg, + &fgSpec, 0); + OPTENT3(0, "var", OPT_UINT, &cmdlineP->var, + &varSpec, 0); OPTENT3(0, "randomseed", OPT_UINT, &cmdlineP->randomseed, &cmdlineP->randomseedSpec, 0); OPTENT3(0, "init", OPT_UINT, &cmdlineP->randomseed, &cmdlineP->randomseedSpec, 0); - OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); - - /* Set the defaults */ - cmdlineP->width = 100; - cmdlineP->height = 100; - cmdlineP->left = cmdlineP->right = cmdlineP->top = cmdlineP->bottom = -1; - cmdlineP->bg_rgb = NULL; - cmdlineP->fg_rgb = NULL; - cmdlineP->var = 10; + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ @@ -80,6 +86,17 @@ parseCommandLine(int argc, const char ** argv, pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + if (!widthSpec) + cmdlineP->width = 100; + if (!heightSpec) + cmdlineP->height = 100; + if (!bgSpec) + cmdlineP->bg = NULL; + if (!fgSpec) + cmdlineP->fg = NULL; + if (!varSpec) + cmdlineP->var = 10; + if (argc-1 != 0) pm_error("There are no arguments. You specified %d.", argc-1); @@ -89,239 +106,340 @@ parseCommandLine(int argc, const char ** argv, static void -procLeft(int const r1, - int const r2, - int const c1, - int const c2, - unsigned int const var) { +reportParameters(struct CmdlineInfo const cmdline, + pixel const bgcolor, + pixel const fgcolor) { + + pm_message("width is %d, height is %d, variance is %d.", + cmdline.width, cmdline.height, cmdline.var); + if (cmdline.leftSpec) + pm_message("ragged left border is required"); + if (cmdline.rightSpec) + pm_message("ragged right border is required"); + if (cmdline.topSpec) + pm_message("ragged top border is required"); + if (cmdline.bottomSpec) + pm_message("ragged bottom border is required"); + pm_message("background is %s", + ppm_colorname(&bgcolor, PPM_MAXMAXVAL, 1)); + pm_message("foreground is %s", + ppm_colorname(&fgcolor, PPM_MAXMAXVAL, 1)); + if (cmdline.randomseedSpec) + pm_message("pm_rand() initialized with seed %u", + cmdline.randomseed); +} - int cm, rm, c; - if (r1 + 1 == r2) return; - rm = (r1 + r2) >> 1; - cm = (c1 + c2) >> 1; - cm += (int)floor(((float)rand() / RAND_MAX - 0.5) * var + 0.5); - for (c = 0; c < cm; c++) - PPM_ASSIGN(PIX[rm][c], BG_RED, BG_GREEN, BG_BLUE); +static void +makeAllForegroundColor(pixel ** const pixels, + unsigned int const rows, + unsigned int const cols, + pixel const fgcolor) { + + pixval const r = PPM_GETR(fgcolor); + pixval const g = PPM_GETG(fgcolor); + pixval const b = PPM_GETB(fgcolor); + + unsigned int row; + + for (row = 0; row < rows; ++row) { + unsigned int col; - procLeft(r1, rm, c1, cm, var); - procLeft(rm, r2, cm, c2, var); + for (col = 0; col < cols; ++col) + PPM_ASSIGN(pixels[row][col], r, g, b); + } } static void -procRight(int const r1, - int const r2, - int const c1, - int const c2, - unsigned int const width, - unsigned int const var) { +procLeft(pixel ** const pixels, + int const r1, + int const r2, + int const c1, + int const c2, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (r1 + 1 != r2) { + int const rm = (r1 + r2) >> 1; + int const cm = ((c1 + c2) >> 1) + + (int)floor(((float)pm_rand(randStP) / RAND_MAX - 0.5) * var + 0.5); + + int c; + + for (c = 0; c < cm; c++) + pixels[rm][c] = bgcolor; + + procLeft(pixels, r1, rm, c1, cm, var, bgcolor, randStP); + procLeft(pixels, rm, r2, cm, c2, var, bgcolor, randStP); + } +} + - int cm, rm, c; - if (r1 + 1 == r2) return; - rm = (r1 + r2) >> 1; - cm = (c1 + c2) >> 1; - cm += (int)floor(((float)rand() / RAND_MAX - 0.5) * var + 0.5); +static void +procRight(pixel ** const pixels, + int const r1, + int const r2, + int const c1, + int const c2, + unsigned int const width, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (r1 + 1 != r2) { + int const rm = (r1 + r2) >> 1; + int const cm = ((c1 + c2) >> 1) + + (int)floor(((float)pm_rand(randStP) / RAND_MAX - 0.5) * var + 0.5); + + int c; + + for (c = cm; c < width; c++) + pixels[rm][c] = bgcolor; + + procRight(pixels, r1, rm, c1, cm, width, var, bgcolor, randStP); + procRight(pixels, rm, r2, cm, c2, width, var, bgcolor, randStP); + } +} + - for (c = cm; c < width; c++) - PPM_ASSIGN(PIX[rm][c], BG_RED, BG_GREEN, BG_BLUE); - procRight(r1, rm, c1, cm, width, var); - procRight(rm, r2, cm, c2, width, var); +static void +procTop(pixel ** const pixels, + int const c1, + int const c2, + int const r1, + int const r2, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (c1 + 1 != c2) { + int const cm = (c1 + c2) >> 1; + int const rm = ((r1 + r2) >> 1) + + (int)floor(((float)pm_rand(randStP) / RAND_MAX - 0.5) * var + 0.5); + + int r; + + for (r = 0; r < rm; r++) + pixels[r][cm] = bgcolor; + + procTop(pixels, c1, cm, r1, rm, var, bgcolor, randStP); + procTop(pixels, cm, c2, rm, r2, var, bgcolor, randStP); + } } static void -procTop(int const c1, - int const c2, - int const r1, - int const r2, - unsigned int const var) { +procBottom(pixel ** const pixels, + int const c1, + int const c2, + int const r1, + int const r2, + unsigned int const height, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (c1 + 1 != c2) { + int const cm = (c1 + c2) >> 1; + int const rm = ((r1 + r2) >> 1) + + (int)floor(((float)pm_rand(randStP) / RAND_MAX - 0.5) * var + 0.5); + + int r; + + for (r = rm; r < height; ++r) + pixels[r][cm] = bgcolor; + + procBottom(pixels, c1, cm, r1, rm, height, var, bgcolor, randStP); + procBottom(pixels, cm, c2, rm, r2, height, var, bgcolor, randStP); + } +} - int rm, cm, r; - if (c1 + 1 == c2) return; - cm = (c1 + c2) >> 1; - rm = (r1 + r2) >> 1; - rm += (int)floor(((float)rand() / RAND_MAX - 0.5) * var + 0.5); - for (r = 0; r < rm; r++) - PPM_ASSIGN(PIX[r][cm], BG_RED, BG_GREEN, BG_BLUE); +static void +makeRaggedLeftBorder(pixel ** const pixels, + unsigned int const rows, + unsigned int const cols, + bool const leftSpec, + unsigned int const left, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (leftSpec) { + int const leftC1 = left; + int const leftC2 = left; + int const leftR1 = 0; + int const leftR2 = rows - 1; - procTop(c1, cm, r1, rm, var); - procTop(cm, c2, rm, r2, var); + unsigned int col; + + for (col = 0; col < leftC1; ++col) + pixels[leftR1][col] = bgcolor; + for (col = 0; col < leftC2; ++col) + pixels[leftR2][col] = bgcolor; + + procLeft(pixels, leftR1, leftR2, leftC1, leftC2, var, + bgcolor, randStP); + } } static void -procBottom(int const c1, - int const c2, - int const r1, - int const r2, - unsigned int const height, - unsigned int const var) { +makeRaggedRightBorder(pixel ** const pixels, + unsigned int const rows, + unsigned int const cols, + bool const rightSpec, + unsigned int const right, + unsigned int const width, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (rightSpec) { + int const rightC1 = cols - right - 1; + int const rightC2 = cols - right - 1; + int const rightR1 = 0; + int const rightR2 = rows - 1; - int rm, cm, r; - - if (c1 + 1 == c2) return; - cm = (c1 + c2) >> 1; - rm = (r1 + r2) >> 1; - rm += (int)floor(((float)rand() / RAND_MAX - 0.5) * var + 0.5); + unsigned int col; - for (r = rm; r < height; r++) - PPM_ASSIGN(PIX[r][cm], BG_RED, BG_GREEN, BG_BLUE); + for (col = rightC1; col < cols; ++col) + pixels[rightR1][col] = bgcolor; + for (col = rightC2; col < cols; ++col) + pixels[rightR2][col] = bgcolor; - procBottom(c1, cm, r1, rm, height, var); - procBottom(cm, c2, rm, r2, height, var); + procRight(pixels, rightR1, rightR2, rightC1, rightC2, width, var, + bgcolor, randStP); + } } -int -main(int argc, const char * argv[]) { +static void +makeRaggedTopBorder(pixel ** const pixels, + unsigned int const rows, + unsigned int const cols, + bool const topSpec, + unsigned int const top, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (topSpec) { + unsigned int const topR1 = top; + unsigned int const topR2 = top; + unsigned int const topC1 = 0; + unsigned int const topC2 = cols - 1; - struct CmdlineInfo cmdline; - pixel bgcolor, fgcolor; - pixval fg_red, fg_green, fg_blue; - int rows, cols, row; - int left, right, top, bottom; + unsigned int row; - pm_proginit(&argc, argv); + for (row = 0; row < topR1; ++row) + pixels[row][topC1] = bgcolor; + for (row = 0; row < topR2; ++row) + pixels[row][topC2] = bgcolor; - parseCommandLine(argc, argv, &cmdline); + procTop(pixels, topC1, topC2, topR1, topR2, var, bgcolor, randStP); + } +} - srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed()); - cols = cmdline.width; - rows = cmdline.height; - left = cmdline.left; - right = cmdline.right; - top = cmdline.top; - bottom = cmdline.bottom; - if (cmdline.bg_rgb) - bgcolor = ppm_parsecolor(cmdline.bg_rgb, PPM_MAXMAXVAL); - else - PPM_ASSIGN(bgcolor, 0, 0, 0); - BG_RED = PPM_GETR(bgcolor); - BG_GREEN = PPM_GETG(bgcolor); - BG_BLUE = PPM_GETB(bgcolor); +static void +makeRaggedBottomBorder(pixel ** const pixels, + unsigned int const rows, + unsigned int const cols, + bool const bottomSpec, + unsigned int const bottom, + unsigned int const height, + unsigned int const var, + pixel const bgcolor, + struct pm_randSt * const randStP) { + + if (bottomSpec) { + unsigned int const bottomR1 = rows - bottom - 1; + unsigned int const bottomR2 = rows - bottom - 1; + unsigned int const bottomC1 = 0; + unsigned int const bottomC2 = cols - 1; - if (cmdline.fg_rgb) - fgcolor = ppm_parsecolor(cmdline.fg_rgb, PPM_MAXMAXVAL); - else - PPM_ASSIGN(fgcolor, PPM_MAXMAXVAL, PPM_MAXMAXVAL, PPM_MAXMAXVAL); - fg_red = PPM_GETR(fgcolor); - fg_green = PPM_GETG(fgcolor); - fg_blue = PPM_GETB(fgcolor); - - if (cmdline.verbose) { - pm_message("width is %d, height is %d, variance is %d.", - cols, rows, cmdline.var); - if (left >= 0) - pm_message("ragged left border is required"); - if (right >= 0) - pm_message("ragged right border is required"); - if (top >= 0) - pm_message("ragged top border is required"); - if (bottom >= 0) - pm_message("ragged bottom border is required"); - pm_message("background is %s", - ppm_colorname(&bgcolor, PPM_MAXMAXVAL, 1)); - pm_message("foreground is %s", - ppm_colorname(&fgcolor, PPM_MAXMAXVAL, 1)); - if (cmdline.randomseedSpec) - pm_message("srand() initialized with seed %u", cmdline.randomseed); - } + unsigned int row; - /* Allocate memory for the whole pixmap */ - PIX = ppm_allocarray(cols, rows); + for (row = bottomR1; row < rows; ++row) + pixels[row][bottomC1] = bgcolor; + for (row = bottomR2; row < rows; ++row) + pixels[row][bottomC2] = bgcolor; - /* First, set all pixel to foreground color */ - for (row = 0; row < rows; row++) { - unsigned int col; - for (col = 0; col < cols; ++col) - PPM_ASSIGN(PIX[row][col], fg_red, fg_green, fg_blue); + procBottom(pixels, bottomC1, bottomC2, bottomR1, bottomR2, + height, var, bgcolor, randStP); } - /* Make a ragged left border */ - if (left >= 0) { - int const left_c1 = left; - int const left_c2 = left; - int const left_r1 = 0; - int const left_r2 = rows - 1; +} - unsigned int col; - for (col = 0; col < left_c1; ++col) - PPM_ASSIGN(PIX[left_r1][col], BG_RED, BG_GREEN, BG_BLUE); - for (col = 0; col < left_c2; ++col) - PPM_ASSIGN(PIX[left_r2][col], BG_RED, BG_GREEN, BG_BLUE); - procLeft(left_r1, left_r2, left_c1, left_c2, cmdline.var); - } +int +main(int argc, const char ** const argv) { - /* Make a ragged right border */ - if (right >= 0) { - int const right_c1 = cols - right - 1; - int const right_c2 = cols - right - 1; - int const right_r1 = 0; - int const right_r2 = rows - 1; + struct CmdlineInfo cmdline; + pixel bgcolor, fgcolor; + struct pm_randSt randSt; + static pixel** pixels; - unsigned int col; + pm_proginit(&argc, argv); - for (col = right_c1; col < cols; col++) - PPM_ASSIGN(PIX[right_r1][col], BG_RED, BG_GREEN, BG_BLUE); - for (col = right_c2; col < cols; col++) - PPM_ASSIGN(PIX[right_r2][col], BG_RED, BG_GREEN, BG_BLUE); + parseCommandLine(argc, argv, &cmdline); - procRight(right_r1, right_r2, right_c1, right_c2, - cmdline.width, cmdline.var); - } + pm_randinit(&randSt); + pm_srand(&randSt, + cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed()); - /* Make a ragged top border */ - if (top >= 0) { - int const top_r1 = top; - int const top_r2 = top; - int const top_c1 = 0; - int const top_c2 = cols - 1; + if (cmdline.bg) + bgcolor = ppm_parsecolor(cmdline.bg, PPM_MAXMAXVAL); + else + PPM_ASSIGN(bgcolor, 0, 0, 0); - unsigned int row; + if (cmdline.fg) + fgcolor = ppm_parsecolor(cmdline.fg, PPM_MAXMAXVAL); + else + PPM_ASSIGN(fgcolor, PPM_MAXMAXVAL, PPM_MAXMAXVAL, PPM_MAXMAXVAL); - for (row = 0; row < top_r1; ++row) - PPM_ASSIGN(PIX[row][top_c1], BG_RED, BG_GREEN, BG_BLUE); - for (row = 0; row < top_r2; ++row) - PPM_ASSIGN(PIX[row][top_c2], BG_RED, BG_GREEN, BG_BLUE); + if (cmdline.verbose) + reportParameters(cmdline, bgcolor, fgcolor); - procTop(top_c1, top_c2, top_r1, top_r2, cmdline.var); - } + pixels = ppm_allocarray(cmdline.width, cmdline.height); - /* Make a ragged bottom border */ - if (bottom >= 0) { - int const bottom_r1 = rows - bottom - 1; - int const bottom_r2 = rows - bottom - 1; - int const bottom_c1 = 0; - int const bottom_c2 = cols - 1; + makeAllForegroundColor(pixels, cmdline.height, cmdline.width, fgcolor); - unsigned int row; + makeRaggedLeftBorder(pixels, cmdline.height, cmdline.width, + cmdline.leftSpec, cmdline.left, + cmdline.var, bgcolor, &randSt); - for (row = bottom_r1; row < rows; ++row) - PPM_ASSIGN(PIX[row][bottom_c1], BG_RED, BG_GREEN, BG_BLUE); - for (row = bottom_r2; row < rows; ++row) - PPM_ASSIGN(PIX[row][bottom_c2], BG_RED, BG_GREEN, BG_BLUE); + makeRaggedRightBorder(pixels, cmdline.height, cmdline.width, + cmdline.rightSpec, cmdline.right, + cmdline.width, cmdline.var, bgcolor, &randSt); - procBottom(bottom_c1, bottom_c2, bottom_r1, bottom_r2, - cmdline.height, cmdline.var); - } + makeRaggedTopBorder(pixels, cmdline.height, cmdline.width, + cmdline.topSpec, cmdline.top, + cmdline.var, bgcolor, &randSt); + + makeRaggedBottomBorder(pixels, cmdline.height, cmdline.width, + cmdline.bottomSpec, cmdline.bottom, + cmdline.height, cmdline.var, bgcolor, &randSt); + + pm_randterm(&randSt); /* Write pixmap */ - ppm_writeppm(stdout, PIX, cols, rows, PPM_MAXMAXVAL, 0); + ppm_writeppm(stdout, pixels, cmdline.width, cmdline.height, + PPM_MAXMAXVAL, 0); - ppm_freearray(PIX, rows); + ppm_freearray(pixels, cmdline.height); pm_close(stdout); @@ -329,4 +447,3 @@ main(int argc, const char * argv[]) { } - |