about summary refs log tree commit diff
path: root/generator/pamstereogram.c
diff options
context:
space:
mode:
Diffstat (limited to 'generator/pamstereogram.c')
-rw-r--r--generator/pamstereogram.c134
1 files changed, 90 insertions, 44 deletions
diff --git a/generator/pamstereogram.c b/generator/pamstereogram.c
index 9b861b51..4bc1ea92 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,42 +1216,59 @@ makeImageRow(outGenerator *       const outGenP,
 
   sameL[N] > N is not allowed.
 -----------------------------------------------------------------------------*/
-    int col;
-    int lastLinked;
+    unsigned int const width  = outGenP->pam.width;
+    unsigned int const height = outGenP->pam.height;
 
-    for (col = (int)xbegin, lastLinked = INT_MIN;
-         col < outGenP->pam.width;
-         ++col) {
+    unsigned int col;
+    bool colHasBeenLinked;
+    unsigned int lastLinkedCol;
+        /* Last column to have been linked; meaningless if 'colHasBeenLinked'
+           is false.
+        */
+
+    for (col = xbegin, colHasBeenLinked = false; col < width; ++col) {
 
         tuple newtuple;
 
-        if (sameL[col] == col || sameL[col] < (int)xbegin) {
-            if (lastLinked == col - 1)
-                newtuple = outRow[col - 1];
-            else
-                newtuple = outGenP->getTuple(outGenP, col, row);
+        if (sameL[col] == col || sameL[col] < xbegin) {
+            if (colHasBeenLinked && lastLinkedCol == col - 1)
+                newtuple = outRow[lastLinkedCol];
+            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;
-              /* Keep track of the last pixel to be constrained. */
+            newtuple = outRow[sameL[col]];
+            colHasBeenLinked = true;
+            lastLinkedCol = col;
+                /* Keep track of the last pixel to be constrained. */
         }
         pnm_assigntuple(&outGenP->pam, outRow[col], newtuple);
     }
 
-    for (col = (int)xbegin - 1, lastLinked = INT_MIN; col >= 0; --col) {
+    for (col = xbegin, colHasBeenLinked = false; 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 (colHasBeenLinked && lastLinkedCol == col)
+                newtuple = outRow[lastLinkedCol];
+            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]];
+            colHasBeenLinked = true;
+            lastLinkedCol = 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 +1294,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 +1307,7 @@ makeOneImageRow(unsigned int         const row,
                             rowBuffer, outRow);
         else
             makeImageRow(outputGeneratorP, row,
-                         xbegin, sameL, sameR, outRow);
+                         xbegin, farWidth, yfillshift, sameL, sameR, outRow);
     }
 }
 
@@ -1284,6 +1319,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 +1337,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 +1399,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 +1436,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 +1465,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 +1476,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 +1496,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 +1558,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 +1616,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 +1627,3 @@ main(int argc, const char *argv[]) {
 }
 
 
-