-- SplineFontWriterJaM.mesa
-- Written by Michael Plass on November 8, 1982 10:58 am
-- Last edit by Michael Plass on December 2, 1982 1:17 pm
-- Last edit by Maureen Stone on May 16, 1984 10:58:49 am PDT
DIRECTORY
IO,
FS USING [StreamOpen],
FitJaM,
Curve,
JaM,
Real,
Rope,
Cubic,
Vector USING [Vec];
SplineFontWriterJaM: CEDAR PROGRAM
IMPORTS JaM, IO, FitJaM, Real, Rope, Curve, FS, Cubic
= BEGIN
ROPE: TYPE = Rope.ROPE;
fontFile: IO.STREAMNIL;
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;
Open: PROCEDURE [f: JaM.State] = {
fileName: ROPE ← JaM.PopRope[f];
IF fontFile # NIL THEN fontFile.Close[];
fontFile ← NIL;
IF fileName.Length[] > 0 THEN fontFile ← FS.StreamOpen[fileName, $append];
};
Family: PROCEDURE [f: JaM.State] = {
family ← JaM.PopRope[f];
};
Face: PROCEDURE [f: JaM.State] = {
face ← JaM.PopRope[f];
};
Origin: PROCEDURE [f: JaM.State] = {
originy ← JaM.PopReal[f];
originx ← JaM.PopReal[f];
};
Quad: PROCEDURE [f: JaM.State] = {
quad ← JaM.PopReal[f];
};
Close: PROCEDURE [f: JaM.State] = {
IF fontFile # NIL THEN fontFile.Close[];
fontFile ← NIL;
};
Char: PROCEDURE [f: JaM.State] = {
widthy: REAL ← JaM.PopReal[f];
widthx: REAL ← JaM.PopReal[f];
charCode: NAT ← JaM.PopInt[f];
BezierSequenceRec: TYPE = RECORD[SEQUENCE length: NAT OF Cubic.Bezier];
bezier: REF BezierSequenceRec ←
NEW[BezierSequenceRec[Curve.CountContours[Curve.defaultHandle]]];
k: NAT ← 0;
NewContour: PROC [] = {
WriteCurrentOutline[];
};
NewCubic: PROC [c: Cubic.Bezier] = {
bezier[k] ← [b0: Grid[c.b0], b1: Transform[c.b1], b2: Transform[c.b2], b3: Grid[c.b3]];
k ← k+1;
};
Transform: PROC [vec: Vector.Vec] RETURNS [gridVec: Vector.Vec] = {
gridVec.x ← (vec.x-originx)*fiducial/quad;
gridVec.y ← (vec.y-originy)*fiducial/quad;
};
Grid: PROC [vec: Vector.Vec] RETURNS [gridVec: Vector.Vec] = {
gridVec.x ← Real.RoundLI[(vec.x-originx)*fiducial/quad];
gridVec.y ← Real.RoundLI[(vec.y-originy)*fiducial/quad];
};
WriteCurrentOutline: PROC = {
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: Cubic.Coeffs ← Cubic.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"];
Curve.EnumerateContours[handle: Curve.defaultHandle, newContour: NewContour, newCubic: NewCubic];
WriteCurrentOutline[];
fontFile.PutRope["))\n"];
};
SFWriterJaMInit: FitJaM.InitProc = {
Operations for creating a .SF format font file via JaMGraphics.
JaM.Register[state, "SF.Open", Open]; -- <filename> -> . Opens .sf file in append mode
JaM.Register[state, "SF.Family", Family]; -- <family: string> -> . sets the family for subsequent DrawChar operations.
JaM.Register[state, "SF.Face", Face]; -- <face: string> -> . sets the face for subsequent DrawChar operations.
JaM.Register[state, "SF.Origin", Origin]; -- <x: number> <y: number> -> . says what the character origins are.
JaM.Register[state, "SF.Quad", Quad]; -- <baselineSpacing: number> -> . says what the units are.
JaM.Register[state, "SF.Close", Close]; -- -> . closes .sf file.
JaM.Register[state, "SF.Char", Char]; -- . <ascii code: integer> <widthx: number> <widthy: number> -> . Takes the current path and writes it out as a character in .sf format.
};
FitJaM.RegisterInit[$SFWriterJaMInit, SFWriterJaMInit];
END.