DIRECTORY Atom, Imager, ImagerBasic, ImagerDisplay, ImagerFrameBuffer, ImagerManhattan, ImagerMasks, ImagerPixelMaps, ImagerPrivate, Terminal, TerminalExtras;
ImagerExampleDisplayImpl:
CEDAR PROGRAM
IMPORTS Atom, Imager, ImagerDisplay, ImagerFrameBuffer, ImagerMasks, ImagerPrivate, Terminal, TerminalExtras ~ BEGIN
This is an example implementation of an Imager display device. It implements an 8-bit-per-pixel gray-level display with no antialiasing.
DisplayClass: TYPE ~ ImagerDisplay.DisplayClass;
DisplayClassRep: TYPE ~ ImagerDisplay.DisplayClassRep;
DisplayData: TYPE ~ ImagerDisplay.DisplayData;
DisplayDataRep: TYPE ~ ImagerDisplay.DisplayDataRep;
DeviceRectangle: TYPE ~ ImagerBasic.DeviceRectangle;
Color:
TYPE ~ ImagerBasic.Color;
ColorRep: TYPE ~ ImagerBasic.ColorRep;
SampledColor: TYPE = REF ColorRep.sampled;
ConstantColor: TYPE = REF ColorRep.constant;
SpecialColor: TYPE = REF ColorRep.special;
Mask: TYPE ~ ImagerMasks.Mask;
ManhattanPolygon:
TYPE ~ ImagerManhattan.Polygon;
exampleDisplayClass: ImagerDisplay.DisplayClass ~
NEW[ImagerDisplay.DisplayClassRep ← [
displayType: $Gray8bpp,
viewUnitsPerPixel: 1,
Create: Create,
ApplyMask: ApplyMask,
DoUnderLock: DoUnderLock
]];
Create:
PROC [displayClass: DisplayClass, creationData:
REF]
RETURNS [displayData: DisplayData] ~ {
The creationData is inherited from the Create call. Here we ignore it, but a possible use for it is to point to an alternate buffer.
ppi: REAL ← 42;
WITH creationData
SELECT
FROM
props: Atom.PropList => {
ppiRef: REF ← Atom.GetPropFromList[props, $pixelsPerInch];
WITH ppiRef
SELECT
FROM
r: REF REAL => ppi ← r^;
i: REF INT => ppi ← i^;
ENDCASE => NULL;
};
ENDCASE => NULL;
displayData ← NEW[DisplayDataRep[1]];
displayData.displayClass ← displayClass;
displayData.xRes ← ppi;
displayData.yRes ← ppi;
displayData.rotate ← TRUE;
TRUSTED {displayData[0] ← ImagerFrameBuffer.GrayScaleDisplay8[]};
displayData.surfaceWidth ← displayData[0].fSize;
displayData.surfaceHeight ← displayData[0].sSize;
};
DoUnderLock:
PROC [displayData: DisplayData, action:
PROC, rectangle: DeviceRectangle] ~ {
vt: Terminal.Virtual ← Terminal.Current[];
TerminalExtras.LockColorFrame[
vt: vt,
xmin: MAX[rectangle.fMin, 0],
ymin: MAX[rectangle.sMin, 0],
xmax: MAX[rectangle.fMin+rectangle.fSize, 0],
ymax: MAX[rectangle.sMin+rectangle.sSize, 0]
];
action[! UNWIND => {TerminalExtras.UnlockColorFrame[vt]}];
TerminalExtras.UnlockColorFrame[vt];
};
ApplyMask:
PROC [displayData: DisplayData, color: Color, mask: Mask, sTranslate, fTranslate:
INTEGER] ~ {
LockedApplyMask:
PROC ~ {
function: ImagerPixelMaps.Function ← [null, null];
IF color = Imager.
XOR
THEN {
color ← Imager.white;
function ← [xor, null];
};
WITH color
SELECT
FROM
constantColor: ConstantColor => {
pixelValue: [0..255] ← constantColor.Y/256;
ImagerMasks.ApplyConstant[
mask: mask,
clipper: displayData.compositeClipper,
dest: displayData[0],
value: pixelValue,
function: function,
sTranslate: sTranslate,
fTranslate: fTranslate
];
};
ENDCASE => Imager.Error[$UnsupportedColorType];
};
bb: DeviceRectangle ← ImagerMasks.BoundingBox[mask];
bb.sMin ← bb.sMin + sTranslate;
bb.fMin ← bb.fMin + fTranslate;
IF color # displayData.cachedColor
THEN {
displayData.cachedColorData ←
NIL;
This is where we would calculate any cached color data.
displayData.cachedColor ← color;
};
DoUnderLock[displayData, LockedApplyMask, bb];
};
exampleImagerClass: ImagerPrivate.Class ~ ImagerDisplay.CreateImagerClass[exampleDisplayClass];
ImagerPrivate.RegisterDevice[exampleImagerClass];
END.