-- Straw1.mesa
-- Written by Joe Maleson
-- Last changed by Doug Wyatt, April 8, 1981 1:20 PM

DIRECTORY
AltoFileDefs,
DiscoDefs USING[DiskPosition,TransferBytes],
DisplayListDefs,
GraphicsDefs,
HalftoneDefs,
MiscDefs,
Mopcodes,
PressDefs,
Real USING [RoundI],
RealConvert USING [BcplToIeee],
StrawDefs,
SegmentDefs,
SystemDefs;
Straw1: PROGRAM
IMPORTS DiscoDefs, DisplayListDefs, GraphicsDefs, HalftoneDefs,
MiscDefs, PressDefs, Real, RealConvert, SystemDefs, StrawDefs
EXPORTS StrawDefs =
BEGIN
OPEN DiscoDefs;
maxDataBytes: CARDINAL ← 0;
maxObjCommandSize: CARDINAL = 256; --make larger for complex spline display
KLUDGESegs: CARDINAL ← 0; --modify spline display (show points KSegs..3)
errorVec: ARRAY [0..608) OF INTEGER ← ALL[0];

DoHalftone
: PROCEDURE [pdd: POINTER TO PressDefs.PressDotsData,b: POINTER TO GraphicsDefs.Bitmap] =
BEGIN
sampleVec: POINTER ← SystemDefs.AllocateSegment[(pdd.nPixels+1)/2];
sMode: CARDINAL ← pdd.mode MOD 4;
normal: BOOLEAN = sMode IN [2..3]; --otherwise, sideways
dp: DiscoDefs.DiskPosition ← pdd.diskPosition;

IF normal THEN
HalftoneDefs.InitHalftone[0,0,pdd.displayPixels,b.nBits,pdd.min,pdd.max,b,
pdd.displayLines,b.nLines,pdd.mode]
ELSE
HalftoneDefs.InitHalftone[0,0,pdd.displayPixels,b.nLines,pdd.min,pdd.max,b,
pdd.displayLines,b.nBits,pdd.mode];

DiscoDefs.TransferBytes[dp:@dp,data:sampleVec,nBytes:pdd.passPixels];
THROUGH [0..pdd.passLines) DO
DiscoDefs.TransferBytes[dp:@dp,data:sampleVec,nBytes:pdd.nPixels];
ENDLOOP;

THROUGH [0..pdd.displayLines) DO
DiscoDefs.TransferBytes[dp:@dp,data:sampleVec,nBytes:pdd.nPixels];
[] ← HalftoneDefs.PrintHalftoneLine[sampleVec];
ENDLOOP;

SystemDefs.FreeSegment[sampleVec];
END;

Screen: POINTER TO GraphicsDefs.Bitmap ← GraphicsDefs.GetDefaultBitmapHandle[];
bitsPerInch: CARDINAL ← 72;
micasPerInch: CARDINAL = 2540;
dispXOff: CARDINAL ← 0;
dispYOff: CARDINAL ← 0;

--to transform A,B,C,D coords to Bezier control points:
--
-- x0
y00003AxAy
-- x1
y10013BxBy
-- x2
y2 ← (1/3)*0123*CxCy
-- x3
y33333DxDy
--
--
x0 ← Dx
-- x1 ← (Cx/3) + Dx
-- x2 ← (Bx/3) + (2*Cx/3) + Dx
-- x3 ← Ax + Bx + Cx + Dx
--
--(same for y)
--
--since the D coords are current position, we just return just 6 offsets
ControlPoints: PUBLIC PROCEDURE [coeff: POINTER TO ARRAY [0..6) OF REAL,
dx,dy: POINTER TO ARRAY [0..3) OF INTEGER] =
BEGIN
dx[0] ← Real.RoundI[coeff[0]/3];
dx[1] ← Real.RoundI[(coeff[2] + 2*coeff[0])/3];
dx[2] ← Real.RoundI[coeff[4] + coeff[2] + coeff[0]];
dy[0] ← Real.RoundI[coeff[1]/3];
dy[1] ← Real.RoundI[(coeff[3] + 2*coeff[1])/3];
dy[2] ← Real.RoundI[coeff[5] + coeff[3] + coeff[1]];
END;

