-- JaMGraphicsImpl.mesa
-- Last changed by Doug Wyatt, 19-Jan-82 15:20:56

DIRECTORY
  JaMGraphics USING [Mouse, Update],
  Graphics,
  GraphicsExtra,
  CGBasic USING [Vec],
  CGScreen USING [MouseToWorld],
  CGVector USING [Sub, Cross],
  Spline USING [Ref, New, Knot, Enter],
  JaMFnsDefs USING [PopInteger, PushInteger, PushReal, GetReal, PopString,
    PushBoolean, PopBoolean, Register],
  JaMTajo USING [SetMouseProc];

JaMGraphicsImpl: PROGRAM
IMPORTS JaMFnsDefs, JaMTajo, JaMGraphics,
  Graphics, GraphicsExtra, CGVector, CGScreen, Spline
EXPORTS JaMGraphics = {
OPEN J: JaMFnsDefs, G: Graphics, E: GraphicsExtra,
  Vector: CGVector, Screen: CGScreen, JaMGraphics;

Vec: TYPE = CGBasic.Vec;

dc: G.Context←NIL;
box: G.Box;
image: G.ImageRef;

GetDC: PUBLIC PROCEDURE RETURNS[G.Context] = { RETURN[dc] };

InitDC: PROCEDURE = {
  dc ← G.NewContext[];
  G.ClipBox[dc,box];
  };

PushDC: PROCEDURE = {
  [] ← G.Save[dc];
  };

PopDC: PROCEDURE = {
  G.Restore[dc];
  };

GetVec: PROCEDURE RETURNS[Vec] = {
  y: REAL ← J.GetReal[]; x: REAL ← J.GetReal[]; RETURN[[x,y]] };

GetPoint: PROCEDURE RETURNS[x,y: REAL] = {
  y ← J.GetReal[]; x ← J.GetReal[]; RETURN[x,y] };

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

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

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

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

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

JClipArea: PROCEDURE = {
  G.ClipArea[dc];
  };

JClipEOArea: PROCEDURE = {
  G.ClipArea[self: dc, parityFill: TRUE];
  };

JClipXArea: PROCEDURE = {
  G.ClipArea[self: dc, exclude: TRUE];
  };

JClipBox: PROCEDURE = {
  box: G.Box ← GetBox[];
  G.ClipBox[dc,box];
  };

JClipXBox: PROCEDURE = {
  box: G.Box ← GetBox[];
  G.ClipBox[dc,box,TRUE];
  };

JTranslate: PROCEDURE = {
  tx,ty: REAL; [tx,ty]←GetPoint[];
  G.Translate[dc,tx,ty];
  };

JScale: PROCEDURE = {
  sx,sy: REAL; [sx,sy]←GetPoint[];
  G.Scale[dc,sx,sy];
  };

JRotate: PROCEDURE = {
  a: REAL ← J.GetReal[];
  G.Rotate[dc,a];
  };

JSixPoint: PROCEDURE = {
  f1,f2,f3,t1,t2,t3,df1,df2,dt1,dt2: Vec;
  adet: REAL;
  xx,xy,yx,yy,tx,ty: REAL;
  t3←GetVec[];
  t2←GetVec[];
  t1←GetVec[];
  f3←GetVec[];
  f2←GetVec[];
  f1←GetVec[];
  [[tx,ty]]←Vector.Sub[t1,f1];
  dt1←Vector.Sub[t2,t1];
  df1←Vector.Sub[f2,f1];
  dt2←Vector.Sub[t3,t1];
  df2←Vector.Sub[f3,f1];
  adet←1.0/Vector.Cross[df1,df2];
  xx←(dt1.x*df2.y-dt2.x*df1.y)*adet;
  xy←(df1.x*dt2.x-df2.x*dt1.x)*adet;
  yx←(dt1.y*df2.y-dt2.y*df1.y)*adet;
  yy←(df1.x*dt2.y-df2.x*dt1.y)*adet;
  G.Translate[dc,tx,ty];
  G.Concat[dc,xx,xy,yx,yy]
  };

JConcat: PROCEDURE = {
  xx,xy,yx,yy: REAL;
  yy ← J.GetReal[];
  yx ← J.GetReal[];
  xy ← J.GetReal[];
  xx ← J.GetReal[];
  G.Concat[dc,xx,xy,yx,yy];
  };


JGetPos: PROCEDURE = {
  x,y: REAL; [x,y]←G.GetCP[dc];
  PutPoint[x,y];
  };

JMoveTo: PROCEDURE = {
  x,y: REAL; [x,y]←GetPoint[];
  G.MoveTo[dc,x,y];
  };

JDrawTo: PROCEDURE = {
  x,y: REAL; [x,y]←GetPoint[];
  G.DrawTo[dc,x,y];
  Update[];
  };

JRelMoveTo: PROCEDURE = {
  x,y: REAL; [x,y]←GetPoint[];
  G.MoveTo[dc,x,y,TRUE];
  };

JRelDrawTo: PROCEDURE = {
  x,y: REAL; [x,y]←GetPoint[];
  G.DrawTo[dc,x,y,TRUE];
  Update[];
  };

JDrawBox: PROCEDURE = {
  box: G.Box ← GetBox[];
  G.DrawBox[dc,box];
  Update[];
  };

JCover: PROCEDURE = {
  G.DrawBox[dc,G.GetBounds[dc]];
  Update[];
  };

JSetInvert: PROCEDURE = {
  [] ← G.SetPaintMode[dc, invert];
  };

JSetColor: PROCEDURE = {
  t: CARDINAL←LOOPHOLE[J.PopInteger[],CARDINAL];
  G.SetColor[dc,t];
  };

JSetFat: PROCEDURE = {
  b: BOOLEAN ← J.PopBoolean[];
  [] ← G.SetFat[dc,b];
  };

JSetOpaque: PROCEDURE = {
  b: BOOLEAN ← J.PopBoolean[];
  [] ← G.SetPaintMode[dc,IF b THEN opaque ELSE transparent];
  };

JErase: PROCEDURE = {
  mark: G.Mark ← G.Save[dc];
  G.SetColor[dc,0];
  JCover[];
  G.Restore[dc,mark];
  };

JGetTouch: PROCEDURE = {
  mx,my: INTEGER;
  [mx,my] ← Mouse[TRUE];
  PutCoords[mx,my];
  };

JGetMouse: PROCEDURE = {
  mx,my: INTEGER;
  [mx,my] ← Mouse[FALSE];
  PutCoords[mx,my];
  };

PutCoords: PROC[mx,my: INTEGER] = {
  x,y: REAL;
  [x,y] ← ScreenCoordsToUser[mx,my];
  PutPoint[x,y];
  };

MouseToUser: PROCEDURE[x,y:INTEGER] = {
  ux,uy: REAL; [ux,uy]←ScreenCoordsToUser[x,y];
  PutPoint[ux,uy];
  };

half: REAL=0.5;

ScreenCoordsToUser: PROCEDURE[sx,sy: INTEGER] RETURNS[x,y: REAL] = {
  x0,y0: INTEGER;
  [x0,y0] ← Screen.MouseToWorld[sx,sy];
  [x,y] ← G.WorldToUser[dc,x0,y0];
  RETURN[x,y];
  };

font: E.FontRef ← E.DefaultStrikeFont[];

text: REF TEXT ← NEW[TEXT[256]];

JSetFont: PROCEDURE = {
  J.PopString[LOOPHOLE[text]];
  font ← E.NewStrikeFont[text];
  };

JGetYMode: PROCEDURE = {
  mode: E.YMode ← E.GetYMode[dc];
  J.PushInteger[IF mode=topDown THEN 1 ELSE 0];
  };

JSetYMode: PROCEDURE = {
  mode: INTEGER ← J.PopInteger[];
  E.SetYMode[dc,IF mode>0 THEN topDown ELSE bottomUp];
  };

JDrawChar: PROCEDURE = {
  J.PopString[LOOPHOLE[text]];
  IF text.length>0 THEN text.length ← 1;
  G.DrawText[self: dc, text: text, font: font];
  Update[];
  };

JDrawText: PROCEDURE = {
  J.PopString[LOOPHOLE[text]];
  G.DrawText[self: dc, text: text, font: font];
  Update[];
  };

JCharBox: PROCEDURE = {
  J.PopString[LOOPHOLE[text]];
  IF text.length>0 THEN text.length ← 1;
  PushTextBox[text];
  };

JTextBox: PROCEDURE = {
  J.PopString[LOOPHOLE[text]];
  PushTextBox[text];
  };

JCharWidth: PROCEDURE = {
  J.PopString[LOOPHOLE[text]];
  IF text.length>0 THEN text.length ← 1;
  PushTextWidth[text];
  };

JTextWidth: PROCEDURE = {
  J.PopString[LOOPHOLE[text]];
  PushTextWidth[text];
  };

PushTextBox: PROCEDURE[text: REF READONLY TEXT] = {
  xmin,xmax,ymin,ymax: REAL;
  [xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax] ← G.TextBox[font,text];
  J.PushReal[xmin];
  J.PushReal[ymin];
  J.PushReal[xmax];
  J.PushReal[ymax];
  };

PushTextWidth: PROCEDURE[text: REF READONLY TEXT] = {
  xw,yw: REAL;
  [xw: xw, yw: yw] ← G.TextWidth[font,text];
  J.PushReal[xw];
  J.PushReal[yw];
  };

JFontBox: PROCEDURE = {
  xmin,xmax,ymin,ymax: REAL;
  [xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax] ← G.FontBox[font];
  J.PushReal[xmin];
  J.PushReal[ymin];
  J.PushReal[xmax];
  J.PushReal[ymax];
  };

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

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

JStartBoxing: PROCEDURE = {
  G.BeginBox[dc];
  };

JStopBoxing: PROCEDURE = {
  b: G.Box ← G.EndBox[dc];
  PutBox[b];
  };

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

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

JVisible: PROCEDURE = {
  J.PushBoolean[G.Visible[dc]];
  };

JLineTo: PROCEDURE = {
  x,y: REAL; [x,y]←GetPoint[];
  G.LineTo[dc,x,y];
  };

JCurveTo: PROCEDURE = {
  x1,y1,x2,y2,x3,y3: REAL;
  [x3,y3]←GetPoint[];
  [x2,y2]←GetPoint[];
  [x1,y1]←GetPoint[];
  G.CurveTo[dc,x1,y1,x2,y2,x3,y3];
  };

JRectangle: PROCEDURE = {
  x0,y0,x1,y1: REAL;
  [x1,y1]←GetPoint[];
  [x0,y0]←GetPoint[];
  G.Rectangle[dc,x0,y0,x1,y1];
  };

JClose: PROCEDURE = {
  G.Close[dc];
  };

JDrawArea: PROCEDURE = {
  G.DrawArea[dc];
  Update[];
  };

JDrawEOArea: PROCEDURE = {
  G.DrawArea[dc,TRUE];
  Update[];
  };

JDrawPath: PROCEDURE = {
  width: REAL ← J.GetReal[];
  G.DrawPath[dc,width];
  Update[];
  };

spline: Spline.Ref ← Spline.New[];

JKnot: PROCEDURE = {
  y: REAL ← J.GetReal[];
  x: REAL ← J.GetReal[];
  Spline.Knot[spline,x,y];
  };

JSpline: PROCEDURE = {
  Spline.Enter[spline,dc,FALSE];
  };

JCSpline: PROCEDURE = {
  Spline.Enter[spline,dc,TRUE];
  };

bitmap: E.BitmapRef ← NIL;
bmw: CARDINAL = 250;
bmh: CARDINAL = 200;

JBitmap: PROCEDURE = {
  E.DrawBitmap[dc,bitmap,bmw,bmh,0,0,0,bmh];
  Update[];
  };

JSetTarget: PROC = {
  b: BOOLEAN ← J.PopBoolean[];
  E.SetTargetBitmap[dc,IF b THEN bitmap ELSE NIL];
  };

JNewAISImage: PROC = {
  J.PopString[LOOPHOLE[text]];
  image ← E.NewAisImage[text];
  };

JDrawImage: PROC = {
  IF image=NIL THEN RETURN;
  G.DrawImage[dc,image];
  Update[];
  };

-- Initialization starts here

dc ← G.NewContext[];
box ← G.GetBounds[dc];
G.ClipBox[dc,box];
bitmap ← E.NewBitmap[bmw,bmh];

[] ← JaMTajo.SetMouseProc[MouseToUser];

J.Register[".initdc"L,InitDC];
J.Register[".pushdc"L,PushDC];
J.Register[".popdc"L,PopDC];
J.Register[".setview"L,JSetVw];
J.Register[".translate"L,JTranslate];
J.Register[".scale"L,JScale];
J.Register[".rotate"L,JRotate];
J.Register[".sixpoint"L,JSixPoint];
J.Register[".concat"L,JConcat];
J.Register[".getpos"L,JGetPos];
J.Register[".moveto"L,JMoveTo];
J.Register[".rmoveto"L,JRelMoveTo];
J.Register[".drawto"L,JDrawTo];
J.Register[".rdrawto"L,JRelDrawTo];
J.Register[".drawbox"L,JDrawBox];
J.Register[".cover"L,JCover];
J.Register[".setinvert"L,JSetInvert];
J.Register[".setcolor"L,JSetColor];
J.Register[".setfat"L,JSetFat];
J.Register[".setopaque"L,JSetOpaque];
J.Register[".touch"L,JGetTouch];
J.Register[".mouse"L,JGetMouse];
J.Register[".erase"L,JErase];
J.Register[".setfont"L,JSetFont];
J.Register[".drawchar"L,JDrawChar];
J.Register[".drawtext"L,JDrawText];
J.Register[".charbox"L,JCharBox];
J.Register[".textbox"L,JTextBox];
J.Register[".charwidth"L,JCharWidth];
J.Register[".textwidth"L,JTextWidth];
J.Register[".fontbox"L,JFontBox];
J.Register[".initboxer"L,JStartBoxing];
J.Register[".stopboxer"L,JStopBoxing];
J.Register[".pushbox"L,JPushBox];
J.Register[".popbox"L,JPopBox];
J.Register[".visible"L,JVisible];
J.Register[".cliparea"L,JClipArea];
J.Register[".clipbox"L,JClipBox];
J.Register[".lineto"L,JLineTo];
J.Register[".curveto"L,JCurveTo];
J.Register[".rect"L,JRectangle];
J.Register[".close"L,JClose];
J.Register[".drawarea"L,JDrawArea];
J.Register[".draweoarea"L,JDrawEOArea];
J.Register[".drawpath"L,JDrawPath];
J.Register[".knot"L,JKnot];
J.Register[".spline"L,JSpline];
J.Register[".cspline"L,JCSpline];
J.Register[".bitmap"L,JBitmap];
J.Register[".clipeoarea"L,JClipEOArea];
J.Register[".clipxarea"L,JClipXArea];
J.Register[".clipxbox"L,JClipXBox];
J.Register[".getymode"L,JGetYMode];
J.Register[".setymode"L,JSetYMode];
J.Register[".settarget"L,JSetTarget];

J.Register[".newaisimage"L,JNewAISImage];
J.Register[".drawimage"L,JDrawImage];

}.