ImagerSampleImpl.mesa
Copyright © 1984, 1985, 1986 by Xerox Corporation. All rights reserved.
Michael Plass, January 21, 1986 12:07:30 pm PST
Doug Wyatt, March 6, 1986 4:09:53 pm PST
DIRECTORY
Basics USING [BITAND, BITSHIFT, bitsPerWord, BoundsCheck, CARD, DoubleShiftRight, HighHalf, logBitsPerWord, LongDivMod, LongMult, LongNumber, NonNegative, RawWords, ShortNumber],
CountedVM USING [Handle, SimpleAllocate],
FunctionCache USING [Cache, CacheInfo, GetInfo, GlobalCache, SetLimits],
ImagerSample,
ImagerTransformation,
PrincOps USING [BBptr, BBTableSpace, BitAddress, BitBltFlags, BitBltTable],
PrincOpsUtils USING [AlignedBBTable, BITBLT, LongCopy, LongZero],
Real,
SF,
Terminal USING [FrameBuffer],
VM USING [CantAllocate, wordsPerPage];
ImagerSampleImpl: CEDAR MONITOR
IMPORTS Basics, CountedVM, FunctionCache, ImagerTransformation, PrincOpsUtils, Real, SF, VM
EXPORTS ImagerSample
~ BEGIN OPEN ImagerSample;
MultipleReleaseOfScratch:
PUBLIC
ERROR ~
CODE;
NewSamples:
PUBLIC
PROC [length:
NAT,
scratch: SampleBuffer ←
NIL]
RETURNS [SampleBuffer] ~ {
new: SampleBuffer ← scratch;
IF new=NIL OR new.maxLength<length THEN new ← NEW[SampleBufferRep[length]];
new.length ← length;
RETURN[new];
};
nScratchSampleBuffers: NAT ~ 6;
scratchSampleBuffers:
ARRAY [0..nScratchSampleBuffers)
OF SampleBuffer ←
ALL[
NIL];
ObtainScratchSamples:
PUBLIC
ENTRY
PROC [length:
NAT]
RETURNS [SampleBuffer] ~ {
FOR i:
NAT
IN [0..nScratchSampleBuffers)
DO
buf: SampleBuffer ~ scratchSampleBuffers[i];
IF buf #
NIL
AND buf.maxLength >= length
THEN {
scratchSampleBuffers[i] ← NIL;
buf.length ← length;
RETURN [buf];
};
ENDLOOP;
RETURN [NEW[SampleBufferRep[length] ← [length: length, samples:]]]
};
ReleaseScratchSamples:
PUBLIC
ENTRY
PROC [samples: SampleBuffer] ~ {
r: SampleBuffer ← samples;
samples.length ← 0;
FOR i:
NAT
IN [0..nScratchSampleBuffers)
UNTIL r =
NIL
DO
Push least-recently-used towards end.
t: SampleBuffer ← scratchSampleBuffers[i];
scratchSampleBuffers[i] ← r;
r ← t;
IF r = samples THEN RETURN WITH ERROR MultipleReleaseOfScratch;
ENDLOOP;
};
DoWithScratchSamples:
PUBLIC
PROC [length:
NAT, action:
PROC [SampleBuffer]] ~ {
scratch: SampleBuffer ~ ObtainScratchSamples[length];
action[scratch ! UNWIND => ReleaseScratchSamples[scratch]];
ReleaseScratchSamples[scratch];
};
InlinePointerToSamples:
PROC [samples: 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[SampleBufferRep[start]]];
};
PointerToSamples:
PUBLIC
PROC [samples: SampleBuffer, start:
NAT, count:
NAT]
RETURNS [
LONG
POINTER
TO RawSamples] ~ {
RETURN [InlinePointerToSamples[samples, start, count]]
};
FlipSamples:
PUBLIC
PROC [samples: SampleBuffer] ~ {
size: NAT ~ samples.length;
IF size>0
THEN
TRUSTED {
pointer: LONG POINTER TO RawSamples ~ InlinePointerToSamples[samples, 0, size];
last: NAT ~ size-1;
FOR j:
NAT
IN [0..size/2)
DO
k: NAT ~ last-j;
t: Sample ~ pointer[j];
pointer[j] ← pointer[k];
pointer[k] ← t;
ENDLOOP;
};
};
FillSamples:
PUBLIC
PROC [samples: SampleBuffer, value: Sample, start, count:
NAT] ~ {
size: NAT ~ MIN[samples.length-start, count];
IF size>0
THEN
TRUSTED {
pointer: LONG POINTER TO RawSamples ~ InlinePointerToSamples[samples, start, size];
pointer[0] ← value;
PrincOpsUtils.LongCopy[from: pointer, nwords: size-1, to: pointer+1];
};
};
bitsPerWord: NAT ~ Basics.bitsPerWord;
logBitsPerWord: NAT ~ Basics.logBitsPerWord;
CARD:
TYPE ~ Basics.
CARD;
nullBitBltTable: PrincOps.BitBltTable ~ [
dst: [word: NIL, bit: 0], dstBpl: 0,
src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]],
width: 0, height: 0, flags: []
];
IsPowerOfTwo:
PROC [c:
CARDINAL]
RETURNS [
BOOL] ~
INLINE {
RETURN[Basics.BITAND[c, c-1]=0];
};
WordsForBits:
PROC [bitCount:
CARD]
RETURNS [
CARD] ~
INLINE {
RETURN[Basics.DoubleShiftRight[[lc[bitCount+(bitsPerWord-1)]], logBitsPerWord].lc]
};
Lg:
PROC [a:
NAT]
RETURNS [lg:
NAT ← 0] ~ {
b: CARDINAL ← 1;
UNTIL b >= a
DO
lg ← lg + 1;
b ← b*2;
ENDLOOP;
};
IndexBit:
PROC [addr: PrincOps.BitAddress, offset:
CARD]
RETURNS [PrincOps.BitAddress] ~
TRUSTED
INLINE {
Addr:
TYPE ~
MACHINE
DEPENDENT
RECORD [pointer:
LONG
POINTER, offset:
CARDINAL];
This record is to designed to avoid the need for partial-word access to the bit offset field, since the BITBLT format has carefully made this field word-aligned, and PrincOps.BitAddress has just as carefully made it hard to take advantage of this fact.
pointer: LONG POINTER ~ LOOPHOLE[addr, Addr].pointer;
index: Basics.LongNumber ~ [lc[LOOPHOLE[addr, Addr].offset+offset]];
RETURN[
LOOPHOLE[Addr[
pointer: pointer+Basics.DoubleShiftRight[index, logBitsPerWord].lc,
offset: index.lo MOD bitsPerWord
]]];
};
BitsForSamples:
PUBLIC
PROC [fSize:
NAT, bitsPerSample:
NAT]
RETURNS [
NAT] ~ {
Returns required number of bits, rounded up to a whole number of words.
RETURN[Basics.BITAND[Basics.LongMult[fSize, bitsPerSample]+(bitsPerWord-1), WORD.LAST-(bitsPerWord-1)]];
};
WordsForLines:
PUBLIC
PROC [sSize:
NAT, bitsPerLine:
NAT]
RETURNS [
INT] ~ {
IF (bitsPerLine
MOD bitsPerWord)=0
THEN RETURN[Basics.LongMult[sSize, bitsPerLine/bitsPerWord]]
ELSE RETURN[WordsForBits[Basics.LongMult[sSize, bitsPerLine]]];
};
WordsForMap:
PUBLIC
PROC [size: Vec, bitsPerSample: BitsPerSample,
bitsPerLine:
NAT ← 0]
RETURNS [
INT] ~ {
IF bitsPerLine=0 THEN bitsPerLine ← BitsForSamples[size.f, bitsPerSample];
RETURN[WordsForLines[size.s, bitsPerLine]];
};
UnsafeNewSampleMap:
PUBLIC
UNSAFE
PROC [size: Vec, bitsPerSample: BitsPerSample, bitsPerLine:
NAT, base: PrincOps.BitAddress, ref:
REF, words:
INT, scratchDescriptor: SampleMap ←
NIL]
RETURNS [SampleMap] ~ {
dataBitsPerLine: INT ~ Basics.LongMult[NAT[size.f], bitsPerSample];
fillBits: INT ~ Basics.NonNegative[bitsPerLine-dataBitsPerLine]; -- check sufficient bitsPerLine
totalBits: INT ~ INT[base.bit]+Basics.LongMult[NAT[size.s], bitsPerLine]-fillBits;
totalWords: INT ~ WordsForBits[totalBits];
spareWords: INT ~ Basics.NonNegative[words-totalWords]; -- check sufficient words
s: SampleMap ← scratchDescriptor;
IF s=NIL THEN s ← NEW[SampleMapRep];
s^ ← [size: size, bitsPerSample: bitsPerSample, bitsPerLine: bitsPerLine, base: base, ref: ref];
RETURN[s];
};
WordSeqRep: TYPE ~ RECORD [SEQUENCE length: NAT OF WORD];
maxWordSeqWords:
INT ←
VM.wordsPerPage-
VM.wordsPerPage/10-
SIZE[WordSeqRep[0]];
NewSampleMap:
PUBLIC
PROC [size: Vec, bitsPerSample: BitsPerSample, bitsPerLine:
NAT ← 0,
scratch: SampleMap ←
NIL]
RETURNS [SampleMap] ~ {
actualBitsPerLine:
NAT ~
SELECT bitsPerLine
FROM
0 => BitsForSamples[size.f, bitsPerSample], ENDCASE => bitsPerLine;
IF scratch#NIL AND scratch.size.Eq[size] AND scratch.bitsPerSample=bitsPerSample AND scratch.bitsPerLine=actualBitsPerLine THEN RETURN[scratch]
ELSE {
words: INT ~ WordsForLines[size.s, actualBitsPerLine];
IF words <= maxWordSeqWords
THEN {
wordSeq: REF WordSeqRep ~ NEW[WordSeqRep[words]];
TRUSTED {
RETURN[UnsafeNewSampleMap[
size: size, bitsPerSample: bitsPerSample, bitsPerLine: actualBitsPerLine,
base: [word: @wordSeq[0], bit: 0], ref: wordSeq, words: wordSeq.length
]] };
}
ELSE
RETURN[MapFromVM[vm: Allocate[words],
size: size, bitsPerSample: bitsPerSample, bitsPerLine: actualBitsPerLine]];
};
};
Allocate:
PROC [nWords:
CARD]
RETURNS [vm: CountedVM.Handle ←
NIL] ~ {
nWords ← MAX[nWords, 256];
vm ← CountedVM.SimpleAllocate[nWords ! VM.CantAllocate => CONTINUE];
IF vm =
NIL
THEN {
Try flushing the global function cache to get some space back.
cache: FunctionCache.Cache ~ FunctionCache.GlobalCache[];
info: FunctionCache.CacheInfo ~ FunctionCache.GetInfo[cache];
FunctionCache.SetLimits[cache, 0, 0];
FunctionCache.SetLimits[x: cache, maxEntries: info.maxEntries, maxTotalSize: info.maxTotalSize];
ClearScratchMaps[];
vm ← CountedVM.SimpleAllocate[nWords];
};
};
MapFromVM:
PUBLIC
PROC [vm: CountedVM.Handle,
size: Vec, bitsPerSample: BitsPerSample ← 1, bitsPerLine:
NAT ← 0
]
RETURNS [SampleMap] ~ {
actualBitsPerLine:
NAT ~
SELECT bitsPerLine
FROM
0 => BitsForSamples[size.f, bitsPerSample], ENDCASE => bitsPerLine;
TRUSTED {
RETURN[UnsafeNewSampleMap[
size: size, bitsPerSample: bitsPerSample, bitsPerLine: actualBitsPerLine,
base: [word: vm.pointer, bit: 0], ref: vm, words: vm.words
]] };
};
MapFromFrameBuffer:
PUBLIC
PROC [frameBuffer: Terminal.FrameBuffer]
RETURNS [SampleMap] ~ {
bitsPerLine: NAT ~ Basics.LongMult[frameBuffer.wordsPerLine, bitsPerWord];
vm: CountedVM.Handle ~ frameBuffer.vm;
base: LONG POINTER ~ frameBuffer.base;
baseOffset: INT ~ LOOPHOLE[base, INT]-LOOPHOLE[vm.pointer, INT];
words: INT ~ vm.words-Basics.NonNegative[baseOffset];
TRUSTED {
RETURN[UnsafeNewSampleMap[
size: [s: frameBuffer.height, f: frameBuffer.width],
bitsPerSample: frameBuffer.bitsPerPixel, bitsPerLine: bitsPerLine,
base: [word: base, bit: 0], ref: vm, words: words
]] };
};
SubMap:
PUBLIC
PROC [self: SampleMap, box: Box]
RETURNS [SampleMap] ~
TRUSTED {
size: Vec ~ self.size.Min[box.max].Sub[box.min];
skipBits:
CARD ~
Basics.LongMult[box.min.s, self.bitsPerLine] +
Basics.LongMult[box.min.f, self.bitsPerSample];
new: SampleMap ~ NEW[SampleMapRep ← self^];
new.size ← size;
new.base ← IndexBit[self.base, skipBits];
RETURN[new];
};
CopyMap:
PUBLIC
PROC [self: SampleMap, box: Box]
RETURNS [SampleMap] ~ {
size: Vec ~ self.size.Min[box.max].Sub[box.min];
new: SampleMap ~ NewSampleMap[size: size, bitsPerSample: self.bitsPerSample];
Transfer[dst: new, src: self, srcMin: box.min];
RETURN[new];
};
nScratchMaps: NAT ~ 5;
scratchMaps:
ARRAY [0..nScratchMaps)
OF SampleMap ←
ALL[
NIL];
ObtainScratchMap:
PUBLIC
PROC [size: Vec, bitsPerSample: BitsPerSample]
RETURNS [SampleMap] ~ {
TryObtainScratch:
ENTRY
PROC
RETURNS [SampleMap] ~
TRUSTED {
bitsPerLine: NAT ~ BitsForSamples[fSize: size.f, bitsPerSample: bitsPerSample];
nWords: INT ~ WordsForLines[sSize: size.s, bitsPerLine: bitsPerLine];
FOR i:
NAT
IN [0..nScratchMaps)
DO
s: SampleMap ← scratchMaps[i];
IF s #
NIL
THEN
WITH s.ref
SELECT
FROM
vm: CountedVM.Handle => {
IF vm.words >= nWords
THEN {
scratchMaps[i] ← NIL;
s.size ← size;
s.bitsPerSample ← bitsPerSample;
s.bitsPerLine ← bitsPerLine;
s.base ← [word: vm.pointer, bit: 0];
RETURN [s]
};
};
ENDCASE => NULL;
ENDLOOP;
RETURN [NIL]
};
s: SampleMap ← TryObtainScratch[];
IF s =
NIL
THEN {
vm: CountedVM.Handle ~ Allocate[WordsForMap[size, bitsPerSample]];
s ← MapFromVM[vm: vm, size: size, bitsPerSample: bitsPerSample];
};
RETURN [s]
};
ReleaseScratchMap:
PUBLIC
ENTRY
PROC [self: SampleMap] ~ {
r: SampleMap ← self;
*** test for excessive size here ? ***
FOR i:
NAT
IN [0..nScratchMaps)
UNTIL r =
NIL
DO
Push least-recently-used towards end.
t: SampleMap ← scratchMaps[i];
scratchMaps[i] ← r;
r ← t;
IF r = self THEN RETURN WITH ERROR MultipleReleaseOfScratch;
ENDLOOP;
};
ClearScratchMaps:
ENTRY
PROC ~ {
FOR i:
NAT
IN [0..nScratchMaps)
DO
scratchMaps[i] ← NIL;
ENDLOOP;
};
DoWithScratchMap:
PUBLIC
PROC [size: Vec, bitsPerSample: BitsPerSample,
action:
PROC [SampleMap]] ~ {
scratch: SampleMap ~ ObtainScratchMap[size, bitsPerSample];
action[scratch ! UNWIND => ReleaseScratchMap[scratch]];
ReleaseScratchMap[scratch];
};
Clear:
PUBLIC
PROC [self: SampleMap] ~
TRUSTED {
bitsPerLine: NAT ~ self.bitsPerLine;
pointer: LONG POINTER ← self.base.word;
fillBitsPerLine: NAT ~ bitsPerLine - self.bitsPerSample*self.size.f;
IF fillBitsPerLine < bitsPerWord
THEN {
-- Contiguous, except perhaps for some padding. --
nBits: CARD ~ Basics.LongMult[bitsPerLine, self.size.s]+self.base.bit-fillBitsPerLine;
nWords: CARD ← WordsForBits[nBits];
WHILE nWords > 32768
DO
PrincOpsUtils.LongZero[pointer, 32768];
pointer ← pointer + 32768;
nWords ← nWords - 32768;
ENDLOOP;
PrincOpsUtils.LongZero[pointer, nWords];
}
ELSE {
-- Discontiguous, so do pieces (could BITBLT here; which is cheaper?) --
dataBitsPlus: NAT ~ self.bitsPerSample*self.size.f + (bitsPerWord-1);
bit: CARDINAL ← self.base.bit;
FOR i:
NAT
IN [0..self.size.s)
DO
PrincOpsUtils.LongZero[where: pointer, nwords: (bit + dataBitsPlus)/bitsPerWord];
bit ← bit + bitsPerLine;
pointer ← pointer + bit/bitsPerWord;
bit ← bit MOD bitsPerWord;
ENDLOOP;
};
};
Get:
PUBLIC
PROC [self: SampleMap, index: Vec]
RETURNS [Sample] ~
TRUSTED {
bitsPerSample: NAT ~ self.bitsPerSample;
bitIndex:
CARD ~
Basics.LongMult[Basics.BoundsCheck[index.s, self.size.s], self.bitsPerLine] +
Basics.LongMult[Basics.BoundsCheck[index.f, self.size.f], bitsPerSample];
bitAddress: PrincOps.BitAddress ~ IndexBit[self.base, bitIndex];
IF bitsPerSample=1
THEN
TRUSTED {
pointer: LONG POINTER TO Basics.ShortNumber ~ bitAddress.word;
RETURN[LOOPHOLE[pointer.bits[bitAddress.bit]]];
}
ELSE
TRUSTED {
pointer: LONG POINTER TO Basics.RawWords ~ bitAddress.word;
shiftAmt: INTEGER ~ bitAddress.bit + bitsPerSample - bitsPerWord;
mask: WORD ~ Basics.BITSHIFT[1, bitsPerSample]-1;
shiftedBits:
WORD ~
IF shiftAmt <= 0
THEN Basics.BITSHIFT[pointer[0], shiftAmt]
ELSE Basics.BITSHIFT[pointer[0], shiftAmt] + Basics.BITSHIFT[pointer[1], shiftAmt-16];
RETURN[Basics.BITAND[shiftedBits, mask]];
};
};
Put:
PUBLIC
PROC [self: SampleMap, index: Vec, value: Sample,
function: Function ← nullFunction] ~ {
bitsPerSample: NAT ~ self.bitsPerSample;
bitIndex:
CARD ~
Basics.LongMult[Basics.BoundsCheck[index.s, self.size.s], self.bitsPerLine] +
Basics.LongMult[Basics.BoundsCheck[index.f, self.size.f], bitsPerSample];
bitAddress: PrincOps.BitAddress ~ IndexBit[self.base, bitIndex];
IF bitsPerSample=1
AND function=nullFunction
THEN
TRUSTED {
pointer: LONG POINTER TO Basics.ShortNumber ~ bitAddress.word;
pointer.bits[bitAddress.bit] ← LOOPHOLE[value];
}
ELSE
TRUSTED {
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
bb^ ← nullBitBltTable;
bb.dst ← bitAddress;
bb.src.word ← @value;
bb.src.bit ← bitsPerWord-bitsPerSample;
bb.height ← 1;
bb.width ← bitsPerSample;
bb.flags ← [disjoint: TRUE, disjointItems: TRUE, gray: FALSE];
bb.flags.srcFunc ← function.srcFunc;
bb.flags.dstFunc ← function.dstFunc;
PrincOpsUtils.BITBLT[bb];
};
};
GetSamples:
PUBLIC
PROC [self: SampleMap, min: Vec ← zeroVec, delta: Vec ← [s: 0, f: 1],
samples: SampleBuffer, start:
NAT ← 0, count:
NAT ← maxCount] ~ {
size: NAT ~ MIN[samples.length-start, count];
IF size#0
THEN
TRUSTED {
bitsPerLine: NAT ~ self.bitsPerLine;
bitsPerSample: NAT ~ self.bitsPerSample;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
bbTableSpace: PrincOps.BBTableSpace;
bufferPointer: LONG POINTER ~ InlinePointerToSamples[samples, start, size];
srcBitIndex:
CARD ←
Basics.LongMult[Basics.BoundsCheck[min.s, self.size.s], bitsPerLine] +
Basics.LongMult[Basics.BoundsCheck[min.f, self.size.f], bitsPerSample];
srcBitDelta:
NAT ~
Basics.LongMult[delta.s, bitsPerLine] +
Basics.LongMult[delta.f, bitsPerSample];
srcBitSkipDelta: NAT ← srcBitDelta;
lgSkip: NAT ← 0;
skipMinusOne: NAT ← 0;
IF delta.s#0 THEN []sics.BoundsCheck[min.s+Basics.LongMult[size-1, delta.s], self.size.s];
IF delta.f#0 THEN []sics.BoundsCheck[min.f+Basics.LongMult[size-1, delta.f], self.size.f];
WHILE srcBitSkipDelta<=
NAT.
LAST/2
AND
CARDINAL[srcBitSkipDelta]
MOD bitsPerWord#0
DO
srcBitSkipDelta ← srcBitSkipDelta*2; lgSkip ← lgSkip+1;
ENDLOOP;
skipMinusOne ← Basics.BITSHIFT[1, lgSkip]-1;
PrincOpsUtils.LongZero[where: bufferPointer, nwords: size];
bb^ ← nullBitBltTable;
bb.dst.bit ← bitsPerWord-bitsPerSample;
bb.dstBpl ← Basics.BITSHIFT[bitsPerWord, lgSkip];
bb.srcDesc ← [srcBpl[srcBitSkipDelta]];
bb.width ← bitsPerSample;
bb.flags ← [disjoint: TRUE, disjointItems: TRUE, gray: FALSE];
FOR i:
NAT
IN [0..Basics.
BITSHIFT[1, lgSkip])
DO
bb.src ← IndexBit[self.base, srcBitIndex];
bb.height ← Basics.BITSHIFT[size-i+skipMinusOne, -lgSkip];
bb.dst.word ← bufferPointer+i;
PrincOpsUtils.BITBLT[bb];
srcBitIndex ← srcBitIndex + srcBitDelta;
ENDLOOP;
};
};
PutSamples:
PUBLIC
PROC [self: SampleMap, min: Vec ← zeroVec, delta: Vec ← [s: 0, f: 1],
samples: SampleBuffer, start:
NAT ← 0, count:
NAT ← maxCount,
function: Function ← nullFunction] ~ {
size: NAT ~ MIN[samples.length-start, count];
IF size # 0
THEN
TRUSTED {
bitsPerLine: NAT ~ self.bitsPerLine;
bitsPerSample: NAT ~ self.bitsPerSample;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
bbTableSpace: PrincOps.BBTableSpace;
bufferPointer: LONG POINTER ~ InlinePointerToSamples[samples, start, size];
dstBitIndex:
CARD ←
Basics.LongMult[Basics.BoundsCheck[min.s, self.size.s], bitsPerLine] +
Basics.LongMult[Basics.BoundsCheck[min.f, self.size.f], bitsPerSample];
dstBitDelta:
NAT ←
Basics.LongMult[delta.s, bitsPerLine] +
Basics.LongMult[delta.f, bitsPerSample];
dstBitSkipDelta: NAT ← dstBitDelta;
lgSkip: NAT ← 0;
skipMinusOne: NAT ← 0;
IF delta.s#0 THEN []sics.BoundsCheck[min.s+Basics.LongMult[size-1, delta.s], self.size.s];
IF delta.f#0 THEN []sics.BoundsCheck[min.f+Basics.LongMult[size-1, delta.f], self.size.f];
WHILE dstBitSkipDelta<=
NAT.
LAST/2
AND
CARDINAL[dstBitSkipDelta]
MOD bitsPerWord#0
DO
dstBitSkipDelta ← dstBitSkipDelta*2; lgSkip ← lgSkip+1;
ENDLOOP;
skipMinusOne ← Basics.BITSHIFT[1, lgSkip]-1;
bb^ ← nullBitBltTable;
bb.flags ← [disjoint: TRUE, disjointItems: TRUE, gray: FALSE];
bb.flags.srcFunc ← function.srcFunc;
bb.flags.dstFunc ← function.dstFunc;
bb.dstBpl ← dstBitSkipDelta;
bb.src.bit ← bitsPerWord-bitsPerSample;
bb.srcDesc ← [srcBpl[Basics.BITSHIFT[bitsPerWord, lgSkip]]];
bb.width ← bitsPerSample;
FOR i:
NAT
IN [0..Basics.
BITSHIFT[1, lgSkip])
DO
bb.dst ← IndexBit[self.base, dstBitIndex];
bb.height ← Basics.BITSHIFT[size-i+skipMinusOne, -lgSkip];
bb.src.word ← bufferPointer+i;
PrincOpsUtils.BITBLT[bb];
dstBitIndex ← dstBitIndex + dstBitDelta;
ENDLOOP;
};
};
DumbTransfer:
PROC [dst: SampleMap, src: SampleMap,
dstMin: Vec ← zeroVec, srcMin: Vec ← zeroVec, size: Vec ← maxVec,
function: Function ← nullFunction] ~ {
sSize: NAT ~ MIN[dst.size.s-dstMin.s, src.size.s-srcMin.s, size.s];
fSize: NAT ~ MIN[dst.size.f-dstMin.f, src.size.f-srcMin.f, size.f];
FOR s:
NAT
IN [0..sSize)
DO
FOR f:
NAT
IN [0..fSize)
DO
offset: Vec ~ [s: s, f: f];
value: Sample ~ Get[src, srcMin.Add[offset]];
Put[dst, dstMin.Add[offset], value, function];
ENDLOOP;
ENDLOOP;
};
BufferTransfer:
PROC [dst: SampleMap, src: SampleMap,
dstMin: Vec ← zeroVec, srcMin: Vec ← zeroVec, size: Vec ← maxVec,
function: Function ← nullFunction] ~ {
sSize: NAT ~ MIN[dst.size.s-dstMin.s, src.size.s-srcMin.s, size.s];
fSize: NAT ~ MIN[dst.size.f-dstMin.f, src.size.f-srcMin.f, size.f];
transferAction:
PROC [samples: SampleBuffer] ~ {
FOR s:
NAT
IN [0..sSize)
DO
GetSamples[self: src, min: [s: srcMin.s+s, f: srcMin.f], samples: samples];
PutSamples[self: dst, min: [s: dstMin.s+s, f: dstMin.f], samples: samples,
function: function];
ENDLOOP;
};
DoWithScratchSamples[length: fSize, action: transferAction];
};
Transfer:
PUBLIC
PROC [dst: SampleMap, src: SampleMap,
dstMin: Vec ← zeroVec, srcMin: Vec ← zeroVec, size: Vec ← maxVec,
function: Function ← nullFunction] ~ {
bitsPerSample: NAT ~ dst.bitsPerSample;
IF src.bitsPerSample=bitsPerSample
THEN
TRUSTED {
sSize: NAT ~ MIN[dst.size.s-dstMin.s, src.size.s-srcMin.s, size.s];
fSize: NAT ~ MIN[dst.size.f-dstMin.f, src.size.f-srcMin.f, size.f];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
dstBitIndex:
CARD ~
Basics.LongMult[dstMin.s, dst.bitsPerLine] +
Basics.LongMult[dstMin.f, bitsPerSample];
srcBitIndex:
CARD ~
Basics.LongMult[srcMin.s, src.bitsPerLine] +
Basics.LongMult[srcMin.f, bitsPerSample];
bb^ ← nullBitBltTable;
bb.dst ← IndexBit[dst.base, dstBitIndex];
bb.dstBpl ← dst.bitsPerLine;
bb.src ← IndexBit[src.base, srcBitIndex];
bb.srcDesc ← [srcBpl[src.bitsPerLine]];
bb.width ← fSize*bitsPerSample;
bb.height ← sSize;
bb.flags ← [disjoint: TRUE, disjointItems: TRUE, gray: FALSE];
bb.flags.srcFunc ← function.srcFunc;
bb.flags.dstFunc ← function.dstFunc;
PrincOpsUtils.BITBLT[bb];
}
ELSE BufferTransfer[dst, src, dstMin, srcMin, size, function];
};
TransferBoxes:
PUBLIC
PROC [dst: SampleMap, src: SampleMap,
boxes: BoxGenerator, dstOffset: Vec ← zeroVec, srcOffset: Vec ← zeroVec,
function: Function ← nullFunction] ~ {
bitsPerSample: NAT ~ dst.bitsPerSample;
IF src.bitsPerSample=bitsPerSample
THEN
TRUSTED {
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
fastTransfer: BoxAction ~
TRUSTED {
dstMin: Vec ~ box.min.Add[dstOffset];
srcMin: Vec ~ box.min.Add[srcOffset];
sSize: NAT ~ MIN[dst.size.s-dstMin.s, src.size.s-srcMin.s, box.max.s-box.min.s];
fSize: NAT ~ MIN[dst.size.f-dstMin.f, src.size.f-srcMin.f, box.max.f-box.min.f];
dstBitIndex:
CARD ~
Basics.LongMult[dstMin.s, dst.bitsPerLine] +
Basics.LongMult[dstMin.f, bitsPerSample];
srcBitIndex:
CARD ~
Basics.LongMult[srcMin.s, src.bitsPerLine] +
Basics.LongMult[srcMin.f, bitsPerSample];
bb.dst ← IndexBit[dst.base, dstBitIndex];
bb.src ← IndexBit[src.base, srcBitIndex];
bb.width ← fSize*bitsPerSample;
bb.height ← sSize;
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← dst.bitsPerLine;
bb.srcDesc ← [srcBpl[src.bitsPerLine]];
bb.flags ← [disjoint: TRUE, disjointItems: TRUE, gray: FALSE];
bb.flags.srcFunc ← function.srcFunc;
bb.flags.dstFunc ← function.dstFunc;
boxes[fastTransfer];
}
ELSE {
slowTransfer: BoxAction ~ {
dstMin: Vec ~ box.min.Add[dstOffset];
srcMin: Vec ~ box.min.Add[srcOffset];
BufferTransfer[dst, src, dstMin, srcMin, box.max.Sub[box.min], function];
};
boxes[slowTransfer];
};
};
Move:
PUBLIC
PROC [self: SampleMap,
dstMin: Vec ← zeroVec, srcMin: Vec ← zeroVec, size: Vec ← maxVec,
function: Function ← nullFunction] ~
TRUSTED {
sSize: NAT ~ MIN[self.size.s-srcMin.s, self.size.s-dstMin.s, size.s];
fSize: NAT ~ MIN[self.size.f-srcMin.f, self.size.f-dstMin.f, size.f];
bitsPerSample: NAT ~ self.bitsPerSample;
bitsPerLine: NAT ~ self.bitsPerLine;
dstBitIndex:
CARD ←
Basics.LongMult[dstMin.s, bitsPerLine] +
Basics.LongMult[dstMin.f, bitsPerSample];
srcBitIndex:
CARD ←
Basics.LongMult[srcMin.s, bitsPerLine] +
Basics.LongMult[srcMin.f, bitsPerSample];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
bb^ ← nullBitBltTable;
bb.dstBpl ← bitsPerLine;
bb.srcDesc ← [srcBpl[bitsPerLine]];
bb.height ← sSize;
bb.width ← bitsPerSample * fSize;
bb.flags ← [disjoint: TRUE, disjointItems: TRUE, gray: FALSE];
bb.flags.srcFunc ← function.srcFunc;
bb.flags.dstFunc ← function.dstFunc;
IF sSize > 0
AND
(srcMin.f+fSize) > dstMin.f
AND (dstMin.f+fSize) > srcMin.f
AND
(srcMin.s+sSize) > dstMin.s
AND (dstMin.s+sSize) > srcMin.s
THEN {
bb.flags.disjoint ← FALSE; -- the rectangles overlap
IF srcMin.s=dstMin.s THEN bb.flags.disjointItems ← FALSE; -- so do the items
IF dstMin.s>srcMin.s
OR (dstMin.s=srcMin.s
AND dstMin.f>srcMin.f)
THEN {
delta: CARD ~ Basics.LongMult[sSize-1, bitsPerLine];
bb.flags.direction ← backward; -- reverse direction
bb.srcDesc.srcBpl ← bb.dstBpl ← -bitsPerLine;
dstBitIndex ← dstBitIndex + delta;
srcBitIndex ← srcBitIndex + delta;
};
};
bb.dst ← IndexBit[self.base, dstBitIndex];
bb.src ← IndexBit[self.base, srcBitIndex];
PrincOpsUtils.BITBLT[bb];
};
MoveBoxes:
PUBLIC
PROC [self: SampleMap,
boxes: BoxGenerator, dstOffset: Vec ← zeroVec, srcOffset: Vec ← zeroVec,
function: Function ← nullFunction] ~
TRUSTED {
bitsPerSample: NAT ~ self.bitsPerSample;
bitsPerLine: NAT ~ self.bitsPerLine;
bbTableSpace: PrincOps.BBTableSpace;
bbPtr: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
initialFlags: PrincOps.BitBltFlags ~ [direction: forward, disjoint: TRUE, disjointItems: TRUE,
gray: FALSE, srcFunc: function.srcFunc, dstFunc: function.dstFunc];
fastMoveBox: BoxAction ~
TRUSTED {
bb: PrincOps.BBptr ~ bbPtr;
dstMin: Vec ~ dstOffset.Add[box.min];
srcMin: Vec ~ srcOffset.Add[box.min];
sSize: NAT ~ MIN[self.size.s-dstMin.s, self.size.s-srcMin.s, box.max.s-box.min.s];
fSize: NAT ~ MIN[self.size.f-dstMin.f, self.size.f-srcMin.f, box.max.f-box.min.f];
dstBitIndex:
CARD ←
Basics.LongMult[dstMin.s, bitsPerLine] +
Basics.LongMult[dstMin.f, bitsPerSample];
srcBitIndex:
CARD ←
Basics.LongMult[srcMin.s, bitsPerLine] +
Basics.LongMult[srcMin.f, bitsPerSample];
bpl: INTEGER ← bitsPerLine;
flags: PrincOps.BitBltFlags ← initialFlags;
IF sSize > 0
AND
(srcMin.f+fSize) > dstMin.f
AND (dstMin.f+fSize) > srcMin.f
AND
(srcMin.s+sSize) > dstMin.s
AND (dstMin.s+sSize) > srcMin.s
THEN {
flags.disjoint ← FALSE; -- the rectangles overlap
IF srcMin.s=dstMin.s THEN flags.disjointItems ← FALSE; -- so do the items
IF dstMin.s>srcMin.s
OR (dstMin.s=srcMin.s
AND dstMin.f>srcMin.f)
THEN {
delta: CARD ~ Basics.LongMult[sSize-1, bitsPerLine];
flags.direction ← backward; -- reverse direction
bpl ← -bpl;
dstBitIndex ← dstBitIndex + delta;
srcBitIndex ← srcBitIndex + delta;
};
};
bb.dst ← IndexBit[self.base, dstBitIndex];
bb.dstBpl ← bpl;
bb.src ← IndexBit[self.base, srcBitIndex];
bb.srcDesc ← [srcBpl[bpl]];
bb.height ← sSize;
bb.width ← bitsPerSample * fSize;
bb.flags ← flags;
PrincOpsUtils.BITBLT[bb];
};
bbPtr^ ← nullBitBltTable;
boxes[fastMoveBox];
};
DumbFill:
PROC [self: SampleMap, box: Box ← maxBox,
value: Sample, function: Function ← nullFunction] ~ {
sSize: NAT ~ MIN[self.size.s, box.max.s]-box.min.s;
fSize: NAT ~ MIN[self.size.f, box.max.f]-box.min.f;
FOR s:
NAT
IN [0..sSize)
DO
FOR f:
NAT
IN [0..fSize)
DO
offset: Vec ~ [s: s, f: f];
Put[self, box.min.Add[offset], value, function];
ENDLOOP;
ENDLOOP;
};
replicator:
ARRAY [0..4]
OF Sample ~ [
0FFFFH, 05555H, 01111H, 00101H, 00001H];
Fill:
PUBLIC
PROC [self: SampleMap, box: Box ← maxBox,
value: Sample, function: Function ← nullFunction] ~ {
bitsPerSample: NAT ~ self.bitsPerSample;
bitsPerLine: NAT ~ self.bitsPerLine;
IF (bitsPerWord
MOD bitsPerSample)=0
THEN
TRUSTED {
sSize: NAT ~ MIN[self.size.s, box.max.s]-box.min.s;
fSize: NAT ~ MIN[self.size.f, box.max.f]-box.min.f;
dstBitIndex:
CARD ~
Basics.LongMult[box.min.s, bitsPerLine] +
Basics.LongMult[box.min.f, bitsPerSample];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
bitMask: WORD ~ Basics.BITSHIFT[1, bitsPerSample]-1;
replicatedPixel: WORD ← Basics.BITAND[value, bitMask] * replicator[Lg[bitsPerSample]];
IF function = [null, complement]
THEN {
-- Bug in Dorado BITBLT microcode (as of December 4, 1985) --
replicatedPixel ← WORD.LAST-replicatedPixel;
function ← [null, null];
};
bb^ ← nullBitBltTable;
bb.dst ← IndexBit[self.base, dstBitIndex];
bb.dstBpl ← bitsPerLine;
bb.src.word ← @replicatedPixel;
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 0, heightMinusOne: 0];
bb.width ← fSize*bitsPerSample;
bb.height ← sSize;
bb.flags ← [disjoint: TRUE, disjointItems: TRUE, gray: TRUE];
bb.flags.srcFunc ← function.srcFunc;
bb.flags.dstFunc ← function.dstFunc;
PrincOpsUtils.BITBLT[bb];
}
ELSE DumbFill[self: self, box: box, value: value, function: function];
};
FillBoxes:
PUBLIC
PROC [self: SampleMap, boxes: BoxGenerator,
value: Sample ← maxSample, function: Function ← nullFunction] ~ {
bitsPerSample: NAT ~ self.bitsPerSample;
IF (bitsPerWord
MOD bitsPerSample)=0
THEN
TRUSTED {
lgBitsPerSample: NAT ~ Lg[bitsPerSample];
bitsPerLine: NAT ~ self.bitsPerLine;
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
fastFill: BoxAction ~
TRUSTED {
sSize: NAT ~ MIN[self.size.s, box.max.s]-box.min.s;
fSize: NAT ~ MIN[self.size.f, box.max.f]-box.min.f;
dstBitIndex:
CARD ~
Basics.LongMult[box.min.s, bitsPerLine] +
Basics.BITSHIFT[box.min.f, lgBitsPerSample];
bb.dst ← IndexBit[self.base, dstBitIndex];
bb.width ← Basics.BITSHIFT[fSize, lgBitsPerSample];
bb.height ← sSize;
PrincOpsUtils.BITBLT[bb];
};
fastFillW: BoxAction ~ TRUSTED {
sSize: NAT ~ MIN[self.size.s, box.max.s]-box.min.s;
fSize: NAT ~ MIN[self.size.f, box.max.f]-box.min.f;
dstBitIndex: NAT ~ self.base.bit +
Basics.BITSHIFT[box.min.f, lgBitsPerSample];
bb.dst.word ← self.base.word +
Basics.LongMult[box.min.s, wordsPerLine] +
dstBitIndex/bitsPerWord;
bb.dst.bit ← dstBitIndex MOD bitsPerWord;
bb.width ← Basics.BITSHIFT[fSize, lgBitsPerSample];
bb.height ← sSize;
PrincOpsUtils.BITBLT[bb];
};
bitMask: WORD ~ Basics.BITSHIFT[1, bitsPerSample]-1;
replicatedPixel: WORD ← Basics.BITAND[value, bitMask] * replicator[lgBitsPerSample];
IF function = [null, complement]
THEN {
-- Bug in Dorado BITBLT microcode (as of December 4, 1985) --
replicatedPixel ← WORD.LAST-replicatedPixel;
function ← [null, null];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← bitsPerLine;
bb.src.word ← @replicatedPixel;
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 0, heightMinusOne: 0];
bb.flags ← [disjoint: TRUE, disjointItems: TRUE, gray: TRUE];
bb.flags.srcFunc ← function.srcFunc;
bb.flags.dstFunc ← function.dstFunc;
boxes[fastFill];
}
ELSE {
slowFill: BoxAction ~ { DumbFill[self, box, value, function] };
boxes[slowFill];
};
};
Zeros:
PROC [pointer:
LONG
POINTER, count:
NAT]
RETURNS [
BOOL] ~
TRUSTED {
-- Checks for (pointer+i)^ = 0 for i IN [0..count) --
chomp: NAT ~ 8;
scratch: ARRAY [0..chomp) OF WORD ← ALL[0];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
bb^ ← nullBitBltTable;
bb.dstBpl ← 0;
bb.srcDesc ← [srcBpl[chomp*bitsPerWord]];
bb.height ← count/chomp;
bb.width ← chomp*bitsPerWord;
bb.flags ← [disjoint: TRUE, disjointItems: TRUE, dstFunc: or];
bb.dst.word ← @scratch;
bb.src.word ← pointer;
IF bb.height # 0 THEN PrincOpsUtils.BITBLT[bb];
bb.src.word ← pointer + Basics.LongMult[bb.height, chomp];
bb.height ← 1;
bb.width ← count MOD chomp;
IF bb.width # 0 THEN PrincOpsUtils.BITBLT[bb];
FOR i: NAT IN [0..MIN[chomp, count]) DO IF scratch[i]#0 THEN RETURN [FALSE] ENDLOOP;
RETURN [TRUE];
};
Equal:
PUBLIC
PROC [
map1: SampleMap, box1: Box ← maxBox,
map2: SampleMap, box2: Box ← maxBox
]
RETURNS [equal:
BOOL ←
TRUE] ~ {
size: Vec ~ map1.size.Min[box1.max].Sub[box1.min];
size2: Vec ~ map2.size.Min[box2.max].Sub[box2.min];
bandAction:
PROC [band: SampleMap] ~ {
bandSize: Vec ← band.size;
Clear[band];
FOR s:
NAT ← 0, s+bandSize.s
WHILE s<size.s
DO
rem: NAT ~ size.s-s;
IF rem<bandSize.s THEN bandSize.s ← rem;
Transfer[dst: band, src: map1, srcMin: [s: box1.min.s+s, f: box1.min.f], size: bandSize];
Transfer[dst: band, src: map2, srcMin: [s: box2.min.s+s, f: box2.min.f], size: bandSize,
function: [xor, null]];
IF NOT Zeros[band.base.word, WordsForLines[bandSize.s, band.bitsPerLine]]
THEN GOTO NotEqual;
REPEAT NotEqual => equal ← FALSE;
ENDLOOP;
};
IF size.s=0 OR size.f=0 THEN NULL
ELSE IF size.s#size2.s OR size.f#size2.f THEN equal ← FALSE
ELSE {
bandLines: NAT ~ MIN[MAX[4096/size.f, 1], size.s];
bandBitsPerSample: NAT ~ MAX[map1.bitsPerSample, map2.bitsPerSample];
DoWithScratchMap[[s: bandLines, f: size.f], bandBitsPerSample, bandAction];
};
};
IsAll:
PUBLIC
PROC [self: SampleMap, box: Box ← maxBox, value: Sample ← 0]
RETURNS [equal:
BOOL ←
TRUE] ~ {
size: Vec ~ self.size.Min[box.max].Sub[box.min];
bitsPerSample: NAT ~ self.bitsPerSample;
bitMask: Sample ~ Basics.BITSHIFT[1, bitsPerSample]-1;
bandAction:
PROC [band: SampleMap] ~ {
bandSize: Vec ← band.size;
Clear[band];
FOR s:
NAT ← 0, s+bandSize.s
WHILE s<size.s
DO
rem: NAT ~ size.s-s;
IF rem<bandSize.s THEN bandSize.s ← rem;
Transfer[dst: band, src: self, srcMin: [s: box.min.s+s, f: box.min.f], size: bandSize];
IF value#0 THEN Fill[self: band, box: [min: [0, 0], max: bandSize], value: value,
function: [xor, null]];
IF NOT Zeros[band.base.word, WordsForLines[bandSize.s, band.bitsPerLine]]
THEN GOTO NotEqual;
REPEAT NotEqual => equal ← FALSE;
ENDLOOP;
};
IF size.s=0 OR size.f=0 THEN NULL
ELSE IF Basics.BITAND[value, bitMask]#0 THEN equal ← FALSE
ELSE {
bandLines: NAT ~ MIN[MAX[4096/size.f, 1], size.s];
DoWithScratchMap[[s: bandLines, f: size.f], bitsPerSample, bandAction];
};
};
Trim:
PUBLIC
PROC [self: SampleMap, box: Box, background: Sample ← 0]
RETURNS [Box] ~ {
size: Vec ~ self.size.Min[box.max].Sub[box.min];
min: Vec ← box.min; max: Vec ← min.Add[size];
bandAction:
PROC [band: SampleMap] ~ {
bandWords: NAT ~ WordsForLines[band.size.s, band.bitsPerLine];
Clear[band];
WHILE min.s < max.s
-- OR EXIT below --
DO
Transfer[dst: band, src: self, srcMin: [s: max.s-1, f: min.f]];
IF background#0 THEN Fill[self: band, value: background, function: [xor, null]];
IF Zeros[band.base.word, bandWords] THEN max.s ← max.s-1 ELSE EXIT;
ENDLOOP;
WHILE min.s < max.s
-- OR EXIT below --
DO
Transfer[dst: band, src: self, srcMin: [s: min.s, f: min.f]];
IF background#0 THEN Fill[self: band, value: background, function: [xor, null]];
IF Zeros[band.base.word, bandWords] THEN min.s ← min.s+1 ELSE EXIT;
ENDLOOP;
};
DoWithScratchMap[size: [s: 1, f: size.f], bitsPerSample: self.bitsPerSample, action: bandAction];
IF min.s=max.s THEN max.f ← min.f
ELSE
FOR delta:
NAT ← 16, delta/4
UNTIL delta=0
DO
WHILE min.f+delta <= max.f
-- OR EXIT below --
DO
margin: Box ~ [min: [s: min.s, f: max.f-delta], max: max];
IF IsAll[self, margin, background] THEN max.f ← max.f-delta ELSE EXIT;
ENDLOOP;
WHILE min.f+delta <= max.f
-- OR EXIT below --
DO
margin: Box ~ [min: min, max: [s: max.s, f: min.f+delta]];
IF IsAll[self, margin, background] THEN min.f ← min.f+delta ELSE EXIT;
ENDLOOP;
ENDLOOP;
RETURN[[min: min, max: max]];
};
TileFromStipple:
PUBLIC
PROC [stipple:
WORD,
bitsPerSample: BitsPerSample ← 1, value0: Sample ← 0, value1: Sample ← Sample.
LAST,
scratch: SampleMap ←
NIL]
RETURNS [SampleMap] ~ {
easy: BOOL ~ (16 MOD (bitsPerSample*4) = 0) OR (bitsPerSample=8 AND Basics.BITAND[stipple, 3333H] = Basics.BITAND[stipple/4, 3333H]);
size: Vec ~ IF easy THEN [s: 4, f: 16/bitsPerSample] ELSE [s: 8, f: 16];
temp: SampleMap ~ ObtainScratchMap[[4, 4], bitsPerSample];
tile: SampleMap ~ NewSampleMap[size: size, bitsPerSample: bitsPerSample, scratch: scratch];
Clear[tile];
FOR s:
NAT
DECREASING
IN [0..4)
DO
FOR f:
NAT
DECREASING
IN [0..4)
DO
Put[temp, [s: s, f: f], (IF (stipple MOD 2)=0 THEN value0 ELSE value1)];
stipple ← stipple/2;
ENDLOOP;
ENDLOOP;
Tile[self: tile, tile: temp];
ReleaseScratchMap[temp];
RETURN[tile];
};
QR:
TYPE ~
RECORD [quotient:
INTEGER, remainder:
NAT];
DivMod:
PROC [n:
INT, d:
NAT]
RETURNS [qr:
QR] ~ {
-- Number-theoretic: 0 <= remainder < d, n = quotient*d + remainder --
IF d#1
THEN {
nn: Basics.LongNumber ← [li[n]];
qq: Basics.LongNumber ← [lc[0]];
IF nn.li < 0 THEN {nn.highbits ← nn.highbits + d; -- qq.highbits ← CARDINAL.LAST --};
[quotient: qq.lowbits, remainder: qr.remainder] ← Basics.LongDivMod[nn.lc, d];
-- quotient ← qq.li; --
qr.quotient ← LOOPHOLE[qq.lowbits];
}
ELSE RETURN [[quotient: n, remainder: 0]];
};
Mod:
PROC [n:
INT, d:
NAT]
RETURNS [remainder:
NAT] ~ {
-- Number-theoretic: 0 <= remainder < d --
IF d#1
THEN {
nn: Basics.LongNumber ← [li[n]];
WHILE nn.li < 0 DO nn.highbits ← nn.highbits + d ENDLOOP;
WHILE nn.highbits >= d DO nn.highbits ← nn.highbits - d ENDLOOP;
RETURN [Basics.LongDivMod[nn.lc, d].remainder];
}
ELSE RETURN [remainder: 0];
};
QMul:
PROC [a:
INTEGER, b:
CARDINAL]
RETURNS [
INT] ~
INLINE {
IF a >= 0 THEN RETURN [LOOPHOLE[Basics.LongMult[a, b]]]
ELSE RETURN [-LOOPHOLE[Basics.LongMult[-a, b], INT]]
};
DumbTile:
PROC [self: SampleMap, box: Box ← maxBox,
tile: SampleMap, s0, f0:
INT ← 0, phase:
NAT ← 0,
function: Function ← nullFunction] ~ {
size: Vec ~ self.size.Min[box.max].Sub[box.min];
FOR s:
NAT
IN [0..size.s)
DO
dstIndex: Vec ← [s: box.min.s+s, f: box.min.f];
sOffset: INT ~ dstIndex.s-s0;
qr: QR ~ DivMod[sOffset, tile.size.s];
fOffset: INT ~ dstIndex.f-(f0+QMul[qr.quotient, phase]);
srcIndex: Vec ← [s: qr.remainder, f: Mod[fOffset, tile.size.f]];
FOR f:
NAT
IN [0..size.f)
DO
Put[self, dstIndex, Get[tile, srcIndex], function];
dstIndex.f ← dstIndex.f+1;
srcIndex.f ← srcIndex.f+1;
IF srcIndex.f=tile.size.f THEN srcIndex.f ← 0;
ENDLOOP;
ENDLOOP;
};
GeneralTile:
PROC [self: SampleMap, box: Box ← maxBox,
tile: SampleMap, s0, f0:
INT ← 0, phase:
NAT ← 0,
function: Function ← nullFunction] ~ {
boxes: BoxGenerator ~ { boxAction[box] };
GeneralTileBoxes[self, boxes, tile, s0, f0, phase, function];
};
GeneralTileBoxes:
PROC [self: SampleMap, boxes: BoxGenerator,
tile: SampleMap, s0, f0:
INT ← 0, phase:
NAT ← 0,
function: Function ← nullFunction] ~ {
generalTile: BoxAction ~ {
DumbTile[self, box, tile, s0, f0, phase, function];
};
generalTile: BoxAction ~ {
size: Vec ~ self.size.Min[box.max].Sub[box.min];
dstMax: Vec ~ box.min.Add[size];
srcMax: Vec ~ tile.size;
dstRow: Vec ← box.min;
sOffset: INT ~ dstRow.s-s0;
qr: QR ~ DivMod[sOffset, srcMax.s];
fOffset: INT ~ dstRow.f-(f0+QMul[qr.quotient, phase]);
srcRow: Vec ← [s: qr.remainder, f: Mod[fOffset, srcMax.f]];
WHILE dstRow.s < dstMax.s
DO
sSize: NAT ~ MIN[srcMax.s-srcRow.s, dstMax.s-dstRow.s];
dstCol: Vec ← dstRow;
srcCol: Vec ← srcRow;
WHILE dstCol.f < dstMax.f
DO
fSize: NAT ~ MIN[srcMax.f-srcCol.f, dstMax.f-dstCol.f];
Transfer[dst: self, src: tile, dstMin: dstCol, srcMin: srcCol, size: [s: sSize, f: fSize],
function: function];
dstCol.f ← dstCol.f+fSize;
srcCol.f ← 0;
ENDLOOP;
dstRow.s ← dstRow.s+sSize;
srcRow.s ← 0;
srcRow.f ← IF srcRow.f<phase THEN srcRow.f+(tile.size.f-phase) ELSE srcRow.f-phase;
ENDLOOP;
};
IF phase>=tile.size.f THEN phase ← phase MOD tile.size.f;
boxes[generalTile];
};
Tile:
PUBLIC
PROC [self: SampleMap, box: Box ← maxBox,
tile: SampleMap, s0, f0:
INT ← 0, phase:
NAT ← 0,
function: Function ← nullFunction] ~ {
boxes: BoxGenerator ~ { boxAction[box] };
TileBoxes[self, boxes, tile, s0, f0, phase, function];
};
TileBoxes:
PUBLIC
PROC [self: SampleMap, boxes: BoxGenerator,
tile: SampleMap, s0, f0:
INT ← 0, phase:
NAT ← 0,
function: Function ← nullFunction] ~ {
bitsPerSample: NAT ~ self.bitsPerSample;
IF phase=0
AND tile.bitsPerSample=bitsPerSample
AND tile.bitsPerLine=bitsPerWord
AND tile.base.bit=0
AND tile.size.f*bitsPerSample=bitsPerWord
AND tile.size.s
IN [1..16]
AND function#[null, complement]
THEN
TRUSTED {
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
sOffset: CARDINAL ~ Mod[-s0, tile.size.s];
fOffset: CARDINAL ~ Mod[-f0, tile.size.f];
fastTile: BoxAction ~
TRUSTED {
size: Vec ~ self.size.Min[box.max].Sub[box.min];
dstBitIndex:
CARD ~
Basics.LongMult[box.min.s, self.bitsPerLine] +
Basics.LongMult[box.min.f, bitsPerSample];
yOffset: CARDINAL ~ (sOffset+box.min.s) MOD tile.size.s;
bb.dst ← IndexBit[self.base, dstBitIndex];
bb.src.word ← tile.base.word+yOffset;
bb.src.bit ← (fOffset+box.min.f) MOD bitsPerWord;
bb.srcDesc.gray.yOffset ← yOffset;
bb.height ← size.s;
bb.width ← size.f*bitsPerSample;
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← self.bitsPerLine;
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 0, heightMinusOne: tile.size.s-1];
bb.flags ← [disjoint: TRUE, disjointItems: TRUE, gray: TRUE];
bb.flags.srcFunc ← function.srcFunc;
bb.flags.dstFunc ← function.dstFunc;
boxes[fastTile];
}
ELSE
IF tile.bitsPerSample#bitsPerSample
OR tile.size.f*bitsPerSample <
MIN[smallWidth, self.size.f*bitsPerSample]
THEN {
ns: CARDINAL ~ 1;
nf: CARDINAL ~ ((smallWidth+tile.size.f-1)/tile.size.f+bitsPerSample-1)/bitsPerSample;
macroTileSize: Vec ~ [s: ns*tile.size.s, f: nf*tile.size.f];
macroTileAction:
PROC [macroTile: SampleMap] ~ {
GeneralTile[self: macroTile, tile: tile, phase: phase];
GeneralTileBoxes[self: self, boxes: boxes, tile: macroTile, s0: s0, f0: f0, phase: ns*phase, function: function];
};
DoWithScratchMap[macroTileSize, bitsPerSample, macroTileAction];
}
ELSE GeneralTileBoxes[self, boxes, tile, s0, f0, phase, function];
};
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] ← NewSamples[length: length, scratch: new[i]];
ENDLOOP;
new.length ← length;
RETURN[new];
};
nScratchPixelBuffers: NAT ~ 6;
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.maxLength >= length THEN {
scratchPixelBuffers[i] ← NIL;
buf.length ← length;
RETURN [buf];
};
ENDLOOP;
RETURN[NewPixels[samplesPerPixel: samplesPerPixel, length: length]]
};
ReleaseScratchPixels:
PUBLIC
ENTRY
PROC [pixels: PixelBuffer] ~ {
r: PixelBuffer ← samples;
samples.length ← 0;
FOR i: NAT IN [0..nScratchPixelBuffers) UNTIL r = NIL DO
-- Push least-recently-used towards end. --
t: PixelBuffer ← scratchPixelBuffers[i];
scratchPixelBuffers[i] ← r;
r ← t;
IF r = samples THEN RETURN WITH ERROR MultipleReleaseOfScratch;
ENDLOOP;
};
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, size: Vec, maxSample: PixelProc,
scratch: PixelMap ←
NIL]
RETURNS [PixelMap] ~ {
new: PixelMap ← scratch;
IF new=
NIL
OR new.samplesPerPixel#samplesPerPixel
THEN
new ← NEW[PixelMapRep[samplesPerPixel]];
FOR i:
NAT
IN[0..samplesPerPixel)
DO
bitsPerSample: BitsPerSample ~
SELECT maxSample[i]
FROM
<2 => 1, <4 => 2, <16 => 4, <256 => 8, ENDCASE => BitsPerSample.LAST;
new[i] ← NewSampleMap[size: size, bitsPerSample: bitsPerSample, scratch: new[i]];
ENDLOOP;
new.size ← size;
RETURN[new];
};
GetPixels:
PUBLIC
PROC [self: PixelMap, min: Vec ← zeroVec, delta: Vec ← [s: 0, f: 1],
pixels: PixelBuffer, start:
NAT ← 0, count:
NAT ← maxCount] ~ {
FOR i:
NAT
IN [0..self.samplesPerPixel)
DO
GetSamples[self[i], min, delta, pixels[i], start, count];
ENDLOOP;
};
PutPixels:
PUBLIC
PROC [self: PixelMap, min: Vec ← zeroVec, delta: Vec ← [s: 0, f: 1],
pixels: PixelBuffer, start:
NAT ← 0, count:
NAT ← maxCount,
function: Function ← nullFunction] ~ {
FOR i:
NAT
IN [0..self.samplesPerPixel)
DO
PutSamples[self[i], min, delta, pixels[i], start, count, function];
ENDLOOP;
};
realLastInt:
REAL ←
REAL[
LAST[
INT]];
Floor:
PROC[a:
REAL]
RETURNS[c:
REAL] ~ {
IF ABS[a] >= realLastInt THEN RETURN [a];
c ← REAL[Real.Fix[a]];
IF c>a THEN RETURN[c-1] ELSE RETURN[c]
};
ScaledFromRealMod:
PROC [d:
REAL, m:
CARDINAL]
RETURNS [
INT] ~ {
s: Basics.LongNumber ← [li[0]];
IF m # 0
THEN {
modulus: REAL ~ m;
residue: REAL ← IF d IN [0..modulus) THEN d ELSE (d-modulus*Floor[d/modulus]);
s.li ← Real.Round[Real.FScale[residue, Basics.bitsPerWord]];
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 ~ Sample[0..1B];
Sample8: TYPE ~ Sample[0..377B];
RawSamples1: TYPE ~ RECORD [PACKED SEQUENCE COMPUTED CARDINAL OF Sample1];
RawSamples8: TYPE ~ RECORD [PACKED SEQUENCE COMPUTED CARDINAL OF Sample8];
Pointer1: TYPE ~ LONG POINTER TO RawSamples1;
Pointer8: TYPE ~ LONG POINTER TO RawSamples8;
Resample:
PUBLIC
PROC [self: PixelMap, m: Transformation, interpolate:
BOOL,
boxes: BoxGenerator, bounds: Box, action: ResampleAction] ~ {
samplesPerPixel: NAT ~ self.samplesPerPixel;
sSize: NAT ~ self.size.s; -- source size in slow (scan line) direction
fSize: NAT ~ self.size.f; -- source size in fast (pixel) direction
ssDelta: Basics.LongNumber; -- source delta s for destination f increment
fsDelta: Basics.LongNumber; -- source delta f for destination f increment
sfDelta: Basics.LongNumber; -- source delta s for destination s increment
ffDelta: Basics.LongNumber; -- source delta f for destination s increment
d0: 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: 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]];
d1: Vec ← d0; -- destination position at start of scan line
s1: Basics.LongNumber ← s0; -- source s corresponding to d1
f1: Basics.LongNumber ← f0; -- source f corresponding to d1
WHILE d1.s<box.min.s
DO
d1.s ← d1.s+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;
IF d1.s=box.min.s THEN { d0 ← d1; s0.lc ← s1.lc; f0.lc ← f1.lc } ELSE ERROR;
WHILE d1.f<box.min.f
DO
d1.f ← d1.f+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;
IF d1.f=box.min.f THEN NULL ELSE ERROR;
pixels.length ← count;
--For each scan line of box--
DO
FOR i:
NAT
IN[0..samplesPerPixel)
DO
map: SampleMap ~ self[i];
samples: SampleBuffer ~ pixels[i];
s: Basics.LongNumber ← s1;
f: Basics.LongNumber ← f1;
IF map.base.bit=0
AND (map.bitsPerLine
MOD bitsPerWord)=0
AND
map.bitsPerSample=8
THEN {
base: Pointer8 ~ LOOPHOLE[map.base.word];
wordsPerLine: NAT ~ map.bitsPerLine/bitsPerWord;
result: LONG POINTER TO RawSamples ~ InlinePointerToSamples[samples, 0, count];
IF sfup.lc=0
THEN {
line: Pointer8 ~ base+Basics.LongMult[s.hi, wordsPerLine];
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 {
FOR k:
NAT
IN[0..count)
DO
line: Pointer8 ~ base+Basics.LongMult[s.hi, wordsPerLine];
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;
};
}
ELSE {
-- the slow but general way
FOR k:
NAT
IN[0..count)
DO
samples[k] ← Get[map, [s: s.hi, f: 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;
};
ENDLOOP;
action[pixels, d1];
d1.s ← d1.s+1; IF NOT d1.s<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: 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;
d1: Vec ← d0; -- destination position at start of scan line
s1: Basics.LongNumber ← s0; -- source s corresponding to d1
f1: Basics.LongNumber ← f0; -- source f corresponding to d1
WHILE d1.s<box.min.s
DO d1.s ← d1.s+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;
IF d1.s=box.min.s THEN { d0 ← d1; s0.lc ← s1.lc; f0.lc ← f1.lc } ELSE ERROR;
WHILE d1.f<box.min.f
DO d1.f ← d1.f+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;
IF d1.f=box.min.f THEN NULL ELSE ERROR;
pixels.length ← count;
--For each scan line of box--
DO
FOR i:
NAT
IN[0..samplesPerPixel)
DO
map: SampleMap ~ self[i];
samples: SampleBuffer ~ pixels[i];
s: Basics.LongNumber ← s1;
f: Basics.LongNumber ← f1;
IF map.base.bit=0
AND (map.bitsPerLine
MOD bitsPerWord)=0
AND
map.bitsPerSample=8
THEN {
base: Pointer8 ~ LOOPHOLE[map.base.word];
wordsPerLine: NAT ~ map.bitsPerLine/bitsPerWord;
result: LONG POINTER TO RawSamples ~ InlinePointerToSamples[samples, 0, count];
FOR k:
NAT
IN[0..count)
DO
-- Loop overhead (23 cycles) --
-- Calculate i* (34 cycles) --
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* (68 cycles) --
w11: CARDINAL ~ Basics.HighHalf[Basics.LongMult[s.lo, f.lo]];
w10: CARDINAL ~ s.lo-w11;
w01: CARDINAL ~ f.lo-w11;
w00: CARDINAL ~ 0-w01-w10-w11;
v00, v01, v10, v11, value: CARDINAL;
-- Calculate line* (80 cycles) --
line0: Pointer8 ~ base+Basics.LongMult[is0, wordsPerLine];
line1: Pointer8 ~ base+Basics.LongMult[is1, wordsPerLine];
-- Fetch v* (52 cycles) --
TRUSTED { v00 ← line0[if0]; v01 ← line0[if1]; v10 ← line1[if0]; v11 ← line1[if1]; };
-- Calculate value (143 cycles) --
value ←
IF w00#0
THEN Basics.HighHalf[
Basics.LongMult[w00, v00] + Basics.LongMult[w01, v01] +
Basics.LongMult[w10, v10] + Basics.LongMult[w11, v11]
] ELSE v00;
-- Store result (14 cycles) --
TRUSTED { result[k] ← value };
-- Bump s and f (66 cycles) --
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;
-- Total (480 cycles): 30.7 microseconds/sample; 8 seconds for 512*512 samples --
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[Basics.LongMult[s.lo, f.lo]];
w10: CARDINAL ~ s.lo-w11;
w01: CARDINAL ~ f.lo-w11;
w00: CARDINAL ~ 0-w01-w10-w11;
v00, v01, v10, v11, value: CARDINAL;
v00 ← Get[map, [s: is0, f: if0]];
v01 ← Get[map, [s: is0, f: if1]];
v10 ← Get[map, [s: is1, f: if0]];
v11 ← Get[map, [s: is1, f: if1]];
value ←
IF w00=0
THEN v00
ELSE Basics.HighHalf[
Basics.LongMult[w00, v00] + Basics.LongMult[w01, v01] +
Basics.LongMult[w10, v10] + Basics.LongMult[w11, v11]];
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, d1];
d1.s ← d1.s+1; IF NOT d1.s<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]] ← m.InverseTransformVec[[0, 1] !
Real.RealException => { rs ← rf ← 0; CONTINUE }];
A singular transformation means the image can't be shown anyway.
sfDelta.li ← ScaledFromRealMod[rs, sSize];
ffDelta.li ← ScaledFromRealMod[rf, fSize];
[[rs, rf]] ← m.InverseTransformVec[[1, 0] !
Real.RealException => { rs ← rf ← 0; CONTINUE }];
ssDelta.li ← ScaledFromRealMod[rs, sSize];
fsDelta.li ← ScaledFromRealMod[rf, fSize];
-- Set initial position --
[[rs, rf]] ← m.InverseTransform[[d0.s+0.5, d0.f+0.5] !
Real.RealException => { rs ← rf ← 0; CONTINUE }];
IF interpolate THEN { rs ← rs-0.5; rf ← rf-0.5 };
s0.li ← ScaledFromRealMod[rs, sSize];
f0.li ← ScaledFromRealMod[rf, fSize];
boxes[IF interpolate THEN boxActionInterpolatedSamples ELSE boxActionPointSamples];
ReleaseScratchPixels[pixels];
};
END.