-- TJaMGraphicsImpl.mesa
-- Last changed by Bill Paxton, March 12, 1982 8:19 am
-- Last changed by Maureen Stone April 11, 1983 3:35 pm
-- Last changed by McGregor, September 13, 1982 1:44 pm
-- Last changed by Doug Wyatt, September 16, 1982 12:14 am

DIRECTORY
Graphics,
GraphicsOps,
GL USING [ Start, End, Draw],
GraphicsBasic USING [Vec],
CGVector USING [Sub, Cross],
Rope USING [FromRefText],
Spline USING [Ref, Knot, Enter],
ViewerOps USING[PaintViewer],
ViewerClasses USING [Viewer],
JaMBasic USING [Object],
JaMInternal USING [Frame],
JaMOps USING [defaultFrame, PopInteger, PushInteger, PushReal, PopReal, PopString,
PushBoolean, PopBoolean, RegisterExplicit, StringText],
TJaMGraphics,
TJaMGraphicsContexts,
TJaMGraphicsInfo;

TJaMGraphicsImpl: MONITOR
IMPORTS JaMOps, TJaMGraphics, TJaMGraphicsInfo,
Graphics, GraphicsOps, CGVector, Rope, Spline, ViewerOps, GL, TJaMGraphicsContexts
EXPORTS TJaMGraphics, TJaMGraphicsInfo = {
OPEN J: JaMOps, G: Graphics, E: GraphicsOps,
Vector: CGVector, TJaMGraphics, TJaMGraphicsInfo, TDC: TJaMGraphicsContexts;

Vec: TYPE = GraphicsBasic.Vec;
GProc: TYPE = TDC.GProc;

PopString: PROC [info: Info] = {
J.StringText[J.PopString[info.frame.opstk],LOOPHOLE[info.text, LONG STRING]];
};

Paint: PUBLIC ENTRY SAFE PROCEDURE [self: ViewerClasses.Viewer, context: G.Context,
whatChanged: REF ANY, clear: BOOL] = TRUSTED {
ENABLE UNWIND => NULL;
info: Info ← NARROW[self.data];
IF whatChanged=NIL THEN { -- reestablish context and erase
G.SetCP[context, 0, 0];
info.vinitdc ← G.CopyContext[context];
info.vdc ←G.CopyContext[info.vinitdc];
IF ~clear THEN { -- cannot simply call JErase because of monitor deadlock
mark: G.Mark ← G.Save[info.vdc];
G.SetColor[info.vdc, G.white];
G.DrawBox[info.vdc,G.GetBounds[info.vdc]];
G.Restore[info.vdc,mark] };
IF info.drawGL THEN {
 gl: TDC.DCList ← NIL;
FOR l: TDC.DCList ← info.dcList, l.next UNTIL l=NIL DO
  IF l.name=$GList THEN gl ← l;
  ENDLOOP;
 info.gl ← GL.End[gl.dc];
IF info.gl#NIL THEN GL.Draw[info.vdc,info.gl];
 gl.dc ← GL.Start[info.gl];
 };
RETURN };
info.proc[info];
};

Painter: PUBLIC PROCEDURE[proc: PROC [Graphics.Context], frame: Frame ← NIL] = {
info: Info;
CallBack: PROC [info: Info] = { proc[info.vdc] };
IF frame=NIL THEN frame ← J.defaultFrame;
info ← GetInfo[frame];
TDC.ForAllDCs[info.dcList,proc];
IF info.venabled THEN {
 info.proc ← CallBack;
 ViewerOps.PaintViewer[viewer: info.viewer, hint: client, whatChanged: info, clearClient: FALSE];
 };
};

PushDC: PROCEDURE [frame: Frame] = {
pushdc: GProc = {[] ← G.Save[dc]};
Painter[pushdc,frame];
};

PopDC: PROCEDURE [frame: Frame] = {
 popdc: GProc = {[] ← G.Restore[dc]};
 Painter[popdc, frame];
};

GetVec: PROCEDURE [frame: Frame] RETURNS[Vec] = {
y: REALJ.PopReal[frame.opstk]; x: REALJ.PopReal[frame.opstk]; RETURN[[x,y]] };

GetPoint: PROCEDURE [frame: Frame] RETURNS[x,y: REAL] = {
y ← J.PopReal[frame.opstk]; x ← J.PopReal[frame.opstk]; RETURN[x,y] };

PutPoint: PROCEDURE[frame: Frame, x,y: REAL] = {
J.PushReal[frame.opstk,x]; J.PushReal[frame.opstk,y] };

Rect: TYPE = RECORD[xmin,ymin,xmax,ymax: REAL];

GetRect: PROCEDURE [frame: Frame] RETURNS[r: Rect] = {
[r.xmax,r.ymax] ← GetPoint[frame];
[r.xmin,r.ymin] ← GetPoint[frame];
RETURN[r];
};

PutRect: PROCEDURE[frame: Frame, r: Rect] = {
PutPoint[frame,r.xmin,r.ymin];
PutPoint[frame,r.xmax,r.ymax];
};

JSetVw: PROCEDURE [frame: Frame] = {
rt: Rect ← GetRect[frame];
rf: Rect ← GetRect[frame];
-- *** fix this
-- SetView[dc,@rf,@rt];
};

JClipArea: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
paint: GProc ={G.ClipArea[self: dc, path: info.path]};
Painter[paint,frame];
};

