Imager1bitDisplayImpl.mesa
This implements the low level routines for the LF display.
Last Edited by:
Crow, August 1, 1983 3:38 pm
DIRECTORY
Real USING [FixC],
Inline USING [LongMult],
BitBlt USING [AlignedBBTable, BBTableSpace, BITBLT, BitBltTable, BitBltTablePtr],
Environment USING [wordsPerPage, bitsPerWord],
UserTerminal USING [GetState, SetState, GetBitBltTable, screenWidth, screenHeight, State],
Space USING [Handle, Create, virtualMemory, defaultBase, LongPointer, Delete,
Map],
ImagerBasic USING [Transformation, IntRectangle, IntPair,
CIEColor, CIEColorRep, PixelArray, PixelArrayRep],
ImagerDisplay USING [ByteSequence, ByteSequenceRep, DisplayProcs, DisplayProcsRec,
Mask, MaskRep, VtxSequence],
ImagerDisplayPrivate USING [Data1bitPixels, Data1bitPixelsRep],
Imager1bitDisplay USING [SetUp, ShutDown, OpenPixelBuffer, ClosePixelBuffer,
ColortoPixel, PixeltoColor, HilitePxls, MovePxls, StorePxls,
LoadPxls, StoreScanSeg, LoadScanSeg, LoadTrapezoid, SetPxl,
GetPxl, DrawLine, Tiler];
Imager1bitDisplayImpl: CEDAR MONITOR
IMPORTS Real, Inline, BitBlt, Imager1bitDisplay, Space, UserTerminal
EXPORTS Imager1bitDisplay
= BEGIN
OPEN ImagerBasic, ImagerDisplay;
bpPxl: CARDINAL = 1;
maxPxlValue: CARDINAL = 1;
bpWd: CARDINAL = Environment.bitsPerWord;
pxpWd: CARDINAL = bpWd/bpPxl;
maxDisplayWidth: CARDINAL = 8192; -- number in excess of maximum expected BITBLT width
storage: Space.Handle; -- space for double-buffering
swapUnitSize: CARDINAL ← 50; -- unbelieveable crap for getting large spaces
pixelBuffer: PixelArray ← NIL; -- ref for double buffering
bufferLimits: Mask;
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] ];
bbTableForLF: BitBlt.BitBltTable;
NotImplementedYet: PUBLIC SIGNAL = CODE;
IncompatiblePixelArray: PUBLIC SIGNAL = CODE;
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]; };
GetBufferSpecs: PROCEDURE [place: IntPair] RETURNS [ CARDINAL, LONG POINTER ]
=
TRUSTED
INLINE {
wordsPerLine: CARDINAL;
pxlPtr: LONG POINTER;
IF pixelBuffer = NIL
THEN {
wordsPerLine ← bbTableForLF.dstBpl/pxpWd;
pxlPtr ← LOOPHOLE[ bbTableForLF.dst.word +
Inline.LongMult[wordsPerLine, place.y] +
(place.x/pxpWd),
LONG POINTER];
}
ELSE {
wordsPerLine ←
IF pixelBuffer.xPixels
MOD pxpWd = 0
THEN pixelBuffer.xPixels/pxpWd
ELSE pixelBuffer.xPixels/pxpWd + 1 ;
pxlPtr ← LOOPHOLE[ NARROW[pixelBuffer.data, ImagerDisplayPrivate.Data1bitPixels].p +
Inline.LongMult[wordsPerLine, place.y] +
(place.x/pxpWd),
LONG POINTER];
};
RETURN [ wordsPerLine, pxlPtr ];
};
SetUp: PUBLIC PROC [pin: BOOLEAN ← TRUE]
RETURNS [
REF Transformation, Mask, DisplayProcs] =
TRUSTED {
get memory, pin it, set the transform and clipper
oldState: UserTerminal.State;
IF NOT UserTerminal.GetState[] = on
THEN oldState ← UserTerminal.SetState[ on ];
bbTableForLF ← UserTerminal.GetBitBltTable[];
RETURN[
NEW [Transformation ← [1., 0., 0., 0., -1., UserTerminal.screenHeight, mirrorY] ],
NEW [MaskRep ← [
1, 1, UserTerminal.screenHeight, UserTerminal.screenWidth - 1, NIL] ],
NEW [DisplayProcsRec ← [ setUp: Imager1bitDisplay.SetUp,
shutDown: Imager1bitDisplay.ShutDown,
openPixelBuffer: Imager1bitDisplay.OpenPixelBuffer,
closePixelBuffer: Imager1bitDisplay.ClosePixelBuffer,
colortoPixel: Imager1bitDisplay.ColortoPixel,
pixeltoColor: Imager1bitDisplay.PixeltoColor,
hilitePxls: Imager1bitDisplay.HilitePxls,
movePxls: Imager1bitDisplay.MovePxls,
storePxls: Imager1bitDisplay.StorePxls,
loadPxls: Imager1bitDisplay.LoadPxls,
storeScanSeg: Imager1bitDisplay.StoreScanSeg,
loadScanSeg: Imager1bitDisplay.LoadScanSeg,
loadTrapezoid: Imager1bitDisplay.LoadTrapezoid,
setPixel: Imager1bitDisplay.SetPxl,
getPixel: Imager1bitDisplay.GetPxl,
drawLine: Imager1bitDisplay.DrawLine,
tiler: Imager1bitDisplay.Tiler
]
]
];
};
ShutDown:
PUBLIC PROC [] =
TRUSTED {
-- free memory in case the last user has left
oldState: UserTerminal.State;
oldState ← UserTerminal.SetState[ disconnected ];
};
OpenPixelBuffer:
PUBLIC
PROC [box: Mask, buffer: PixelArray ←
NIL]
RETURNS [PixelArray] =
TRUSTED {
-- redirect writes for double-buffer
boxWidth: CARDINAL ← box.fSize;
boxHeight: CARDINAL ← box.sSize;
IF pixelBuffer # NIL THEN RETURN [pixelBuffer]; -- can't support multiple buffers yet
IF buffer = NIL
THEN {
wordsPerLine: CARDINAL ← IF boxWidth MOD pxpWd = 0 THEN boxWidth/pxpWd
ELSE boxWidth/pxpWd + 1;
pages: CARDINAL ← (Inline.LongMult[wordsPerLine, boxHeight + 1] /
Environment.wordsPerPage) + 1;
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];
pixelBuffer ←
NEW[ PixelArrayRep ← [
xPixels: boxWidth,
yPixels: boxHeight,
maxSampleValue: maxPxlValue,
samplesPerPixel: 1,
xDelta: 1,
yDelta: wordsPerLine,
data: NEW[ ImagerDisplayPrivate.Data1bitPixelsRep ← [ Space.LongPointer[storage] ] ]
] ]
}
ELSE
IF
NOT ( buffer.maxSampleValue = maxPxlValue
AND
buffer.xPixels MOD pxpWd = 0 AND -- Check for integer row length in words
ISTYPE [buffer.data, ImagerDisplayPrivate.Data1bitPixels] )
THEN ERROR IncompatiblePixelArray[]
ELSE { buffer.xPixels ← boxWidth;
buffer.yPixels ← boxHeight;
pixelBuffer ← buffer; };
bufferLimits ← box; -- keep limits for translating loads to buffer
RETURN [pixelBuffer];
};
ClosePixelBuffer:
PUBLIC
PROC [] =
TRUSTED {
IF pixelBuffer = NIL THEN RETURN;
Space.Delete[storage]; -- deallocate bit storage
pixelBuffer ← NIL;
};
ColortoPixel:
PUBLIC PROC [color: CIEColor]
RETURNS [
LONG
CARDINAL] = {
-- Color to device transform
RETURN [ IF color.Y > 0 THEN 0 ELSE LAST[CARDINAL] ];
};
PixeltoColor:
PUBLIC PROC [pxlValue:
LONG
CARDINAL]
RETURNS [CIEColor] =
TRUSTED {
color: CIEColor ← NEW[ CIEColorRep ];
IF pxlValue # 0 THEN pxlValue ← 1; -- bivalued pixels
color.x ← Real.FixC[pxlValue * LAST[CARDINAL]]; -- this should be proceeded by a transform
color.y ← Real.FixC[pxlValue * LAST[CARDINAL]];
color.Y ← Real.FixC[pxlValue * LAST[CARDINAL]];
RETURN [ color ];
};
HilitePxls:
PUBLIC PROC [area: IntRectangle] = {
-- Device dependent highlighting scheme
};
MovePxls:
PUBLIC PROC [source: IntRectangle, destination: IntPair] =
TRUSTED {
-- move on display
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
srcPxlPtr, dstPxlPtr: LONG POINTER;
wordsPerLine: CARDINAL;
[ wordsPerLine, dstPxlPtr ] ← GetBufferSpecs[ destination];
[ wordsPerLine, srcPxlPtr ] ← GetBufferSpecs[ IntPair[source.x, source.y] ];
bb^ ← bbTableForLF;
bb.dst.word ← dstPxlPtr;
bb.dst.bit ← destination.x MOD pxpWd;
bb.src.word ← srcPxlPtr;
bb.src.bit ← source.x MOD pxpWd;
bb.srcDesc.srcBpl ← bb.dstBpl ← wordsPerLine * bpWd;
bb.width ← MIN[source.w, (UserTerminal.screenWidth - destination.x)];
bb.height ← MIN[source.h, UserTerminal.screenHeight - destination.y];
BitBlt.BITBLT[bb];
};
StorePxls:
PUBLIC PROC [source: IntRectangle]
RETURNS [PixelArray] = {
dest: PixelArray ← NEW[ PixelArrayRep ];
RETURN [dest];
};
LoadPxls:
PUBLIC
PROC [source: PixelArray ←
NIL, destination: IntRectangle] =
TRUSTED {
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
IF source = NIL
THEN {
IF pixelBuffer =
NIL
THEN
RETURN[]
-- error return if no buffer
ELSE source ← pixelBuffer; } -- default to double buffer
ELSE IF NOT ( source.maxSampleValue = maxPxlValue AND
source.xPixels MOD pxpWd = 0 AND -- Check for integer row length in words
ISTYPE [source.data, ImagerDisplayPrivate.Data1bitPixels] )
THEN ERROR IncompatiblePixelArray[]; -- error return if not BLT-able
bb^ ← bbTableForLF;
bb.dst.word ← LOOPHOLE[bb.dst.word + Inline.LongMult[bb.dstBpl/pxpWd, destination.y] +
(destination.x/pxpWd), LONG POINTER];
bb.dst.bit ← destination.x MOD pxpWd;
bb.src.word ← NARROW[source.data, ImagerDisplayPrivate.Data1bitPixels].p;
bb.srcDesc.srcBpl ←
IF source # pixelBuffer
THEN source.xPixels
ELSE IF pixelBuffer.xPixels MOD pxpWd = 0
THEN (pixelBuffer.xPixels/pxpWd)*bpWd
ELSE (pixelBuffer.xPixels/pxpWd + 1)*bpWd;
bb.width ← MIN[source.xPixels,
destination.w,
UserTerminal.screenWidth - destination.x];
bb.height ← MIN[source.yPixels,
destination.h,
UserTerminal.screenHeight - destination.y];
BitBlt.BITBLT[bb];
};
StoreScanSeg:
PUBLIC PROC [x, y, length:
CARDINAL]
RETURNS [ByteSequence] = {
segment: ByteSequence ← NEW [ ByteSequenceRep[length/pxpWd] ];
RETURN [segment];
};
LoadScanSeg:
PUBLIC
PROC [x, y, length:
CARDINAL, segment: ByteSequence, transparent:
BOOLEAN] =
TRUSTED {
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
pxlPtr: LONG POINTER;
wordsPerLine: CARDINAL;
IF pixelBuffer # NIL THEN { x ← x - bufferLimits.fMin; y ← y - bufferLimits.sMin; };
[wordsPerLine, pxlPtr] ← GetBufferSpecs[ [x, y] ];
bb^ ← nullBitBltTable;
bb.dst.word ← pxlPtr;
bb.dst.bit ← x MOD pxpWd;
bb.src.word ← LOOPHOLE[segment, LONG POINTER];
bb.width ← length;
BitBlt.BITBLT[bb];
};
LoadTrapezoid:
PUBLIC
PROC [top, bottom, leftTop, leftBot, rightTop, rightBot:
CARDINAL, pxlValue:
LONG
CARDINAL] =
TRUSTED {
-- Scan convert trapezoid, constant color
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
pxlPtr: LONG POINTER;
color: CARDINAL;
wordsPerLine: CARDINAL;
IF pixelBuffer #
NIL
THEN {
-- adjust for buffer limits
top ← top - bufferLimits.sMin; bottom ← bottom - bufferLimits.sMin;
leftTop ← leftTop - bufferLimits.fMin; leftBot ← leftBot - bufferLimits.fMin;
rightTop ← rightTop - bufferLimits.fMin; rightBot ← rightBot - bufferLimits.fMin;
};
[wordsPerLine, pxlPtr] ← GetBufferSpecs[ [leftTop, bottom] ];
IF leftTop = leftBot
AND rightTop = rightBot
THEN {
-- rectangle
color ← IF pxlValue # 0 THEN LAST[CARDINAL] ELSE 0; -- make brick for BitBlt
bb^ ← nullBitBltTable;
bb.flags.gray ← TRUE;
bb.dstBpl ← wordsPerLine * bpWd;
bb.dst.word ← pxlPtr;
bb.dst.bit ← leftBot MOD pxpWd;
bb.src.word ← @color;
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 15, heightMinusOne: 0];
bb.width ← MIN[rightBot - leftBot + 1, UserTerminal.screenWidth - leftBot];
bb.height ← MIN[top - bottom + 1, UserTerminal.screenHeight - bottom];
BitBlt.BITBLT[bb];
}
ELSE {
-- not rectangle
};
};
SetPxl:
PUBLIC PROC [x, y:
CARDINAL, pxlValue:
LONG
CARDINAL] =
TRUSTED {
wordsPerLine: CARDINAL;
pxlPtr: LONG POINTER TO PACKED ARRAY [0..16) OF BOOLEAN;
[wordsPerLine, LOOPHOLE[pxlPtr, LONG POINTER]] ← GetBufferSpecs[ [x, y] ];
pxlPtr[x MOD pxpWd] ← IF pxlValue # 0 THEN TRUE ELSE FALSE;
};
GetPxl:
PUBLIC PROC [x, y:
CARDINAL]
RETURNS [
LONG
CARDINAL] =
TRUSTED {
wordsPerLine: CARDINAL;
pxlPtr: LONG POINTER TO PACKED ARRAY [0..16) OF BOOLEAN;
[wordsPerLine, LOOPHOLE[pxlPtr, LONG POINTER]] ← GetBufferSpecs[ [x, y] ];
RETURN [ IF pxlPtr[x MOD pxpWd] THEN 1 ELSE 0 ];
};
DrawLine:
PUBLIC PROC [a, b: IntPair, pxlValue:
LONG
CARDINAL] =
TRUSTED {
-- fast line, constant color
Using a slightly modified Bresenham's algorithm
increment, bias, error, yBump: INTEGER; bit: [0..pxpWd); t: IntPair;
wordsPerLine: CARDINAL;
bitValue: BOOLEAN;
pxlPtr: LONG POINTER TO PACKED ARRAY [0..16) OF BOOLEAN;
IF pixelBuffer #
NIL
THEN {
-- adjust for buffer limits
a.x ← a.x - bufferLimits.fMin; a.y ← a.y - bufferLimits.sMin;
b.x ← b.x - bufferLimits.fMin; b.y ← b.y - bufferLimits.sMin;
};
IF a.x > b.x THEN { t ← a; a ← b; b ← t; }; -- make sure of positive-going x
bitValue ← IF pxlValue # 0 THEN FALSE ELSE TRUE;
[wordsPerLine, LOOPHOLE[pxlPtr, LONG POINTER]] ← GetBufferSpecs[ a ];
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;
bit ← a.x MOD pxpWd;
FOR i:
CARDINAL
IN [0..
ABS[b.x-a.x]]
DO
pxlPtr[bit] ← bitValue;
IF bit = (pxpWd - 1) THEN { pxlPtr ← pxlPtr + 1; bit ← 0 }
ELSE bit ← bit + 1;
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;
bit ← a.x MOD pxpWd;
FOR i:
CARDINAL
IN [0..
ABS[b.y-a.y]]
DO
pxlPtr[bit] ← bitValue;
pxlPtr ← pxlPtr + yBump;
IF error > 0
THEN {
error ← error - bias;
IF bit = (pxpWd - 1) THEN { pxlPtr ← pxlPtr + 1; bit ← 0 }
ELSE bit ← bit + 1;
};
error ← error + increment;
ENDLOOP;
};
};
Tiler:
PUBLIC PROC [vtxCount:
CARDINAL, vertices: VtxSequence] = {
};
END.