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: BOOLEAN ← TRUE,
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.