JClipEOArea: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
paint: GProc ={G.ClipArea[self: dc, path: info.path, parityFill: TRUE]};
Painter[paint,frame];
};

JClipXArea: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
paint: GProc ={G.ClipArea[self: dc, path: info.path, exclude: TRUE]};
Painter[paint,frame];
};

JClipBox: PROCEDURE [frame: Frame] = {
paint: GProc ={G.ClipBox[dc, box]};
box: G.Box ← GetBox[frame];
Painter[paint,frame];
};

JClipXBox: PROCEDURE [frame: Frame] = {
paint: GProc ={G.ClipBox[dc,box,TRUE]};
box: G.Box ← GetBox[frame];
Painter[paint,frame];
};

JTranslate: PROCEDURE [frame: Frame] = {
 paint: GProc ={G.Translate[dc,tx,ty]};
 tx,ty: REAL;
 [tx,ty]←GetPoint[frame];
 Painter[paint,frame];
 };

JScale: PROCEDURE [frame: Frame] = {
 paint: GProc ={ G.Scale[dc,sx,sy]};
 sx,sy: REAL;
 [sx,sy]←GetPoint[frame];
 Painter[paint,frame];
 };

JRotate: PROCEDURE [frame: Frame] = {
 paint: GProc ={G.Rotate[dc,a]};
 a: REALJ.PopReal[frame.opstk];
 Painter[paint,frame];
};

JSixPoint: PROCEDURE [frame: Frame] = {
 paint: GProc ={
  G.Translate[dc,t1.x,t1.y];
  G.Concat[dc,m11,m12,m21,m22];
  G.Translate[dc,-f1.x,-f1.y];
  };
 f1,f2,f3,t1,t2,t3,df1,df2,dt1,dt2: Vec;
 adet: REAL;
 m11,m12,m21,m22: REAL;
 t3←GetVec[frame];
 t2←GetVec[frame];
 t1←GetVec[frame];
 f3←GetVec[frame];
 f2←GetVec[frame];
 f1←GetVec[frame];
 dt1←Vector.Sub[t2,t1];
 df1←Vector.Sub[f2,f1];
 dt2←Vector.Sub[t3,t1];
 df2←Vector.Sub[f3,f1];
 adet𡤁.0/Vector.Cross[df1,df2];
 m11←(dt1.x*df2.y-dt2.x*df1.y)*adet;
 m12←(dt1.y*df2.y-dt2.y*df1.y)*adet;
 m21←(df1.x*dt2.x-df2.x*dt1.x)*adet;
 m22←(df1.x*dt2.y-df2.x*dt1.y)*adet;
 Painter[paint,frame];
 };

JConcat: PROCEDURE [frame: Frame] = {
paint: GProc ={G.Concat[dc,m11,m12,m21,m22]};
m11,m12,m21,m22: REAL;
m22 ← J.PopReal[frame.opstk];
m21 ← J.PopReal[frame.opstk];
m12 ← J.PopReal[frame.opstk];
m11 ← J.PopReal[frame.opstk];
Painter[paint,frame];
};

--note multiple display context behavior
JGetPos: PROCEDURE [frame: Frame] = {
paint: GProc ={[x,y]←G.GetCP[dc]};
x,y: REAL;
Painter[paint,frame];
PutPoint[frame,x,y];
};

JSetPos: PROCEDURE [frame: Frame] = {
paint: GProc ={G.SetCP[dc,x,y]};
x,y: REAL; [x,y] ← GetPoint[frame];
Painter[paint,frame];
};

JRelSetPos: PROCEDURE [frame: Frame] = {
paint: GProc ={ G.SetCP[dc,x,y,TRUE]};
x,y: REAL; [x,y]←GetPoint[frame];
Painter[paint,frame];
};

