--File CIFUtilities.Mesa
-- August 1980 by MN
--
Last changed: June 10, 1981 11:26 PM

DIRECTORY

AltoDevice: FROM "AltoDevice" USING [Bitmap, ScreenBitmap, NewAltoDevice, ScreenOrigin],
BitBltDefs: FROM "BitBltDefs" USING [BBTable, BITBLT],
CIFUtilitiesDefs: FROM "CIFUtilitiesDefs" USING [Rectangle],
Graphics: FROM "Graphics" USING [DisplayContext, BoundingBox, StartAreaPath, EnterPoint,
DestroyPath, SetClipArea, NewContext, Translate, Scale, Map, MoveTo, DrawTo,
PushClipBox, PopClipBox, ScreenToUser, UserToScreen, CopyContext, PushContext, PopContext,
SetPaint, SetTexture, black, DrawScreenArea, SetFont, MakeFont],
InlineDefs: FROM "InlineDefs" USING [HighHalf, LowHalf],
IODefs: FROM "IODefs" USING [WriteLine],
JaMFnsDefs: FROM "JaMFnsDefs" USING [SetMouseProc, JaMStream, PushReal],
KeyDefs: FROM "KeyDefs" USING [MouseButton, Mouse],
Memory: FROM "Memory" USING [long],
Real: FROM "Real" USING [FixI],
Vector: FROM "Vector" USING [Vec];

CIFUtilities: PROGRAM
IMPORTS AltoDevice, BitBltDefs, Graphics, InlineDefs, IODefs, JaMFnsDefs, Memory, Real
EXPORTS CIFUtilitiesDefs =

BEGIN OPEN AltoDevice, BitBltDefs, CIFUtilitiesDefs, Graphics, InlineDefs, IODefs, JaMFnsDefs, KeyDefs, Real, Vector;

InitCedarGraphics: PUBLIC PROCEDURE =
BEGIN
screenbitmap ← ScreenBitmap[];
ScreenBaseContext ← NewContext[AltoDevice.NewAltoDevice[screenbitmap]];
ScreenBaseClipRectangle ←
[llx:1, lly:1, urx:screenbitmap.raster*16-1, ury:screenbitmap.height-1];
SetFont[ScreenBaseContext, MakeFont["Helvetica"], 10];
ScreenContext ← CurrentDisplayContext ← CopyContext[ScreenBaseContext];
CurrentClipRectangle ← ScreenBaseClipRectangle; --This is always held in Base Coordinates
ClippingOn ← TRUE;

SetClipRect[ScreenBaseContext, ScreenBaseClipRectangle];
SetMouseProc[JaMStream[], MouseToUser];
END;

SetDisplayContext: PUBLIC PROCEDURE[dc: DisplayContext] =
BEGIN
IF ~ClippingOn THEN EnableClipping[];
CurrentDisplayContext ← dc;
END;

GetDisplayContext: PUBLIC PROCEDURE RETURNS[dc: DisplayContext] =
BEGIN
RETURN[CurrentDisplayContext];
END;

GetBaseContext: PUBLIC PROCEDURE RETURNS[dc: DisplayContext] =
BEGIN
RETURN[ScreenBaseContext];
END;

SetClipRectangle: PUBLIC PROCEDURE[cr: Rectangle] =
--set clip rectangle in current context
BEGIN
SetClipRect[CurrentDisplayContext, cr];
CurrentClipRectangle ← MapRectangle[cr, CurrentDisplayContext,ScreenBaseContext];
END;

SetClipRect: PROCEDURE[dc: DisplayContext, cr: Rectangle] =
--set clip rectangle in dc context
BEGIN
StartAreaPath[dc,FALSE];
EnterPoint[dc,[cr.llx,cr.lly]];
EnterPoint[dc,[cr.urx,cr.lly]];
EnterPoint[dc,[cr.urx,cr.ury]];
EnterPoint[dc,[cr.llx,cr.ury]];
SetClipArea[dc];
DestroyPath[dc];
END;

GetClipRectangle: PUBLIC PROCEDURE RETURNS[cr: Rectangle] =
BEGIN
RETURN[MapRectangle[CurrentClipRectangle, ScreenBaseContext,CurrentDisplayContext]];
END;

GetBaseClipRectangle: PUBLIC PROCEDURE RETURNS[cr: Rectangle] =
BEGIN
RETURN[MapRectangle[ScreenBaseClipRectangle, ScreenBaseContext,CurrentDisplayContext]];
END;

DrawClipRectangle: PUBLIC PROCEDURE =
BEGIN
DrawRectOutline[ScreenBaseContext, CurrentClipRectangle];
END;

ClearClipRectangle: PUBLIC PROCEDURE =
BEGIN
PushContext[CurrentDisplayContext];
SetPaint[CurrentDisplayContext, erase];
SetTexture[CurrentDisplayContext, black];
DrawScreenArea[CurrentDisplayContext];
PopContext[CurrentDisplayContext];
END;

