Imager8bitDisplayImpl.mesa
This implements the low level routines for the color display at 8 bits per pixel.
Last Edited by:
Crow, September 1, 1983 4:18 pm
DIRECTORY
Real    USING [FixC, Float],
Inline    USING [BytePair, LongMult, HighHalf],
BitBlt    USING [AlignedBBTable, BBTableSpace, BITBLT, BitBltTable, BitBltTablePtr],
Environment  USING [wordsPerPage, bitsPerWord, LongNumber],
Space    USING [Handle, Create, virtualMemory, defaultBase, LongPointer, Delete,
        Map, nullHandle],
Imager   USING [ClassRep],
ImagerBasic  USING [Transformation, IntRectangle, IntPair,
        CIEColor, CIEColorRep],
ImagerRegistration USING [RegisterDevice],
ImagerDisplay USING [ByteSequence, ByteSequenceRep, RegisterDisplayDevice, Vertex,
        VtxSequence, Direction, ContextData, DisplayClassRep],
ImagerMasks  USING [Mask],
ColorDisplay  USING [GetMode, SetMode, TurnOn, GetColor, disconnected, width, height,
        baseA, wplA, SetColor],
Imager8bitDisplay,
ImagerDisplayImpl, ImagerDisplayTransformImpl, ImagerDisplayClipperImpl, ImagerDisplayColorImpl, ImagerDisplayMasksImpl, ImagerDisplayCharactersImpl, ImagerDisplayInteractiveImpl;
Imager8bitDisplayImpl: CEDAR MONITOR
IMPORTS Real, Inline, BitBlt, ColorDisplay, Space, ImagerRegistration, ImagerDisplay, ImagerDisplayImpl, ImagerDisplayTransformImpl, ImagerDisplayClipperImpl, ImagerDisplayColorImpl, ImagerDisplayMasksImpl, ImagerDisplayCharactersImpl, ImagerDisplayInteractiveImpl
EXPORTS Imager8bitDisplay
~ BEGIN
OPEN ImagerBasic, ImagerDisplay;
NoColorDisplay: PUBLIC SIGNAL ~ CODE;
IncompatibleDisplayMode: PUBLIC SIGNAL ~ CODE;
NotImplementedYet: PUBLIC SIGNAL ~ CODE;
IncompatiblePixelArray: PUBLIC SIGNAL ~ CODE;
Mask: TYPE ~ ImagerMasks.Mask;
bpPxl: CARDINAL ~ 8;
maxPxlValue: CARDINAL ~ 255;
bpWd: CARDINAL ~ Environment.bitsPerWord;
pxpWd: CARDINAL ~ bpWd/bpPxl;
maxDisplayWidth: CARDINAL ~ 8192; -- number in excess of maximum expected BITBLT width
getPxlPtr, setPxlPtr: LONG POINTER TO Inline.BytePair;
getPxlDir, setPxlDir: Direction;
getLeftByte, setLeftByte: BOOLEAN;
getWordsPerLine, setWordsPerLine: CARDINAL;
swapUnitSize: CARDINAL ← 50;  -- unbelieveable crap for getting large spaces
nullBitBltTable: BitBlt.BitBltTable = [dst: [word: NIL, bit: 0], dstBpl: maxDisplayWidth,
           src: [word: NIL, bit: 0],
           srcDesc: [srcBpl[maxDisplayWidth]],
           width: 0, height: 1, flags: [disjoint: TRUE] ];
SQR: PROCEDURE [number: REAL] RETURNS [REAL] = INLINE { RETURN[number * number]; };
SGN: PROCEDURE [number: INTEGER] RETURNS [INTEGER] = INLINE {
           IF number >= 0 THEN RETURN[1] ELSE RETURN[-1]; };
