-- ColorDisplay.mesa
-- Last edit by Maureen Stone, June 9, 1982 4:04 pm
-- Last edit by Doug Wyatt, 10-Jul-81  0:50:42

DIRECTORY
  Inline USING [LongMult],
  UserTerminal USING [CursorArray];

ColorDisplay: DEFINITIONS
IMPORTS Inline = {

-- Processor-independent interface to color display.

-- Types

Mode: TYPE = RECORD[full: BOOLEAN, bitsPerPixelA,bitsPerPixelB: [0..8]];
-- Mode encodes the possible color display modes.
-- full=TRUE specifies 24 bit per pixel mode; the other fields are ignored
-- full=FALSE specifies a mapped mode with one or two bitmaps, each with the given
--  number of bits per pixel. Acceptable values are 0 (no bitmap), 1, 2, 4, or 8.
-- Not all modes are implemented on a particular processor; see HasMode, below.

disconnected: Mode = [FALSE,0,0];
-- The initial mode, with the color display entirely disabled.
-- Setting this mode releases the resources used by the color display.
-- Processors lacking color displays have only this mode.

Byte: TYPE = [0..256);
Pair: TYPE = MACHINE DEPENDENT RECORD[r,g: Byte];
ByteSeq: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF Byte];
PairSeq: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF Pair];

CursorArray: TYPE = UserTerminal.CursorArray;
Coordinate: TYPE = MACHINE DEPENDENT RECORD [x, y: INTEGER];

-- The cursor mode indicates whether, given a bit=1 in the cursor array, 
-- the corresponding pixel value is set to all ones or all zeros.  For 24 bpp mode
-- and the conventional color maps, the correspondence is ones=white and zeros=black.
CursorMode: TYPE = {ones,zeros};

-- Interface variables

pixelsPerInch: READONLY CARDINAL; -- size of a pixel
displayType: READONLY CARDINAL; -- display type; 0 means display not available
mixedRG: READONLY BOOLEAN; -- red and green interleaved in 24 bit mode

-- The following variables may be changed by SetMode!
curmode: READONLY Mode; -- the current mode
width,height: READONLY CARDINAL; -- size of raster in current mode
baseA,baseB,baseC: READONLY LONG POINTER; -- bitmap address
wplA,wplB,wplC: READONLY CARDINAL; -- bitmap words per line

cursorPosition: READONLY LONG POINTER TO Coordinate;
cursorWidth: READONLY INTEGER;	--defined as 16 for now
cursorHeight: READONLY INTEGER;	--defined as 16 for now

-- Procedures

HasMode: PROCEDURE[mode: Mode] RETURNS[BOOLEAN];
-- Return TRUE if the specified mode is available.

GetMode: PROCEDURE RETURNS[Mode] = INLINE { RETURN[curmode] };
-- Return the current mode.

SetMode: PROCEDURE[mode: Mode] RETURNS[BOOLEAN];
-- Establish the specified mode. Allocate bitmap and colormap storage as necessary.
-- Return TRUE if successful, FALSE if mode is not available.
-- Subsequent bitmap or colormap changes will affect the color image,
-- but the image will not appear on the screen until TurnOn is called.
-- If mode=disconnected, disable the color display, releasing all storage.

-- All following procedures should be used only when GetMode[]#disconnected.

TurnOn: PROCEDURE;
-- Turn the display on, causing an image to appear on the screen.

TurnOff: PROCEDURE;
-- Turn the display off, causing the screen to be dark.
-- The display's storage is retained; the image will reappear if TurnOn is called.

Show: PROCEDURE[a,b,c: BOOLEAN ← TRUE];
-- Make the specified bitmap visible (TRUE) or invisible (FALSE).

-- Procedures for mapped modes (mode.full=FALSE)

GetColor: PROCEDURE[pixelA,pixelB: CARDINAL ← 0] RETURNS[r,g,b: Byte];
-- Return the current color map entry for the given pixel value(s).

SetColor: PROCEDURE[pixelA,pixelB: CARDINAL ← 0, r,g,b: Byte];
-- Set the color map entry for the given pixel value(s).
-- If the display is 'on', the screen will show the change by the next frame time.

-- Procedures for manipulating the cursor

SetCursorPattern: PROC [cursorPattern: CursorArray];
GetCursorPattern: PROCEDURE RETURNS [cursorPattern: CursorArray];
SetCursorPosition: PROCEDURE [newMousePosition: Coordinate];

SetCursorMode: PROC [color: CursorMode];

--the cursor must be hidden and restored when the area of the
--framebuffer occupied by the cursor is changed.
HideCursor: PROC;  --restore the frame buffer
RestoreCursor: PROC;  --draw the cursor at its last position

