<> <> <> <> <> <<>> DIRECTORY Basics USING [LongMult, BITSHIFT, BITAND, logBitsPerWord, bitsPerWord, HighHalf, LongNumber, BITOR, BITNOT, BytePair], ImagerBasic USING [IntPair], PrincOps USING [DstFunc, SrcFunc, BitAddress, BBTableSpace, BBptr], PrincOpsUtils USING [AlignedBBTable, BITBLT], ImagerPixelMaps USING [PixelMap, PixelMapRep, Function, DeviceRectangle, BoundedWindow], ImagerPixelMapsExtras USING [SetBit, Set2Bits, Set4Bits, Set8Bits, Set16Bits, ByteSequence]; ImagerPixelMapsExtrasImpl: CEDAR PROGRAM IMPORTS Basics, ImagerPixelMaps, PrincOpsUtils, ImagerPixelMapsExtras EXPORTS ImagerPixelMapsExtras ~ BEGIN <> BytePair: TYPE ~ Basics.BytePair; IntPair: TYPE ~ ImagerBasic.IntPair; DeviceRectangle: TYPE ~ ImagerPixelMaps.DeviceRectangle; Function: TYPE ~ ImagerPixelMaps.Function; ByteSequence: TYPE ~ ImagerPixelMapsExtras.ByteSequence; PixelMap: TYPE ~ ImagerPixelMaps.PixelMap; <> <> <> <> <> <> <<];>> <> <> <> <> <> <<];>> <> lgBitsPerWord: NAT ~ Basics.logBitsPerWord; bitsPerWord: NAT ~ Basics.bitsPerWord; BitAddr: UNSAFE PROC [lineStart: LONG POINTER, pixel: CARDINAL, lgBitsPerPixel: INTEGER] RETURNS [PrincOps.BitAddress] ~ UNCHECKED { RETURN [[ word: lineStart + Basics.BITSHIFT[pixel, lgBitsPerPixel-lgBitsPerWord], bit: Basics.BITAND[Basics.BITSHIFT[pixel, lgBitsPerPixel], bitsPerWord-1] ]] }; SGN: PROCEDURE [number: INTEGER] RETURNS [INTEGER] = INLINE { IF number >= 0 THEN RETURN[1] ELSE RETURN[-1]; }; <> replicator: ARRAY [0..4] OF CARDINAL ~ [0FFFFH, 05555H, 01111H, 00101H, 00001H]; FillConstantTrap: PUBLIC PROC [destination: PixelMap, -- trapezoid, constant color top, bottom, leftTop, leftBot, rightTop, rightBot: NAT, pxlValue: CARDINAL, function: Function _ [null, null]] ~ TRUSTED { lgBitsPerPixel: NAT ~ destination.refRep.lgBitsPerPixel; bitsPerPixel: NAT ~ Basics.BITSHIFT[1, lgBitsPerPixel]; value: CARDINAL ~ MIN[pxlValue, Basics.BITSHIFT[1, bitsPerPixel] - 1]; rastWds: CARDINAL ~ destination.refRep.rast; rastBits: CARDINAL ~ rastWds * bitsPerWord; EdgeBlock: TYPE = RECORD [xPos: LONG CARDINAL, xIncr: LONG INTEGER]; MakeEdge: UNSAFE PROC[xTop, xBot, height: NAT] RETURNS [edge: EdgeBlock] = { LOOPHOLE[edge.xPos, Basics.LongNumber].highbits _ xBot; LOOPHOLE[edge.xPos, Basics.LongNumber].lowbits _ 0; LOOPHOLE[edge.xIncr, Basics.LongNumber].highbits _ xTop - xBot; LOOPHOLE[edge.xIncr, Basics.LongNumber].lowbits _ 0; IF height > 1 THEN edge.xIncr _ edge.xIncr / height; }; DoScanSeg: UNSAFE PROC[] ~ { PrincOpsUtils.BITBLT[bb]; }; bbspace: PrincOps.BBTableSpace; bb: PrincOps.BBptr _ PrincOpsUtils.AlignedBBTable[@bbspace]; replicatedPixel: CARDINAL _ Basics.BITAND[value, Basics.BITSHIFT[1, Basics.BITSHIFT[1, lgBitsPerPixel]]-1] * replicator[lgBitsPerPixel]; -- make brick for BitBlt lEdge: EdgeBlock _ MakeEdge[leftTop, leftBot, top - bottom]; rEdge: EdgeBlock _ MakeEdge[rightTop, rightBot, top - bottom]; bb^ _ [ dst: BitAddr[destination.refRep.pointer + Basics.LongMult[bottom, rastWds], leftBot, lgBitsPerPixel], dstBpl: rastBits, src: [word: @replicatedPixel, bit: 0], srcDesc: [gray[[yOffset: 0, widthMinusOne: 0, heightMinusOne: 0]]], height: 1, width: Basics.BITSHIFT[rightTop - leftTop, lgBitsPerPixel], flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: TRUE, srcFunc: function.srcFunc, dstFunc: function.dstFunc] ]; FOR height: NAT IN [bottom..top] DO bb.dst _ BitAddr[destination.refRep.pointer + Basics.LongMult[height, rastWds], Basics.HighHalf[lEdge.xPos], lgBitsPerPixel]; bb.width _ Basics.BITSHIFT[ Basics.HighHalf[rEdge.xPos] - Basics.HighHalf[lEdge.xPos] + 1, lgBitsPerPixel ]; DoScanSeg[]; lEdge.xPos _ lEdge.xPos + lEdge.xIncr; rEdge.xPos _ rEdge.xPos + rEdge.xIncr; ENDLOOP; }; FillSmoothTrap: PUBLIC PROC [destination: PixelMap, -- bilinear interpolated 8-bit color top, bottom, leftTop, leftBot, rightTop, rightBot: NAT, leftTopVal, leftBotVal, rightTopVal, rightBotVal: NAT] ~ TRUSTED { rastWds: CARDINAL ~ destination.refRep.rast; rastBits: CARDINAL ~ rastWds * bitsPerWord; EdgeBlock: TYPE = RECORD [xPos, value: LONG CARDINAL, xIncr, valIncr: INT]; MakeEdge: UNSAFE PROC[xTop, valTop, xBot, valBot, height: NAT] RETURNS [edge: EdgeBlock] = { valBot _ MIN[valBot, 255]; valTop _ MIN[valTop, 255]; LOOPHOLE[edge.xPos, Basics.LongNumber].highbits _ xBot; LOOPHOLE[edge.xPos, Basics.LongNumber].lowbits _ 0; LOOPHOLE[edge.xIncr, Basics.LongNumber].highbits _ xTop - xBot; LOOPHOLE[edge.xIncr, Basics.LongNumber].lowbits _ 0; LOOPHOLE[edge.value, Basics.LongNumber].highbits _ valBot; LOOPHOLE[edge.value, Basics.LongNumber].lowbits _ 0; LOOPHOLE[edge.valIncr, Basics.LongNumber].highbits _ valTop - valBot; LOOPHOLE[edge.valIncr, Basics.LongNumber].lowbits _ 0; IF height > 1 THEN { edge.xIncr _ edge.xIncr / height; edge.valIncr _ edge.valIncr / height; }; }; DoScanSeg: PROC[lx, lVal, rx, rVal: LONG CARDINAL] = TRUSTED { value, valIncr: INT; xStart: NAT _ Basics.HighHalf[lx]; xFinish: NAT _ Basics.HighHalf[rx]; length: INTEGER _ xFinish - xStart; leftByte: BOOLEAN; valIncr _ INT[rVal] - INT[lVal]; IF ABS[length] >= 1 THEN valIncr _ valIncr / length; IF xFinish >= xStart THEN { value _ lVal; pxlPtr _ scanPtr + LOOPHOLE[Basics.HighHalf[lx] / 2, CARDINAL]; } ELSE { -- twisted or otherwise backwards xTemp: CARDINAL _ xStart; xStart _ xFinish; xFinish _ xTemp; value _ rVal; pxlPtr _ scanPtr + LOOPHOLE[Basics.HighHalf[rx] / 2, CARDINAL]; }; leftByte _ (xStart MOD 2) = 0; FOR i: NAT IN [xStart..xFinish] DO IF leftByte THEN pxlPtr^.high _ Basics.HighHalf[value] ELSE { pxlPtr^.low _ Basics.HighHalf[value]; pxlPtr _ pxlPtr + 1; }; leftByte _ NOT leftByte; value _ value + valIncr; ENDLOOP; }; scanPtr, pxlPtr: LONG POINTER TO Basics.BytePair; wordsPerLine: NAT _ destination.refRep.rast; lEdge: EdgeBlock _ MakeEdge[leftTop, leftTopVal, leftBot, leftBotVal, top - bottom]; rEdge: EdgeBlock _ MakeEdge[rightTop, rightTopVal, rightBot, rightBotVal, top - bottom]; IF destination.refRep.lgBitsPerPixel # 3 THEN ERROR; TRUSTED { scanPtr _ LOOPHOLE[ destination.refRep.pointer + Basics.LongMult[destination.refRep.rast, bottom], LONG POINTER TO Basics.BytePair]; }; FOR height: NAT IN [bottom..top] DO DoScanSeg[lEdge.xPos, lEdge.value, rEdge.xPos, rEdge.value]; lEdge.xPos _ lEdge.xPos + lEdge.xIncr; lEdge.value _ lEdge.value + lEdge.valIncr; rEdge.xPos _ rEdge.xPos + rEdge.xIncr; rEdge.value _ rEdge.value + rEdge.valIncr; scanPtr _ scanPtr + wordsPerLine; ENDLOOP; }; DrawLine: PUBLIC PROC [destination: PixelMap, p1, p2: IntPair, -- fast line, constant color pxlValue: NAT, function: Function _ [null, null]] ~ { increment, bias, error, sBump, t, shiftDist: INTEGER; wrdPtr: LONG POINTER TO WORD; p1s, p1f, p2s, p2f: INTEGER; <> lgBitsPerPixel: NAT ~ destination.refRep.lgBitsPerPixel; logPxlsPerWd: NAT ~ Basics.logBitsPerWord - lgBitsPerPixel; bitsPerPixel: NAT ~ Basics.BITSHIFT[1, lgBitsPerPixel]; maxShift: NAT ~ Basics.bitsPerWord - bitsPerPixel; maxValue: NAT ~ Basics.BITSHIFT[1, bitsPerPixel] - 1; value: NAT ~ MIN[pxlValue, maxValue]; p1f _ p1.x; p1s _ p1.y; p2f _ p2.x; p2s _ p2.y; <> IF p1f > p2f THEN { t _ p1f; p1f _ p2f; p2f _ t; t _ p1s; p1s _ p2s; p2s _ t; }; <> TRUSTED { wrdPtr _ destination.refRep.pointer + Basics.LongMult[destination.refRep.rast, p1s] + Basics.BITSHIFT[p1f, -logPxlsPerWd]; }; shiftDist _ maxShift - Basics.BITSHIFT[ Basics.BITAND[ p1f, Basics.BITSHIFT[1, logPxlsPerWd] - 1], -- p1f MOD pixelsPerWord lgBitsPerPixel ]; IF (p2f - p1f) > ABS[p2s - p1s] <> THEN { increment _ 2 * (p2s - p1s); bias _ 2 * (p2f - p1f); sBump _ SGN[increment] * destination.refRep.rast; increment _ ABS[increment]; error _ increment - bias/2; IF lgBitsPerPixel = 3 -- speedup for 8 bits per pixel THEN FOR i: NAT IN [0..(p2f-p1f)] DO TRUSTED { IF shiftDist = 0 THEN { LOOPHOLE[wrdPtr^, BytePair].low _ value; wrdPtr _ wrdPtr + 1; shiftDist _ 8; } ELSE { LOOPHOLE[wrdPtr^, BytePair].high _ value; shiftDist _ 0; }; IF error > 0 THEN TRUSTED { wrdPtr _ wrdPtr + sBump; error _ error - bias; }; error _ error + increment; }; ENDLOOP ELSE FOR i: NAT IN [0..(p2f-p1f)] DO TRUSTED { wrdPtr^ _ Basics.BITOR[ -- deposit pixel bits in word Basics.BITAND[wrdPtr^, Basics.BITNOT[Basics.BITSHIFT[maxValue, shiftDist]]], Basics.BITSHIFT[value, shiftDist] ]; }; IF shiftDist = 0 THEN TRUSTED { wrdPtr _ wrdPtr + 1; shiftDist _ maxShift; } ELSE shiftDist _ shiftDist - bitsPerPixel; IF error > 0 THEN TRUSTED { wrdPtr _ wrdPtr + sBump; error _ error - bias; }; error _ error + increment; ENDLOOP; } <> ELSE { j: NAT _ Basics.BITSHIFT[shiftDist, -lgBitsPerPixel]; pixelsPerWd: NAT ~ Basics.BITSHIFT[1, logPxlsPerWd]; mask, values: ARRAY [0..16) OF CARDINAL; FOR i: NAT IN [0..pixelsPerWd) DO mask[i] _ Basics.BITNOT[Basics.BITSHIFT[maxValue, Basics.BITSHIFT[i, lgBitsPerPixel]]]; values[i] _ Basics.BITSHIFT[value, Basics.BITSHIFT[i, lgBitsPerPixel]]; ENDLOOP; increment _ 2 * (p2f - p1f); bias _ 2 * (p2s - p1s); sBump _ SGN[bias] * destination.refRep.rast; bias _ ABS[bias]; error _ increment - bias/2; IF lgBitsPerPixel = 3 -- speedup for 8 bits per pixel THEN FOR i: NAT IN [0..ABS[p2s - p1s]] DO TRUSTED { IF shiftDist = 0 THEN { LOOPHOLE[wrdPtr^, BytePair].low _ value; IF error > 0 THEN { wrdPtr _ wrdPtr + 1; shiftDist _ 8; error _ error - bias; }; } ELSE { LOOPHOLE[wrdPtr^, BytePair].high _ value; IF error > 0 THEN { shiftDist _ 0; error _ error - bias; }; }; wrdPtr _ wrdPtr + sBump; error _ error + increment; }; ENDLOOP ELSE FOR i: NAT IN [0..ABS[p2s - p1s]] DO TRUSTED { wrdPtr^ _ Basics.BITOR[ Basics.BITAND[wrdPtr^, mask[j]] , values[j]]; }; TRUSTED { wrdPtr _ wrdPtr + sBump; }; IF error > 0 THEN { error _ error - bias; IF j = 0 THEN TRUSTED { wrdPtr _ wrdPtr + 1; j _ pixelsPerWd - 1; } ELSE j _ j - 1; }; error _ error + increment; ENDLOOP; }; }; DrawBltLine: PUBLIC PROC [destination: PixelMap, -- fast line using BitBLT, constant color p1, p2: IntPair, pxlValue: NAT, function: Function _ [null, null]] ~ TRUSTED { increment, bias, error, sBump, t: INTEGER; p1s, p1f, p2s, p2f: INTEGER; wrdPtr: LONG POINTER; bbTableSpace: PrincOps.BBTableSpace; bb: PrincOps.BBptr _ PrincOpsUtils.AlignedBBTable[@bbTableSpace]; <> lgBitsPerPixel: NAT ~ destination.refRep.lgBitsPerPixel; logBitsPerPixel: NAT ~ lgBitsPerPixel; bitsPerPixel: NAT ~ Basics.BITSHIFT[1, lgBitsPerPixel]; logPxlsPerWd: NAT ~ Basics.logBitsPerWord - logBitsPerPixel; pxlsPerWordLessOne: NAT ~ Basics.BITSHIFT[1, logPxlsPerWd] - 1; replicatedPixel: CARDINAL _ Basics.BITAND[ value, Basics.BITSHIFT[1, Basics.BITSHIFT[1, logBitsPerPixel]] - 1 ] * replicator[logBitsPerPixel]; -- make brick for BitBlt pxlCnt, leftOverPixels: NAT _ 0; --pixels since last jag in line value: NAT ~ MIN[pxlValue, Basics.BITSHIFT[1, bitsPerPixel] - 1]; p1f _ p1.x; p1s _ p1.y; p2f _ p2.x; p2s _ p2.y; <> IF p1f > p2f THEN { t _ p1f; p1f _ p2f; p2f _ t; t _ p1s; p1s _ p2s; p2s _ t; }; <> wrdPtr _ destination.refRep.pointer + Basics.LongMult[destination.refRep.rast, p1s] + Basics.BITSHIFT[p1f, -logPxlsPerWd]; leftOverPixels _ Basics.BITAND[p1f, pxlsPerWordLessOne]; <> bb^ _ [ dst: [word: wrdPtr, bit: Basics.BITSHIFT[leftOverPixels, logBitsPerPixel]], dstBpl: destination.refRep.rast * Basics.bitsPerWord, src: [word: @replicatedPixel, bit: 0], srcDesc: [gray[[yOffset: 0, widthMinusOne: 0, heightMinusOne: 0]]], height: 1, width: bitsPerPixel, flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: TRUE, srcFunc: function.srcFunc, dstFunc: function.dstFunc] ]; IF (p2f - p1f) > ABS[p2s - p1s] <> THEN { increment _ 2 * (p2s - p1s); bias _ 2 * (p2f - p1f); sBump _ SGN[increment] * destination.refRep.rast; increment _ ABS[increment]; error _ increment - bias/2; FOR i: NAT IN [0..(p2f-p1f)] DO pxlCnt _ pxlCnt + 1; IF error > 0 THEN { -- end of straight segment bb.dst _ [word: wrdPtr, bit: Basics.BITSHIFT[leftOverPixels, logBitsPerPixel] ]; bb.width _ Basics.BITSHIFT[pxlCnt, lgBitsPerPixel]; PrincOpsUtils.BITBLT[bb]; pxlCnt _ pxlCnt + leftOverPixels; wrdPtr _ wrdPtr + sBump + Basics.BITSHIFT[pxlCnt, -logPxlsPerWd]; leftOverPixels _ Basics.BITAND[pxlCnt, pxlsPerWordLessOne]; pxlCnt _ 0; error _ error - bias }; error _ error + increment; ENDLOOP; bb.dst _ [word: wrdPtr, -- BLT last segment bit: Basics.BITSHIFT[leftOverPixels, logBitsPerPixel] ]; bb.width _ Basics.BITSHIFT[pxlCnt, logBitsPerPixel]; PrincOpsUtils.BITBLT[bb]; } <> ELSE { lastWrdPtr: LONG POINTER TO CARDINAL _ wrdPtr; increment _ 2 * (p2f - p1f); bias _ 2 * (p2s - p1s); sBump _ SGN[bias] * destination.refRep.rast; bias _ ABS[bias]; error _ increment - bias/2; FOR i: NAT IN [0..ABS[p2s - p1s]] DO pxlCnt _ pxlCnt + 1; wrdPtr _ wrdPtr + sBump; IF error > 0 THEN { bb.dst _ [ word: IF sBump < 0 THEN wrdPtr ELSE lastWrdPtr, bit: Basics.BITSHIFT[leftOverPixels, logBitsPerPixel] ]; bb.height _ pxlCnt; PrincOpsUtils.BITBLT[bb]; IF leftOverPixels = pxlsPerWordLessOne THEN { wrdPtr _ wrdPtr + 1; leftOverPixels _ 0; } ELSE leftOverPixels _ leftOverPixels + 1; lastWrdPtr _ wrdPtr; pxlCnt _ 0; error _ error - bias; }; error _ error + increment; ENDLOOP; bb.dst _ [word: IF sBump < 0 THEN wrdPtr ELSE lastWrdPtr, -- BLT last segment bit: Basics.BITSHIFT[leftOverPixels, logBitsPerPixel] ]; bb.height _ pxlCnt; PrincOpsUtils.BITBLT[bb]; }; }; LoadScanSeg: PUBLIC PROC[destination: PixelMap, s, f: INTEGER, length: NAT, segment: LONG POINTER, offset: NAT _ 0] = TRUSTED{ bbspace: PrincOps.BBTableSpace; bb: PrincOps.BBptr _ PrincOpsUtils.AlignedBBTable[@bbspace]; pxpWd: NAT ~ Basics.BITSHIFT[1, Basics.logBitsPerWord - destination.refRep.lgBitsPerPixel]; bb^ _ [ dst: [ word: LOOPHOLE[ destination.refRep.pointer + Basics.LongMult[destination.refRep.rast, s] + (f / pxpWd), LONG POINTER], bit: Basics.BITSHIFT[f MOD pxpWd, destination.refRep.lgBitsPerPixel] ], dstBpl: 0, src: [ word: segment + offset/pxpWd, bit: Basics.BITSHIFT[offset MOD pxpWd, destination.refRep.lgBitsPerPixel] ], srcDesc: [srcBpl[0]], width: Basics.BITSHIFT[length , destination.refRep.lgBitsPerPixel], height: 1, flags: [disjoint: TRUE] ]; PrincOpsUtils.BITBLT[bb]; }; StoreScanSeg: PUBLIC PROC [source: PixelMap, s, f: INTEGER, length: NAT, segment: LONG POINTER, offset: NAT _ 0] = TRUSTED{ bbspace: PrincOps.BBTableSpace; bb: PrincOps.BBptr _ PrincOpsUtils.AlignedBBTable[@bbspace]; pxpWd: NAT ~ Basics.BITSHIFT[1, Basics.logBitsPerWord - source.refRep.lgBitsPerPixel]; bb^ _ [ dst: [ word: segment + offset/pxpWd, bit: Basics.BITSHIFT[offset MOD pxpWd, source.refRep.lgBitsPerPixel] ], dstBpl: 0, src: [ word: LOOPHOLE[ source.refRep.pointer + Basics.LongMult[source.refRep.rast, s] + (f / pxpWd), LONG POINTER], bit: Basics.BITSHIFT[f MOD pxpWd, source.refRep.lgBitsPerPixel] ], srcDesc: [srcBpl[0]], width: Basics.BITSHIFT[length , source.refRep.lgBitsPerPixel], height: 1, flags: [disjoint: TRUE] ]; PrincOpsUtils.BITBLT[bb]; }; SetPixel: PUBLIC PROC [destination: PixelMap, s, f: INTEGER, value: NAT] ~ { <> bounds: DeviceRectangle _ ImagerPixelMaps.BoundedWindow[destination]; sCheck: NAT _ bounds.sSize-1-NAT[s-bounds.sMin]; fCheck: NAT _ bounds.fSize-1-NAT[f-bounds.fMin]; SELECT destination.refRep.lgBitsPerPixel FROM 0 => ImagerPixelMapsExtras.SetBit[destination, s, f, value]; 1 => ImagerPixelMapsExtras.Set2Bits[destination, s, f, value]; 2 => ImagerPixelMapsExtras.Set4Bits[destination, s, f, value]; 3 => ImagerPixelMapsExtras.Set8Bits[destination, s, f, value]; 4 => ImagerPixelMapsExtras.Set16Bits[destination, s, f, value]; ENDCASE => ERROR; }; END.