-- File CIFRamtekUtils.mesa
-- Written by Rich Pasco, September, 1981
-- Last updated: December 6, 1981 7:23 PM

DIRECTORY

CIFUtilitiesDefs: FROM "CIFUtilitiesDefs" USING [ScreenParams],
CIFRamtekScanDefs: FROM "CIFRamtekScanDefs" USING
[RamtekScanConvert],
CIFRamtekTypeDefs: FROM "CIFRamtekTypeDefs" USING [Edge,
EdgeRecord, EdgeAngle, HalfTone, ColorStipple],
CIFRamtekUtilsDefs: FROM "CIFRamtekUtilsDefs" USING
[RStripeWidth],
CIFDevicesDefs: FROM "CIFDevicesDefs",
InlineDefs: FROM "InlineDefs" USING[LongCOPY],
Mopcodes: FROM "Mopcodes" USING [zWBL],
SegmentDefs: FROM "SegmentDefs" USING[NewDataSegment, DefaultXMBase,
LongDataSegmentAddress],
SystemDefs: FROM "SystemDefs" USING[AllocateHeapNode, FreeHeapNode],
TrapezoidDefs: FROM "TrapezoidDefs" USING[TrapezoidBlock, TrapezoidBlt],
RamtekDefs: FROM "RamtekDefs" USING [StartRamtekPlot, EndRamtekPlot,
WriteRamtekLine];

CIFRamtekUtils: PROGRAM
IMPORTS CIFUtilitiesDefs, CIFRamtekScanDefs, InlineDefs, SegmentDefs, SystemDefs, TrapezoidDefs, RamtekDefs
EXPORTS CIFRamtekUtilsDefs =

BEGIN OPEN CIFDevicesDefs, CIFUtilitiesDefs, CIFRamtekScanDefs, CIFRamtekTypeDefs, CIFRamtekUtilsDefs, InlineDefs, Mopcodes, SegmentDefs, SystemDefs, TrapezoidDefs, RamtekDefs;

RamtekNextStripe: PUBLIC PROCEDURE =
BEGIN --finish off and output current stripe, and step to next
RamtekScanConvert[VStripeTop, FALSE];
RamtekScanConvert[VStripeTop, TRUE];
RamtekOutStripe[];
RamtekClearStripes[TRUE];
VStripeBottom ← VStripeTop;
VStripeTop ← VStripeTop + VStripeHeight;
END;

OutputStripesUntil: PUBLIC PROCEDURE[y: REAL] =
BEGIN
WHILE y>=VStripeTop DO RamtekNextStripe[]; ENDLOOP;
END;

VersatecMakeEdge: PUBLIC PROCEDURE [xstart,ystart,xend,yend: REAL, up: BOOLEAN]
RETURNS[edge: Edge] =
BEGIN
--make edge of appropriate type
dx: REAL;
dy: REAL ← yend-ystart;
IF dy<=0 THEN RETURN[NIL];
dx ← xend-xstart;
IF dx=0 THEN
BEGIN --make vertical edge
edge ← AllocateVerticalEdge[];
edge↑ ← [
next: ,
xstart: xstart,
ystart: ystart,
yend: yend,
lastouty: ystart,
mate: NIL,
up: up,
flagout: FALSE,
vert: TRUE,
var: vertical[]
];
END
ELSE
BEGIN --make oblique edge
edge ← AllocateObliqueEdge[];
edge↑ ← [
next: ,
xstart: xstart,
ystart: ystart,
yend: yend,
lastouty: ystart,
mate: NIL,
up: up,
flagout: FALSE,
vert: FALSE,
var: oblique[
xend: xend,
slope: dx/dy
]
];
END;
RETURN[edge];
END;

RamtekAllocateStripes: PUBLIC PROCEDURE =
BEGIN
--allocate space for VStripeHeight+1 lines (last one never output, but copied to 1st after buffer output to provide overlap)
vPages: CARDINAL;
[DisplayLongAddress, DisplayWidthWords, ] ← ScreenParams[];
RStripeWidthWords ← (RStripeWidth+15)/16;
RStripeWidthBytes ← RStripeWidthWords*2;
RStripeWords ← RStripeWidthWords*(VStripeHeight+1);
vPages ← (RStripeWords+255)/256;
FOR ink IN [0..4) DO
Stripes[ink] ← LongDataSegmentAddress[NewDataSegment[DefaultXMBase,vPages]];
ENDLOOP;
END;

MakeLongPointer: PROCEDURE[low,high: UNSPECIFIED]
RETURNS[LONG POINTER] = MACHINE CODE
BEGIN --nothing to do-- END;

BreakLongPointer: PROCEDURE[lptr: LONG POINTER]
RETURNS[low,high: UNSPECIFIED] = MACHINE CODE
BEGIN --nothing to do-- END;