JDrawTo: PROCEDURE [frame: Frame] = {
paint: GProc ={G.DrawTo[dc,x,y]};
x,y: REAL;
[x,y]←GetPoint[frame];
Painter[paint,frame];
};

JRelDrawTo: PROCEDURE [frame: Frame] = {
paint: GProc ={G.DrawTo[dc,x,y,TRUE]};
x,y: REAL;
[x,y]←GetPoint[frame];
Painter[paint,frame];
};


JDrawBox: PROCEDURE [frame: Frame] = {
paint: GProc ={G.DrawBox[dc,box]};
box: G.Box ← GetBox[frame];
Painter[paint,frame];
};

JCover: PROCEDURE [frame: Frame] = {
paint: GProc ={G.DrawBox[dc,G.GetBounds[dc]]};
Painter[paint,frame];
};

JSetInvert: PROCEDURE [frame: Frame] = {
paint: GProc ={[] ← G.SetPaintMode[dc, invert]};
Painter[paint,frame];
};

JSetFat: PROCEDURE [frame: Frame] = {
paint: GProc ={[] ← G.SetFat[dc,b]};
b: BOOLEANJ.PopBoolean[frame.opstk];
Painter[paint,frame];
};

JSetOpaque: PROCEDURE [frame: Frame] = {
paint: GProc ={[] ← G.SetPaintMode[dc,IF b THEN opaque ELSE transparent]};
b: BOOLEANJ.PopBoolean[frame.opstk];
Painter[paint,frame];
};

JGetTouch: PROCEDURE [frame: Frame] = {
mx,my: REAL;
[mx,my] ← RealViewerMouse[frame,TRUE];
PutPoint[frame,mx,my];
};

JGetMouse: PROCEDURE [frame: Frame] = {
mx,my: REAL;
[mx,my] ← RealViewerMouse[frame,FALSE];
PutPoint[frame,mx,my];
};

JSetFont: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
PopString[info];
info.font ← G.MakeFont[Rope.FromRefText[info.text]];
};

JGetYMode: PROCEDURE [frame: Frame] = {
paint: GProc ={mode ← E.GetYMode[dc]};
mode: E.YMode;
Painter[paint,frame];
J.PushInteger[frame.opstk, IF mode=topDown THEN 1 ELSE 0];
};

JSetYMode: PROCEDURE [frame: Frame] = {
mode: LONG INTEGERJ.PopInteger[frame.opstk];
paint: GProc ={E.SetYMode[dc,IF mode>0 THEN topDown ELSE bottomUp]};
Painter[paint,frame];
};

JDrawChar: PROCEDURE [frame: Frame] = {
paint: GProc ={E.DrawText[self: dc, text: info.text, font: info.font]};
info: Info ← GetInfo[frame];
PopString[info];
IF info.text.length>0 THEN info.text.length ← 1;
Painter[paint,frame];
};

JDrawText: PROCEDURE [frame: Frame] = {
paint: GProc ={E.DrawText[self: dc, text: info.text, font: info.font]};
info: Info ← GetInfo[frame];
PopString[info];
Painter[paint,frame];
};

JCharBox: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
PopString[info];
IF info.text.length>0 THEN info.text.length ← 1;
PushTextBox[frame,info.text];
};

JTextBox: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
PopString[info];
PushTextBox[frame,info.text];
};

JCharWidth: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
PopString[info];
IF info.text.length>0 THEN info.text.length ← 1;
PushTextWidth[frame,info.text];
};

JTextWidth: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
PopString[info];
PushTextWidth[frame,info.text];
};

PushTextBox: PROCEDURE[frame: Frame, text: REF READONLY TEXT] = {
info: Info ← GetInfo[frame];
xmin,xmax,ymin,ymax: REAL;
[xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax] ← E.TextBox[info.font,info.text];
J.PushReal[frame.opstk,xmin];
J.PushReal[frame.opstk,ymin];
J.PushReal[frame.opstk,xmax];
J.PushReal[frame.opstk,ymax];
};

PushTextWidth: PROCEDURE[frame: Frame, text: REF READONLY TEXT] = {
info: Info ← GetInfo[frame];
xw,yw: REAL;
[xw: xw, yw: yw] ← E.TextWidth[info.font,info.text];
J.PushReal[frame.opstk,xw];
J.PushReal[frame.opstk,yw];
};

JFontBox: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
xmin,xmax,ymin,ymax: REAL;
[xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax] ← G.FontBox[info.font];
J.PushReal[frame.opstk,xmin];
J.PushReal[frame.opstk,ymin];
J.PushReal[frame.opstk,xmax];
J.PushReal[frame.opstk,ymax];
};

