-- BcplFontFile.Mesa: Last modified by Geschke on November 6, 1979 10:31 AM
-- Last changed by Doug Wyatt, August 27, 1980 11:52 AM
-- Mesa 6 version: assumes REALs are Ieee format

DIRECTORY
BcplFontFileDefs,
RealConvert USING [BcplToIeee],
AltoDefs,
InlineDefs,
Mopcodes,
StreamDefs,
StringDefs,
SystemDefs;


BcplFontFile: PROGRAM
IMPORTS BcplFontFileDefs, RealConvert,
InlineDefs, StringDefs, StreamDefs, SystemDefs
EXPORTS BcplFontFileDefs
SHARES BcplFontFileDefs =
BEGIN OPEN BcplFontFileDefs;

BcplToMesaReal: PROCEDURE[b: BcplREAL] RETURNS[REAL] = INLINE
BEGIN RETURN[RealConvert.BcplToIeee[LOOPHOLE[b]]] END;

inStream: StreamDefs.StreamHandle ← NIL;

inSDname: POINTER TO name RawIndex;
inSDsplines: POINTER TO splines RawIndex;
inSDfontname: STRING ← [40];

inBaseIndex: StreamDefs.StreamIndex;

mesaSplineData: mesaSplineDataDesc;
mesaSplineDir: mesaSplineDirDesc;

OpenSDFontFile: PUBLIC PROCEDURE [file: STRING] =
BEGIN
c: CHARACTER;
inSDend: POINTER TO end RawIndex;
inSplineData: SplineDataDesc;
inSplineDir: SplineDirDesc;
nChars: CARDINAL;

IF inStream # NIL THEN ERROR;
inStream ← StreamDefs.NewWordStream[file, StreamDefs.Read];

inSDname ← GetRawIndex[SystemDefs.AllocateHeapNode];
IF inSDname.hdr.type # name THEN ERROR;
inSDfontname.length ← 0;
StringDefs.BcplToMesaString[@inSDname.fontname, inSDfontname];

inSDsplines ← GetRawIndex[SystemDefs.AllocateHeapNode];
IF inSDsplines.hdr.type # splines OR
inSDsplines.rotation # 0 THEN ERROR;

inSDend ← GetRawIndex[SystemDefs.AllocateHeapNode];
IF inSDend.hdr.type # end THEN ERROR;
SystemDefs.FreeHeapNode[inSDend];

nChars ← inSDsplines.ec-inSDsplines.bc+1;

inSplineData ← DESCRIPTOR[
SystemDefs.AllocatePages[
SystemDefs.PagesForWords[nChars*SIZE[BcplSplineData]]],
nChars];
StreamDefs.SetIndex[
inStream,
LongPointerToStreamIndex[BcplToMesaLongPointer[inSDsplines.startaddress]]];
[] ← StreamDefs.ReadBlock[inStream,
BASE[inSplineData],
nChars*SIZE[BcplSplineData]];
mesaSplineData ← LOOPHOLE[inSplineData];

inBaseIndex←StreamDefs.GetIndex[inStream];

inSplineDir ← DESCRIPTOR[
SystemDefs.AllocatePages[
SystemDefs.PagesForWords[nChars*SIZE[bcplLONGPOINTER]]],
nChars];
[] ← StreamDefs.ReadBlock[inStream,
BASE[inSplineDir],
nChars*SIZE[bcplLONGPOINTER]];
mesaSplineDir ← LOOPHOLE[inSplineDir];

-- convert BCPL dir and spline data to Mesa

FOR c IN [inSDsplines.bc..inSDsplines.ec] DO
IF inSplineDir[c-inSDsplines.bc] =
LOOPHOLE[LOOPHOLE[LONG[-1], LONG INTEGER], bcplLONGPOINTER] THEN
BEGIN mesaSplineDir[c-inSDsplines.bc] ← NIL; LOOP END;
mesaSplineDir[c-inSDsplines.bc] ←
BcplToMesaLongPointer[inSplineDir[c-inSDsplines.bc]];
BEGIN
bcplData: POINTER TO BcplSplineData ← @inSplineData[c-inSDsplines.bc];
mesaData: POINTER TO SplineData ← @mesaSplineData[c-inSDsplines.bc];
mesaData.xwidth ← BcplToMesaReal[bcplData.xwidth];
mesaData.ywidth ← BcplToMesaReal[bcplData.ywidth];
mesaData.bbox ← BcplToMesaReal[bcplData.bbox];
mesaData.bboy ← BcplToMesaReal[bcplData.bboy];
mesaData.rightx ← BcplToMesaReal[bcplData.rightx];
mesaData.topy ← BcplToMesaReal[bcplData.topy];
END;
ENDLOOP;

-- at this point we are prepared to read splines from the SD file

RETURN
END;

CloseSDFontFile: PUBLIC PROCEDURE =
BEGIN
inStream.destroy[inStream];
inStream ← NIL;
SystemDefs.FreeHeapNode[inSDname];
SystemDefs.FreeHeapNode[inSDsplines];
SystemDefs.FreePages[BASE[mesaSplineData]];
SystemDefs.FreePages[BASE[mesaSplineDir]];
RETURN
END;

