ImagerDeviceSmoothGrayImpl.mesa
Copyright (C) 1984, 1985, 1986 by Xerox Corporation. All rights reserved.
Michael Plass, July 19, 1984 12:57:21 pm PDT
Doug Wyatt, March 2, 1986 5:37:53 pm PST
DIRECTORY
Basics USING [LongDiv, LongDivMod, LongMult],
ImagerColor USING [Color, ConstantColor, SampledColor],
ImagerDevice USING [Class, ClassRep, Device, DeviceRep, HalftoneParameters, RunProc],
ImagerPixelMap USING [DeviceRectangle, Fill, Get8Bits, PixelMap],
ImagerTransformation USING [ApplyPreRotate, Transformation, Translate],
PrincOps USING [zBNDCK, zINC],
Real USING [RoundC];
ImagerDeviceSmoothGrayImpl: 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 ~ ImagerDevice.Device;
RunProc: TYPE ~ ImagerDevice.RunProc;
HalftoneParameters: TYPE ~ ImagerDevice.HalftoneParameters;
DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle;
Transformation: TYPE ~ ImagerTransformation.Transformation;
Color: TYPE ~ ImagerColor.Color;
ConstantColor: TYPE ~ ImagerColor.ConstantColor;
SampledColor: TYPE ~ ImagerColor.SampledColor;
Case: TYPE ~ {nil, constant, gray, sampled};
Data: TYPE ~ REF DataRep;
DataRep: TYPE ~ RECORD[
frame: ImagerPixelMap.PixelMap, -- the frame buffer
case: Case ← nil, -- what type of color
pixelValue: [0..255] ← 0 -- for ConstantColor
];
defaultPixelsPerInch: REAL ~ 42;
defaultSurfaceUnitsPerPixel: NAT ~ 5;
class: ImagerDevice.Class ~ NEW[ImagerDevice.ClassRep ← [
type: $SmoothGrayDisplay,
SetColor: SetColor,
SetPriority: SetPriority,
SetHalftone: SetHalftone,
MaskRuns: MaskRuns
]];
Create: PROC[frame: ImagerPixelMap.PixelMap,
pixelsPerInch: REAL ← defaultPixelsPerInch,
surfaceUnitsPerPixel: NAT ← defaultSurfaceUnitsPerPixel] RETURNS[Device] ~ {
data: Data ~ NEW[DataRep ← [frame: frame]];
unitsPerInch: REAL ~ pixelsPerInch*surfaceUnitsPerPixel;
sSize: NAT ~ frame.sSize*surfaceUnitsPerPixel;
fSize: NAT ~ frame.fSize*surfaceUnitsPerPixel;
surfaceToDevice: Transformation ~ ImagerTransformation.Translate[[sSize, 0]];
surfaceToDevice.ApplyPreRotate[90];
RETURN[NEW[ImagerDevice.DeviceRep ← [class: class,
clipBox: [sMin: 0, fMin: 0, sSize: sSize, fSize: fSize],
surfaceToDevice: surfaceToDevice,
surfaceUnitsPerInch: [unitsPerInch, unitsPerInch],
surfaceUnitsPerPixel: surfaceUnitsPerPixel,
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];
data.pixelValue ← 255-Real.RoundC[MIN[MAX[color.f, 0], 1]*255];
data.case ← constant;
};
SetPriority: PROC[device: Device, priorityImportant: BOOL] ~ {
};
SetHalftone: PROC[device: Device, halftone: HalftoneParameters] ~ {
};
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
MaskRuns: 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.surfaceUnitsPerPixel;
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.