<> <> <<>> <> <> 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 { << Scan convert rectangle, constant color>> 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.