SetUp: PUBLIC PROC [ displayContext: ContextData,
       pin: BOOLEANTRUE,
       box: Mask] = {
get memory, pin it if requested, set the transform and clipper
IF pin
Open color display, set to 8-bit mode and find bitmap
THEN TRUSTED {           
IF ColorDisplay.GetMode[] = ColorDisplay.disconnected
THEN IF ColorDisplay.SetMode[ [FALSE, 8, 0] ]
THEN ColorDisplay.TurnOn[]
ELSE ERROR NoColorDisplay[]
ELSE IF ColorDisplay.GetMode[] # [FALSE, 8, 0]
THEN ERROR IncompatibleDisplayMode[];
FOR i: LONG CARDINAL IN [0..40) DO ColorDisplay.SetColor[ i + 216, 0, i*6, i*6, i*6] ENDLOOP; -- greyscale
FOR i: LONG CARDINAL IN [0..216) DO          -- 6 x 6 x 6 color cube
ColorDisplay.SetColor[ i, 0, 36 * (i MOD 6 + 1), 36 * ((i/6) MOD 6 + 1), 36 * (i/36 + 1)];
ENDLOOP;
displayContext.deviceClipper ← [1, 1, ColorDisplay.height - 1, ColorDisplay.width - 1, NIL];
displayContext.wordsPerLine ← ColorDisplay.wplA;
displayContext.pxlBase ← ColorDisplay.baseA;
displayContext.storage ← Space.nullHandle;
}
Get contiguous block of memory to act as nondisplayed frame buffer
ELSE {
wordsPerLine, pages: CARDINAL; storage: Space.Handle;
IF box.sSize = 0           -- degenerate box implies full screen
THEN box ← [1, 1, ColorDisplay.height - 1, ColorDisplay.width - 1, NIL];
wordsPerLine ← IF box.fSize MOD pxpWd = 0 THEN box.fSize/pxpWd
                 ELSE box.fSize/pxpWd + 1;
pages ← (Inline.LongMult[wordsPerLine, box.sSize + 1] / Environment.wordsPerPage) + 1;
TRUSTED {
storage ← Space.Create[ pages, Space.virtualMemory, Space.defaultBase];
FOR offset: CARDINAL ← 0, offset + swapUnitSize
WHILE offset + swapUnitSize <= pages DO     -- get space in small pieces
[] ← Space.Create[size: swapUnitSize, parent: storage, base: offset]
ENDLOOP;
Space.Map[storage];
};
displayContext.pxlBase ← Space.LongPointer[storage];
displayContext.wordsPerLine ← wordsPerLine;
displayContext.deviceClipper ← box;
displayContext.storage ← storage;
};
displayContext.deviceTransform ← [1., 0., 0., 0.,-1., ColorDisplay.height, mirrorY];
};
ShutDown: PUBLIC PROC [displayContext: ContextData] = TRUSTED {
Free memory (how can you be sure somebody else isn't using it?)
IF displayContext.storage = Space.nullHandle
THEN { IF NOT ColorDisplay.SetMode[ ColorDisplay.disconnected ]
   THEN ERROR NoColorDisplay[]; }
ELSE Space.Delete[displayContext.storage];
};
ColortoPixel: PUBLIC PROC [color: CIEColor] RETURNS [LONG CARDINAL] = { -- Color to device transform
Finds color table entry with least sum-of-square difference from color
val: CIEColor;
sum, minSum: REAL;
entry: LONG CARDINAL;
FOR i: LONG CARDINAL IN [0..maxPxlValue] DO
val ← PixeltoColor[i];
sum ← SQR[val.Y - color.Y];
IF i = 0
THEN { entry ← i; minSum ← sum; }
ELSE IF sum < minSum THEN { entry ← i; minSum ← sum; };
ENDLOOP;
RETURN [ entry ];
};
PixeltoColor: PUBLIC PROC [pxlValue: LONG CARDINAL] RETURNS [CIEColor] = TRUSTED {
r, g, b: [0..maxPxlValue];        -- RGB from color display lookup table
rr, rg, rb: REAL;        -- Imager RGB value (range 0.-1.)
color: CIEColor ← NEW[ CIEColorRep ];
[r, g, b] ← ColorDisplay.GetColor[ pxlValue ];
rr ← r/Real.Float[maxPxlValue];
rg ← g/Real.Float[maxPxlValue];
rb ← b/Real.Float[maxPxlValue];
color.x ← Real.FixC[rr * LAST[CARDINAL]];  -- this should be proceeded by a transform
color.y ← Real.FixC[rg * LAST[CARDINAL]];
color.Y ← Real.FixC[rb * LAST[CARDINAL]];
RETURN [ color ];
};
HilitePxls: PUBLIC PROC [area: IntRectangle] = {     -- Device dependent highlighting scheme
};
MovePxls: PUBLIC PROC [context: ContextData,
        source: IntRectangle, destination: IntPair] = TRUSTED { 
Move a rectangle within a context
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
srcPxlPtr, dstPxlPtr: LONG POINTER;
wordsPerLine: CARDINAL;
wordsPerLine ← context.wordsPerLine;
dstPxlPtr ← LOOPHOLE[ context.pxlBase
+ Inline.LongMult[wordsPerLine, destination.y]
+ (destination.x / pxpWd),
LONG POINTER];
srcPxlPtr ← LOOPHOLE[ context.pxlBase
+ Inline.LongMult[wordsPerLine, source.y]
+ (source.x / pxpWd),
LONG POINTER];
bb^ ← nullBitBltTable;
bb.dst.word ← dstPxlPtr;
bb.dst.bit ← (destination.x MOD pxpWd) * bpPxl;
bb.dstBpl ← wordsPerLine * bpWd;
bb.src.word ← srcPxlPtr;
bb.src.bit ← (source.x MOD pxpWd) * bpPxl;
bb.srcDesc.srcBpl ← bb.dstBpl;
bb.width ← source.w * bpPxl;
bb.height ← source.h;
BitBlt.BITBLT[bb];
};
TransferPxls: PUBLIC PROC [source, destination: ContextData] = TRUSTED {
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
destMaskX, destMaskY: INTEGER;
bb^ ← nullBitBltTable;
{ OPEN destination;
destMaskX ← clipper.fMin - viewerClipper.fMin;  -- get mask defined by client clipper
destMaskY ← clipper.sMin - viewerClipper.sMin;
bb.dst.word ← LOOPHOLE[ pxlBase
+ Inline.LongMult[wordsPerLine, clipper.sMin]
+ (clipper.fMin / pxpWd),
LONG POINTER];
IF clipper.fMin MOD pxpWd # 0 THEN bb.dst.bit ← bpPxl;
bb.dstBpl ← wordsPerLine * bpWd;
};
{ OPEN source;
bb.src.word ← LOOPHOLE[ pxlBase
+ Inline.LongMult[wordsPerLine, viewerClipper.sMin + destMaskY]
+ ((viewerClipper.fMin + destMaskX) / pxpWd),
LONG POINTER];
IF (viewerClipper.fMin + destMaskX) MOD pxpWd # 0 THEN bb.src.bit ← bpPxl;
bb.srcDesc.srcBpl ← wordsPerLine * bpWd;
};
bb.width ← MIN[source.viewerClipper.fSize - destMaskX, destination.clipper.fSize] * bpPxl;
bb.height ← MIN[source.viewerClipper.sSize - destMaskY, destination.clipper.sSize];
BitBlt.BITBLT[bb];
};
StoreScanSeg: PUBLIC PROC [source: ContextData,
         x, y, length: CARDINAL] RETURNS [ByteSequence] = TRUSTED {
segment: ByteSequence ← NEW [ ByteSequenceRep[length/pxpWd] ];
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
bb^ ← nullBitBltTable;
bb.dst.word ← LOOPHOLE[segment, LONG POINTER];
bb.src.word ← LOOPHOLE[ source.pxlBase
+ Inline.LongMult[source.wordsPerLine, y] + (x / pxpWd),
LONG POINTER];
bb.src.bit ← (x MOD pxpWd) * bpPxl;
bb.width ← length * bpPxl;
BitBlt.BITBLT[bb];
RETURN [segment];
};
LoadScanSeg: PUBLIC PROC [destination: ContextData,
         x, y, length: CARDINAL,
         segment: ByteSequence] = TRUSTED {
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
bb^ ← nullBitBltTable;
bb.dst.word ← LOOPHOLE[ destination.pxlBase
+ Inline.LongMult[destination.wordsPerLine, y] + (x / pxpWd),
LONG POINTER];
bb.dst.bit ← (x MOD pxpWd) * bpPxl;
bb.src.word ← LOOPHOLE[segment, LONG POINTER];
bb.width ← length * bpPxl;
BitBlt.BITBLT[bb];
};
LoadTrapezoid: PUBLIC PROC [destination: ContextData,
          top, bottom, leftTop, leftBot, rightTop, rightBot: CARDINAL,
          pxlValue: LONG CARDINAL] = TRUSTED {   
Scan convert trapezoid, constant color
IF leftTop = leftBot AND rightTop = rightBot
THEN LoadRectangle[destination, [leftBot, bottom, rightBot - leftBot, top - bottom], pxlValue]
ELSE {      -- not rectangle
EdgeBlock: TYPE = RECORD [xPos: LONG CARDINAL, xIncr: LONG INTEGER];
MakeEdge: UNSAFE PROC[xTop, xBot, height: NAT] RETURNS [edge: EdgeBlock] = INLINE {
LOOPHOLE[edge.xPos, Environment.LongNumber].high ← LOOPHOLE[xBot, UNSPECIFIED];
LOOPHOLE[edge.xPos, Environment.LongNumber].low ← LOOPHOLE[0, UNSPECIFIED];
LOOPHOLE[edge.xIncr, Environment.LongNumber].high ←
               LOOPHOLE[xTop - xBot, UNSPECIFIED];
LOOPHOLE[edge.xIncr, Environment.LongNumber].low ← LOOPHOLE[0, UNSPECIFIED];
IF height > 1 THEN edge.xIncr ← edge.xIncr / height;
};
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
value: CARDINAL ← pxlValue * 256 + pxlValue; -- make pxlValue brick for BitBlt
scanPtr, pxlPtr: LONG POINTER;
lEdge: EdgeBlock ← MakeEdge[leftTop, leftBot, top - bottom];
rEdge: EdgeBlock ← MakeEdge[rightTop, rightBot, top - bottom];
bb^ ← nullBitBltTable;
bb.flags.gray ← TRUE;
bb.src.word ← @value;
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 15, heightMinusOne: 0];
TRUSTED { scanPtr ← LOOPHOLE[ destination.pxlBase
       + Inline.LongMult[destination.wordsPerLine, bottom],
         LONG POINTER TO Inline.BytePair]; };
FOR height: NAT IN [bottom..top] DO
TRUSTED {         -- Get pixel pointer and Step scan pointer
pxlPtr ← scanPtr + LOOPHOLE[Inline.HighHalf[lEdge.xPos] / pxpWd, CARDINAL];
scanPtr ← scanPtr + destination.wordsPerLine;
};
bb.dst.word ← pxlPtr;
bb.dst.bit ← (Inline.HighHalf[lEdge.xPos] MOD pxpWd) * bpPxl;
bb.width ← (Inline.HighHalf[rEdge.xPos] - Inline.HighHalf[lEdge.xPos]) * bpPxl;
BitBlt.BITBLT[bb];
lEdge.xPos ← lEdge.xPos + lEdge.xIncr;
rEdge.xPos ← rEdge.xPos + rEdge.xIncr;
ENDLOOP;
};
};
LoadRectangle: PUBLIC PROC [destination: ContextData, area: ImagerBasic.IntRectangle,
          pxlValue: LONG CARDINAL] = TRUSTED {
 Scan convert rectangle, constant color
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
color: CARDINAL;
pxlValue ← MIN[pxlValue, maxPxlValue];
color ← pxlValue * 256 + pxlValue;  -- make pxlValue brick for BitBlt                      
bb^ ← nullBitBltTable;
bb.flags.gray ← TRUE;
bb.dst.word ← LOOPHOLE[ destination.pxlBase
+ Inline.LongMult[destination.wordsPerLine, area.y] + (area.x / pxpWd),
LONG POINTER];
bb.dst.bit ← (area.x MOD pxpWd) * bpPxl;
bb.dstBpl ← destination.wordsPerLine * bpWd;
bb.src.word ← @color;
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 15, heightMinusOne: 0];
bb.width ← area.w * bpPxl;
bb.height ← area.h;
BitBlt.BITBLT[bb];
};
SetAnyPixel: PUBLIC PROC [destination: ContextData, x, y: CARDINAL, pxlValue: LONG CARDINAL, newDirection: Direction ← none] = TRUSTED {
byteValue: [0..256) ← MIN[pxlValue, maxPxlValue];
setPxlPtr ← LOOPHOLE[ destination.pxlBase
+ Inline.LongMult[destination.wordsPerLine, y] + (x / pxpWd),
LONG POINTER TO Inline.BytePair];
IF x MOD pxpWd = 0
THEN { setPxlPtr^.high ← byteValue; setLeftByte ← TRUE; }
ELSE { setPxlPtr^.low ← byteValue; setLeftByte ← FALSE; };
setPxlDir ← newDirection;
setWordsPerLine ← destination.wordsPerLine;
};
GetAnyPixel: PUBLIC PROC [source: ContextData, x, y: CARDINAL, newDirection: Direction ← none] RETURNS [LONG CARDINAL] = TRUSTED {
pixel: LONG CARDINAL;
getPxlPtr ← LOOPHOLE[ source.pxlBase
+ Inline.LongMult[source.wordsPerLine, y] + (x / pxpWd),
LONG POINTER TO Inline.BytePair];
IF x MOD pxpWd = 0
THEN { pixel ← getPxlPtr^.high; getLeftByte ← TRUE; }
ELSE { pixel ← getPxlPtr^.low; getLeftByte ← FALSE; };
getPxlDir ← newDirection;
getWordsPerLine ← source.wordsPerLine;
RETURN [ pixel ];
};
SetNextPixel: PUBLIC PROC [pxlValue: LONG CARDINAL] = TRUSTED {
byteValue: [0..256) ← MIN[pxlValue, maxPxlValue];
SELECT setPxlDir FROM
left    => { IF NOT setLeftByte THEN setPxlPtr ← setPxlPtr + 1;
      setLeftByte ← NOT setLeftByte; };
right    => { IF setLeftByte THEN setPxlPtr ← setPxlPtr - 1;
      setLeftByte ← NOT setLeftByte; };
up    =>  setPxlPtr ← setPxlPtr - setWordsPerLine;
down   =>  setPxlPtr ← setPxlPtr + setWordsPerLine;
upLeft  => { IF NOT setLeftByte THEN setPxlPtr ← setPxlPtr + 1;
      setLeftByte ← NOT setLeftByte;
      setPxlPtr ← setPxlPtr - setWordsPerLine; };
downLeft  => { IF NOT setLeftByte THEN setPxlPtr ← setPxlPtr + 1;
      setLeftByte ← NOT setLeftByte;
      setPxlPtr ← setPxlPtr + setWordsPerLine; };
upRight  => { IF setLeftByte THEN setPxlPtr ← setPxlPtr - 1;
      setLeftByte ← NOT setLeftByte;
      setPxlPtr ← setPxlPtr - setWordsPerLine; };
downRight => { IF setLeftByte THEN setPxlPtr ← setPxlPtr - 1;
      setLeftByte ← NOT setLeftByte;
      setPxlPtr ← setPxlPtr + setWordsPerLine; };
ENDCASE;
IF setLeftByte THEN setPxlPtr^.high ← byteValue ELSE setPxlPtr^.low ← byteValue;
};
GetNextPixel: PUBLIC PROC [] RETURNS [LONG CARDINAL]= TRUSTED {
SELECT getPxlDir FROM
left    => { IF NOT getLeftByte THEN getPxlPtr ← getPxlPtr + 1;
      getLeftByte ← NOT getLeftByte; };
right    => { IF getLeftByte THEN getPxlPtr ← getPxlPtr - 1;
      getLeftByte ← NOT getLeftByte; };
up    =>  getPxlPtr ← getPxlPtr - getWordsPerLine;
down   =>  getPxlPtr ← getPxlPtr + getWordsPerLine;
upLeft  => { IF NOT getLeftByte THEN getPxlPtr ← getPxlPtr + 1;
      getLeftByte ← NOT getLeftByte;
      getPxlPtr ← getPxlPtr - getWordsPerLine; };
downLeft  => { IF NOT getLeftByte THEN getPxlPtr ← getPxlPtr + 1;
      getLeftByte ← NOT getLeftByte;
      getPxlPtr ← getPxlPtr + getWordsPerLine; };
upRight  => { IF getLeftByte THEN getPxlPtr ← getPxlPtr - 1;
      getLeftByte ← NOT getLeftByte;
      getPxlPtr ← getPxlPtr - getWordsPerLine; };
downRight => { IF getLeftByte THEN getPxlPtr ← getPxlPtr - 1;
      getLeftByte ← NOT getLeftByte;
      getPxlPtr ← getPxlPtr + getWordsPerLine; };
ENDCASE;
IF getLeftByte THEN RETURN[getPxlPtr^.high] ELSE RETURN[getPxlPtr^.low];
};
DrawLine: PUBLIC PROC [destination: ContextData, a, b: IntPair,
        pxlValue: LONG CARDINAL] = {
Fast line, constant color, using a slightly modified Bresenham's algorithm
byteValue: [0..maxPxlValue];
increment, bias, error, yBump: INTEGER; leftByte: BOOLEAN; t: IntPair;
wordsPerLine: CARDINAL;
pxlPtr: LONG POINTER TO Inline.BytePair;
IF a.x > b.x THEN { t ← a; a ← b; b ← t; };  -- make sure of positive-going x
byteValue ← MIN[pxlValue, maxPxlValue];
wordsPerLine ← destination.wordsPerLine;
TRUSTED { pxlPtr ← LOOPHOLE[ destination.pxlBase
       + Inline.LongMult[destination.wordsPerLine, a.y] + (a.x / pxpWd),
       LONG POINTER TO Inline.BytePair]; };
IF (b.x - a.x) > ABS[b.y - a.y]
THEN {                 -- more horizontal line
increment ← 2 * (b.y - a.y);
bias ← 2 * (b.x - a.x);
yBump ← SGN[increment] * wordsPerLine;
increment ← ABS[increment]; bias ← ABS[bias];
error ← increment - bias/2;
leftByte ← a.x MOD pxpWd = 0;   -- left byte is high byte
FOR i: CARDINAL IN [0..ABS[b.x-a.x]] DO TRUSTED {
IF leftByte
THEN pxlPtr^.high ← byteValue
ELSE { pxlPtr^.low ← byteValue; pxlPtr ← pxlPtr + 1; };
leftByte ← NOT leftByte;
IF error > 0 THEN { pxlPtr ← pxlPtr + yBump; error ← error - bias; };
error ← error + increment;
}; ENDLOOP;  
}
ELSE {                 -- more vertical line
increment ← 2 * (b.x - a.x);
bias ← 2 * (b.y - a.y);
yBump ← SGN[bias] * wordsPerLine;
increment ← ABS[increment]; bias ← ABS[bias];
error ← increment - bias/2;
leftByte ← a.x MOD pxpWd = 0;
FOR i: CARDINAL IN [0..ABS[b.y-a.y]] DO TRUSTED {
IF leftByte THEN pxlPtr^.high ← byteValue ELSE pxlPtr^.low ← byteValue;
pxlPtr ← pxlPtr + yBump;
IF error > 0
THEN {
error ← error - bias;
IF NOT leftByte THEN pxlPtr ← pxlPtr + 1;
leftByte ← NOT leftByte;
};
error ← error + increment;
}; ENDLOOP;
};
};
Tiler: PUBLIC PROC [destination: ContextData,
      vtxCount: NAT, vertices: VtxSequence] = {
EdgeBlock: TYPE = RECORD [length: CARDINAL, xPos, value: LONG CARDINAL,
xIncr, valIncr: LONG INTEGER];
MakeEdge: PROC[vtx1, vtx2: Vertex] RETURNS [edge: EdgeBlock] = -- INLINE -- {
edge.length ← IF vtx2.y > vtx1.y THEN vtx2.y - vtx1.y ELSE 0;
LOOPHOLE[edge.xPos, Environment.LongNumber].high ← LOOPHOLE[vtx1.x, UNSPECIFIED];
LOOPHOLE[edge.xPos, Environment.LongNumber].low ← LOOPHOLE[0, UNSPECIFIED];
edge.xIncr ← MakeIncr[vtx1.x, vtx2.x, edge.length];
LOOPHOLE[edge.value, Environment.LongNumber].high ←
          LOOPHOLE[vtx1.pxlValue, Environment.LongNumber].low;
LOOPHOLE[edge.value, Environment.LongNumber].low ← LOOPHOLE[0, UNSPECIFIED];
edge.valIncr ← MakeIncr[vtx1.pxlValue, vtx2.pxlValue, edge.length];
};
MakeScanSeg: PROC[lx, lv, rx, rv: CARDINAL, pxlPtr: LONG POINTER TO Inline.BytePair] = TRUSTED -- INLINE -- {
incr: LONG INTEGER;
value: LONG CARDINAL;
leftByte: BOOLEAN ← (lx MOD pxpWd) = 0;
incr ← MakeIncr[lv, rv, rx - lx];
LOOPHOLE[value, Environment.LongNumber].high ← LOOPHOLE[lv, UNSPECIFIED];
LOOPHOLE[value, Environment.LongNumber].low ← LOOPHOLE[0, UNSPECIFIED];
FOR i: CARDINAL IN [lx..rx] DO
IF leftByte
THEN pxlPtr^.high ← Inline.HighHalf[value]
ELSE { pxlPtr^.low ← Inline.HighHalf[value]; pxlPtr ← pxlPtr + 1; };
leftByte ← NOT leftByte;
value ← value + incr;
ENDLOOP;
};
MakeIncr: PROC[v1, v2, length: CARDINAL] RETURNS[ incr: LONG INTEGER ] = -- INLINE -- {
LOOPHOLE[incr, Environment.LongNumber].high ← LOOPHOLE[v2 - v1, UNSPECIFIED];
LOOPHOLE[incr, Environment.LongNumber].low ← LOOPHOLE[0, UNSPECIFIED];
IF length > 1 THEN incr ← incr / length;
};
lVtx, rVtx, least, most, height, vtxCountMinusOne, lastX, wordsPerLine: CARDINAL;
scanPtr, pxlPtr: LONG POINTER TO Inline.BytePair;
lEdge: EdgeBlock ← [0, 0, 0, 0, 0];
rEdge: EdgeBlock ← [0, 0, 0, 0, 0];
vtxCountMinusOne ← vtxCount - 1;
find least and most y-values
FOR i: CARDINAL IN [0..vtxCount) DO
IF i = 0
THEN { most ← least ← vertices[i].y; lVtx ← i; }
ELSE IF vertices[i].y < least
THEN { least ← vertices[i].y; lVtx ← i; }
ELSE IF vertices[i].y > most THEN most ← vertices[i].y;
ENDLOOP;
rVtx ← lVtx; -- set pointers to bottom vertex
height ← vertices[lVtx].y;
lastX ← vertices[lVtx].x;
wordsPerLine ← destination.wordsPerLine;
TRUSTED { scanPtr ← LOOPHOLE[ destination.pxlBase
       + Inline.LongMult[destination.wordsPerLine, vertices[lVtx].y],
         LONG POINTER TO Inline.BytePair]; };
WHILE height < most DO-- Do until top scan line (rejects zero-height polys)
WHILE lEdge.length = 0 DO        -- work left edge counterclockwise
nxtVtx: CARDINAL ← (lVtx + vtxCountMinusOne) MOD vtxCount;
lEdge ← MakeEdge[vertices[lVtx], vertices[nxtVtx]];
lVtx ← nxtVtx;
ENDLOOP;
WHILE rEdge.length = 0 DO        -- work right edge clockwise
nxtVtx: CARDINAL ← (rVtx + 1) MOD vtxCount;
rEdge ← MakeEdge[vertices[rVtx], vertices[nxtVtx]];
rVtx ← nxtVtx;
ENDLOOP;
TRUSTED {         -- Get pixel pointer and Step scan pointer
pxlPtr ← scanPtr + LOOPHOLE[Inline.HighHalf[lEdge.xPos] / pxpWd, CARDINAL];
scanPtr ← scanPtr + wordsPerLine;
};
MakeScanSeg[Inline.HighHalf[lEdge.xPos], Inline.HighHalf[lEdge.value],
    Inline.HighHalf[rEdge.xPos], Inline.HighHalf[rEdge.value],
    pxlPtr];
lEdge.xPos ← lEdge.xPos + lEdge.xIncr;
lEdge.value ← lEdge.value + lEdge.valIncr;
lEdge.length ← lEdge.length - 1;
rEdge.xPos ← rEdge.xPos + rEdge.xIncr;
rEdge.value ← rEdge.value + rEdge.valIncr;
rEdge.length ← rEdge.length - 1;
height ← height + 1;
ENDLOOP;
Include bottom line of polygon
TRUSTED { pxlPtr ← scanPtr + LOOPHOLE[Inline.HighHalf[lEdge.xPos] / pxpWd, CARDINAL]; };
MakeScanSeg[Inline.HighHalf[lEdge.xPos], Inline.HighHalf[lEdge.value],
    Inline.HighHalf[rEdge.xPos], Inline.HighHalf[rEdge.value],
    pxlPtr];
};
ConstantTiler: PUBLIC PROC [destination: ContextData, vtxCount: NAT,
         vertices: VtxSequence, pxlValue: LONG CARDINAL] = {
EdgeBlock: TYPE = RECORD [length: CARDINAL, xPos: LONG CARDINAL, xIncr: LONG INTEGER];
MakeEdge: PROC[vtx1, vtx2: Vertex] RETURNS [edge: EdgeBlock] = -- INLINE -- {
edge.length ← IF vtx2.y > vtx1.y THEN vtx2.y - vtx1.y ELSE 0;
LOOPHOLE[edge.xPos, Environment.LongNumber].high ← LOOPHOLE[vtx1.x, UNSPECIFIED];
LOOPHOLE[edge.xPos, Environment.LongNumber].low ← LOOPHOLE[0, UNSPECIFIED];
LOOPHOLE[edge.xIncr, Environment.LongNumber].high ←
               LOOPHOLE[vtx2.x - vtx1.x, UNSPECIFIED];
LOOPHOLE[edge.xIncr, Environment.LongNumber].low ← LOOPHOLE[0, UNSPECIFIED];
IF edge.length > 1 THEN edge.xIncr ← edge.xIncr / edge.length;
};
value: CARDINAL ← pxlValue * 256 + pxlValue; -- make pxlValue brick for BitBlt
lVtx, rVtx, least, most, height, vtxCountMinusOne, lastX, wordsPerLine: CARDINAL;
scanPtr, pxlPtr: LONG POINTER;
lEdge: EdgeBlock ← [0, 0, 0];
rEdge: EdgeBlock ← [0, 0, 0];
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr;
TRUSTED {
bb ← BitBlt.AlignedBBTable[@bbspace];
bb^ ← nullBitBltTable;
bb.flags.gray ← TRUE;
bb.src.word ← @value;
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 15, heightMinusOne: 0];
};
vtxCountMinusOne ← vtxCount - 1;
find least and most y-values
FOR i: CARDINAL IN [0..vtxCount) DO
IF i = 0
THEN { most ← least ← vertices[i].y; lVtx ← i; }
ELSE IF vertices[i].y < least
THEN { least ← vertices[i].y; lVtx ← i; }
ELSE IF vertices[i].y > most THEN most ← vertices[i].y;
ENDLOOP;
rVtx ← lVtx; -- set pointers to bottom vertex
height ← vertices[lVtx].y;
lastX ← vertices[lVtx].x;
wordsPerLine ← destination.wordsPerLine;
TRUSTED { scanPtr ← LOOPHOLE[ destination.pxlBase
       + Inline.LongMult[destination.wordsPerLine, vertices[lVtx].y],
         LONG POINTER]; };
