<> <> <> <<>> DIRECTORY BitBlt, Environment, Inline, PDInterpBitmap; PDInterpBitmapImpl: PROGRAM IMPORTS BitBlt, Inline EXPORTS PDInterpBitmap = BEGIN BitmapDesc: TYPE = PDInterpBitmap.BitmapDesc; Tile: TYPE = PDInterpBitmap.Tile; Rectangle: TYPE = PDInterpBitmap.Rectangle; Function: TYPE = PDInterpBitmap.Function; bitsPerWord: NAT = Environment.bitsPerWord; lgBitsPerWord: NAT = Environment.logBitsPerWord; wordsPerPage: NAT = Environment.wordsPerPage; lgBitsPerPixel: NAT = 0; pixelsPerWord: NAT = bitsPerWord; <> BITAND: PROC [a, b: CARDINAL] RETURNS[CARDINAL] = INLINE {RETURN[Inline.BITAND[a, b]]}; Shift: PROC [a: CARDINAL, b: INTEGER] RETURNS [CARDINAL] = INLINE {RETURN[Inline.BITSHIFT[a, b]]}; BITBLT: PROC [ptr: BitBlt.BBptr] = { <> <> BitBlt.BITBLT[ptr]; }; Intersect: PUBLIC PROC [a, b: Rectangle] RETURNS [Rectangle] = { sMin: INTEGER _ MAX[a.sMin, b.sMin]; fMin: INTEGER _ MAX[a.fMin, b.fMin]; sMax: INTEGER _ MIN[INT[a.sMin]+a.sSize, INT[b.sMin]+b.sSize]; fMax: INTEGER _ MIN[INT[a.fMin]+a.fSize, INT[b.fMin]+b.fSize]; IF sMax <= sMin OR fMax <= fMin THEN RETURN [[0, 0, 0, 0]] ELSE RETURN [[sMin, fMin, sMax-sMin, fMax-fMin]] }; LongZero: PROC [address: LONG POINTER TO CARDINAL, count: CARDINAL] = { IF count > 0 THEN { address^ _ 0; Inline.LongCOPY[from: address, nwords: count-1, to: address+1]; }; }; Clear: PUBLIC PROC [bitmapDesc: BitmapDesc] = { pointer: LONG POINTER _ bitmapDesc.pointer; words: LONG CARDINAL _ Inline.LongMult[bitmapDesc.rast, bitmapDesc.lines]; WHILE words > 32768 DO LongZero[pointer, 32768]; pointer _ pointer + 32768; words _ words - 32768; ENDLOOP; LongZero[pointer, words]; }; InsufficientSpace: PUBLIC ERROR = CODE; Reshape: PUBLIC PROC [pointer: LONG POINTER, words: INT, bounds: Rectangle] RETURNS [bitmapDesc: BitmapDesc] = { bitsPerPixel: CARDINAL = Shift[1, lgBitsPerPixel]; bitsPerLine: NAT = Inline.LongMult[bounds.fSize, bitsPerPixel]; <> wordsPerLine: CARDINAL = (bitsPerLine+(bitsPerWord-1)) / bitsPerWord; wordsNeeded: INT = Inline.LongMult[wordsPerLine, bounds.sSize]; IF wordsNeeded > words THEN ERROR InsufficientSpace; RETURN [[bounds.sMin, bounds.fMin, 0, 0, bounds.sSize, bounds.fSize, pointer, wordsPerLine, bounds.sSize]]; }; ShiftMap: PUBLIC PROC [p: BitmapDesc, s, f: INTEGER] RETURNS [BitmapDesc] = { p.sOrigin _ p.sOrigin + s; p.fOrigin _ p.fOrigin + f; RETURN [p] }; ShiftWindow: PUBLIC PROC [p: BitmapDesc, s, f: INTEGER] RETURNS [BitmapDesc] = { p.sMin _ p.sMin + s; p.fMin _ p.fMin + f; RETURN [p] }; Clip: PUBLIC PROC [p: BitmapDesc, bounds: Rectangle] RETURNS [BitmapDesc] = { bounds _ Intersect[Window[p], bounds]; p.sMin _ bounds.sMin-p.sOrigin; p.fMin _ bounds.fMin-p.fOrigin; p.sSize _ bounds.sSize; p.fSize _ bounds.fSize; RETURN [p] }; SetWindow: PUBLIC PROC [p: BitmapDesc, bounds: Rectangle] RETURNS [BitmapDesc] = { RETURN [p] }; Window: PUBLIC PROC [p: BitmapDesc] RETURNS [Rectangle] = { RETURN [[p.sOrigin + p.sMin, p.fOrigin + p.fMin, p.sSize, p.fSize]] }; BufferBounds: PUBLIC PROC [p: BitmapDesc] RETURNS [Rectangle] = { RETURN [[p.sOrigin, p.fOrigin, p.lines, Shift[p.rast, lgBitsPerWord-lgBitsPerPixel]]] }; BoundedWindow: PUBLIC PROC [p: BitmapDesc] RETURNS [Rectangle] = { sMin: INTEGER _ MAX[p.sOrigin + p.sMin, p.sOrigin]; fMin: INTEGER _ MAX[p.fOrigin + p.fMin, p.fOrigin]; sMax: INTEGER _ MIN[p.sOrigin + p.sMin + p.sSize, p.sOrigin + p.lines]; fMax: INTEGER _ MIN[p.fOrigin + p.fMin + p.fSize, p.fOrigin + Shift[p.rast, lgBitsPerWord-lgBitsPerPixel]]; RETURN [[sMin, fMin, MAX[sMax-sMin, 0], MAX[fMax-fMin, 0]]] }; replicator: ARRAY [0..4] OF CARDINAL = [0FFFFH, 05555H, 01111H, 00101H, 00001H]; Fill: PUBLIC PROC [dest: BitmapDesc, area: Rectangle, value: CARDINAL, function: Function] = { lgPixelsPerWord: INTEGER = lgBitsPerWord-lgBitsPerPixel; <> sMin: INTEGER = MAX[dest.sMin, 0, area.sMin-dest.sOrigin]; sMax: INTEGER = MIN[dest.sMin+dest.sSize, dest.lines, area.sMin+area.sSize-dest.sOrigin]; fMin: INTEGER = MAX[dest.fMin, 0, area.fMin-dest.fOrigin]; fMax: INTEGER = MIN[dest.fMin+dest.fSize, Shift[dest.rast, lgBitsPerWord-lgBitsPerPixel], area.fMin+area.fSize-dest.fOrigin]; replicatedPixel: CARDINAL _ Inline.BITAND[value, Shift[1, Shift[1, lgBitsPerPixel]]-1] * replicator[lgBitsPerPixel]; bbTableSpace: BitBlt.BBTableSpace; bb: BitBlt.BBptr _ BitBlt.AlignedBBTable[@bbTableSpace]; IF sMinfMinDest AND (fMinDest+fSize)>fMinSource AND (sStartSource+sSize)>sStartDest AND (sStartDest+sSize)>sStartSource THEN { bb.flags.disjoint _ FALSE; -- the rectangles overlap IF sStartDest=sStartSource THEN bb.flags.disjointItems _ FALSE; -- so do the items IF sStartDest>sStartSource OR (sStartDest=sStartSource AND fMinDest>fMinSource) THEN { -- reverse direction bb.flags.direction _ backward; bb.srcDesc.srcBpl _ bb.dstBpl _ -bb.dstBpl; sStartSource _ sStartSource + (sSize-1); sStartDest _ sStartDest + (sSize-1); }; }; }; bb.dst _ [word: dest.pointer + Inline.LongMult[sStartDest, dest.rast] + Shift[fMinDest, -lgPixelsPerWord], bit: Inline.BITAND[fMinDest, Shift[1, lgPixelsPerWord]-1]]; bb.src _ [word: source.pointer + Inline.LongMult[sStartSource, source.rast] + Shift[fMinSource, -lgPixelsPerWord], bit: Inline.BITAND[fMinSource, Shift[1, lgPixelsPerWord]-1]]; BITBLT[bb]; }; }; IsPowerOfTwo: PROC [c: CARDINAL] RETURNS [BOOLEAN] = INLINE { RETURN [BITAND[c, c-1] = 0] }; largeBitSize: INT _ 5000; fSizeHint: NAT _ 100; CreateTile: PUBLIC PROC [rectangle: Rectangle, phase: INTEGER _ 0, rasterPointer: LONG POINTER, scratchPointer: LONG POINTER _ NIL, scratchWords: INT _ 0] RETURNS [tile: Tile] = { ENABLE InsufficientSpace => GO TO InsufficientScratch; bitWidth: CARDINAL = Shift[rectangle.fSize, lgBitsPerPixel]; bitmapDesc: BitmapDesc = [rectangle.sMin, rectangle.fMin, 0, 0, rectangle.sSize, rectangle.fSize, rasterPointer, (rectangle.fSize+(pixelsPerWord-1))/pixelsPerWord, rectangle.sSize]; IF bitWidth <= 16 AND IsPowerOfTwo[bitWidth] AND bitmapDesc.sSize < 16 AND phase = 0 THEN { small: BitmapDesc _ Reshape[scratchPointer, scratchWords, [rectangle.sMin, rectangle.fMin, rectangle.sSize, Shift[16, -lgBitsPerPixel]]]; FOR fShift: NAT _ 0, fShift+bitmapDesc.fSize UNTIL fShift>=small.fSize DO Transfer[small, ShiftMap[bitmapDesc, 0, fShift], [null, null]]; ENDLOOP; tile _ [small.sOrigin, small.fOrigin, small.sSize, small.fSize, 0, small.pointer, small.rast, small.lines]; } ELSE { fSize: NAT _ (fSizeHint+bitmapDesc.fSize-1)/bitmapDesc.fSize*bitmapDesc.fSize; bitsPerLine: NAT _ Shift[fSize, lgBitsPerPixel]; sSize: NAT _ MAX[(((largeBitSize+bitsPerLine-1)/bitsPerLine)/bitmapDesc.sSize)*bitmapDesc.sSize, bitmapDesc.sSize]; large: BitmapDesc _ Reshape[scratchPointer, scratchWords, [bitmapDesc.sOrigin+bitmapDesc.sMin, bitmapDesc.fOrigin+bitmapDesc.fMin, sSize, fSize]]; finalPhase: CARDINAL; WHILE phase<0 DO phase _ phase + bitmapDesc.fSize ENDLOOP; phase _ phase MOD bitmapDesc.fSize; finalPhase _ (phase * (sSize/bitmapDesc.sSize)) MOD bitmapDesc.fSize; large.sSize _ bitmapDesc.sSize; large.fSize _ bitmapDesc.fSize; Transfer[large, bitmapDesc, [null, null]]; WHILE large.fSize bitmapDesc.fSize DO phase _ phase - bitmapDesc.fSize ENDLOOP; ENDLOOP; tile _ [large.sOrigin, large.fOrigin, sSize, fSize, finalPhase, large.pointer, large.rast, large.lines]; }; EXITS InsufficientScratch => { tile _ [rectangle.sMin, rectangle.fMin, rectangle.sSize, rectangle.fSize, phase, rasterPointer, (rectangle.fSize+(pixelsPerWord-1))/pixelsPerWord, rectangle.sSize]; }; }; TransferTile: PUBLIC PROC [dest: BitmapDesc, tile: Tile, function: Function _ [null, null]] = { bitWidth: CARDINAL = Shift[tile.fSize, lgBitsPerPixel]; IF bitWidth = bitsPerWord AND tile.rast = 1 AND tile.sSize <= 16 AND tile.phase = 0 THEN { startLine: NAT _ MAX[dest.sMin, 0]; endLine: INTEGER _ MIN[dest.sMin+dest.sSize, dest.lines]; startPixel: NAT _ MAX[dest.fMin, 0]; endPixel: INTEGER _ MIN[dest.fMin+dest.fSize, Shift[dest.rast, lgBitsPerWord-lgBitsPerPixel]]; IF endLine>startLine AND endPixel>startPixel THEN { startBit: NAT _ Shift[startPixel, lgBitsPerPixel]; bbTableSpace: BitBlt.BBTableSpace; bb: BitBlt.BBptr = BitBlt.AlignedBBTable[@bbTableSpace]; sOffset: INTEGER _ (dest.sOrigin+dest.sMin-tile.sOrigin) MOD tile.sSize; fOffset: INTEGER _ (dest.fOrigin+dest.fMin-tile.fOrigin) MOD tile.fSize; WHILE sOffset < 0 DO sOffset _ sOffset + tile.sSize ENDLOOP; WHILE fOffset < 0 DO fOffset _ fOffset + tile.fSize ENDLOOP; bb^ _ [ dst: [word: dest.pointer + Inline.LongMult[startLine, dest.rast] + startBit/bitsPerWord, bit: startBit MOD bitsPerWord], dstBpl: dest.rast*bitsPerWord, src: [word: tile.pointer+sOffset, bit: Shift[fOffset, lgBitsPerPixel]], srcDesc: [gray[[yOffset: sOffset, widthMinusOne: 0, heightMinusOne: tile.sSize-1]]], height: endLine-startLine, width: Shift[endPixel-startPixel, lgBitsPerPixel], flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: TRUE, srcFunc: function.srcFunc, dstFunc: function.dstFunc] ]; BITBLT[bb]; }; } ELSE { sMin: INT _ dest.sOrigin+dest.sMin; fMin: INT _ dest.fOrigin+dest.fMin; source: BitmapDesc; sOrigin: INT _ tile.sOrigin; fOrigin: INT _ tile.fOrigin; WHILE sOrigin < sMin DO sOrigin _ sOrigin + tile.sSize; fOrigin _ fOrigin + tile.phase; ENDLOOP; WHILE sOrigin > sMin DO sOrigin _ sOrigin - tile.sSize; fOrigin _ fOrigin - tile.phase; ENDLOOP; WHILE fOrigin < fMin DO fOrigin _ fOrigin + tile.fSize ENDLOOP; WHILE fOrigin > fMin DO fOrigin _ fOrigin - tile.fSize ENDLOOP; source _ [sOrigin, fOrigin, 0, 0, tile.sSize, tile.fSize, tile.pointer, tile.rast, tile.lines]; WHILE source.sOrigin < sMin+dest.sSize DO source.fOrigin _ fOrigin; WHILE source.fOrigin < fMin+dest.fSize DO Transfer[dest, source, function]; source.fOrigin _ source.fOrigin + source.fSize; ENDLOOP; source.sOrigin _ source.sOrigin + source.sSize; fOrigin _ fOrigin + tile.phase; WHILE fOrigin > fMin DO fOrigin _ fOrigin - source.fSize ENDLOOP; ENDLOOP; }; }; END.