#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <gimp-print/gimp-print.h>
#include "gimp-print-internal.h"
#include <gimp-print/gimp-print-intl-internal.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#if 1
#define ASSERTIONS
#endif
#ifdef ASSERTIONS
#define assert(x,v) \
do \
{ \
if (!(x)) \
{ \
stp_eprintf(v, "Assertion %s failed! file %s, line %d.\n", \
#x, __FILE__, __LINE__); \
stp_abort(); \
} \
} while (0)
#else
#define assert(x,v) do {} while (0)
#endif
static int
gcd(int x, int y)
{
if (y == 0)
return x;
while (x != 0) {
if (y > x) {
int t = x;
x = y;
y = t;
}
x %= y;
}
return y;
}
typedef struct stpi_softweave
{
stp_linebufs_t *linebases;
stp_lineoff_t *lineoffsets;
stp_lineactive_t *lineactive;
stp_linecount_t *linecounts;
stp_linebounds_t *linebounds;
stp_pass_t *passes;
int last_pass_offset;
int last_pass;
int jets;
int virtual_jets;
int separation;
void *weaveparm;
int horizontal_weave;
int vertical_subpasses;
int vmod;
int oversample;
int repeat_count;
int ncolors;
int linewidth;
int vertical_height;
int firstline;
int bitwidth;
int lineno;
int vertical_oversample;
int current_vertical_subpass;
int horizontal_width;
int *head_offset;
unsigned char *s[STP_MAX_WEAVE];
unsigned char *fold_buf;
unsigned char *comp_buf;
stp_weave_t wcache;
int rcache;
int vcache;
stp_flushfunc *flushfunc;
stp_fillfunc *fillfunc;
stp_packfunc *pack;
stp_compute_linewidth_func *compute_linewidth;
} stpi_softweave_t;
typedef struct raw {
int separation;
int jets;
int oversampling;
int advancebasis;
int subblocksperpassblock;
int passespersubblock;
stp_weave_strategy_t strategy;
stp_vars_t *v;
} raw_t;
static void
initialize_raw_weave(raw_t *w,
int separation,
int jets,
int oversample,
stp_weave_strategy_t strat,
stp_vars_t *v)
{
w->separation = separation;
w->jets = jets;
w->oversampling = oversample;
w->advancebasis = jets / oversample;
if (w->advancebasis == 0)
w->advancebasis++;
w->subblocksperpassblock = gcd(separation, w->advancebasis);
w->passespersubblock = separation / w->subblocksperpassblock;
w->strategy = strat;
w->v = v;
}
static void
calculate_raw_pass_parameters(raw_t *w,
int pass,
int *startrow,
int *subpass)
{
int band, passinband, subpassblock, subpassoffset;
band = pass / (w->separation * w->oversampling);
passinband = pass % (w->separation * w->oversampling);
subpassblock = pass % w->separation
* w->subblocksperpassblock / w->separation;
switch (w->strategy) {
case STP_WEAVE_ZIGZAG:
if (subpassblock * 2 < w->subblocksperpassblock)
subpassoffset = 2 * subpassblock;
else
subpassoffset = 2 * (w->subblocksperpassblock
- subpassblock) - 1;
break;
case STP_WEAVE_ASCENDING:
subpassoffset = subpassblock;
break;
case STP_WEAVE_DESCENDING:
subpassoffset = w->subblocksperpassblock - 1 - subpassblock;
break;
case STP_WEAVE_ASCENDING_2X:
if (subpassblock * 2 < w->subblocksperpassblock)
subpassoffset = 2 * subpassblock;
else
subpassoffset = 1 + 2 * (subpassblock
- (w->subblocksperpassblock
+ 1) / 2);
break;
case STP_WEAVE_ASCENDING_3X:
if (subpassblock * 3 < w->subblocksperpassblock)
subpassoffset = 3 * subpassblock;
else if (3 * (subpassblock - (w->subblocksperpassblock + 2) / 3)
< w->subblocksperpassblock - 2)
subpassoffset = 2 + 3 * (subpassblock
- (w->subblocksperpassblock
+ 2) / 3);
else
subpassoffset = 1 + 3 * (subpassblock
- (w->subblocksperpassblock
+ 2) / 3
- w->subblocksperpassblock
/ 3);
break;
case STP_WEAVE_STAGGERED:
if (subpassblock * 2 < w->subblocksperpassblock)
subpassoffset = 2 * subpassblock;
else if (subpassblock * 2 < w->subblocksperpassblock + 2)
subpassoffset = 1;
else
subpassoffset = 2 * (w->subblocksperpassblock
- subpassblock) + 1;
break;
default:
subpassoffset = subpassblock;
break;
}
*startrow = w->separation * w->jets * band
+ w->advancebasis * passinband + subpassoffset;
*subpass = passinband / w->separation;
}
static void
calculate_raw_row_parameters(raw_t *w,
int row,
int subpass,
int *pass,
int *jet,
int *startrow)
{
int subblockoffset, subpassblock, band, baserow, passinband, offset;
int pass_div_separation;
int pass_mod_separation;
int off_mod_separation;
subblockoffset = row % w->subblocksperpassblock;
switch (w->strategy) {
case STP_WEAVE_ZIGZAG:
if (subblockoffset % 2 == 0)
subpassblock = subblockoffset / 2;
else
subpassblock = w->subblocksperpassblock
- (subblockoffset + 1) / 2;
break;
case STP_WEAVE_ASCENDING:
subpassblock = subblockoffset;
break;
case STP_WEAVE_DESCENDING:
subpassblock = w->subblocksperpassblock - 1 - subblockoffset;
break;
case STP_WEAVE_ASCENDING_2X:
if (subblockoffset % 2 == 0)
subpassblock = subblockoffset / 2;
else
subpassblock = (subblockoffset - 1) / 2
+ (w->subblocksperpassblock + 1) / 2;
break;
case STP_WEAVE_ASCENDING_3X:
if (subblockoffset % 3 == 0)
subpassblock = subblockoffset / 3;
else if (subblockoffset % 3 == 1)
subpassblock = (subblockoffset - 1) / 3
+ (w->subblocksperpassblock + 2) / 3;
else
subpassblock = (subblockoffset - 2) / 3
+ (w->subblocksperpassblock + 2) / 3
+ (w->subblocksperpassblock + 1) / 3;
break;
case STP_WEAVE_STAGGERED:
if (subblockoffset % 2 == 0)
subpassblock = subblockoffset / 2;
else if (subblockoffset == 1)
subpassblock = (w->subblocksperpassblock + 1) / 2;
else
subpassblock = w->subblocksperpassblock
- (subblockoffset - 1) / 2;
break;
default:
subpassblock = subblockoffset;
break;
}
band = row / (w->separation * w->jets);
baserow = row - subblockoffset - band * w->separation * w->jets;
passinband = baserow / w->advancebasis;
offset = baserow % w->advancebasis;
pass_div_separation = passinband / w->separation;
pass_mod_separation = passinband % w->separation;
off_mod_separation = offset % w->separation;
while (off_mod_separation != 0
|| pass_div_separation != subpass
|| pass_mod_separation / w->passespersubblock
!= subpassblock)
{
offset += w->advancebasis;
passinband--;
if (passinband >= 0)
{
pass_mod_separation--;
if (pass_mod_separation < 0)
{
pass_mod_separation += w->separation;
pass_div_separation--;
}
if (w->advancebasis < w->separation)
{
off_mod_separation += w->advancebasis;
if (off_mod_separation >= w->separation)
off_mod_separation -= w->separation;
}
else if (w->advancebasis > w->separation)
off_mod_separation = offset % w->separation;
}
else
{
const int roundedjets =
(w->advancebasis * w->oversampling) % w->jets;
band--;
passinband += w->separation * w->oversampling;
offset += w->separation * (w->jets - roundedjets);
pass_div_separation = passinband / w->separation;
pass_mod_separation = passinband % w->separation;
off_mod_separation = offset % w->separation;
}
}
*pass = band * w->oversampling * w->separation + passinband;
*jet = (offset / w->separation) % w->jets;
*startrow = row - (*jet * w->separation);
}
typedef struct cooked {
raw_t rw;
int first_row_printed;
int last_row_printed;
int first_premapped_pass;
int first_normal_pass;
int first_postmapped_pass;
int first_unused_pass;
int *pass_premap;
int *stagger_premap;
int *pass_postmap;
int *stagger_postmap;
} cooked_t;
static void
sort_by_start_row(int *map, int *startrows, int count)
{
int dirty;
do {
int x;
dirty = 0;
for (x = 1; x < count; x++) {
if (startrows[x - 1] > startrows[x]) {
int temp = startrows[x - 1];
startrows[x - 1] = startrows[x];
startrows[x] = temp;
temp = map[x - 1];
map[x - 1] = map[x];
map[x] = temp;
dirty = 1;
}
}
} while (dirty);
}
static void
calculate_stagger(raw_t *w, int *map, int *startrows_stagger, int count)
{
int i;
for (i = 0; i < count; i++) {
int startrow, subpass;
calculate_raw_pass_parameters(w, map[i], &startrow, &subpass);
startrow -= w->separation * w->jets;
startrows_stagger[i] = (startrows_stagger[i] - startrow)
/ w->separation;
}
}
static void
invert_map(int *map, int *stagger, int count, int oldfirstpass,
int newfirstpass)
{
int i;
int *newmap, *newstagger;
newmap = stp_malloc(count * sizeof(int));
newstagger = stp_malloc(count * sizeof(int));
for (i = 0; i < count; i++) {
newmap[map[i] - oldfirstpass] = i + newfirstpass;
newstagger[map[i] - oldfirstpass] = stagger[i];
}
memcpy(map, newmap, count * sizeof(int));
memcpy(stagger, newstagger, count * sizeof(int));
stp_free(newstagger);
stp_free(newmap);
}
static void
make_passmap(raw_t *w, int **map, int **starts, int first_pass_number,
int first_pass_to_map, int first_pass_after_map,
int first_pass_to_stagger, int first_pass_after_stagger,
int first_row_of_maximal_pass, int separations_to_distribute)
{
int *passmap, *startrows;
int passes_to_map = first_pass_after_map - first_pass_to_map;
int i;
assert(first_pass_to_map <= first_pass_after_map, w->v);
assert(first_pass_to_stagger <= first_pass_after_stagger, w->v);
*map = passmap = stp_malloc(passes_to_map * sizeof(int));
*starts = startrows = stp_malloc(passes_to_map * sizeof(int));
for (i = 0; i < passes_to_map; i++) {
int startrow, subpass;
int pass = i + first_pass_to_map;
calculate_raw_pass_parameters(w, pass, &startrow, &subpass);
passmap[i] = pass;
if (first_row_of_maximal_pass >= 0)
startrow = first_row_of_maximal_pass - startrow
+ w->separation * w->jets;
else
startrow -= w->separation * w->jets;
while (startrow < 0)
startrow += w->separation;
startrows[i] = startrow;
}
sort_by_start_row(passmap, startrows, passes_to_map);
separations_to_distribute++;
for (i = 0; i < first_pass_after_stagger - first_pass_to_stagger; i++) {
int offset = first_pass_to_stagger - first_pass_to_map;
if (startrows[i + offset] / w->separation
< i % separations_to_distribute)
{
startrows[i + offset]
= startrows[i + offset] % w->separation
+ w->separation * (i % separations_to_distribute);
}
}
if (first_row_of_maximal_pass >= 0) {
for (i = 0; i < passes_to_map; i++) {
startrows[i] = first_row_of_maximal_pass - startrows[i];
}
}
sort_by_start_row(passmap, startrows, passes_to_map);
calculate_stagger(w, passmap, startrows, passes_to_map);
invert_map(passmap, startrows, passes_to_map, first_pass_to_map,
first_pass_to_map - first_pass_number);
}
static void
calculate_pass_map(stp_vars_t *v,
cooked_t *w,
int pageheight,
int firstrow,
int lastrow)
{
int startrow, subpass;
int pass = -1;
w->first_row_printed = firstrow;
w->last_row_printed = lastrow;
if (pageheight <= lastrow)
pageheight = lastrow + 1;
do {
calculate_raw_pass_parameters(&w->rw, ++pass,
&startrow, &subpass);
} while (startrow - w->rw.separation < firstrow);
w->first_premapped_pass = pass;
while (startrow < w->rw.separation * w->rw.jets
&& startrow - w->rw.separation < pageheight
&& startrow <= lastrow + w->rw.separation * w->rw.jets)
{
calculate_raw_pass_parameters(&w->rw, ++pass,
&startrow, &subpass);
}
w->first_normal_pass = pass;
while (startrow - w->rw.separation < pageheight
&& startrow <= lastrow + w->rw.separation * w->rw.jets)
{
calculate_raw_pass_parameters(&w->rw, ++pass,
&startrow, &subpass);
}
w->first_postmapped_pass = pass;
while (startrow <= lastrow + w->rw.separation * w->rw.jets) {
calculate_raw_pass_parameters(&w->rw, ++pass,
&startrow, &subpass);
}
w->first_unused_pass = pass;
stp_dprintf(STP_DBG_WEAVE_PARAMS, v,
"first premapped %d first normal %d first postmapped %d "
"first unused %d\n",
w->first_premapped_pass, w->first_normal_pass,
w->first_postmapped_pass, w->first_unused_pass);
if (w->first_normal_pass > w->first_premapped_pass) {
int spread, separations_to_distribute, normal_passes_mapped;
separations_to_distribute = firstrow / w->rw.separation;
spread = (separations_to_distribute + 1) * w->rw.separation;
normal_passes_mapped = (spread + w->rw.advancebasis - 1)
/ w->rw.advancebasis;
w->first_normal_pass += normal_passes_mapped;
make_passmap(&w->rw, &w->pass_premap, &w->stagger_premap,
w->first_premapped_pass,
w->first_premapped_pass, w->first_normal_pass,
w->first_premapped_pass,
w->first_normal_pass - normal_passes_mapped,
-1, separations_to_distribute);
} else {
w->pass_premap = 0;
w->stagger_premap = 0;
}
if (w->first_unused_pass >= w->first_postmapped_pass) {
int spread, separations_to_distribute, normal_passes_mapped;
separations_to_distribute = (pageheight - lastrow - 1)
/ w->rw.separation;
spread = (separations_to_distribute + 1) * w->rw.separation;
normal_passes_mapped = (spread + w->rw.advancebasis)
/ w->rw.advancebasis;
w->first_postmapped_pass -= normal_passes_mapped;
make_passmap(&w->rw, &w->pass_postmap, &w->stagger_postmap,
w->first_premapped_pass,
w->first_postmapped_pass, w->first_unused_pass,
w->first_postmapped_pass + normal_passes_mapped,
w->first_unused_pass,
pageheight - 1
- w->rw.separation * (w->rw.jets - 1),
separations_to_distribute);
} else {
w->pass_postmap = 0;
w->stagger_postmap = 0;
}
}
static void *
initialize_weave_params(int separation,
int jets,
int oversample,
int firstrow,
int lastrow,
int pageheight,
stp_weave_strategy_t strategy,
stp_vars_t *v)
{
cooked_t *w = stp_malloc(sizeof(cooked_t));
if (w) {
initialize_raw_weave(&w->rw, separation, jets, oversample, strategy, v);
calculate_pass_map(v, w, pageheight, firstrow, lastrow);
}
return w;
}
static void
stpi_destroy_weave_params(void *vw)
{
cooked_t *w = (cooked_t *) vw;
if (w->pass_premap) stp_free(w->pass_premap);
if (w->stagger_premap) stp_free(w->stagger_premap);
if (w->pass_postmap) stp_free(w->pass_postmap);
if (w->stagger_postmap) stp_free(w->stagger_postmap);
stp_free(w);
}
static void
stpi_calculate_row_parameters(void *vw,
int row,
int subpass,
int *pass,
int *jetnum,
int *startingrow,
int *ophantomrows,
int *ojetsused)
{
cooked_t *w = (cooked_t *) vw;
int raw_pass, jet, startrow, phantomrows, jetsused;
int stagger = 0;
int extra;
assert(row >= w->first_row_printed, w->rw.v);
assert(row <= w->last_row_printed, w->rw.v);
calculate_raw_row_parameters(&w->rw,
row + w->rw.separation * w->rw.jets,
subpass, &raw_pass, &jet, &startrow);
startrow -= w->rw.separation * w->rw.jets;
jetsused = w->rw.jets;
phantomrows = 0;
if (raw_pass < w->first_normal_pass) {
assert(raw_pass >= w->first_premapped_pass, w->rw.v);
*pass = w->pass_premap[raw_pass - w->first_premapped_pass];
stagger = w->stagger_premap[raw_pass - w->first_premapped_pass];
} else if (raw_pass >= w->first_postmapped_pass) {
assert(raw_pass >= w->first_postmapped_pass, w->rw.v);
*pass = w->pass_postmap[raw_pass - w->first_postmapped_pass];
stagger = w->stagger_postmap[raw_pass
- w->first_postmapped_pass];
} else {
*pass = raw_pass - w->first_premapped_pass;
}
startrow += stagger * w->rw.separation;
*jetnum = jet - stagger;
if (stagger < 0) {
stagger = -stagger;
phantomrows += stagger;
}
jetsused -= stagger;
extra = w->first_row_printed
- (startrow + w->rw.separation * phantomrows);
if (extra > 0) {
extra = (extra + w->rw.separation - 1) / w->rw.separation;
jetsused -= extra;
phantomrows += extra;
}
extra = startrow + w->rw.separation * (phantomrows + jetsused - 1)
- w->last_row_printed;
if (extra > 0) {
extra = (extra + w->rw.separation - 1) / w->rw.separation;
jetsused -= extra;
}
*startingrow = startrow;
*ophantomrows = phantomrows;
*ojetsused = jetsused;
}
static stp_lineoff_t *
allocate_lineoff(int count, int ncolors)
{
int i;
stp_lineoff_t *retval = stp_malloc(count * sizeof(stp_lineoff_t));
for (i = 0; i < count; i++)
{
retval[i].ncolors = ncolors;
retval[i].v = stp_zalloc(ncolors * sizeof(unsigned long));
}
return (retval);
}
static stp_lineactive_t *
allocate_lineactive(int count, int ncolors)
{
int i;
stp_lineactive_t *retval = stp_malloc(count * sizeof(stp_lineactive_t));
for (i = 0; i < count; i++)
{
retval[i].ncolors = ncolors;
retval[i].v = stp_zalloc(ncolors * sizeof(char));
}
return (retval);
}
static stp_linecount_t *
allocate_linecount(int count, int ncolors)
{
int i;
stp_linecount_t *retval = stp_malloc(count * sizeof(stp_linecount_t));
for (i = 0; i < count; i++)
{
retval[i].ncolors = ncolors;
retval[i].v = stp_zalloc(ncolors * sizeof(int));
}
return (retval);
}
static stp_linebounds_t *
allocate_linebounds(int count, int ncolors)
{
int i;
stp_linebounds_t *retval = stp_malloc(count * sizeof(stp_linebounds_t));
for (i = 0; i < count; i++)
{
retval[i].ncolors = ncolors;
retval[i].start_pos = stp_zalloc(ncolors * sizeof(int));
retval[i].end_pos = stp_zalloc(ncolors * sizeof(int));
}
return (retval);
}
static stp_linebufs_t *
allocate_linebuf(int count, int ncolors)
{
int i;
stp_linebufs_t *retval = stp_malloc(count * sizeof(stp_linebufs_t));
for (i = 0; i < count; i++)
{
retval[i].ncolors = ncolors;
retval[i].v = stp_zalloc(ncolors * sizeof(unsigned char *));
}
return (retval);
}
static void
stpi_destroy_weave(void *vsw)
{
int i, j;
stpi_softweave_t *sw = (stpi_softweave_t *) vsw;
stp_free(sw->passes);
if (sw->fold_buf)
stp_free(sw->fold_buf);
if (sw->comp_buf)
stp_free(sw->comp_buf);
for (i = 0; i < STP_MAX_WEAVE; i++)
if (sw->s[i])
stp_free(sw->s[i]);
for (i = 0; i < sw->vmod; i++)
{
for (j = 0; j < sw->ncolors; j++)
{
if (sw->linebases[i].v[j])
stp_free(sw->linebases[i].v[j]);
}
stp_free(sw->linecounts[i].v);
stp_free(sw->linebases[i].v);
stp_free(sw->lineactive[i].v);
stp_free(sw->lineoffsets[i].v);
stp_free(sw->linebounds[i].start_pos);
stp_free(sw->linebounds[i].end_pos);
}
stp_free(sw->linecounts);
stp_free(sw->lineactive);
stp_free(sw->lineoffsets);
stp_free(sw->linebases);
stp_free(sw->linebounds);
stp_free(sw->head_offset);
stpi_destroy_weave_params(sw->weaveparm);
stp_free(vsw);
}
void
stp_initialize_weave(stp_vars_t *v,
int jets,
int sep,
int osample,
int v_subpasses,
int v_subsample,
int ncolors,
int bitwidth,
int linewidth,
int line_count,
int first_line,
int page_height,
const int *head_offset,
stp_weave_strategy_t weave_strategy,
stp_flushfunc flushfunc,
stp_fillfunc fillfunc,
stp_packfunc pack,
stp_compute_linewidth_func compute_linewidth)
{
int i;
int last_line, maxHeadOffset;
stpi_softweave_t *sw = stp_zalloc(sizeof (stpi_softweave_t));
if (jets < 1)
jets = 1;
if (jets == 1 || sep < 1)
sep = 1;
if (v_subpasses < 1)
v_subpasses = 1;
if (v_subsample < 1)
v_subsample = 1;
sw->separation = sep;
sw->jets = jets;
sw->horizontal_weave = osample;
sw->oversample = osample * v_subpasses * v_subsample;
if (sw->oversample > jets)
{
int found = 0;
for (i = 2; i <= osample; i++)
{
if ((osample % i == 0) && (sw->oversample / i <= jets))
{
sw->repeat_count = i;
osample /= i;
found = 1;
break;
}
}
if (!found)
{
stp_eprintf(v, "Weave error: oversample (%d) > jets (%d)\n",
sw->oversample, jets);
stp_free(sw);
return;
}
}
else
sw->repeat_count = 1;
sw->vertical_oversample = v_subsample;
sw->vertical_subpasses = v_subpasses;
sw->oversample = osample * v_subpasses * v_subsample;
sw->firstline = first_line;
sw->lineno = first_line;
sw->flushfunc = flushfunc;
if (sw->oversample > jets)
{
stp_eprintf(v, "Weave error: oversample (%d) > jets (%d)\n",
sw->oversample, jets);
stp_free(sw);
return;
}
sw->head_offset = stp_zalloc(ncolors * sizeof(int));
if (ncolors > 1)
for(i = 0; i < ncolors; i++)
sw->head_offset[i] = head_offset[i];
maxHeadOffset = 0;
for (i = 0; i < ncolors; i++)
if (sw->head_offset[i] > maxHeadOffset)
maxHeadOffset = sw->head_offset[i];
sw->virtual_jets = sw->jets;
if (maxHeadOffset > 0)
sw->virtual_jets += (maxHeadOffset + sw->separation - 1) / sw->separation;
last_line = first_line + line_count - 1 + maxHeadOffset;
sw->weaveparm = initialize_weave_params(sw->separation, sw->jets,
sw->oversample, first_line, last_line,
page_height, weave_strategy, v);
sw->vmod = 2 * sw->separation * sw->oversample * sw->repeat_count;
if (sw->virtual_jets > sw->jets)
sw->vmod *= (sw->virtual_jets + sw->jets - 1) / sw->jets;
sw->bitwidth = bitwidth;
sw->last_pass_offset = 0;
sw->last_pass = -1;
sw->current_vertical_subpass = 0;
sw->ncolors = ncolors;
sw->linewidth = linewidth;
sw->vertical_height = line_count;
sw->lineoffsets = allocate_lineoff(sw->vmod, ncolors);
sw->lineactive = allocate_lineactive(sw->vmod, ncolors);
sw->linebases = allocate_linebuf(sw->vmod, ncolors);
sw->linebounds = allocate_linebounds(sw->vmod, ncolors);
sw->passes = stp_zalloc(sw->vmod * sizeof(stp_pass_t));
sw->linecounts = allocate_linecount(sw->vmod, ncolors);
sw->rcache = -2;
sw->vcache = -2;
sw->fillfunc = fillfunc;
sw->compute_linewidth = compute_linewidth;
sw->pack = pack;
sw->horizontal_width =
(sw->compute_linewidth)(v, ((sw->linewidth + sw->horizontal_weave - 1) /
sw->horizontal_weave));
sw->horizontal_width = ((sw->horizontal_width + 7) / 8);
for (i = 0; i < sw->vmod; i++)
{
int j;
sw->passes[i].pass = -1;
for (j = 0; j < sw->ncolors; j++)
{
sw->linebases[i].v[j] = NULL;
}
}
stp_allocate_component_data(v, "Weave", NULL, stpi_destroy_weave, sw);
return;
}
static void
weave_parameters_by_row(const stp_vars_t *v, const stpi_softweave_t *sw,
int row, int vertical_subpass, stp_weave_t *w)
{
int jetsused;
int sub_repeat_count = vertical_subpass % sw->repeat_count;
stpi_softweave_t *wsw = (stpi_softweave_t *) sw;
vertical_subpass /= sw->repeat_count;
if (sw->rcache == row && sw->vcache == vertical_subpass)
{
memcpy(w, &sw->wcache, sizeof(stp_weave_t));
w->pass = (w->pass * sw->repeat_count) + sub_repeat_count;
return;
}
wsw->rcache = row;
wsw->vcache = vertical_subpass;
w->row = row;
stpi_calculate_row_parameters(sw->weaveparm, row, vertical_subpass,
&w->pass, &w->jet, &w->logicalpassstart,
&w->missingstartrows, &jetsused);
w->physpassstart = w->logicalpassstart + sw->separation * w->missingstartrows;
w->physpassend = w->physpassstart + sw->separation * (jetsused - 1);
memcpy(&(((stpi_softweave_t *) wsw)->wcache), w, sizeof(stp_weave_t));
w->pass = (w->pass * sw->repeat_count) + sub_repeat_count;
stp_dprintf(STP_DBG_WEAVE_PARAMS, v, "row %d, jet %d of pass %d "
"(pos %d, start %d, end %d, missing rows %d)\n",
w->row, w->jet, w->pass, w->logicalpassstart, w->physpassstart,
w->physpassend, w->missingstartrows);
}
void
stp_weave_parameters_by_row(const stp_vars_t *v, int row,
int vertical_subpass, stp_weave_t *w)
{
const stpi_softweave_t *sw =
(stpi_softweave_t *) stp_get_component_data(v, "Weave");
weave_parameters_by_row(v, sw, row, vertical_subpass, w);
}
static stp_lineoff_t *
stpi_get_lineoffsets(const stp_vars_t *v, const stpi_softweave_t *sw,
int row, int subpass, int offset)
{
stp_weave_t w;
weave_parameters_by_row(v, sw, row + offset, subpass, &w);
return &(sw->lineoffsets[w.pass % sw->vmod]);
}
static stp_lineactive_t *
stpi_get_lineactive(const stp_vars_t *v, const stpi_softweave_t *sw,
int row, int subpass, int offset)
{
stp_weave_t w;
weave_parameters_by_row(v, sw, row + offset, subpass, &w);
return &(sw->lineactive[w.pass % sw->vmod]);
}
static stp_linecount_t *
stpi_get_linecount(const stp_vars_t *v, const stpi_softweave_t *sw,
int row, int subpass, int offset)
{
stp_weave_t w;
weave_parameters_by_row(v, sw, row + offset, subpass, &w);
return &(sw->linecounts[w.pass % sw->vmod]);
}
static stp_linebufs_t *
stpi_get_linebases(const stp_vars_t *v, const stpi_softweave_t *sw,
int row, int subpass, int offset)
{
stp_weave_t w;
weave_parameters_by_row(v, sw, row + offset, subpass, &w);
return &(sw->linebases[w.pass % sw->vmod]);
}
static stp_linebounds_t *
stpi_get_linebounds(const stp_vars_t *v, const stpi_softweave_t *sw,
int row, int subpass, int offset)
{
stp_weave_t w;
weave_parameters_by_row(v, sw, row + offset, subpass, &w);
return &(sw->linebounds[w.pass % sw->vmod]);
}
static stp_pass_t *
stpi_get_pass_by_row(stp_vars_t *v, const stpi_softweave_t *sw,
int row, int subpass,int offset)
{
stp_weave_t w;
weave_parameters_by_row(v, sw, row + offset, subpass, &w);
return &(sw->passes[w.pass % sw->vmod]);
}
stp_lineoff_t *
stp_get_lineoffsets_by_pass(const stp_vars_t *v, int pass)
{
const stpi_softweave_t *sw =
(stpi_softweave_t *) stp_get_component_data(v, "Weave");
return &(sw->lineoffsets[pass % sw->vmod]);
}
stp_lineactive_t *
stp_get_lineactive_by_pass(const stp_vars_t *v, int pass)
{
const stpi_softweave_t *sw =
(stpi_softweave_t *) stp_get_component_data(v, "Weave");
return &(sw->lineactive[pass % sw->vmod]);
}
stp_linecount_t *
stp_get_linecount_by_pass(const stp_vars_t *v, int pass)
{
const stpi_softweave_t *sw =
(stpi_softweave_t *) stp_get_component_data(v, "Weave");
return &(sw->linecounts[pass % sw->vmod]);
}
const stp_linebufs_t *
stp_get_linebases_by_pass(const stp_vars_t *v, int pass)
{
const stpi_softweave_t *sw =
(stpi_softweave_t *) stp_get_component_data(v, "Weave");
return &(sw->linebases[pass % sw->vmod]);
}
stp_pass_t *
stp_get_pass_by_pass(const stp_vars_t *v, int pass)
{
const stpi_softweave_t *sw =
(stpi_softweave_t *) stp_get_component_data(v, "Weave");
return &(sw->passes[pass % sw->vmod]);
}
static void
check_linebases(stp_vars_t *v, const stpi_softweave_t *sw,
int row, int cpass, int head_offset, int color)
{
stp_linebufs_t *bufs =
(stp_linebufs_t *) stpi_get_linebases(v, sw, row, cpass, head_offset);
if (!(bufs[0].v[color]))
bufs[0].v[color] =
stp_zalloc (sw->virtual_jets * sw->bitwidth * sw->horizontal_width);
}
void
stp_fill_tiff(stp_vars_t *v, int row, int subpass,
int width, int missingstartrows, int color)
{
stpi_softweave_t *sw =
(stpi_softweave_t *) stp_get_component_data(v, "Weave");
stp_lineoff_t *lineoffs;
stp_linecount_t *linecount;
const stp_linebufs_t *bufs;
int i = 0;
int k = 0;
width = sw->bitwidth * width * 8;
for (k = 0; k < missingstartrows; k++)
{
int bytes_to_fill = width;
int full_blocks = bytes_to_fill / (128 * 8);
int leftover = (7 + (bytes_to_fill % (128 * 8))) / 8;
int l = 0;
bufs = stpi_get_linebases(v, sw, row, subpass, sw->head_offset[color]);
while (l < full_blocks)
{
(bufs[0].v[color][2 * i]) = 129;
(bufs[0].v[color][2 * i + 1]) = 0;
i++;
l++;
}
if (leftover == 1)
{
(bufs[0].v[color][2 * i]) = 1;
(bufs[0].v[color][2 * i + 1]) = 0;
i++;
}
else if (leftover > 0)
{
(bufs[0].v[color][2 * i]) = 257 - leftover;
(bufs[0].v[color][2 * i + 1]) = 0;
i++;
}
}
lineoffs = stpi_get_lineoffsets(v, sw, row, subpass, sw->head_offset[color]);
linecount = stpi_get_linecount(v, sw, row, subpass, sw->head_offset[color]);
lineoffs[0].v[color] = 2 * i;
linecount[0].v[color] = missingstartrows;
}
void
stp_fill_uncompressed(stp_vars_t *v, int row, int subpass,
int width, int missingstartrows, int color)
{
stpi_softweave_t *sw =
(stpi_softweave_t *) stp_get_component_data(v, "Weave");
stp_lineoff_t *lineoffs;
stp_linecount_t *linecount;
const stp_linebufs_t *bufs;
bufs = stpi_get_linebases(v, sw, row, subpass, sw->head_offset[color]);
lineoffs = stpi_get_lineoffsets(v, sw, row, subpass, sw->head_offset[color]);
linecount = stpi_get_linecount(v, sw, row, subpass, sw->head_offset[color]);
width *= sw->bitwidth * missingstartrows;
memset(bufs[0].v[color], 0, width);
lineoffs[0].v[color] = width;
linecount[0].v[color] = missingstartrows;
}
int
stp_compute_tiff_linewidth(stp_vars_t *v, int n)
{
return ((n + 128 + 7) * 129 / 128);
}
int
stp_compute_uncompressed_linewidth(stp_vars_t *v, int n)
{
return (8 * ((n + 7) / 8));
}
static void
initialize_row(stp_vars_t *v, stpi_softweave_t *sw,
int row, int width, unsigned char *const cols[])
{
stp_weave_t w;
int i, j, jj;
stp_pass_t *pass;
for (i = 0; i < sw->oversample; i++)
{
for (j = 0; j < sw->ncolors; j++)
{
if (cols[j])
{
stp_lineoff_t *lineoffs =
stpi_get_lineoffsets(v, sw, row, i, sw->head_offset[j]);
stp_lineactive_t *lineactive =
stpi_get_lineactive(v, sw, row, i, sw->head_offset[j]);
stp_linecount_t *linecount =
stpi_get_linecount(v, sw, row, i, sw->head_offset[j]);
stp_linebounds_t *linebounds =
stpi_get_linebounds(v, sw, row, i, sw->head_offset[j]);
check_linebases(v, sw, row, i, sw->head_offset[j], j);
weave_parameters_by_row(v, sw, row+sw->head_offset[j], i, &w);
pass = stpi_get_pass_by_row(v, sw, row, i, sw->head_offset[j]);
if (pass->pass < 0)
{
pass->pass = w.pass;
pass->missingstartrows = w.missingstartrows;
pass->logicalpassstart = w.logicalpassstart;
pass->physpassstart = w.physpassstart;
pass->physpassend = w.physpassend;
pass->subpass = i;
for(jj=0; jj<sw->ncolors; jj++)
{
if (lineoffs[0].v[jj] != 0)
stp_eprintf(v, "WARNING: pass %d subpass %d row %d: "
"lineoffs %ld should be zero!\n",
w.pass, i, row, lineoffs[0].v[jj]);
lineoffs[0].v[jj] = 0;
lineactive[0].v[jj] = 0;
if (linecount[0].v[jj] != 0)
stp_eprintf(v, "WARNING: pass %d subpass %d row %d: "
"linecount %d should be zero!\n",
w.pass, i, row, linecount[0].v[jj]);
linecount[0].v[jj] = 0;
linebounds[0].start_pos[jj] = INT_MAX;
linebounds[0].end_pos[jj] = -1;
}
}
if((linecount[0].v[j] == 0) && (w.jet > 0))
{
(sw->fillfunc)(v, row, i, width, w.jet, j);
}
}
}
}
}
static void
add_to_row(stp_vars_t *v, stpi_softweave_t *sw, int row, unsigned char *buf,
size_t nbytes, int color, int setactive, int h_pass)
{
const stp_linebufs_t *bufs =
stpi_get_linebases(v, sw, sw->lineno, h_pass, sw->head_offset[color]);
stp_lineoff_t *lineoffs =
stpi_get_lineoffsets(v, sw, sw->lineno, h_pass, sw->head_offset[color]);
stp_lineactive_t *lineactive =
stpi_get_lineactive(v, sw, sw->lineno, h_pass, sw->head_offset[color]);
stp_linecount_t *linecount =
stpi_get_linecount(v, sw, sw->lineno, h_pass, sw->head_offset[color]);
size_t place = lineoffs[0].v[color];
size_t count = linecount[0].v[color];
if (place + nbytes > sw->virtual_jets * sw->bitwidth * sw->horizontal_width)
{
stp_eprintf(v, "Buffer overflow: limit %d, actual %d, count %d\n",
sw->virtual_jets * sw->bitwidth * sw->horizontal_width,
place + nbytes, count);
stp_abort();
}
memcpy(bufs[0].v[color] + lineoffs[0].v[color], buf, nbytes);
lineoffs[0].v[color] += nbytes;
if (setactive)
lineactive[0].v[color] = 1;
}
static void
stpi_flush_passes(stp_vars_t *v, int flushall)
{
stpi_softweave_t *sw =
(stpi_softweave_t *) stp_get_component_data(v, "Weave");
while (1)
{
stp_pass_t *pass = stp_get_pass_by_pass(v, sw->last_pass + 1);
if (pass->pass < 0 || (!flushall && pass->physpassend >= sw->lineno))
return;
(sw->flushfunc)(v, pass->pass, pass->subpass);
sw->last_pass = pass->pass;
pass->pass = -1;
}
}
void
stp_flush_all(stp_vars_t *v)
{
stpi_flush_passes(v, 1);
}
static void
finalize_row(stp_vars_t *v, int row)
{
stpi_softweave_t *sw =
(stpi_softweave_t *) stp_get_component_data(v, "Weave");
int i,j;
stp_dprintf(STP_DBG_ROWS, v, "Finalizing row %d...\n", row);
for (i = 0; i < sw->oversample; i++)
{
stp_weave_t w;
stp_linecount_t *lines;
for(j=0; j<sw->ncolors; j++)
{
lines = stpi_get_linecount(v, sw, row, i, sw->head_offset[j]);
lines[0].v[j]++;
}
weave_parameters_by_row(v, sw, row, i, &w);
if (w.physpassend == row)
{
stp_dprintf(STP_DBG_ROWS, v,
"Pass=%d, physpassend=%d, row=%d, lineno=%d, flush..\n",
w.pass, w.physpassend, row, sw->lineno);
stpi_flush_passes(v, 0);
}
}
}
void
stp_write_weave(stp_vars_t *v, unsigned char *const cols[])
{
stpi_softweave_t *sw =
(stpi_softweave_t *) stp_get_component_data(v, "Weave");
int length = (sw->linewidth + 7) / 8;
stp_lineoff_t *lineoffs[STP_MAX_WEAVE];
stp_lineactive_t *lineactives[STP_MAX_WEAVE];
stp_linecount_t *linecounts[STP_MAX_WEAVE];
stp_linebounds_t *linebounds[STP_MAX_WEAVE];
const stp_linebufs_t *bufs[STP_MAX_WEAVE];
int xlength = (length + sw->horizontal_weave - 1) / sw->horizontal_weave;
int ylength = xlength * sw->horizontal_weave;
unsigned char *comp_ptr;
int i, j;
int setactive;
int h_passes = sw->horizontal_weave * sw->vertical_subpasses;
int cpass = sw->current_vertical_subpass * h_passes;
if (!sw->fold_buf)
sw->fold_buf = stp_zalloc(sw->bitwidth * ylength);
if (!sw->comp_buf)
sw->comp_buf = stp_zalloc(sw->bitwidth *
(sw->compute_linewidth)(v,ylength));
if (sw->current_vertical_subpass == 0)
initialize_row(v, sw, sw->lineno, xlength, cols);
for (j = 0; j < sw->ncolors; j++)
{
if (cols[j])
{
const unsigned char *in;
int idx;
for (i = 0; i < h_passes; i++)
{
int offset = sw->head_offset[j];
int pass = cpass + i;
if (!sw->s[i])
sw->s[i] = stp_zalloc(sw->bitwidth *
(sw->compute_linewidth)(v, ylength));
lineoffs[i] =
stpi_get_lineoffsets(v, sw, sw->lineno, pass, offset);
linecounts[i] =
stpi_get_linecount(v, sw, sw->lineno, pass, offset);
lineactives[i] =
stpi_get_lineactive(v, sw, sw->lineno, pass,offset);
linebounds[i] =
stpi_get_linebounds(v, sw, sw->lineno, pass, offset);
bufs[i] =
stpi_get_linebases(v, sw, sw->lineno, pass, offset);
}
if (sw->bitwidth == 2)
{
stp_fold(cols[j], length, sw->fold_buf);
in = sw->fold_buf;
}
else
in = cols[j];
switch (sw->horizontal_weave)
{
case 1:
memcpy(sw->s[0], in, length * sw->bitwidth);
break;
case 2:
stp_unpack_2(length, sw->bitwidth, in, sw->s[0], sw->s[1]);
break;
case 4:
stp_unpack_4(length, sw->bitwidth, in,
sw->s[0], sw->s[1], sw->s[2], sw->s[3]);
break;
case 8:
stp_unpack_8(length, sw->bitwidth, in,
sw->s[0], sw->s[1], sw->s[2], sw->s[3],
sw->s[4], sw->s[5], sw->s[6], sw->s[7]);
break;
}
switch (sw->vertical_subpasses)
{
case 4:
for (idx = 0; idx < sw->horizontal_weave; idx++)
stp_split_4(length, sw->bitwidth, sw->s[idx], sw->s[idx],
sw->s[idx + sw->horizontal_weave],
sw->s[idx + sw->horizontal_weave * 2],
sw->s[idx + sw->horizontal_weave * 3]);
break;
case 2:
for (idx = 0; idx < sw->horizontal_weave; idx++)
stp_split_2(length, sw->bitwidth, sw->s[idx], sw->s[idx],
sw->s[idx + sw->horizontal_weave]);
break;
}
for (i = 0; i < h_passes; i++)
{
int first, last;
setactive = (sw->pack)(v, sw->s[i], sw->bitwidth * xlength,
sw->comp_buf, &comp_ptr, &first, &last);
if (first < linebounds[i]->start_pos[j])
linebounds[i]->start_pos[j] = first;
if (last > linebounds[i]->end_pos[j])
linebounds[i]->end_pos[j] = last;
add_to_row(v, sw, sw->lineno, sw->comp_buf,
comp_ptr - sw->comp_buf, j, setactive, cpass + i);
}
}
}
sw->current_vertical_subpass++;
if (sw->current_vertical_subpass >= sw->vertical_oversample)
{
finalize_row(v, sw->lineno);
sw->lineno++;
sw->current_vertical_subpass = 0;
}
}
#if 0
#define TEST_RAW
#endif
#if 0
#define TEST_COOKED
#endif
#if 0
#define ACCUMULATE
#endif
#if defined(TEST_RAW) || defined(TEST_COOKED)
#define TEST
#endif
#ifdef TEST
#define MAXCOLLECT (1000)
#endif
#ifdef TEST_COOKED
static void
calculate_pass_parameters(cooked_t *w,
int pass,
int *startrow,
int *subpass,
int *phantomrows,
int *jetsused)
{
int raw_pass = pass + w->first_premapped_pass;
int stagger = 0;
int extra;
if (raw_pass < w->first_normal_pass) {
int i = 0;
while (i + w->first_premapped_pass < w->first_normal_pass) {
if (w->pass_premap[i] == pass) {
raw_pass = i + w->first_premapped_pass;
stagger = w->stagger_premap[i];
break;
}
i++;
}
} else if (raw_pass >= w->first_postmapped_pass) {
int i = 0;
while (i + w->first_postmapped_pass < w->first_unused_pass) {
if (w->pass_postmap[i] == pass) {
raw_pass = i + w->first_postmapped_pass;
stagger = w->stagger_postmap[i];
break;
}
i++;
}
}
calculate_raw_pass_parameters(&w->rw, raw_pass, startrow, subpass);
*startrow -= w->rw.separation * w->rw.jets;
*jetsused = w->rw.jets;
*phantomrows = 0;
*startrow += stagger * w->rw.separation;
if (stagger < 0) {
stagger = -stagger;
*phantomrows += stagger;
}
*jetsused -= stagger;
extra = w->first_row_printed - (*startrow + w->rw.separation * *phantomrows);
extra = (extra + w->rw.separation - 1) / w->rw.separation;
if (extra > 0) {
*jetsused -= extra;
*phantomrows += extra;
}
extra = *startrow + w->rw.separation * (*phantomrows + *jetsused - 1)
- w->last_row_printed;
extra = (extra + w->rw.separation - 1) / w->rw.separation;
if (extra > 0) {
*jetsused -= extra;
}
}
#endif
#ifdef TEST
#ifdef ACCUMULATE
#define PUTCHAR(x)
#else
#define PUTCHAR(x) putchar(x)
#endif
static void
plotpass(int startrow, int phantomjets, int jetsused, int totaljets,
int separation, int subpass, int *collect, int *prints)
{
int hpos, i;
for (hpos = 0; hpos < startrow; hpos++)
PUTCHAR(' ');
for (i = 0; i < phantomjets; i++) {
int j;
PUTCHAR('X');
hpos++;
for (j = 1; j < separation; j++) {
PUTCHAR(' ');
hpos++;
}
}
for (; i < phantomjets + jetsused; i++) {
if (i > phantomjets) {
int j;
for (j = 1; j < separation; j++) {
PUTCHAR('-');
hpos++;
}
}
if (hpos < MAXCOLLECT) {
if (collect[hpos] & 1 << subpass)
PUTCHAR('^');
else if (subpass < 10)
PUTCHAR('0' + subpass);
else
PUTCHAR('A' + subpass - 10);
collect[hpos] |= 1 << subpass;
prints[hpos]++;
} else {
PUTCHAR('0' + subpass);
}
hpos++;
}
while (i++ < totaljets) {
int j;
for (j = 1; j < separation; j++) {
PUTCHAR(' ');
hpos++;
}
PUTCHAR('X');
}
#ifdef ACCUMULATE
for (i=0; i<=MAXCOLLECT; i++) {
if (collect[i] == 0)
putchar(' ');
else if (collect[i] < 10)
putchar('0'+collect[i]);
else
putchar('A'+collect[i]-10);
}
#endif
putchar('\n');
}
#endif
#ifdef TEST_COOKED
int
main(int ac, char *av[])
{
int S =ac>1 ? atoi(av[1]) : 4;
int J =ac>2 ? atoi(av[2]) : 12;
int H =ac>3 ? atoi(av[3]) : 1;
int firstrow =ac>4 ? atoi(av[4]) : 1;
int lastrow =ac>5 ? atoi(av[5]) : 100;
int pageheight=ac>6 ? atoi(av[6]) : 1000;
stp_weave_strategy_t strategy =ac>7 ? atoi(av[7]) : 1;
cooked_t *weave;
int passes;
int pass, x;
int collect[MAXCOLLECT];
int prints[MAXCOLLECT];
memset(collect, 0, MAXCOLLECT*sizeof(int));
memset(prints, 0, MAXCOLLECT*sizeof(int));
printf("S=%d J=%d H=%d firstrow=%d lastrow=%d "
"pageheight=%d strategy=%d\n",
S, J, H, firstrow, lastrow, pageheight, strategy);
weave = initialize_weave_params(S, J, H, firstrow, lastrow,
pageheight, strategy);
passes = weave->first_unused_pass - weave->first_premapped_pass;
for (pass = 0; pass < passes; pass++) {
int startrow, subpass, phantomjets, jetsused;
calculate_pass_parameters(weave, pass, &startrow, &subpass,
&phantomjets, &jetsused);
plotpass(startrow, phantomjets, jetsused, J, S, subpass,
collect, prints);
}
for (pass=MAXCOLLECT - 1; prints[pass] == 0; pass--)
;
for (x=0; x<=pass; x++) {
if (collect[x] < 10)
putchar('0'+collect[x]);
else
putchar('A'+collect[x]-10);
}
putchar('\n');
for (x=0; x<=pass; x++) {
if (prints[x] < 10)
putchar('0'+prints[x]);
else
putchar('A'+prints[x]-10);
}
putchar('\n');
return 0;
}
#endif
#ifdef TEST_RAW
int
main(int ac, char *av[])
{
int S =ac>1 ? atoi(av[1]) : 4;
int J =ac>2 ? atoi(av[2]) : 12;
int h_pos =ac>3 ? atoi(av[3]) : 1;
int h_over=ac>4 ? atoi(av[4]) : 1;
int v_over=ac>5 ? atoi(av[5]) : 1;
int H = h_pos * h_over * v_over;
int pass, passes, x;
int collect[MAXCOLLECT];
int prints[MAXCOLLECT];
raw_t raw;
memset(collect, 0, MAXCOLLECT*sizeof(int));
memset(prints, 0, MAXCOLLECT*sizeof(int));
printf("S=%d J=%d H=%d\n", S, J, H);
if (H > J) {
printf("H > J, so this weave will not work!\n");
}
passes = S * H * 3;
initialize_raw_weave(&raw, S, J, H);
for (pass=0; pass<passes + S * H; pass++) {
int startrow, subpass, phantomjets, jetsused;
calculate_raw_pass_parameters(&raw, pass, &startrow, &subpass);
phantomjets = 0;
jetsused = J;
plotpass(startrow, phantomjets, jetsused, J, S, subpass,
collect, prints);
}
for (pass=MAXCOLLECT - 1; prints[pass] == 0; pass--)
;
for (x=0; x<=pass; x++) {
if (collect[x] < 10)
putchar('0'+collect[x]);
else
putchar('A'+collect[x]-10);
}
putchar('\n');
for (x=0; x<=pass; x++) {
if (prints[x] < 10)
putchar('0'+prints[x]);
else
putchar('A'+prints[x]-10);
}
putchar('\n');
printf(" A first row given by pass lookup doesn't match row lookup\n"
" B jet out of range\n"
" C given jet number of pass doesn't print this row\n"
" D subpass given by reverse lookup doesn't match requested subpass\n");
for (x = S * J; x < S * J * 20; x++) {
int h;
for (h = 0; h < H; h++) {
int pass, jet, start, first, subpass, z;
int a=0, b=0, c=0, d=0;
calculate_raw_row_parameters(&raw, x, h, &pass, &jet, &start);
for (z=0; z < pass; z++) {
putchar(' ');
}
printf("%d", jet);
calculate_raw_pass_parameters(&raw, pass, &first, &subpass);
if (first != start)
a=1;
if (jet < 0 || jet >= J)
b=1;
if (x != first + jet * S)
c=1;
if (subpass != h)
d=1;
if (a || b || c || d) {
printf(" (");
if (a) putchar('A');
if (b) putchar('B');
if (c) putchar('C');
if (d) putchar('D');
putchar(')');
printf("\npass=%d first=%d start=%d jet=%d subpass=%d", pass, first, start, jet, subpass);
}
putchar('\n');
}
}
return 0;
}
#endif