WHILE height < most DO-- Do until top scan line (rejects zero-height polys)
WHILE lEdge.length = 0 DO        -- work left edge counterclockwise
nxtVtx: CARDINAL ← (lVtx + vtxCountMinusOne) MOD vtxCount;
lEdge ← MakeEdge[vertices[lVtx], vertices[nxtVtx]];
lVtx ← nxtVtx;
ENDLOOP;
WHILE rEdge.length = 0 DO        -- work right edge clockwise
nxtVtx: CARDINAL ← (rVtx + 1) MOD vtxCount;
rEdge ← MakeEdge[vertices[rVtx], vertices[nxtVtx]];
rVtx ← nxtVtx;
ENDLOOP;
TRUSTED {         -- Get pixel pointer and Step scan pointer
pxlPtr ← scanPtr + LOOPHOLE[Inline.HighHalf[lEdge.xPos] / pxpWd, CARDINAL];
scanPtr ← scanPtr + wordsPerLine;
bb.dst.word ← pxlPtr;
bb.dst.bit ← (Inline.HighHalf[lEdge.xPos] MOD pxpWd) * bpPxl;
bb.width ← (Inline.HighHalf[rEdge.xPos] - Inline.HighHalf[lEdge.xPos]) * bpPxl;
BitBlt.BITBLT[bb];
};
lEdge.xPos ← lEdge.xPos + lEdge.xIncr;
lEdge.length ← lEdge.length - 1;
rEdge.xPos ← rEdge.xPos + rEdge.xIncr;
rEdge.length ← rEdge.length - 1;
height ← height + 1;
ENDLOOP;
Include bottom line of polygon
TRUSTED {
pxlPtr ← scanPtr + LOOPHOLE[Inline.HighHalf[lEdge.xPos] / pxpWd, CARDINAL];
bb.dst.word ← pxlPtr;
bb.dst.bit ← (Inline.HighHalf[lEdge.xPos] MOD pxpWd) * bpPxl;
bb.width ← (Inline.HighHalf[rEdge.xPos] - Inline.HighHalf[lEdge.xPos]) * bpPxl;
BitBlt.BITBLT[bb];
};
};
Initialization: Register DeviceType with Imager
TRUSTED {
color8BitClass: REF Imager.ClassRep ← NEW [Imager.ClassRep ← [
deviceType:   $Color8BitDisplay,
Init:     ImagerDisplayImpl.Init,
DoSaveAll:   ImagerDisplayImpl.DoSaveAll,
DoSave:    ImagerDisplayImpl.DoSave,
Flush:    ImagerDisplayImpl.Flush,
Close:    ImagerDisplayImpl.Close,
TransferBuffer:  ImagerDisplayImpl.TransferBuffer,
Reset:    ImagerDisplayImpl.Reset,
TranslateT:  ImagerDisplayTransformImpl.TranslateT,
RotateT:   ImagerDisplayTransformImpl.RotateT,
ScaleT:   ImagerDisplayTransformImpl.ScaleT,
ConcatT:   ImagerDisplayTransformImpl.ConcatT,
GetT:    ImagerDisplayTransformImpl.GetT,
SetT:    ImagerDisplayTransformImpl.SetT,
IntTranslateT: ImagerDisplayTransformImpl.IntTranslateT,
IntScaleT:  ImagerDisplayTransformImpl.IntScaleT,
GetClipper:   ImagerDisplayClipperImpl.GetClipper,
SetClipper:   ImagerDisplayClipperImpl.SetClipper,
ClipPath:   ImagerDisplayClipperImpl.ClipPath,
ClipRectangle:  ImagerDisplayClipperImpl.ClipRectangle,
TestRectangle:  ImagerDisplayClipperImpl.TestRectangle,
ClipIntRectangle: ImagerDisplayClipperImpl.ClipIntRectangle,
TestIntRectangle: ImagerDisplayClipperImpl.TestIntRectangle,
DoWithoutClipping: ImagerDisplayClipperImpl.DoWithoutClipping,
SetView:    ImagerDisplayClipperImpl.SetView,
ClipView:   ImagerDisplayClipperImpl.ClipView,
GetSurfaceBounds: ImagerDisplayClipperImpl.GetSurfaceBounds,
SetColor:  ImagerDisplayColorImpl.SetColor,
GetColor: ImagerDisplayColorImpl.GetColor,
MaskStroke:   ImagerDisplayMasksImpl.MaskStroke,
MaskFill:    ImagerDisplayMasksImpl.MaskFill,
MaskPixel:    ImagerDisplayMasksImpl.MaskPixel,
MaskBits:    ImagerDisplayMasksImpl.MaskBits,
MaskSegment:   ImagerDisplayMasksImpl.MaskSegment,
MaskIntSegment:  ImagerDisplayMasksImpl.MaskIntSegment,
MaskThinStroke:  ImagerDisplayMasksImpl.MaskThinStroke,
MaskRectangle:   ImagerDisplayMasksImpl.MaskRectangle,
MaskIntRectangle:  ImagerDisplayMasksImpl.MaskIntRectangle,
SetCP:    ImagerDisplayCharactersImpl.SetCP,
GetCP:    ImagerDisplayCharactersImpl.GetCP,
SetIntCP:    ImagerDisplayCharactersImpl.SetIntCP,
GetIntCP:   ImagerDisplayCharactersImpl.GetIntCP,
MaskChar:   ImagerDisplayCharactersImpl.MaskChar,
MaskCharacters: ImagerDisplayCharactersImpl.MaskCharacters,
MoveSurfaceRectangle: ImagerDisplayInteractiveImpl.MoveSurfaceRectangle,
SetColorInvert:   ImagerDisplayInteractiveImpl.SetColorInvert,
DrawBitmap:   ImagerDisplayInteractiveImpl.DrawBitmap,
SpecialOp:    ImagerDisplayInteractiveImpl.SpecialOp
]];
color8BitDisplayClass: REF ImagerDisplay.DisplayClassRep ← NEW [
ImagerDisplay.DisplayClassRep ← [
deviceType:   $Color8BitDisplay,
SetUp:    SetUp,
ShutDown:   ShutDown,
ColortoPixel:   ColortoPixel,
PixeltoColor:   PixeltoColor,
HilitePxls:  HilitePxls,
MovePxls:  MovePxls,
TransferPxls:  TransferPxls,
StoreScanSeg:  StoreScanSeg,
LoadScanSeg:  LoadScanSeg,
LoadTrapezoid: LoadTrapezoid,
LoadRectangle: LoadRectangle,
SetAnyPixel:  SetAnyPixel,
GetAnyPixel:  GetAnyPixel,
SetNextPixel:  SetNextPixel,
GetNextPixel:  GetNextPixel,
DrawLine:  DrawLine,
Tiler:    Tiler
]
];  
ImagerRegistration.RegisterDevice[color8BitClass];
ImagerDisplay.RegisterDisplayDevice[ color8BitDisplayClass ];
};
END.