--TSSDFontImpl.mesa
--sd font manager
-- Michael Plass,  June 24, 1982 3:27 pm

DIRECTORY
	Rope USING[ROPE],
	TSBcplFontFile USING [SplineCommandPtr, SplineDataPtr, GetSplineCommands, OpenSDFontFile, CloseSDFontFile],
	IO USING[Error],
	Heap USING[MakeNode,FreeNode,systemZone],
	Real,
	TSSDFont;

TSSDFontImpl: MONITOR
	IMPORTS TSBcplFontFile, Heap, IO, Real
	EXPORTS TSSDFont =

BEGIN OPEN TSSDFont;

-- First some copied routines for converting to bezier points.
Vec: TYPE = RECORD [x,y: REAL];
VecAdd: PROC [a: Vec, b: Vec] RETURNS[Vec] = INLINE {RETURN[[a.x+b.x,a.y+b.y]]};
VecSub: PROC [a: Vec, b: Vec] RETURNS[Vec] = INLINE {RETURN[[a.x-b.x,a.y-b.y]]};
VecDiv: PROC [a: Vec, s: REAL] RETURNS[Vec] = INLINE {RETURN[[a.x/s,a.y/s]]}; 
Coeffs: TYPE = RECORD[c0,c1,c2,c3: Vec];
Bezier: TYPE = RECORD[b0,b1,b2,b3: Vec];
CoeffsToBezier: PROC [c: Coeffs] RETURNS[b: Bezier] = {
	OPEN b,c;
	b0←c0;
	b1←VecAdd[c0,VecDiv[c1,3]];
	b2←VecAdd[b1,VecDiv[VecAdd[c1,c2],3]];
	b3←VecAdd[VecAdd[VecAdd[c0,c1],c2],c3];
	};

Load: PUBLIC ENTRY PROCEDURE [sdName: ROPE]
	RETURNS [fontSplines: FontSplines ← NIL] = {
	TSBcplFontFile.OpenSDFontFile[sdName
		! IO.Error => GOTO Quit];
	fontSplines ← NEW[FontSplinesRec[256]];
	fontSplines.bc ← 0;
	FOR i: NAT IN [0..256) DO
		fontSplines[i] ← LoadSDChar[LOOPHOLE[i]];
		ENDLOOP;
	TSBcplFontFile.CloseSDFontFile[];
	EXITS Quit => {};
	};

LoadSDChar: PROC [char: CHARACTER] RETURNS [charSplines: CharSplines] = {
	unit: REAL;
	pos: Vec ← [0,0];
	largestDimension: REAL ← 1.0/(1.0+LAST[INT]);
	nextSlot: NAT ← 0;
	size: NAT ← 0;
	IncSize: PROC [d: NAT] = INLINE {size ← size + d};
	TakeMax: PROC [t: REAL] = {largestDimension ← MAX[largestDimension, ABS[t]]};
	ProduceMoveTo: PROC = {charSplines[nextSlot] ← moveToCode; nextSlot ← nextSlot + 1};
	Produce: PROC [t: REAL] = {charSplines[nextSlot] ← Real.RoundI[t/unit]; nextSlot ← nextSlot + 1};
	tscp,scp:TSBcplFontFile.SplineCommandPtr;
	splineDataPtr:TSBcplFontFile.SplineDataPtr;
	[splineDataPtr,scp]←TSBcplFontFile.GetSplineCommands[char, Allocate];
	tscp←scp;
	UNTIL scp = NIL DO
		WITH scp SELECT FROM
			MoveTo => {TakeMax[x]; TakeMax[y]; IncSize[3]; pos ← [x,y]};
			DrawTo => {TakeMax[x]; TakeMax[y]; IncSize[6]; pos ← [x,y]};
			DrawCurve => {
				b: Bezier ← CoeffsToBezier[[c3:[x2,y2],c2:[x1,y1],c1:[x0,y0],c0:pos]];
				TakeMax[b.b0.x]; TakeMax[b.b0.y];
				TakeMax[b.b1.x]; TakeMax[b.b1.y];
				TakeMax[b.b2.x]; TakeMax[b.b2.y];
				TakeMax[b.b3.x]; TakeMax[b.b3.y];
				IncSize[6];
				pos ← b.b3;
				};
			NewObject => NULL;
			EndDefinition => EXIT;
			ENDCASE;
		scp←scp.next;
		ENDLOOP;
	charSplines ← NEW[CharSplinesRec[size]];
	charSplines.unit ← unit ← (largestDimension*1.125)/LAST[INTEGER];
	scp←tscp;
	pos ← [0,0];
	UNTIL scp = NIL DO
		WITH scp SELECT FROM
			MoveTo => {
				ProduceMoveTo[];
				Produce[x];
				Produce[y];
				pos ← [x,y];
				};
			DrawTo => {
				Produce[(pos.x+pos.x+x)/3.0];
				Produce[(pos.y+pos.y+y)/3.0];
				Produce[(pos.x+x+x)/3.0];
				Produce[(pos.y+y+y)/3.0];
				Produce[x];
				Produce[y];
				pos ← [x,y];
				};
			DrawCurve => {
				b: Bezier ← CoeffsToBezier[[c3:[x2,y2],c2:[x1,y1],c1:[x0,y0],c0:pos]];
				Produce[b.b1.x]; Produce[b.b1.y];
				Produce[b.b2.x]; Produce[b.b2.y];
				Produce[b.b3.x]; Produce[b.b3.y];
				pos ← b.b3;
				};
			NewObject => NULL;
			EndDefinition => EXIT;
			ENDCASE;
		scp←scp.next;
		ENDLOOP;
	scp←tscp;
	UNTIL (scp←tscp) = NIL DO
		tscp←scp.next;
		Heap.FreeNode[Heap.systemZone,scp];
		ENDLOOP;
	};
	
Allocate:  PROC[nwords: INTEGER]  RETURNS[LONG POINTER] = {RETURN[Heap.MakeNode[Heap.systemZone,nwords]]};

END.

-- Michael Plass,  June 24, 1982 3:27 pm. Cedar 3.2 conversion.