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: BOOLEANTRUE]
    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: CARDINALIF 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.