--calculate gray value from hue,sat,brightness
--
--255
blackfullSatVal
--
--sat
--
--
0blackwhite
--
0brightness255
SetGray: PROCEDURE [currentHue,currentSat,currentBr: CARDINAL] RETURNS [currentGray: CARDINAL] =
BEGIN
RED: CARDINAL = 0;
YELLOW: CARDINAL = 40;
GREEN: CARDINAL = 80;
CYAN: CARDINAL = 120;
BLUE: CARDINAL = 160;
MAGENTA: CARDINAL = 200;
RED2: CARDINAL = 240;
rSAT,cSAT: CARDINAL = 64;
ySAT: CARDINAL = 160;
bSAT: CARDINAL = 32;
fullSatVal,scaledSatVal,gray: CARDINAL;
fullSatVal ← SELECT currentHue FROM
IN [RED..YELLOW) => rSAT + (currentHue*(ySAT-rSAT))/(YELLOW-RED),
IN [YELLOW..CYAN) =>
ySAT - ((currentHue-YELLOW)*(ySAT-cSAT))/(CYAN-YELLOW),
IN [CYAN..BLUE) => cSAT - ((currentHue-CYAN)*(cSAT-bSAT))/(BLUE-CYAN),
IN [BLUE..RED2) => bSAT + ((currentHue-BLUE)*(rSAT-bSAT))/(RED2-BLUE),
ENDCASE => 255;
--ok, find saturation value at full brightness
scaledSatVal ← 255 - PressDefs.MulDiv[255-fullSatVal,currentSat,255];
--and move between that and black according to brightness
gray ← PressDefs.MulDiv[scaledSatVal,currentBr,255];
currentGray ← (gray+1)/16;
GraphicsDefs.SetGrayLevel[currentGray];
END;

DisplayPressPage: PUBLIC PROCEDURE [p: POINTER TO PressDefs.PressPage] =
BEGIN OPEN PressDefs;
currentDLRecord: CARDINAL ← 177777B;
spaceX: CARDINAL ← 177777B;
spaceY: CARDINAL ← 0;
obj: POINTER TO PressObject ← p.ObjectList;
micaX,micaY: CARDINAL;
chStr: STRING ← "a";
currentFontIndex: CARDINAL ← 177777B;
currentFont: POINTER TO GraphicsDefs.StrikeFont;
currentMode: GraphicsDefs.textMode;
currentWidth: POINTER TO ARRAY CHARACTER [0C..377C] OF INTEGER;
currentSat,currentHue,currentBr,currentGray: CARDINAL ← 0;
AlternativeOn: BOOLEAN ← FALSE;

DoChars: PROCEDURE[obj: POINTER TO PressDefs.PressObject,s: STRING] =
BEGIN
i: CARDINAL;
micaWidth: CARDINAL ← 0;
eBox: POINTER TO StrawDefs.EntityBox ←
SystemDefs.AllocateHeapNode[SIZE[StrawDefs.EntityBox]];
eBitmap: POINTER TO GraphicsDefs.Bitmap;

FOR i IN [0..s.length) DO
IF s[i] = ’ AND spaceX # 177777B THEN micaWidth ← micaWidth + spaceX
ELSE micaWidth ← micaWidth + currentWidth[s[i]];
ENDLOOP;

eBox↑←[Box:,Object:obj];
GraphicsDefs.CreateBox[@eBox.Box,
PressDefs.MulDiv[micaWidth,bitsPerInch,micasPerInch]+4,--4 is fudge
currentFont.ascent+currentFont.descent];
eBitmap ← @eBox.Box.boxBitmap;
micaWidth ← 0;
FOR i IN [0..s.length) DO
chStr[0]←s[i];
IF s[i] = ’ AND spaceX#177777B THEN
BEGIN
micaWidth ← micaWidth + spaceX;
LOOP;
END;
[] ← GraphicsDefs.PutText[chStr,
PressDefs.MulDiv[micaWidth,bitsPerInch,micasPerInch]+1,
currentFont.ascent,currentFont,currentMode,eBitmap];
micaWidth ← micaWidth+ currentWidth[s[i]];
ENDLOOP;

[eBox.Box.displayX,eBox.Box.displayY] ← DisplayCoord[micaX,micaY];
micaX ← micaX + micaWidth;
eBox.Box.function ← paint;
IF currentGray # 0 THEN
BEGIN
eBox.Box.type ← gray;
eBox.Box.gray ← currentGray;
END;
AddToDisplay[@eBox.Box,eBox.Box.displayX,eBox.Box.displayY-currentFont.ascent];
END;

