DIRECTORY Real USING [FixC, Float], Inline USING [BytePair, LongMult, HighHalf], BitBlt USING [AlignedBBTable, BBTableSpace, BITBLT, BitBltTable, BitBltTablePtr], Environment USING [wordsPerPage, bitsPerWord, LongNumber], Space USING [Handle, Create, virtualMemory, defaultBase, LongPointer, Delete, Map, nullHandle], Imager USING [ClassRep], ImagerBasic USING [Transformation, IntRectangle, IntPair, CIEColor, CIEColorRep], ImagerRegistration USING [RegisterDevice], ImagerDisplay USING [ByteSequence, ByteSequenceRep, RegisterDisplayDevice, Vertex, VtxSequence, Direction, ContextData, DisplayClassRep], ImagerMasks USING [Mask], ColorDisplay USING [GetMode, SetMode, TurnOn, GetColor, disconnected, width, height, baseA, wplA, SetColor], Imager8bitDisplay, ImagerDisplayImpl, ImagerDisplayTransformImpl, ImagerDisplayClipperImpl, ImagerDisplayColorImpl, ImagerDisplayMasksImpl, ImagerDisplayCharactersImpl, ImagerDisplayInteractiveImpl; Imager8bitDisplayImpl: CEDAR MONITOR IMPORTS Real, Inline, BitBlt, ColorDisplay, Space, ImagerRegistration, ImagerDisplay, ImagerDisplayImpl, ImagerDisplayTransformImpl, ImagerDisplayClipperImpl, ImagerDisplayColorImpl, ImagerDisplayMasksImpl, ImagerDisplayCharactersImpl, ImagerDisplayInteractiveImpl EXPORTS Imager8bitDisplay ~ BEGIN OPEN ImagerBasic, ImagerDisplay; NoColorDisplay: PUBLIC SIGNAL ~ CODE; IncompatibleDisplayMode: PUBLIC SIGNAL ~ CODE; NotImplementedYet: PUBLIC SIGNAL ~ CODE; IncompatiblePixelArray: PUBLIC SIGNAL ~ CODE; Mask: TYPE ~ ImagerMasks.Mask; bpPxl: CARDINAL ~ 8; maxPxlValue: CARDINAL ~ 255; bpWd: CARDINAL ~ Environment.bitsPerWord; pxpWd: CARDINAL ~ bpWd/bpPxl; maxDisplayWidth: CARDINAL ~ 8192; -- number in excess of maximum expected BITBLT width getPxlPtr, setPxlPtr: LONG POINTER TO Inline.BytePair; getPxlDir, setPxlDir: Direction; getLeftByte, setLeftByte: BOOLEAN; getWordsPerLine, setWordsPerLine: CARDINAL; swapUnitSize: CARDINAL _ 50; -- unbelieveable crap for getting large spaces 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]; }; SetUp: PUBLIC PROC [ displayContext: ContextData, pin: BOOLEAN _ TRUE, box: Mask] = { IF pin THEN TRUSTED { IF ColorDisplay.GetMode[] = ColorDisplay.disconnected THEN IF ColorDisplay.SetMode[ [FALSE, 8, 0] ] THEN ColorDisplay.TurnOn[] ELSE ERROR NoColorDisplay[] ELSE IF ColorDisplay.GetMode[] # [FALSE, 8, 0] THEN ERROR IncompatibleDisplayMode[]; FOR i: LONG CARDINAL IN [0..40) DO ColorDisplay.SetColor[ i + 216, 0, i*6, i*6, i*6] ENDLOOP; -- greyscale FOR i: LONG CARDINAL IN [0..216) DO -- 6 x 6 x 6 color cube ColorDisplay.SetColor[ i, 0, 36 * (i MOD 6 + 1), 36 * ((i/6) MOD 6 + 1), 36 * (i/36 + 1)]; ENDLOOP; displayContext.deviceClipper _ [1, 1, ColorDisplay.height - 1, ColorDisplay.width - 1, NIL]; displayContext.wordsPerLine _ ColorDisplay.wplA; displayContext.pxlBase _ ColorDisplay.baseA; displayContext.storage _ Space.nullHandle; } ELSE { wordsPerLine, pages: CARDINAL; storage: Space.Handle; IF box.sSize = 0 -- degenerate box implies full screen THEN box _ [1, 1, ColorDisplay.height - 1, ColorDisplay.width - 1, NIL]; wordsPerLine _ IF box.fSize MOD pxpWd = 0 THEN box.fSize/pxpWd ELSE box.fSize/pxpWd + 1; pages _ (Inline.LongMult[wordsPerLine, box.sSize + 1] / Environment.wordsPerPage) + 1; TRUSTED { 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]; }; displayContext.pxlBase _ Space.LongPointer[storage]; displayContext.wordsPerLine _ wordsPerLine; displayContext.deviceClipper _ box; displayContext.storage _ storage; }; displayContext.deviceTransform _ [1., 0., 0., 0.,-1., ColorDisplay.height, mirrorY]; }; ShutDown: PUBLIC PROC [displayContext: ContextData] = TRUSTED { IF displayContext.storage = Space.nullHandle THEN { IF NOT ColorDisplay.SetMode[ ColorDisplay.disconnected ] THEN ERROR NoColorDisplay[]; } ELSE Space.Delete[displayContext.storage]; }; 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.Y - color.Y]; IF i = 0 THEN { entry _ i; minSum _ sum; } ELSE 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 [context: ContextData, source: IntRectangle, destination: IntPair] = TRUSTED { bbspace: BitBlt.BBTableSpace; bb: BitBlt.BitBltTablePtr _ BitBlt.AlignedBBTable[@bbspace]; srcPxlPtr, dstPxlPtr: LONG POINTER; wordsPerLine: CARDINAL; wordsPerLine _ context.wordsPerLine; dstPxlPtr _ LOOPHOLE[ context.pxlBase + Inline.LongMult[wordsPerLine, destination.y] + (destination.x / pxpWd), LONG POINTER]; srcPxlPtr _ LOOPHOLE[ context.pxlBase + Inline.LongMult[wordsPerLine, source.y] + (source.x / pxpWd), LONG POINTER]; bb^ _ nullBitBltTable; bb.dst.word _ dstPxlPtr; bb.dst.bit _ (destination.x MOD pxpWd) * bpPxl; bb.dstBpl _ wordsPerLine * bpWd; bb.src.word _ srcPxlPtr; bb.src.bit _ (source.x MOD pxpWd) * bpPxl; bb.srcDesc.srcBpl _ bb.dstBpl; bb.width _ source.w * bpPxl; bb.height _ source.h; BitBlt.BITBLT[bb]; }; TransferPxls: PUBLIC PROC [source, destination: ContextData] = TRUSTED { bbspace: BitBlt.BBTableSpace; bb: BitBlt.BitBltTablePtr _ BitBlt.AlignedBBTable[@bbspace]; destMaskX, destMaskY: INTEGER; bb^ _ nullBitBltTable; { OPEN destination; destMaskX _ clipper.fMin - viewerClipper.fMin; -- get mask defined by client clipper destMaskY _ clipper.sMin - viewerClipper.sMin; bb.dst.word _ LOOPHOLE[ pxlBase + Inline.LongMult[wordsPerLine, clipper.sMin] + (clipper.fMin / pxpWd), LONG POINTER]; IF clipper.fMin MOD pxpWd # 0 THEN bb.dst.bit _ bpPxl; bb.dstBpl _ wordsPerLine * bpWd; }; { OPEN source; bb.src.word _ LOOPHOLE[ pxlBase + Inline.LongMult[wordsPerLine, viewerClipper.sMin + destMaskY] + ((viewerClipper.fMin + destMaskX) / pxpWd), LONG POINTER]; IF (viewerClipper.fMin + destMaskX) MOD pxpWd # 0 THEN bb.src.bit _ bpPxl; bb.srcDesc.srcBpl _ wordsPerLine * bpWd; }; bb.width _ MIN[source.viewerClipper.fSize - destMaskX, destination.clipper.fSize] * bpPxl; bb.height _ MIN[source.viewerClipper.sSize - destMaskY, destination.clipper.sSize]; BitBlt.BITBLT[bb]; }; StoreScanSeg: PUBLIC PROC [source: ContextData, x, y, length: CARDINAL] RETURNS [ByteSequence] = TRUSTED { segment: ByteSequence _ NEW [ ByteSequenceRep[length/pxpWd] ]; bbspace: BitBlt.BBTableSpace; bb: BitBlt.BitBltTablePtr _ BitBlt.AlignedBBTable[@bbspace]; bb^ _ nullBitBltTable; bb.dst.word _ LOOPHOLE[segment, LONG POINTER]; bb.src.word _ LOOPHOLE[ source.pxlBase + Inline.LongMult[source.wordsPerLine, y] + (x / pxpWd), LONG POINTER]; bb.src.bit _ (x MOD pxpWd) * bpPxl; bb.width _ length * bpPxl; BitBlt.BITBLT[bb]; RETURN [segment]; }; LoadScanSeg: PUBLIC PROC [destination: ContextData, x, y, length: CARDINAL, segment: ByteSequence] = TRUSTED { bbspace: BitBlt.BBTableSpace; bb: BitBlt.BitBltTablePtr _ BitBlt.AlignedBBTable[@bbspace]; bb^ _ nullBitBltTable; bb.dst.word _ LOOPHOLE[ destination.pxlBase + Inline.LongMult[destination.wordsPerLine, y] + (x / pxpWd), LONG POINTER]; bb.dst.bit _ (x MOD pxpWd) * bpPxl; bb.src.word _ LOOPHOLE[segment, LONG POINTER]; bb.width _ length * bpPxl; BitBlt.BITBLT[bb]; }; LoadTrapezoid: PUBLIC PROC [destination: ContextData, top, bottom, leftTop, leftBot, rightTop, rightBot: CARDINAL, pxlValue: LONG CARDINAL] = TRUSTED { IF leftTop = leftBot AND rightTop = rightBot THEN LoadRectangle[destination, [leftBot, bottom, rightBot - leftBot, top - bottom], pxlValue] ELSE { -- not rectangle EdgeBlock: TYPE = RECORD [xPos: LONG CARDINAL, xIncr: LONG INTEGER]; MakeEdge: UNSAFE PROC[xTop, xBot, height: NAT] RETURNS [edge: EdgeBlock] = INLINE { LOOPHOLE[edge.xPos, Environment.LongNumber].high _ LOOPHOLE[xBot, UNSPECIFIED]; LOOPHOLE[edge.xPos, Environment.LongNumber].low _ LOOPHOLE[0, UNSPECIFIED]; LOOPHOLE[edge.xIncr, Environment.LongNumber].high _ LOOPHOLE[xTop - xBot, UNSPECIFIED]; LOOPHOLE[edge.xIncr, Environment.LongNumber].low _ LOOPHOLE[0, UNSPECIFIED]; IF height > 1 THEN edge.xIncr _ edge.xIncr / height; }; bbspace: BitBlt.BBTableSpace; bb: BitBlt.BitBltTablePtr _ BitBlt.AlignedBBTable[@bbspace]; value: CARDINAL _ pxlValue * 256 + pxlValue; -- make pxlValue brick for BitBlt scanPtr, pxlPtr: LONG POINTER; lEdge: EdgeBlock _ MakeEdge[leftTop, leftBot, top - bottom]; rEdge: EdgeBlock _ MakeEdge[rightTop, rightBot, top - bottom]; bb^ _ nullBitBltTable; bb.flags.gray _ TRUE; bb.src.word _ @value; bb.srcDesc.gray _ [yOffset: 0, widthMinusOne: 15, heightMinusOne: 0]; TRUSTED { scanPtr _ LOOPHOLE[ destination.pxlBase + Inline.LongMult[destination.wordsPerLine, bottom], LONG POINTER TO Inline.BytePair]; }; FOR height: NAT IN [bottom..top] DO TRUSTED { -- Get pixel pointer and Step scan pointer pxlPtr _ scanPtr + LOOPHOLE[Inline.HighHalf[lEdge.xPos] / pxpWd, CARDINAL]; scanPtr _ scanPtr + destination.wordsPerLine; }; bb.dst.word _ pxlPtr; bb.dst.bit _ (Inline.HighHalf[lEdge.xPos] MOD pxpWd) * bpPxl; bb.width _ (Inline.HighHalf[rEdge.xPos] - Inline.HighHalf[lEdge.xPos]) * bpPxl; BitBlt.BITBLT[bb]; lEdge.xPos _ lEdge.xPos + lEdge.xIncr; rEdge.xPos _ rEdge.xPos + rEdge.xIncr; ENDLOOP; }; }; LoadRectangle: PUBLIC PROC [destination: ContextData, area: ImagerBasic.IntRectangle, pxlValue: LONG CARDINAL] = TRUSTED { bbspace: BitBlt.BBTableSpace; bb: BitBlt.BitBltTablePtr _ BitBlt.AlignedBBTable[@bbspace]; color: CARDINAL; pxlValue _ MIN[pxlValue, maxPxlValue]; color _ pxlValue * 256 + pxlValue; -- make pxlValue brick for BitBlt bb^ _ nullBitBltTable; bb.flags.gray _ TRUE; bb.dst.word _ LOOPHOLE[ destination.pxlBase + Inline.LongMult[destination.wordsPerLine, area.y] + (area.x / pxpWd), LONG POINTER]; bb.dst.bit _ (area.x MOD pxpWd) * bpPxl; bb.dstBpl _ destination.wordsPerLine * bpWd; bb.src.word _ @color; bb.srcDesc.gray _ [yOffset: 0, widthMinusOne: 15, heightMinusOne: 0]; bb.width _ area.w * bpPxl; bb.height _ area.h; BitBlt.BITBLT[bb]; }; SetAnyPixel: PUBLIC PROC [destination: ContextData, x, y: CARDINAL, pxlValue: LONG CARDINAL, newDirection: Direction _ none] = TRUSTED { byteValue: [0..256) _ MIN[pxlValue, maxPxlValue]; setPxlPtr _ LOOPHOLE[ destination.pxlBase + Inline.LongMult[destination.wordsPerLine, y] + (x / pxpWd), LONG POINTER TO Inline.BytePair]; IF x MOD pxpWd = 0 THEN { setPxlPtr^.high _ byteValue; setLeftByte _ TRUE; } ELSE { setPxlPtr^.low _ byteValue; setLeftByte _ FALSE; }; setPxlDir _ newDirection; setWordsPerLine _ destination.wordsPerLine; }; GetAnyPixel: PUBLIC PROC [source: ContextData, x, y: CARDINAL, newDirection: Direction _ none] RETURNS [LONG CARDINAL] = TRUSTED { pixel: LONG CARDINAL; getPxlPtr _ LOOPHOLE[ source.pxlBase + Inline.LongMult[source.wordsPerLine, y] + (x / pxpWd), LONG POINTER TO Inline.BytePair]; IF x MOD pxpWd = 0 THEN { pixel _ getPxlPtr^.high; getLeftByte _ TRUE; } ELSE { pixel _ getPxlPtr^.low; getLeftByte _ FALSE; }; getPxlDir _ newDirection; getWordsPerLine _ source.wordsPerLine; RETURN [ pixel ]; }; SetNextPixel: PUBLIC PROC [pxlValue: LONG CARDINAL] = TRUSTED { byteValue: [0..256) _ MIN[pxlValue, maxPxlValue]; SELECT setPxlDir FROM left => { IF NOT setLeftByte THEN setPxlPtr _ setPxlPtr + 1; setLeftByte _ NOT setLeftByte; }; right => { IF setLeftByte THEN setPxlPtr _ setPxlPtr - 1; setLeftByte _ NOT setLeftByte; }; up => setPxlPtr _ setPxlPtr - setWordsPerLine; down => setPxlPtr _ setPxlPtr + setWordsPerLine; upLeft => { IF NOT setLeftByte THEN setPxlPtr _ setPxlPtr + 1; setLeftByte _ NOT setLeftByte; setPxlPtr _ setPxlPtr - setWordsPerLine; }; downLeft => { IF NOT setLeftByte THEN setPxlPtr _ setPxlPtr + 1; setLeftByte _ NOT setLeftByte; setPxlPtr _ setPxlPtr + setWordsPerLine; }; upRight => { IF setLeftByte THEN setPxlPtr _ setPxlPtr - 1; setLeftByte _ NOT setLeftByte; setPxlPtr _ setPxlPtr - setWordsPerLine; }; downRight => { IF setLeftByte THEN setPxlPtr _ setPxlPtr - 1; setLeftByte _ NOT setLeftByte; setPxlPtr _ setPxlPtr + setWordsPerLine; }; ENDCASE; IF setLeftByte THEN setPxlPtr^.high _ byteValue ELSE setPxlPtr^.low _ byteValue; }; GetNextPixel: PUBLIC PROC [] RETURNS [LONG CARDINAL]= TRUSTED { SELECT getPxlDir FROM left => { IF NOT getLeftByte THEN getPxlPtr _ getPxlPtr + 1; getLeftByte _ NOT getLeftByte; }; right => { IF getLeftByte THEN getPxlPtr _ getPxlPtr - 1; getLeftByte _ NOT getLeftByte; }; up => getPxlPtr _ getPxlPtr - getWordsPerLine; down => getPxlPtr _ getPxlPtr + getWordsPerLine; upLeft => { IF NOT getLeftByte THEN getPxlPtr _ getPxlPtr + 1; getLeftByte _ NOT getLeftByte; getPxlPtr _ getPxlPtr - getWordsPerLine; }; downLeft => { IF NOT getLeftByte THEN getPxlPtr _ getPxlPtr + 1; getLeftByte _ NOT getLeftByte; getPxlPtr _ getPxlPtr + getWordsPerLine; }; upRight => { IF getLeftByte THEN getPxlPtr _ getPxlPtr - 1; getLeftByte _ NOT getLeftByte; getPxlPtr _ getPxlPtr - getWordsPerLine; }; downRight => { IF getLeftByte THEN getPxlPtr _ getPxlPtr - 1; getLeftByte _ NOT getLeftByte; getPxlPtr _ getPxlPtr + getWordsPerLine; }; ENDCASE; IF getLeftByte THEN RETURN[getPxlPtr^.high] ELSE RETURN[getPxlPtr^.low]; }; DrawLine: PUBLIC PROC [destination: ContextData, a, b: IntPair, pxlValue: LONG CARDINAL] = { byteValue: [0..maxPxlValue]; increment, bias, error, yBump: INTEGER; leftByte: BOOLEAN; t: IntPair; wordsPerLine: CARDINAL; 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 _ MIN[pxlValue, maxPxlValue]; wordsPerLine _ destination.wordsPerLine; TRUSTED { pxlPtr _ LOOPHOLE[ destination.pxlBase + Inline.LongMult[destination.wordsPerLine, a.y] + (a.x / pxpWd), 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] * wordsPerLine; increment _ ABS[increment]; bias _ ABS[bias]; error _ increment - bias/2; leftByte _ a.x MOD pxpWd = 0; -- left byte is high byte FOR i: CARDINAL IN [0..ABS[b.x-a.x]] DO TRUSTED { 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] * wordsPerLine; increment _ ABS[increment]; bias _ ABS[bias]; error _ increment - bias/2; leftByte _ a.x MOD pxpWd = 0; FOR i: CARDINAL IN [0..ABS[b.y-a.y]] DO TRUSTED { 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; }; }; Tiler: PUBLIC PROC [destination: ContextData, vtxCount: NAT, vertices: VtxSequence] = { EdgeBlock: TYPE = RECORD [length: CARDINAL, xPos, value: LONG CARDINAL, xIncr, valIncr: LONG INTEGER]; MakeEdge: PROC[vtx1, vtx2: Vertex] RETURNS [edge: EdgeBlock] = -- INLINE -- { edge.length _ IF vtx2.y > vtx1.y THEN vtx2.y - vtx1.y ELSE 0; LOOPHOLE[edge.xPos, Environment.LongNumber].high _ LOOPHOLE[vtx1.x, UNSPECIFIED]; LOOPHOLE[edge.xPos, Environment.LongNumber].low _ LOOPHOLE[0, UNSPECIFIED]; edge.xIncr _ MakeIncr[vtx1.x, vtx2.x, edge.length]; LOOPHOLE[edge.value, Environment.LongNumber].high _ LOOPHOLE[vtx1.pxlValue, Environment.LongNumber].low; LOOPHOLE[edge.value, Environment.LongNumber].low _ LOOPHOLE[0, UNSPECIFIED]; edge.valIncr _ MakeIncr[vtx1.pxlValue, vtx2.pxlValue, edge.length]; }; MakeScanSeg: PROC[lx, lv, rx, rv: CARDINAL, pxlPtr: LONG POINTER TO Inline.BytePair] = TRUSTED -- INLINE -- { incr: LONG INTEGER; value: LONG CARDINAL; leftByte: BOOLEAN _ (lx MOD pxpWd) = 0; incr _ MakeIncr[lv, rv, rx - lx]; LOOPHOLE[value, Environment.LongNumber].high _ LOOPHOLE[lv, UNSPECIFIED]; LOOPHOLE[value, Environment.LongNumber].low _ LOOPHOLE[0, UNSPECIFIED]; FOR i: CARDINAL IN [lx..rx] DO IF leftByte THEN pxlPtr^.high _ Inline.HighHalf[value] ELSE { pxlPtr^.low _ Inline.HighHalf[value]; pxlPtr _ pxlPtr + 1; }; leftByte _ NOT leftByte; value _ value + incr; ENDLOOP; }; MakeIncr: PROC[v1, v2, length: CARDINAL] RETURNS[ incr: LONG INTEGER ] = -- INLINE -- { LOOPHOLE[incr, Environment.LongNumber].high _ LOOPHOLE[v2 - v1, UNSPECIFIED]; LOOPHOLE[incr, Environment.LongNumber].low _ LOOPHOLE[0, UNSPECIFIED]; IF length > 1 THEN incr _ incr / length; }; lVtx, rVtx, least, most, height, vtxCountMinusOne, lastX, wordsPerLine: CARDINAL; scanPtr, pxlPtr: LONG POINTER TO Inline.BytePair; lEdge: EdgeBlock _ [0, 0, 0, 0, 0]; rEdge: EdgeBlock _ [0, 0, 0, 0, 0]; vtxCountMinusOne _ vtxCount - 1; FOR i: CARDINAL IN [0..vtxCount) DO IF i = 0 THEN { most _ least _ vertices[i].y; lVtx _ i; } ELSE IF vertices[i].y < least THEN { least _ vertices[i].y; lVtx _ i; } ELSE IF vertices[i].y > most THEN most _ vertices[i].y; ENDLOOP; rVtx _ lVtx; -- set pointers to bottom vertex height _ vertices[lVtx].y; lastX _ vertices[lVtx].x; wordsPerLine _ destination.wordsPerLine; TRUSTED { scanPtr _ LOOPHOLE[ destination.pxlBase + Inline.LongMult[destination.wordsPerLine, vertices[lVtx].y], LONG POINTER TO Inline.BytePair]; }; WHILE height < most DO -- Do until top scan line (rejects zero-height polys) WHILE lEdge.length = 0 DO -- work left edge counterclockwise nxtVtx: CARDINAL _ (lVtx + vtxCountMinusOne) MOD vtxCount; lEdge _ MakeEdge[vertices[lVtx], vertices[nxtVtx]]; lVtx _ nxtVtx; ENDLOOP; WHILE rEdge.length = 0 DO -- work right edge clockwise nxtVtx: CARDINAL _ (rVtx + 1) MOD vtxCount; rEdge _ MakeEdge[vertices[rVtx], vertices[nxtVtx]]; rVtx _ nxtVtx; ENDLOOP; TRUSTED { -- Get pixel pointer and Step scan pointer pxlPtr _ scanPtr + LOOPHOLE[Inline.HighHalf[lEdge.xPos] / pxpWd, CARDINAL]; scanPtr _ scanPtr + wordsPerLine; }; MakeScanSeg[Inline.HighHalf[lEdge.xPos], Inline.HighHalf[lEdge.value], Inline.HighHalf[rEdge.xPos], Inline.HighHalf[rEdge.value], pxlPtr]; lEdge.xPos _ lEdge.xPos + lEdge.xIncr; lEdge.value _ lEdge.value + lEdge.valIncr; lEdge.length _ lEdge.length - 1; rEdge.xPos _ rEdge.xPos + rEdge.xIncr; rEdge.value _ rEdge.value + rEdge.valIncr; rEdge.length _ rEdge.length - 1; height _ height + 1; ENDLOOP; TRUSTED { pxlPtr _ scanPtr + LOOPHOLE[Inline.HighHalf[lEdge.xPos] / pxpWd, CARDINAL]; }; MakeScanSeg[Inline.HighHalf[lEdge.xPos], Inline.HighHalf[lEdge.value], Inline.HighHalf[rEdge.xPos], Inline.HighHalf[rEdge.value], pxlPtr]; }; ConstantTiler: PUBLIC PROC [destination: ContextData, vtxCount: NAT, vertices: VtxSequence, pxlValue: LONG CARDINAL] = { EdgeBlock: TYPE = RECORD [length: CARDINAL, xPos: LONG CARDINAL, xIncr: LONG INTEGER]; MakeEdge: PROC[vtx1, vtx2: Vertex] RETURNS [edge: EdgeBlock] = -- INLINE -- { edge.length _ IF vtx2.y > vtx1.y THEN vtx2.y - vtx1.y ELSE 0; LOOPHOLE[edge.xPos, Environment.LongNumber].high _ LOOPHOLE[vtx1.x, UNSPECIFIED]; LOOPHOLE[edge.xPos, Environment.LongNumber].low _ LOOPHOLE[0, UNSPECIFIED]; LOOPHOLE[edge.xIncr, Environment.LongNumber].high _ LOOPHOLE[vtx2.x - vtx1.x, UNSPECIFIED]; LOOPHOLE[edge.xIncr, Environment.LongNumber].low _ LOOPHOLE[0, UNSPECIFIED]; IF edge.length > 1 THEN edge.xIncr _ edge.xIncr / edge.length; }; value: CARDINAL _ pxlValue * 256 + pxlValue; -- make pxlValue brick for BitBlt lVtx, rVtx, least, most, height, vtxCountMinusOne, lastX, wordsPerLine: CARDINAL; scanPtr, pxlPtr: LONG POINTER; lEdge: EdgeBlock _ [0, 0, 0]; rEdge: EdgeBlock _ [0, 0, 0]; bbspace: BitBlt.BBTableSpace; bb: BitBlt.BitBltTablePtr; TRUSTED { bb _ BitBlt.AlignedBBTable[@bbspace]; bb^ _ nullBitBltTable; bb.flags.gray _ TRUE; bb.src.word _ @value; bb.srcDesc.gray _ [yOffset: 0, widthMinusOne: 15, heightMinusOne: 0]; }; vtxCountMinusOne _ vtxCount - 1; FOR i: CARDINAL IN [0..vtxCount) DO IF i = 0 THEN { most _ least _ vertices[i].y; lVtx _ i; } ELSE IF vertices[i].y < least THEN { least _ vertices[i].y; lVtx _ i; } ELSE IF vertices[i].y > most THEN most _ vertices[i].y; ENDLOOP; rVtx _ lVtx; -- set pointers to bottom vertex height _ vertices[lVtx].y; lastX _ vertices[lVtx].x; wordsPerLine _ destination.wordsPerLine; TRUSTED { scanPtr _ LOOPHOLE[ destination.pxlBase + Inline.LongMult[destination.wordsPerLine, vertices[lVtx].y], LONG POINTER]; }; WHILE height < most DO -- Do until top scan line (rejects zero-height polys) WHILE lEdge.length = 0 DO -- work left edge counterclockwise nxtVtx: CARDINAL _ (lVtx + vtxCountMinusOne) MOD vtxCount; lEdge _ MakeEdge[vertices[lVtx], vertices[nxtVtx]]; lVtx _ nxtVtx; ENDLOOP; WHILE rEdge.length = 0 DO -- work right edge clockwise nxtVtx: CARDINAL _ (rVtx + 1) MOD vtxCount; rEdge _ MakeEdge[vertices[rVtx], vertices[nxtVtx]]; rVtx _ nxtVtx; ENDLOOP; TRUSTED { -- Get pixel pointer and Step scan pointer pxlPtr _ scanPtr + LOOPHOLE[Inline.HighHalf[lEdge.xPos] / pxpWd, CARDINAL]; scanPtr _ scanPtr + wordsPerLine; bb.dst.word _ pxlPtr; bb.dst.bit _ (Inline.HighHalf[lEdge.xPos] MOD pxpWd) * bpPxl; bb.width _ (Inline.HighHalf[rEdge.xPos] - Inline.HighHalf[lEdge.xPos]) * bpPxl; BitBlt.BITBLT[bb]; }; lEdge.xPos _ lEdge.xPos + lEdge.xIncr; lEdge.length _ lEdge.length - 1; rEdge.xPos _ rEdge.xPos + rEdge.xIncr; rEdge.length _ rEdge.length - 1; height _ height + 1; ENDLOOP; TRUSTED { pxlPtr _ scanPtr + LOOPHOLE[Inline.HighHalf[lEdge.xPos] / pxpWd, CARDINAL]; bb.dst.word _ pxlPtr; bb.dst.bit _ (Inline.HighHalf[lEdge.xPos] MOD pxpWd) * bpPxl; bb.width _ (Inline.HighHalf[rEdge.xPos] - Inline.HighHalf[lEdge.xPos]) * bpPxl; BitBlt.BITBLT[bb]; }; }; TRUSTED { color8BitClass: REF Imager.ClassRep _ NEW [Imager.ClassRep _ [ deviceType: $Color8BitDisplay, Init: ImagerDisplayImpl.Init, DoSaveAll: ImagerDisplayImpl.DoSaveAll, DoSave: ImagerDisplayImpl.DoSave, Flush: ImagerDisplayImpl.Flush, Close: ImagerDisplayImpl.Close, TransferBuffer: ImagerDisplayImpl.TransferBuffer, Reset: ImagerDisplayImpl.Reset, TranslateT: ImagerDisplayTransformImpl.TranslateT, RotateT: ImagerDisplayTransformImpl.RotateT, ScaleT: ImagerDisplayTransformImpl.ScaleT, ConcatT: ImagerDisplayTransformImpl.ConcatT, GetT: ImagerDisplayTransformImpl.GetT, SetT: ImagerDisplayTransformImpl.SetT, IntTranslateT: ImagerDisplayTransformImpl.IntTranslateT, IntScaleT: ImagerDisplayTransformImpl.IntScaleT, GetClipper: ImagerDisplayClipperImpl.GetClipper, SetClipper: ImagerDisplayClipperImpl.SetClipper, ClipPath: ImagerDisplayClipperImpl.ClipPath, ClipRectangle: ImagerDisplayClipperImpl.ClipRectangle, TestRectangle: ImagerDisplayClipperImpl.TestRectangle, ClipIntRectangle: ImagerDisplayClipperImpl.ClipIntRectangle, TestIntRectangle: ImagerDisplayClipperImpl.TestIntRectangle, DoWithoutClipping: ImagerDisplayClipperImpl.DoWithoutClipping, SetView: ImagerDisplayClipperImpl.SetView, ClipView: ImagerDisplayClipperImpl.ClipView, GetSurfaceBounds: ImagerDisplayClipperImpl.GetSurfaceBounds, SetColor: ImagerDisplayColorImpl.SetColor, GetColor: ImagerDisplayColorImpl.GetColor, MaskStroke: ImagerDisplayMasksImpl.MaskStroke, MaskFill: ImagerDisplayMasksImpl.MaskFill, MaskPixel: ImagerDisplayMasksImpl.MaskPixel, MaskBits: ImagerDisplayMasksImpl.MaskBits, MaskSegment: ImagerDisplayMasksImpl.MaskSegment, MaskIntSegment: ImagerDisplayMasksImpl.MaskIntSegment, MaskThinStroke: ImagerDisplayMasksImpl.MaskThinStroke, MaskRectangle: ImagerDisplayMasksImpl.MaskRectangle, MaskIntRectangle: ImagerDisplayMasksImpl.MaskIntRectangle, SetCP: ImagerDisplayCharactersImpl.SetCP, GetCP: ImagerDisplayCharactersImpl.GetCP, SetIntCP: ImagerDisplayCharactersImpl.SetIntCP, GetIntCP: ImagerDisplayCharactersImpl.GetIntCP, MaskChar: ImagerDisplayCharactersImpl.MaskChar, MaskCharacters: ImagerDisplayCharactersImpl.MaskCharacters, MoveSurfaceRectangle: ImagerDisplayInteractiveImpl.MoveSurfaceRectangle, SetColorInvert: ImagerDisplayInteractiveImpl.SetColorInvert, DrawBitmap: ImagerDisplayInteractiveImpl.DrawBitmap, SpecialOp: ImagerDisplayInteractiveImpl.SpecialOp ]]; color8BitDisplayClass: REF ImagerDisplay.DisplayClassRep _ NEW [ ImagerDisplay.DisplayClassRep _ [ deviceType: $Color8BitDisplay, SetUp: SetUp, ShutDown: ShutDown, ColortoPixel: ColortoPixel, PixeltoColor: PixeltoColor, HilitePxls: HilitePxls, MovePxls: MovePxls, TransferPxls: TransferPxls, StoreScanSeg: StoreScanSeg, LoadScanSeg: LoadScanSeg, LoadTrapezoid: LoadTrapezoid, LoadRectangle: LoadRectangle, SetAnyPixel: SetAnyPixel, GetAnyPixel: GetAnyPixel, SetNextPixel: SetNextPixel, GetNextPixel: GetNextPixel, DrawLine: DrawLine, Tiler: Tiler ] ]; ImagerRegistration.RegisterDevice[color8BitClass]; ImagerDisplay.RegisterDisplayDevice[ color8BitDisplayClass ]; }; END. JImager8bitDisplayImpl.mesa This implements the low level routines for the color display at 8 bits per pixel. Last Edited by: Crow, September 1, 1983 4:18 pm get memory, pin it if requested, set the transform and clipper Open color display, set to 8-bit mode and find bitmap Get contiguous block of memory to act as nondisplayed frame buffer Free memory (how can you be sure somebody else isn't using it?) Finds color table entry with least sum-of-square difference from color Move a rectangle within a context Scan convert trapezoid, constant color Scan convert rectangle, constant color Fast line, constant color, using a slightly modified Bresenham's algorithm find least and most y-values Include bottom line of polygon find least and most y-values Include bottom line of polygon Initialization: Register DeviceType with Imager Κα˜headšœ™J™Q—™šœ™Jšœ™—unitšΟk ˜ Jšœœ˜Jšœ œ ˜/Jšœ œ œ˜TJšœ œ)˜;Jšœ œB˜PJšœ˜Jšœ œ ˜Jšœ œ(˜:Jšœ˜Jšœœ˜*Jšœœ?˜RJšœ?˜?Jšœ œ˜Jšœ œB˜UJšœ˜Jšœ˜Jšœ³˜³——head2šœ$˜$Jšœ˜ˆJšœ˜Lšœ˜Lšœ˜ Lšœœœœ˜%Jšœœœœ˜.Jšœœœœ˜(Icšœœœœ˜-Lšœœ˜Lšœœ˜Jšœ œ˜Jšœœ˜)Jšœœ˜Jšœœ Οc4˜WLšœœœœ˜6Iašœ ˜ Ošœœ˜"Ošœ"œ˜+Lšœœž.˜ULšœ3œ$˜ZJšœœ ˜'Jšœ0˜0Jšœ4œ˜™>šœ˜J™5—šœœ ˜Jšœ3˜5šœœœ ˜.Jšœœ˜Jšœœœ˜—šœœœ˜/Jšœœœ˜&—Jš œœœœ œ5œž ˜mš œœœœ œ ž˜EJšœ%œœ˜ZJšœ˜—JšœWœ˜\Jšœ0˜0Jšœ,˜,Jšœ*˜*J˜J™B—šœ˜Jšœœ˜8Jšœž%˜@Jšœ?œ˜HJšœœ œ œ˜>Jšœ˜+JšœV˜Všœ˜ JšœG˜Gšœ œ˜/Jšœ œž˜HJšœD˜DJšœ˜—Jšœ˜J˜—Lšœ4˜4Ošœ+˜+Ošœ#˜#Ošœ!˜!J˜—JšœU˜UJšœ˜—šŸœ œ!œ˜?Ošœ?™?Jšœ*˜,Jšœœœ3˜AJšœœœ˜$Jšœ&˜*Jšœ˜—š Ÿ œ œœœœž˜dJšœF™FJšœ˜Jšœ œ˜Jšœœœ˜š œœœœ˜+Jšœ˜Jšœœ˜Jšœ˜ Jšœ"˜&Jšœœœ"˜>Jšœ˜—Jšœ ˜J˜—š Ÿ œ œ œœœœ˜RJšœ"ž&˜HJšœ œ ž!˜:Jšœœ˜%Lšœ.˜.Jšœ ˜ Jšœ ˜ Jšœ˜Jšœœœž+˜YJšœœœ˜-Jšœœœ˜)Jšœ ˜J˜—šŸ œ œž*˜\J˜—LšŸœ œ˜-šœ7œ˜AOšœ!™!Jšœ˜Jšœ<˜Jšœ˜Jšœ<˜˜>Jšœœ˜—Jšœœ˜#Jšœœ œœ˜.Jšœ˜J˜Jšœ˜—LšŸ œœœ˜6Ošœ>œ˜Gšœœœœ˜2Ošž&™&Lšœœ˜-OšœZ˜^šœž˜Oš œ œœœœ œœ˜Dš Ÿœœœœœœ˜SJšœ+œ œ˜OJšœ*œ œ˜KJšœ,˜4Jšœœ œ˜2Jšœ,œ œ˜MJšœ œ#˜5Jšœ˜—Ošœ˜Jšœ<˜˜>Jšœ˜Jšœœ˜Jšœ˜JšœE˜EJ˜šœœ˜3Jšœ<˜˜>Jšœœœ˜!—Jšœœ ˜Jšœ2œ˜@Jšœ3œ˜AJšœ˜Jšœ+˜+Jšœ˜—šŸ œ œ œ œœœœ˜‚Jšœœœ˜šœ œ˜%Jšœ9˜9Jšœœœ˜!—Jšœœ ˜Jšœ.œ˜;Jšœ/œ˜=Jšœ˜Jšœ&˜&Jšœ ˜Jšœ˜—š Ÿ œœœ œœœ˜?Ošœœ˜1šœ ˜Ošœœœ œ˜COšœ(˜(Ošœœ œ˜@Ošœ(˜(Ošœ2˜2Ošœ3˜3Ošœœœ œ˜COšœ$˜$Ošœ2˜2Ošœœœ œ˜EOšœ%˜%Ošœ2˜2Ošœœ œ˜@Ošœœ ˜$Ošœ2˜2Ošœœ œ˜AOšœ$˜$Ošœ2˜2Oš˜—Ošœ œœ˜ROšœ˜—šŸ œœœœœœœ˜?šœ ˜Ošœœœ œ˜COšœ(˜(Ošœœ œ˜@Ošœ(˜(Ošœ2˜2Ošœ3˜3Ošœœœ œ˜COšœ$˜$Ošœ2˜2Ošœœœ œ˜EOšœ%˜%Ošœ2˜2Ošœœ œ˜@Ošœ$˜$Ošœ2˜2Ošœœ œ˜AOšœ$˜$Ošœ2˜2Oš˜—Oš œ œœœœ˜JOšœ˜—LšŸœ œ+˜@šœœœ˜'Jšžœ1™JJšœ˜Jšœœœ˜LJšœœ˜Jšœœœœ˜(Lšœ œ+ž ˜\Jšœ œ˜'Jšœ(˜(šœ œ˜2JšœI˜IJšœœœœ˜,—Lšœœ ˜šœž˜.J˜ Jšœ˜Jšœœ˜&Jšœ œœ˜0J˜J˜Jšœœž˜9š œœœœ œ ˜1Jšœ ˜ Jšœ!˜%Jšœ8˜Jšœ+œ œ˜LJ˜DJ˜—šŸ œœœ œœœœ˜mJšœœœ˜Jšœœœ˜Jšœ œœ ˜'J˜J˜"Jšœ'œ œ˜IJšœ&œ œ˜Gšœœœ ˜Jšœ ˜ Jšœ&˜*JšœE˜IJšœ œ ˜J˜Jšœ˜—J˜—šŸœœœœœœ œ˜WJšœ&œ  œ˜MJšœ&œ œ˜GJšœ œ˜(J˜—LšœH ˜QJšœœœœ˜2J˜#J˜#˜ LšΟi™—šœœœ˜#Jšœ˜Jšœ2˜6šœœ˜Jšœ)˜-Jšœœœ˜8—Jšœ˜ —Jšœž ˜J˜ —J˜'J˜*J˜ J˜&J˜*J˜ J˜—šœ˜Jšœ™—Jšœœ&œ˜X˜FJ˜>J˜ —J˜—LšŸ œœœ&œ˜Ešœ*œœ˜=Jšœ œœ œœœ œœ˜VšŸœœœ œ˜MJšœœœœ˜=Jšœ+œ  œ˜QJšœ*œ œ˜KJšœ,˜4Jšœœ œ˜6Jšœ,œ œ˜MJšœœ(˜?Jšœ˜—Lšœœž!˜NOšœH ˜QJšœœœ˜Jšœ˜J˜Lšœ˜Jšœ˜šœ˜ Jšœ%˜%Jšœ˜Jšœœ˜Jšœ˜JšœE˜EJ˜—˜ Lš ™—šœœœ˜#Jšœ˜Jšœ2˜6šœœ˜Jšœ)˜-Jšœœœ˜8—Jšœ˜ —Jšœž ˜Jšœ ˜ Jšœ!˜!Jšœ)˜)Jšœ$˜$Jšœ"˜"Jšœ"˜"Jšœ2˜2Jšœ"˜"Jšœ3˜3Jšœ.˜.Jšœ,˜,Jšœ.˜.Jšœ)˜)Jšœ)˜)Jšœ8˜8Jšœ1˜1Jšœ2˜2Jšœ2˜2Jšœ.˜.Jšœ7˜7Jšœ7˜7Jšœ<˜˜>Jšœ-˜-Jšœ.˜.Jšœ<˜˜>Jšœ6˜6Jšœ4˜4Jšœ˜——J˜šœœ!œ˜@šœ!˜!Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜J˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜J˜—Jšœ˜—Lšœ2˜2Lšœ=˜=J˜J˜—Jšœ˜J˜—…—h’…Ν