ImagerSmoothGrayDisplayImpl.mesa
Copyright (C) 1984, Xerox Corporation. All rights reserved.
Michael Plass, July 19, 1984 12:57:21 pm PDT
DIRECTORY Atom, Basics, Imager, ImagerBasic, ImagerDisplay, ImagerFrameBuffer, ImagerManhattan, ImagerMasks, ImagerPixelMaps, ImagerPrivate, Terminal, TerminalExtras;
ImagerSmoothGrayDisplayImpl: CEDAR PROGRAM
IMPORTS Atom, Basics, Imager, ImagerDisplay, ImagerFrameBuffer, ImagerMasks, ImagerPixelMaps, 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: $SmoothGray,
viewUnitsPerPixel: 5,
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;
frameBuffer: REF ImagerPixelMaps.PixelMap ← NIL;
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;
};
buffer: REF ImagerPixelMaps.PixelMap => frameBuffer ← buffer;
ENDCASE => NULL;
displayData ← NEW[DisplayDataRep[1]];
displayData.displayClass ← displayClass;
displayData.xRes ← ppi*exampleDisplayClass.viewUnitsPerPixel;
displayData.yRes ← ppi*exampleDisplayClass.viewUnitsPerPixel;
displayData.rotate ← TRUE;
IF frameBuffer = NIL THEN
TRUSTED {displayData[0] ← ImagerFrameBuffer.GrayScaleDisplay8[]}
ELSE displayData[0] ← frameBuffer^;
displayData.surfaceWidth ← displayData[0].fSize*exampleDisplayClass.viewUnitsPerPixel;
displayData.surfaceHeight ← displayData[0].sSize*exampleDisplayClass.viewUnitsPerPixel;
};
DoUnderLock: PROC [displayData: DisplayData, action: PROC, rectangle: DeviceRectangle] ~ {
vt: Terminal.Virtual ← Terminal.Current[];
vupp: NAT ← displayData.displayClass.viewUnitsPerPixel;
TerminalExtras.LockColorFrame[
vt: vt,
xmin: MAX[rectangle.fMin, 0]/vupp,
ymin: MAX[rectangle.sMin, 0]/vupp,
xmax: MAX[rectangle.fMin+rectangle.fSize+vupp-1, 0]/vupp,
ymax: MAX[rectangle.sMin+rectangle.sSize+vupp-1, 0]/vupp
];
action[! UNWIND => {TerminalExtras.UnlockColorFrame[vt]}];
TerminalExtras.UnlockColorFrame[vt];
};
ApplyMask: PROC [displayData: DisplayData, color: Color, mask: Mask, sTranslate, fTranslate: INTEGER] ~ {
LockedApplyMask: PROC ~ {
WITH color SELECT FROM
constantColor: ConstantColor => {
pixelValue: [0..255] ← constantColor.Y/256;
lineBuff: ARRAY [0..2050] OF INTEGERALL[0];
minPixel: NAT ← displayData[0].fSize;
maxPixel: NAT ← 0;
vupp: NAT ← displayData.displayClass.viewUnitsPerPixel;
squpp: NAT ← vupp*vupp;
line: NATCARDINAL[MAX[bb.sMin, 0]]/vupp;
s: NAT ← line*vupp;
sModVupp: NAT ← 0;
fImageLimit: NAT ← displayData[0].fOrigin+displayData[0].fMin+displayData[0].fSize;
DoLine: PROC ~ {
sum: NAT ← 0;
pixel: NAT ← minPixel;
FOR j: NAT IN [minPixel..maxPixel] DO
lineBuff[j] ← sum ← sum + lineBuff[j];
ENDLOOP;
lineBuff[maxPixel+1] ← LAST[NAT];
WHILE pixel <= maxPixel DO
bltStart: NAT;
WHILE lineBuff[pixel] = 0 DO pixel ← pixel + 1 ENDLOOP;
bltStart ← pixel;
WHILE lineBuff[pixel] = squpp DO pixel ← pixel + 1 ENDLOOP;
IF pixel > bltStart THEN {
displayData[0].Fill[[line, bltStart, 1, pixel-bltStart], pixelValue];
};
IF pixel <= maxPixel AND pixel < fImageLimit THEN {
oldValue: CARDINAL ← displayData[0].Get8Bits[line, pixel];
mix: CARDINAL ← lineBuff[pixel];
mixedValue: CARDINAL ← Basics.LongDiv[
Basics.LongMult[oldValue, squpp-mix]+Basics.LongMult[pixelValue, mix],
squpp
];
displayData[0].Fill[[line, pixel, 1, 1], mixedValue];
};
IF pixel <= maxPixel THEN {
pixel ← pixel + 1;
};
ENDLOOP;
lineBuff[maxPixel+1] ← 0;
FOR j: NAT IN [minPixel..maxPixel] DO
lineBuff[j] ← 0;
ENDLOOP;
minPixel ← displayData[0].fSize;
maxPixel ← 0;
};
RunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ {
q0, r0, q1, r1: CARDINAL;
f0: CARDINALMIN[MAX[fMin, 0], displayData.surfaceWidth];
f1: CARDINALMIN[MAX[fMin+fSize, 0], displayData.surfaceWidth];
WHILE s < sMin DO
s ← s + 1;
sModVupp ← sModVupp + 1;
IF sModVupp = vupp THEN {
DoLine[];
sModVupp ← 0;
line ← line + 1;
};
ENDLOOP;
IF fSize > 0 THEN {
[q0, r0] ← Basics.LongDivMod[f0, vupp];
[q1, r1] ← Basics.LongDivMod[f1, vupp];
IF q0 < minPixel THEN minPixel ← q0;
IF q1 > maxPixel THEN maxPixel ← q1;
lineBuff[q0] ← lineBuff[q0] + vupp - r0;
lineBuff[q0+1] ← lineBuff[q0+1] + r0;
lineBuff[q1] ← lineBuff[q1] + r1 - vupp;
lineBuff[q1+1] ← lineBuff[q1+1] - r1;
};
};
ImagerMasks.GenerateRuns[
mask: mask,
clipper: displayData.compositeClipper,
runProc: RunProc,
sTranslate: sTranslate,
fTranslate: fTranslate
];
RunProc[s+vupp+1, 0, 0];
};
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.