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 { 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 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 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. JImager8bitDisplayImpl.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 get memory, pin it, set the transform and clipper Finds color table entry with least sum-of-square difference from color Using a slightly modified Bresenham's algorithm Κ F˜headšœ™J™Q—™šœ™Jšœ™—unitšΟk ˜ Jšœœ ˜Jšœ œœ˜,Jšœœ œ˜TJšœ œ˜!JšœœH˜UJšœ œA˜RJšœJ˜JJšœ$˜$Jšœ œE˜WJšœ-˜-JšœœA˜XJšœ?˜?Jšœ?˜?——head3šœ$˜$Jšœ=˜DJšœ˜Lšœ˜Lšœ ˜J˜—Jšœ œœœ˜ Jšœœœœ˜.LšœΟc˜7Lšœœ ž˜4Lšœœž˜—šŸœ œœ1œ˜WJšž1™1Jšœ3˜5šœœœ ˜.Jšœœ˜Jšœœœ ˜—šœœœ˜/Jšœœœ˜&—Jš œ œ œ5œž ˜hšœ œ œ˜ Jšœ%œœ˜ZJšœ˜—šœ$œ˜0JšœAœ˜Fšœ?˜?Jšœ0˜0Jšœ<˜˜>Jšœ4˜4Jšœ4˜4Jšœ4˜4Jšœ0˜0Jšœ0˜0Jšœ0˜0Jšœ5˜5Jšœ8˜8Jšœ.˜.Jšœ.˜.Jšœ.˜.šœ ˜ J˜—Jšœ˜——J˜—šŸœ œœž-˜SJšœœ3œœ ˜PJšœ˜—š Ÿœœœœœœž%˜~Jš œœœœž%˜VJšœ œ˜šœ˜JšœS˜SJšœ0˜0šœ˜Jšœ˜Jšœ˜Jšœ˜—šœ œ˜/Jšœ ˜'JšœD˜DJšœ˜—Jšœ˜šœœ˜%Jšœ˜Jšœ"˜"Jšœ!˜!Jšœ"˜"Jšœ œ˜—J˜—Jšœœœ,˜SJšœ6˜6Jšœœ˜Jšœœœ˜(Jšœ˜Jšœ˜—šŸœœœœ˜,Jšœœœœ˜!Jšœž˜2Jšœœ˜Jšœ˜—šŸ œ œœž˜]JšœF™FJšœ˜Jšœ œ˜Jšœ˜šœ œ ˜Jšœ˜Jšœœœœ˜[Jšœœ"˜7Jšœ˜—Jšœ ˜J˜—šŸ œ œœœ˜KJ˜Jšœ œ˜Jšœ˜Jšœ/˜/Jšœ3˜9J˜—šŸ œ œž*˜\J˜—šŸœ œ1ž˜\J˜—šŸ œ œœ˜FJšœœ˜)Jšœ˜J˜—š Ÿœœœœœ˜QJšœ˜Jšœ˜Jšœ<˜