-- 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