ImagerRasterSmoothGrayImpl.mesa
Copyright © 1984 Xerox Corporation. All rights reserved.
Michael Plass, July 19, 1984 12:57:21 pm PDT
Doug Wyatt, October 16, 1984 5:36:49 pm PDT
DIRECTORY
Basics USING [LongDiv, LongDivMod, LongMult],
ImagerColor USING [Color, ConstantColor, SampledColor],
ImagerRaster USING [Device, DeviceRep, RectangleProc, RunProc],
ImagerPixelMap USING [DeviceRectangle, Fill, Get8Bits, PixelMap],
ImagerTransformation USING [PreRotate, Transformation, Translate],
PrincOps USING [zBNDCK, zINC],
Real USING [RoundC];
ImagerRasterSmoothGrayImpl: CEDAR PROGRAM
IMPORTS Basics, ImagerPixelMap, ImagerTransformation, Real
~ BEGIN
This is an example implementation of an Imager display device. It implements an 8-bit-per-pixel gray-level display with antialiasing.
Device: TYPE ~ ImagerRaster.Device;
RunProc: TYPE ~ ImagerRaster.RunProc;
RectangleProc: TYPE ~ ImagerRaster.RectangleProc;
DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle;
Transformation: TYPE ~ ImagerTransformation.Transformation;
Color: TYPE ~ ImagerColor.Color;
ConstantColor: TYPE ~ ImagerColor.ConstantColor;
SampledColor: TYPE ~ ImagerColor.SampledColor;
Data: TYPE ~ REF DataRep;
DataRep: TYPE ~ RECORD[
frame: ImagerPixelMap.PixelMap, -- the frame buffer
pixelValue: [0..255] -- for ConstantColor
];
viewUnitsPerPixel: NAT ← 5;
defaultPixelsPerInch: REAL ~ 42;
metersPerInch: REAL ~ 0.0254;
Create: PROC[frame: ImagerPixelMap.PixelMap, pixelsPerInch: REAL ← defaultPixelsPerInch]
RETURNS[Device] ~ {
data: Data ~ NEW[DataRep ← [frame: frame, pixelValue: 0]];
vupp: NAT ~ viewUnitsPerPixel;
viewUnitsPerMeter: REAL ~ (vupp*pixelsPerInch)/metersPerInch;
sSize: NAT ~ frame.sSize*vupp;
fSize: NAT ~ frame.fSize*vupp;
surfaceToDevice: Transformation ~ ImagerTransformation.Translate[[sSize, 0]];
surfaceToDevice.PreRotate[90];
RETURN[NEW[ImagerRaster.DeviceRep ← [type: $SmoothGray,
setColor: SetColor, maskRuns: MaskRunsConst, maskRectangles: MaskRectanglesConst,
surfaceToDevice: surfaceToDevice,
clipBox: [sMin: 0, fMin: 0, sSize: sSize, fSize: fSize],
metersToSurface: [viewUnitsPerMeter, viewUnitsPerMeter],
viewUnitsPerPixel: vupp,
data: data]]];
};
DoUnderLock: PROC [data: Data, action: PROC, rectangle: DeviceRectangle] ~ {
vt: Terminal.Virtual ← Terminal.Current[];
vupp: NAT ← data.class.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];
};
SetColor: PROC[device: Device, color: Color, viewToDevice: Transformation] ~ {
data: Data ~ NARROW[device.data];
WITH color SELECT FROM
color: ConstantColor => {
data.pixelValue ← Real.RoundC[(1-color.f)*255];
device.maskRuns ← MaskRunsConst;
device.maskRectangles ← MaskRectanglesConst;
};
ENDCASE => ERROR; -- not implemented
};
Check: PROC[x: INTEGER, max: NAT] RETURNS[NAT] ~
TRUSTED MACHINE CODE { PrincOps.zINC; PrincOps.zBNDCK };
IF x IN[0..max] THEN RETURN[x] ELSE ERROR RuntimeError.BoundsFault
MaskRectanglesConst: PROC[device: Device, rectangles: PROC[RectangleProc]] ~ {
ERROR; -- not implemented
};
MaskRunsConst: PROC[device: Device, runs: PROC[RunProc]] ~ {
data: Data ~ NARROW[device.data];
pixelValue: [0..255] ~ data.pixelValue;
lineBuff: ARRAY [0..2050] OF INTEGERALL[0];
minPixel: NAT ← data.frame.fSize;
maxPixel: NAT ← 0;
vupp: NAT ← device.viewUnitsPerPixel;
squpp: NAT ← vupp*vupp;
line: NAT ← 0;
s: NAT ← line*vupp;
sModVupp: NAT ← 0;
fImageLimit: NAT ← data.frame.fOrigin+data.frame.fMin+data.frame.fSize;
fSizeSpatial: NAT ~ data.frame.fSize*vupp;
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 {
data.frame.Fill[[line, bltStart, 1, pixel-bltStart], pixelValue];
};
IF pixel <= maxPixel AND pixel < fImageLimit THEN {
oldValue: CARDINAL ← data.frame.Get8Bits[line, pixel];
mix: CARDINAL ← lineBuff[pixel];
mixedValue: CARDINAL ← Basics.LongDiv[
Basics.LongMult[oldValue, squpp-mix]+Basics.LongMult[pixelValue, mix],
squpp
];
data.frame.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 ← data.frame.fSize;
maxPixel ← 0;
};
run: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ {
q0, r0, q1, r1: CARDINAL;
f0: CARDINAL ← Check[fMin, fSizeSpatial];
f1: CARDINAL ← Check[fMin+fSize, fSizeSpatial];
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;
};
};
runs[run];
run[s+vupp+1, 0, 0];
};
END.