-- MesaBandsImpl.mesa -- Last changed by Ken Pier, March 30, 1982 10:47 AM DIRECTORY MesaBands, MesaBandStream USING [InitBandFileBuffer, GetBand], MesaBandFormat USING [Bit, Type, Marker, TBrickRef, tBrickSize, Run, runSize, HeraldRef, HeraldObject, heraldObjectSize, Line, LineRef, ObjectRef, Object, objectSize], MesaBrickBLT USING [InitializeBrickBLT, BrickBLT], PressBandsDefs USING [StoreScanLine], PressNetDefs USING [PageAttributes, ScanDirection], Inline USING [LowHalf, HighHalf, LongMult, LongCOPY], DynamicZone USING [InitializeZones, SystemZone], MiscDefs USING [CallDebugger], SegmentDefs USING [NewDataSegment, DefaultXMBase, LongVMtoDataSegment, DeleteDataSegment, LongDataSegmentAddress], BitBltDefs USING [BBTableSpace, BBptr, BITBLT]; MesaBandsImpl: PROGRAM IMPORTS MesaBandStream, MesaBrickBLT, PressBandsDefs, Inline, BitBltDefs, SegmentDefs, DynamicZone, MiscDefs EXPORTS MesaBands = { OPEN BStream: MesaBandStream, BFormat: MesaBandFormat, BB: BitBltDefs, Seg: SegmentDefs, PB: PressBandsDefs, PN: PressNetDefs, DZ: DynamicZone, MiscDefs, MesaBands; bitsPerWord: CARDINAL = 16; wordsPerPage: CARDINAL = 256; debug: BOOLEAN = TRUE; Error: SIGNAL = CODE; myMark: BFormat.Marker;-- = 98765432 Assert: PROC[pred: BOOLEAN] = INLINE { IF debug AND ~pred THEN CallDebugger["FalseAssertion"L] }; Data: TYPE = POINTER TO DataRep; DataRep: TYPE = RECORD [ device: BandDevice, base: LONG POINTER, -- base address of bitmap in upper bank pages: [0..254], -- pages in bitmap rast: CARDINAL, -- bitmap words per line lines: CARDINAL -- bitmap lines ]; New: PUBLIC PROC [bDevice: BandDevice] RETURNS [Data] = { data ← uz.NEW[DataRep ← [device: bDevice, base: NIL, pages: 0, rast: 0, lines: 0]]; InitBands[data];--verifies device type match [data.base, data.pages] ← AcquireBandBitmap[data]; RETURN[data]; }; InitBands: PROC [data: Data] = { wordsRead: CARDINAL ← 0; BStream.InitBandFileBuffer[]; wordsRead ← BStream.GetBand[heraldRef, BFormat.heraldObjectSize]; Assert[wordsRead=BFormat.heraldObjectSize]; Assert[heraldRef.mark=myMark]; Assert[heraldRef.device=data.device]; data.lines ← heraldRef.bandCount*heraldRef.bandHeight; data.rast ← heraldRef.bandWidth; Assert[data.rast*data.lines<65024D];--one bank less two pages runsRef ← uz.NEW[RunsBuffer[heraldRef.bandHeight]]; lineRef ← uz.NEW[BFormat.Line[maxLx2+(heraldRef.bandWidth*bitsPerWord)]];--brickline limit is (L+xmax+L-1) bits };--InitBands AcquireBandBitmap: PROC[data: Data] RETURNS [lp: LONG POINTER, pages: CARDINAL ← 0] = { SELECT data.device FROM IN [hornet..end] => { longrast, longtemp, longDiv: LONG CARDINAL;--KLUDGE longDiv ← heraldRef.bandCount*wordsPerPage; longrast ← data.rast; longtemp ← ((longrast*data.lines)+longDiv-1)/longDiv; -- number of words per image (+normalize for arithmetic)/(256 words per diskpage * # bands per image) Assert[Inline.HighHalf[longtemp]=0]; pages ← Inline.LowHalf[longtemp]; lp ← Seg.LongDataSegmentAddress[Seg.NewDataSegment[Seg.DefaultXMBase, pages]]; }; screen => ERROR; ENDCASE => ERROR; };--AcquireBandBitmap SpaceZero: PROC[base: LONG POINTER, pages: CARDINAL] = { Inline.LongCOPY[from: longZAddress, nwords: 1, to: base]; Inline.LongCOPY[from: base, nwords: (pages*wordsPerPage)-1, to: base+1]; };--SpaceZero Close: PUBLIC PROC[data: Data] = { Seg.DeleteDataSegment[Seg.LongVMtoDataSegment[data.base]]; data.base ← NIL; uz.FREE[@lineRef]; lineRef ← NIL; uz.FREE[@runsRef]; runsRef ← NIL; };--Close -- Modd copied from CGBrickImpl Modd: PROC[x, y: LONG INTEGER] RETURNS [LONG INTEGER] = INLINE { RETURN [IF x >= 0 THEN (x MOD y) ELSE ((y-1) + (x+1) MOD y)]; };--Modd GetNextOb: PROC [bandIndex: CARDINAL, objRef: BFormat.ObjectRef] = { --GetNextOb takes a local buffer and puts an object head --into the buffer, then fills in globals RunsBuffer, tBrick buffer, as appropriate. OPEN BFormat; wordsRead, runWords, brickWords: CARDINAL ← 0; wordsRead ← BStream.GetBand[to: objRef, words: objectSize]; Assert[ wordsRead=objectSize]; Assert[objRef.mark=myMark]; IF objRef.flags.type=end THEN RETURN; Assert[objRef.band=bandIndex ]; runWords ← IF objRef.flags.rect THEN BFormat.runSize ELSE BFormat.runSize*objRef.height; wordsRead ← BStream.GetBand[to: runsRef, words: runWords];--read runs Assert[ wordsRead=runWords]; SELECT objRef.flags.type FROM all0, all1, bits => RETURN; --no data for allx, scanlines later for bits brick => { --tBrick and runs. Read brick. wordsRead ← BStream.GetBand[to: tBrick, words: tBrickSize]; Assert[ wordsRead=tBrickSize]; brickWords ← (tBrick.brickSize + bitsPerWord-1)/bitsPerWord; wordsRead ← BStream.GetBand[to: brickBuffer, words: brickWords]; Assert[ wordsRead=brickWords]; Assert[ maxL>tBrick.L]; RETURN };--tBrick fontcache, herald, end => ERROR; ENDCASE => ERROR; };--GetNextOb ShowBandsInit: PUBLIC PROC[bDevice: BandDevice] RETURNS[p: PN.PageAttributes] = { scanDirection: PN.ScanDirection; data ← New[bDevice]; scanDirection ← SELECT bDevice FROM hornet => landscape, platemaker => portrait, reticlemaker => landscape, ENDCASE => ERROR; p ← [scanDirection: scanDirection, filler: , firstScan: 0, lastScan: data.lines-1, margin: 0, bitWc: data.rast]; };--ShowBandsInit ShowBands: PUBLIC PROC [] = { lptr: LONG POINTER ← NIL; yOffset ← 0; FOR bI: CARDINAL IN [0..heraldRef.bandCount) DO SpaceZero[data.base, data.pages]; --GetNextOb takes a band and a buffer and puts an object head for this band --into the buffer, then fills in globals RunsBuffer, tBrick buffer, Scanline -- as appropriate. DO GetNextOb[bandIndex: bI, objRef: objectRef]; SELECT objectRef.flags.type FROM all0, all1, bits, brick => Render[data: data]; herald => ERROR; end => EXIT; ENDCASE=> ERROR; ENDLOOP;--for each trap UNTIL end of band --write out the completed band buffer to the bits file lptr ← data.base; THROUGH [0..heraldRef.bandHeight) DO PB.StoreScanLine[lptr]; lptr ← lptr+data.rast; ENDLOOP; yOffset ← yOffset + heraldRef.bandHeight;-- band relative baseline ENDLOOP;--for each band in [0..bandcount) Close[data];--release the band segment };--ShowBands Render: PROC [data: Data] = { rect: BOOLEAN ← objectRef.flags.rect; type: BFormat.Type ← objectRef.flags.type; y, yTop, height, bandWidth, grayWord: CARDINAL; longline: LONG POINTER TO WORD; run: POINTER TO BFormat.Run; runBump: CARDINAL; black: CARDINAL = LAST[CARDINAL]; white: CARDINAL = 0; y ← yTop ← objectRef.yStart-yOffset; height ← objectRef.height; bandWidth ← heraldRef.bandWidth; -- pointer to beginning of first destination scan line longline ← data.base + Inline.LongMult[yTop, data.rast]; run ← LOOPHOLE[runsRef]; -- pointer to first Run -- rectangles use the same Run for each line -- trapezoids have a new Run for each line runBump ← IF rect THEN 0 ELSE BFormat.runSize; SELECT type FROM all0, all1 => { -- constant white or black grayWord ← IF type = all1 THEN black ELSE white; bbPointer↑ ← [ ptrs: short, pad: 0, sourcealt: FALSE, destalt: TRUE, sourcetype: gray, function: replace, unused: Inline.HighHalf[data.base], --NOT REALLY UNUSED dbca: Inline.LowHalf[data.base], dbmr: bandWidth, -- destination raster width(in words) dlx: run.xmin, -- destination left x dty: y, -- destination top y dw: run.xmax-run.xmin,--may be zero !! block width in bits dh: height, -- block height in scanlines may be zero !! sbca: NIL, -- no source sbmr: 0, -- source raster width(in words) slx: 0, -- source left x sty: 0, -- source top y gray0: grayWord, -- four words of "gray" gray1: grayWord, gray2: grayWord, gray3: grayWord, slbca: NIL, -- ignored dlbca: NIL]; -- ignored IF rect THEN BB.BITBLT[bbPointer] --BLT a rectangle in one shot!! ELSE {--BLT a trapezoid one line at a time bbPointer.dh ← 1; THROUGH [0..height) DO bbPointer.dlx ← run.xmin; -- destination left x bbPointer.dty ← y; -- destination top y bbPointer.dw ← run.xmax-run.xmin; --may be zero !! block width bits BB.BITBLT[bbPointer]; run ← run + runBump; y ← y+1;--index of next line ENDLOOP; };--BLT a trapezoid one line at a time }; -- constant white or black bits => { -- specified bits (opaque), fetch each line and BLT it bbPointer↑ ← [ ptrs: short, pad: 0, sourcealt: FALSE, destalt: TRUE, sourcetype: block, function: replace, unused: Inline.HighHalf[data.base], --NOT REALLY UNUSED dbca: Inline.LowHalf[data.base], dbmr: bandWidth, -- destination raster width(in words) dlx: 0, -- destination left x dty: 0, -- destination top y dw: 0, -- block width in bits dh: 1, -- block height in scanlines sbca: lineRef, sbmr: 0, -- source raster width(UNUSED for height=1) slx: 0, -- source left x sty: 0, -- source top y slbca: NIL, -- ignored dlbca: NIL]; -- ignored THROUGH [0..height) DO--BLT either trap or rect one line at a time [] ← BStream.GetBand[lineRef, (run.xmax-run.xmin+15)/bitsPerWord];--may fetch 0 words bbPointer.dlx ← run.xmin; -- destination left x bbPointer.dty ← y; -- destination top y bbPointer.dw ← run.xmax-run.xmin; -- block width in bits BB.BITBLT[bbPointer]; run ← run + runBump; y ← y + 1;--index of start of next line ENDLOOP; };-- specified bits (opaque), fetch each line and BLT it brick => { -- construct each line and BLT it L, p, hx, hy: CARDINAL; D: INTEGER ← 0; L ← tBrick.L; p ← tBrick.p; D ← tBrick.D; y ← objectRef.yStart; -- absolute, not relative y THROUGH [0..height) DO hy ← y MOD p; hx ← Inline.LowHalf[Modd[(run.xmin - LONG[D]*(y/p)), L]]; MesaBrickBLT.BrickBLT[bbptr: bbPointer, tBrick: tBrick, destLine: longline, hx: hx, hy: hy, xmin: run.xmin, xmax: run.xmax, lineBuffer: lineRef]; run ← run + runBump; y ← y+1;--index of start of next line absolute longline ← longline + bandWidth; ENDLOOP; };-- construct each line and BLT it ENDCASE => ERROR; };--Render --START CODE FOR MesaBandImageImpl uz: MDSZone; data: Data ← NIL; yOffset: CARDINAL ← 0; -- global buffering requiring POINTERS heraldRef: BFormat.HeraldRef; heraldSizeX2: CARDINAL ← 2*BFormat.heraldObjectSize; objectRef: BFormat.ObjectRef; zeroWord: CARDINAL ← 0; longZAddress: LONG POINTER ← LONG[@zeroWord]; -- see SpaceZero TBrick: TYPE = RECORD[SEQUENCE COMPUTED CARDINAL OF WORD];--buffer for tBrick words coming from stream maxTBrick: CARDINAL = 400+BFormat.tBrickSize;--6400 bits maximum in a tBrick for now TBrickPtr: TYPE = POINTER TO TBrick; brickBuffer: TBrickPtr; tBrick: BFormat.TBrickRef; RunsBuffer: TYPE = RECORD[SEQUENCE COMPUTED CARDINAL OF BFormat.Run]; RunsRef: TYPE = POINTER TO RunsBuffer; runsRef: RunsRef ← NIL; -- initialized by InitBands runsIndex: CARDINAL ← 0; -- runs buffer index maxL: CARDINAL = 2000;--longest permitted L for a thresholded brick maxLx2: CARDINAL = maxL*2;--longest permitted L for a thresholded brick times 2 lineRef: BFormat.LineRef ← NIL; -- initialized by InitBands lineIndex: CARDINAL ← 0;-- Scanline bit index BBTable: BB.BBTableSpace; bbPointer: BB.BBptr; DZ.InitializeZones[]; uz ← DZ.SystemZone[]; heraldRef ← uz.NEW[BFormat.HeraldObject]; objectRef ← uz.NEW[BFormat.Object[1]]; brickBuffer ← uz.NEW[TBrick[maxTBrick]]; bbPointer ← MesaBrickBLT.InitializeBrickBLT[@BBTable]; --fix up tBrick from brickBuffer tBrick ← LOOPHOLE[brickBuffer];--common storage covering tBHead+brickBuffer brickBuffer ← brickBuffer+BFormat.tBrickSize; }. LOG March 11, 1982 changed everything to SHORT POINTERS March 30, 1982 changed everything to use Assert