home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / print / print-weave.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-22  |  25.1 KB  |  892 lines

  1. /*
  2.  * "$Id: print-weave.c,v 1.4 2000/10/21 13:27:30 mitch Exp $"
  3.  *
  4.  *   Softweave calculator for gimp-print.
  5.  *
  6.  *   Copyright 2000 Charles Briscoe-Smith <cpbs@debian.org>
  7.  *
  8.  *   This program is free software; you can redistribute it and/or modify it
  9.  *   under the terms of the GNU General Public License as published by the Free
  10.  *   Software Foundation; either version 2 of the License, or (at your option)
  11.  *   any later version.
  12.  *
  13.  *   This program is distributed in the hope that it will be useful, but
  14.  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  15.  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16.  *   for more details.
  17.  *
  18.  *   You should have received a copy of the GNU General Public License
  19.  *   along with this program; if not, write to the Free Software
  20.  *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. /*
  24.  * This file must include only standard C header files.  The core code must
  25.  * compile on generic platforms that don't support glib, gimp, gtk, etc.
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include "print.h"
  32.  
  33. #if 0
  34. #define TEST_RAW
  35. #endif
  36. #if 0
  37. #define TEST_COOKED
  38. #endif
  39. #if 0
  40. #define ACCUMULATE
  41. #endif
  42. #if 1
  43. #define ASSERTIONS
  44. #endif
  45.  
  46. #if defined(TEST_RAW) || defined(TEST_COOKED)
  47. #define TEST
  48. #endif
  49.  
  50. #ifdef ASSERTIONS
  51. #define assert(x) if (!(x)) { fprintf(stderr, "ASSERTION FAILURE!  \"%s\", line %d.\n", __FILE__, __LINE__); exit(1); }
  52. #else
  53. #define assert(x) /* nothing */
  54. #endif
  55.  
  56. #ifdef TEST
  57. #define MAXCOLLECT (1000)
  58. #endif
  59.  
  60. static int
  61. gcd(int x, int y)
  62. {
  63.     assert (x >= 0);
  64.     assert (y >= 0);
  65.     if (y == 0)
  66.         return x;
  67.     while (x != 0) {
  68.         if (y > x) {
  69.             int t = x;
  70.             x = y;
  71.             y = t;
  72.         }
  73.         x %= y;
  74.     }
  75.     return y;
  76. }
  77.  
  78. /* RAW WEAVE */
  79.  
  80. typedef struct raw {
  81.     int separation;
  82.     int jets;
  83.     int oversampling;
  84.     int advancebasis;
  85.     int subblocksperpassblock;
  86.     int passespersubblock;
  87.     int strategy;
  88. } raw_t;
  89.  
  90. /*
  91.  * Strategy types currently defined:
  92.  *
  93.  *  0: microweave (intercepted at the escp2 driver level so we never
  94.  *     see it here)
  95.  *  1: zig-zag type pass block filling
  96.  *  2: ascending pass block filling
  97.  *  3: descending pass block filling
  98.  *  4: ascending fill with 2x expansion
  99.  *  5: ascending fill with 3x expansion
  100.  *  6: staggered zig-zag neighbour-avoidance fill
  101.  *
  102.  * In theory, strategy 1 should be optimal; in practice, it can lead
  103.  * to visible areas of banding.  If it's necessary to avoid filling
  104.  * neighbouring rows in neighbouring passes, strategy 6 should be optimal,
  105.  * at least for some weaves.
  106.  */
  107.  
  108. static void
  109. initialize_raw_weave(raw_t *w,    /* I - weave struct to be filled in */
  110.                      int S,    /* I - jet separation */
  111.                      int J,    /* I - number of jets */
  112.                      int H,    /* I - oversampling factor */
  113.                      int strat)    /* I - weave pattern variation to use */
  114. {
  115.     w->separation = S;
  116.     w->jets = J;
  117.     w->oversampling = H;
  118.     w->advancebasis = J / H;
  119.     w->subblocksperpassblock = gcd(S, w->advancebasis);
  120.     w->passespersubblock = S / w->subblocksperpassblock;
  121.     w->strategy = strat;
  122. }
  123.  
  124. static void
  125. calculate_raw_pass_parameters(raw_t *w,        /* I - weave parameters */
  126.                               int pass,        /* I - pass number ( >= 0) */
  127.                               int *startrow,    /* O - print head position */
  128.                               int *subpass)    /* O - subpass number */
  129. {
  130.     int band, passinband, subpassblock, subpassoffset;
  131.  
  132.     band = pass / (w->separation * w->oversampling);
  133.     passinband = pass % (w->separation * w->oversampling);
  134.     subpassblock = pass % w->separation
  135.                      * w->subblocksperpassblock / w->separation;
  136.  
  137.     switch (w->strategy) {
  138.     case 1:
  139.         if (subpassblock * 2 < w->subblocksperpassblock)
  140.             subpassoffset = 2 * subpassblock;
  141.         else
  142.             subpassoffset = 2 * (w->subblocksperpassblock
  143.                                   - subpassblock) - 1;
  144.         break;
  145.     case 2:
  146.         subpassoffset = subpassblock;
  147.         break;
  148.     case 3:
  149.         subpassoffset = w->subblocksperpassblock - 1 - subpassblock;
  150.         break;
  151.     case 4:
  152.         if (subpassblock * 2 < w->subblocksperpassblock)
  153.             subpassoffset = 2 * subpassblock;
  154.         else
  155.             subpassoffset = 1 + 2 * (subpassblock
  156.                                       - (w->subblocksperpassblock
  157.                                           + 1) / 2);
  158.         break;
  159.     case 5:
  160.         if (subpassblock * 3 < w->subblocksperpassblock)
  161.             subpassoffset = 3 * subpassblock;
  162.         else if (3 * (subpassblock - (w->subblocksperpassblock + 2) / 3)
  163.                   < w->subblocksperpassblock - 2)
  164.             subpassoffset = 2 + 3 * (subpassblock
  165.                                       - (w->subblocksperpassblock
  166.                                           + 2) / 3);
  167.         else
  168.             subpassoffset = 1 + 3 * (subpassblock
  169.                                       - (w->subblocksperpassblock
  170.                                           + 2) / 3
  171.                           - w->subblocksperpassblock
  172.                               / 3);
  173.         break;
  174.     case 6:
  175.         if (subpassblock * 2 < w->subblocksperpassblock)
  176.             subpassoffset = 2 * subpassblock;
  177.         else if (subpassblock * 2 < w->subblocksperpassblock + 2)
  178.             subpassoffset = 1;
  179.         else
  180.             subpassoffset = 2 * (w->subblocksperpassblock
  181.                                   - subpassblock) + 1;
  182.         break;
  183.     default:
  184.         subpassoffset = subpassblock;
  185.         break;
  186.     }
  187.  
  188.     *startrow = w->separation * w->jets * band
  189.                   + w->advancebasis * passinband + subpassoffset;
  190.     *subpass = passinband / w->separation;
  191. }
  192.  
  193. static void
  194. calculate_raw_row_parameters(raw_t *w,        /* I - weave parameters */
  195.                              int row,        /* I - row number */
  196.                              int subpass,    /* I - subpass number */
  197.                              int *pass,        /* O - pass number */
  198.                              int *jet,        /* O - jet number in pass */
  199.                              int *startrow)    /* O - starting row of pass */
  200. {
  201.     int subblockoffset, subpassblock, band, baserow, passinband, offset;
  202.  
  203.     subblockoffset = row % w->subblocksperpassblock;
  204.     switch (w->strategy) {
  205.     case 1:
  206.         if (subblockoffset % 2 == 0)
  207.             subpassblock = subblockoffset / 2;
  208.         else
  209.             subpassblock = w->subblocksperpassblock
  210.                              - (subblockoffset + 1) / 2;
  211.         break;
  212.     case 2:
  213.         subpassblock = subblockoffset;
  214.         break;
  215.     case 3:
  216.         subpassblock = w->subblocksperpassblock - 1 - subblockoffset;
  217.         break;
  218.     case 4:
  219.         if (subblockoffset % 2 == 0)
  220.             subpassblock = subblockoffset / 2;
  221.         else
  222.             subpassblock = (subblockoffset - 1) / 2
  223.                            + (w->subblocksperpassblock + 1) / 2;
  224.         break;
  225.     case 5:
  226.         if (subblockoffset % 3 == 0)
  227.             subpassblock = subblockoffset / 3;
  228.         else if (subblockoffset % 3 == 1)
  229.             subpassblock = (subblockoffset - 1) / 3
  230.                              + (w->subblocksperpassblock + 2) / 3;
  231.         else
  232.             subpassblock = (subblockoffset - 2) / 3
  233.                              + (w->subblocksperpassblock + 2) / 3
  234.                              + (w->subblocksperpassblock + 1) / 3;
  235.         break;
  236.     case 6:
  237.         if (subblockoffset % 2 == 0)
  238.             subpassblock = subblockoffset / 2;
  239.         else if (subblockoffset == 1)
  240.             subpassblock = w->subblocksperpassblock / 2;
  241.         else
  242.             subpassblock = w->subblocksperpassblock
  243.                              - (subblockoffset - 1) / 2;
  244.     default:
  245.         subpassblock = subblockoffset;
  246.         break;
  247.     }
  248.  
  249.     band = row / (w->separation * w->jets);
  250.     baserow = row - subblockoffset - band * w->separation * w->jets;
  251.     passinband = baserow / w->advancebasis;
  252.     offset = baserow % w->advancebasis;
  253.  
  254.     while (offset % w->separation != 0
  255.            || passinband / w->separation != subpass
  256.            || passinband % w->separation / w->passespersubblock
  257.                 != subpassblock)
  258.     {
  259.         offset += w->advancebasis;
  260.         passinband--;
  261.         if (passinband < 0) {
  262.             const int roundedjets = w->advancebasis
  263.                                       * w->oversampling;
  264.             band--;
  265.             passinband += w->separation * w->oversampling;
  266.             offset += w->separation * (w->jets - roundedjets);
  267.         }
  268.     }
  269.  
  270.     *pass = band * w->oversampling * w->separation + passinband;
  271.     *jet = offset / w->separation;
  272.     *startrow = row - (*jet * w->separation);
  273. }
  274.  
  275. /* COOKED WEAVE */
  276.  
  277. typedef struct cooked {
  278.     raw_t rw;
  279.     int first_row_printed;
  280.     int last_row_printed;
  281.  
  282.     int first_premapped_pass;    /* First raw pass used by this page */
  283.     int first_normal_pass;
  284.     int first_postmapped_pass;
  285.     int first_unused_pass;
  286.  
  287.     int *pass_premap;
  288.     int *stagger_premap;
  289.     int *pass_postmap;
  290.     int *stagger_postmap;
  291. } cooked_t;
  292.  
  293. static void
  294. sort_by_start_row(int *map, int *startrows, int count)
  295. {
  296.     /*
  297.      * Yes, it's a bubble sort, but we do it no more than 4 times
  298.      * per page, and we are only sorting a small number of items.
  299.      */
  300.  
  301.     int dirty;
  302.  
  303.     do {
  304.         int x;
  305.         dirty = 0;
  306.         for (x = 1; x < count; x++) {
  307.             if (startrows[x - 1] > startrows[x]) {
  308.                 int temp = startrows[x - 1];
  309.                 startrows[x - 1] = startrows[x];
  310.                 startrows[x] = temp;
  311.                 temp = map[x - 1];
  312.                 map[x - 1] = map[x];
  313.                 map[x] = temp;
  314.                 dirty = 1;
  315.             }
  316.         }
  317.     } while (dirty);
  318. }
  319.  
  320. static void
  321. calculate_stagger(raw_t *w, int *map, int *startrows_stagger, int count)
  322. {
  323.     int i;
  324.  
  325.     for (i = 0; i < count; i++) {
  326.         int startrow, subpass;
  327.         calculate_raw_pass_parameters(w, map[i], &startrow, &subpass);
  328.         startrow -= w->separation * w->jets;
  329.         startrows_stagger[i] = (startrows_stagger[i] - startrow)
  330.                                  / w->separation;
  331.     }
  332. }
  333.  
  334. static void
  335. invert_map(int *map, int *stagger, int count, int oldfirstpass,
  336.            int newfirstpass)
  337. {
  338.     int i;
  339.     int *newmap, *newstagger;
  340.     newmap = malloc(count * sizeof(int));
  341.     newstagger = malloc(count * sizeof(int));
  342.  
  343.     for (i = 0; i < count; i++) {
  344.         newmap[map[i] - oldfirstpass] = i + newfirstpass;
  345.         newstagger[map[i] - oldfirstpass] = stagger[i];
  346.     }
  347.  
  348.     memcpy(map, newmap, count * sizeof(int));
  349.     memcpy(stagger, newstagger, count * sizeof(int));
  350.     free(newstagger);
  351.     free(newmap);
  352. }
  353.  
  354. static void
  355. make_passmap(raw_t *w, int **map, int **starts, int first_pass_number,
  356.              int first_pass_to_map, int first_pass_after_map,
  357.              int first_pass_to_stagger, int first_pass_after_stagger,
  358.              int first_row_of_maximal_pass, int separations_to_distribute)
  359. {
  360.     int *passmap, *startrows;
  361.     int passes_to_map = first_pass_after_map - first_pass_to_map;
  362.     int i;
  363.  
  364.     assert(first_pass_to_map <= first_pass_after_map);
  365.     assert(first_pass_to_stagger <= first_pass_after_stagger);
  366.  
  367.     *map = passmap = malloc(passes_to_map * sizeof(int));
  368.     *starts = startrows = malloc(passes_to_map * sizeof(int));
  369.  
  370.     for (i = 0; i < passes_to_map; i++) {
  371.         int startrow, subpass;
  372.         int pass = i + first_pass_to_map;
  373.         calculate_raw_pass_parameters(w, pass, &startrow, &subpass);
  374.         passmap[i] = pass;
  375.         if (first_row_of_maximal_pass >= 0)
  376.             startrow = first_row_of_maximal_pass - startrow
  377.                          + w->separation * w->jets;
  378.         else
  379.             startrow -= w->separation * w->jets;
  380.         while (startrow < 0)
  381.             startrow += w->separation;
  382.         startrows[i] = startrow;
  383.     }
  384.  
  385.     sort_by_start_row(passmap, startrows, passes_to_map);
  386.  
  387.     separations_to_distribute++;
  388.  
  389.     for (i = 0; i < first_pass_after_stagger - first_pass_to_stagger; i++) {
  390.         int offset = first_pass_to_stagger - first_pass_to_map;
  391.         if (startrows[i + offset] / w->separation
  392.               < i % separations_to_distribute)
  393.         {
  394.             startrows[i + offset]
  395.               = startrows[i + offset] % w->separation
  396.                  + w->separation * (i % separations_to_distribute);
  397.         }
  398.     }
  399.  
  400.     if (first_row_of_maximal_pass >= 0) {
  401.         for (i = 0; i < passes_to_map; i++) {
  402.             startrows[i] = first_row_of_maximal_pass - startrows[i];
  403.         }
  404.     }
  405.  
  406.     sort_by_start_row(passmap, startrows, passes_to_map);
  407.     calculate_stagger(w, passmap, startrows, passes_to_map);
  408.  
  409.     invert_map(passmap, startrows, passes_to_map, first_pass_to_map,
  410.            first_pass_to_map - first_pass_number);
  411. }
  412.  
  413. static void
  414. calculate_pass_map(cooked_t *w,        /* I - weave parameters */
  415.                    int pagelength,    /* I - number of rows on page */
  416.                    int firstrow,    /* I - first printed row */
  417.                    int lastrow)        /* I - last printed row */
  418. {
  419.     int startrow, subpass;
  420.     int pass = -1;
  421.  
  422.     w->first_row_printed = firstrow;
  423.     w->last_row_printed = lastrow;
  424.  
  425.     if (pagelength <= lastrow)
  426.         pagelength = lastrow + 1;
  427.  
  428.     do {
  429.         calculate_raw_pass_parameters(&w->rw, ++pass,
  430.                                       &startrow, &subpass);
  431.     } while (startrow - w->rw.separation < firstrow);
  432.  
  433.     w->first_premapped_pass = pass;
  434.  
  435.     while (startrow < w->rw.separation * w->rw.jets
  436.            && startrow - w->rw.separation < pagelength
  437.            && startrow <= lastrow + w->rw.separation * w->rw.jets)
  438.     {
  439.         calculate_raw_pass_parameters(&w->rw, ++pass,
  440.                                       &startrow, &subpass);
  441.     }
  442.     w->first_normal_pass = pass;
  443.  
  444.     while (startrow - w->rw.separation < pagelength
  445.            && startrow <= lastrow + w->rw.separation * w->rw.jets)
  446.     {
  447.         calculate_raw_pass_parameters(&w->rw, ++pass,
  448.                                       &startrow, &subpass);
  449.     }
  450.     w->first_postmapped_pass = pass;
  451.  
  452.     while (startrow <= lastrow + w->rw.separation * w->rw.jets) {
  453.         calculate_raw_pass_parameters(&w->rw, ++pass,
  454.                                       &startrow, &subpass);
  455.     }
  456.     w->first_unused_pass = pass;
  457.  
  458.     /*
  459.      * FIXME: make sure first_normal_pass doesn't advance beyond
  460.      * first_postmapped_pass, or first_postmapped_pass doesn't
  461.      * retreat before first_normal_pass.
  462.      */
  463.  
  464.     if (w->first_normal_pass > w->first_premapped_pass) {
  465.         int spread, separations_to_distribute, normal_passes_mapped;
  466.         separations_to_distribute = firstrow / w->rw.separation;
  467.         spread = (separations_to_distribute + 1) * w->rw.separation;
  468.         normal_passes_mapped = (spread + w->rw.advancebasis - 1)
  469.                                     / w->rw.advancebasis;
  470.         w->first_normal_pass += normal_passes_mapped;
  471.         make_passmap(&w->rw, &w->pass_premap, &w->stagger_premap,
  472.                      w->first_premapped_pass,
  473.                      w->first_premapped_pass, w->first_normal_pass,
  474.                  w->first_premapped_pass,
  475.                  w->first_normal_pass - normal_passes_mapped,
  476.                      -1, separations_to_distribute);
  477.     } else {
  478.         w->pass_premap = 0;
  479.         w->stagger_premap = 0;
  480.     }
  481.  
  482.     if (w->first_unused_pass > w->first_postmapped_pass) {
  483.         int spread, separations_to_distribute, normal_passes_mapped;
  484.         separations_to_distribute = (pagelength - lastrow - 1)
  485.                                              / w->rw.separation;
  486.         spread = (separations_to_distribute + 1) * w->rw.separation;
  487.         normal_passes_mapped = (spread + w->rw.advancebasis)
  488.                                      / w->rw.advancebasis;
  489.         w->first_postmapped_pass -= normal_passes_mapped;
  490.         make_passmap(&w->rw, &w->pass_postmap, &w->stagger_postmap,
  491.                      w->first_premapped_pass,
  492.                      w->first_postmapped_pass, w->first_unused_pass,
  493.                  w->first_postmapped_pass + normal_passes_mapped,
  494.                  w->first_unused_pass,
  495.                      pagelength - 1
  496.                          - w->rw.separation * (w->rw.jets - 1),
  497.                  separations_to_distribute);
  498.     } else {
  499.         w->pass_postmap = 0;
  500.         w->stagger_postmap = 0;
  501.     }
  502. }
  503.  
  504. void *                    /* O - weave parameter block */
  505. initialize_weave_params(int S,        /* I - jet separation */
  506.                         int J,        /* I - number of jets */
  507.                         int H,        /* I - oversampling factor */
  508.                         int firstrow,    /* I - first row number to print */
  509.                         int lastrow,    /* I - last row number to print */
  510.                         int pagelength,    /* I - number of rows on the whole
  511.                                        page, without using any
  512.                                        expanded margin facilities */
  513.                         int strategy)    /* I - weave pattern variant to use */
  514. {
  515.     cooked_t *w = malloc(sizeof(cooked_t));
  516.     if (w) {
  517.         initialize_raw_weave(&w->rw, S, J, H, strategy);
  518.         calculate_pass_map(w, pagelength, firstrow, lastrow);
  519.     }
  520.     return w;
  521. }
  522.  
  523. void
  524. destroy_weave_params(void *vw)
  525. {
  526.     cooked_t *w = (cooked_t *) vw;
  527.  
  528.     if (w->pass_premap) free(w->pass_premap);
  529.     if (w->stagger_premap) free(w->stagger_premap);
  530.     if (w->pass_postmap) free(w->pass_postmap);
  531.     if (w->stagger_postmap) free(w->stagger_postmap);
  532.     free(w);
  533. }
  534.  
  535. void
  536. calculate_row_parameters(void *vw,        /* I - weave parameters */
  537.                          int row,        /* I - row number */
  538.                          int subpass,        /* I - subpass */
  539.                          int *pass,        /* O - pass containing row */
  540.                          int *jetnum,        /* O - jet number of row */
  541.                          int *startingrow,    /* O - phys start row of pass */
  542.                          int *ophantomrows,    /* O - missing rows at start */
  543.                          int *ojetsused)    /* O - jets used by pass */
  544. {
  545.     cooked_t *w = (cooked_t *) vw;
  546.     int raw_pass, jet, startrow, phantomrows, jetsused;
  547.     int stagger = 0;
  548.     int extra;
  549.  
  550.     assert(row >= w->first_row_printed);
  551.     assert(row <= w->last_row_printed);
  552.     calculate_raw_row_parameters(&w->rw,
  553.                                  row + w->rw.separation * w->rw.jets,
  554.                                  subpass, &raw_pass, &jet, &startrow);
  555.     startrow -= w->rw.separation * w->rw.jets;
  556.     jetsused = w->rw.jets;
  557.     phantomrows = 0;
  558.  
  559.     if (raw_pass < w->first_normal_pass) {
  560.         *pass = w->pass_premap[raw_pass - w->first_premapped_pass];
  561.         stagger = w->stagger_premap[raw_pass - w->first_premapped_pass];
  562.     } else if (raw_pass >= w->first_postmapped_pass) {
  563.         *pass = w->pass_postmap[raw_pass - w->first_postmapped_pass];
  564.         stagger = w->stagger_postmap[raw_pass
  565.                                      - w->first_postmapped_pass];
  566.     } else {
  567.         *pass = raw_pass - w->first_premapped_pass;
  568.     }
  569.  
  570.     startrow += stagger * w->rw.separation;
  571.     *jetnum = jet - stagger;
  572.     if (stagger < 0) {
  573.         stagger = -stagger;
  574.         phantomrows += stagger;
  575.     }
  576.     jetsused -= stagger;
  577.  
  578.     extra = w->first_row_printed
  579.                  - (startrow + w->rw.separation * phantomrows);
  580.     if (extra > 0) {
  581.         extra = (extra + w->rw.separation - 1) / w->rw.separation;
  582.         jetsused -= extra;
  583.         phantomrows += extra;
  584.     }
  585.  
  586.     extra = startrow + w->rw.separation * (phantomrows + jetsused - 1)
  587.               - w->last_row_printed;
  588.     if (extra > 0) {
  589.         extra = (extra + w->rw.separation - 1) / w->rw.separation;
  590.         jetsused -= extra;
  591.     }
  592.  
  593.     *startingrow = startrow;
  594.     *ophantomrows = phantomrows;
  595.     *ojetsused = jetsused;
  596. }
  597.  
  598. #ifdef TEST_COOKED
  599. static void
  600. calculate_pass_parameters(cooked_t *w,        /* I - weave parameters */
  601.                           int pass,        /* I - pass number ( >= 0) */
  602.                           int *startrow,    /* O - print head position */
  603.                           int *subpass,        /* O - subpass number */
  604.               int *phantomrows,    /* O - missing rows */
  605.               int *jetsused)    /* O - jets used to print */
  606. {
  607.     int raw_pass = pass + w->first_premapped_pass;
  608.     int stagger = 0;
  609.     int extra;
  610.  
  611.     if (raw_pass < w->first_normal_pass) {
  612.         int i = 0;
  613.         while (i + w->first_premapped_pass < w->first_normal_pass) {
  614.             if (w->pass_premap[i] == pass) {
  615.                 raw_pass = i + w->first_premapped_pass;
  616.                 stagger = w->stagger_premap[i];
  617.                 break;
  618.             }
  619.             i++;
  620.         }
  621.     } else if (raw_pass >= w->first_postmapped_pass) {
  622.         int i = 0;
  623.         while (i + w->first_postmapped_pass < w->first_unused_pass) {
  624.             if (w->pass_postmap[i] == pass) {
  625.                 raw_pass = i + w->first_postmapped_pass;
  626.                 stagger = w->stagger_postmap[i];
  627.                 break;
  628.             }
  629.             i++;
  630.         }
  631.     }
  632.  
  633.     calculate_raw_pass_parameters(&w->rw, raw_pass, startrow, subpass);
  634.     *startrow -= w->rw.separation * w->rw.jets;
  635.     *jetsused = w->rw.jets;
  636.     *phantomrows = 0;
  637.  
  638.     *startrow += stagger * w->rw.separation;
  639.     if (stagger < 0) {
  640.         stagger = -stagger;
  641.         *phantomrows += stagger;
  642.     }
  643.     *jetsused -= stagger;
  644.  
  645.     extra = w->first_row_printed - (*startrow + w->rw.separation * *phantomrows);
  646.     extra = (extra + w->rw.separation - 1) / w->rw.separation;
  647.     if (extra > 0) {
  648.         *jetsused -= extra;
  649.         *phantomrows += extra;
  650.     }
  651.  
  652.     extra = *startrow + w->rw.separation * (*phantomrows + *jetsused - 1)
  653.               - w->last_row_printed;
  654.     extra = (extra + w->rw.separation - 1) / w->rw.separation;
  655.     if (extra > 0) {
  656.         *jetsused -= extra;
  657.     }
  658. }
  659. #endif /* TEST_COOKED */
  660.  
  661. #ifdef TEST
  662.  
  663. #ifdef ACCUMULATE
  664. #define PUTCHAR(x) /* nothing */
  665. #else
  666. #define PUTCHAR(x) putchar(x)
  667. #endif
  668.  
  669. static void
  670. plotpass(int startrow, int phantomjets, int jetsused, int totaljets,
  671.          int separation, int subpass, int *collect, int *prints)
  672. {
  673.     int hpos, i;
  674.  
  675.     for (hpos = 0; hpos < startrow; hpos++)
  676.         PUTCHAR(' ');
  677.  
  678.     for (i = 0; i < phantomjets; i++) {
  679.         int j;
  680.         PUTCHAR('X');
  681.         hpos++;
  682.         for (j = 1; j < separation; j++) {
  683.             PUTCHAR(' ');
  684.             hpos++;
  685.         }
  686.     }
  687.  
  688.     for (; i < phantomjets + jetsused; i++) {
  689.         if (i > phantomjets) {
  690.             int j;
  691.             for (j = 1; j < separation; j++) {
  692.                 PUTCHAR('-');
  693.                 hpos++;
  694.             }
  695.         }
  696.         if (hpos < MAXCOLLECT) {
  697.             if (collect[hpos] & 1 << subpass)
  698.                 PUTCHAR('^');
  699.             else if (subpass < 10)
  700.                 PUTCHAR('0' + subpass);
  701.             else
  702.                 PUTCHAR('A' + subpass - 10);
  703.             collect[hpos] |= 1 << subpass;
  704.             prints[hpos]++;
  705.         } else {
  706.             PUTCHAR('0' + subpass);
  707.         }
  708.         hpos++;
  709.     }
  710.  
  711.     while (i++ < totaljets) {
  712.         int j;
  713.         for (j = 1; j < separation; j++) {
  714.             PUTCHAR(' ');
  715.             hpos++;
  716.         }
  717.         PUTCHAR('X');
  718.     }
  719. #ifdef ACCUMULATE
  720.     for (i=0; i<=MAXCOLLECT; i++) {
  721.         if (collect[i] == 0)
  722.             putchar(' ');
  723.         else if (collect[i] < 10)
  724.             putchar('0'+collect[i]);
  725.         else
  726.             putchar('A'+collect[i]-10);
  727.     }
  728. #endif
  729.     putchar('\n');
  730. }
  731. #endif /* TEST */
  732.  
  733. #ifdef TEST_COOKED
  734. int
  735. main(int ac, char *av[])
  736. {
  737.     int S         =ac>1 ? atoi(av[1]) : 4;
  738.     int J         =ac>2 ? atoi(av[2]) : 12;
  739.     int H         =ac>3 ? atoi(av[3]) : 1;
  740.     int firstrow  =ac>4 ? atoi(av[4]) : 1;
  741.     int lastrow   =ac>5 ? atoi(av[5]) : 100;
  742.     int pagelength=ac>6 ? atoi(av[6]) : 1000;
  743.     int strategy  =ac>7 ? atoi(av[7]) : 1;
  744.     cooked_t *weave;
  745.     int passes;
  746.  
  747.     int pass, x;
  748.     int collect[MAXCOLLECT];
  749.     int prints[MAXCOLLECT];
  750.  
  751.     memset(collect, 0, MAXCOLLECT*sizeof(int));
  752.     memset(prints, 0, MAXCOLLECT*sizeof(int));
  753.     printf("S=%d  J=%d  H=%d  firstrow=%d  lastrow=%d  "
  754.            "pagelength=%d  strategy=%d\n",
  755.            S, J, H, firstrow, lastrow, pagelength, strategy);
  756.  
  757.     weave = initialize_weave_params(S, J, H, firstrow, lastrow,
  758.                                     pagelength, strategy);
  759.     passes = weave->first_unused_pass - weave->first_premapped_pass;
  760.  
  761.     for (pass = 0; pass < passes; pass++) {
  762.         int startrow, subpass, phantomjets, jetsused;
  763.  
  764.         calculate_pass_parameters(weave, pass, &startrow, &subpass,
  765.                                   &phantomjets, &jetsused);
  766.  
  767.         plotpass(startrow, phantomjets, jetsused, J, S, subpass,
  768.                  collect, prints);
  769.     }
  770.  
  771.     for (pass=MAXCOLLECT - 1; prints[pass] == 0; pass--)
  772.         ;
  773.  
  774.     for (x=0; x<=pass; x++) {
  775.         if (collect[x] < 10)
  776.             putchar('0'+collect[x]);
  777.         else
  778.             putchar('A'+collect[x]-10);
  779.     }
  780.     putchar('\n');
  781.  
  782.     for (x=0; x<=pass; x++) {
  783.         if (prints[x] < 10)
  784.             putchar('0'+prints[x]);
  785.         else
  786.             putchar('A'+prints[x]-10);
  787.     }
  788.     putchar('\n');
  789.  
  790.     return 0;
  791. }
  792. #endif /* TEST_COOKED */
  793.  
  794. #ifdef TEST_RAW
  795. int
  796. main(int ac, char *av[])
  797. {
  798.     int S     =ac>1 ? atoi(av[1]) : 4;
  799.     int J     =ac>2 ? atoi(av[2]) : 12;
  800.     int h_pos =ac>3 ? atoi(av[3]) : 1;
  801.     int h_over=ac>4 ? atoi(av[4]) : 1;
  802.     int v_over=ac>5 ? atoi(av[5]) : 1;
  803.     int H = h_pos * h_over * v_over;
  804.  
  805.     int pass, passes, x;
  806.     int collect[MAXCOLLECT];
  807.     int prints[MAXCOLLECT];
  808.     raw_t raw;
  809.  
  810.     memset(collect, 0, MAXCOLLECT*sizeof(int));
  811.     memset(prints, 0, MAXCOLLECT*sizeof(int));
  812.     printf("S=%d  J=%d  H=%d\n", S, J, H);
  813.  
  814.     if (H > J) {
  815.         printf("H > J, so this weave will not work!\n");
  816.     }
  817.     passes = S * H * 3;
  818.  
  819.     initialize_raw_weave(&raw, S, J, H);
  820.  
  821.     for (pass=0; pass<passes + S * H; pass++) {
  822.         int startrow, subpass, phantomjets, jetsused;
  823.  
  824.         calculate_raw_pass_parameters(&raw, pass, &startrow, &subpass);
  825.         phantomjets = 0;
  826.         jetsused = J;
  827.  
  828.         plotpass(startrow, phantomjets, jetsused, J, S, subpass,
  829.                  collect, prints);
  830.     }
  831.     for (pass=MAXCOLLECT - 1; prints[pass] == 0; pass--)
  832.         ;
  833.  
  834.     for (x=0; x<=pass; x++) {
  835.         if (collect[x] < 10)
  836.             putchar('0'+collect[x]);
  837.         else
  838.             putchar('A'+collect[x]-10);
  839.     }
  840.     putchar('\n');
  841.  
  842.     for (x=0; x<=pass; x++) {
  843.         if (prints[x] < 10)
  844.             putchar('0'+prints[x]);
  845.         else
  846.             putchar('A'+prints[x]-10);
  847.     }
  848.     putchar('\n');
  849.  
  850.     printf("  A  first row given by pass lookup doesn't match row lookup\n"
  851.            "  B  jet out of range\n"
  852.            "  C  given jet number of pass doesn't print this row\n"
  853.            "  D  subpass given by reverse lookup doesn't match requested subpass\n");
  854.  
  855.     for (x = S * J; x < S * J * 20; x++) {
  856.         int h;
  857.         for (h = 0; h < H; h++) {
  858.             int pass, jet, start, first, subpass, z;
  859.             int a=0, b=0, c=0, d=0;
  860.             calculate_raw_row_parameters(&raw, x, h, &pass, &jet, &start);
  861.             for (z=0; z < pass; z++) {
  862.                 putchar(' ');
  863.             }
  864.             printf("%d", jet);
  865.             calculate_raw_pass_parameters(&raw, pass, &first, &subpass);
  866.             if (first != start)
  867.                 a=1;
  868.             if (jet < 0 || jet >= J)
  869.                 b=1;
  870.             if (x != first + jet * S)
  871.                 c=1;
  872.             if (subpass != h)
  873.                 d=1;
  874.             if (a || b || c || d) {
  875.                 printf("    (");
  876.                 if (a) putchar('A');
  877.                 if (b) putchar('B');
  878.                 if (c) putchar('C');
  879.                 if (d) putchar('D');
  880.                 putchar(')');
  881.                 printf("\npass=%d first=%d start=%d jet=%d subpass=%d", pass, first, start, jet, subpass);
  882.             }
  883.             putchar('\n');
  884.         }
  885.         /* putchar('\n'); */
  886.     }
  887.  
  888.     return 0;
  889. }
  890.  
  891. #endif /* TEST_RAW */
  892.