-- PressDeviceImpl.mesa
-- Last changed by Doug Wyatt, September 22, 1980 5:36 PM

DIRECTORY
Device,
PressDevice,
OpaqueDevice USING [TextHandle],
Vector USING [Vec, Matrix],
Area USING [Rec, Handle, Vertices, Rectangular, Rectangle, Free],
Poly USING [NewRec],
Pipe USING [Handle, Object, Procs],
Font USING [Id],
Mapper USING [Handle, Concat],
Style USING [Data, PaintingFunction, Texture, Color],
Memory USING [NewZone, mds],
PressDefs USING [PressFileDescriptor, InitPressFileDescriptor,
StartOutline, PutDrawTo, EndOutline, SetColor, PutRectangle,
ClosePressFile],
Real USING [FixC];

PressDeviceImpl: PROGRAM
IMPORTS Memory,Mapper,Area,Poly,Real,PressDefs
EXPORTS OpaqueDevice,PressDevice SHARES Device,Pipe = {
OPEN Device;

zone: UNCOUNTED ZONE = Memory.NewZone["PressDeviceImpl"];
mds: MDSZone = Memory.mds;

PaintFunction: TYPE = Style.PaintingFunction;
Texture: TYPE = Style.Texture;
Color: TYPE = Style.Color;

DeviceObject: PUBLIC TYPE = Device.Object;

PressHandle: TYPE = POINTER TO PressDefs.PressFileDescriptor;

-- Concrete form of the data
Data: TYPE = RECORD [
pressHandle: PressHandle,
fileName: STRING,
width,height: CARDINAL -- width and height in micas
];
DataRef: TYPE = LONG POINTER TO Data;

procs: LONG POINTER TO READONLY Procs = zone.NEW[Procs = [
NewPipe: CNewPipe,
NewText: CNewText,
ApplyBaseTransform: CApplyBaseTransform,
Boundary: CBoundary,
Free: CFree
]];

-- Procedures for creating a Device object

NewPressDevice: PUBLIC PROCEDURE[filename: STRING] RETURNS[Handle] = {
pd: PressHandle = mds.NEW[PressDefs.PressFileDescriptor];
name: STRING = CopyString[filename];
d: DataRef = zone.NEW[Data ← [
pressHandle: pd,
fileName: name,
width: (2540/2)*17, height: 2540*11
]];
PressDefs.InitPressFileDescriptor[pd,name];
RETURN[zone.NEW[Object ← [procs: procs, data: LOOPHOLE[d]]]];
};

CopyString: PROCEDURE[s: STRING] RETURNS[STRING] = {
n: CARDINAL=s.length;
t: STRING=mds.NEW[StringBody[n]];
FOR i: CARDINAL IN[0..n) DO t[i]←s[i] ENDLOOP; t.length←n;
RETURN[t];
};

PData: TYPE = RECORD [
pressHandle: PressHandle,
color: Color
];

PDataRef: TYPE = LONG POINTER TO PData;

pProcs: LONG POINTER TO READONLY Pipe.Procs = zone.NEW[Pipe.Procs = [
Put: PPut, Free: PFree]];

CNewPipe: PROCEDURE[self: Handle, style: POINTER TO Style.Data]
RETURNS[Pipe.Handle] = {
d: DataRef=LOOPHOLE[self.data];
pd: PressHandle=d.pressHandle;
p: PDataRef=zone.NEW[PData ← [
pressHandle: pd, color: style.color
]];
PressDefs.SetColor[pd,p.color.r,p.color.g,p.color.b];
RETURN[zone.NEW[Pipe.Object ← [procs: pProcs, data: LOOPHOLE[p]]]];
};

RoundC: PROC[r: REAL] RETURNS[CARDINAL] = INLINE { RETURN[Real.FixC[r+.5]] };

PPut: PROCEDURE[self: Pipe.Handle, area: Area.Handle] = {
p: PDataRef=LOOPHOLE[self.data];
pd: PressHandle=p.pressHandle;
IF Area.Rectangular[area] THEN {
r: Area.Rec=Area.Rectangle[area];
llx: CARDINAL=RoundC[r.ll.x];
lly: CARDINAL=RoundC[r.ll.y];
urx: CARDINAL=RoundC[r.ur.x];
ury: CARDINAL=RoundC[r.ur.y];
PressDefs.PutRectangle[pd,llx,lly,urx-llx,ury-lly];
}
ELSE {
first: BOOLEAN←TRUE;
Put: PROC[v: Vector.Vec] = {
mx: CARDINAL=RoundC[v.x]; -- rounded to micas
my: CARDINAL=RoundC[v.y]; -- rounded to micas
IF first THEN { PressDefs.StartOutline[pd,mx,my]; first←FALSE }
ELSE PressDefs.PutDrawTo[pd,mx,my];
};
Area.Vertices[area,Put]; PressDefs.EndOutline[pd];
};
Area.Free[@area];
};

PFree: PROCEDURE[self: Pipe.Handle] = {
p: PDataRef←LOOPHOLE[self.data];
zone.FREE[@p]; zone.FREE[@self];
};

CNewText: PROCEDURE[self: Handle, id: Font.Id, size: REAL,
pm: POINTER TO READONLY Vector.Matrix,
style: POINTER TO READONLY Style.Data]
RETURNS[OpaqueDevice.TextHandle] = {
RETURN[NIL];
};

CApplyBaseTransform: PROCEDURE[self: Handle, mapper: Mapper.Handle] = {
s: REAL=2540.0/72.0;
Mapper.Concat[mapper,[s,0,0,s]];
};

CBoundary: PROCEDURE[self: Handle] RETURNS[Area.Handle] = {
d: DataRef=LOOPHOLE[self.data];
r: Area.Rec=[[0,0],[d.width,d.height]];
RETURN[Poly.NewRec[r]];
};

CFree: PROCEDURE[self: Handle] = {
d: DataRef←LOOPHOLE[self.data];
pd: PressHandle←d.pressHandle;
name: STRING←d.fileName;
PressDefs.ClosePressFile[pd];
mds.FREE[@pd]; mds.FREE[@name];
zone.FREE[@d]; zone.FREE[@self];
};

}.