ImagerPixelImpl.mesa
Copyright Ó 1986, 1987, 1989, 1991 by Xerox Corporation. All rights reserved.
Doug Wyatt, March 6, 1986 4:09:53 pm PST
Michael Plass, July 15, 1992 10:04 am PDT
Russ Atkinson (RRA) December 18, 1990 12:08 pm PST
DIRECTORY
Basics,
ImagerPixel USING [PixelBuffer, PixelBufferRep, PixelMap, PixelMapRep, PixelProc, ResampleAction],
ImagerSample USING [BitsPerSample, Function, Get, GetSamples, CopySamples, maxCount, NewSampleMap, NewSamples, GetBox, MultipleReleaseOfScratch, nullFunction, PutSamples, RasterSampleMap, Sample, SampleBuffer, SampleBufferRep, SampleMap, zeroVec],
ImagerTransformation USING [InverseTransform, InverseTransformVec, Singular, Transformation],
RealInline,
SF USING [Box, BoxAction, BoxGenerator, SizeF, Vec];
ImagerPixelImpl: CEDAR MONITOR
IMPORTS Basics, ImagerSample, ImagerTransformation, RealInline, SF
EXPORTS ImagerPixel
SHARES ImagerSample
~ BEGIN OPEN ImagerPixel;
bitsPerUnit: NAT ~ BITS[UNIT];
bitsPerWord: NAT ~ BITS[WORD];
RawSamples: TYPE ~ Basics.RawWords;
RawSamplesPtr: TYPE ~ LONG POINTER TO Basics.RawWords;
Transformation: TYPE ~ ImagerTransformation.Transformation;
InlinePointerToSamples: PROC [samples: ImagerSample.SampleBuffer, start: NAT, count: NAT]
RETURNS
[LONG POINTER TO RawSamples] ~ TRUSTED INLINE {
check: NAT ~ NAT[samples.maxLength-start]-count;
RETURN[LOOPHOLE[samples, LONG POINTER]+SIZE[ImagerSample.SampleBufferRep[start]]];
};
NewPixels: PUBLIC PROC [samplesPerPixel: NAT, length: NAT, scratch: PixelBuffer ¬ NIL] RETURNS [PixelBuffer] ~ {
new: PixelBuffer ¬ scratch;
IF new=NIL OR new.samplesPerPixel#samplesPerPixel THEN
new ¬ NEW[PixelBufferRep[samplesPerPixel]];
FOR i: NAT IN [0..samplesPerPixel) DO
new[i] ¬ ImagerSample.NewSamples[length: length];
ENDLOOP;
new.length ¬ length;
RETURN[new];
};
nScratchPixelBuffers: NAT ~ 12;
scratchPixelBuffers: ARRAY [0..nScratchPixelBuffers) OF PixelBuffer ¬ ALL[NIL];
ObtainScratchPixels: PUBLIC ENTRY PROC [samplesPerPixel: NAT, length: NAT] RETURNS [PixelBuffer] ~ {
FOR i: NAT IN [0..nScratchPixelBuffers) DO
buf: PixelBuffer ~ scratchPixelBuffers[i];
IF buf # NIL AND buf.samplesPerPixel = samplesPerPixel AND buf.length >= length THEN {
scratchPixelBuffers[i] ¬ NIL;
buf.length ¬ length;
FOR j: NAT IN [0..samplesPerPixel) DO
buf[j].length ¬ length;
ENDLOOP;
RETURN [buf];
};
ENDLOOP;
RETURN[NewPixels[samplesPerPixel: samplesPerPixel, length: length]]
};
ReleaseScratchPixels: PUBLIC ENTRY PROC [pixels: PixelBuffer] ~ {
slot: NAT ¬ 0;
IF pixels.samplesPerPixel = 0 THEN RETURN; -- Joker
FOR j: NAT IN [1..pixels.samplesPerPixel) DO
IF pixels[j].maxLength # pixels[0].maxLength THEN RETURN
ENDLOOP;
FOR i: NAT IN [0..nScratchPixelBuffers) DO
t: PixelBuffer ¬ scratchPixelBuffers[i];
IF t = NIL THEN slot ¬ i
ELSE IF pixels = t THEN RETURN WITH ERROR ImagerSample.MultipleReleaseOfScratch;
ENDLOOP;
pixels.length ¬ pixels[0].maxLength;
scratchPixelBuffers[slot] ¬ pixels;
};
DoWithScratchPixels: PUBLIC PROC [samplesPerPixel: NAT, length: NAT,
action: PROC [PixelBuffer]] ~ {
scratch: PixelBuffer ~ ObtainScratchPixels[samplesPerPixel: samplesPerPixel, length: length];
action[scratch ! UNWIND => ReleaseScratchPixels[scratch]];
ReleaseScratchPixels[scratch];
};
NewPixelMap: PUBLIC PROC [samplesPerPixel: NAT, box: SF.Box, maxSample: PixelProc] RETURNS [PixelMap] ~ {
new: PixelMap ¬ NEW[PixelMapRep[samplesPerPixel]];
FOR i: NAT IN [0..samplesPerPixel) DO
bitsPerSample: ImagerSample.BitsPerSample ~ SELECT maxSample[i] FROM
<2 => 1, <4 => 2, <16 => 4, <256 => 8, <=65535 => 16, ENDCASE => ImagerSample.BitsPerSample.LAST;
new[i] ¬ ImagerSample.NewSampleMap[box: box, bitsPerSample: bitsPerSample];
ENDLOOP;
new.box ¬ box;
RETURN[new];
};
MakePixelMap: PUBLIC PROC [s0, s1, s2, s3, s4: ImagerSample.SampleMap ¬ NIL] RETURNS [PixelMap] ~ {
s: ARRAY [0..5) OF ImagerSample.SampleMap ~ [s0, s1, s2, s3, s4];
Count: PROC RETURNS [i: NAT ¬ 0]
~ INLINE {WHILE i < 5 AND s[i] # NIL DO i ¬ i + 1 ENDLOOP};
n: NAT ~ Count[];
new: PixelMap ~ NEW[PixelMapRep[n]];
new.box ¬ IF n = 0 THEN [ImagerSample.zeroVec, ImagerSample.zeroVec] ELSE ImagerSample.GetBox[s[0]];
FOR i: NAT IN [0..n) DO
assert: BOOL[TRUE..TRUE] ~ ImagerSample.GetBox[s[i]] = new.box;
new[i] ¬ s[i];
ENDLOOP;
FOR i: NAT IN [n..5) DO
assert: BOOL[TRUE..TRUE] ~ s[i] = NIL;
ENDLOOP;
RETURN [new]
};
GetPixels: PUBLIC PROC [self: PixelMap, initIndex: SF.Vec ¬ ImagerSample.zeroVec, delta: SF.Vec ¬ [s: 0, f: 1],
pixels: PixelBuffer, start: NAT ¬ 0, count: NAT ¬ ImagerSample.maxCount] ~ {
FOR i: NAT IN [0..self.samplesPerPixel) DO
ImagerSample.GetSamples[self[i], initIndex, delta, pixels[i], start, count];
ENDLOOP;
};
PutPixels: PUBLIC PROC [self: PixelMap, initIndex: SF.Vec ¬ ImagerSample.zeroVec, delta: SF.Vec ¬ [s: 0, f: 1],
pixels: PixelBuffer, start: NAT ¬ 0, count: NAT ¬ ImagerSample.maxCount,
function: ImagerSample.Function ¬ ImagerSample.nullFunction] ~ {
FOR i: NAT IN [0..self.samplesPerPixel) DO
ImagerSample.PutSamples[self[i], initIndex, delta, pixels[i], start, count, function];
ENDLOOP;
};
realLastInt: REAL ¬ REAL[LAST[INT]];
ScaledFromRealMod: PROC [d: REAL, m: CARDINAL[0..32768]] RETURNS [INT] ~ {
s: Basics.LongNumber ¬ [li[0]];
IF m # 0 THEN {
modulus: REAL ~ m;
This funny way of rounding is intended to round such that the image gets ever so slightly enlarged; plain rounding can cause an image to be slightly too small, causing unwanted wraparound at the edges.
SELECT d FROM
IN [0..modulus) => s.li ¬ RealInline.MCFix[ d * 65536.0 ];
IN (-modulus..0) => s.li ¬ (m*65536) - RealInline.MCFix[ -d * 65536.0 ];
ENDCASE => s.li ¬ RealInline.MCRound[ (d-modulus*RealInline.MCFloor[d/modulus]) * 65536.0 ];
Now some paranoia about floating-point fuzz
IF s.li < 0 THEN {s.hi ¬ s.hi + m};
IF s.hi >= m THEN {s.hi ¬ s.hi - m};
IF s.hi >= m THEN ERROR;
};
RETURN [s.li];
};
Sample1: TYPE ~ ImagerSample.Sample[0..1B];
Sample8: TYPE ~ ImagerSample.Sample[0..377B];
Sample16: TYPE ~ ImagerSample.Sample[0..177777B];
RawSamples1: TYPE ~ RECORD [PACKED SEQUENCE COMPUTED CARDINAL OF Sample1];
RawSamples8: TYPE ~ RECORD [PACKED SEQUENCE COMPUTED CARDINAL OF Sample8];
RawSamples16: TYPE ~ RECORD [PACKED SEQUENCE COMPUTED CARDINAL OF Sample16];
Pointer1: TYPE ~ LONG POINTER TO RawSamples1;
Pointer8: TYPE ~ LONG POINTER TO RawSamples8;
Pointer16: TYPE ~ LONG POINTER TO RawSamples16;
Resample1: PROC [dest, source: PixelMap, m: Transformation, interpolate: BOOL] ~ {
This is here for testing and as an example of how to call Resample
boxes: SF.BoxGenerator ~ {boxAction[dest.box]};
action: ResampleAction ~ {
FOR j: NAT IN [0..pixels.samplesPerPixel) DO
ImagerSample.PutSamples[map: dest[j], buffer: pixels[j], initIndex: min];
ENDLOOP;
};
Resample[self: source, m: m, interpolate: interpolate, boxes: boxes, bounds: dest.box, action: action];
};
Resample: PUBLIC PROC [self: PixelMap, m: Transformation, interpolate: BOOL, boxes: SF.BoxGenerator, bounds: SF.Box, action: ResampleAction] ~ {
IF NOT ImagerTransformation.Singular[m] THEN {
samplesPerPixel: NAT ~ self.samplesPerPixel;
sSize: NAT15 ~ self.box.max.s-self.box.min.s; -- source size in slow (scan line) direction
fSize: NAT15 ~ self.box.max.f-self.box.min.f; -- source size in fast (pixel) direction
ssDelta: Basics.LongNumber; -- source delta s for destination s increment
fsDelta: Basics.LongNumber; -- source delta f for destination s increment
sfDelta: Basics.LongNumber; -- source delta s for destination f increment
ffDelta: Basics.LongNumber; -- source delta f for destination f increment
d0: SF.Vec ¬ bounds.min; -- initial destination position
s0: Basics.LongNumber; -- initial source s (corresponding to d0)
f0: Basics.LongNumber; -- initial source f (corresponding to d0)
pixels: PixelBuffer ~ ObtainScratchPixels[samplesPerPixel, SF.SizeF[bounds]];
rs, rf: REAL ¬ 0.0;
boxActionPointSamples: SF.BoxAction ~ {
count: NAT ~ SF.SizeF[box];
smax: Basics.LongNumber ~ [pair[hi: sSize, lo: 0]];
fmax: Basics.LongNumber ~ [pair[hi: fSize, lo: 0]];
ssup: Basics.LongNumber ~ ssDelta;
fsup: Basics.LongNumber ~ fsDelta;
ssdn: Basics.LongNumber ~ [lc[smax.lc-ssup.lc]];
fsdn: Basics.LongNumber ~ [lc[fmax.lc-fsup.lc]];
sfup: Basics.LongNumber ~ sfDelta;
ffup: Basics.LongNumber ~ ffDelta;
sfdn: Basics.LongNumber ~ [lc[smax.lc-sfup.lc]];
ffdn: Basics.LongNumber ~ [lc[fmax.lc-ffup.lc]];
d1s, d1f: INTEGER; -- destination position at start of scan line
s1: Basics.LongNumber ¬ s0; -- source s corresponding to [d1s, d1f]
f1: Basics.LongNumber ¬ f0; -- source f corresponding to [d1s, d1f]
[d1s, d1f] ¬ d0;
WHILE d1s<box.min.s DO
d1s ¬ d1s+1;
IF s1.lc<ssdn.lc THEN s1.lc ¬ s1.lc+ssup.lc ELSE s1.lc ¬ s1.lc-ssdn.lc;
IF f1.lc<fsdn.lc THEN f1.lc ¬ f1.lc+fsup.lc ELSE f1.lc ¬ f1.lc-fsdn.lc;
ENDLOOP;
WHILE d1s>box.min.s DO
d1s ¬ d1s-1;
IF s1.lc>=ssup.lc THEN s1.lc ¬ s1.lc-ssup.lc ELSE s1.lc ¬ s1.lc+ssdn.lc;
IF f1.lc>=fsup.lc THEN f1.lc ¬ f1.lc-fsup.lc ELSE f1.lc ¬ f1.lc+fsdn.lc;
ENDLOOP;
d0 ¬ [d1s, d1f];
s0.lc ¬ s1.lc;
f0.lc ¬ f1.lc;
WHILE d1f<box.min.f DO
d1f ¬ d1f+1;
IF s1.lc<sfdn.lc THEN s1.lc ¬ s1.lc+sfup.lc ELSE s1.lc ¬ s1.lc-sfdn.lc;
IF f1.lc<ffdn.lc THEN f1.lc ¬ f1.lc+ffup.lc ELSE f1.lc ¬ f1.lc-ffdn.lc;
ENDLOOP;
WHILE d1f>box.min.f DO
d1f ¬ d1f-1;
IF s1.lc>=sfup.lc THEN s1.lc ¬ s1.lc-sfup.lc ELSE s1.lc ¬ s1.lc+sfdn.lc;
IF f1.lc>=ffup.lc THEN f1.lc ¬ f1.lc-ffup.lc ELSE f1.lc ¬ f1.lc+ffdn.lc;
ENDLOOP;
pixels.length ¬ count;
DO --For each scan line of box--
FOR i: NAT IN [0..samplesPerPixel) DO
map: ImagerSample.SampleMap ~ self[i];
rasterMap: ImagerSample.RasterSampleMap ~ WITH map SELECT FROM r: ImagerSample.RasterSampleMap => r ENDCASE => NIL;
easyLineCalc: BOOL ~ rasterMap # NIL AND rasterMap.base.bit=0 AND (rasterMap.bitsPerLine MOD bitsPerWord)=0;
samples: ImagerSample.SampleBuffer ~ pixels[i];
s: Basics.LongNumber ¬ s1;
f: Basics.LongNumber ¬ f1;
SELECT TRUE FROM
sfDelta.li = 0 AND ffDelta = [pair[hi: 1, lo: 0]] => {
count1: NAT ~ MIN [count, fSize-f.hi];
count2: NAT ~ MIN [count-count1, f.hi];
count3: NAT ~ count-count1-count2;
ImagerSample.GetSamples[map: map, initIndex: [s: s.hi+self.box.min.s, f: f.hi+self.box.min.f], buffer: samples, start: 0, count: count1];
IF count2 # 0 THEN
ImagerSample.GetSamples[map: map, initIndex: [s: s.hi+self.box.min.s, f: self.box.min.f], buffer: samples, start: count1, count: count2];
IF count3 # 0 THEN
ImagerSample.CopySamples[dst: samples, src: samples, dstStart: count1+count2, srcStart: 0, count: count3];
};
easyLineCalc AND rasterMap.bitsPerSample=1 => {
base: Pointer1 ~ LOOPHOLE[rasterMap.base.word];
upl: NAT ~ rasterMap.bitsPerLine/bitsPerUnit;
result: RawSamplesPtr ~ InlinePointerToSamples[samples, 0, count];
lastSHi: CARDINAL ¬ s.hi;
line: Pointer1 ¬ base+lastSHi*upl;
FOR k: NAT IN [0..count) DO
IF lastSHi # s.hi THEN {lastSHi ¬ s.hi; line ¬ base+lastSHi*upl};
TRUSTED { result[k] ¬ line[f.hi] };
IF s.lc<sfdn.lc THEN s.lc ¬ s.lc+sfup.lc ELSE s.lc ¬ s.lc-sfdn.lc;
IF f.lc<ffdn.lc THEN f.lc ¬ f.lc+ffup.lc ELSE f.lc ¬ f.lc-ffdn.lc;
ENDLOOP;
};
easyLineCalc AND rasterMap.bitsPerSample=8 => {
base: Pointer8 ~ LOOPHOLE[rasterMap.base.word];
upl: NAT ~ rasterMap.bitsPerLine/bitsPerUnit;
result: RawSamplesPtr ~ InlinePointerToSamples[samples, 0, count];
IF sfup.lc=0
THEN {
line: Pointer8 ~ base+LONG[s.hi]*upl;
FOR k: NAT IN [0..count) DO
TRUSTED { result[k] ¬ line[f.hi] };
IF f.lc<ffdn.lc THEN f.lc ¬ f.lc+ffup.lc ELSE f.lc ¬ f.lc-ffdn.lc;
ENDLOOP;
}
ELSE {
lastSHi: CARDINAL ¬ s.hi;
line: Pointer8 ¬ base+LONG[lastSHi]*upl;
FOR k: NAT IN [0..count) DO
IF lastSHi # s.hi THEN {lastSHi ¬ s.hi; line ¬ base+lastSHi*upl};
TRUSTED { result[k] ¬ line[f.hi] };
IF s.lc<sfdn.lc THEN s.lc ¬ s.lc+sfup.lc ELSE s.lc ¬ s.lc-sfdn.lc;
IF f.lc<ffdn.lc THEN f.lc ¬ f.lc+ffup.lc ELSE f.lc ¬ f.lc-ffdn.lc;
ENDLOOP;
};
};
easyLineCalc AND rasterMap.bitsPerSample=16 => {
base: Pointer16 ~ LOOPHOLE[rasterMap.base.word];
upl: NAT ~ rasterMap.bitsPerLine/bitsPerUnit;
result: RawSamplesPtr ~ InlinePointerToSamples[samples, 0, count];
lastSHi: CARDINAL ¬ s.hi;
line: Pointer16 ¬ base+LONG[lastSHi]*upl;
FOR k: NAT IN [0..count) DO
IF lastSHi # s.hi THEN {lastSHi ¬ s.hi; line ¬ base+lastSHi*upl};
TRUSTED { result[k] ¬ line[f.hi] };
IF s.lc<sfdn.lc THEN s.lc ¬ s.lc+sfup.lc ELSE s.lc ¬ s.lc-sfdn.lc;
IF f.lc<ffdn.lc THEN f.lc ¬ f.lc+ffup.lc ELSE f.lc ¬ f.lc-ffdn.lc;
ENDLOOP;
};
ENDCASE => { -- the slow but general way
FOR k: NAT IN [0..count) DO
samples[k] ¬ ImagerSample.Get[map, [s: s.hi+self.box.min.s, f: f.hi+self.box.min.f]];
IF s.lc<sfdn.lc THEN s.lc ¬ s.lc+sfup.lc ELSE s.lc ¬ s.lc-sfdn.lc;
IF f.lc<ffdn.lc THEN f.lc ¬ f.lc+ffup.lc ELSE f.lc ¬ f.lc-ffdn.lc;
ENDLOOP;
};
ENDLOOP;
action[pixels, [d1s, d1f]];
d1s ¬ d1s+1; IF NOT d1s<box.max.s THEN EXIT;
IF s1.lc<ssdn.lc THEN s1.lc ¬ s1.lc+ssup.lc ELSE s1.lc ¬ s1.lc-ssdn.lc;
IF f1.lc<fsdn.lc THEN f1.lc ¬ f1.lc+fsup.lc ELSE f1.lc ¬ f1.lc-fsdn.lc;
ENDLOOP;
};
boxActionInterpolatedSamples: SF.BoxAction ~ {
count: NAT ~ SF.SizeF[box];
smax: Basics.LongNumber ~ [pair[hi: sSize, lo: 0]];
fmax: Basics.LongNumber ~ [pair[hi: fSize, lo: 0]];
ssup: Basics.LongNumber ~ ssDelta;
fsup: Basics.LongNumber ~ fsDelta;
ssdn: Basics.LongNumber ~ [lc[smax.lc-ssup.lc]];
fsdn: Basics.LongNumber ~ [lc[fmax.lc-fsup.lc]];
sfup: Basics.LongNumber ~ sfDelta;
ffup: Basics.LongNumber ~ ffDelta;
sfdn: Basics.LongNumber ~ [lc[smax.lc-sfup.lc]];
ffdn: Basics.LongNumber ~ [lc[fmax.lc-ffup.lc]];
isup: CARDINAL ~ 1;
ifup: CARDINAL ~ 1;
isdn: CARDINAL ~ smax.hi-isup;
ifdn: CARDINAL ~ fmax.hi-ifup;
d1s, d1f: INTEGER; -- destination position at start of scan line
s1: Basics.LongNumber ¬ s0; -- source s corresponding to [d1s, d1f]
f1: Basics.LongNumber ¬ f0; -- source f corresponding to [d1s, d1f]
[d1s, d1f] ¬ d0;
WHILE d1s<box.min.s DO
d1s ¬ d1s+1;
IF s1.lc<ssdn.lc THEN s1.lc ¬ s1.lc+ssup.lc ELSE s1.lc ¬ s1.lc-ssdn.lc;
IF f1.lc<fsdn.lc THEN f1.lc ¬ f1.lc+fsup.lc ELSE f1.lc ¬ f1.lc-fsdn.lc;
ENDLOOP;
WHILE d1s>box.min.s DO
d1s ¬ d1s-1;
IF s1.lc>=ssup.lc THEN s1.lc ¬ s1.lc-ssup.lc ELSE s1.lc ¬ s1.lc+ssdn.lc;
IF f1.lc>=fsup.lc THEN f1.lc ¬ f1.lc-fsup.lc ELSE f1.lc ¬ f1.lc+fsdn.lc;
ENDLOOP;
d0 ¬ [d1s, d1f];
s0.lc ¬ s1.lc;
f0.lc ¬ f1.lc;
WHILE d1f<box.min.f DO
d1f ¬ d1f+1;
IF s1.lc<sfdn.lc THEN s1.lc ¬ s1.lc+sfup.lc ELSE s1.lc ¬ s1.lc-sfdn.lc;
IF f1.lc<ffdn.lc THEN f1.lc ¬ f1.lc+ffup.lc ELSE f1.lc ¬ f1.lc-ffdn.lc;
ENDLOOP;
WHILE d1f>box.min.f DO
d1f ¬ d1f-1;
IF s1.lc>=sfup.lc THEN s1.lc ¬ s1.lc-sfup.lc ELSE s1.lc ¬ s1.lc+sfdn.lc;
IF f1.lc>=ffup.lc THEN f1.lc ¬ f1.lc-ffup.lc ELSE f1.lc ¬ f1.lc+ffdn.lc;
ENDLOOP;
pixels.length ¬ count;
DO --For each scan line of box--
FOR i: NAT IN [0..samplesPerPixel) DO
map: ImagerSample.SampleMap ~ self[i];
rasterMap: ImagerSample.RasterSampleMap ~ WITH map SELECT FROM r: ImagerSample.RasterSampleMap => r ENDCASE => NIL;
samples: ImagerSample.SampleBuffer ~ pixels[i];
s: Basics.LongNumber ¬ s1;
f: Basics.LongNumber ¬ f1;
IF rasterMap#NIL
AND rasterMap.base.bit=0
AND (rasterMap.bitsPerLine MOD bitsPerWord)=0
AND rasterMap.bitsPerSample=8 THEN {
base: Pointer8 ~ LOOPHOLE[rasterMap.base.word];
unitsPerLine: NAT ~ rasterMap.bitsPerLine/bitsPerUnit;
result: LONG POINTER TO RawSamples ~ InlinePointerToSamples[samples, 0, count];
FOR k: NAT IN [0..count) DO
-- Calculate i*
is0: CARDINAL ~ s.hi;
is1: CARDINAL ~ IF is0<isdn THEN is0+isup ELSE is0-isdn;
if0: CARDINAL ~ f.hi;
if1: CARDINAL ~ IF if0<ifdn THEN if0+ifup ELSE if0-ifdn;
-- Calculate w*
w11: CARDINAL ~ Basics.HighHalf[(LONG[s.lo]*f.lo)+LAST[CARD16]];
w10: CARDINAL ~ s.lo-w11;
w01: CARDINAL ~ f.lo-w11;
w00: CARDINAL ~ LAST[CARD16]-w01-w10-w11;
-- Calculate line*
line0: Pointer8 ~ base+LONG[is0]*unitsPerLine;
line1: Pointer8 ~ base+LONG[is1]*unitsPerLine;
TRUSTED {
-- Fetch v*
v00: CARDINAL ~ line0[if0];
v01: CARDINAL ~ line0[if1];
v10: CARDINAL ~ line1[if0];
v11: CARDINAL ~ line1[if1];
-- Calculate value
value: CARDINAL ~ Basics.HighHalf[
(LONG[w00]*v00) + (LONG[w01]*v01) +
(LONG[w10]*v10) + (LONG[w11]*v11) + LAST[CARD16]
];
-- Store result
result[k] ¬ value;
};
-- Bump s and f
IF s.lc<sfdn.lc THEN s.lc ¬ s.lc+sfup.lc ELSE s.lc ¬ s.lc-sfdn.lc;
IF f.lc<ffdn.lc THEN f.lc ¬ f.lc+ffup.lc ELSE f.lc ¬ f.lc-ffdn.lc;
ENDLOOP;
}
ELSE { -- the slow but general way
FOR k: NAT IN [0..count) DO
is0: CARDINAL ~ s.hi;
is1: CARDINAL ~ IF is0<isdn THEN is0+isup ELSE is0-isdn;
if0: CARDINAL ~ f.hi;
if1: CARDINAL ~ IF if0<ifdn THEN if0+ifup ELSE if0-ifdn;
w11: CARDINAL ~ Basics.HighHalf[(LONG[s.lo]*f.lo)+LAST[CARD16]];
w10: CARDINAL ~ s.lo-w11;
w01: CARDINAL ~ f.lo-w11;
w00: CARDINAL ~ LAST[CARD16]-w01-w10-w11;
v00, v01, v10, v11, value: CARDINAL;
v00 ¬ ImagerSample.Get[map, [s: is0+self.box.min.s, f: if0+self.box.min.f]];
v01 ¬ ImagerSample.Get[map, [s: is0+self.box.min.s, f: if1+self.box.min.f]];
v10 ¬ ImagerSample.Get[map, [s: is1+self.box.min.s, f: if0+self.box.min.f]];
v11 ¬ ImagerSample.Get[map, [s: is1+self.box.min.s, f: if1+self.box.min.f]];
value ¬ Basics.HighHalf[
(LONG[w00]*v00) + (LONG[w01]*v01) +
(LONG[w10]*v10) + (LONG[w11]*v11) + LAST[CARD16]
];
samples[k] ¬ value;
IF s.lc<sfdn.lc THEN s.lc ¬ s.lc+sfup.lc ELSE s.lc ¬ s.lc-sfdn.lc;
IF f.lc<ffdn.lc THEN f.lc ¬ f.lc+ffup.lc ELSE f.lc ¬ f.lc-ffdn.lc;
ENDLOOP;
};
ENDLOOP;
action[pixels, [d1s, d1f]];
d1s ¬ d1s+1; IF NOT d1s<box.max.s THEN EXIT;
IF s1.lc<ssdn.lc THEN s1.lc ¬ s1.lc+ssup.lc ELSE s1.lc ¬ s1.lc-ssdn.lc;
IF f1.lc<fsdn.lc THEN f1.lc ¬ f1.lc+fsup.lc ELSE f1.lc ¬ f1.lc-fsdn.lc;
ENDLOOP;
};
-- Set increments --
[[rs, rf]] ¬ ImagerTransformation.InverseTransformVec[m, [0, 1]];
sfDelta.li ¬ ScaledFromRealMod[rs, sSize];
ffDelta.li ¬ ScaledFromRealMod[rf, fSize];
[[rs, rf]] ¬ ImagerTransformation.InverseTransformVec[m, [1, 0]];
ssDelta.li ¬ ScaledFromRealMod[rs, sSize];
fsDelta.li ¬ ScaledFromRealMod[rf, fSize];
-- Set initial position --
[[rs, rf]] ¬ ImagerTransformation.InverseTransform[m, [d0.s+0.5, d0.f+0.5]];
IF interpolate AND HalfInteger[rs] AND HalfInteger[rf] AND sfDelta.lo = 0 AND ffDelta.lo = 0 AND ssDelta.lo = 0 AND fsDelta.lo = 0
THEN {
-- No need to interpolate, since all sampling points fall on pixel centers anyway --
interpolate ¬ FALSE;
};
IF interpolate THEN { rs ¬ rs-0.5; rf ¬ rf-0.5 };
s0.li ¬ ScaledFromRealMod[rs-self.box.min.s, sSize];
f0.li ¬ ScaledFromRealMod[rf-self.box.min.f, fSize];
boxes[IF interpolate THEN boxActionInterpolatedSamples ELSE boxActionPointSamples];
ReleaseScratchPixels[pixels];
};
};
HalfInteger: PROC [r: REAL] RETURNS [BOOL] ~ {
fuzz: INT ~ 8;
half: INT ~ INT[LAST[CARD16]]/2+1;
lo: CARD16 ~ half-fuzz;
hi: CARD16 ~ half+fuzz;
n: Basics.LongNumber ~ [li[ScaledFromRealMod[r, 1]]];
halfInteger: BOOL ~ n.lo IN [lo..hi];
RETURN [halfInteger]
};
END.