GraphicsDefs.SetGrayLevel[0];
UNTIL obj = NIL DO
micaX ← obj.micaX;
micaY ← obj.micaY;
spaceX ← obj.spaceX;
spaceY ← obj.spaceY;
IF (currentBr#obj.br) OR (currentHue#obj.hue) OR (currentSat#obj.sat) THEN
BEGIN
currentGray ← SetGray[obj.hue,obj.sat,obj.br];
currentBr ← obj.br;
currentHue ← obj.hue;
currentSat ← obj.sat;
END;
maxDataBytes ← MAX[obj.nDataBytes,maxDataBytes];
SELECT obj.command FROM
ELShowCharacters=>
BEGIN
string: STRING ← SystemDefs.AllocateHeapString[obj.nDataBytes];
dp: DiscoDefs.DiskPosition ← obj.diskPosition;
DiscoDefs.TransferBytes[dp: @dp,nBytes: obj.nDataBytes,
data: LOOPHOLE[@string.text]];
string.length ← obj.nDataBytes;
IF currentFontIndex # obj.font THEN
[currentFont,currentMode,currentWidth,currentFontIndex] ←
StrawDefs.GetFont[obj.font];
DoChars[obj,string];
SystemDefs.FreeHeapString[string];
END;
ELShowObject=>
BEGIN
eBox: POINTER TO StrawDefs.EntityBox ←
SystemDefs.AllocateHeapNode[SIZE[StrawDefs.EntityBox]];
eBox.Object ← obj;
CreateObjectBox[eBox];
AddToDisplay[@eBox.Box,eBox.Box.displayX,eBox.Box.displayY];
END;
ELShowDots,ELShowDotsOpaque=> --EL[i] tells which
BEGIN
do: POINTER TO StrawDefs.DotObject ←
SystemDefs.AllocateHeapNode[SIZE[StrawDefs.DotObject]];
do↑ ← [Box:,Object: obj,DotsData: LOOPHOLE[obj+SIZE[PressObject]]];
CreateDotsBox[do];
GraphicsDefs.SetGrayLevel[currentGray]; --reset to prev value
AddToDisplay[@do.Box,do.Box.displayX,do.Box.displayY];
END;
ELShowRectangle=>
BEGIN
x1,y1,x2,y2: CARDINAL;
eBox: POINTER TO StrawDefs.EntityBox ←
SystemDefs.AllocateHeapNode[SIZE[StrawDefs.EntityBox]];
[x1,y2] ← StrawDefs.DisplayCoord[micaX,micaY];
[x2,y1] ← StrawDefs.DisplayCoord[micaX+spaceX,micaY+spaceY];
x2 ← PressDefs.MulDiv[spaceX,bitsPerInch,micasPerInch];
y2 ← PressDefs.MulDiv[spaceY,bitsPerInch,micasPerInch];
eBox↑←[Box:,Object: obj];
GraphicsDefs.CreateBox[@eBox.Box,x2+1,y2+1];
GraphicsDefs.PutArea[0,0,x2,y2,@eBox.Box.boxBitmap];
IF currentGray # 0 THEN
BEGIN
eBox.Box.type ← gray;
eBox.Box.gray ← currentGray;
END;
AddToDisplay[@eBox.Box,x1,y1];
END;
ENDCASE=>NULL;
obj ← obj.link;
ENDLOOP; --until obj = NIL

END; --DisplayPressPage

CreateDotsBox: PUBLIC PROCEDURE [do: POINTER TO StrawDefs.DotObject] =
BEGIN
dispX,dispY: CARDINAL;
pdd: POINTER TO PressDefs.PressDotsData ← do.DotsData;
obj: POINTER TO PressDefs.PressObject ← do.Object;

dispX ← PressDefs.MulDiv[pdd.micaWidth,bitsPerInch,micasPerInch];
dispY ← PressDefs.MulDiv[pdd.micaHeight,bitsPerInch,micasPerInch];
GraphicsDefs.CreateBox[@do.Box,dispX,dispY];
IF pdd.nBitsPerPixel = 0 AND pdd.mode = 3 THEN
BEGIN
nWords: CARDINAL = (pdd.nPixels/16)*pdd.nLines;
nChunks: CARDINAL = (nWords+4095)/4096;
sArea: GraphicsDefs.Rectangle←[x1:0,y1:0,x2:pdd.displayPixels-1,y2:pdd.nLines/nChunks-1];
dArea: GraphicsDefs.Rectangle ← [x1:0,y1:0,x2:dispX-1,y2:];
temp: GraphicsDefs.Bitmap ←
[bank:0,nWords:pdd.nPixels/16,nBits:pdd.nPixels,nLines:
pdd.nLines/nChunks,bits:
SystemDefs.AllocateSegment[pdd.nPixels/16+nWords/nChunks]];
dataPos: DiscoDefs.DiskPosition ← pdd.diskPosition;
i: CARDINAL;
FOR i IN [1..nChunks] DO
sArea.y2 ← (pdd.nLines*i)/nChunks-(pdd.nLines*(i-1))/nChunks-1;
dArea.y2 ← (dispY*i)/nChunks-1;
DiscoDefs.TransferBytes[dp:@dataPos,nBytes:
((pdd.nLines*i)/nChunks-(pdd.nLines*(i-1))/nChunks)*(pdd.nPixels/8),
data:LOOPHOLE[temp.bits]];
GraphicsDefs.TransferRectangle[src:@temp,dest:@do.Box.boxBitmap,
srcRectangle:@sArea,destRectangle:@dArea];
dArea.y1 ← dArea.y2+1;
ENDLOOP;
SystemDefs.FreeSegment[temp.bits];
END
ELSE
BEGIN
IF pdd.nBitsPerPixel = 8 AND pdd.fileName = NIL THEN
DoHalftone[pdd,@do.Box.boxBitmap]
ELSE -- no can do
BEGIN
GraphicsDefs.SetGrayLevel[14];
GraphicsDefs.PutGray[0,0,dispX,dispY,@do.Box.boxBitmap];
END;
END;
do.Box.function ← IF pdd.opaque THEN replace ELSE paint;
[do.Box.displayX,do.Box.displayY] ←
StrawDefs.DisplayCoord[obj.micaX,obj.micaY+pdd.micaHeight];
--kludge: got to store mica width, height
do
.Object.spaceX ← pdd.micaWidth;
do
.Object.spaceY ← pdd.micaHeight;
END; --end of ShowDots

CreateObjectBox: PUBLIC PROCEDURE [eBox: POINTER TO StrawDefs.EntityBox] =
BEGIN
obj: POINTER TO PressDefs.PressObject ← eBox.Object;
Box: POINTER TO GraphicsDefs.Box ← @eBox.Box;
cX,cY,x1,y1,x2,y2,j: CARDINAL;
ObjCommand: TYPE = RECORD
[move:BOOLEAN,x,y: CARDINAL];
maxObj: CARDINAL =
maxObjCommandSize/SIZE[ObjCommand];
ObjList: ARRAY [0..maxObj) OF ObjCommand;
nObjects: CARDINAL ← 0;
objCommand: POINTER TO ARRAY [0..0) OF CARDINAL ←
SystemDefs.AllocateSegment[(obj.nDataBytes+1)/2];
minX,minY: CARDINAL ← 177777B;
maxX,maxY: CARDINAL ← 0;
currentX,currentY: CARDINAL;
commIndex: CARDINAL ← 0;
dp: DiscoDefs.DiskPosition ← obj.diskPosition;
DiscoDefs.TransferBytes[dp: @dp,nBytes: obj.nDataBytes,
data: LOOPHOLE[objCommand]];
UNTIL commIndex >= obj.nDataBytes/2 DO
SELECT objCommand[commIndex] FROM
PressDefs.DLMoveTo =>
BEGIN
currentX ← obj.micaX + objCommand[commIndex+1];
currentY ← obj.micaY + objCommand[commIndex+2];
commIndex ← commIndex+3;
ObjList[nObjects] ← [TRUE,currentX,currentY];
minX ← MIN[minX,currentX];maxX ← MAX[maxX,currentX];
minY ← MIN[minY,currentY];maxY ← MAX[maxY,currentY];
nObjects ← nObjects+1;
IF nObjects > maxObj THEN MiscDefs.CallDebugger["obj overflow"];
END;
PressDefs.DLDrawTo =>
BEGIN
currentX ← obj.micaX + objCommand[commIndex+1];
currentY ← obj.micaY + objCommand[commIndex+2];
commIndex ← commIndex+3;
ObjList[nObjects] ← [FALSE,currentX,currentY];
minX ← MIN[minX,currentX];maxX ← MAX[maxX,currentX];
minY ← MIN[minY,currentY];maxY ← MAX[maxY,currentY];
nObjects ← nObjects+1;
IF nObjects > maxObj THEN MiscDefs.CallDebugger["obj overflow"];
END;
PressDefs.DLDrawCurve =>
BEGIN
fake: ARRAY[0..2) OF UNSPECIFIED;
coeff: ARRAY[0..6) OF REAL;
dx,dy: ARRAY[0..3) OF INTEGER;
commIndex ← commIndex+1;
FOR j IN [0..6) DO
fake[0]←objCommand[commIndex];
fake[1]←objCommand[commIndex+1];
commIndex ← commIndex+2;
coeff[j] ← RealConvert.BcplToIeee[LOOPHOLE[fake]];
ENDLOOP;
ControlPoints[@coeff,@dx,@dy];
FOR j IN [KLUDGESegs..3) DO
cX ← currentX + dx[j];cY ← currentY + dy[j];
ObjList[nObjects] ← [FALSE,cX,cY];
minX ← MIN[minX,cX];maxX ← MAX[maxX,cX];
minY ← MIN[minY,cY];maxY ← MAX[maxY,cY];
nObjects ← nObjects+1;
IF nObjects > maxObj THEN MiscDefs.CallDebugger["obj overflow"];
ENDLOOP;
currentX ← cX;currentY ← cY;
END;
ENDCASE => MiscDefs.CallDebugger["bad object"];
ENDLOOP;

SystemDefs.FreeSegment[objCommand];
--now, process linked list of commands
[x1,y2] ← StrawDefs.DisplayCoord[minX,minY];
[x2,y1] ← StrawDefs.DisplayCoord[maxX,maxY];
GraphicsDefs.CreateBox[Box,x2+1-x1,y2+1-y1];
FOR j IN [0..nObjects) DO
[cX,cY] ← StrawDefs.DisplayCoord[ObjList[j].x,ObjList[j].y];
cX ← cX-x1;cY ← cY-y1;
IF NOT ObjList[j].move THEN
GraphicsDefs.PutLine[currentX,currentY,cX,cY,
@Box.boxBitmap];
currentX ← cX;currentY ← cY;
ENDLOOP;
[cX,cY] ← StrawDefs.DisplayCoord[ObjList[0].x,ObjList[0].y];
GraphicsDefs.PutLine[currentX,currentY,cX-x1,cY-y1,@Box.boxBitmap];
Box.function ← paint;
Box.displayX ← x1;Box.displayY ← y1;
--kludge: got to store mica offset from position to corner
BEGIN
e: POINTER TO
StrawDefs.EntityBox ← LOOPHOLE[Box];
e.Object.spaceX ← minX-e.Object.micaX;
e.Object.spaceY ← maxY-e.Object.micaY;
END;
END;

AddToDisplay
: PROCEDURE [box: POINTER TO GraphicsDefs.Box,x,y: CARDINAL] =
BEGIN
DisplayListDefs.AddDisplayItem[box];
box.displayX ← x;
box.displayY ← y;
box.displayBitmap ← Screen;
box.displayed ← TRUE;
SELECT box.type FROM
gray =>GraphicsDefs.PutGrayBitmap[@box.boxBitmap,x,y];
normal =>SELECT box.function FROM
replace =>GraphicsDefs.ReplaceBitmap[@box.boxBitmap,x,y];
paint =>GraphicsDefs.PutBitmap[@box.boxBitmap,x,y];
ENDCASE => ERROR;
ENDCASE => ERROR;
END;

DisplayCoord: PUBLIC PROCEDURE[x,y: CARDINAL] RETURNS[dispX,dispY: CARDINAL] =
BEGIN
sh: CARDINAL ← Screen.nLines; -- screen height
dx: CARDINAL ← dispXOff + PressDefs.MulDiv[x,bitsPerInch,micasPerInch];
dy: CARDINAL ← dispYOff + PressDefs.MulDiv[y,bitsPerInch,micasPerInch];
RETURN[dispX: dx, dispY: (IF dy>sh THEN 0 ELSE sh-dy)];
END;

PageCoord: PUBLIC PROCEDURE [dispX,dispY: CARDINAL] RETURNS [x,y: CARDINAL] =
BEGIN
sh: CARDINAL ← Screen.nLines; -- screen height
dx: CARDINAL ← dispX-dispXOff;
dy: CARDINAL ← sh-(dispY-dispYOff);
RETURN[
x: PressDefs.MulDiv[dx,micasPerInch,bitsPerInch],
y: PressDefs.MulDiv[dy,micasPerInch,bitsPerInch]];
END;

LongDiv32: PROCEDURE[CARDINAL,CARDINAL,CARDINAL] RETURNS[CARDINAL] =
MACHINE CODE BEGIN Mopcodes.zLDIV;END;
--LongDiv32: PROCEDURE[ARRAY [0..1] OF CARDINAL,CARDINAL] RETURNS[CARDINAL] =MACHINE CODE BEGIN Mopcodes.zEXCH;Mopcodes.zLDIV;END;

END.