-- JaMSplineImpl.mesa
-- Mesa 6 version
-- Last changed by Doug Wyatt, October 10, 1980 3:17 PM

DIRECTORY
JaMGraphicsDefs USING [GetDC],
Graphics USING [DisplayContext,
MoveTo, DrawTo, DrawCubic, EnterPoint, EnterCubic, NewBoundary
],
Vector USING [Vec],
Cubic USING [Coeffs],
SplineDefs USING [--InitSplines, --FPCoords, X, Y, Coeffs, SplineType,
MakeSpline, FreeCoeffs],
SplineMemoryDefs USING [Allocate, Free],
BcplFontFileDefs USING [OpenSDFontFile, CloseSDFontFile,
SplineCommandPtr, SplineDataPtr, GetSplineCommands],
JaMFnsDefs USING [PopInteger, PushReal, GetReal, PopString, Register],
SystemDefs USING [AllocateHeapNode, FreeHeapNode];

JaMSplineImpl: PROGRAM
IMPORTS JaMFnsDefs,JaMGraphicsDefs,Graphics,
SplineDefs,SplineMemoryDefs,BcplFontFileDefs,SystemDefs = {
OPEN J:JaMFnsDefs,G:Graphics;

Vec: TYPE = Vector.Vec;
Coeffs: TYPE = Cubic.Coeffs;

KnotArray: TYPE = DESCRIPTOR FOR ARRAY OF SplineDefs.FPCoords;

JEnterALSpline: PUBLIC PROCEDURE = {
knots: KnotArray;
n: CARDINAL←J.PopInteger[]; -- get number of knots.
knots←DESCRIPTOR[SplineMemoryDefs.Allocate[n*SIZE[SplineDefs.FPCoords]],n];
FOR i: CARDINAL DECREASING IN[0..n) DO
knots[i][SplineDefs.Y]←J.GetReal[];
knots[i][SplineDefs.X]←J.GetReal[];
ENDLOOP;
EnterSpline[knots,naturalAL];
SplineMemoryDefs.Free[BASE[knots]];
};

JEnterCyclicALSpline: PUBLIC PROCEDURE = {
knots: KnotArray;
n: CARDINAL←J.PopInteger[]+1; -- get number of knots.
knots←DESCRIPTOR[SplineMemoryDefs.Allocate[n*SIZE[SplineDefs.FPCoords]],n];
FOR i: CARDINAL DECREASING IN[1..n) DO
knots[i][SplineDefs.Y]←J.GetReal[];
knots[i][SplineDefs.X]←J.GetReal[];
ENDLOOP;
knots[0]←knots[n-1]; -- close the curve
EnterSpline[knots,cyclicAL];
SplineMemoryDefs.Free[BASE[knots]];
};

EnterSpline: PROCEDURE[knots: KnotArray, type: SplineDefs.SplineType] = {
dc: G.DisplayContext←JaMGraphicsDefs.GetDC[];
allcoeffs: DESCRIPTOR FOR ARRAY OF SplineDefs.Coeffs;
allcoeffs ← SplineDefs.MakeSpline[knots,type];
FOR i: CARDINAL IN[0..LENGTH[allcoeffs]) DO
OPEN SplineDefs;
cf: Cubic.Coeffs←[
c0:[allcoeffs[i].t0[X],allcoeffs[i].t0[Y]],
c1:[allcoeffs[i].t1[X],allcoeffs[i].t1[Y]],
c2:[allcoeffs[i].t2[X],allcoeffs[i].t2[Y]],
c3:[allcoeffs[i].t3[X],allcoeffs[i].t3[Y]]
];
G.EnterCubic[dc,@cf];
ENDLOOP;
SplineDefs.FreeCoeffs[allcoeffs];
};

-- the following are the SDFont interfaces;

OpenSDFile: PROCEDURE = {
s:STRING ←[64];
J.PopString[s];
BcplFontFileDefs.OpenSDFontFile[s];
};

CloseSDFile: PROCEDURE = {
BcplFontFileDefs.CloseSDFontFile[];
};

DrawSDChar: PROCEDURE = {
dc: G.DisplayContext←JaMGraphicsDefs.GetDC[];
Move: PROC[v: POINTER TO Vec] = { G.MoveTo[dc,v↑] };
Draw: PROC[v: POINTER TO Vec] = { G.DrawTo[dc,v↑] };
Cubic: PROC[c: POINTER TO Coeffs] = { G.DrawCubic[dc,c] };
s:STRING←[8]; J.PopString[s];
J.PushReal[DoSDChar[s[0],Move,Draw,Cubic]];
};

EnterSDChar: PROCEDURE = {
dc: G.DisplayContext←JaMGraphicsDefs.GetDC[];
Move: PROC[v: POINTER TO Vec] = { G.NewBoundary[dc]; G.EnterPoint[dc,v↑] };
Draw: PROC[v: POINTER TO Vec] = { G.EnterPoint[dc,v↑] };
Cubic: PROC[c: POINTER TO Coeffs] = { G.EnterCubic[dc,c] };
s:STRING←[8]; J.PopString[s];
J.PushReal[DoSDChar[s[0],Move,Draw,Cubic]];
};

DoSDChar: PROCEDURE[char: CHARACTER,
Move: PROCEDURE[v: POINTER TO Vec],
Draw: PROCEDURE[v: POINTER TO Vec],
Cubic: PROCEDURE[c: POINTER TO Coeffs]
] RETURNS[width: REAL] = {
pos: Vec←[0,0];
tscp,scp:BcplFontFileDefs.SplineCommandPtr;
sdp:BcplFontFileDefs.SplineDataPtr;
[sdp,scp]←BcplFontFileDefs.GetSplineCommands[
char, SystemDefs.AllocateHeapNode];
tscp←scp;
UNTIL scp = NIL DO
WITH scp SELECT FROM
MoveTo => { pos←[x,y]; Move[@pos] };
DrawTo => { pos←[x,y]; Draw[@pos] };
DrawCurve => {
c: Coeffs←[c3:[x2,y2],c2:[x1,y1],c1:[x0,y0],c0:pos];
Cubic[@c]; pos←[pos.x+x0+x1+x2, pos.y+y0+y1+y2];
};
NewObject => NULL;
EndDefinition => EXIT;
ENDCASE;
scp←scp.next;
ENDLOOP;
width←sdp.xwidth;
scp←tscp;
UNTIL (scp←tscp) = NIL DO
tscp←scp.next;
SystemDefs.FreeHeapNode[scp];
ENDLOOP;
RETURN[width];
};

-- SplineDefs.InitSplines[
--
alloc: SystemDefs.AllocateHeapNode,
--
free: SystemDefs.FreeHeapNode
--
];

J.Register[".enterspline"L,JEnterALSpline];
J.Register[".entercspline"L,JEnterCyclicALSpline];
J.Register[".opensd",OpenSDFile];
J.Register[".closesd",CloseSDFile];
J.Register[".drawsdchar",DrawSDChar];
J.Register[".entersdchar",EnterSDChar];

}.