CDColorVersatecImpl.mesa YOU'L FIND INTERESTING PLACES BY LOOKING FOR "???"
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, May 15, 1984 2:37:12 pm PDT
Last Edited by: Kimr, June 28, 1984 5:28:47 pm PDT
DIRECTORY
Atom,
CD,
CDApplications,
CDCallSpecific,
CDViewer,
CDExtras,
CDInline,
CDOps,
CDProperties,
CDSequencer,
CornerStitching,
FS,
Graphics,
GraphicsOps,
List,
Menus,
IO,
PDFileFormat,
PDFileWriter,
Process,
Real,
Rope,
TerminalIO,
VFonts,
ViewerClasses,
ViewerSpecs;
CDColorVersatecImpl: CEDAR MONITOR
IMPORTS Atom, CD, -- CDCallSpecific,-- CDViewer, CDInline, CDOps, CDProperties, CDSequencer, CornerStitching, IO, Menus, PDFileWriter, Process, Real, TerminalIO, VFonts
EXPORTS =
BEGIN
Ink: TYPE = PDFileFormat.Toner; -- {black, cyan, magenta, yellow};
ColorLoad: TYPE = ARRAY Ink OF PDFileWriter.LoadReference;
-- a color associated with a level is a collection of textures associated with inks
TexVector: TYPE = ARRAY Ink OF CARDINAL;
-- used to generate LoadReferences through indexes, there are four textures to a color
whiteLoadRef: PDFileWriter.LoadReference ← LAST[PDFileWriter.LoadReference];
-- used to identify tiles without toner
localFile: Rope.ROPE ← "///temp/plot0.pd";
versatec: PDFileFormat.DeviceCode ← last; -- ???
sRes, fRes: CARDINAL ← 200; -- pixels per inch
pdState: PDFileWriter.PDState;
pdx, pdy : CARDINAL ← 0; -- origin of band in pixel coords
cdx, cdy,      -- origin of band in chipndale coords
xoffset, yoffset : INT ← 0; -- offset in transforming bet coord systems
plotScale: REAL; -- scale factor between systems, is negative for y
axis due to reversed direction of increasing values
numStipples: CARDINAL = 27;
-- number of stipple patterns defined by MakeLoadref
texValue: REF ARRAY [0..100] OF PDFileWriter.LoadReference
NEW[ARRAY [0..100] OF PDFileWriter.LoadReference] ;
-- used to make sure that a given texture is only put into the load once
ColorRef: TYPE = REF ColorLoad←NIL;
maxScanLineWidth: CARDINAL = 8000;
the wide-bed Versatec, length in the "fast" direction
scanLineWidth: CARDINAL ← maxScanLineWidth;
imageSSize: REAL ← 0;
imageFSize: CARDINAL ← maxScanLineWidth;
bandSSize: CARDINAL ← 64;
debugging: BOOLFALSE;
numBands, numRectangles: INT ← 0;
PlotStateRef: TYPE = REF PlotState;
PlotState: TYPE = RECORD [
text: REF CornerStitching.Tesselation ← NIL,
tes: ARRAY CD.Level OF REF CornerStitching.Tesselation ← ALL[NIL],
-- enumerates all the rectangles in a given level
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
colorLoads: REF ARRAY CD.Level OF ColorRef
];
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]];
CDSequencer.ImplementCommand[a~$VPlotLocal, p~PlotDesignToLocalFile];
CDSequencer.ImplementCommand[a~$VersatecColorPlot, p~PlotDesignToAny];
CDSequencer.ImplementCommand[a~$VPlot, p~PlotDesignToAny];
signalFont ← VFonts.GraphicsFont[VFonts.EstablishFont[family: "Helvetica", size: 18, bold: TRUE]];
TerminalIO.WriteRope["ChipNDale COLOR Versatec plotter loaded\n"];
};
NewPlotName: PROC [index: INTEGER] RETURNS [name: Rope.ROPE] =
BEGIN
name ← IO.PutFR[ "///temp/plot%d.pd", IO.int[index+1]];
END;
PlotDesignToAny: ENTRY PROC [ c: CDSequencer.Command ] =
BEGIN ENABLE UNWIND => NULL;
n: CARDINAL ← 0;
TerminalIO.WriteRope["Color plot\n"];
p: CARDINAL ← TerminalIO.RequestSelection[
label: "Debugging",
choice: LIST["yes", "no"]
];
SELECT p FROM
1 => debugging ← TRUE;
2 => debugging ← FALSE;
ENDCASE => debugging ← FALSE;
n ← 2;
TerminalIO.RequestSelection[
label: "Versatec Plot",
choice: LIST[" plotter", " local", " read name", " remote"]
];
SELECT n FROM
1 => {
TerminalIO.WriteRope["plotter is not yet implemented\n"];
PlotDesign[c: c, to: plotter]
};
2 => PlotDesign[c: c, to: localFile];
3 => {
TerminalIO.WriteRope[" requestFilename is not yet implemented\n"]
PlotDesign[c: c, to: requestFilename]
};
4 => {
TerminalIO.WriteRope["remote is not yet implemented\n"];
PlotDesign[c: c, to: remoteFile];
};
ENDCASE => TerminalIO.WriteRope["skipped\n"];
END;
PlotDesignToLocalFile: ENTRY PROC [ c: CDSequencer.Command ] =
BEGIN ENABLE UNWIND => NULL;
TerminalIO.WriteRope["Color plot to local file\n"];
PlotDesign[c: c, to: localFile];
END;
PlotDesignToRemoteFile: ENTRY PROC [ c: CDSequencer.Command ] =
BEGIN ENABLE UNWIND => NULL;
TerminalIO.WriteRope["Color plot to remote file\n"];
PlotDesign[c: c, to: remoteFile];
END;
PlotDesignToPlotter: ENTRY PROC [ c: CDSequencer.Command ] =
BEGIN ENABLE UNWIND => NULL;
TerminalIO.WriteRope["Color plot directly to plotter\n"];
PlotDesign[c: c, to: plotter];
END;
signalFont: Graphics.FontRef ← NIL;
viewer: ViewerClasses.Viewer ← NIL;
plotter: Rope.ROPE ← "vice";
plotFileToSpool: Rope.ROPE ← "[vice]<sysdir>plot.pd";
plotFileOnPlotter: Rope.ROPE ← "<sysdir>plot.pd";
plotFileOnLocalMachine: Rope.ROPE ← "plot0.pd";
plotFileOnServer: Rope.ROPE ← "[Luther.alpine]<McCreight.pa>plot.pd";
latestPlotFile: Rope.ROPENIL;
spoolToPlotter: BOOLTRUE;
abortPlot: BOOLFALSE;
PlotDesign: INTERNAL PROC [ c: CDSequencer.Command, to: {localFile, remoteFile, plotter, requestFilename}] =
BEGIN
s: IO.STREAMNIL;
n: INT ← TerminalIO.RequestInt["How many vertical strips? [1..10] "];
strips: INTMAX[1, MIN[10, n]];
BEGIN ENABLE -- for ERRORs
BEGIN
???x.Error =>
BEGIN
TerminalIO.WriteRope[];
GOTO AbortPlot;
END;
UNWIND => {s ← AbortFile[s]; CDViewer.RemoveArrow[design: c.design]; TerminalIO.WriteRope[" ** plot aborted ** "]};
END;
design: CD.Design = c.design;
plotClip: CD.DesignRect = CDInline.ToRect[c.pos, c.sPos];
-- takes the right and left sides of the square outlined by
-- the user and returns normalized rectangle coordinates
dr: CD.DrawRef = CD.NewNullDeviceDrawRef[design];
scale: REALMIN[32.0/CD.lambda, (REAL[scanLineWidth]+REAL[scanLineWidth-150]*(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 150 pixels.
-- total number of pixels in plot = REAL[scanLineWidth]+REAL[scanLineWidth-150]*(strips-1))
-- total width of design = plotClip.x2-plotClip.x1
ps: PlotStateRef = NEW[ PlotState ← [
text: CornerStitching.NewTesselation[],
scale: scale,
totalPlotClip: plotClip,
colorLoads: NEW[ARRAY CD.Level OF ColorRef←ALL[NIL]]
] ];
usedLevels: REF PACKED ARRAY CD.Level OF BOOLNIL;
imageSSize ← (plotClip.y2-plotClip.y1)* scale;
-- length of plot <in slow direction> in pixels
plotScale ← scale;
IF debugging THEN {
TerminalIO.WriteRope[" Scale factor (pixels/design#)*100 --> "];
TerminalIO.WriteInt[Real.RoundLI[plotScale*100]];
TerminalIO.WriteLn[];
};
abortPlot ← FALSE;
TerminalIO.WriteRope["Starting Color Versatec plot "];
TerminalIO.WriteLn[];
TRUSTED {Process.SetPriority[Process.priorityBackground]};
dr.minimalSize ← 0;
dr.drawRect ← dr.saveRect ← NoteLevel;
dr.devicePrivate ← usedLevels;
dr.worldClip ← CDInline.universe;
dr.devicePrivate ← usedLevels ← NEW[PACKED ARRAY CD.Level OF BOOLALL[FALSE]];
CDOps.DrawDesign[design, dr]; -- mark used levels
dr.drawRect ← dr.saveRect ← NoteRectangle;
dr.devicePrivate ← ps;
localFile ← "///temp/plot0.pd";
For each strip in the design
FOR strip: INT IN [0..strips) DO
-- Determine clip rectangle for strip
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[150./scale]+1,
y2: plotClip.y2];
tonerSet: PDFileWriter.TonerSet ← ALL[TRUE];
TerminalIO.WriteRope["Recording strip on file "];
TerminalIO.WriteRope[localFile];
TerminalIO.WriteLn[];
pdState ← PDFileWriter.Create[ fileName: localFile, deviceCode: versatec, sResolution: sRes, fResolution: fRes, imageSSize: Real.RoundC[imageSSize + 1], imageFSize: imageFSize, bandSSize: bandSSize, leftOverMode: FALSE];
ps.colorLoads^ ← ALL[NIL];
numBands ← 0;
numRectangles ← 0;
PDFileWriter.StartImage[pdState: pdState, toners: tonerSet];
For each band in the strip
FOR topLine: INT ← 0, topLine+bandSSize WHILE topLine<imageSSize DO
x1, y1, x2, y2: REAL;
dc: CD.DesignRect;
IF abortPlot THEN GOTO AbortPlot;
-- Determine coordinate transformations
pdx ← 0;
pdy ← topLine;
cdx ← clip.x1;
cdy ← clip.y2 - Real.Fix[topLine*(1./scale)];
xoffset ← pdx - Real.Fix[cdx*scale];
yoffset ← pdy - Real.Fix[cdy*(-1*scale)];
-- (negative scale to account for CD increasing y north, PD increasing y going south)
x1 ← (-1 - xoffset )/scale;
y1 ← ((pdy + bandSSize +1) - yoffset)/(-scale);
x2 ← (scanLineWidth - xoffset)/scale;
y2 ← (pdy - yoffset)/(-scale);
dc ← CDInline.NormalizeRect[[x1: Real.Fix[x1], y1: Real.Fix[y1], x2: Real.Fix[x2], y2: Real.Fix[y2]]] ;
ps.bandClip ← dr.worldClip ← [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
IF debugging THEN {
TerminalIO.WriteLn;
TerminalIO.WriteRope[" pdy: "];
TerminalIO.WriteInt[pdy];
TerminalIO.WriteLn;
TerminalIO.WriteRope[" CD band: "];
TerminalIO.WriteInt[ps.bandClip.x1];
TerminalIO.WriteInt[ps.bandClip.y1];
TerminalIO.WriteInt[ps.bandClip.x2];
TerminalIO.WriteInt[ps.bandClip.y2];
TerminalIO.WriteLn
};
Display current band under consideration to pacify user
CDViewer.ShowArrow[design: design,
pos: [x: (dr.worldClip.x1+dr.worldClip.x2)/2, y: (dr.worldClip.y1+dr.worldClip.y2)/2]];
FOR l: CD.Level IN CD.Level DO
IF ps.tes[l]#NIL THEN
-- clear previous tessalations
CornerStitching.ChangeRect[plane: ps.tes[l], rect: CDInline.universe, newvalue: NIL, checkOldvalue: FALSE];
ENDLOOP;
CDOps.DrawDesign[design, dr]; -- build tesselations of the relevant design rectangle
AnalyzeTesselations[ps];
-- assign each level a texture and draw all the rectangles in the region
TerminalIO.WriteRope["."];
numBands ← numBands + 1;
ENDLOOP; -- for each band in the strip
PDFileWriter.EndPage[pdState];
TerminalIO.WriteRope["*"];
TerminalIO.WriteLn[];
PDFileWriter.Close[pdState];
localFile ← NewPlotName[strip];
ENDLOOP; -- for each strip
TerminalIO.WriteRope[" finished plot(s)\n"];
IF debugging THEN {
TerminalIO.WriteRope["# bands -> "];
TerminalIO.WriteInt[numBands];
TerminalIO.WriteRope[" # rectangles -> "];
TerminalIO.WriteInt[numRectangles];
TerminalIO.WriteLn;
};
CDViewer.RemoveArrow[design: design];
EXITS
AbortPlot => {s ← AbortFile[s]; CDViewer.RemoveArrow[design: c.design]; TerminalIO.WriteRope[" ** plot aborted ** "]; abortPlot ← FALSE};
END; -- enable
END; -- PlotDesign
NoteLevel: PROC [ r: CD.DesignRect, l: CD.Level, pr: CD.DrawRef ] =
BEGIN
ps: REF PACKED ARRAY CD.Level OF BOOL = NARROW[pr.devicePrivate];
ps[l] ← TRUE;
END;
NoteRectangle: PROC [ r: CD.DesignRect, l: CD.Level, pr: CD.DrawRef ] =
BEGIN
ps: PlotStateRef = NARROW[pr.devicePrivate];
IF CDInline.NonEmpty[r] THEN
BEGIN
IF ps.tes[l]=NIL THEN ps.tes[l] ← CornerStitching.NewTesselation[];
ps.tes[l].ChangeRect[rect: r, newvalue: $covered, checkOldvalue: FALSE];
END;
END;
tonerKey: ARRAY [PDFileFormat.Toner] OF ATOM
[$CDxVersatecBlack, $CDxVersatecCyan, $CDxVersatecMagenta, $CDxVersatecYellow];
tonerKey: PROC [toner: PDFileFormat.Toner] RETURNS [ATOM] = INLINE {
RETURN [ SELECT toner FROM
black => $CDxVersatecBlack,
cyan => $CDxVersatecCyan,
magenta => $CDxVersatecMagenta,
yellow => $CDxVersatecYellow,
ENDCASE => $CDxVersatecBlack
]
};
AnalyzeTesselations: PROC [ ps: PlotStateRef ] =
BEGIN
FOR lev: CD.Level IN CD.Level DO
IF ps.tes[lev]#NIL THEN {
IF ps.colorLoads^[lev]=NIL THEN {
tex: REF;
ps.colorLoads^[lev] ← NEW[ColorLoad];
FOR toner: Ink IN Ink DO
tex ← CDProperties.GetPropFromLevel[from: lev, prop: tonerKey[toner]];
ps.colorLoads^[lev][toner] ←
(IF tex = NIL THEN whiteLoadRef ELSE MakeLoadref[tex]);
ENDLOOP;
};
FOR toner: Ink IN Ink DO
IF ps.colorLoads^[lev][toner] = whiteLoadRef THEN
PDFileWriter.SetColorOff[pdState, toner]
ELSE
PDFileWriter.SetColorTile[pdState, toner, ps.colorLoads^[lev][toner], transparent];
ENDLOOP;
[] ← ps.tes[lev].EnumerateArea[
rect: ps.bandClip,
perTile: ProcessTile,
data: ps,
backgroundValue: $none
];
};
ENDLOOP;
END;
ProcessTile: PROCEDURE [tile: CornerStitching.TilePtr, data: REF ANY] RETURNS [REF ANY]
-- CornerStitching.PerTileProc -- =
BEGIN -- only called on covered tiles
rightBound, x1, y1, x2, y2: INT;
pdx1, pdx2, pdy1, pdy2 : CARDINAL;
sSize, fSize : CARDINAL;
t: CornerStitching.TilePtr;
ps: PlotStateRef = NARROW[data];
tileValue: REF = tile.Value;
IF tileValue = $covered THEN
BEGIN
r: CD.DesignRect = tile.Area;
Calculate absolute coords of rectangle here as offset from plot origin
x1 ← Real.RoundLI[xoffset + r.x1*plotScale];
y1 ← Real.RoundLI[yoffset + r.y1*(-plotScale)];
x2 ← Real.RoundLI[xoffset + r.x2*plotScale];
y2 ← Real.RoundLI[yoffset + r.y2*(-plotScale)];
rightBound ← Real.RoundLI[xoffset + ps.bandClip.x2*plotScale];
-- if rectangle is in bandarea, clip and write; otherwise disregard rectangle
IF NOT ((( x1 > rightBound) OR (x2 < 0)) OR
(( y1 < pdy) OR (y2 > MIN[imageSSize, pdy+bandSSize]))) THEN {
pdx1 ← MAX[x1, 0];
pdx2 ← MIN[x2, rightBound, imageFSize];
pdy1 ← MIN[y1, pdy+bandSSize];
pdy2 ← MAX[y2, pdy];
fSize ← pdx2 - pdx1;
sSize ← pdy1 - pdy2;
-- can't have rectangles landing on or over the imageSSize
IF pdy1 >= imageSSize THEN
sSize ← Real.Fix[imageSSize - pdy2] ;
-- disregard rectangles without area
IF ((sSize # 0) AND (fSize # 0)) THEN {
PDFileWriter.MaskRectangle[pdState: pdState, sMin: pdy2, fMin: pdx1, sSize: sSize, fSize: fSize];
TerminalIO.WriteRope["+"];
numRectangles ← numRectangles + 1;
IF debugging THEN {
TerminalIO.WriteRope[" position -> "];
TerminalIO.WriteInt[Real.RoundLI[y1]];
TerminalIO.WriteInt[Real.RoundLI[x1]];
TerminalIO.WriteRope[" size -> "];
TerminalIO.WriteInt[sSize];
TerminalIO.WriteInt[fSize];
TerminalIO.WriteLn;
}
}
}
END;
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
BEGIN
ps.context[black].SetCP[x: tile.EastEdge, y: MAX[tile.SouthEdge, t.SouthEdge]];
ps.context[black].DrawTo[x: tile.EastEdge, y: MIN[tile.NorthEdge, t.NorthEdge]];
END;
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
BEGIN
ps.context[black].SetCP[x: MAX[tile.WestEdge, t.WestEdge], y: tile.NorthEdge];
ps.context[black].DrawTo[x: MIN[tile.EastEdge, t.EastEdge], y: tile.NorthEdge];
END;
ENDLOOP;
RETURN[data];
END;
SignalValueRef: TYPE = REF SignalValue;
SignalValue: TYPE = RECORD [s: Rope.ROPE];
LookForSignalName: PROC [ design: CD.Design, aptr: CD.ApplicationPtr, x: REF ] RETURNS [done: BOOLFALSE, 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 = CDInline.Intersection[ps.totalPlotClip, CDApplications.ApplicationRect[aptr]];
signal: REF = CDProperties.GetProp[from: aptr, prop: $SignalName];
IF signal # NIL AND CDInline.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, checkOldvalue: FALSE];
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, checkOldvalue: FALSE];
ENDLOOP;
END
ELSE done ← FALSE;
END;
PaintASignalName: PROC [tile: CornerStitching.TilePtr, data: REF ANY] RETURNS [REF ANY] -- CornerStitching.PerTileProc -- =
BEGIN
ps: PlotStateRef = NARROW[data];
textContext: Graphics.Context = ps.vPatch[black].CopyContext[];
signalValue: SignalValueRef = NARROW[tile.Value[]];
dx, dy, xmin, xmax, ymin, ymax: REAL;
r: CD.DesignRect = CDInline.Intersection[tile.Area, ps.totalPlotClip];
ctr: CD.DesignPosition = Center[r];
[dx: dx, dy: dy] ← Graphics.Map[sc: ps.context[black], 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];
RETURN[data];
END;
Center: PROC [ r: CD.Rect ] RETURNS [ CD.Position ] =
{RETURN[[x: (r.x1+r.x2)/2, y: (r.y1+r.y2)/2]]};
Stipple16: TYPE = ARRAY[0..16) OF CARDINAL;
Stipple8: TYPE = ARRAY[0..8) OF [0..256);
Stipple4: TYPE = ARRAY[0..4) OF [0..16);
ToTexture: PROC [pattern: REF ANY] RETURNS [texture: Stipple16] =
--tries to convert pattern to a texture stipple
BEGIN
IF pattern=NIL THEN RETURN[Stipple16[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]; -- should not occur
WITH pattern SELECT FROM
s16: REF Stipple16 => texture ← s16^;
s8: REF Stipple8 =>
FOR i: [0..8) IN [0..8) DO
texture[i] ← texture[i+8] ← (256+1)*s8[i];
ENDLOOP;
s4: REF Stipple4 =>
FOR i: [0..4) IN [0..4) DO
texture[i] ← texture[i+4] ← texture[i+8] ← texture[i+12] ← s4[i]*1111H;
ENDLOOP;
ENDCASE => RETURN[Stipple16[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0FFFFH]]; -- error texture
RETURN [texture]
END;
MakeLoadref: PROC [pattern: REF ANY] RETURNS [PDFileWriter.LoadReference] =
TRUSTED BEGIN
loadRef: PDFileWriter.LoadReference;
texture: Stipple16 ← ToTexture[pattern];
loadRef ← PDFileWriter.LoadContiguousColorTile[pdState: pdState, phase: 0, sMin: 0, fMin: 0, sSize: 16, fSize: 16, bitsPtr: @texture];
RETURN[loadRef];
END;
AbortProc: Menus.MenuProc = {abortPlot ← TRUE};
AbortFile: PROC [s: IO.STREAM ] RETURNS [ IO.STREAM ] =
{IF s#NIL THEN s.Close[abort: TRUE]; RETURN[NIL]};
Module START code...
Init[];
END. -- of VersatecImpl