<> <> <> <<>> 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, WaitForBWVerticalRetrace], 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 <> 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: 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] ~ { <> 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 _ 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 <> 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] _ GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight, 8]; -- green 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 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] _ GetPixelMap[box.x, box.y, box.w, box.h, 8]; -- green pixels displayData[3] _ GetPixelMap[box.x, box.y, box.w, box.h, 8]; -- alpha pixels }; }; } 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[0].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; <> 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] ~ { <> fSize2, sSize2: 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 channelsVisible = all THEN { fSize2 _ data[1].fSize; sSize2 _ data[1].sSize; } ELSE { fSize2 _ data[0].fSize; sSize2 _ data[0].sSize; }; [] _ TerminalColorExtras.SetColorBitmapState[ vt, displayed, mode, channelsVisible, data[0].fSize, data[0].sSize, fSize2, sSize2, NARROW[data[0].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] ~ { <> 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; 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 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..MAX[colorEntries.length, 256]) DO oldColorData.map[i] _ colorEntries[i]; loadColor[ colorEntries[i], colorCalibration, i ]; ENDLOOP; oldColorData.nextEntry _ colorEntries.length; }; IF rgbEntries # NIL THEN { FOR i: NAT IN [0..MAX[rgbEntries.length, 256]) DO oldColorData.map[i] _ ConstantColors.RGBToColor[ rgbEntries[i].r/255.0, rgbEntries[i].g/255.0, rgbEntries[i].b/255.0, colorCalibration ]; loadColor[ oldColorData.map[i], colorCalibration, i ]; ENDLOOP; oldColorData.nextEntry _ rgbEntries.length; }; }; MonitorSpecs: UserProfile.ProfileChangedProc = TRUSTED { <> 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]; <> [] _ 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.