PutBox: PROC[frame: Frame, b: G.Box] = {
PutPoint[frame,b.xmin,b.ymin];
PutPoint[frame,b.xmax,b.ymax];
};

GetBox: PROC [frame: Frame] RETURNS[G.Box] = {
b: G.Box;
[b.xmax,b.ymax] ← GetPoint[frame];
[b.xmin,b.ymin] ← GetPoint[frame];
RETURN[b];
};

JStartBoxing: PROCEDURE [frame: Frame] = {
-- info: Info ← GetInfo[frame];
-- E.BeginBox[dc];
};

JStopBoxing: PROCEDURE [frame: Frame] = {
-- info: Info ← GetInfo[frame];
-- b: G.Box ← E.EndBox[dc];
-- PutBox[frame,b];
};

JPushBox: PROCEDURE [frame: Frame] = {
-- b: G.Box ← GetBox[frame];
-- G.PushClipBox[dc,b];
-- **** temporarily removed ****
};

JPopBox: PROCEDURE [frame: Frame] = {
-- G.PopClipBox[dc];
-- **** temporarily removed ****
};

JVisible: PROCEDURE [frame: Frame] = {
b: BOOLEAN;
paint: GProc = {b ← G.Visible[dc]};
Painter[paint,frame];
J.PushBoolean[frame.opstk,b];
};

JFlushPath: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
G.FlushPath[info.path];
};

JMoveTo: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
x,y: REAL; [x,y]←GetPoint[frame];
G.MoveTo[info.path,x,y];
};

JMoveToNext: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
x,y: REAL; [x,y]←GetPoint[frame];
G.MoveTo[info.path,x,y,FALSE];
};

JLineTo: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
x,y: REAL; [x,y]←GetPoint[frame];
G.LineTo[info.path,x,y];
};

JCurveTo: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
x1,y1,x2,y2,x3,y3: REAL;
[x3,y3]←GetPoint[frame];
[x2,y2]←GetPoint[frame];
[x1,y1]←GetPoint[frame];
G.CurveTo[info.path,x1,y1,x2,y2,x3,y3];
};

JRectangle: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
x0,y0,x1,y1: REAL;
[x1,y1]←GetPoint[frame];
[x0,y0]←GetPoint[frame];
G.Rectangle[info.path,x0,y0,x1,y1];
};

JDrawArea: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
paint: GProc = {G.DrawArea[dc, info.path]};
Painter[paint,frame];
};

JDrawEOArea: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
paint: GProc = {G.DrawArea[dc,info.path,TRUE]};
Painter[paint,frame];
};

JDrawStroke: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
paint: GProc = {G.DrawStroke[dc,info.path,width,FALSE,ends]};
i: INTEGERJ.PopInteger[frame.opstk];
width: REALJ.PopReal[frame.opstk];
ends: G.StrokeEnds ← (IF i=1 THEN square ELSE IF i=2 THEN round ELSE butt);
Painter[paint,frame];
};

JDrawStrokeClosed: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
paint: GProc = {G.DrawStroke[dc,info.path,width,TRUE]};
width: REALJ.PopReal[frame.opstk];
Painter[paint,frame];
};

JKnot: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
y: REALJ.PopReal[frame.opstk];
x: REALJ.PopReal[frame.opstk];
Spline.Knot[info.spline,x,y];
};

JSpline: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
Spline.Enter[info.spline,info.path,FALSE];
};

JCSpline: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
Spline.Enter[info.spline,info.path,TRUE];
};

bmw: CARDINAL = 250;
bmh: CARDINAL = 200;

GetBitmapSize: PUBLIC PROC RETURNS [w, h: CARDINAL] = {RETURN[bmw,bmh]};

JBitmap: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
paint: GProc = {E.DrawBitmap[dc,info.bitmap,bmw,bmh,0,0,0,bmh]};
Painter[paint,frame];
};

JSetTarget: PROC [frame: Frame] = {
info: Info ← GetInfo[frame];
b: BOOLEANJ.PopBoolean[frame.opstk];
paint: GProc = {E.SetTargetBitmap[dc,IF b THEN info.bitmap ELSE NIL]};
Painter[paint,frame];
};

JScreenCoords: PROCEDURE [frame: Frame] = {
y: REALJ.PopReal[frame.opstk];
x: REALJ.PopReal[frame.opstk];
paint: GProc = {[x, y] ← Graphics.UserToWorld[dc, x, y]}; -- get screen coordinates
Painter[paint,frame];
J.PushReal[frame.opstk,x];
J.PushReal[frame.opstk,y];
};