--the cursor must be locked while a scanline is being drawn
--ONLY ColorDeviceImpl should call these two procedures
SetLock: PROC;
ClearLock: PROC;
--called ONLY by ColorDisplayImpl to indicate that the display mode changed 
NotifyCursor: PROC; 

-- Procedures for 24 bit per pixel mode (mode.full=TRUE)

InBounds: PROC[x,y: CARDINAL] RETURNS[BOOLEAN] = INLINE {
  RETURN[curmode.full AND x<width AND y<height] };

GetR: PRIVATE PROC[x,y: CARDINAL] RETURNS[Byte] = INLINE { IF mixedRG
  THEN RETURN[LOOPHOLE[baseA + Inline.LongMult[wplA,y],LONG POINTER TO PairSeq][x].r]
  ELSE RETURN[LOOPHOLE[baseA + Inline.LongMult[wplA,y],LONG POINTER TO ByteSeq][x]] };
GetG: PRIVATE PROC[x,y: CARDINAL] RETURNS[Byte] = INLINE { IF mixedRG
  THEN RETURN[LOOPHOLE[baseA + Inline.LongMult[wplA,y],LONG POINTER TO PairSeq][x].g]
  ELSE RETURN[LOOPHOLE[baseB + Inline.LongMult[wplB,y],LONG POINTER TO ByteSeq][x]] };
GetB: PRIVATE PROC[x,y: CARDINAL] RETURNS[Byte] = INLINE { IF mixedRG
  THEN RETURN[LOOPHOLE[baseB + Inline.LongMult[wplB,y],LONG POINTER TO ByteSeq][x]]
  ELSE RETURN[LOOPHOLE[baseC + Inline.LongMult[wplC,y],LONG POINTER TO ByteSeq][x]] };

SetR: PRIVATE PROC[x,y: CARDINAL, r: Byte] = INLINE { IF mixedRG
  THEN LOOPHOLE[baseA + Inline.LongMult[wplA,y],LONG POINTER TO PairSeq][x].r ← r
  ELSE LOOPHOLE[baseA + Inline.LongMult[wplA,y],LONG POINTER TO ByteSeq][x] ← r };
SetG: PRIVATE PROC[x,y: CARDINAL, g: Byte] = INLINE { IF mixedRG
  THEN LOOPHOLE[baseA + Inline.LongMult[wplA,y],LONG POINTER TO PairSeq][x].g ← g
  ELSE LOOPHOLE[baseB + Inline.LongMult[wplB,y],LONG POINTER TO ByteSeq][x] ← g };
SetB: PRIVATE PROC[x,y: CARDINAL, b: Byte] = INLINE { IF mixedRG
  THEN LOOPHOLE[baseB + Inline.LongMult[wplB,y],LONG POINTER TO ByteSeq][x] ← b
  ELSE LOOPHOLE[baseC + Inline.LongMult[wplC,y],LONG POINTER TO ByteSeq][x] ← b };

GetPixel: PUBLIC PROC[x,y: CARDINAL] RETURNS[r,g,b: Byte] = INLINE {
  IF InBounds[x,y] THEN RETURN[r: GetR[x,y], g: GetG[x,y], b: GetB[x,y]]
  ELSE RETURN[0,0,0] };
-- Return the color of the pixel at coordinates (x,y).
-- The pixel with coordinates (0,0) is at the upper left corner of the screen.
-- Returns [0,0,0] if x or y is out of range.

SetPixel: PUBLIC PROC[x,y: CARDINAL, r,g,b: Byte] = INLINE {
  IF InBounds[x,y] THEN { SetR[x,y,r]; SetG[x,y,g]; SetB[x,y,b] } };
-- Set the pixel at coordinates (x,y) to the specified color.
-- The pixel with coordinates (0,0) is at the upper left corner of the screen.
-- Ignored if x or y is out of range.

SetRed: PUBLIC PROC[x,y: CARDINAL, value: Byte] = INLINE {
  IF InBounds[x,y] THEN SetR[x,y,value] };
SetGreen: PUBLIC PROC[x,y: CARDINAL, value: Byte] = INLINE {
  IF InBounds[x,y] THEN SetG[x,y,value] };
SetBlue: PUBLIC PROC[x,y: CARDINAL, value: Byte] = INLINE {
  IF InBounds[x,y] THEN SetB[x,y,value] };
-- Set red, green, or blue value for a pixel independently.

GetRedMap,GetGreenMap,GetBlueMap: PROCEDURE[in: Byte] RETURNS[out: Byte];
-- Return the current entry from the red, green, or blue map.

SetRedMap,SetGreenMap,SetBlueMap: PROCEDURE[in,out: Byte];
-- Set an entry in the red, green, or blue map.
-- If the display is 'on', the screen will show the change by the next frame time.

}.