ScanConvertImpl.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Frank Crow, March 28, 1986 11:09:09 am PST
Scan conversion operations on pixel buffers.
DIRECTORY
Atom       USING [GetPropFromList],
Basics       USING [LongMult, BITSHIFT, BITAND, logBitsPerWord,
          bitsPerWord, BITOR, BITNOT, BytePair],
PrincOps      USING [DstFunc, SrcFunc, BitAddress, BBTableSpace, BBptr],
PrincOpsUtils    USING [AlignedBBTable, BITBLT],
Real       USING [RoundC, FixI, FixC, Float],
Terminal      USING [ModifyColorFrame, Virtual],
ImagerColor     USING [RGB],
SampleMapOps    USING [SampleMap, Function],
Vector2      USING [VEC],
Pixels       USING [PixelBuffer, SampleSet, GetSampleSet, SampleSetSequence,
          TerminalFromBuffer, GetPixel, PutPixel, PixelOp,
          SumLessProd, ByteAvrgWgtd, XfmMapPlace, SubMap],
ScanConvert     USING [IntVec2, IntVec2Sequence, RealSequence,
          Spot, SpotSequence, IntRGB, IntRGBT,
          justNoticeable];
ScanConvertImpl: CEDAR PROGRAM
IMPORTS Atom, Basics, PrincOpsUtils, Terminal, Real, Pixels
EXPORTS ScanConvert
~ BEGIN
Type Definitions
PixelBuffer: TYPE ~ Pixels.PixelBuffer;
RGB: TYPE ~ ImagerColor.RGB;        -- RECORD[ R, G, B: REAL]
IntRGB: TYPE ~ ScanConvert.IntRGB;      -- RECORD[ r, g, b: CARDINAL]
IntRGBT: TYPE ~ ScanConvert.IntRGBT;     -- RECORD[ r, g, b, t: CARDINAL]
Vec2: TYPE ~ Vector2.VEC;         -- RECORD[x, y: REAL]
IntVec2: TYPE ~ ScanConvert.IntVec2;     -- RECORD[x, y: INTEGER]
IntVec2Sequence: TYPE ~ ScanConvert.IntVec2Sequence;
RealSequence: TYPE ~ ScanConvert.RealSequence;
SampleSet: TYPE ~ Pixels.SampleSet;
SampleSetSequence: TYPE ~ Pixels.SampleSetSequence;
Spot: TYPE ~ ScanConvert.Spot;
SpotSequence: TYPE ~ ScanConvert.SpotSequence;
BytePair: TYPE ~ Basics.BytePair;
Function: TYPE ~ SampleMapOps.Function;
IncrementalDesc: TYPE ~ RECORD [val, intInc, intSgn, fracInc, fracRng, fracPos: INTEGER];
IncDescSeq: TYPE ~ RECORD [SEQUENCE length: NAT OF IncrementalDesc];
ScanConvertError: PUBLIC SIGNAL [reason: ATOM] = CODE;
Utility Procedures
bltValue: ARRAY [0..4] OF CARDINAL;
bbspace: ARRAY[0..4) OF PrincOps.BBTableSpace;
bb: ARRAY[0..4) OF PrincOps.BBptr;
bbWdsPerLine: ARRAY[0..4) OF NAT;
lgBitsPerWord: NAT ~ Basics.logBitsPerWord;
bitsPerWord: NAT ~ Basics.bitsPerWord;
Extend: PUBLIC PROC[seq: REF RealSequence, newLength: NAT] RETURNS[REF RealSequence]~{
newSeq: REF RealSequence ← NEW[ RealSequence[newLength] ];
FOR i: NAT IN [0..seq.length) DO newSeq[i] ← seq[i]; ENDLOOP;
newSeq.length ← seq.length; seq ← newSeq;
RETURN[seq];
};
Sqr: PROCEDURE [number: INTEGER] RETURNS [INTEGER] ~ INLINE {
RETURN[number * number]; };
Log2: PROC [n: INT] RETURNS [lg: NAT ← 0] ~ { -- finds log base 2 of input (from M. Plass)
nn: LONG CARDINAL ~ n;
k: LONG CARDINAL ← 1;
UNTIL k=0 OR k>= nn DO
lg ← lg + 1;
k ← k + k;
ENDLOOP;
};
Power: PUBLIC PROC[ value: INTEGER, power: NAT] RETURNS[ result: INTEGER ] ~ {
binaryCount: NAT ← power;   -- makes highlights same size as those by ShadePt
temp: REAL ← 1.0;
val: REAL ← Real.Float[value] / 256.0;
WHILE binaryCount > 0 DO
IF Basics.BITAND[binaryCount, 1] = 1 THEN temp ← temp * val;
val ← val * val;
binaryCount ← binaryCount/2;
ENDLOOP;
result ← Real.RoundC[temp*256.0];
};
SetUpConstBlt: PROC[buf: PixelBuffer, y: INTEGER, color: SampleSet] ~ TRUSTED {
Assumes 8-bit pixels
j: NAT ← 0;
FOR i: NAT IN [0..buf.pixels.length) DO
dest: SampleMapOps.SampleMap ← buf.pixels[i].subMap.sampleMap;
bbWdsPerLine[i] ← Basics.BITSHIFT[dest.bitsPerLine, -4];
IF Basics.BITAND[dest.bitsPerLine, 15] # 0 THEN bbWdsPerLine[i] ← bbWdsPerLine[i] + 1;
IF buf.pixels[i].df = 2
THEN IF dest.base.bit = 0
THEN { bltValue[i] ← 256*color[j] + color[j+1]; j ← j + 2; } -- interleaved RG
ELSE bltValue[i] ← 0   -- ignore interleaved map off word boundary
ELSE { bltValue[i] ← color[j] * 00101H;   j ← j + 1; }; -- replicate value
bb[i] ← PrincOpsUtils.AlignedBBTable[@bbspace[i]];
bb[i]^ ← [   -- set up to point to beginning of scan line at polygon bottom
dst: [word: dest.base.word + Basics.LongMult[y, bbWdsPerLine[i]], bit: 0],
dstBpl: dest.bitsPerLine,
src: [word: @bltValue[i], bit: 0],
srcDesc: [gray[[yOffset: 0, widthMinusOne: 0, heightMinusOne: 0]]],
height: 1,
width: 1,
flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: TRUE, srcFunc: null, dstFunc: null]
];
ENDLOOP;
};
DoConstBlt: PROC[buf: PixelBuffer, left, right: INTEGER] ~ TRUSTED {
IF left > right THEN [left, right] ← Swap[left, right];  -- allow screwed up scan segments
FOR i: NAT IN [0..buf.samplesPerPixel) DO
scanLinePtr: LONG POINTER ← bb[i].dst.word;
IF buf.pixels[i].df = 2   -- interleaved maps, write the one which is word-aligned
THEN IF buf.pixels[i].subMap.sampleMap.base.bit = 0
THEN {
bb[i].dst ← [word: scanLinePtr + left, bit: 0];
bb[i].width ← (right - left + 1) * 16;
}
ELSE LOOP      -- not word-aligned, ignore
ELSE {
bb[i].dst ← [
word: scanLinePtr + Basics.BITSHIFT[left,-1],
bit: Basics.BITSHIFT[Basics.BITAND[left,1], 3]
];
bb[i].width ← (right - left + 1) * 8;
};
PrincOpsUtils.BITBLT[bb[i]];
bb[i].dst.word ← scanLinePtr + bbWdsPerLine[i]; -- increment scan pointer for next call
ENDLOOP;
};
GetSlopeIncr: PROC[pBeg, pEnd: IntVec2] RETURNS[incr: IncrementalDesc] ~ {
xDiff: INTEGER ← pEnd.x - pBeg.x; yDiff: INTEGER ← pEnd.y - pBeg.y;
IF yDiff <= 0 THEN yDiff ← LAST[NAT]; -- zero height edge, let increments => 0
incr.intInc ← xDiff / yDiff;    -- get integer increment
incr.intSgn ← SGN[xDiff];     -- get sign of integer increment
xDiff ← xDiff - incr.intInc * yDiff;    -- subtract out effect of integer increment
incr.fracInc ← 2 * ABS[xDiff];      -- fractional increment
incr.fracRng ← 2 * yDiff;        -- range to increment over
incr.fracPos ← incr.fracInc - incr.fracRng/2;  -- start at halfway position (midpixel)
incr.val ← pBeg.x;         -- initial value
};
UpdateIncr: PROC[incr: IncrementalDesc] RETURNS [IncrementalDesc] ~ {
Extended Bresenham incrementation
IF incr.fracPos > 0 THEN {           -- fractional position overflowed
incr.fracPos ← incr.fracPos - incr.fracRng;        -- reset fractional part
incr.val ← incr.val + incr.intSgn;          -- bump integer part
};
incr.val ← incr.val + incr.intInc;        -- increment integer part
incr.fracPos ← incr.fracPos + incr.fracInc;     -- increment fractional position
RETURN[ incr ];
};
ditherTable: ARRAY [0..4) OF ARRAY [0..4) OF NAT
             [[0,12,3,15], [8,4,11,7], [2,14,1,13], [10,6,9,5]];