JUserCoords: PROCEDURE [frame: Frame] = {
y: REALJ.PopReal[frame.opstk];
x: REALJ.PopReal[frame.opstk];
paint: GProc = {[x, y] ← Graphics.WorldToUser[dc, x, y]}; -- get user coordinates
Painter[paint,frame];
J.PushReal[frame.opstk,x];
J.PushReal[frame.opstk,y];
};

-- Initialization starts here

Init: PROC = {
frame: Frame ← J.defaultFrame;

J.RegisterExplicit[frame,".pushdc"L,PushDC];
J.RegisterExplicit[frame,".popdc"L,PopDC];
-- J.RegisterExplicit[frame,".setview"L,JSetVw];
J.RegisterExplicit[frame,".translate"L,JTranslate];
J.RegisterExplicit[frame,".scale"L,JScale];
J.RegisterExplicit[frame,".rotate"L,JRotate];
J.RegisterExplicit[frame,".sixpoint"L,JSixPoint];
J.RegisterExplicit[frame,".concat"L,JConcat];
J.RegisterExplicit[frame,".getpos"L,JGetPos];
J.RegisterExplicit[frame,".setpos"L,JSetPos];
J.RegisterExplicit[frame,".rsetpos"L,JRelSetPos];
J.RegisterExplicit[frame,".drawto"L,JDrawTo];
J.RegisterExplicit[frame,".rdrawto"L,JRelDrawTo];
J.RegisterExplicit[frame,".drawbox"L,JDrawBox];
J.RegisterExplicit[frame,".cover"L,JCover];
J.RegisterExplicit[frame,".setinvert"L,JSetInvert];
J.RegisterExplicit[frame,".setfat"L,JSetFat];
J.RegisterExplicit[frame,".setopaque"L,JSetOpaque];
J.RegisterExplicit[frame,".touch"L,JGetTouch];
J.RegisterExplicit[frame,".mouse"L,JGetMouse];
J.RegisterExplicit[frame,".setfont"L,JSetFont];
J.RegisterExplicit[frame,".drawchar"L,JDrawChar];
J.RegisterExplicit[frame,".drawtext"L,JDrawText];
J.RegisterExplicit[frame,".charbox"L,JCharBox];
J.RegisterExplicit[frame,".textbox"L,JTextBox];
J.RegisterExplicit[frame,".charwidth"L,JCharWidth];
J.RegisterExplicit[frame,".textwidth"L,JTextWidth];
J.RegisterExplicit[frame,".fontbox"L,JFontBox];
-- J.RegisterExplicit[frame,".initboxer"L,JStartBoxing];
-- J.RegisterExplicit[frame,".stopboxer"L,JStopBoxing];
-- J.RegisterExplicit[frame,".pushbox"L,JPushBox];
-- J.RegisterExplicit[frame,".popbox"L,JPopBox];

J.RegisterExplicit[frame,".visible"L,JVisible];
J.RegisterExplicit[frame,".cliparea"L,JClipArea];
J.RegisterExplicit[frame,".clipbox"L,JClipBox];
J.RegisterExplicit[frame,".flushpath"L,JFlushPath];
J.RegisterExplicit[frame,".moveto"L,JMoveTo];
J.RegisterExplicit[frame,".movetonext"L,JMoveToNext];
J.RegisterExplicit[frame,".lineto"L,JLineTo];
J.RegisterExplicit[frame,".curveto"L,JCurveTo];
J.RegisterExplicit[frame,".rect"L,JRectangle];
J.RegisterExplicit[frame,".drawarea"L,JDrawArea];
J.RegisterExplicit[frame,".draweoarea"L,JDrawEOArea];
J.RegisterExplicit[frame,".drawstroke"L,JDrawStroke];
J.RegisterExplicit[frame,".drawstrokeclosed"L,JDrawStrokeClosed];
J.RegisterExplicit[frame,".knot"L,JKnot];
J.RegisterExplicit[frame,".spline"L,JSpline];
J.RegisterExplicit[frame,".cspline"L,JCSpline];
J.RegisterExplicit[frame,".bitmap"L,JBitmap];
J.RegisterExplicit[frame,".clipeoarea"L,JClipEOArea];
J.RegisterExplicit[frame,".clipxarea"L,JClipXArea];
J.RegisterExplicit[frame,".clipxbox"L,JClipXBox];
J.RegisterExplicit[frame,".getymode"L,JGetYMode];
J.RegisterExplicit[frame,".setymode"L,JSetYMode];
J.RegisterExplicit[frame,".settarget"L,JSetTarget];
J.RegisterExplicit[frame,".screencoords"L,JScreenCoords];
J.RegisterExplicit[frame,".usercoords"L,JUserCoords];
};

Init;

}.