Imager8bitDisplayImpl.mesa
This implements the low level routines for the color display at 8 bits per pixel.
Last Edited by:
Crow, June 16, 1983 6:23 pm
DIRECTORY
Real   USING [Float],
Inline   USING [BytePair, LongMult, BITAND],
BitBlt    USING [AlignedBBTable, BBTableSpace, BITBLT, BitBltTable, BitBltTablePtr],
Environment USING [wordsPerPage],
Space   USING [Handle, Create, virtualMemory, defaultBase, LongPointer, Delete, Map],
ImagerBasic USING [TransformRecord, ClipperRecord, IntRectangle, IntVec, RGBValue,
       PxlValue, PixelArray, PixelArrayRep, ByteSequence, ByteSequenceRep,
       DeviceProcs, DeviceProcsRec],
ColorDisplay USING [GetMode, SetMode, TurnOn, GetColor, SetRed, GetPixel, disconnected,
       width, height, baseA, wplA, SetColor],
Imager8bitDisplay USING [SetUp, ShutDown, OpenPixelBuffer, ClosePixelBuffer, RGBtoPixel,
         PixeltoRGB, HilitePxls, MovePxls, StorePxls, LoadPxls,
         LoadScanSeg, LoadTrapezoid, SetPxl, GetPxl, DrawLine];