DitheredRGB: PUBLIC PROC[renderMode: ATOM, x, y, red, grn, blu: INTEGER] RETURNS[INTEGER] ~ {
val2R, val2G, val2B, pixelValue: NAT;
SELECT renderMode FROM
$PseudoClr => {
Ordered dither for crude looks at full-color
threshold: NAT ← ditherTable[ Basics.BITAND[x,3] ][ Basics.BITAND[y,3] ];
valR: NAT ← Basics.BITSHIFT[ Basics.BITSHIFT[red,2] + red, -4 ];  -- (red * 5) / 16
valG: NAT ← Basics.BITSHIFT[ Basics.BITSHIFT[grn,2] + Basics.BITSHIFT[grn,1], -4 ];
valB: NAT ← Basics.BITSHIFT[ Basics.BITSHIFT[blu,2] + blu, -4 ];  -- (blu * 5) / 16
val2R ← Basics.BITSHIFT[valR,-4];           -- valR / 16
IF Basics.BITAND[valR,15] > threshold THEN val2R ← val2R + 1;  -- valr MOD 16
val2G ← Basics.BITSHIFT[valG,-4];
IF Basics.BITAND[valG,15] > threshold THEN val2G ← val2G + 1;
val2B ← Basics.BITSHIFT[valB,-4];
IF Basics.BITAND[valB,15] > threshold THEN val2B ← val2B + 1;
RETURN[ MIN[ 255,
Basics.BITSHIFT[val2R,5] + Basics.BITSHIFT[val2R,3] + Basics.BITSHIFT[val2R,1]
+ Basics.BITSHIFT[val2G,2] + Basics.BITSHIFT[val2G,1]
+ val2B + 2 ] ];     --val2R*42 + val2G*6 + val2B + 2
};
$Dithered => {
Ordered dither for crude looks at full-color using Imager's color map
threshold: NAT ← ditherTable[x MOD 4][y MOD 4];
valR: NAT ← 4* red / 16;
valG: NAT ← 5* grn / 16;
valB: NAT ← 3* blu / 16;
val2R ← valR/16; IF valR MOD 16 > threshold THEN val2R ← val2R + 1;
val2G ← valG/16; IF valG MOD 16 > threshold THEN val2G ← val2G + 1;
val2B ← valB/16; IF valB MOD 16 > threshold THEN val2B ← val2B + 1;
pixelValue ← val2R*24 + val2G*4 + val2B;
IF pixelValue >= 60 THEN pixelValue ← pixelValue + 135;  -- move to top of map
RETURN[ MIN[255, pixelValue] ];
};
ENDCASE => SIGNAL ScanConvertError[$BadRenderMode];
RETURN[ 255 ];
};
MappedRGB: PUBLIC PROC[renderMode: ATOM, clr: IntRGB] RETURNS[NAT] ~ {
SELECT renderMode FROM 
$Dithered  => {
mapVal: NAT ← Real.FixC[clr.r*5.0/255.0]*24
     + Real.FixC[clr.g*6.0/255.0]*4
     + Real.FixC[clr.b*4.0/255.0];
IF mapVal >= 60 THEN mapVal ← mapVal + 135;   -- move to top of map
RETURN[ mapVal ];
};
$PseudoClr => {
fctr: REAL ← 5.99 / 255.0; fctr2: REAL ← 6.99 / 255.0;
RETURN[ Real.FixC[clr.r*fctr]*42 + Real.FixC[clr.g*fctr2]*6 + Real.FixC[clr.b*fctr] +2 ];
};
ENDCASE  => SIGNAL ScanConvertError[$BadRenderMode];
RETURN[ 255 ];
};
RGBFromMap: PUBLIC PROC[renderMode: ATOM, value: NAT] RETURNS[IntRGB] ~ {
SELECT renderMode FROM
$Dithered  => {
IF value >= 60 THEN value ← value - 135;   -- move from top of map
value ← MIN[119, value];
RETURN[ [
r: (value / 24) * 256 / 5,
g: (value MOD 24) / 4 * 256 / 6,
b: (value MOD 4) * 256 / 6
] ];
};
$PseudoClr => {
value ← MIN[253, value] - 2;
RETURN[ [
r: (value / 42) * 256 / 6,
g: (value MOD 42) / 6 * 256 / 7,
b: (value MOD 6) * 256 / 6
] ];
};
ENDCASE  => SIGNAL ScanConvertError[$BadRenderMode];
RETURN[[255, 255, 255]];
};
Swap: PROCEDURE [first, second: INTEGER] RETURNS [INTEGER, INTEGER] = {
RETURN [second, first];
};
BitAddr: UNSAFE PROC [lineStart: LONG POINTER, pixel: CARDINAL, lgBitsPerPixel: INTEGER] RETURNS [PrincOps.BitAddress] ~ UNCHECKED {
RETURN [[
word: lineStart + Basics.BITSHIFT[pixel, lgBitsPerPixel-lgBitsPerWord],
bit: Basics.BITAND[Basics.BITSHIFT[pixel, lgBitsPerPixel], bitsPerWord-1]
]]
};
SGN: PROCEDURE [number: INTEGER] RETURNS [INTEGER] = INLINE {
IF number >= 0 THEN RETURN[1] ELSE RETURN[-1];
};
Point/Spot Operations
oldPixel: SampleSet ← Pixels.GetSampleSet[4];   -- own memory for pixel storage
newPixel: SampleSet ← Pixels.GetSampleSet[4];
justNoticeable: REAL ~ ScanConvert.justNoticeable;
PutSpot: PUBLIC PROC [ buf: PixelBuffer, spot: Spot, op, renderMode: ATOM ] ~ {
PutPixel: PROC[] ~ {
DoIt: PROC[] ~ { Pixels.PutPixel[ buf, spot.x, spot.y, newPixel ]; };
IF vt # NIL
THEN {
x, y: NAT;
[x, y] ← Pixels.XfmMapPlace[buf.pixels[buf.samplesPerPixel-1], spot.x, spot.y ];
Terminal.ModifyColorFrame[vt, DoIt, x, y, x+1, y+1];
}
ELSE DoIt[];
};
GetPixel: PROC[] RETURNS[pixel: SampleSet] ~ {
DoIt: PROC[] ~ { pixel ← Pixels.GetPixel[ buf, spot.x, spot.y, oldPixel ]; };
IF vt # NIL
THEN {
x, y: NAT;
[x, y] ← Pixels.XfmMapPlace[buf.pixels[buf.samplesPerPixel-1], spot.x, spot.y ];
Terminal.ModifyColorFrame[vt, DoIt, x, y, x+1, y+1];
}
ELSE DoIt[];
};
vt : Terminal.Virtual ← Pixels.TerminalFromBuffer[buf];
alpha: REF NATNARROW[ Atom.GetPropFromList[buf.props, $Alpha] ];
depth: REF NATNARROW[ Atom.GetPropFromList[buf.props, $Depth] ];
oldClr: ScanConvert.IntRGB;
newClr: ScanConvert.IntRGBT;
addOn: NAT ← 0;
cvrge: NAT;
IF alpha # NIL THEN addOn ← addOn + 1;
IF depth # NIL THEN addOn ← addOn + 1;
IF alpha # NIL THEN {    -- Using Alpha buffer
IF spot.coverage < justNoticeable THEN RETURN; -- any changes would be insignificant
IF op = $WriteUnder OR op = $WriteLineUnder OR spot.coverage < 1.0 - justNoticeable
THEN oldPixel ← GetPixel[];           -- need to blend pixels
IF (op = $WriteUnder OR op = $WriteLineUnder) AND oldPixel[alpha^] = 255 THEN RETURN; -- pixel already covered
SELECT renderMode FROM          -- get rgb color from old pixel
$Dithered, $PseudoClr => oldClr ← RGBFromMap[ renderMode, oldPixel[0] ];
$FullClr, $Dorado24  => oldClr ← [ oldPixel[0], oldPixel[1], oldPixel[2] ];
$Grey   => oldClr ← [ oldPixel[0], oldPixel[0], oldPixel[0] ];
ENDCASE  => SIGNAL ScanConvertError[$BadRenderMode];
newClr ← spot.proc[spot];          -- extract color from spot
cvrge ← Real.RoundC[spot.coverage * 255.0];
IF newClr.t > 0 THEN cvrge ← cvrge * (255 - newClr.t) / 256;
IF op = $WriteUnder OR op = $WriteLineUnder
THEN IF oldPixel[alpha^] # 0
THEN {    -- previous coverage blend under using VonNeumann rounding
IF op = $WriteLineUnder
THEN cvrge ← MAX[ 0, INTEGER[cvrge] - oldPixel[alpha^] ]  
ELSE cvrge ← MIN[ cvrge, 255 - oldPixel[alpha^] ]; -- only what's uncovered
newClr.r ← Basics.BITOR[ oldClr.r + cvrge * newClr.r / 256, 1 ];
newClr.g ← Basics.BITOR[ oldClr.g + cvrge * newClr.g / 256, 1 ];
newClr.b ← Basics.BITOR[ oldClr.b + cvrge * newClr.b / 256, 1 ];
cvrge ← Basics.BITOR[ cvrge + oldPixel[alpha^], 1 ];  -- store total coverage
}
ELSE {              -- first surface written
newClr.r ← cvrge * newClr.r / 256;
newClr.g ← cvrge * newClr.g / 256;
newClr.b ← cvrge * newClr.b / 256;
}
ELSE {              -- Writing over
cvrge ← Pixels.SumLessProd[ oldPixel[alpha^], cvrge ]; -- sum less overlap estimate
newClr.r ← Pixels.ByteAvrgWgtd[ b1: oldPixel[1], b2: newClr.r, wgt: cvrge ]; -- blend
newClr.g ← Pixels.ByteAvrgWgtd[ b1: oldPixel[2], b2: newClr.g, wgt: cvrge ];
newClr.b ← Pixels.ByteAvrgWgtd[ b1: oldPixel[3], b2: newClr.b, wgt: cvrge ];
};
}
ELSE newClr ← spot.proc[spot];    -- No alpha buffer, just extract color from spot
SELECT renderMode FROM 
$FullClr, $Dorado24  => {
IF newPixel.maxLength < 3+addOn THEN newPixel ← Pixels.GetSampleSet[3+addOn];
newPixel[0]  ← newClr.r;
newPixel[1] ← newClr.g;
newPixel[2] ← newClr.b;
newPixel.length ← 3+addOn;
};
$Grey   => {
IF newPixel.maxLength < 1+addOn THEN newPixel ← Pixels.GetSampleSet[1+addOn];
newPixel[0] ← (newClr.r + newClr.g + newClr.b) / 3;
newPixel.length ← 1+addOn;
};
$Dithered, $PseudoClr => {
IF newPixel.maxLength < 1+addOn THEN newPixel ← Pixels.GetSampleSet[1+addOn];
newPixel[0] ← DitheredRGB[ renderMode, spot.x, spot.y,
          newClr.r, newClr.g, newClr.b ];
newPixel.length ← 1+addOn;
};
ENDCASE  => ScanConvertError[$BadRenderMode];
IF depth # NIL THEN newPixel[depth^] ← oldPixel[depth^]; -- no way to get it, currently
IF alpha # NIL
THEN { newPixel[alpha^] ← cvrge; PutPixel[]; }
ELSE Pixels.PixelOp[ buf, [spot.x, spot.y, 1, 1], newPixel, op ];
};
GetSpot: PUBLIC PROC [ buf: PixelBuffer, spot: Spot, renderMode: ATOM] RETURNS[ Spot ] ~ {
size: NAT ← 3;
alpha: REF NATNARROW[ Atom.GetPropFromList[buf.props, $Alpha] ];
depth: REF NATNARROW[ Atom.GetPropFromList[buf.props, $Depth] ];
oldPixel ← Pixels.GetPixel[buf, spot.x, spot.y, oldPixel];
IF alpha # NIL THEN spot.coverage ← oldPixel[alpha^] / 256.0;
IF depth # NIL THEN { size ← 4; spot.val[3] ← oldPixel[depth^]; };
IF spot.val = NIL OR spot.val.maxLength < size THEN spot.val ← NEW[RealSequence[size]];
SELECT renderMode FROM 
$FullClr, $Dorado24  => {
spot.val[0] ← oldPixel[0] / 256.0;
spot.val[1] ← oldPixel[1] / 256.0;
spot.val[2] ← oldPixel[2] / 256.0;
};
$Grey   => {
spot.val[2] ← spot.val[1] ← spot.val[0] ← oldPixel[0] / 256.0;
};
$Dithered, $PseudoClr => {
clr: IntRGB ← RGBFromMap[renderMode, oldPixel[0] ];
spot.val[0] ← clr.r / 256.0;
spot.val[1] ← clr.g / 256.0;
spot.val[2] ← clr.b / 256.0;
};
ENDCASE  => ScanConvertError[$BadRenderMode];
spot.val.length ← size;
RETURN[spot];
};
Scan Conversion for Lines and Scan Segments
PutLine: PUBLIC PROC [ buf: PixelBuffer, p1, p2: IntVec2, color: SampleSet ] ~ {
DoLine: PROC[] ~ {
FOR i: NAT IN [0..buf.pixels.length) DO   -- do one spot for each 8 bits or less
IF buf.pixels[i].df = 1
THEN DrawLine[ buf.pixels[i], p1, p2, color[i] ]
ELSE IF buf.pixels[i].subMap.sampleMap.base.bit = 0    -- 16-bit pixel map
THEN DrawLine[ buf.pixels[i], p1, p2, color[i] * 256 + color[i+1] ];
ENDLOOP;
};
Lock out cursor
vt : Terminal.Virtual ← Pixels.TerminalFromBuffer[buf];
IF vt # NIL
THEN {
x1, y1, x2, y2: NAT;
[x1, y1] ← Pixels.XfmMapPlace[buf.pixels[buf.samplesPerPixel-1], p1.x, p1.y ];
[x2, y2] ← Pixels.XfmMapPlace[buf.pixels[buf.samplesPerPixel-1], p2.x, p2.y ];
Terminal.ModifyColorFrame[vt, DoLine, MIN[x1, x2], MIN[y1, y2],
            MAX[x1, x2], MAX[y1, y2] ];
}
ELSE DoLine[];
};
Scan Conversion for Convex Areas
ConstantPoly: PUBLIC PROC [buf: PixelBuffer, color: SampleSet,
         plygn: REF IntVec2Sequence] ~ {
vt : Terminal.Virtual ← Pixels.TerminalFromBuffer[buf];
highest, lowest, leftmost, rightmost, firstVtx: NAT ← 0;
DoItConstant: PROC[] ~ {
yPosn: NAT;        -- current scan line
nxtLVtx, nxtRVtx, rVtx, lVtx, nxtRHeight, nxtLHeight: NAT ← 0;
left, right: IncrementalDesc;   -- incremental descriptions for left and right edges
IncrementalDesc: TYPE ~ RECORD[val, intInc, intSgn, fracInc, fracRng, fracPos: INTEGER];
nxtLVtx ← nxtRVtx ← rVtx ← lVtx ← firstVtx;    -- set pointers to bottom vertex
yPosn ← nxtRHeight ← nxtLHeight ← lowest;
SetUpConstBlt[buf, yPosn, color];        -- set up scan segment blt
WHILE yPosn < highest DO          -- work up through vertices
WHILE yPosn >= nxtLHeight DO        -- next left vertex reached?
lVtx ← nxtLVtx; nxtLVtx ← (lVtx + plygn.length - 1) MOD plygn.length;
nxtLHeight ← plygn[nxtLVtx].y;
left ← GetSlopeIncr[ plygn[lVtx], plygn[nxtLVtx] ];
ENDLOOP;
WHILE yPosn >= nxtRHeight DO     -- next right vertex reached?
rVtx ← nxtRVtx; nxtRVtx ← (rVtx + 1) MOD plygn.length;
nxtRHeight ← plygn[nxtRVtx].y;
right ← GetSlopeIncr[ plygn[rVtx], plygn[nxtRVtx] ];
ENDLOOP;
DoConstBlt[buf, left.val, right.val];           -- write segment
left ← UpdateIncr[left];
right ← UpdateIncr[right];
yPosn ← yPosn + 1;              -- update scan line
ENDLOOP;
IF yPosn > lowest THEN DoConstBlt[buf, left.val, right.val]; -- write top scan segment
};
FOR i: CARDINAL IN [0..plygn.length) DO   -- convert to pixel map coordinates
[ plygn[i].x, plygn[i].y ] ← Pixels.XfmMapPlace[
         buf.pixels[buf.pixels.length-1], plygn[i].x, plygn[i].y ];
ENDLOOP;
find least and most values
highest ← lowest ← plygn[0].y;
leftmost ← rightmost ← plygn[0].x;
FOR i: CARDINAL IN [1..plygn.length) DO
yCoord: NAT ← plygn[i].y;
xCoord: NAT ← plygn[i].x;
IF yCoord < lowest
THEN { lowest ← yCoord; firstVtx ← i; }
ELSE IF yCoord > highest THEN highest ← yCoord;
IF xCoord < leftmost
THEN leftmost ← xCoord
ELSE IF xCoord > rightmost THEN rightmost ← xCoord;
ENDLOOP;
Lock out cursor
IF vt # NIL
THEN Terminal.ModifyColorFrame[vt, DoItConstant, leftmost, lowest, rightmost, highest ]
ELSE DoItConstant[];
};
SmoothPoly: PUBLIC PROC [buf: PixelBuffer, plygn: REF SpotSequence, renderMode: ATOM] ~ {
vt : Terminal.Virtual ← Pixels.TerminalFromBuffer[buf];
alpha: REF NATNARROW[ Atom.GetPropFromList[buf.props, $Alpha] ];
depth: REF NATNARROW[ Atom.GetPropFromList[buf.props, $Depth] ];
highest, lowest, leftmost, rightmost, firstVtx: NAT ← 0;
DoItSmooth: PROC[] ~ {
segPtr: ARRAY [0..5) OF LONG POINTER;
wdsPerLine: ARRAY [0..5) OF CARDINAL;
wrdPtr: ARRAY [0..5) OF LONG POINTER;
SetUpScanSeg: PROC[yPosn: NAT] ~ TRUSTED {
addOn: NATIF alpha # NIL THEN 1 ELSE 0;   -- make room for alpha buffer
FOR i: NAT IN [0 .. buf.pixels.length - addOn) DO
wdsPerLine[i] ← buf.pixels[i].subMap.sampleMap.bitsPerLine / bitsPerWord;
segPtr[i] ← buf.pixels[i].subMap.sampleMap.base.word
           + Basics.LongMult[yPosn, wdsPerLine[i]];
ENDLOOP;
};
PutScanSeg: PROC[ left, lftR, lftG, lftB, lftZ, right, rgtR, rgtG, rgtB, rgtZ: INTEGER ] ~ TRUSTED {
doIt: BOOLEANTRUE;
red, grn, blu, z: IncrementalDesc;
EvalDepth: PROC[] ~ TRUSTED {
IF LOOPHOLE[wrdPtr[depth^]^, CARDINAL] > CARDINAL[z.val]
THEN { LOOPHOLE[wrdPtr[depth^]^, CARDINAL] ← z.val;
  doIt ← TRUE; }
ELSE doIt ← FALSE;
z ← UpdateIncr[z];
wrdPtr[depth^] ← wrdPtr[depth^] + 1;
};
IF left > right THEN [left, right] ← Swap[left, right];
red ← GetSlopeIncr[ [lftR, left], [rgtR, right] ];
grn ← GetSlopeIncr[ [lftG, left], [rgtG, right] ];
blu ← GetSlopeIncr[ [lftB, left], [rgtB, right] ];
IF depth # NIL THEN {
z ← GetSlopeIncr[ [lftZ, left], [rgtZ, right] ];
wrdPtr[depth^] ← segPtr[depth^] + left;
};
SELECT renderMode FROM
$Dithered, $PseudoClr => {
wrdPtr[0] ← segPtr[0] + Basics.BITSHIFT[left,-1];
FOR x: INTEGER IN [left..right] DO
value: INTEGER ← DitheredRGB[renderMode, x, yPosn, red.val, grn.val, blu.val];
IF depth # NIL THEN EvalDepth[];    -- sets/clears doIt based on depth
IF Basics.BITAND[x,1] = 0
THEN { IF doIt THEN LOOPHOLE[wrdPtr[0]^, BytePair].high ← value; }
ELSE { IF doIt THEN LOOPHOLE[wrdPtr[0]^, BytePair].low ← value;
   wrdPtr[0] ← wrdPtr[0] + 1; };  -- odd, low byte, incr. to next
red ← UpdateIncr[red]; grn ← UpdateIncr[grn]; blu ← UpdateIncr[blu];
ENDLOOP;
};
$Grey   => {
wrdPtr[0] ← segPtr[0] + Basics.BITSHIFT[left,-1];
FOR x: INTEGER IN [left..right] DO
IF depth # NIL THEN EvalDepth[];    -- sets/clears doIt based on depth
IF Basics.BITAND[x,1] = 0
THEN { IF doIt THEN LOOPHOLE[wrdPtr[0]^, BytePair].high ← red.val; }
ELSE { IF doIt THEN LOOPHOLE[wrdPtr[0]^, BytePair].low ← red.val;
   wrdPtr[0] ← wrdPtr[0] + 1; };  -- odd, low byte, incr. to next
red ← UpdateIncr[red];
ENDLOOP;
};
$FullClr, $Dorado24  => {
wrdPtr[0] ← segPtr[0] + left; wrdPtr[2] ← segPtr[2] + Basics.BITSHIFT[left,-1];
FOR x: INTEGER IN [left..right] DO
IF depth # NIL THEN EvalDepth[];    -- sets/clears doIt based on depth
IF doIt THEN wrdPtr[0]^ ← Basics.BITSHIFT[red.val, 8] + grn.val;
wrdPtr[0] ← wrdPtr[0] + 1;
IF Basics.BITAND[x,1] = 0
THEN { IF doIt THEN LOOPHOLE[wrdPtr[2]^, BytePair].high ← blu.val; }
ELSE { IF doIt THEN LOOPHOLE[wrdPtr[2]^, BytePair].low ← blu.val;
   wrdPtr[2] ← wrdPtr[2] + 1; };  -- odd, low byte, incr. to next
red ← UpdateIncr[red]; grn ← UpdateIncr[grn]; blu ← UpdateIncr[blu];
ENDLOOP;
segPtr[2] ← segPtr[2] + wdsPerLine[2];
};
ENDCASE => SIGNAL ScanConvertError[$BadRenderMode];
IF depth # NIL THEN segPtr[depth^] ← segPtr[depth^] + wdsPerLine[depth^];
segPtr[0] ← segPtr[0] + wdsPerLine[0];
};
GetColor: PROC[color: REF RealSequence] RETURNS[outClr: IntRGBT] ~ {
SELECT color.length FROM
1 => outClr ← [Real.RoundC[color[0]], 0, 0, 0 ];
2 => outClr ← [Real.RoundC[color[0]], 0, 0, Real.RoundC[color[1]] ];
3 => outClr ← [Real.RoundC[color[0]], Real.RoundC[color[1]], Real.RoundC[color[2]],
     0];
4 => outClr ← [Real.RoundC[color[0]], Real.RoundC[color[1]], Real.RoundC[color[2]],
     Real.RoundC[color[3]] ];
ENDCASE => SIGNAL ScanConvertError[$BadLength];
};
yPosn: NAT;                -- current scan line
left, lftR, lftG, lftB, lftZ, right, rgtR, rgtG, rgtB, rgtZ: IncrementalDesc; -- edge description
nxtLVtx, nxtRVtx, rVtx, lVtx, nxtRHeight, nxtLHeight: NAT ← 0;
clr, nxtClr: IntRGBT;
bytePtr: LONG POINTER TO rawBytes;
IncrementalDesc: TYPE ~ RECORD[val, intInc, intSgn, fracInc, fracRng, fracPos: INTEGER];
nxtLVtx ← nxtRVtx ← rVtx ← lVtx ← firstVtx; -- set pointers to bottom vertex
yPosn ← nxtRHeight ← nxtLHeight ← lowest;
SetUpScanSeg[yPosn];
WHILE yPosn < highest DO  -- work up through vertices
WHILE yPosn >= nxtLHeight DO     -- next left vertex reached?
lVtx ← nxtLVtx; nxtLVtx ← (lVtx + plygn.length - 1) MOD plygn.length;
nxtLHeight ← plygn[nxtLVtx].y;
left ← GetSlopeIncr[
   [plygn[lVtx].x, plygn[lVtx].y], [plygn[nxtLVtx].x, plygn[nxtLVtx].y] ];
clr ← GetColor[plygn[lVtx].val];
nxtClr ← GetColor[plygn[nxtLVtx].val];
lftR ← GetSlopeIncr[ [clr.r, plygn[lVtx].y], [nxtClr.r, plygn[nxtLVtx].y] ];
lftG ← GetSlopeIncr[ [clr.g, plygn[lVtx].y], [nxtClr.g, plygn[nxtLVtx].y] ];
lftB ← GetSlopeIncr[ [clr.b, plygn[lVtx].y], [nxtClr.b, plygn[nxtLVtx].y] ];
IF depth # NIL THEN
lftZ ← GetSlopeIncr[ [clr.t, plygn[lVtx].y], [nxtClr.t, plygn[nxtLVtx].y] ];
ENDLOOP;
WHILE yPosn >= nxtRHeight DO     -- next right vertex reached?
rVtx ← nxtRVtx; nxtRVtx ← (rVtx + 1) MOD plygn.length;
nxtRHeight ← plygn[nxtRVtx].y;
right ← GetSlopeIncr[
   [plygn[rVtx].x, plygn[rVtx].y], [plygn[nxtRVtx].x, plygn[nxtRVtx].y] ];
clr ← GetColor[plygn[rVtx].val];
nxtClr ← GetColor[plygn[nxtRVtx].val];
rgtR ← GetSlopeIncr[ [clr.r, plygn[rVtx].y], [nxtClr.r, plygn[nxtRVtx].y] ];
rgtG ← GetSlopeIncr[ [clr.g, plygn[rVtx].y], [nxtClr.g, plygn[nxtRVtx].y] ];
rgtB ← GetSlopeIncr[ [clr.b, plygn[rVtx].y], [nxtClr.b, plygn[nxtRVtx].y] ];
IF depth # NIL THEN
rgtZ ← GetSlopeIncr[ [clr.t, plygn[rVtx].y], [nxtClr.t, plygn[nxtRVtx].y] ];
ENDLOOP;
PutScanSeg[ left.val, lftR.val, lftG.val, lftB.val, lftZ.val,
    right.val, rgtR.val, rgtG.val, rgtB.val, rgtZ.val ];
left ← UpdateIncr[left];
lftR ← UpdateIncr[lftR]; lftG ← UpdateIncr[lftG]; lftB ← UpdateIncr[lftB];
right ← UpdateIncr[right];
rgtR ← UpdateIncr[rgtR]; rgtG ← UpdateIncr[rgtG]; rgtB ← UpdateIncr[rgtB];
IF depth # NIL THEN { lftZ ← UpdateIncr[lftZ]; rgtZ ← UpdateIncr[rgtZ]; };
yPosn ← yPosn + 1;              -- update scan line
ENDLOOP;
Write top segment (polygon includes all its edges)
IF yPosn > lowest
THEN PutScanSeg[ left.val, lftR.val, lftG.val, lftB.val, lftZ.val,
      right.val, rgtR.val, rgtG.val, rgtB.val, rgtZ.val ];
};
FOR i: CARDINAL IN [0..plygn.length) DO   -- convert to pixel map coordinates
[ plygn[i].x, plygn[i].y ] ← Pixels.XfmMapPlace[
          buf.pixels[buf.pixels.length-1], plygn[i].x, plygn[i].y ];