DrawRectangleOutline: PUBLIC PROCEDURE[cr: Rectangle] =
BEGIN --draw it in BaseContext to get uniform thin lines
SetClipRect[ScreenBaseContext, CurrentClipRectangle];
DrawRectOutline[ScreenBaseContext,
MapRectangle[cr, CurrentDisplayContext,ScreenBaseContext]];
SetClipRect[ScreenBaseContext, ScreenBaseClipRectangle];
END;

DrawRectOutline: PROCEDURE[dc: DisplayContext, cr: Rectangle] =
BEGIN --draw cr in dc
Graphics.MoveTo[dc, [cr.llx,cr.lly]];
Graphics.DrawTo[dc, [cr.urx,cr.lly]];
Graphics.DrawTo[dc, [cr.urx,cr.ury]];
Graphics.DrawTo[dc, [cr.llx,cr.ury]];
Graphics.DrawTo[dc, [cr.llx,cr.lly]];
END;

MoveTo: PUBLIC PROCEDURE[x,y: REAL] =
BEGIN
SetClipRect[ScreenBaseContext, CurrentClipRectangle];
Graphics.MoveTo[ScreenBaseContext,
Map[CurrentDisplayContext, ScreenBaseContext, [x,y]]];
SetClipRect[ScreenBaseContext, ScreenBaseClipRectangle];
--
Graphics.MoveTo[CurrentDisplayContext, [x,y]];
END;

DrawTo: PUBLIC PROCEDURE[x,y: REAL] =
BEGIN --draw it in BaseContext to get uniform thin lines
SetClipRect[ScreenBaseContext, CurrentClipRectangle];
Graphics.DrawTo[ScreenBaseContext,
Map[CurrentDisplayContext, ScreenBaseContext, [x,y]]];
SetClipRect[ScreenBaseContext, ScreenBaseClipRectangle];
END;

Debugging: BOOLEAN ← TRUE;

EnableClipping: PUBLIC PROCEDURE =
BEGIN
IF Debugging THEN RETURN; --***Temporary
IF ClippingOn THEN RETURN
ELSE
{PopClipBox[CurrentDisplayContext];
ClippingOn ← TRUE;
};
END;

DisableClipping: PUBLIC PROCEDURE =
--big kludge to turn off clipping -
-- PushClipBox with zero size box at center of clipping region
BEGIN
IF Debugging THEN RETURN; --***Temporary
IF ~ClippingOn THEN RETURN
ELSE
{cr: Rectangle ← GetClipRectangle[];
c: Vec ← [(cr.llx + cr.urx)/2,
(cr.lly + cr.ury)/2];
box: BoundingBox ← [c,c,c,c];
PushClipBox[CurrentDisplayContext, @box];
ClippingOn ← FALSE;
};
END;

MapRectangle: PUBLIC PROCEDURE[rect1: Rectangle, cntxt1,cntxt2: DisplayContext]
RETURNS[rect2: Rectangle] =
BEGIN
--return rectangle which in cntxt2 generates same as rect1 does in cntxt1
v0,v1: Vec;
v0 ← Map[cntxt1,cntxt2, [rect1.llx,rect1.lly]];
v1 ← Map[cntxt1,cntxt2, [rect1.urx,rect1.ury]];
RETURN[[llx:MIN[v0.x,v1.x],lly:MIN[v0.y,v1.y], urx:MAX[v0.x,v1.x],ury:MAX[v0.y,v1.y]]];
END;

--
GetBaseContextRecord: PUBLIC PROCEDURE RETURNS[baseContext: DisplayContext] =
--
BEGIN
--get the base context RECORD
--
PushBaseContext[];
--
baseContext ← GetDisplayContext[]↑;
--
PopDisplayContext[];
--
END;

SetUniformView: PUBLIC PROCEDURE[rfrom, rto: Rectangle] =
--Set up transform to map rectangles, but without introducing differential scaling
--Minimum scale factor is used, and centers will correspond
BEGIN
sx,sy,scale: REAL;
dxfrom: REAL ← rfrom.urx-rfrom.llx;
dyfrom: REAL ← rfrom.ury-rfrom.lly;
dxto: REAL ← rto.urx-rto.llx;
dyto: REAL ← rto.ury-rto.lly;
IF dxfrom=0 OR dyfrom=0 OR dxto=0 OR dyto=0 THEN
BEGIN
WriteLine["Invalid scale factor"];
RETURN;
END;
sx ← dxto/dxfrom;
sy ← dyto/dyfrom;
scale ← IF ABS[sx]<ABS[sy] THEN sx ELSE sy;
Translate[CurrentDisplayContext, [(rto.urx+rto.llx)/2, (rto.ury+rto.lly)/2]];
Scale[CurrentDisplayContext, [scale,scale]];
Translate[CurrentDisplayContext, [-(rfrom.urx+rfrom.llx)/2, -(rfrom.ury+rfrom.lly)/2]];
END;

