DIRECTORY Real USING [FixC, Float], Inline USING [LongMult, BITOR, BITSHIFT], BitBlt USING [AlignedBBTable, BBTableSpace, BITBLT, BitBltTable, BitBltTablePtr], Environment USING [wordsPerPage, bitsPerWord], Space USING [Handle, Create, virtualMemory, defaultBase, LongPointer, Delete, Map], ImagerBasic USING [Transformation, TransformationRep, IntRectangle, IntPair, CIEColor, CIEColorRep, PixelArray, PixelArrayRep], ImagerDisplay USING [ByteSequence, ByteSequenceRep, Data4bitPixels, Data4bitPixelsRep, DisplayProcs, DisplayProcsRec, ClipperRecord, VtxSequence], ColorDisplay USING [Byte, GetMode, SetMode, TurnOn, GetColor, SetRed, GetPixel, disconnected, width, height, baseA, wplA, SetColor], Imager4bitDisplay; --exports to this interface Imager4bitDisplayImpl: CEDAR MONITOR IMPORTS Real, Inline, BitBlt, ColorDisplay, Space EXPORTS Imager4bitDisplay = BEGIN OPEN ImagerBasic, ImagerDisplay, Inline; NoDisplay: PUBLIC SIGNAL = CODE; IncompatibleDisplayMode: PUBLIC SIGNAL = CODE; IncompatiblePixelArray: PUBLIC SIGNAL = CODE; BadBitAlignment: PUBLIC ERROR = CODE; PixelWidth: TYPE = [0..maxPxlValue]; PixelIndex: TYPE = [0..pxpWd); PixelAddr: TYPE = PACKED ARRAY PixelIndex OF PixelWidth; bpPxl: CARDINAL = 4; maxPxlValue: CARDINAL = 15; bpWd: CARDINAL = Environment.bitsPerWord; pxpWd: CARDINAL = bpWd/bpPxl; maxDisplayWidth: CARDINAL = 4096; -- 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: ClipperRecord; 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]; }; GetBufferSpecs: PROCEDURE [place: IntPair] RETURNS [ CARDINAL, LONG POINTER ] = TRUSTED INLINE { wordsPerLine: CARDINAL; pxlPtr: LONG POINTER; IF pixelBuffer = NIL THEN { wordsPerLine _ ColorDisplay.wplA; pxlPtr _ LOOPHOLE[ ColorDisplay.baseA + 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, Data4bitPixels].p + Inline.LongMult[wordsPerLine, place.y] + (place.x/pxpWd), LONG POINTER]; }; RETURN [ wordsPerLine, pxlPtr ]; }; GenColor: PROC [n: CARDINAL] RETURNS[r,g,b: ColorDisplay.Byte] = { SELECT n FROM 0 => RETURN[1, 0, 0]; --red 1 => RETURN[0, 0, 1]; --blue 2 => RETURN[0, 1, 0]; --green 3 => RETURN[0, 1, 1]; --cyan 4 => RETURN[1, 0, 1]; --magenta 5 => RETURN [1, 1, 0]; --yellow ENDCASE => RETURN[0,0,0]; }; SetUp: PUBLIC PROC [] RETURNS [Transformation, REF ClipperRecord, DisplayProcs] = TRUSTED { red, green, blue: ColorDisplay.Byte; IF ColorDisplay.GetMode[] = ColorDisplay.disconnected THEN IF ColorDisplay.SetMode[ [FALSE, 4, 0] ] THEN ColorDisplay.TurnOn[] ELSE ERROR NoDisplay[] ELSE IF ColorDisplay.GetMode[] # [FALSE, 4, 0] THEN ERROR IncompatibleDisplayMode[]; FOR i: LONG CARDINAL IN [16..1024) DO [red, green, blue] _ GenColor[i MOD 6]; ColorDisplay.SetColor[ i, 0, red, green, blue] ENDLOOP; -- put in red, green, blue, cyan, magenta, yellow sequences ColorDisplay.SetColor[ 5, 0, 168, 0, 87]; --trade with yellow(0) for debugging ColorDisplay.SetColor[ 1, 0, 213, 0, 42]; ColorDisplay.SetColor[ 2, 0, 255, 0, 0]; -- full red ColorDisplay.SetColor[ 3, 0, 210, 45, 0]; ColorDisplay.SetColor[ 4, 0, 168, 87, 0]; ColorDisplay.SetColor[ 0, 0, 126, 129, 0]; --yellow ColorDisplay.SetColor[ 6, 0, 84, 171, 0]; ColorDisplay.SetColor[ 7, 0, 42, 213, 0]; ColorDisplay.SetColor[ 8, 0, 0, 255, 0]; --full green ColorDisplay.SetColor[ 9, 0, 0, 213, 42]; ColorDisplay.SetColor[ 10, 0, 0, 171, 84]; ColorDisplay.SetColor[ 11, 0, 0, 129, 126]; ColorDisplay.SetColor[ 12, 0, 0, 87, 168]; ColorDisplay.SetColor[ 13, 0, 0, 45, 210]; ColorDisplay.SetColor[ 14, 0, 0, 0, 255]; --full blue ColorDisplay.SetColor[ 15, 0, 128, 0, 127]; RETURN[ NEW [TransformationRep _ [1., 0., 0., 0.,-1., ColorDisplay.height, mirrorY] ], NEW [ClipperRecord _ [1, ColorDisplay.width - 1, 1, ColorDisplay.height, rectangle, NIL] ], NEW [DisplayProcsRec _ [ setUp: SetUp, shutDown: ShutDown, openPixelBuffer: OpenPixelBuffer, closePixelBuffer: ClosePixelBuffer, ColortoPixel: ColortoPixel, pixeltoColor: PixeltoColor, hilitePxls: HilitePxls, movePxls: MovePxls, storePxls: StorePxls, loadPxls: LoadPxls, storeScanSeg: StoreScanSeg, loadScanSeg: LoadScanSeg, loadTrapezoid: LoadTrapezoid, setPixel: SetPxl, getPixel: GetPxl, drawLine: DrawLine, tiler: Tiler ] ] ]; }; 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 [box: ClipperRecord, buffer: PixelArray _ NIL] RETURNS [PixelArray] = TRUSTED { -- redirect writes for double-buffer boxWidth: CARDINAL _ box.xMax - box.xMin + 1; boxHeight: CARDINAL _ box.yMax - box.yMin + 1; 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, data: NEW[ Data4bitPixelsRep _ [ 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, Data4bitPixels] ) THEN SIGNAL IncompatibleDisplayMode[] 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 val: CIEColor; sum, minSum: REAL; entry: LONG CARDINAL; FOR i: LONG CARDINAL IN [0..maxPxlValue] DO val _ PixeltoColor[i]; sum _ SQR[val.x - color.x] + SQR[val.y - color.y] + SQR[val.Y - color.Y]; 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 [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[ [source.x, source.y] ]; bb^ _ nullBitBltTable; bb.dst.word _ dstPxlPtr; bb.dst.bit _ (destination.x MOD pxpWd) * bpPxl; bb.src.word _ srcPxlPtr; bb.src.bit _ (source.x MOD pxpWd) * bpPxl; bb.srcDesc.srcBpl _ bb.dstBpl _ wordsPerLine * bpWd; bb.width _ MIN[source.w * bpPxl, (ColorDisplay.width - destination.x) * bpPxl]; bb.height _ MIN[source.h, ColorDisplay.height - 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: IntPair, transparent: BOOLEAN] = 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, Data4bitPixels] ) THEN ERROR IncompatiblePixelArray[]; -- error return if not BLT-able bb^ _ nullBitBltTable; bb.dst.word _ LOOPHOLE[ ColorDisplay.baseA + Inline.LongMult[ColorDisplay.wplA, destination.y] + (destination.x/pxpWd), LONG POINTER]; IF destination.x MOD pxpWd # 0 THEN bb.dst.bit _ bpPxl; bb.src.word _ NARROW[source.data, Data4bitPixels].p; bb.srcDesc.srcBpl _ IF source # pixelBuffer THEN source.xPixels * bpPxl ELSE IF pixelBuffer.xPixels MOD pxpWd = 0 THEN (pixelBuffer.xPixels/pxpWd)*bpWd ELSE (pixelBuffer.xPixels/pxpWd + 1)*bpWd; bb.dstBpl _ ColorDisplay.wplA * bpWd; bb.width _ MIN[source.xPixels * bpPxl, (ColorDisplay.width - 1 - destination.x) * bpPxl]; bb.height _ MIN[source.yPixels, ColorDisplay.height - 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 { y _ y - bufferLimits.yMin; x _ x - bufferLimits.xMin; }; [wordsPerLine, pxlPtr] _ GetBufferSpecs[ [x, y] ]; bb^ _ nullBitBltTable; bb.dst.word _ pxlPtr; bb.dst.bit _ (x MOD pxpWd) * bpPxl; bb.src.word _ LOOPHOLE[segment, LONG POINTER]; bb.width _ length * bpPxl; 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; shortPxlValue: CARDINAL _ pxlValue; IF pixelBuffer # NIL THEN { -- adjust for buffer limits top _ top - bufferLimits.yMin; bottom _ bottom - bufferLimits.yMin; leftTop _ leftTop - bufferLimits.xMin; leftBot _ leftBot - bufferLimits.xMin; rightTop _ rightTop - bufferLimits.xMin; rightBot _ rightBot - bufferLimits.xMin; }; [wordsPerLine, pxlPtr] _ GetBufferSpecs[ [leftTop, bottom] ]; IF leftTop = leftBot AND rightTop = rightBot THEN { -- rectangle color _ BITOR[BITSHIFT[shortPxlValue, 4], shortPxlValue]; -- make pxlValue brick for BitBlt color _ BITOR[BITSHIFT[color, 8], color]; bb^ _ nullBitBltTable; bb.flags.gray _ TRUE; bb.dst.word _ pxlPtr; bb.dst.bit _ (leftBot MOD bpPxl) * bpPxl; bb.src.word _ @color; bb.srcDesc.gray _ [yOffset: 0, widthMinusOne: 15, heightMinusOne: 0]; bb.dstBpl _ wordsPerLine * bpWd; bb.width _ MIN[(rightBot - leftBot + 1) * bpPxl, (ColorDisplay.width - leftBot) * bpPxl]; bb.height _ MIN[(top - bottom + 1), ColorDisplay.height - bottom]; BitBlt.BITBLT[bb];} ELSE { -- not rectangle }; }; SetPxl: PUBLIC PROC [x, y: CARDINAL, pxlValue: LONG CARDINAL] = TRUSTED { byte: [0..256) _ pxlValue; ColorDisplay.SetRed[ x, y, byte ]; }; GetPxl: PUBLIC PROC [x, y: CARDINAL] RETURNS [LONG CARDINAL] = TRUSTED { pixel: LONG CARDINAL; r, g, b: [0..256); [r, g, b] _ ColorDisplay.GetPixel[x, y]; pixel _ r; RETURN [ pixel ]; }; DrawLine: PUBLIC PROC [a, b: IntPair, pxlValue: LONG CARDINAL] = TRUSTED { -- fast line, constant color byteValue: [0..maxPxlValue] _ pxlValue; increment, bias, error, wordsPerLine, yBump: INTEGER; t: IntPair; pxlPtr: LONG POINTER TO PixelAddr; whichByte: INTEGER; IF pixelBuffer # NIL THEN { -- adjust for buffer limits a.x _ a.x - bufferLimits.xMin; a.y _ a.y - bufferLimits.yMin; b.x _ b.x - bufferLimits.xMin; b.y _ b.y - bufferLimits.yMin; }; IF a.x > b.x THEN { t _ a; a _ b; b _ t; }; -- make sure of positive-going x [wordsPerLine, pxlPtr] _ 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; whichByte _ a.x MOD pxpWd; --Get to proper pixel in the word FOR i: CARDINAL IN [0..ABS[b.x-a.x]] DO pxlPtr[whichByte] _ byteValue; IF (whichByte _ (whichByte + 1)) >= pxpWd THEN {pxlPtr _ pxlPtr + 1; whichByte _ 0}; 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; whichByte _ a.x MOD pxpWd; --Get to proper pixel in the word FOR i: CARDINAL IN [0..ABS[b.y-a.y]] DO pxlPtr[whichByte] _ byteValue; pxlPtr _ pxlPtr + yBump; IF error > 0 THEN { error _ error - bias; IF (whichByte _ (whichByte + 1)) >= pxpWd THEN {pxlPtr _ pxlPtr + 1; whichByte _ 0}; }; error _ error + increment; ENDLOOP; }; }; Tiler: PUBLIC PROC [VtxCount: CARDINAL, Vertices: VtxSequence] = { }; END. PImager4bitDisplayImpl.mesa This implements the low level routines for the color display at 4 bits per pixel. Last Edited by: GWilliams, July 29, 1983 5:18 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 Κ³˜headšœ™J™Q—™šœ™Jšœ ™ —unitšΟk ˜ Jšœœ˜Jšœ œ œ˜,Jšœ œ œ˜TJšœ œ˜/Jšœ œB˜PJšœ ˜ Jšœœ;˜NJšœ:˜:Jšœœb˜uJšœ$˜$Jšœœ=˜PJšœ<˜——Lš Ÿœ œœœœœ˜Našœœœ˜Nšœœ˜Nšœœœ˜Lšœ˜cšœ˜Ošœ!˜!Ošœ œ˜(Jšœ.˜.Jšœ˜Jšœœœ˜J˜—šœ˜šœœœ ˜3Jšœ˜Jšœ!˜%—Jšœ œœ'˜@Nšœ.˜.Jšœ˜Jšœœœ˜J˜—Jšœ˜ Jšœ˜—J˜šŸœœœœ˜Bšœ˜ Jšœœ ž˜Jšœœ ž˜Jšœœ ž˜Jšœœž˜Jšœœ ž˜Jšœœ ž˜—Jšœ˜J˜—J˜š Ÿœœœœœ œ˜[Jšž1™1J˜$J˜Jšœ3˜5šœœœ ˜.Jšœœ˜Jšœœœ ˜—šœœœ˜/Jšœœœ˜&—J˜š œœœœ ˜%Jšœ œ˜'Jšœ0œž;˜u—˜Jšœ)ž%˜NJšœ)˜)Jšœ)ž ˜4Jšœ)˜)Jšœ)˜)Jšœ+ž˜3Jšœ)˜)Jšœ*˜*Jšœ)ž ˜5Jšœ)˜)Jšœ+˜+Jšœ+˜+Jšœ+˜+Jšœ*˜*Jšœ,ž ˜5Jšœ+˜+J˜—šœ˜JšœL˜OJšœQœ˜[šœ.˜1Jšœ˜Jšœ*˜*Jšœ,˜,Jšœ&˜&Jšœ&˜&Jšœ"˜"Jšœ˜Jšœ ˜ Jšœ˜Jšœ%˜%Jšœ#˜#Jšœ&˜&Jšœ˜Jšœ˜Jšœ6˜6Jšœ ˜ Jšœ˜—Jšœ˜—J˜—šŸœ œœž-˜SJšœœ3œœ ˜PJšœ˜—š Ÿœœœ+œœœž'˜”Jšœ œ˜-Jšœ œ˜.Lš œœœœž%˜VJšœ œ˜šœ˜Jš œœœ œ œ˜FJšœœ˜,Jšœœ2˜AJšœ0˜0šœ˜Jšœ˜Jšœ˜Jšœ˜—šœ œ˜/Jšœ œž˜HJšœD˜DJšœ˜—Jšœ˜šœœ˜%Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœœ6˜?Jšœ˜—J˜—šœœœ'œ˜6Jšœœ ž*˜OJšœœ ˜+—Jšœœœ˜'šœœ˜%Jšœ˜Jšœ˜—Jšœž.˜JJšœ˜Jšœ˜—šŸœœœœ˜,Jšœœœœ˜!Jšœž˜2Jšœœ˜Jšœ˜—š Ÿ œ œœœœž˜dJšœF™FJšœ˜Jšœ œ˜Jšœœœ˜š œœœœ˜+Jšœ˜Jšœœœœ˜IJšœœ"˜7Jšœ˜—Jšœ ˜J˜—š Ÿ œ œ œœœœ˜RJšœ"ž&˜HJšœ œ ž!˜:Jšœœ˜%Lšœ.˜.Jšœ ˜ Jšœ ˜ Jšœ˜Jšœœœž+˜YJšœœœ˜-Jšœœœ˜)Jšœ ˜J˜—šŸ œ œž*˜\J˜—šŸœ œ0œž˜eJšœ˜Jšœ<˜Jšœ ˜—Jšœ˜š Ÿ œœœœ&œœ˜jJšœ˜Jšœ<˜