ENDLOOP;
find least and most y-values
highest ← lowest ← plygn[0].y;
leftmost ← rightmost ← plygn[0].x;
FOR i: CARDINAL IN [1..plygn.length) DO
yCoord: NAT ← plygn[i].y;
xCoord: NAT ← plygn[i].x;
IF yCoord < lowest
THEN { lowest ← yCoord; firstVtx ← i; }
ELSE IF yCoord > highest THEN highest ← yCoord;
IF xCoord < leftmost
THEN leftmost ← xCoord
ELSE IF xCoord > rightmost THEN rightmost ← xCoord;
ENDLOOP;
Lock out cursor
IF vt # NIL
THEN Terminal.ModifyColorFrame[vt, DoItSmooth, leftmost, lowest, rightmost, highest ]
ELSE DoItSmooth[];
};
lftSeq: REF IncDescSeq ← NEW[IncDescSeq[9]]; -- 9 = rgb(3) + nml x-y(2) + light rgb(3) + z
rgtSeq: REF IncDescSeq ← NEW[IncDescSeq[9]];
segSeq: REF IncDescSeq ← NEW[IncDescSeq[9]];
ShinyPoly: PUBLIC PROC [buf: PixelBuffer, plygn: REF SpotSequence, shininess: NAT,
        renderMode: ATOM] ~ {
vt : Terminal.Virtual ← Pixels.TerminalFromBuffer[buf];
alpha: REF NATNARROW[ Atom.GetPropFromList[buf.props, $Alpha] ];
depth: REF NATNARROW[ Atom.GetPropFromList[buf.props, $Depth] ];
highest, lowest, leftmost, rightmost, firstVtx: NAT ← 0;
DoItShiny: PROC[] ~ {
segPtr: ARRAY [0..5) OF LONG POINTER;
wdsPerLine: ARRAY [0..5) OF CARDINAL;
wrdPtr: ARRAY [0..5) OF LONG POINTER;
SetUpShinySeg: PROC[yPosn: NAT] ~ TRUSTED {
addOn: NATIF alpha # NIL THEN 1 ELSE 0;   -- make room for alpha buffer
FOR i: NAT IN [0 .. buf.pixels.length - addOn) DO
wdsPerLine[i] ← buf.pixels[i].subMap.sampleMap.bitsPerLine / bitsPerWord;
segPtr[i] ← buf.pixels[i].subMap.sampleMap.base.word
           + Basics.LongMult[yPosn, wdsPerLine[i]];
ENDLOOP;
};
GetShinyColor: PROC[ segSeq: REF IncDescSeq ] RETURNS[clr: IntRGB] ~ {
Calculate color with hilite
red, grn, blu: CARDINAL ← 0;
noticeableHilite: BOOLEANFALSE;
FOR i: NAT IN [ 0 .. (segSeq.length-3)/5 ) DO
j: NAT ← i*5 + 3;
pctHilite: CARDINAL ← Power[
MAX[ 0, INTEGER[Basics.BITSHIFT[65535 - Sqr[segSeq[j].val] - Sqr[segSeq[j+1].val], -8] ] ],
shininess
];
IF pctHilite > justNoticeable THEN { -- Scale light color by hilite strength
red ← red + Basics.BITSHIFT[pctHilite * segSeq[j+2].val, -8];
grn ← grn + Basics.BITSHIFT[pctHilite * segSeq[j+3].val, -8];
blu ← blu + Basics.BITSHIFT[pctHilite * segSeq[j+4].val, -8];
noticeableHilite ← TRUE;
};
ENDLOOP;
IF noticeableHilite THEN {
clr.r ← MIN[255, segSeq[0].val + Basics.BITSHIFT[(255 - segSeq[0].val) * red, -8] ];
clr.g ← MIN[255, segSeq[1].val + Basics.BITSHIFT[(255 - segSeq[1].val) * grn, -8] ];
clr.b ← MIN[255, segSeq[2].val + Basics.BITSHIFT[(255 - segSeq[2].val) * blu, -8] ];
}
ELSE {
clr.r ← segSeq[0].val;
clr.g ← segSeq[1].val;
clr.b ← segSeq[2].val;
};
FOR j: NAT IN [0..segSeq.length) DO   -- increment for next pixel
segSeq[j] ← UpdateIncr[ segSeq[j] ];
ENDLOOP;
};
PutShinySeg: PROC[ left: INTEGER, lftSeq: REF IncDescSeq,
      right: INTEGER, rgtSeq: REF IncDescSeq ] ~ TRUSTED {
doIt: BOOLEANTRUE;
EvalDepth: PROC[] ~ TRUSTED {
IF LOOPHOLE[wrdPtr[depth^]^, CARDINAL] > CARDINAL[segSeq[segSeq.length-1].val]
THEN { LOOPHOLE[wrdPtr[depth^]^, CARDINAL] ← segSeq[segSeq.length-1].val;
  doIt ← TRUE; }
ELSE doIt ← FALSE;
wrdPtr[depth^] ← wrdPtr[depth^] + 1;
};
IF left > right THEN [left, right] ← Swap[left, right];
FOR j: NAT IN [0..lftSeq.length) DO
segSeq[j] ← GetSlopeIncr[ [lftSeq[j].val, left], [rgtSeq[j].val, right] ];
ENDLOOP;
IF depth # NIL THEN wrdPtr[depth^] ← segPtr[depth^] + left;
SELECT renderMode FROM
$Dithered, $PseudoClr, $Grey => {
wrdPtr[0] ← segPtr[0] + Basics.BITSHIFT[left,-1];
FOR x: INTEGER IN [left..right] DO
clr: IntRGB; value: INTEGER;
IF depth # NIL THEN EvalDepth[];    -- sets/clears doIt based on depth
clr ← GetShinyColor[segSeq];
value ← IF renderMode = $Grey
THEN (clr.r+clr.g+clr.b)/3
ELSE DitheredRGB[renderMode, x, yPosn, clr.r, clr.g, clr.b];
IF Basics.BITAND[x,1] = 0
THEN { IF doIt THEN LOOPHOLE[wrdPtr[0]^, BytePair].high ← value; }
ELSE { IF doIt THEN LOOPHOLE[wrdPtr[0]^, BytePair].low ← value;
   wrdPtr[0] ← wrdPtr[0] + 1; };  -- odd, low byte, incr. to next
ENDLOOP;
};
$FullClr, $Dorado24  => {
wrdPtr[0] ← segPtr[0] + left; wrdPtr[2] ← segPtr[2] + Basics.BITSHIFT[left,-1];
FOR x: INTEGER IN [left..right] DO
clr: IntRGB;
IF depth # NIL THEN EvalDepth[];    -- sets/clears doIt based on depth
clr ← GetShinyColor[segSeq];
IF doIt THEN wrdPtr[0]^ ← Basics.BITSHIFT[clr.r, 8] + clr.g;
wrdPtr[0] ← wrdPtr[0] + 1;
IF Basics.BITAND[x,1] = 0
THEN { IF doIt THEN LOOPHOLE[wrdPtr[2]^, BytePair].high ← clr.b; }
ELSE { IF doIt THEN LOOPHOLE[wrdPtr[2]^, BytePair].low ← clr.b;
   wrdPtr[2] ← wrdPtr[2] + 1; };  -- odd, low byte, incr. to next
ENDLOOP;
segPtr[2] ← segPtr[2] + wdsPerLine[2];
};
ENDCASE => SIGNAL ScanConvertError[$BadRenderMode];
IF depth # NIL THEN segPtr[depth^] ← segPtr[depth^] + wdsPerLine[depth^];
segPtr[0] ← segPtr[0] + wdsPerLine[0];
};
yPosn: NAT;                -- current scan line
left, right: IncrementalDesc;  -- edge descriptions
nxtLVtx, nxtRVtx, rVtx, lVtx, nxtRHeight, nxtLHeight: NAT ← 0;
nxtLVtx ← nxtRVtx ← rVtx ← lVtx ← firstVtx; -- set pointers to bottom vertex
yPosn ← nxtRHeight ← nxtLHeight ← lowest;
SetUpShinySeg[yPosn];        -- prepare scan segment structure
IF lftSeq.length < plygn[lVtx].val.length THEN {
length: NAT← plygn[lVtx].val.length;      -- get more space
lftSeq ← NEW[IncDescSeq[length]]; -- length = rgb(3)
rgtSeq ← NEW[IncDescSeq[length]]; -- + (nml x-y(2) + light rgb(3)) * # of lights
segSeq ← NEW[IncDescSeq[length]];
};
WHILE yPosn < highest DO  -- work up through vertices
this, next: REF RealSequence;
WHILE yPosn >= nxtLHeight DO     -- next left vertex reached?
lVtx ← nxtLVtx; nxtLVtx ← (lVtx + plygn.length - 1) MOD plygn.length;
nxtLHeight ← plygn[nxtLVtx].y;
left ← GetSlopeIncr[
   [plygn[lVtx].x, plygn[lVtx].y], [plygn[nxtLVtx].x, plygn[nxtLVtx].y] ];
this ← plygn[lVtx].val; next ← plygn[nxtLVtx].val;
FOR j: NAT IN [0..plygn[lVtx].val.length) DO
lftSeq[j] ← GetSlopeIncr[ [Real.FixI[this[j]], plygn[lVtx].y],
       [Real.FixI[next[j]], plygn[nxtLVtx].y] ];
ENDLOOP;
ENDLOOP;
WHILE yPosn >= nxtRHeight DO     -- next right vertex reached?
rVtx ← nxtRVtx; nxtRVtx ← (rVtx + 1) MOD plygn.length;
nxtRHeight ← plygn[nxtRVtx].y;
right ← GetSlopeIncr[
   [plygn[rVtx].x, plygn[rVtx].y], [plygn[nxtRVtx].x, plygn[nxtRVtx].y] ];
this ← plygn[rVtx].val; next ← plygn[nxtRVtx].val;
FOR j: NAT IN [0..plygn[lVtx].val.length) DO
rgtSeq[j] ← GetSlopeIncr[ [Real.FixI[this[j]], plygn[rVtx].y],
       [Real.FixI[next[j]], plygn[nxtRVtx].y] ];
ENDLOOP;
ENDLOOP;
PutShinySeg[ left.val, lftSeq, right.val, rgtSeq ];   -- put out scan segment
left ← UpdateIncr[left];
right ← UpdateIncr[right];
FOR j: NAT IN [0..lftSeq.length) DO
lftSeq[j] ← UpdateIncr[ lftSeq[j] ];
rgtSeq[j] ← UpdateIncr[ rgtSeq[j] ];
ENDLOOP;
yPosn ← yPosn + 1;              -- update scan line
ENDLOOP;
Write top segment (polygon includes all its edges)
IF yPosn > lowest THEN PutShinySeg[ left.val, lftSeq, right.val, rgtSeq ];
};
FOR i: CARDINAL IN [0..plygn.length) DO   -- convert to pixel map coordinates
[ plygn[i].x, plygn[i].y ] ← Pixels.XfmMapPlace[
          buf.pixels[buf.pixels.length-1], plygn[i].x, plygn[i].y ];
ENDLOOP;
find least and most y-values
highest ← lowest ← plygn[0].y;
leftmost ← rightmost ← plygn[0].x;
FOR i: CARDINAL IN [1..plygn.length) DO
yCoord: NAT ← plygn[i].y;
xCoord: NAT ← plygn[i].x;
IF yCoord < lowest
THEN { lowest ← yCoord; firstVtx ← i; }
ELSE IF yCoord > highest THEN highest ← yCoord;
IF xCoord < leftmost
THEN leftmost ← xCoord
ELSE IF xCoord > rightmost THEN rightmost ← xCoord;
ENDLOOP;
Lock out cursor
IF vt # NIL
THEN Terminal.ModifyColorFrame[vt, DoItShiny, leftmost, lowest, rightmost, highest ]
ELSE DoItShiny[];
};
Scan Conversion
Teach this one how to use dithering etc.
DrawLine: PROC [destination: Pixels.SubMap, p1, p2: IntVec2, -- fast line, constant color
      pxlValue: CARDINAL, function: Function ← [null, null]] ~ {
increment, bias, error, sBump, t, shiftDist: INTEGER;
wrdPtr: LONG POINTER TO WORD;
p1s, p1f, p2s, p2f: INTEGER;
dest: SampleMapOps.SampleMap ← destination.subMap.sampleMap;
Get necessary constants based on bits per pixel
bitsPerPixel: NAT ~ dest.bitsPerSample * destination.df;
lgBitsPerPixel: NAT ~ Log2[bitsPerPixel];
logPxlsPerWd: NAT ~ Basics.logBitsPerWord - lgBitsPerPixel;
wordsPerLine: NAT ← dest.bitsPerLine / bitsPerWord;
maxShift: NAT ~ Basics.bitsPerWord - bitsPerPixel;
maxValue: CARDINAL ~ Basics.BITSHIFT[1, bitsPerPixel] - 1;
value: CARDINAL ~ MIN[pxlValue, maxValue];
[p1f, p1s] ← Pixels.XfmMapPlace[destination, p1.x, p1.y];
[p2f, p2s] ← Pixels.XfmMapPlace[destination, p2.x, p2.y];
IF destination.df = 2 THEN {
p1f ← p1f / 2;
p2f ← p2f / 2;
};
Make sure of positive-going fast coordinate
IF p1f > p2f THEN { t ← p1f; p1f ← p2f; p2f ← t; t ← p1s; p1s ← p2s; p2s ← t; }; 
Get pointer to initial word and bit offset
TRUSTED {
wrdPtr ← LOOPHOLE[dest.base.word
+ Basics.LongMult[wordsPerLine, p1s]
+ Basics.BITSHIFT[p1f, -logPxlsPerWd]
];
};
shiftDist ← maxShift - Basics.BITSHIFT[
Basics.BITAND[ p1f, Basics.BITSHIFT[1, logPxlsPerWd] - 1], -- p1f MOD pixelsPerWord
lgBitsPerPixel
];
IF (p2f - p1f) > ABS[p2s - p1s]
More horizontal line (moves faster along fast axis)
THEN {
increment ← LOOPHOLE[Basics.BITSHIFT[LOOPHOLE[p2s - p1s], 1], INTEGER];
bias ← LOOPHOLE[Basics.BITSHIFT[LOOPHOLE[p2f - p1f], 1], INTEGER];
sBump ← SGN[increment] * wordsPerLine;
increment ← ABS[increment];
error ← increment - Basics.BITSHIFT[bias, -1];
IF lgBitsPerPixel = 3    -- speedup for 8 bits per pixel
THEN FOR i: NAT IN [0..(p2f-p1f)] DO TRUSTED {
IF shiftDist = 0
THEN { LOOPHOLE[wrdPtr^, BytePair].low ← value;
   wrdPtr ← wrdPtr + 1; shiftDist ← 8; }
ELSE { LOOPHOLE[wrdPtr^, BytePair].high ← value; shiftDist ← 0; };
IF error > 0 THEN TRUSTED { wrdPtr ← wrdPtr + sBump; error ← error - bias; };
error ← error + increment;
};
ENDLOOP
ELSE FOR i: NAT IN [0..(p2f-p1f)] DO
TRUSTED {
wrdPtr^ ← Basics.BITOR[      -- deposit pixel bits in word
Basics.BITAND[wrdPtr^, Basics.BITNOT[Basics.BITSHIFT[maxValue, shiftDist]]],
Basics.BITSHIFT[value, shiftDist]
];
};
IF shiftDist = 0 THEN TRUSTED { wrdPtr ← wrdPtr + 1; shiftDist ← maxShift; }
     ELSE shiftDist ← shiftDist - bitsPerPixel;
IF error > 0 THEN TRUSTED { wrdPtr ← wrdPtr + sBump; error ← error - bias; };
error ← error + increment;
ENDLOOP;  
}
More vertical line (moves faster along slow axis)
ELSE {
j: NAT ← Basics.BITSHIFT[shiftDist, -lgBitsPerPixel];
pixelsPerWd: NAT ~ Basics.BITSHIFT[1, logPxlsPerWd];
mask, values: ARRAY [0..16) OF CARDINAL;
FOR i: NAT IN [0..pixelsPerWd) DO
mask[i] ← Basics.BITNOT[Basics.BITSHIFT[maxValue, Basics.BITSHIFT[i, lgBitsPerPixel]]];
values[i] ← Basics.BITSHIFT[value, Basics.BITSHIFT[i, lgBitsPerPixel]];
ENDLOOP;
increment ← LOOPHOLE[Basics.BITSHIFT[LOOPHOLE[p2f - p1f], 1], INTEGER];
bias ← LOOPHOLE[Basics.BITSHIFT[LOOPHOLE[p2s - p1s], 1], INTEGER];
sBump ← SGN[bias] * wordsPerLine;
bias ← ABS[bias];
error ← increment - Basics.BITSHIFT[bias, -1];
IF lgBitsPerPixel = 3    -- speedup for 8 bits per pixel
THEN FOR i: NAT IN [0..ABS[p2s - p1s]] DO TRUSTED {
IF shiftDist = 0
THEN { LOOPHOLE[wrdPtr^, BytePair].low ← value;
   IF error > 0
   THEN { wrdPtr ← wrdPtr + 1; shiftDist ← 8; error ← error - bias; };
 }
ELSE { LOOPHOLE[wrdPtr^, BytePair].high ← value;
   IF error > 0
   THEN { shiftDist ← 0; error ← error - bias; };
 };
wrdPtr ← wrdPtr + sBump;
error ← error + increment;
};
ENDLOOP
ELSE FOR i: NAT IN [0..ABS[p2s - p1s]] DO
TRUSTED {
wrdPtr^ ← Basics.BITOR[ Basics.BITAND[wrdPtr^, mask[j]] , values[j]];
};
TRUSTED { wrdPtr ← wrdPtr + sBump; };
IF error > 0
THEN {
error ← error - bias;
IF j = 0 THEN TRUSTED { wrdPtr ← wrdPtr + 1; j ← pixelsPerWd - 1; }
     ELSE j ← j - 1;
};
error ← error + increment;
ENDLOOP;
};
};
END.