ScreenParams: PUBLIC PROCEDURE
RETURNS[base: LONG POINTER, widthWords, heightLines: CARDINAL] =
BEGIN OPEN screenbitmap;
RETURN[base, raster, height];
END;

mousex: POINTER TO INTEGER = LOOPHOLE[424B];
mousey: POINTER TO INTEGER = LOOPHOLE[425B];

TrackBox: PUBLIC PROCEDURE[x,y: REAL, mouseButtons: KeyDefs.MouseButton] =
BEGIN
x0,y0: INTEGER;
xs,ys: REAL;
xori,yori,xold,yold,xnew,ynew: INTEGER;
left,bottom,right,top: INTEGER;
cr: Rectangle ← MapRectangle[GetClipRectangle[], CurrentDisplayContext,
ScreenBaseContext];
p: Vec;

[x0,y0] ← ScreenOrigin[];
left ← FixI[cr.llx];
top ← FixI[screenbitmap.height - cr.lly]; --top means bigger y value in screen coords
right ← FixI[cr.urx];
bottom ← FixI[screenbitmap.height - cr.ury];
IF Memory.long THEN
BEGIN --D*
bbt.ptrs ← long;
bbt.dlbca ← screenbitmap.base;
END
ELSE
BEGIN --Alto
bbt.ptrs ← short;
bbt.destalt ← HighHalf[screenbitmap.base]#0;
bbt.unused ← HighHalf[screenbitmap.base];
bbt.dbca ← LowHalf[screenbitmap.base];
END;
bbt.dbmr ← screenbitmap.raster;
p ← Map[CurrentDisplayContext, ScreenBaseContext, [x,y]];
xs ← p.x;
ys ← screenbitmap.height - p.y;
xold ← xori ← MAX[left,MIN[right,FixI[xs]]];
yold ← yori ← MAX[bottom,MIN[top,FixI[ys]]];
WHILE Mouse.buttons = mouseButtons DO
xnew ← MAX[left,MIN[right,mousex↑-x0]];
ynew ← MAX[bottom,MIN[top,mousey↑-y0]];
InvertBox[xold,yori,xnew,yold];
InvertBox[xori,yold,xnew,ynew];
xold ← xnew; yold ← ynew;
ENDLOOP;
InvertBox[xori,yori,xold,yold];
END;

InvertBox: PROCEDURE[x0,y0,x1,y1: INTEGER] =
BEGIN
dx,dy: INTEGER;
IF (dx ← x1-x0)=0 OR (dy ← y1-y0)=0 THEN RETURN;
bbt.dlx ← MIN[x0,x1];
bbt.dty ← MIN[y0,y1];
bbt.dw ← ABS[dx];
bbt.dh ← ABS[dy];
BitBltDefs.BITBLT[bbt];
END;

MoveCursorTo: PUBLIC PROCEDURE[x,y: REAL] =
BEGIN
s: Vec ← ScreenToUser[CurrentDisplayContext, [x,y]];
p: Vec ← UserToScreen[ScreenContext, s];
x0,y0: REAL;
[x0,y0] ← ScreenOrigin[];
mousex↑ ← FixI[p.x];
mousey↑ ← FixI[p.y + y0];
END;

MouseToUser: PROCEDURE[x,y:INTEGER] =
BEGIN
x0,y0: INTEGER;
p,p1: Vec;
[x0,y0]←AltoDevice.ScreenOrigin[];
p←[(x-x0)+0.5,(y-y0)+0.5]; -- the center of the pixel
p1 ← Graphics.ScreenToUser[CurrentDisplayContext,p];
PushReal[p1.x];
PushReal[p1.y];
END;

screenbitmap: AltoDevice.Bitmap;
ScreenContext: DisplayContext;
ScreenBaseContext: DisplayContext;
ScreenBaseClipRectangle: Rectangle;
CurrentDisplayContext: DisplayContext;
CurrentClipRectangle: Rectangle; --This is always held in Base Coordinates
ClippingOn: BOOLEAN ← TRUE;

bb:ARRAY [0..SIZE[BitBltDefs.BBTable]] OF UNSPECIFIED;
bbt:POINTER TO BitBltDefs.BBTable ← @bb[LOOPHOLE[@bb,CARDINAL] MOD 2];

bbt↑ ← BitBltDefs.BBTable[
ptrs: ,
pad: 0,
sourcealt: FALSE,
destalt: ,
sourcetype: gray,
function: invert,
unused: ,
dbca: ,
dbmr: ,
dlx: ,-- destination left x
dty: ,-- destination top y
dw: ,
dh: ,
sbca: NIL,
sbmr: 0,
slx: 0,
sty: 0,
gray0: 177777B,
gray1: 177777B,
gray2: 177777B,
gray3: 177777B,
slbca: NIL,
dlbca: NIL
];



END.