GetRawIndex: PROCEDURE [userAlloc: PROCEDURE [CARDINAL] RETURNS [POINTER]] RETURNS [POINTER TO UNSPECIFIED] =
BEGIN
p:POINTER TO RawIndex;
p← userAlloc[SIZE[RawIndex]];
[]←StreamDefs.ReadBlock[inStream,p,SIZE[IndexHeader]];
[]←StreamDefs.ReadBlock[inStream,p+SIZE[IndexHeader],p.hdr.length-1];
RETURN[p];
END;

GetSplineCommands: PUBLIC PROCEDURE[char: CHARACTER, userAlloc: AllocProc]
RETURNS [sd: SplineDataPtr, scp: SplineCommandPtr] =
BEGIN
index: StreamDefs.StreamIndex;
last: SplineCommandPtr;
IF char-inSDsplines.bc ~ IN[0..LENGTH[mesaSplineDir])
OR mesaSplineDir[char-inSDsplines.bc] = NIL THEN RETURN[NIL, NIL];
sd ← @mesaSplineData[char-inSDsplines.bc];
index ← LongPointerToStreamIndex[
StreamIndexToLongCardinal[inBaseIndex]
+mesaSplineDir[char-inSDsplines.bc]];
StreamDefs.SetIndex[inStream, index];
[scp,index] ← GetNextCommand[index, userAlloc];
last ← scp;
DO
[last.next,index] ← GetNextCommand[index, userAlloc];
IF last.next.type = EndDefinition THEN EXIT;
last ← last.next;
ENDLOOP;
RETURN
END;

GetNextCommand: PROCEDURE[index: StreamDefs.StreamIndex, userAlloc: AllocProc]
RETURNS [SplineCommandPtr, StreamDefs.StreamIndex] =
BEGIN
bsc: BcplSplineCommand;
scc: SplineCommandCode;
scp: SplineCommandPtr;
StreamDefs.SetIndex[inStream, index];
scc ← BcplToMesaCommandCode[bsc.type ← inStream.get[inStream]];
[]←StreamDefs.ReadBlock[
inStream, @bsc+1,
(SELECT scc FROM
MoveTo, DrawTo => SIZE[MoveTo BcplSplineCommand],
DrawCurve => SIZE[DrawCurve BcplSplineCommand],
ENDCASE => SIZE[EndDefinition BcplSplineCommand])-1];
scp ← userAlloc[SELECT scc FROM
MoveTo, DrawTo => SIZE[MoveTo SplineCommand],
DrawCurve => SIZE[DrawCurve SplineCommand],
ENDCASE => SIZE[EndDefinition SplineCommand]];
SELECT scc FROM
MoveTo => scp↑ ← [, MoveTo[,]];
DrawTo => scp↑ ← [, DrawTo[,]];
DrawCurve => scp↑ ← [, DrawCurve[,,,,,]];
NewObject => scp↑ ← [, NewObject[]];
EndDefinition => scp↑ ← [, EndDefinition[]];
ENDCASE;
scp.next ← NIL;
WITH scp SELECT FROM
MoveTo, DrawTo =>
BEGIN
x ← BcplToMesaReal[bsc.x];
y ← BcplToMesaReal[bsc.y];
END;
DrawCurve =>
BEGIN
x0 ← BcplToMesaReal[bsc.x0];
y0 ← BcplToMesaReal[bsc.y0];
x1 ← BcplToMesaReal[bsc.x1];
y1 ← BcplToMesaReal[bsc.y1];
x2 ← BcplToMesaReal[bsc.x2];
y2 ← BcplToMesaReal[bsc.y2];
END;
ENDCASE;
RETURN[scp, StreamDefs.GetIndex[inStream]]
END;

BcplToMesaCommandCode
: PROCEDURE[bcc: BcplCommandCode] RETURNS [SplineCommandCode] =
BEGIN
SELECT bcc FROM
1 => RETURN[MoveTo];
2 => RETURN[DrawTo];
3 => RETURN[DrawCurve];
-1 => RETURN[NewObject];
-2 => RETURN[EndDefinition];
ENDCASE => ERROR
END;

LongPointerToStreamIndex
: PROCEDURE [l:LONG POINTER] RETURNS [s:StreamDefs.StreamIndex]=
BEGIN
s.page ← InlineDefs.LowHalf[(LOOPHOLE[l,LONG CARDINAL]*2)/AltoDefs.CharsPerPage];
s.byte ← InlineDefs.LowHalf[(LOOPHOLE[l,LONG CARDINAL]*2) MOD AltoDefs.CharsPerPage];END;

StreamIndexToLongCardinal
: PROCEDURE [s:StreamDefs.StreamIndex] RETURNS [l:LONG CARDINAL]=
BEGIN
l ← InlineDefs.LowHalf[LOOPHOLE[s,LONG CARDINAL]] *AltoDefs.CharsPerPage;
l ← (InlineDefs.HighHalf[LOOPHOLE[s,LONG CARDINAL]] +l)/2;
END;


END.