-- Callig.mesa, for drawing thick lines from JaM.
-- Maureen Stone August 27, 1982 11:23 am
-- Michael Plass 10-Mar-82 9:17:44
-- Rick Beach, May 26, 1982 10:50 am
DIRECTORY
Complex, Cubic, Graphics, JaMFnsDefs, JaMGraphics, PolygonPen, Real, RealFns, Rope, SirPress, Vector;
Callig: PROGRAM
IMPORTS Complex, Cubic, Graphics, JaMFnsDefs, JaMGraphics, PolygonPen, Real, RealFns, Rope, SirPress = {
Vec: TYPE = Vector.Vec;
PathType: TYPE = {moveTo, lineTo, curveTo};
PathNode: TYPE = RECORD [
next: REF PathNode ← NIL,
pathInfo: SELECT pathType: PathType FROM
moveTo => [z0: Vector.Vec],
lineTo => [z1: Vector.Vec],
curveTo => [b1, b2, b3: Vector.Vec],
ENDCASE];
curPath, lastPathNode: REF PathNode ← NIL;
pi: REAL = 3.14159625;
RoundPenCacheRef: TYPE = REF RoundPenCacheRec;
RoundPenCacheRec: TYPE = RECORD [
next: RoundPenCacheRef,
numCorners: CARDINAL,
multiplier: Vec,
record: PolygonPen.Pen];
pens: RoundPenCacheRef ← NIL;
curLoc: Vec;
p: SirPress.PressHandle ← NIL;
press: BOOLEAN ← FALSE;
pen: PolygonPen.Pen;
context: Graphics.Context;
Mica: PROCEDURE[pt:REAL] RETURNS [LONG INTEGER] = INLINE {
RETURN[Real.RoundLI[pt*2540.0/72.0]]};
JBeginObject: PROC = {
IF press THEN SirPress.StartOutline[p]
ELSE context ← JaMGraphics.GetDC[]};
JEndObject: PROC = {
IF press THEN SirPress.EndOutline[p]
ELSE {context ← JaMGraphics.GetDC[]; Graphics.DrawArea[context]; JaMGraphics.Update[]};
};
JMoveTo: PROC = {
t: Vec ← PopVec[];
PathMoveTo[t];
MoveTo[t]};
PathMoveTo: PolygonPen.MoveToProc = {
-- begin a new path. throw away any path defined previously
IF curPath#NIL THEN curPath ← lastPathNode ← NIL;
curPath ← lastPathNode ← NEW[moveTo PathNode];
lastPathNode^ ← [next: NIL, pathInfo: moveTo[z0]];
};
MoveTo: PolygonPen.MoveToProc = {
IF press THEN {
SirPress.EndOutline[p];
SirPress.StartOutline[p];
SirPress.PutMoveTo[p,Mica[z0.x],Mica[z0.y]]}
ELSE {
context ← JaMGraphics.GetDC[];
Graphics.MoveTo[context,0,0];
Graphics.DrawArea[context]; JaMGraphics.Update[];
Graphics.MoveTo[context,z0.x,z0.y]};
curLoc ← z0;
};
JLineTo: PROC = {
PathLineTo[PopVec[]]};
PathLineTo: PolygonPen.LineToProc = {
-- add point z1 to the existing path, if one has been started
IF curPath#NIL THEN {
lastPathNode^.next ← NEW[lineTo PathNode];
lastPathNode^.next^ ← [next: NIL, pathInfo: lineTo[z1]];
lastPathNode ← lastPathNode^.next};
};
LineTo: PolygonPen.LineToProc = {
IF press THEN SirPress.PutDrawTo[p,Mica[z1.x],Mica[z1.y]]
ELSE Graphics.LineTo[JaMGraphics.GetDC[],z1.x,z1.y];
curLoc ← z1;
};
JCurveTo: PROC = {
b3:Vec ← PopVec[];
b2:Vec ← PopVec[];
PathCurveTo[PopVec[],b3,b3]};
PathCurveTo: PolygonPen.CurveToProc = {
-- add curve definition to an existing path
IF curPath#NIL THEN {
lastPathNode^.next ← NEW[curveTo PathNode];
lastPathNode^.next^ ← [next: NIL, pathInfo: curveTo[z1, z2, z3]];
lastPathNode ← lastPathNode^.next};
};
CurveTo: PolygonPen.CurveToProc = {
IF press THEN {
c: Cubic.Coeffs ← Cubic.BezierToCoeffs[[curLoc,z1,z2,z3]];
SirPress.PutCubic[p,
Mica[c.c1.x], Mica[c.c1.y],
Mica[c.c2.x], Mica[c.c2.y],
Mica[c.c3.x],Mica[c.c3.y]]}
ELSE Graphics.CurveTo[JaMGraphics.GetDC[],z1.x,z1.y,z2.x,z2.y,z3.x,z3.y];
curLoc ← z3;
};
JDrawPath: PROC = {
n: REF PathNode ← curPath;
pen ← RoundPen[JaMFnsDefs.PopReal[]];
IF press THEN SirPress.StartOutline[p];
WHILE n#NIL DO
WITH n SELECT FROM
moveTo => curLoc ← z0;
lineTo => {
PolygonPen.Line[pen, curLoc, z1, MoveTo, LineTo, CurveTo];
curLoc ← z1};
curveTo => {
PolygonPen.Stroke[pen, [curLoc, b1, b2, b3], MoveTo, LineTo, CurveTo];
curLoc ← b3};
ENDCASE;
n ← n.next;
ENDLOOP;
IF press THEN SirPress.EndOutline[p];
};
JDrawArea: PROC = {
n: REF PathNode ← curPath;
IF press THEN SirPress.StartOutline[p]
ELSE context ← JaMGraphics.GetDC[];
WHILE n#NIL DO
WITH n SELECT FROM
moveTo => {
IF press THEN SirPress.PutMoveTo[p, Mica[z0.x], Mica[z0.y]]
ELSE Graphics.MoveTo[context,z0.x,z0.y];
curLoc ← z0};
lineTo => {
IF press THEN SirPress.PutDrawTo[p, Mica[z1.x], Mica[z1.y]]
ELSE Graphics.LineTo[context,z1.x,z1.y];
curLoc ← z1};
curveTo => {
IF press THEN {
c: Cubic.Coeffs ← Cubic.BezierToCoeffs[[curLoc, b1, b2, b3]];
SirPress.PutCubic [p,
Mica[c.c1.x], Mica[c.c1.y],
Mica[c.c2.x], Mica[c.c2.y],
Mica[c.c3.x], Mica[c.c3.y]]}
ELSE Graphics.CurveTo[context,b1.x,b1.y,b2.x,b2.y,b3.x,b3.y];
curLoc ← b3;
};
ENDCASE;
n ← n.next;
ENDLOOP;
IF press THEN SirPress.EndOutline[p];
};
PopVec: PROCEDURE RETURNS [v:Vec] = {
v.y ← JaMFnsDefs.GetReal[];
v.x ← JaMFnsDefs.GetReal[]};
PopText: PROCEDURE RETURNS [t: REF TEXT] = {
t←NEW[TEXT[128]];
JaMFnsDefs.PopString[LOOPHOLE[t]];
};
JOpenPress: PROC = {
name: Rope.ROPE ← Rope.FromRefText[PopText[]];
p ← SirPress.NewPressHandle[FixFileName[name, ".Press"]];
press ← p#NIL};
FixFileName: PROC [oldname, extension: Rope.ROPE] RETURNS [newname:Rope.ROPE] = {
dotPosition: INTEGER ← Rope.Find[oldname, "."];
IF dotPosition < 0 THEN
newname ← Rope.Cat[oldname, extension]
ELSE
newname ← Rope.Cat[Rope.Substr[oldname, 0, dotPosition], extension];
};
JClosePress: PROC = {
IF press THEN SirPress.ClosePress[p];
p ← NIL;
press ← FALSE};
JNewPage: PROC = {
IF press THEN SirPress.WritePage[p]};
JPen: PROC = {
n: NAT ← JaMFnsDefs.PopInteger[];
pen ← NEW[PolygonPen.PenRec[n]];
FOR i:NAT DECREASING IN [0..n) DO pen[i] ← PopVec[]; ENDLOOP;
};
JRoundPen: PROC = {
pen ← RoundPen[JaMFnsDefs.PopReal[]]};
-- create a regular polygon of n sides, with n > pi*sqrt(w/2)
RoundPen: PROC[width: REAL] RETURNS[PolygonPen.Pen] = {
nCorners: CARDINAL ← Real.RoundC[0.5+(pi*RealFns.SqRt[width/2])];
r: RoundPenCacheRef ← pens;
i: CARDINAL;
WHILE r#NIL DO
IF r.numCorners=nCorners THEN RETURN[r.record];
r ← r.next;
ENDLOOP;
pens ← NEW[RoundPenCacheRec ← [pens, nCorners, Complex.Exp[[0,2*pi/nCorners]], NEW[PolygonPen.PenRec[nCorners]]] ];
pens.record[0] ← [width/2, 0];
FOR i IN [1 .. nCorners) DO
pens.record[i] ← Complex.Mul[pens.record[i-1], pens.multiplier];
ENDLOOP;
RETURN[pens.record];
};
JDrawDot: PROC = {
point: Vec ← PopVec[];
IF press THEN SirPress.StartOutline[p];
PolygonPen.Dot[pen,point,MoveTo,LineTo,CurveTo];
IF press THEN SirPress.EndOutline[p]
ELSE {Graphics.DrawArea[JaMGraphics.GetDC[]]; JaMGraphics.Update[]};
};
JDrawLine: PROC = {
t: Vec ← PopVec[];
s: Vec ← PopVec[];
IF press THEN SirPress.StartOutline[p];
PolygonPen.Line[pen,s,t,MoveTo,LineTo,CurveTo];
IF press THEN SirPress.EndOutline[p]
ELSE {Graphics.DrawArea[JaMGraphics.GetDC[]]; JaMGraphics.Update[]};
};
JDrawBezier: PROC = {
b3: Vec ← PopVec[];
b2: Vec ← PopVec[];
b1: Vec ← PopVec[];
b0: Vec ← PopVec[];
IF press THEN SirPress.StartOutline[p];
PolygonPen.Stroke[pen,[b0,b1,b2,b3],MoveTo,LineTo,CurveTo];
IF press THEN SirPress.EndOutline[p]
ELSE {Graphics.DrawArea[JaMGraphics.GetDC[]]; JaMGraphics.Update[]};
};
JDrawText: PROC = {
s: REF TEXT ← PopText[];
loc: Vec ← PopVec[];
IF press THEN SirPress.PutText[p,LOOPHOLE[s],Mica[loc.x],Mica[loc.y]]
ELSE {
context ← JaMGraphics.GetDC[];
Graphics.MoveTo[context,loc.x,loc.y];
Graphics.DrawText[context,LOOPHOLE[s]];
JaMGraphics.Update[]};
};
JSetFont: PROC = {
fontName: Rope.ROPE ← Rope.FromRefText[PopText[]];
IF press THEN {
len: INTEGER ← Rope.Length[fontName]-1;
family: Rope.ROPE;
face, size: INTEGER ← 0;
units: INTEGER ← 1;
DO SELECT Rope.Fetch[fontName, len] FROM
'B => {face ← face + 1; len ← len - 1};
'I => {face ← face + 2; len ← len - 1};
ENDCASE => EXIT;
ENDLOOP;
WHILE Rope.Digit[Rope.Fetch[fontName, len]] DO
size ← size+(Rope.Fetch[fontName, len]-'0)*units;
len ← len-1;
units ← units*10;
ENDLOOP;
family ← Rope.Substr[fontName, 0, len+1];
SirPress.SetFont[p,LOOPHOLE[family],size,face]}
ELSE {
Graphics.SetDefaultFont[JaMGraphics.GetDC[],Graphics.MakeFont[fontName]]};
};
JPressHue: PROC = {
IF press THEN SirPress.SetHue[p,JaMFnsDefs.PopInteger[]]};
JPressSaturation: PROC = {
IF press THEN SirPress.SetSaturation[p,JaMFnsDefs.PopInteger[]]};
JPressBrightness: PROC = {
IF press THEN SirPress.SetBrightness[p,JaMFnsDefs.PopInteger[]]};
JaMFnsDefs.Register[".openpress"L,JOpenPress]; -- .openpress
JaMFnsDefs.Register[".closepress"L,JClosePress]; -- .closepress
JaMFnsDefs.Register[".pressnewpage"L,JNewPage]; -- .pressnewpage
JaMFnsDefs.Register[".beginpressobject"L,JBeginObject]; -- .beginpressobject
JaMFnsDefs.Register[".endpressobject"L,JEndObject]; -- .endpressobject
JaMFnsDefs.Register[".calligmoveto"L,JMoveTo]; -- x y .calligmoveto
JaMFnsDefs.Register[".calliglineto"L,JLineTo]; -- x y .calliglineto
JaMFnsDefs.Register[".calligcurveto"L,JCurveTo]; -- b1.x b1.y b2.x b2.y b3.x b3.y .calligcurveto
JaMFnsDefs.Register[".calligdrawdot"L,JDrawDot]; -- x y .calligdrawdot
JaMFnsDefs.Register[".calligdrawline"L,JDrawLine]; -- sx sy tx ty .calligdrawline
JaMFnsDefs.Register[".calligdrawbezier"L,JDrawBezier]; -- b0.x b0.y b1.x b1.y b2.x b2.y b3.x b3.y .calligdrawbezier
JaMFnsDefs.Register[".calligdrawpath"L,JDrawPath]; -- width .calligdrawpath
JaMFnsDefs.Register[".calligdrawarea"L,JDrawArea]; -- .calligdrawarea
JaMFnsDefs.Register[".calligpen"L,JPen]; -- x1 y1 . . . xn yn n .calligpen
JaMFnsDefs.Register[".calligroundpen"L,JRoundPen]; -- width .calligroundpen
JaMFnsDefs.Register[".presshue"L,JPressHue]; -- hue[0-255] .presshue
JaMFnsDefs.Register[".presssaturation"L,JPressSaturation]; -- saturation[0-255] .presssaturation
JaMFnsDefs.Register[".pressbrightness"L,JPressBrightness]; -- brightness[0-255] .pressbrightness
JaMFnsDefs.Register[".calligtext"L,JDrawText]; -- string .calligtext
JaMFnsDefs.Register[".presssetfont"L,JSetFont]; -- fontname .presssetfont
pen ← NEW[PolygonPen.PenRec[2]];
pen[0] ← [-2,-2];
pen[1] ← [2,2];
}.