Imager8bitDisplayImpl: CEDAR MONITOR
IMPORTS Real, Inline, BitBlt, ColorDisplay, Imager8bitDisplay, Space
EXPORTS Imager8bitDisplay
= BEGIN
OPEN ImagerBasic;
NoDisplay: PUBLIC SIGNAL = CODE;
IncompatibleDisplayMode: PUBLIC SIGNAL = CODE;
storage: Space.Handle;    -- space for double-buffering
swapUnitSize: CARDINAL ← 50;   -- unbelieveable crap
pixelBuffer: PixelArray ← NIL;   -- ref for double buffering
nullBitBltTable: BitBlt.BitBltTable = [dst: [word: NIL, bit: 0], dstBpl: 8192, src: [word: NIL, bit: 0],
         srcDesc: [srcBpl[8192]], 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 [] RETURNS [TransformRecord, ClipperRecord, DeviceProcs] = TRUSTED {
get memory, pin it, set the transform and clipper
IF ColorDisplay.GetMode[] = ColorDisplay.disconnected
THEN IF ColorDisplay.SetMode[ [FALSE, 8, 0] ]
THEN ColorDisplay.TurnOn[]
ELSE ERROR NoDisplay[]
ELSE IF ColorDisplay.GetMode[] # [FALSE, 8, 0]
THEN ERROR IncompatibleDisplayMode[];
FOR i: PxlValue IN [0..40) DO ColorDisplay.SetColor[ i + 216, 0, i*6, i*6, i*6] ENDLOOP; -- greyscale
FOR i: PxlValue IN [0..216) DO
ColorDisplay.SetColor[ i, 0, 36 * (i MOD 6 + 1), 36 * ((i/6) MOD 6 + 1), 36 * (i/36 + 1)];
ENDLOOP;
RETURN[ [0, ColorDisplay.height, mirrorY, NIL],
  [1, ColorDisplay.width - 1, 1, ColorDisplay.height, rectangle, NIL],
  NEW [DeviceProcsRec ← [ setUp:     Imager8bitDisplay.SetUp,
         shutDown:   Imager8bitDisplay.ShutDown,
         openPixelBuffer: Imager8bitDisplay.OpenPixelBuffer,
         closePixelBuffer: Imager8bitDisplay.ClosePixelBuffer,
         RGBtoPixel:   Imager8bitDisplay.RGBtoPixel,
         pixeltoRGB:   Imager8bitDisplay.PixeltoRGB,
         hilitePxls:   Imager8bitDisplay.HilitePxls,
         movePxls:   Imager8bitDisplay.MovePxls,
         getPxls:   Imager8bitDisplay.StorePxls,
         loadPxls:   Imager8bitDisplay.LoadPxls,
         loadScanSeg:  Imager8bitDisplay.LoadScanSeg,
         loadTrapezoid: Imager8bitDisplay.LoadTrapezoid,
         setPixel:   Imager8bitDisplay.SetPxl,
         getPixel:   Imager8bitDisplay.GetPxl,
         drawLine:  Imager8bitDisplay.DrawLine
         ]
  ]
];
};
ShutDown: PUBLIC PROC [] = TRUSTED {  -- free memory in case the last user has left
IF NOT ColorDisplay.SetMode[ ColorDisplay.disconnected ] THEN ERROR NoDisplay[];
};
OpenPixelBuffer: PUBLIC PROC [buffer: PixelArray ← NIL] RETURNS [PixelArray] = TRUSTED { -- redirect writes for double-buffer
IF pixelBuffer # NIL THEN RETURN [pixelBuffer]; -- can't support multiple buffers yet
IF buffer = NIL
THEN {
pages: CARDINAL ← (Inline.LongMult[ColorDisplay.width/2, ColorDisplay.height + 1] /
                  Environment.wordsPerPage) + 1;
storage ← Space.Create[
pages,
Space.virtualMemory,
Space.defaultBase];
FOR offset: CARDINAL ← 0, offset + swapUnitSize
WHILE offset + swapUnitSize <= pages DO
[] ← Space.Create[size: swapUnitSize, parent: storage, base: offset]
ENDLOOP;
Space.Map[storage];
pixelBuffer ← NEW[ PixelArrayRep ← [
pixelsPerWord: 2,
numberOfRows: ColorDisplay.height,
pixelsPerRow: ColorDisplay.width,
array: Space.LongPointer[storage],
colorTable: NIL ] ]
}
ELSE IF buffer.pixelsPerWord = 2 AND buffer.numberOfRows <= ColorDisplay.height AND
            buffer.pixelsPerRow <= ColorDisplay.width
  THEN pixelBuffer ← buffer
  ELSE SIGNAL IncompatibleDisplayMode[];
RETURN [pixelBuffer];
};
ClosePixelBuffer: PUBLIC PROC [] = TRUSTED {
IF pixelBuffer = NIL THEN RETURN;
Space.Delete[storage];   -- deallocate bit storage
pixelBuffer ← NIL;
};
RGBtoPixel: PUBLIC PROC [color: RGBValue] RETURNS [PxlValue] = { -- Color to device transform
Finds color table entry with least sum-of-square difference from color
val: RGBValue;
sum, minSum: REAL;
entry: PxlValue;
FOR i: PxlValue IN [0..256) DO
val ← PixeltoRGB[i];
sum ← SQR[val.red - color.red] + SQR[val.green - color.green] + SQR[val.blue - color.blue];
IF sum < minSum THEN { entry ← i; minSum ← sum; };
ENDLOOP;
RETURN [ entry ];
};
PixeltoRGB: PUBLIC PROC [pxlValue: PxlValue] RETURNS [RGBValue] = TRUSTED {
r, g, b: [0..256);
cardValue: CARDINAL;
cardValue ← pxlValue;
[r, g, b] ← ColorDisplay.GetColor[ cardValue ];
RETURN [ [Real.Float[r], Real.Float[g], Real.Float[b]] ];
};
HilitePxls: PUBLIC PROC [area: IntRectangle] = {     -- Device dependent highlighting scheme
};
MovePxls: PUBLIC PROC [source: IntRectangle, destination: IntVec] = {     -- move on display
};
StorePxls: PUBLIC PROC [source: IntRectangle] RETURNS [PixelArray] = {
dest: PixelArray ← NEW[ PixelArrayRep ];
RETURN [dest];
};
LoadPxls: PUBLIC PROC [source: PixelArray ← NIL, destination: IntVec] = TRUSTED {
OPEN ColorDisplay;
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
pxlPtr: LONG POINTER;
IF source = NIL THEN source ← pixelBuffer;  -- default to double buffer
IF source = NIL THEN RETURN[];     -- error return
pxlPtr ← LOOPHOLE[baseA + Inline.LongMult[wplA, destination.y] + (destination.x/2),
                       LONG POINTER];
bb^ ← nullBitBltTable;
bb.dst.word ← pxlPtr + destination.x + destination.y * wplA;
IF Inline.BITAND[destination.x, 1] # 0 THEN bb.dst.bit ← 8;
bb.src.word ← LOOPHOLE[source.array, LONG POINTER];
bb.srcDesc.srcBpl ← source.pixelsPerRow * 8;
bb.dstBpl ← wplA * 16;
bb.width ← MIN[source.pixelsPerRow * 8, (ColorDisplay.width - 1 - destination.x) * 8];
bb.height ← MIN[source.numberOfRows, ColorDisplay.height - destination.y];
BitBlt.BITBLT[bb];
};
StoreScanSeg: PUBLIC PROC [x, y, length: CARDINAL] RETURNS [ByteSequence] = {
segment: ByteSequence ← NEW [ ByteSequenceRep[length/2] ];
RETURN [segment];
};
LoadScanSeg: PUBLIC PROC [x, y, length: CARDINAL, segment: ByteSequence] = TRUSTED {
OPEN ColorDisplay;
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
pxlPtr: LONG POINTER;
pxlPtr ← IF pixelBuffer = NIL
THEN LOOPHOLE[baseA + Inline.LongMult[wplA, y] + (x/2), LONG POINTER]
ELSE LOOPHOLE[pixelBuffer.array + Inline.LongMult[pixelBuffer.pixelsPerRow/2, y] + (x/2),
                        LONG POINTER];
bb^ ← nullBitBltTable;
bb.dst.word ← pxlPtr;
IF Inline.BITAND[x, 1] # 0 THEN bb.dst.bit ← 8;
bb.src.word ← LOOPHOLE[segment, LONG POINTER];
bb.width ← length * 8;
BitBlt.BITBLT[bb];
};
LoadTrapezoid: PUBLIC PROC [top, bottom, leftTop, leftBot, rightTop, rightBot: CARDINAL, pxlValue: PxlValue] = TRUSTED {   -- Scan convert trapezoid, constant color
OPEN ColorDisplay;
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
pxlPtr: LONG POINTER;
color: CARDINAL;
IF leftTop = leftBot AND rightTop = rightBot THEN {      -- rectangle
pxlPtr ← IF pixelBuffer = NIL
THEN LOOPHOLE[baseA + Inline.LongMult[wplA, bottom] + (leftBot/2), LONG POINTER]
ELSE LOOPHOLE[pixelBuffer.array + Inline.LongMult[pixelBuffer.pixelsPerRow/2, bottom] +
                   (leftBot/2), LONG POINTER];
color ← pxlValue * 256 + pxlValue;    -- make pxlValue brick for BitBlt                      
bb^ ← nullBitBltTable;
bb.flags.gray ← TRUE;
bb.dst.word ← pxlPtr;
IF Inline.BITAND[leftBot, 1] # 0 THEN bb.dst.bit ← 8;
bb.src.word ← @color;
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 15, heightMinusOne: 0];
bb.dstBpl ← wplA * 16;
bb.width ← MIN[(rightBot - leftBot + 1) * 8, (ColorDisplay.width - leftBot) * 8];
bb.height ← MIN[(top - bottom + 1), ColorDisplay.height - bottom];
BitBlt.BITBLT[bb];
};
};
SetPxl: PUBLIC PROC [x, y: CARDINAL, pxlValue: PxlValue] = TRUSTED {
byte: [0..256) ← pxlValue;
ColorDisplay.SetRed[ x, y, byte ];
};
GetPxl: PUBLIC PROC [x, y: CARDINAL] RETURNS [PxlValue] = TRUSTED {
pixel: PxlValue;
r, g, b: [0..256);
[r, g, b] ← ColorDisplay.GetPixel[x, y];
pixel ← r;
RETURN [ pixel ];
};
DrawLine: PUBLIC PROC [a, b: IntVec, pxlValue: PxlValue] = TRUSTED { -- fast line, constant color
Using a slightly modified Bresenham's algorithm
OPEN ColorDisplay;
byteValue: [0..256);
increment, bias, error, yBump: INTEGER; leftByte: BOOLEAN; t: IntVec;
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 ← pxlValue;
pxlPtr ← IF pixelBuffer = NIL
THEN LOOPHOLE[baseA + Inline.LongMult[wplA, a.y] + (a.x/2),
                 LONG POINTER TO Inline.BytePair]
ELSE LOOPHOLE[LOOPHOLE[pixelBuffer.array, LONG POINTER] +
      Inline.LongMult[pixelBuffer.pixelsPerRow/2, a.y] +
               (a.x/2), 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] * wplA;
increment ← ABS[increment]; bias ← ABS[bias];
error ← increment - bias/2;
leftByte ← Inline.BITAND[a.x, 1] = 0;   -- left byte is high byte
FOR i: CARDINAL IN [0..ABS[b.x-a.x]] DO
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] * wplA;
increment ← ABS[increment]; bias ← ABS[bias];
error ← increment - bias/2;
leftByte ← Inline.BITAND[a.x, 1] = 0;
FOR i: CARDINAL IN [0..ABS[b.y-a.y]] DO
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;
};
};
END.