-- SplineFontWriterCmds.mesa <<-- Written by Michael Plass on November 8, 1982 10:58 am>> <<-- Last edit by Michael Plass on November 8, 1982 4:12 pm>> DIRECTORY IO, FileIO, Transaction, JaMBasic, JaMInternal, JaMOps, Real, Rope, TJaMGraphicsPrivate, CGCubic, CGPath, GraphicsBasic; SplineFontWriterCmds: PROGRAM IMPORTS JaMOps, IO, FileIO, Transaction, Real, Rope, TJaMGraphicsPrivate, CGCubic, CGPath = BEGIN ROPE: TYPE = Rope.ROPE; Frame: TYPE = JaMInternal.Frame; fontFile: IO.STREAM _ NIL; face: ROPE _ "M R R"; family: ROPE _ "UNKNOWN"; originx, originy: REAL _ 0.0; fiducial: INT _ 15840; -- this is 2*2*2*2*2*3*3*5*11 - lots of small factors. quad: REAL _ 1.0; PopRope: PROCEDURE [f: Frame] RETURNS [rope: ROPE] = { s: string JaMBasic.Object _ JaMOps.PopString[f.opstk]; C: PROC[c: CHAR] RETURNS [BOOLEAN] = {t[t.length]_c; t.length _ t.length+1; RETURN[FALSE]}; t: REF TEXT _ NEW[TEXT[s.length]]; t.length _ 0; JaMOps.StringForAll[s, C]; rope _ Rope.FromRefText[t]; }; Open: PROCEDURE [f: Frame] = { fileName: ROPE _ PopRope[f]; IF fontFile # NIL THEN fontFile.Close[]; fontFile _ NIL; IF fileName.Length[] > 0 THEN fontFile _ FileIO.Open[fileName, append]; }; Family: PROCEDURE [f: Frame] = { family _ PopRope[f]; }; Face: PROCEDURE [f: Frame] = { face _ PopRope[f]; }; Origin: PROCEDURE [f: Frame] = { originy _ JaMOps.PopReal[f.opstk]; originx _ JaMOps.PopReal[f.opstk]; }; Quad: PROCEDURE [f: Frame] = { quad _ JaMOps.PopReal[f.opstk]; }; Close: PROCEDURE [f: Frame] = { IF fontFile # NIL THEN fontFile.Close[]; fontFile _ NIL; }; Char: PROCEDURE [f: Frame] = { widthy: REAL _ JaMOps.PopReal[f.opstk]; widthx: REAL _ JaMOps.PopReal[f.opstk]; charCode: NAT _ JaMOps.PopInteger[f.opstk]; info: TJaMGraphicsPrivate.Info _ TJaMGraphicsPrivate.GetInfo[f]; path: GraphicsBasic.Path _ info.path; CountCon: PROC RETURNS [maxBeziers: NAT _ 0] = { beziers: NAT _ 0; MoveTo1: SAFE PROC [vec: GraphicsBasic.Vec] = CHECKED {maxBeziers _ MAX[maxBeziers, beziers]; beziers _ 0}; LineTo1: SAFE PROC [vec: GraphicsBasic.Vec] = CHECKED {beziers _ beziers+1}; CurveTo1: SAFE PROC [b1, b2, b3: GraphicsBasic.Vec] = CHECKED {beziers _ beziers+1}; CGPath.Generate[path, MoveTo1, LineTo1, CurveTo1]; maxBeziers _ MAX[maxBeziers, beziers]; }; BezierSequenceRec: TYPE = RECORD[SEQUENCE length: NAT OF CGCubic.Bezier]; bezier: REF BezierSequenceRec _ NEW[BezierSequenceRec[CountCon[]]]; k: NAT _ 0; curpt: GraphicsBasic.Vec; MoveTo2: SAFE PROC [vec: GraphicsBasic.Vec] = CHECKED { WriteCurrentOutline[]; curpt _ Grid[vec]; }; LineTo2: SAFE PROC [vec: GraphicsBasic.Vec] = CHECKED { b3: GraphicsBasic.Vec _ Grid[vec]; bezier[k] _ [b0: curpt, b1: [(curpt.x+curpt.x+b3.x)/3, (curpt.y+curpt.y+b3.y)/3], b2: [(curpt.x+b3.x+b3.x)/3, (curpt.y+b3.y+b3.y)/3], b3: b3]; k _ k+1; curpt _ b3; }; CurveTo2: SAFE PROC [b1, b2, b3: GraphicsBasic.Vec] = CHECKED { b3 _ Grid[b3]; bezier[k] _ [b0: curpt, b1: Transform[b1], b2: Transform[b2], b3: b3]; k _ k+1; curpt _ b3; }; Transform: SAFE PROC [vec: GraphicsBasic.Vec] RETURNS [gridVec: GraphicsBasic.Vec] = CHECKED { gridVec.x _ (vec.x-originx)*fiducial/quad; gridVec.y _ (vec.y-originy)*fiducial/quad; }; Grid: SAFE PROC [vec: GraphicsBasic.Vec] RETURNS [gridVec: GraphicsBasic.Vec] = CHECKED { gridVec.x _ Real.RoundLI[(vec.x-originx)*fiducial/quad]; gridVec.y _ Real.RoundLI[(vec.y-originy)*fiducial/quad]; }; WriteCurrentOutline: SAFE PROC = CHECKED { IF k=0 THEN RETURN; fontFile.PutF["\n ((%d (", IO.int[k+1]]; FOR i: NAT IN [0..k) DO fontFile.PutF["(%d %d) ", IO.int[Real.RoundLI[bezier[i].b0.x]], IO.int[Real.RoundLI[bezier[i].b0.y]]]; ENDLOOP; fontFile.PutF["(%d %d)", IO.int[Real.RoundLI[bezier[0].b0.x]], IO.int[Real.RoundLI[bezier[0].b0.y]]]; fontFile.PutRope[")\n NIL ("]; FOR i: NAT IN [0..k) DO coeffs: CGCubic.Coeffs _ CGCubic.BezierToCoeffs[bezier[i]]; IF i>0 THEN fontFile.PutRope[" "]; fontFile.PutF["(%g %g", IO.real[coeffs.c1.x], IO.real[coeffs.c1.y]]; fontFile.PutF[" %g %g", IO.real[coeffs.c2.x*2.0], IO.real[coeffs.c2.y*2.0]]; fontFile.PutF[" %g %g)", IO.real[coeffs.c3.x*6.0], IO.real[coeffs.c3.y*6.0]]; ENDLOOP; fontFile.PutRope[")\n NATURAL))"]; k _ 0; }; fontFile.PutRope["\n((FAMILY "]; fontFile.PutRope[family];fontFile.PutRope[")\n"]; fontFile.PutF[" (CHARACTER %d)\n", IO.int[charCode]]; fontFile.PutRope[" (FACE "]; fontFile.PutRope[face];fontFile.PutRope[")\n"]; fontFile.PutF[" (WIDTH %d %d)\n", IO.int[Real.RoundLI[widthx*fiducial/quad]], IO.int[Real.RoundLI[widthy*fiducial/quad]]]; fontFile.PutF[" (FIDUCIAL %d %d)\n", IO.int[fiducial], IO.int[fiducial]]; fontFile.PutRope[" (SPLINES"]; CGPath.Generate[self: path, move: MoveTo2, line: LineTo2, curve: CurveTo2]; WriteCurrentOutline[]; fontFile.PutRope["))\n"]; }; <<>> <> JaMOps.RegisterExplicit[JaMOps.defaultFrame, "SF.Open", Open]; -- -> . Opens .sf file in append mode JaMOps.RegisterExplicit[JaMOps.defaultFrame, "SF.Family", Family]; -- -> . sets the family for subsequent DrawChar operations. JaMOps.RegisterExplicit[JaMOps.defaultFrame, "SF.Face", Face]; -- -> . sets the face for subsequent DrawChar operations. JaMOps.RegisterExplicit[JaMOps.defaultFrame, "SF.Origin", Origin]; -- -> . says what the character origins are. JaMOps.RegisterExplicit[JaMOps.defaultFrame, "SF.Quad", Quad]; -- -> . says what the units are. JaMOps.RegisterExplicit[JaMOps.defaultFrame, "SF.Close", Close]; -- -> . closes .sf file. JaMOps.RegisterExplicit[JaMOps.defaultFrame, "SF.Char", Char]; -- . -> . Takes the current path and writes it out as a character in .sf format. END.