-- 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]; }.