CDBWVersatecImpl.mesa
Copyright © 1983, 1985 by Xerox Corporation. All rights reserved.
A package to output a ChipnDale design for the Versatec plotter in Oliver format. That format is defined thus:
Bytes 0, 1 (high-order first):
The number of bits per Versatec scan line (probably must be divisible by 4).
Byte j:
Two four-bit nibbles. The high-order nibble tells how many times to repeat the low-order nibble in the output bit stream. A data byte may not carry from one scan line to the next.
N. B. This is not a very economical format. You should be able at least to duplicate previous scan lines.
written by E. McCreight, August 1, 1983 2:00 PM
Last Edited by: McCreight, November 23, 1983 4:58 pm
Last Edited by: Jacobi, October 27, 1983 12:36 pm
Last Edited by: Jacobi, April 11, 1985 3:20:50 pm PST
DIRECTORY
Atom,
CD,
CDApplications,
CDBasics,
CDCallSpecific,
CDViewer,
CDEvents,
CDExtras,
CDIO,
CDMenus,
CDOps,
CDProperties,
CDSequencer,
CornerStitching,
FS,
Graphics,
GraphicsOps,
Menus,
IO,
Process,
Real,
Rope,
STPStreams,
TerminalIO,
VFonts,
ViewerClasses,
ViewerOps,
ViewerSpecs;
CDBWVersatecImpl: CEDAR MONITOR
IMPORTS Atom, CD, CDApplications, CDBasics, CDCallSpecific, CDEvents, CDExtras, CDIO, CDMenus, CDViewer, CDOps, CDProperties, CDSequencer, CornerStitching, FS, Graphics, GraphicsOps, IO, Menus, Process, Real, STPStreams, TerminalIO, VFonts, ViewerOps
EXPORTS =
BEGIN
maxScanLineWidth: CARDINAL = 7040; -- the wide-bed Versatec
scanLineWidth: CARDINAL ← maxScanLineWidth;
maxPatchHeight: CARDINAL = 144; -- fits in 64k
stippleRepeat: CARDINAL = 16;
Nibble: TYPE = [0..16);
ScanLine: TYPE = PACKED ARRAY [0..0) OF WORD;
ScanLineInNibbles: TYPE = PACKED ARRAY [0..0) OF Nibble;
CodedScanLine: TYPE = RECORD [
codeWordCount: CARDINAL ← 0,
codeWords: REF CodeWords ];
CodeWords: TYPE = PACKED ARRAY [0..maxScanLineWidth) OF CodeWord;
CodeWord: TYPE = MACHINE DEPENDENT RECORD [
repeats (0: 0..3): [1..16],
pattern (0: 4..7): Nibble];
textures: ARRAY CD.Layer OF REF GraphicsOps.Texture ← ALL[NIL];
outLine: BOOLTRUE;
skipLayers: BOOLFALSE;
allBlack: BOOLFALSE;
handleSignalNames: BOOLTRUE;
PlotStateRef: TYPE = REF PlotState;
PlotState: TYPE = RECORD [
text: REF CornerStitching.Tesselation ← NIL,
tes: ARRAY CD.Layer OF REF CornerStitching.Tesselation ← ALL[NIL],
bitmap: GraphicsOps.BitmapRef ← NIL,
vPatch, context: Graphics.Context ← NIL,
scale: REAL ← 1.0, -- pixels per CD.DesignNumber
totalPlotClip, bandClip: CD.DesignRect ← [0, 0, 0, 0],
rectangles in design space touching all geometry in the plot, or this band
texture: GraphicsOps.Texture ← ALL[0]
];
currentFlavor: ViewerClasses.ViewerFlavor = $ChipndaleVersatecPlot;
Init: ENTRY PROC ~ {
menu: Menus.Menu = Menus.CreateMenu[];
Menus.AppendMenuEntry[menu: menu,
entry: Menus.CreateEntry[name: "AbortPlot", proc: AbortProc, guarded: TRUE]];
CDEvents.RegisterEventProc[$Abort, AbortEvent];
ViewerOps.RegisterViewerClass[flavor: currentFlavor,
class: NEW[ViewerClasses.ViewerClassRec ← [paint: PaintVersatecStripe, menu: menu]]];
CDSequencer.ImplementCommand[a: $VPlotLocal, p: PlotDesignToLocalFile, queue: doQueue];
CDSequencer.ImplementCommand[a: $VPlotPlotter, p: PlotDesignToPlotter, queue: doQueue];
CDSequencer.ImplementCommand[a: $VPlot, p: PlotDesignToAny, queue: doQueue];
CDSequencer.ImplementCommand[a: $VersatecBWPlot, p: PlotDesignToAny, queue: doQueue];
CDMenus.CreateEntry[menu: $HardCopyMenu, entry: "BW Versatec Plot", key: $VersatecBWPlot];
signalFont ← VFonts.GraphicsFont[VFonts.EstablishFont[family: "Helvetica", size: 18, bold: TRUE]];
TerminalIO.WriteRope["ChipNDale BW Versatec plotter loaded\n"];
TerminalIO.WriteRope[" ..use the hardcopy command for plotting..\n"];
};
PlotDesignToAny: ENTRY PROC [ c: CDSequencer.Command ] =
BEGIN ENABLE UNWIND => NULL;
n: CARDINAL ← TerminalIO.RequestSelection[
label: "Versatec Plot",
choice: LIST[" plotter", " local", " read name"]
];
SELECT n FROM
1 => PlotDesign[c: c, to: plotter];
2 => PlotDesign[c: c, to: localFile];
3 => PlotDesign[c: c, to: requestFilename];
ENDCASE => TerminalIO.WriteRope["skipped\n"];
END;
PlotDesignToLocalFile: ENTRY PROC [ c: CDSequencer.Command ] =
BEGIN ENABLE UNWIND => NULL;
PlotDesign[c: c, to: localFile];
END;
PlotDesignToPlotter: ENTRY PROC [ c: CDSequencer.Command ] =
BEGIN ENABLE UNWIND => NULL;
PlotDesign[c: c, to: plotter];
END;
signalFont: Graphics.FontRef ← NIL;
viewer: ViewerClasses.Viewer ← NIL;
plotter: Rope.ROPE ← "vice";
plotFileToSpool: Rope.ROPE ← "[vice]<sysdir>plot.bits";
plotFileOnPlotter: Rope.ROPE ← "<sysdir>plot.bits";
plotFileOnLocalMachine: Rope.ROPE ← "///chipndale/tem/plot.bits";
latestPlotFile: Rope.ROPENIL;
spoolToPlotter: BOOLTRUE;
abortPlot: BOOLFALSE;
designIfAbort: CD.Design ← NIL;
AssignTextures: PROC [usedLayers: REF PACKED ARRAY CD.Layer OF BOOL] =
BEGIN
IF allBlack THEN {
black: REF GraphicsOps.Texture ← NEW[GraphicsOps.Texture←ALL[0FFH]];
FOR l: CD.Layer IN CD.Layer DO -- assign textures to used layers
textures[l] ← black;
ENDLOOP;
}
ELSE {
textureNo: CARDINAL ← 0;
FOR l: CD.Layer IN CD.Layer DO -- assign textures to used layers
IF usedLayers[l] THEN {
textures[l] ← Texture[textureNo];
textureNo ← textureNo+1
}
ELSE textures[l] ← NIL;
ENDLOOP;
}
END;
PlotDesign: INTERNAL PROC [ c: CDSequencer.Command, to: {localFile, plotter, requestFilename}] =
BEGIN
s: IO.STREAMNIL;
plotClip: CD.DesignRect;
strips: [1..100];
IF ~outLine OR skipLayers OR allBlack OR ~handleSignalNames THEN
TerminalIO.WriteRope["**WARNING, colors set up different from default\n"];
SELECT TerminalIO.RequestSelection["Plot", LIST["complete design", "rectangle"]] FROM
2 => {
plotClip ← CDBasics.ToRect[c.pos, c.sPos];
TerminalIO.WriteRope["plot rectangle\n"];
};
ENDCASE => {
plotClip ← CDExtras.BoundingBox[c.design];
TerminalIO.WriteRope["plot all\n"];
};
strips ← TerminalIO.RequestInt["How many vertical strips in the plot? "];
BEGIN ENABLE { -- for ERRORs
UNWIND => {s ← AbortFile[s]; TerminalIO.WriteRope[" ** plot aborted ** "]};
};
design: CD.Design = c.design;
dr: CD.DrawRef = CD.CreateDrawRef[design];
scale: REAL = MIN[32.0/CD.lambda, (REAL[scanLineWidth]+REAL[scanLineWidth-100]*(strips-1))/(plotClip.x2-plotClip.x1)];
---Center the x range of the selected area of the design on the plotter bed, with at most 32 pixels per lambda. If multiple strips are called for, overlap adjacent ones by 100 pixels.
patchHeight: CARDINAL = stippleRepeat*((MIN[maxPatchHeight, CARDINAL[Real.Fix[50*CD.lambda*scale]]]+stippleRepeat-1)/stippleRepeat);
--divisible by stippleRepeat, so that textures work out
bitmap: GraphicsOps.BitmapRef = GraphicsOps.NewBitmap[width: scanLineWidth, height: patchHeight];
ps: PlotStateRef = NEW[ PlotState ← [
text: CornerStitching.NewTesselation[],
scale: scale,
totalPlotClip: plotClip,
bitmap: bitmap,
vPatch: GraphicsOps.NewContextFromBitmap[bitmap]] ];
usedLayers: REF PACKED ARRAY CD.Layer OF BOOLNIL;
abortPlot ← FALSE;
designIfAbort ← design;
TerminalIO.WriteRope["Starting Versatec plot "];
TRUSTED {Process.SetPriority[Process.priorityBackground]};
viewer ← ViewerOps.FindViewer["Versatec Stripe"];
IF viewer # NIL AND viewer.class.flavor # currentFlavor THEN
{ViewerOps.DestroyViewer[viewer]; viewer ← NIL};
IF viewer=NIL THEN
BEGIN
viewer ← ViewerOps.CreateViewer[flavor: currentFlavor,
info: [name: "Versatec Stripe", iconic: FALSE, openHeight: patchHeight+ViewerSpecs.menuHeight]];
END;
viewer.data ← ps;
dr.minimalSize ← 0;
dr.drawRect ← dr.saveRect ← NoteLayer;
dr.contextFilter ← NEW[CD.ContextFilter←ALL[[doit: TRUE]]];
dr.drawContext ← CheckDrawContext;
dr.devicePrivate ← usedLayers;
dr.interestClip ← CDBasics.universe;
dr.devicePrivate ← usedLayers ← NEW[PACKED ARRAY CD.Layer OF BOOLALL[FALSE]];
CDOps.DrawDesign[design, dr]; -- mark used layers
AssignTextures[usedLayers];
dr.drawRect ← dr.saveRect ← NoteRectangle;
dr.contextFilter ← NIL;
dr.devicePrivate ← ps;
SELECT to FROM
localFile =>
BEGIN
TerminalIO.WriteRope["onto """];
s ← FS.StreamOpen[plotFileOnLocalMachine, create];
TerminalIO.WriteRope[plotFileOnLocalMachine];
TerminalIO.WriteRope[""""];
s.SetLength[0];
latestPlotFile ← plotFileOnLocalMachine;
END;
requestFilename =>
BEGIN
r: Rope.ROPE ← CDIO.MakeName[TerminalIO.RequestRope["to file ? > "], "bits"];
TerminalIO.WriteRope["onto """];
s ← FS.StreamOpen[r, create];
TerminalIO.WriteRope[r];
TerminalIO.WriteRope[""""];
s.SetLength[0];
latestPlotFile ← r;
END;
plotter =>
BEGIN
TerminalIO.WriteRope["onto plotter "];
[self: s] ← STPStreams.OpenSTP[host: plotter, fileName: plotFileOnPlotter, accessOptions: create];
latestPlotFile ← NIL;
END;
ENDCASE => ERROR;
TRUSTED {
s.PutChar[LOOPHOLE[scanLineWidth/256, CHARACTER]];
s.PutChar[LOOPHOLE[scanLineWidth MOD 256]];
send the length of a scan line to the Versatec
};
IF handleSignalNames THEN {
TerminalIO.WriteRope["\n.. found "];
TerminalIO.WriteInt[CDCallSpecific.CallForAll[design: design, whatElse: LookForSignalName, x: ps]];
TerminalIO.WriteRope[" top-layer signal names "];
};
SendWhiteBar[s: s];
SendBlackBar[s: s];
FOR strip: INT IN [0..strips) DO
clip: CD.DesignRect = [
x1: plotClip.x1+strip*((plotClip.x2-plotClip.x1)/strips),
y1: plotClip.y1,
x2: plotClip.x1+(strip+1)*((plotClip.x2-plotClip.x1)/strips)+Real.Fix[100./scale]+1,
y2: plotClip.y2];
FOR topLine: INT ← 0, topLine+patchHeight WHILE topLine<Real.Fix[scale*(clip.y2-clip.y1)] DO
x, y, x1, y1, x2, y2: REAL;
dc: CD.DesignRect;
IF abortPlot THEN GOTO AbortPlot;
[] ← ps.vPatch.SetPaintMode[opaque];
ps.vPatch.SetColor[Graphics.white];
ps.vPatch.DrawBox[[xmin: 0, ymin: 0, xmax: scanLineWidth, ymax: patchHeight]];
clear the bitmap
[] ← ps.vPatch.SetPaintMode[transparent];
ps.vPatch.SetColor[Graphics.black];
ps.context ← ps.vPatch.CopyContext[];
ps.context.Scale[sx: scale, sy: scale];
[dx: x, dy: y] ← Graphics.Map[sc: ps.vPatch, dc: ps.context,
sx: scanLineWidth/2, sy: topLine+patchHeight-1];
ps.context.Translate[tx: x-(clip.x2+clip.x1)/2, ty: y-clip.y2];
ps.context.ClipBox[box: [xmin: clip.x1, ymin: clip.y1, xmax: clip.x2, ymax: clip.y2]];
clip to the user-specified design rectangle
[dx: x1, dy: y1] ← Graphics.Map[sc: ps.vPatch, dc: ps.context, sx: -1, sy: -1];
[dx: x2, dy: y2] ← Graphics.Map[sc: ps.vPatch, dc: ps.context,
sx: scanLineWidth, sy: patchHeight];
dc ← CDBasics.NormalizeRect[[x1: Real.Fix[x1], y1: Real.Fix[y1], x2: Real.Fix[x2], y2: Real.Fix[y2]]];
ps.bandClip ← dr.interestClip ← [x1: MAX[plotClip.x1, dc.x1-1], y1: MAX[plotClip.y1, dc.y1-1], x2: MIN[plotClip.x2, dc.x2+1], y2: MIN[plotClip.y2, dc.y2+1]];
rectangle in design space that ChipNDale can use to clip its recursive drawing
CDViewer.ShowArrow[design: design,
pos: [x: (dr.interestClip.x1+dr.interestClip.x2)/2, y: (dr.interestClip.y1+dr.interestClip.y2)/2]];
FOR l: CD.Layer IN CD.Layer DO
IF ps.tes[l]#NIL THEN CornerStitching.ChangeRect[plane: ps.tes[l], rect: CDBasics.universe, newValue: NIL];
ENDLOOP;
CDOps.DrawDesign[design, dr]; -- build tesselations of the relevant design rectangle
AnalyzeTesselations[ps];
[] ← ps.vPatch.SetPaintMode[opaque];
[] ← ps.text.EnumerateArea[rect: ps.totalPlotClip, perTile: PaintASignalName, data: ps];
ViewerOps.PaintViewer[viewer: viewer, hint: all, clearClient: topLine=0];
for debugging and to pacify the user
SendBitmap[s: s, bitmap: ps.bitmap];
s.Flush[];
TerminalIO.WriteRope["."];
ENDLOOP;
TerminalIO.WriteRope["*"];
SendBlackBar[s: s];
ENDLOOP;
SendWhiteBar[s: s];
s.Close[];
IF to # plotter AND spoolToPlotter THEN SpoolFileToPlotter[latestPlotFile];
designIfAbort ← NIL;
TerminalIO.WriteRope["finished\n"];
EXITS
AbortPlot => {s ← AbortFile[s]; TerminalIO.WriteRope[" ** plot aborted ** "]; abortPlot ← FALSE};
END;
END;
CheckDrawContext: PROC [pr: CD.DrawRef, proc: CD.DrawContextLayerProc, ob: CD.ObPtr, pos: CD.DesignPosition, orient: CD.Orientation, layer: CD.Layer] =
BEGIN
IF pr.contextFilter#NIL AND pr.contextFilter[layer].doit THEN {
pr.contextFilter[layer].doit ← FALSE;
TerminalIO.WriteRope[" "];
TerminalIO.WriteRope[CDOps.Info[ob]];
TerminalIO.WriteRope[" (and maybe others) is not rectilinear and will not appear on plot.\n"];
}
END;
NoteLayer: PROC [ r: CD.DesignRect, l: CD.Layer, pr: CD.DrawRef ] =
BEGIN
ps: REF PACKED ARRAY CD.Layer OF BOOL = NARROW[pr.devicePrivate];
ps[l] ← TRUE;
END;
NoteRectangle: PROC [ r: CD.DesignRect, l: CD.Layer, pr: CD.DrawRef ] =
BEGIN
ps: PlotStateRef = NARROW[pr.devicePrivate];
IF CDBasics.NonEmpty[r] THEN {
IF ps.tes[l]=NIL THEN {
IF skipLayers AND
CDProperties.GetPropFromLayer[l, $DrawMeOnBWVersatec]#$DrawMeOnBWVersatec THEN RETURN;
ps.tes[l] ← CornerStitching.NewTesselation[];
};
ps.tes[l].ChangeRect[rect: r, newValue: $covered];
};
END;
AnalyzeTesselations: PROC [ ps: PlotStateRef ] =
BEGIN
FOR l: CD.Layer IN CD.Layer DO
IF ps.tes[l]#NIL THEN {
ps.texture ← textures[l]^;
[] ← ps.tes[l].EnumerateArea[rect: ps.bandClip, perTile: ProcessTile, data: ps, backgroundValue: $none];
};
ENDLOOP;
END;
ProcessTile: PROCEDURE [tile: CornerStitching.TilePtr, data: REF ANY] =
-- CornerStitching.PerTileProc --
BEGIN -- only called on covered tiles
t: CornerStitching.TilePtr;
ps: PlotStateRef = NARROW[data];
tileValue: REF = tile.Value;
IF tileValue = $covered THEN {
r: CD.DesignRect = tile.Area;
GraphicsOps.DrawTexturedBox[self: ps.context, box: [xmin: r.x1, ymin: r.y1, xmax: r.x2, ymax: r.y2], texture: ps.texture];
};
IF outLine THEN {
--Put lines at boundaries with regions of other color
FOR t ← tile.NEastNeighbour, t.WSouthNeighbour WHILE tile.SouthEdge<t.NorthEdge DO
--going south along east edge of tile
IF t.Value#tileValue THEN {
ps.context.SetCP[x: tile.EastEdge, y: MAX[tile.SouthEdge, t.SouthEdge]];
ps.context.DrawTo[x: tile.EastEdge, y: MIN[tile.NorthEdge, t.NorthEdge]];
};
ENDLOOP;
FOR t ← tile.ENorthNeighbour, t.SWestNeighbour WHILE tile.WestEdge<t.EastEdge DO
--going west along north edge of tile
IF t.Value#tileValue THEN {
ps.context.SetCP[x: MAX[tile.WestEdge, t.WestEdge], y: tile.NorthEdge];
ps.context.DrawTo[x: MIN[tile.EastEdge, t.EastEdge], y: tile.NorthEdge];
};
ENDLOOP;
};
END;
SignalValueRef: TYPE = REF SignalValue;
SignalValue: TYPE = RECORD [s: Rope.ROPE];
LookForSignalName: PROC [ design: CD.Design, aptr: CD.ApplicationPtr, x: REF ] RETURNS [done: BOOLTRUE, removeMe: BOOLFALSE, include: CD.ApplicationList←NIL,
repaintMe: BOOLFALSE, repaintInclude: BOOLFALSE] -- CDCallSpecific.CallProc -- =
BEGIN
This area needs considerable improvement. The ultimate goal is to find a place to put the signal name where it will not be confused with any other geometry (than the named piece, or continuations on the same layer) or signal name.
GetSignalName: PROC [signal: REF] RETURNS [s: Rope.ROPE] =
BEGIN
WITH signal SELECT FROM
atom: ATOM => s ← Atom.GetPName[atom];
rope: Rope.ROPE => s ← rope;
ENDCASE => s ← "?";
END;
ps: PlotStateRef = NARROW[x];
r: CD.DesignRect = CDBasics.Intersection[ps.totalPlotClip, CDApplications.ARectO[aptr]];
signal: REF = CDProperties.GetProp[from: aptr, prop: $SignalName];
IF signal # NIL AND CDBasics.NonEmpty[r] THEN
BEGIN
signalValue: SignalValueRef = NEW[SignalValue ← [s: GetSignalName[signal]]];
others: LIST OF REF CornerStitching.Region = NARROW[ps.text.EnumerateArea[rect: r]];
ps.text.ChangeRect[rect: r, newValue: signalValue];
FOR other: LIST OF REF CornerStitching.Region ← others, other.rest WHILE other#NIL DO
ps.text.ChangeRect[rect: other.first.rect, newValue: other.first.value];
ENDLOOP;
END
ELSE done ← FALSE;
END;
PaintASignalName: PROC [tile: CornerStitching.TilePtr, data: REF ANY] =
CornerStitching.PerTileProc --
BEGIN
ps: PlotStateRef = NARROW[data];
textContext: Graphics.Context = ps.vPatch.CopyContext[];
signalValue: SignalValueRef = NARROW[tile.Value[]];
dx, dy, xmin, xmax, ymin, ymax: REAL;
r: CD.DesignRect = CDBasics.Intersection[tile.Area, ps.totalPlotClip];
ctr: CD.DesignPosition = Center[r];
[dx: dx, dy: dy] ← Graphics.Map[sc: ps.context, dc: ps.vPatch,
sx: ctr.x, sy: ctr.y];
[xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax] ← Graphics.RopeBox[font: signalFont, rope: signalValue.s];
textContext.Translate[tx: dx-(xmax+xmin)/2, ty: dy-(ymax+ymin)/2]; -- centers the text in r
IF ((xmax-xmin)>(ymax-ymin)) # ((r.x2-r.x1)>(r.y2-r.y1)) THEN
textContext.Rotate[270];
textContext.SetColor[Graphics.white];
textContext.DrawBox[[xmin: -2, ymin: -2, xmax: xmax-xmin+2, ymax: ymax-ymin+2]];
leave a two-scan-line white patch all around
textContext.SetColor[Graphics.black];
textContext.SetCP[x: 0, y: 0];
textContext.DrawRope[rope: signalValue.s, font: signalFont];
END;
Center: PROC [ r: CD.Rect ] RETURNS [ CD.Position ] =
{RETURN[[x: (r.x1+r.x2)/2, y: (r.y1+r.y2)/2]]};
SendWhiteBar: PROC [ s: IO.STREAM, lines: CARDINAL ← 40 ] =
{SendBar[s, 0, lines]};
SendBlackBar: PROC [ s: IO.STREAM, lines: CARDINAL ← 20 ] =
{SendBar[s, 15, lines]};
SendBar: PROC [ s: IO.STREAM, pattern: Nibble, lines: CARDINAL ] =
BEGIN
scanLineNibbles: CARDINAL = scanLineWidth/4;
FOR j: CARDINAL IN [0..lines) DO
FOR i: CARDINAL IN [0..(scanLineNibbles+15)/16) DO
TRUSTED {s.PutChar[LOOPHOLE[CodeWord[repeats: MIN[16, scanLineNibbles-16*i], pattern: pattern]]]};
ENDLOOP;
ENDLOOP;
END;
SendBitmap: PROC [ s: IO.STREAM, bitmap: GraphicsOps.BitmapRef ] =
BEGIN
csl: REF CodedScanLine = NEW[CodedScanLine ← [codeWords: NEW[CodeWords]]];
FOR i: CARDINAL IN [0..bitmap.height) DO -- send to the Versatec
TRUSTED {
EncodeScanLine[sl: LOOPHOLE[LOOPHOLE[bitmap.base, INT]+INT[bitmap.raster]*i, LONG POINTER TO ScanLine], bitWidth: bitmap.width, csl: csl];
s.UnsafePutBlock[[base: LOOPHOLE[csl.codeWords], startIndex: 0,
count: csl.codeWordCount]];
}
ENDLOOP;
END;
EncodeScanLine: PROC [ sl: LONG POINTER TO ScanLine, bitWidth: CARDINAL, csl: REF CodedScanLine ] =
TRUSTED BEGIN
size: CARDINAL ← 0;
scanLineInNibbles: LONG POINTER TO ScanLineInNibbles = LOOPHOLE[sl];
scanLineNibbles: CARDINAL = (bitWidth+3)/4;
i: CARDINAL ← 0;
WHILE i<scanLineNibbles DO
pattern: Nibble = scanLineInNibbles[i];
j: CARDINAL ← i+1;
limit: CARDINALMIN[scanLineNibbles, i+16];
WHILE j<limit DO
IF scanLineInNibbles[j]#pattern THEN EXIT;
j ← j+1;
ENDLOOP;
csl.codeWords[size] ← [repeats: j-i, pattern: pattern];
size ← size+1;
i ← j;
ENDLOOP;
csl.codeWordCount ← size;
END;
Texture: PROC [ index: CARDINAL ] RETURNS [ REF GraphicsOps.Texture ] =
BEGIN
t: REF GraphicsOps.Texture ← NEW[GraphicsOps.Texture];
FOR i: [0..16) IN [0..16) DO
Stipple: TYPE = ARRAY [0..4) OF [0..16);
row: [0..4) = i MOD 4;
t[i] ← (4096+256+16+1)*(SELECT index FROM
0 => Stipple[01H, 02H, 04H, 08H],
1 => Stipple[04H, 02H, 01H, 08H],
2 => Stipple[00H, 0AH, 00H, 0AH],
3 => Stipple[08H, 00H, 08H, 00H],
4 => Stipple[0AH, 00H, 00H, 00H],
5 => Stipple[08H, 00H, 02H, 00H],
6 => Stipple[00H, 01H, 00H, 04H],
7 => Stipple[04H, 04H, 00H, 00H],
8 => Stipple[00H, 00H, 00H, 03H],
ENDCASE => Stipple[0FH, 0FH, 0FH, 0FH])[row];
ENDLOOP;
RETURN[t];
END;
PaintVersatecStripe: PROC [ self: ViewerClasses.Viewer, context: Graphics.Context,
whatChanged: REF ANY, clear: BOOL ] -- ViewerClasses.PaintProc -- =
BEGIN
ps: PlotStateRef = NARROW[self.data];
x: INT = MAX[INT[0], (ps.bitmap.width-self.cw)/2];
y: INT = MAX[INT[0], (ps.bitmap.height-self.ch)/2];
context.SetCP[self.cw/2, self.ch/2];
GraphicsOps.DrawBitmap[self: context, bitmap: ps.bitmap,
w: MIN[self.cw, ps.bitmap.width], h: MIN[self.ch, ps.bitmap.height],
x: x, y: y, xorigin: ps.bitmap.width/2, yorigin: ps.bitmap.height/2];
END;
AbortProc: Menus.MenuProc = {abortPlot ← TRUE};
AbortEvent: CDEvents.EventProc = {
IF designIfAbort#NIL AND (design=NIL OR design=designIfAbort) THEN {
abortPlot ← TRUE; designIfAbort ← NIL
}
};
AbortFile: PROC [s: IO.STREAM ] RETURNS [ IO.STREAM ] =
{IF s#NIL THEN s.Close[abort: TRUE]; RETURN[NIL]};
SpoolToPlotter: ENTRY PROC = {SpoolFileToPlotter[latestPlotFile]};
SpoolFileToPlotter: PROC [name: Rope.ROPE] =
BEGIN
IF name # NIL THEN {
TerminalIO.WriteRope["spool file """];
TerminalIO.WriteRope[name];
TerminalIO.WriteRope[""".."];
FS.Copy[from: name, to: plotFileToSpool ! FS.Error =>
IF error.group # bug THEN {
TerminalIO.WriteRope[" not done: "];
TerminalIO.WriteRope[error.explanation];
TerminalIO.WriteLn[];
CONTINUE;
}
];
TerminalIO.WriteRope[" spool finished\n"];
};
END;
Module START code...
Init[];
END. -- of VersatecImpl