ImagerStdColorDisplayImpl.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Frank Crow, June 15, 1984 2:28:59 pm PDT
DIRECTORY
Imager USING [XOR, Error],
ImagerBasic USING [DeviceRectangle, Color, ColorRep, IntRectangle],
ImagerDisplay USING [DisplayClass, DisplayClassRep, DisplayData, DisplayDataRep],
ImagerMasks USING [Mask, ApplyConstant, BoundingBox],
ImagerPixelMaps USING [PixelMap, PixelMapRep, Fill, Function],
ColorModels USING [Calibration, GetPhosphorCalibration],
ConstantColors USING [RGBToColor, white],
Terminal USING [ColorMode, ChannelsVisible, Current, GetColorMode, Virtual],
TerminalExtras USING [LockColorFrame, UnlockColorFrame],
TerminalColorExtras USING [SetColorBitmapState],
Interminal USING [TurnOnColorCursor, TurnOffColorCursor],
Basics USING [bitsPerWord, LongMult, BITSHIFT],
Atom USING [MakeAtom, PutPropOnList, GetPropFromList],
WindowManager USING [ScreenPos, StopColorViewers], -- StartColorViewers ],
ColorDisplayFaceExtras USING [DisplayType, SetMonitorType, SetBOffsets, SwitchChannels],
CountedVM USING [Allocate, Pointer, Handle],
UserProfile USING [Token, ProfileChangedProc, CallWhenProfileChanges],
Rope USING [ROPE, Equal],
ImagerStdColorDisplay;
ImagerStdColorDisplayImpl:
CEDAR
PROGRAM
IMPORTS Imager, ImagerMasks, ColorModels, ConstantColors, Terminal, TerminalExtras,
TerminalColorExtras, Atom, UserProfile, Rope, CountedVM, Basics, Interminal,
ColorDisplayFaceExtras, ImagerPixelMaps, WindowManager
EXPORTS ImagerStdColorDisplay
~ BEGIN
This provides support for the Dorado color display hardware common to standard displays.
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;
ColorDisplayError: PUBLIC SIGNAL [reason: ATOM] ~ CODE;
pixelsPerInch: NAT;
monitorType: ColorDisplayFaceExtras.DisplayType;
currentDisplay: DisplayData ← NIL; -- Currently displayed context
displaySide: PUBLIC WindowManager.ScreenPos;
colorCalibration: PUBLIC ColorModels.Calibration;
Create: PUBLIC PROC [vt: Terminal.Virtual, mode: Terminal.ColorMode,
displayClass: DisplayClass, creationData: REF,
bitsPerPixel:
NAT, setUpMapProc: ImagerStdColorDisplay.SetUpMapProc]
RETURNS [displayData: DisplayData] ~ {
The creationData is inherited from the Create call. Here it is used to specify the dimensions of the pixel map and whether or not to pin it to the screen. NIL, defaults to using the hardware's display dimensions and pinning immediately.
GetPixelMap: PROC [x, y, width, height, bitsPerPixel: NAT,
pointer: LONG POINTER ← NIL]
RETURNS[pixelMap: ImagerPixelMaps.PixelMap] ~ {
lgBitsPerPixel: NAT;
words: INT;
storage: CountedVM.Handle ← NIL;
wordsPerLineA: INT ← width * MIN[ bitsPerPixel,
IF mode.full THEN 16 ELSE mode.bitsPerPixelChannelA];
wordsPerLineB:
INT ←
IF bitsPerPixel > mode.bitsPerPixelChannelA
THEN width * mode.bitsPerPixelChannelB ELSE 0;
IF wordsPerLineA
MOD Basics.bitsPerWord # 0
THEN wordsPerLineA ← wordsPerLineA/ Basics.bitsPerWord + 1
ELSE wordsPerLineA ← wordsPerLineA/ Basics.bitsPerWord;
IF wordsPerLineB
MOD Basics.bitsPerWord # 0
THEN wordsPerLineB ← wordsPerLineB/ Basics.bitsPerWord + 1
ELSE wordsPerLineB ← wordsPerLineB/ Basics.bitsPerWord;
Words to allocate: add 8 pages for maps, etc. needed by color display
words ← Basics.LongMult[wordsPerLineA + wordsPerLineB, height + 1] + 2048;
IF mode.full THEN words ← words + 512; -- extra space for extra color tables
IF pointer =
NIL
THEN {
storage ← CountedVM.Allocate[words: words];
TRUSTED { pointer ← CountedVM.Pointer[storage]; };
};
IF bitsPerPixel > mode.bitsPerPixelChannelA
AND ~mode.full
THEN bitsPerPixel ← mode.bitsPerPixelChannelA;
SELECT bitsPerPixel
FROM
-- log bits per pixel for first map
1 => lgBitsPerPixel ← 0;
2 => lgBitsPerPixel ← 1;
4 => lgBitsPerPixel ← 2;
8 => lgBitsPerPixel ← 3;
16,24,32 => lgBitsPerPixel ← 4;
ENDCASE => ColorDisplayError[$BitsPerPixelWrong];
pixelMap
← [
sOrigin: y, fOrigin: x, sMin: 0, fMin: 0,
sSize: height,
fSize: width,
refRep:
NEW [ImagerPixelMaps.PixelMapRep ← [
ref: storage,
pointer: pointer,
words: words,
lgBitsPerPixel: lgBitsPerPixel,
rast: wordsPerLineA,
lines: height
]]
];
ImagerPixelMaps.Fill[ pixelMap, [0, 0, height, width], Basics.BITSHIFT[1, bitsPerPixel] - 1 ]
};
numMaps: NAT;
channelsVisible: Terminal.ChannelsVisible;
colorData: REF ImagerStdColorDisplay.ColorMapData;
creationList: LIST OF REF ANY ← NARROW[creationData, LIST OF REF ANY];
adjPixPerInch:
NAT ←
IF monitorType = conrac7211Hi
AND mode.full
THEN pixelsPerInch/2 ELSE pixelsPerInch;
SELECT bitsPerPixel
FROM
1,2,4,6,10 => numMaps ← 1;
16,24 => numMaps ← 2;
32 => numMaps ← 4;
ENDCASE => ColorDisplayError[$BitsPerPixelWrong];
channelsVisible ← IF bitsPerPixel > 16 THEN all ELSE aOnly;
TRUSTED { Interminal.TurnOffColorCursor[]; }; -- for safety's sake, disallow cursor action
WindowManager.StopColorViewers[]; -- !!!!! this should be done when terminalimpl is fixed
IF creationList =
NIL
THEN {
-- use default pixel map
displayData ←
NEW[DisplayDataRep[numMaps]];
-- Make a rep
Get display set up and turned on
IF mode.bitsPerPixelChannelB < 8
THEN {
-- no overlays here
mode.bitsPerPixelChannelB ← 0; bitsPerPixel ← mode.bitsPerPixelChannelA; };
[] ← TerminalColorExtras.SetColorBitmapState[vt, displayed, mode, channelsVisible];
displayData[0] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight, bitsPerPixel,
vt.colorBitmapA]; -- gets up to 24 bits per pixel from Terminal
IF currentDisplay #
NIL
THEN currentDisplay.props ←
Atom.PutPropOnList[ currentDisplay.props, $PixelMapStatus, $Allocated ];
currentDisplay ← displayData;
displayData.props ← Atom.PutPropOnList[displayData.props, $PixelMapStatus, $Displayed];
IF mode.full
THEN {
-- full color, set up multiple pixel maps
blueMap: NAT ← IF numMaps = 4 THEN 2 ELSE 1; -- position of Blue map in sequence
displayData[blueMap] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight, 8,
vt.colorBitmapB];
IF numMaps = 4
THEN {
displayData[1] ← displayData[0]; -- green pixels are LSBs of 16-bit pixelmap
displayData[0] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight, 8]; -- red pixels
displayData[3] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight, 8]; -- alpha pixels
};
}
ELSE
IF numMaps = 2
THEN
-- second pixel map used as overlay or double buffer
displayData[1] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight,
bitsPerPixel - mode.bitsPerPixelChannelA, vt.colorBitmapB];
}
ELSE {
-- Non-nil creation list, build new pixel map
mainMap: NAT ← 0; -- Bitmap to be pinned to display
pinned: BOOLEAN ← TRUE;
box, box2: REF ImagerBasic.IntRectangle ← NIL;
nullBox: ImagerBasic.IntRectangle ← [0, 0, 0, 0];
WHILE creationList #
NIL
DO
-- pick up pin command, box, or both
WITH creationList.first
SELECT
FROM
pinTruth: REF BOOLEAN => pinned ← pinTruth^; -- Display now or just compute?
boxRef:
REF ImagerBasic.IntRectangle =>
IF box =
NIL
THEN box ← boxRef -- For less than the full screen
ELSE box2 ← boxRef; -- For overlays (both boxes needed)
ENDCASE;
creationList ← creationList.rest
ENDLOOP;
IF box = NIL THEN box^ ← [0, 0, vt.colorWidth, vt.colorHeight]; -- use screen size
IF box2 #
NIL
AND numMaps = 1
THEN numMaps ← 2 -- an overlay map needed
ELSE
IF numMaps = 1
THEN {
bitsPerPixel ← mode.bitsPerPixelChannelA;
mode.bitsPerPixelChannelB ← 0; };
displayData ← NEW[DisplayDataRep[numMaps]]; -- Make a rep
displayData[0] ← GetPixelMap[box.x, box.y, box.w, box.h, bitsPerPixel]; -- gets up to 24 bpp
IF mode.full
THEN {
-- full color, set up multiple pixel maps
IF numMaps > 1
THEN {
blueMap: NAT ← IF numMaps = 4 THEN 2 ELSE 1;
blueBits: LONG POINTER; -- blue pixels lie above 16-bit interleaved RG pixels
TRUSTED {
blueBits ← displayData[0].refRep.pointer
+ Basics.LongMult[displayData[0].refRep.rast, box.h]
};
displayData[blueMap] ← GetPixelMap[box.x, box.y, box.w, box.h, 8, blueBits];
IF numMaps = 4
THEN {
displayData[1] ← displayData[0]; -- green pixels are LSBs of 16-bit pixelmap
displayData[0] ← GetPixelMap[box.x, box.y, box.w, box.h, 8]; -- red pixels
displayData[3] ← GetPixelMap[box.x, box.y, box.w, box.h, 8]; -- alpha pixels
mainMap ← 1;
};
};
}
ELSE
IF numMaps = 2
THEN {
-- overlay or double buffer
mapBits: LONG POINTER;
TRUSTED {
mapBits ← displayData[0].refRep.pointer
+ Basics.LongMult[displayData[0].refRep.rast, box.h]
};
IF box2 = NIL THEN box2 ← box;
displayData[1] ← GetPixelMap[box2.x, box2.y, box2.w, box2.h,
bitsPerPixel - mode.bitsPerPixelChannelA, mapBits];
};
IF pinned
-- point display at bits
THEN {
IF box2 = NIL THEN { box2 ← box; mode.bitsPerPixelChannelB ← 0; }; -- single map
[] ← TerminalColorExtras.SetColorBitmapState[
vt, displayed, mode, channelsVisible,
box.w, box.h, box2.w, box2.h,
NARROW[displayData[mainMap].refRep.ref, CountedVM.Handle].interval
];
IF currentDisplay #
NIL
THEN currentDisplay.props ←
Atom.PutPropOnList[ currentDisplay.props, $PixelMapStatus, $Allocated ];
currentDisplay ← displayData;
displayData.props ← Atom.PutPropOnList[displayData.props, $PixelMapStatus,$Displayed];
}
ELSE
displayData.props ← Atom.PutPropOnList[displayData.props, $PixelMapStatus, $Allocated];
};
IF bitsPerPixel < 16
AND numMaps = 2
THEN {
channelsVisible ← all;
[] ← TerminalColorExtras.SetColorBitmapState[vt, displayed, mode, channelsVisible];
};
IF currentDisplay #
NIL
THEN
TRUSTED {
Interminal.TurnOnColorCursor[ -- turn on cursor
IF mode.full THEN 24 ELSE mode.bitsPerPixelChannelA, -- bits per pixel
displaySide = left -- true => on left
]; };
WindowManager.StartColorViewers[displaySide, mode.bitsPerPixelChannelA]; -- problems!!!??
displayData.displayClass ← displayClass;
Pixels/inch. Depends on display size and # of lines, from User.Profile in Init[]
displayData.xRes ← adjPixPerInch * displayClass.viewUnitsPerPixel;
displayData.yRes ← adjPixPerInch * displayClass.viewUnitsPerPixel;
displayData.rotate ← TRUE;
displayData.cachedColor ← NIL;
colorData ← NEW[ImagerStdColorDisplay.ColorMapData];
colorData.pixelValueList ← NIL;
colorData.colorCalibration ← colorCalibration;
colorData.nextEntry ← 0;
colorData.map ← NIL;
displayData.cachedColorData ← colorData;
setUpMapProc[displayData];
displayData.surfaceWidth ← displayData[0].fSize * displayClass.viewUnitsPerPixel;
displayData.surfaceHeight ← displayData[0].sSize * displayClass.viewUnitsPerPixel;
};
PinPixelMap:
PUBLIC
PROC [vt: Terminal.Virtual, data: DisplayData
, mode: Terminal.ColorMode] ~ {
Pin a pixel map to the color display, replacing whatever was there before.
fSize2, sSize2, mainMap, secondMap: NAT;
channelsVisible: Terminal.ChannelsVisible ←
IF data.numberOfSeparations > 1 AND (mode.bitsPerPixelChannelB # 8 OR mode.full)
THEN all ELSE aOnly;
IF data[0].refRep.ref = NIL THEN ColorDisplayError[$ContextDoesntOwnPixelMap];
TRUSTED { Interminal.TurnOffColorCursor[]; }; -- for safety's sake, disallow cursor action
IF data.displayClass.displayType = $SmoothColor
THEN { mainMap ← 1; secondMap ← 2; }
ELSE { mainMap ← 0; secondMap ← 1; };
IF channelsVisible = all
THEN { fSize2 ← data[secondMap].fSize; sSize2 ← data[secondMap].sSize; }
ELSE { fSize2 ← data[mainMap].fSize; sSize2 ← data[mainMap].sSize; };
[] ← TerminalColorExtras.SetColorBitmapState[
vt, displayed, mode, channelsVisible,
data[mainMap].fSize, data[mainMap].sSize, fSize2, sSize2,
NARROW[data[mainMap].refRep.ref, CountedVM.Handle].interval
];
IF currentDisplay #
NIL
THEN currentDisplay.props ←
Atom.PutPropOnList[ currentDisplay.props, $PixelMapStatus, $Allocated ];
currentDisplay ← data;
data.props ← Atom.PutPropOnList[ data.props, $PixelMapStatus,$Displayed];
IF currentDisplay #
NIL
THEN
TRUSTED {
Interminal.TurnOnColorCursor[ -- turn on cursor
IF mode.full THEN 24 ELSE mode.bitsPerPixelChannelA, -- bits per pixel
displaySide = left -- true => on left
]; };
};
ReleasePixelMap:
PUBLIC
PROC [vt: Terminal.Virtual, data: DisplayData] ~ {
Remove a pixel map from the color display
IF data # currentDisplay THEN Imager.Error[$DataNotCurrentDisplay];
TRUSTED { Interminal.TurnOffColorCursor[]; }; -- for safety's sake, disallow cursor action
[] ← TerminalColorExtras.SetColorBitmapState[
vt, allocated, Terminal.GetColorMode[vt], none,
];
data.props ← Atom.PutPropOnList[ data.props, $PixelMapStatus, $Allocated ];
currentDisplay ← NIL;
};
MoveOverlay:
PUBLIC
PROC [vt: Terminal.Virtual, data:
REF
ANY] ~ {
x, y: NAT ← 0;
list: LIST OF REF ANY ← NARROW[data, LIST OF REF ANY];
x ← NARROW[list.first, REF INTEGER]^;
list ← list.rest;
y ← NARROW[list.first, REF INTEGER]^;
TRUSTED { ColorDisplayFaceExtras.SetBOffsets[x, y]; };
};
SwitchBuffers:
PUBLIC
PROC [] ~ {
TRUSTED { ColorDisplayFaceExtras.SwitchChannels[]; };
};
DoUnderLock:
PUBLIC 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: PUBLIC PROC [displayData: DisplayData,
color: Color, mask: Mask, sTranslate, fTranslate: INTEGER,
cachedColorProc: ImagerStdColorDisplay.CachedColorProc] ~ {
LockedApplyMask:
PROC ~ {
function: ImagerPixelMaps.Function ← [null, null];
IF color = Imager.
XOR
THEN {
color ← ConstantColors.white;
function ← [xor, null];
};
WITH color
SELECT
FROM
constantColor: ConstantColor => {
ImagerMasks.ApplyConstant[
mask: mask,
clipper: displayData.compositeClipper,
dest: displayData[separationNumber],
value: currentPixelValue,
function: function,
sTranslate: sTranslate,
fTranslate: fTranslate
];
};
ENDCASE => Imager.Error[$UnsupportedColorType];
};
separationNumber: NAT;
pixelValues: LIST OF CARDINAL;
currentPixelValue: CARDINAL;
colorData: REF ImagerStdColorDisplay.ColorMapData ← NARROW[displayData.cachedColorData];
bb: DeviceRectangle ← ImagerMasks.BoundingBox[mask];
bb.sMin ← bb.sMin + sTranslate;
bb.fMin ← bb.fMin + fTranslate;
IF color # displayData.cachedColor THEN cachedColorProc[displayData, color];
pixelValues ← colorData.pixelValueList;
FOR separationNumber
IN [0..displayData.numberOfSeparations)
DO
IF pixelValues #
NIL
THEN {
currentPixelValue ← pixelValues.first; pixelValues ← pixelValues.rest;
IF Atom.GetPropFromList[displayData.props, $PixelMapStatus] = $Displayed
THEN
DoUnderLock[displayData, LockedApplyMask, bb]
ELSE LockedApplyMask[];
};
ENDLOOP;
};
LoadColorMap: PUBLIC PROC [ vt: Terminal.Virtual, data: REF ANY,
displayData: DisplayData,
loadColor
: ImagerStdColorDisplay.LoadColorProc] ~ {
start: NAT ← 0;
rgbEntries: REF ImagerStdColorDisplay.RGBSequence ← NIL;
colorEntries: REF ImagerStdColorDisplay.ColorSequence ← NIL;
colorData: REF ImagerStdColorDisplay.ColorMapData ← NIL;
oldColorData: REF ImagerStdColorDisplay.ColorMapData ← NARROW[displayData.cachedColorData];
colorCalibration: ColorModels.Calibration ← oldColorData.colorCalibration;
list:
LIST
OF
REF
ANY ←
NARROW[data,
LIST
OF
REF
ANY];
mode: Terminal.ColorMode ← vt.GetColorMode;
WHILE list #
NIL
DO
WITH list.first
SELECT
FROM
-- pick up map description
rgb: REF ImagerStdColorDisplay.RGBSequence => rgbEntries ← rgb;
color: REF ImagerStdColorDisplay.ColorSequence => colorEntries ← color;
colorMap: REF ImagerStdColorDisplay.ColorMapData => colorData ← colorMap;
calibration: ColorModels.Calibration => colorCalibration ← calibration;
nat: REF INTEGER => start ← nat^;
ENDCASE;
list ← list.rest;
ENDLOOP;
IF colorData # NIL THEN { colorEntries ← colorData.map; oldColorData ← colorData; };
IF rgbEntries =
NIL
AND colorEntries #
NIL
THEN {
FOR i:
NAT
IN [0..
MIN[colorEntries.length, 1024])
DO
IF NOT mode.full THEN oldColorData.map[i] ← colorEntries[i];
loadColor[ colorEntries[i], colorCalibration, i ];
ENDLOOP;
oldColorData.nextEntry ← colorEntries.length;
};
IF rgbEntries #
NIL
THEN {
color: ConstantColor;
FOR i:
NAT
IN [0..
MIN[rgbEntries.length, 1024])
DO
color ← ConstantColors.RGBToColor[
rgbEntries[i].r/255.0, rgbEntries[i].g/255.0, rgbEntries[i].b/255.0,
colorCalibration ];
IF NOT mode.full THEN oldColorData.map[i] ← color;
loadColor[ color, colorCalibration, i ];
ENDLOOP;
oldColorData.nextEntry ← rgbEntries.length;
};
};
MonitorSpecs: UserProfile.ProfileChangedProc =
TRUSTED {
Initialize: set left margin assuming monitor type from resolution (potentially wrong)
displayType: Rope.ROPE ← UserProfile.Token["ColorDisplay.Type", "conrac7211Lo"];
SELECT
TRUE
FROM
Rope.Equal[displayType, "ramtek714", FALSE] => { monitorType ← ramtek714;
pixelsPerInch ← 64; };
Rope.Equal[displayType, "Hitachi2713", FALSE] => { monitorType ← hitachi2713;
pixelsPerInch ← 64; };
Rope.Equal[displayType, "conrac7211Lo", FALSE] => { monitorType ← conrac7211Lo;
pixelsPerInch ← 42; };
Rope.Equal[displayType, "conrac7211Hi", FALSE] => { monitorType ← conrac7211Hi;
pixelsPerInch ← 68; };
ENDCASE => Imager.Error[$UnknownDisplayType];
IF monitorType = conrac7211Hi
THEN ColorDisplayFaceExtras.SetMonitorType[monitorType, 1024, 768]
ELSE ColorDisplayFaceExtras.SetMonitorType[monitorType, 640, 480];
Get display parameters (height, width, etc.) registered in Terminal's global variables
[] ← TerminalColorExtras.SetColorBitmapState[Terminal.Current[], allocated, [FALSE, 1, 0], none];
displaySide ←
IF Rope.Equal[UserProfile.Token["ColorDisplay.Side", "left"], "left",
FALSE]
THEN left ELSE right;
colorCalibration ← ColorModels.GetPhosphorCalibration[
Atom.MakeAtom[UserProfile.Token["ColorDisplay.Calibration", "DefaultLP"] ]
];
};
{
UserProfile.CallWhenProfileChanges[MonitorSpecs];
};
END.