RamtekOutStripe: PUBLIC PROCEDURE =
BEGIN
blackAddress: LONG POINTER ← Stripes[0];
cyanAddress: LONG POINTER ← Stripes[1];
magentaAddress: LONG POINTER ← Stripes[2];
yellowAddress: LONG POINTER ← Stripes[3];
displayAddress: LONG POINTER ← DisplayLongAddress;
offset: CARDINAL ← MAX[0,DisplayOffset];
offset ← MIN[RStripeWidthWords-DisplayWidthWords,offset];
THROUGH [1..VStripeHeight] DO
--***copy part to screen for testing
LongCOPY[cyanAddress+offset,DisplayWidthWords,displayAddress];
--***now write to file
WriteRamtekLine[blackAddress, cyanAddress, magentaAddress, yellowAddress, RStripeWidthBytes];
blackAddress ← blackAddress + RStripeWidthWords;
cyanAddress ← cyanAddress + RStripeWidthWords;
magentaAddress ← magentaAddress + RStripeWidthWords;
yellowAddress ← yellowAddress + RStripeWidthWords;
displayAddress ← displayAddress + DisplayWidthWords;
ENDLOOP;
END;

RamtekClearStripes: PUBLIC PROCEDURE[overlap: BOOLEAN] =
--If overlap then copy line number VStripeHeight to line number 0 and
-- clear lines 1..VStripeHeight inclusive, otherwise
-- clear lines 0..VStripeHeight inclusive
BEGIN
first: CARDINAL;
IF overlap THEN
BEGIN
--copy line number VStripeHeight to line number 0
FOR ink IN [0..4) DO
LongCOPY[Stripes[ink] + RStripeWords - RStripeWidthWords,
RStripeWidthWords, Stripes[ink]];
ENDLOOP;
first ← RStripeWidthWords;
END
ELSE first ← 0;
--clear lines first..VStripeHeight inclusive
FOR ink IN [0..4) DO
LongStore[0,Stripes[ink] + first]; --zero in 1st word
LongCOPY[Stripes[ink] + first, RStripeWords-first - 1,
Stripes[ink] + first + 1];
ENDLOOP;
END;

LongStore: PROCEDURE[v: UNSPECIFIED, address: LONG POINTER] = MACHINE CODE
BEGIN zWBL,0; END;

LoadStipple: PUBLIC PROCEDURE[layer:CARDINAL, v0,v1,v2,v3: CARDINAL] =
BEGIN
blacktone, cyantone, magentatone, yellowtone: ColorStipple;
blacktone ← DefineTone[v0];
cyantone ← DefineTone[v1];
magentatone ← DefineTone[v2];
yellowtone ← DefineTone[v3];
Stipple[layer] ← [blacktone,cyantone,magentatone,yellowtone];
END;

DefineTone: PROCEDURE [v:CARDINAL] RETURNS [result: ColorStipple] =
BEGIN
IF v=0
THEN BEGIN
result.nonzero ← FALSE;
result.stipple ← [0,0,0,0];
END
ELSE BEGIN
result.nonzero ← TRUE;
result.stipple[0] ← 52525B * (v MOD 4);
result.stipple[1] ← 52525B * (v/4 MOD 4);
result.stipple[2] ← result.stipple[0];
result.stipple[3] ← result.stipple[1];
END;
END;

AllocateVerticalEdge: PUBLIC PROCEDURE RETURNS[Edge] =
BEGIN
RETURN[AllocateHeapNode[SIZE[vertical EdgeRecord]]];
END;

AllocateObliqueEdge: PUBLIC PROCEDURE RETURNS[Edge] =
BEGIN
RETURN[AllocateHeapNode[SIZE[oblique EdgeRecord]]];
END;

FreeEdge: PUBLIC PROCEDURE[edge: Edge] =
BEGIN
FreeHeapNode[edge];
END;

EdgeLessThan: PUBLIC PROCEDURE[e1,e2: Edge, y: REAL] RETURNS[BOOLEAN] =
BEGIN
--orders up/down within slope within x
x1: REAL ← XatY[e1,y];
x2: REAL ← XatY[e2,y];
RETURN[x1<x2 OR (x1=x2 AND (Slope[e1]<Slope[e2] OR (Slope[e1]=Slope[e2] AND e1.up)))];
END;

XatY: PUBLIC PROCEDURE[edge: Edge, y: REAL] RETURNS[x: REAL] =
BEGIN
RETURN[
WITH e:edge SELECT IF edge.vert THEN vertical ELSE oblique FROM
oblique => --i.e. oblique
SELECT TRUE FROM
y=e.ystart => e.xstart,
y=e.yend => e.xend,
ENDCASE => e.xstart + (y-e.ystart)*e.slope, --must compute from consistent end!
ENDCASE => edge.xstart --i.e. vertical
];
END;

Slope: PROCEDURE[edge: Edge] RETURNS[slope: REAL] = INLINE
BEGIN
RETURN[WITH e:edge SELECT IF edge.vert THEN vertical ELSE oblique FROM
oblique => e.slope,
ENDCASE => 0 --i.e.vertical
];
END;

