ImagerStdColorDisplayImpl.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Frank Crow, June 15, 1984 2:28:59 pm PDT
Last Edited by: Hiller, September 6, 1984 11:58:37 pm PDT
DIRECTORY
Imager USING [XOR, Error],
ImagerBasic USING [DeviceRectangle, Color, ColorRep, IntRectangle],
ImagerDisplay USING [DisplayClass, DisplayClassRep, DisplayData, DisplayDataRep],
ImagerDisplayExtras USING [RGBSequence, ColorSequence],
ImagerMasks USING [Mask, ApplyConstant, BoundingBox],
ImagerPixelMaps USING [PixelMap, PixelMapRep, Function],
ColorModels USING [Calibration, GetPhosphorCalibration],
ConstantColors USING [ColorToRGB, white],
Terminal USING [ColorMode, Current, GetColorBitmapState, GetColorMode,
LegalColorMode, SetColor, SetColorBitmapState, Virtual,
SetRedMap, SetGreenMap, SetBlueMap,
WaitForBWVerticalRetrace, GetVisibility, SetVisibility],
TerminalExtras USING [LockColorFrame, UnlockColorFrame],
Interminal USING [TurnOnColorCursor],
Basics USING [LowHalf, BITSHIFT, logBitsPerWord, LongMult],
Atom USING [MakeAtom, PutPropOnList, GetPropFromList],
VM USING [Allocate, AddressForPageNumber, wordsPerPage, Pin, Unpin],
WindowManager USING [ScreenPos],
ColorDisplayFace USING [TurnOn],
ColorDisplayHeadDorado USING [RPtr, mcb, rpNIL, ChanCB, ChanCBPtr, first64K,
screenwidth],
CountedVM USING [Allocate, Pointer, Handle],
UserProfile USING [Token, ProfileChangedProc, CallWhenProfileChanges],
Rope USING [ROPE, Equal],
Real USING [FixC],
ImagerStdColorDisplay;
ImagerStdColorDisplayImpl:
CEDAR
PROGRAM
IMPORTS Imager, ImagerMasks, ColorModels, ConstantColors,
Terminal, TerminalExtras, Atom, UserProfile, Rope, Real, ColorDisplayFace, VM,
CountedVM, Basics, ColorDisplayHeadDorado , Interminal
EXPORTS ImagerStdColorDisplay
SHARES ColorDisplayHeadDorado
~ 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;
on: BOOLEAN ~ TRUE;
off: BOOLEAN ~ FALSE;
ColorDisplayError: PUBLIC SIGNAL [reason: ATOM] ~ CODE;
pinnedDataA, pinnedDataB: DisplayData ← NIL;
fullColor: BOOLEAN ← FALSE;
storage, limit: ColorDisplayHeadDorado.RPtr ← ColorDisplayHeadDorado.rpNIL;
marginOffset: CARDINAL;
leftOverBytes: NAT;
pixelsPerInch: NAT;
displayResolution: {low, high};
displaySide: WindowManager.ScreenPos;
colorCalibration: ColorModels.Calibration;
GetDisplay: PROC[ vt: Terminal.Virtual, onMode: ATOM, mode: Terminal.ColorMode,
lgBitsPerPixel:
NAT] ~ {
displayMode: Terminal.ColorMode ~ vt.GetColorMode;
IF
NOT vt.hasColorDisplay
THEN ERROR ColorDisplayError[$NoColorDisplay];
IF (onMode = $reSet)
OR (vt.GetColorBitmapState = none)
THEN {
-- setting up new display
IF
NOT vt.LegalColorMode[mode]
THEN ERROR ColorDisplayError[$DisplayModeNotSupported];
[] ← vt.SetColorBitmapState[$displayed, mode, $none]; -- turn on display
TRUSTED {
Interminal.TurnOnColorCursor[ -- turn on cursor
IF mode.full THEN 24 ELSE mode.bitsPerPixelChannelA, -- bits per pixel
displaySide = left -- true => on left
]; };
IF onMode = $reSet THEN onMode ← IF lgBitsPerPixel > 3 THEN $all ELSE $aOn;
}
ELSE IF
-- display previously in use
(((onMode = $aOn) OR (onMode = $all))
AND (displayMode.bitsPerPixelChannelA # mode.bitsPerPixelChannelA))
OR
(((onMode = $bOn) OR (onMode = $all))
AND (displayMode.bitsPerPixelChannelB # mode.bitsPerPixelChannelB))
THEN ERROR ColorDisplayError[$IncompatibleDisplayMode];
SELECT onMode
FROM
$aOn => IF vt.GetVisibility = bOnly OR vt.GetVisibility = all THEN vt.SetVisibility[all]
ELSE vt.SetVisibility[aOnly];
$bOn => IF vt.GetVisibility = aOnly OR vt.GetVisibility = all THEN vt.SetVisibility[all]
ELSE vt.SetVisibility[bOnly];
$all => vt.SetVisibility[all];
$none => vt.SetVisibility[none];
$unchanged => {};
ENDCASE => ERROR ColorDisplayError[$UndefinedOnMode];
};
Create: PUBLIC PROC [vt: Terminal.Virtual, mode: Terminal.ColorMode,
displayClass: DisplayClass, creationData: REF,
lgBitsPerPixel:
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, lgBitsPerPixel: NAT, pointer: LONG POINTER ← NIL]
RETURNS[pixelMap: ImagerPixelMaps.PixelMap] ~ {
pxpWd: NAT ← Basics.BITSHIFT[1, Basics.logBitsPerWord - lgBitsPerPixel];
wordsPerLine: NAT ← IF width MOD pxpWd = 0 THEN width / pxpWd
ELSE width / pxpWd + 1;
words: INT ← Basics.LongMult[wordsPerLine, height + 1];
storage: CountedVM.Handle ← NIL;
IF pointer =
NIL
THEN {
storage ← CountedVM.Allocate[words: words];
TRUSTED { pointer ← CountedVM.Pointer[storage]; };
};
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: wordsPerLine,
lines: height
]]
];
};
numMaps: NAT;
colorData: REF ImagerStdColorDisplay.ColorMapData;
pxpWd: NAT ← Basics.BITSHIFT[1, Basics.logBitsPerWord - lgBitsPerPixel];
creationList: LIST OF REF ANY ← NARROW[creationData, LIST OF REF ANY];
SELECT lgBitsPerPixel
FROM
-- 2 maps for 24bit color, 4 for 32bit color
4 => numMaps ← 2;
5 => numMaps ← 4;
ENDCASE => numMaps ← 1;
displayData ← NEW[DisplayDataRep[numMaps]]; -- Make a rep
displayData.displayClass ← displayClass;
Pixels/inch. Depends on display size and # of lines, from User.Profile in Init[]
displayData.xRes ← pixelsPerInch * displayClass.viewUnitsPerPixel;
displayData.yRes ← pixelsPerInch * displayClass.viewUnitsPerPixel;
displayData.rotate ←
TRUE;
IF creationList =
NIL
THEN {
-- use default pixel map
[] ← GetDisplay[vt, $reSet, mode, lgBitsPerPixel];
displayData[0] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight, lgBitsPerPixel,
vt.colorBitmapA];
displayData.props ← Atom.PutPropOnList[displayData.props, $PixelMapStatus, $OnAChannel];
IF numMaps > 1
THEN {
blueMap: NAT ← IF numMaps = 4 THEN 2 ELSE 1;
displayData[blueMap] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight, 3,
vt.colorBitmapB];
};
IF numMaps = 4
THEN {
displayData[1] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight, 3]; -- green pixels
displayData[3] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight, 3]; -- alpha pixels
};
IF pinnedDataA #
NIL
THEN
IF
NOT mode.full
THEN
PinPixelMap[vt, displayData, FALSE, mode] --fix DCB chain
ELSE {
-- old display was full color
IF pinnedDataA #
NIL
THEN
VM.Unpin[ NARROW[pinnedDataA.pix[0].refRep.ref, CountedVM.Handle].interval ];
IF pinnedDataB #
NIL
THEN
IF fullColor
THEN
VM.Unpin[ NARROW[pinnedDataB.pix[1].refRep.ref, CountedVM.Handle].interval ]
ELSE
VM.Unpin[ NARROW[pinnedDataB.pix[0].refRep.ref, CountedVM.Handle].interval ];
pinnedDataA ← NIL; pinnedDataB ← NIL;
};
IF mode.full THEN fullColor ← TRUE ELSE fullColor ← FALSE;
}
ELSE {
-- make new pixel map for 2-bit pixel maps (for overlays)
pinned: BOOLEAN ← TRUE;
box: REF ImagerBasic.IntRectangle ← NIL;
WHILE creationList #
NIL
DO
-- pick up pin command, box, or both
WITH creationList.first
SELECT
FROM
pinTruth: REF BOOLEAN => pinned ← pinTruth^;
boxRef: REF ImagerBasic.IntRectangle => box ← boxRef;
ENDCASE;
creationList ← creationList.rest
ENDLOOP;
IF box = NIL THEN box^ ← [0, 0, vt.colorWidth, vt.colorHeight]; -- use screen size
displayData[0] ← GetPixelMap[box.x, box.y, box.w, box.h, lgBitsPerPixel];
displayData.props ← Atom.PutPropOnList[displayData.props, $PixelMapStatus, $Allocated];
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, 3, blueBits];
};
IF numMaps = 4
THEN {
displayData[1] ← GetPixelMap[box.x, box.y, box.w, box.h, 3]; -- green pixels
displayData[3] ← GetPixelMap[box.x, box.y, box.w, box.h, 3]; -- alpha pixels
};
IF pinned
THEN {
PinPixelMap[vt, displayData, FALSE, mode];
IF mode.full THEN fullColor ← TRUE ELSE fullColor ← FALSE;
};
};
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;
};
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
currentPixelValue ← pixelValues.first; pixelValues ← pixelValues.rest;
IF Atom.GetPropFromList[displayData.props, $PixelMapStatus] = $OnAChannel
THEN
DoUnderLock[displayData, LockedApplyMask, bb]
ELSE LockedApplyMask[];
ENDLOOP;
};
PinPixelMap: PUBLIC PROC [vt: Terminal.Virtual, data: DisplayData, overLay: BOOLEAN ← FALSE,
mode: Terminal.ColorMode] ~ {
Pin a pixel map to the color display, replacing whatever was there before. Overlay = TRUE causes the B-channel to be used. Overlays may have only 2 or 4 bits per pixel, 4 only if the A-channel (non-overlay) pixelmap has <= 4 bits per pixel.
turnOnNeeded: BOOLEAN ← FALSE;
numChannels: NAT ← IF mode.full THEN 2 ELSE 1; -- check for full color
bitmapPtrA, bitmapPtrB:
LONG
POINTER;
Make sure display is on
IF (data[0].refRep.ref =
NIL)
AND (pinnedDataA #
NIL)
THEN
-- this doesn't have own bits
GetDisplay[vt, $reSet, mode, data[0].refRep.lgBitsPerPixel]
ELSE
IF overLay
THEN {
IF (vt.GetVisibility = none) OR (vt.GetVisibility = aOnly)
THEN GetDisplay[vt, $bOn, mode, data.pix[0].refRep.lgBitsPerPixel]
}
ELSE
IF
NOT mode.full
THEN {
IF (vt.GetVisibility = none) OR (vt.GetVisibility = bOnly)
THEN GetDisplay[vt, $aOn, mode, data.pix[0].refRep.lgBitsPerPixel];
}
ELSE {
-- full color, reset if not previously full color
IF fullColor THEN GetDisplay[vt, $all, mode, 4] ELSE GetDisplay[vt, $reSet, mode, 4];
};
Do for both channels if full color, otherwise do for channel indicated by "overLay"
FOR i:
NAT
IN [0 ..
numChannels)
DO
logPixelsPerWord: NAT ← Basics.logBitsPerWord - data.pix[i].refRep.lgBitsPerPixel;
bChannel:
BOOLEAN ← overLay
OR (i = 1);
-- put on B if overlay or 2nd pixelmap
Catch negative origins and bite into pixelmap
bitmapPtr: LONG POINTER;
widthChange, heightChange: INTEGER ← 0;
TRUSTED {
IF data.pix[i].sOrigin >= 0
THEN bitmapPtr ← data.pix[i].refRep.pointer
ELSE {
bitmapPtr ← data.pix[i].refRep.pointer
+ Basics.LongMult[-data.pix[i].sOrigin, data.pix[i].refRep.rast];
heightChange ← data.pix[i].sOrigin;
};
IF data.pix[i].fOrigin < 0
THEN {
ptrChange: NAT ← Basics.BITSHIFT[
Basics.BITSHIFT[ -data.pix[i].fOrigin, -(logPixelsPerWord+1)],
1];
bitmapPtr ← bitmapPtr + ptrChange;
widthChange ← -Basics.BITSHIFT[ ptrChange, logPixelsPerWord];
};
};
IF bChannel
THEN bitmapPtrB ← bitmapPtr
ELSE bitmapPtrA ← bitmapPtr;
Set Null DCB to move down proper distance from top of screen
SetDCB[ aChannel: NOT bChannel,
bitmap: bitmapPtr,
leftMargin: 0,
width: 0,
height: MAX[0, data.pix[i].sOrigin],
wordsPerLine: 0,
whichLink: 0
];
Make sure pinned storage held by ImagerStdColorDisplayImpl is released
IF bChannel
THEN {
IF pinnedDataB #
NIL
THEN
IF fullColor
THEN VM.Unpin[ NARROW[pinnedDataB.pix[i].refRep.ref, CountedVM.Handle].interval ]
ELSE VM.Unpin[ NARROW[pinnedDataB.pix[0].refRep.ref, CountedVM.Handle].interval ];
}
ELSE
IF pinnedDataA #
NIL
THEN
VM.Unpin[
NARROW[pinnedDataA.pix[i].refRep.ref, CountedVM.Handle].interval ];
Pin VM pages for pixelmap
IF data.pix[i].refRep.ref #
NIL
-- refRep = NIL means this is Terminal.mesa's color memory
THEN VM.Pin[ NARROW[data.pix[i].refRep.ref, CountedVM.Handle].interval ];
Set DCB representing pixelmap
SetDCB[ aChannel: NOT bChannel,
bitmap: bitmapPtr,
leftMargin: MAX[0, data.pix[i].fOrigin],
width: MAX[0,
Basics.BITSHIFT[ data.pix[i].refRep.rast, logPixelsPerWord]
+ widthChange],
height: MAX[0, data.pix[i].refRep.lines + heightChange],
wordsPerLine: data.pix[i].refRep.rast,
whichLink: 1
];
Set flags showing whether Terminal or ImagerStdColorDisplay got the bits
IF
NOT bChannel
THEN {
IF pinnedDataA = NIL THEN turnOnNeeded ← TRUE; -- flag need to unpin display
IF data.pix[0].refRep.ref # NIL THEN pinnedDataA ← data ELSE pinnedDataA ← NIL;
}
ELSE {
-- Overlay or full color
IF data.pix[0].refRep.ref # NIL THEN pinnedDataB ← data ELSE pinnedDataB ← NIL;
};
ENDLOOP;
Turn off and unpin standard display if in use
IF turnOnNeeded
THEN {
[] ← vt.SetColorBitmapState[$allocated, mode, vt.GetVisibility];
TRUSTED { ColorDisplayFace.TurnOn[]; }; -- Sneak by TerminalImpl, get display on
Reset bitmap pointer, etc. for color cursor
vt.colorBitmapA ← bitmapPtrA; vt.colorWordsPerLineA ← data.pix[0].refRep.rast;
vt.colorWidth ← data.pix[0].fSize; vt.colorHeight ← data.pix[0].sSize;
IF mode.full
THEN {
-- Reset bitmap pointer, etc. for full color cursor
vt.colorBitmapB ← bitmapPtrB; vt.colorWordsPerLineB ← data.pix[1].refRep.rast;
};
};
Update displayData to show it is on screen, leave ref to displayed data in global
IF overLay
THEN {
data.props ← Atom.PutPropOnList[data.props, $PixelMapStatus, $OnBChannel];
}
ELSE {
data.props ← Atom.PutPropOnList[data.props, $PixelMapStatus, $OnAChannel];
IF NOT mode.full THEN DownLoadColorMap[vt, data]; -- get map if pseudcolor
};
};
ReleasePixelMap:
PUBLIC
PROC [vt: Terminal.Virtual, data: DisplayData] ~ {
Remove a pixel map from the color display
IF Atom.GetPropFromList[data.props, $PixelMapStatus] = $OnAChannel
THEN { DeleteDCB[TRUE, 1];
data.props ← Atom.PutPropOnList[data.props, $PixelMapStatus, $Allocated];
pinnedDataA ← NIL;
}
ELSE
IF Atom.GetPropFromList[data.props, $PixelMapStatus] = $OnBChannel
THEN { DeleteDCB[FALSE, 1];
data.props ← Atom.PutPropOnList[data.props, $PixelMapStatus, $Allocated];
pinnedDataB ← NIL;
}
ELSE SIGNAL ColorDisplayError[$UnDisplayedPixelMap];
VM.Unpin[ NARROW[data.pix[0].refRep.ref, CountedVM.Handle].interval ]; -- release storage
};
DownLoadColorMap:
PROC [vt: Terminal.Virtual, displayData: DisplayData] ~ {
list: LIST OF REF ANY ← LIST[displayData.cachedColorData];
LoadColorMap[vt, list];
};
LoadColorMap:
PUBLIC
PROC [vt: Terminal.Virtual, data:
REF
ANY] ~ {
start: NAT ← 0;
rgbEntries: REF ImagerDisplayExtras.RGBSequence ← NIL;
colorEntries: REF ImagerDisplayExtras.ColorSequence ← NIL;
colorData: REF ImagerStdColorDisplay.ColorMapData ← NIL;
colorCalibration: ColorModels.Calibration ← NIL;
list:
LIST
OF
REF
ANY ←
NARROW[data,
LIST
OF
REF
ANY];
mode: Terminal.ColorMode ← vt.GetColorMode;
vt.WaitForBWVerticalRetrace[];
-- await vt selection and top of scan (to control update rate)
WHILE list #
NIL
DO
WITH list.first
SELECT
FROM
-- pick up map description
rgb: REF ImagerDisplayExtras.RGBSequence => rgbEntries ← rgb;
color: REF ImagerDisplayExtras.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 rgbEntries ← colorData.rgbMap;
IF colorEntries #
NIL
THEN {
rgbEntries ← NEW[ ImagerDisplayExtras.RGBSequence[colorEntries.length] ];
FOR i:
NAT
IN [0..colorEntries.length)
DO
r, g, b: REAL;
[r, g, b] ← ConstantColors.ColorToRGB[colorEntries[i], colorCalibration];
rgbEntries[i].r ← Real.FixC[r * 255.0];
rgbEntries[i].g ← Real.FixC[g * 255.0];
rgbEntries[i].b ← Real.FixC[b * 255.0];
ENDLOOP;
};
IF rgbEntries #
NIL
THEN {
IF mode.full = FALSE -- pseudocolor mapped display
THEN
IF (mode.bitsPerPixelChannelB = 2)
OR (mode.bitsPerPixelChannelB = 0)
THEN {
FOR i:
NAT
DECREASING
IN [start..rgbEntries.length+start)
DO
index: NAT ← i MOD 256; table: NAT ← i / 256; -- 4 tables each 256 entries
vt.SetColor[index, table, rgbEntries[i].r, rgbEntries[i].g, rgbEntries[i].b];
ENDLOOP; }
ELSE {
FOR i:
NAT
DECREASING
IN [start..rgbEntries.length+start)
DO
index: NAT ← i MOD 16; table: NAT ← i / 16; -- 16 tables each 16 entries
vt.SetColor[index, table, rgbEntries[i].r, rgbEntries[i].g, rgbEntries[i].b];
ENDLOOP ; }
ELSE
FOR index:
NAT
IN [start..rgbEntries.length+start)
DO
-- full-color 24-bit display
vt.SetRedMap[index, rgbEntries[index].r];
vt.SetGreenMap[index, rgbEntries[index].g];
vt.SetBlueMap[index, rgbEntries[index].b];
ENDLOOP;
};
};
SetDCB: PROC [aChannel: BOOLEAN ← TRUE, bitmap: LONG POINTER,
leftMargin, width, height, wordsPerLine, whichLink:
NAT] ~
TRUSTED {
Alloc:
PROC [words:
CARDINAL]
RETURNS [pointer: ColorDisplayHeadDorado.RPtr] ~
TRUSTED{
page, count: INT;
storageTop: ColorDisplayHeadDorado.RPtr ← storage + words;
IF (storage = ColorDisplayHeadDorado.rpNIL)
OR (LOOPHOLE[storageTop, CARDINAL] > LOOPHOLE[limit, CARDINAL])
THEN {
[[page, count]] ← VM.Allocate[count: 1, partition: lowCore, in64K: TRUE];
storage ← LOOPHOLE[Basics.LowHalf[LOOPHOLE[VM.AddressForPageNumber[page]]]];
limit ← storage + VM.wordsPerPage;
};
pointer ← storage;
storage ← storage + words;
};
link: NAT ← 0;
chainPtr, lastPtr:
LONG
POINTER
TO ColorDisplayHeadDorado.ChanCB ← NIL;
Check for color display MCB, then DCB chain
IF ColorDisplayHeadDorado.mcb =
NIL
THEN {
SIGNAL ColorDisplayError[$NoColorDisplay]; RETURN[]; };
IF aChannel THEN lastPtr ← chainPtr ←
@ColorDisplayHeadDorado.first64K[ColorDisplayHeadDorado.mcb.achanCB]
ELSE lastPtr ← chainPtr ←
@ColorDisplayHeadDorado.first64K[ColorDisplayHeadDorado.mcb.bchanCB];
IF chainPtr =
NIL
THEN {
SIGNAL ColorDisplayError[$NoDCBChain]; RETURN[]; };
IF whichLink > 31 THEN { SIGNAL ColorDisplayError[$Over32DCBs]; RETURN[]; };
IF (wordsPerLine * 2 > leftOverBytes)
THEN
-- check for excess leftovers at end of scan
IF (ColorDisplayHeadDorado.screenwidth - width) > leftOverBytes
THEN { SIGNAL ColorDisplayError[$ExcessLeftOverPixels]; RETURN[]; };
Find desired link in DCB chain
WHILE (link < whichLink)
AND
NOT (chainPtr = NIL)
DO
link ← link + 1;
lastPtr ← chainPtr; -- step to next link
IF chainPtr.link = ColorDisplayHeadDorado.rpNIL
THEN chainPtr ← NIL
ELSE chainPtr ← @ColorDisplayHeadDorado.first64K[chainPtr.link];
ENDLOOP;
Load desired link; Make new links if desired link lies beyond end of chain
WHILE link <= whichLink
DO
relPtr: ColorDisplayHeadDorado.ChanCBPtr ← ColorDisplayHeadDorado.rpNIL;
IF chainPtr =
NIL
THEN {
-- Make new DCB, if unlinked
relPtr ← Alloc[SIZE[ColorDisplayHeadDorado.ChanCB]];
chainPtr ← @ColorDisplayHeadDorado.first64K[relPtr];
chainPtr.link ← ColorDisplayHeadDorado.rpNIL; -- make sure chain ends here
}
ELSE relPtr ← lastPtr.link; -- in case chain is already linked (or zeroth link)
IF (link < whichLink)
OR (width = 0)
-- null DCB
THEN {
chainPtr.wordsPerLine ← 0;
chainPtr.bitmap ← NIL;
chainPtr.linesPerField ← IF link = whichLink THEN height / 2 ELSE 0;
chainPtr.pixelsPerLine ← 0;
chainPtr.leftMargin ← LAST[NAT];
chainPtr.scan ← lastPtr.scan;
}
ELSE {
chainPtr.wordsPerLine ← wordsPerLine; -- load visible DCB
chainPtr.bitmap ← bitmap;
chainPtr.linesPerField ← height / 2;
chainPtr.pixelsPerLine ← width + 255;
chainPtr.leftMargin ← leftMargin + marginOffset;
chainPtr.scan ← lastPtr.scan;
};
lastPtr.link ← relPtr; -- link into DCB chain after loaded
lastPtr ← chainPtr; -- step to next link
IF chainPtr.link = ColorDisplayHeadDorado.rpNIL
THEN chainPtr ← NIL
ELSE chainPtr ← @ColorDisplayHeadDorado.first64K[chainPtr.link];
link ← link + 1;
ENDLOOP;
};
DeleteDCB:
PROC [aChannel:
BOOLEAN ←
TRUE, whichLink:
NAT] ~
TRUSTED {
link: NAT ← 0;
chainPtr, lastPtr: LONG POINTER TO ColorDisplayHeadDorado.ChanCB ← NIL;
IF ColorDisplayHeadDorado.mcb =
NIL
THEN {
SIGNAL ColorDisplayError[$NoColorDisplay]; RETURN[]; };
IF aChannel THEN lastPtr ← chainPtr ←
@ColorDisplayHeadDorado.first64K[ColorDisplayHeadDorado.mcb.achanCB]
ELSE lastPtr ← chainPtr ←
@ColorDisplayHeadDorado.first64K[ColorDisplayHeadDorado.mcb.bchanCB];
IF chainPtr =
NIL
THEN {
SIGNAL ColorDisplayError[$NoDCBChain]; RETURN[]; };
Find desired link in DCB chain
WHILE (link < whichLink)
AND
NOT (chainPtr = NIL)
DO
link ← link + 1;
lastPtr ← chainPtr; -- step to next link
IF chainPtr.link = ColorDisplayHeadDorado.rpNIL
THEN chainPtr ← NIL
ELSE chainPtr ← @ColorDisplayHeadDorado.first64K[chainPtr.link];
ENDLOOP;
Delete Link, if found, note, no storage recovery
IF (link = whichLink) AND (chainPtr # NIL) THEN lastPtr.link ← chainPtr.link;
};
MonitorSpecs: UserProfile.ProfileChangedProc =
TRUSTED {
Initialize: set left margin assuming monitor type from resolution (potentially wrong)
displayType: Rope.ROPE ← UserProfile.Token["ColorDisplay.Type", "640x480"];
SELECT
TRUE
FROM
Rope.Equal[displayType, "640x480",
FALSE] => {
pixelsPerInch ← 64;
marginOffset ← 54; -- Hitachi 13" monitors @480 lines
leftOverBytes ← 460; -- Exceeding this causes unstable raster
displayResolution ← low;
};
Rope.Equal[displayType, "1024x768",
FALSE] => {
pixelsPerInch ← 68;
marginOffset ← 71; -- Conrac @768 lines (may be 0, actually)
leftOverBytes ← 1024;
displayResolution ← high;
};
ENDCASE => {
-- 640x480 is the default
pixelsPerInch ← 64;
marginOffset ← 54;
leftOverBytes ← 460;
displayResolution ← low;
};
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.