InitRamtekOut: PUBLIC PROCEDURE[fileName: STRING, height: CARDINAL] =
BEGIN
IF Stripes[0]=NIL THEN RamtekAllocateStripes[];
RamtekClearStripes[FALSE]; --clear overlap line
VStripeBottom ← 0;
VStripeTop ← VStripeHeight;
StartRamtekPlot[fileName, RStripeWidth, height];
END;

FinishRamtekOut: PUBLIC PROCEDURE[y: REAL] =
BEGIN
UNTIL VStripeBottom>y+1 DO --1+ is kludge to make sure it all gets out
RamtekNextStripe[];
ENDLOOP;
RamtekOutStripe[];
EndRamtekPlot[];
END;

HorColorLine: PUBLIC PROCEDURE[xleft,xright,y: REAL, layer: CARDINAL] =
BEGIN
stip: HalfTone ← Stipple[layer];
tb: TrapezoidBlock ← [
ystart: y - VStripeBottom,
yend: y - VStripeBottom,
xsleft: xleft,
xsright: xright,
xeleft: xleft,
xeright: xright,
function: paint,
xbase: ,
xwords: RStripeWidthWords,
texture: @Solid.stipple
];
IF xleft=xright THEN RETURN;
FOR ink IN [0..4) DO
IF stip[ink].nonzero THEN
BEGIN
tb.xbase ← Stripes[ink];
TrapezoidBlt[@tb];
END;
ENDLOOP;
TrapezoidBlt[@tb];
END;

DrawTrap: PUBLIC PROCEDURE[left: Edge, ystart: REAL, right: Edge, yend: REAL, layer: CARDINAL] =
BEGIN --draw left and right edges
stip: HalfTone ← Stipple[layer];
tb: TrapezoidBlock ← [
ystart: ystart - VStripeBottom,
yend: yend - VStripeBottom,
xsleft: ,
xsright: ,
xeleft: ,
xeright: ,
function: paint,
xbase: ,
xwords: RStripeWidthWords,
texture:
];

FOR ink IN [0..4) DO
IF stip[ink].nonzero THEN
BEGIN
tb.xbase ← Stripes[ink];
--left edge
tb.xsleft ← XatY[left,ystart];
tb.xsright ← tb.xsleft;
tb.xeleft ← XatY[left,yend];
tb.xeright ← tb.xeleft;
tb.texture ← @Solid.stipple;
TrapezoidBlt[@tb];
--stipple
tb.xsright ← XatY[right,ystart];
tb.xeright ← XatY[right,yend];
tb.texture ← @stip[ink].stipple;
TrapezoidBlt[@tb];
--right edge
tb.xsleft ← tb.xsright;
tb.xeleft ← tb.xeright;
tb.texture ← @Solid.stipple;
TrapezoidBlt[@tb];
END;
ENDLOOP;
END;

ink: CARDINAL;

Stripes: ARRAY [0..4) OF LONG POINTER ← [NIL, NIL, NIL, NIL]; --full addresses of 4 ramtek bitmap buffers: Black, Cyan, Magenta, Yellow

DisplayLongAddress: LONG POINTER; --full address of display bitmap buffer
DisplayWidthWords: CARDINAL;
DisplayOffset: INTEGER ← 0; --in words - controls what part of VStripe is copied to screen. Set in debugger

VStripeBottom,VStripeTop: REAL; --limits to be mapped onto current stripe
VStripeHeight: CARDINAL = 128; --this MUST be a multiple of 4 for stipple phase to work
--***should be wired to required buffer height
RStripeWidthWords: CARDINAL; --required buffer width in words
RStripeWidthBytes: CARDINAL; --required buffer width in bytes
RStripeWords: CARDINAL;
--required buffer size in words

Blank: ColorStipple ← [nonzero: FALSE, stipple: [0,0,0,0]];
Solid: ColorStipple ← [nonzero: TRUE, stipple: [177777B,177777B,177777B,177777B]];
EvenChk: ColorStipple ← [nonzero: TRUE, stipple: [125252B,052525B,125252B,052525B]];
OddChk: ColorStipple ← [nonzero: TRUE, stipple: [052525B,125252B,052525B,125252B]];


Stipple: ARRAY [0..MaxLENGTHLayerArray) OF HalfTone;
--undef

--Set up default stipples
-- Black, Cyan,Magenta, Yellow
Stipple[0] ← [ Blank, Blank, Blank, Solid];
--implant
Stipple[1] ← [ Blank, OddChk, Blank, OddChk];
--diffusion
Stipple[2] ← [ Blank, Blank,EvenChk, Blank];
--poly
Stipple[3] ← [ Solid, Blank, Blank, Blank];
--contact
Stipple[4] ← [ Blank,EvenChk, Blank, Blank];
--metal
Stipple[5] ← [ Blank, Solid, Blank, Blank];
--buried
Stipple[6] ← [ Blank, Blank, Solid, Solid];
--glass
Stipple[7] ← [ Solid, Solid, Solid, Solid];
--undef


END.