MODULE Displays;
IMPORT SYSTEM, Plugins;
CONST
index8* = 1; color565* = 2; color888* = 3; color8888* = 4;
get* = 0; set* = 1;
red* = 00FF0000H; green* = 0000FF00H; blue* = 000000FFH;
trans* = LONGINT(80000000H);
invert* = 40000000H;
BufSize = 65536;
TYPE
Display* = OBJECT (Plugins.Plugin)
VAR
width*, height*: LONGINT;
offscreen*: LONGINT;
format*: LONGINT;
unit*: LONGINT;
fbadr-: SYSTEM.ADDRESS; fbsize-, fbstride-: LONGINT;
PROCEDURE Transfer*(VAR buf: ARRAY OF CHAR; ofs, stride, x, y, w, h, op: LONGINT);
VAR bufadr, buflow, bufhigh, dispadr: SYSTEM.ADDRESS;
BEGIN
IF w > 0 THEN
ASSERT(fbadr # 0);
bufadr := SYSTEM.ADR(buf[ofs]);
dispadr := fbadr + ((y*width)+x)*format;
ASSERT((dispadr >= fbadr) & ((((y+h-1)*width)+x+ w)*format <= fbsize));
w := w * format;
CASE op OF
set:
WHILE h > 0 DO
SYSTEM.MOVE(bufadr, dispadr, w);
INC(bufadr, stride); INC(dispadr, fbstride);
DEC(h)
END
|get:
buflow := SYSTEM.ADR(buf[0]); bufhigh := buflow + LEN(buf);
WHILE h > 0 DO
ASSERT((bufadr >= buflow) & (bufadr+w <= bufhigh));
SYSTEM.MOVE(dispadr, bufadr, w);
INC(bufadr, stride); INC(dispadr, fbstride);
DEC(h)
END
ELSE
END
END
END Transfer;
PROCEDURE Fill*(col, x, y, w, h: LONGINT);
BEGIN
Fill0(SELF, col, x, y, w, h)
END Fill;
PROCEDURE Dot*(col, x, y: LONGINT);
BEGIN
Fill(col, x, y, 1, 1)
END Dot;
PROCEDURE Mask*(VAR buf: ARRAY OF CHAR; bitof, stride, fg, bg, x, y, w, h: LONGINT);
CONST SetSize = MAX (SET) + 1;
VAR p, i, bitofs: SYSTEM.ADDRESS; s: SET;
BEGIN
IF (w > 0) & (h > 0) THEN
i := SYSTEM.ADR(buf[0]) MOD SYSTEM.SIZEOF (SET);
bitofs := bitof + i * 8;
p := SYSTEM.ADR(buf[0])-i + bitofs DIV SetSize * SYSTEM.SIZEOF (SET);
bitofs := bitofs MOD SetSize; stride := stride*8;
LOOP
SYSTEM.GET(p, s); i := bitofs;
LOOP
IF (i MOD SetSize) IN s THEN
IF fg >= 0 THEN Dot(fg, SHORT(x+i-bitofs), y) END
ELSE
IF bg >= 0 THEN Dot(bg, SHORT (x+i-bitofs), y) END
END;
INC(i);
IF i-bitofs = w THEN EXIT END;
IF i MOD SetSize = 0 THEN SYSTEM.GET(p+i DIV 8, s) END
END;
DEC(h);
IF h = 0 THEN EXIT END;
INC(y); INC(bitofs, stride);
IF (bitofs >= SetSize) OR (bitofs < 0) THEN
INC(p, bitofs DIV SetSize * SYSTEM.SIZEOF (SET)); bitofs := bitofs MOD SetSize
END
END
END
END Mask;
PROCEDURE Copy*(sx, sy, w, h, dx, dy: LONGINT);
BEGIN
Copy0(SELF, sx, sy, w, h, dx, dy)
END Copy;
PROCEDURE Update*;
END Update;
PROCEDURE ColorToIndex*(col: LONGINT): LONGINT;
BEGIN
RETURN SYSTEM.VAL(LONGINT,
SYSTEM.VAL(SET, ASH(col, 7-23)) * {5..7} +
SYSTEM.VAL(SET, ASH(col, 4-15)) * {2..4} +
SYSTEM.VAL(SET, ASH(col, 1-7)) * {0..1})
END ColorToIndex;
PROCEDURE IndexToColor*(index: LONGINT): LONGINT;
BEGIN
RETURN
ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {5..7}), 23-7) +
ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {2..4}), 15-4) +
ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {0..1}), 7-1)
END IndexToColor;
PROCEDURE InitFrameBuffer*(adr: SYSTEM.ADDRESS; size: LONGINT);
BEGIN
ASSERT(width*(height+offscreen)*format <= size);
fbadr := adr; fbsize := size; fbstride := width*format
END InitFrameBuffer;
PROCEDURE Finalize*;
BEGIN
fbadr := 0; fbsize := 0
END Finalize;
END Display;
VAR
registry*: Plugins.Registry;
buf: POINTER TO ARRAY OF CHAR;
PROCEDURE Fill0(d: Display; col, x, y, w, h: LONGINT);
VAR j, w0, h0, s: LONGINT; p: SYSTEM.ADDRESS; t, c: SET; invert: BOOLEAN;
BEGIN {EXCLUSIVE}
IF (w > 0) & (h > 0) & (col >= 0) THEN
invert := ASH(col, 1) < 0;
IF buf = NIL THEN NEW(buf, BufSize) END;
CASE d.format OF
index8:
s := 4; col := d.ColorToIndex(col);
c := SYSTEM.VAL(SET, ASH(col, 24) + ASH(col, 16) + ASH(col, 8) + col)
|color565:
s := 4;
col := SYSTEM.VAL(LONGINT,
SYSTEM.VAL(SET, ASH(col, 15-23)) * {11..15} +
SYSTEM.VAL(SET, ASH(col, 10-15)) * {5..10} +
SYSTEM.VAL(SET, ASH(col, 4-7)) * {0..4});
c := SYSTEM.VAL(SET, ASH(col MOD 10000H, 16) + col MOD 10000H)
|color888:
s := 3; c := SYSTEM.VAL(SET, col MOD 1000000H)
|color8888:
s := 4; c := SYSTEM.VAL(SET, col MOD 1000000H)
END;
w0 := w*d.format; h0 := (LEN(buf^)-3) DIV w0;
ASSERT(h0 > 0);
IF h < h0 THEN h0 := h END;
IF ~invert THEN
p := SYSTEM.ADR(buf[0]);
FOR j := 0 TO (w0*h0-1) DIV s DO SYSTEM.PUT32(p, c); INC(p, s) END
ELSE
IF c = {} THEN c := {0..31} END
END;
LOOP
IF invert THEN
d.Transfer(buf^, 0, w0, x, y, w, h0, get);
p := SYSTEM.ADR(buf[0]);
FOR j := 0 TO (w0*h0-1) DIV s DO
t := SYSTEM.VAL (SET, SYSTEM.GET32(p)); SYSTEM.PUT32(p, t / c); INC(p, s)
END
END;
d.Transfer(buf^, 0, w0, x, y, w, h0, set);
DEC(h, h0);
IF h <= 0 THEN EXIT END;
INC(y, h0);
IF h < h0 THEN h0 := h END
END
END
END Fill0;
PROCEDURE Copy0(d: Display; sx, sy, w, h, dx, dy: LONGINT);
VAR w0, h0, s: LONGINT;
BEGIN {EXCLUSIVE}
IF (w > 0) & (h > 0) THEN
IF buf = NIL THEN NEW(buf, BufSize) END;
w0 := w*d.format; h0 := LEN(buf^) DIV w0;
ASSERT(h0 > 0);
IF (sy >= dy) OR (h <= h0) THEN
s := 1
ELSE
s := -1; INC(sy, h-h0); INC(dy, h-h0)
END;
LOOP
IF h < h0 THEN
IF s = -1 THEN INC(sy, h0-h); INC(dy, h0-h) END;
h0 := h
END;
d.Transfer(buf^, 0, w0, sx, sy, w, h0, get);
d.Transfer(buf^, 0, w0, dx, dy, w, h0, set);
DEC(h, h0);
IF h <= 0 THEN EXIT END;
INC(sy, s*h0); INC(dy, s*h0)
END
END
END Copy0;
BEGIN
NEW(registry, "Displays", "Display drivers");
buf := NIL
END Displays.
(**
o The display origin (0,0) is at the top left.
o The display is "width" pixels wide and "height" pixels high.
o The offscreen area is a possibly empty extension below the visible display. Its height is "offscreen" pixels.
o Rectangles are specified with the top left corner as pinpoint.
o No clipping is performed.
o The offset and stride parameters must always specify values inside the supplied buffer (otherwise results undefined).
o Accessing coordinates outside the display space (including offscreen) is undefined.
o "Undefined" in this case means a trap could occur, or garbage can be displayed, but memory will never be corrupted.
o Colors are 888 truecolor values represented in RGB order with B in the least significant byte. The top 2 bits of a 32-bit color value are used for flags. The other bits are reserved.
o The "invert" flag means the destination color is inverted with the given color. The effect is implementation-defined, but must be reversible with the same color. Usually an XOR operation is performed.
o The "trans" flag means the color is transparent and drawing in this color has no effect. It is defined for Mask only.
o The transfer "format" should be chosen close to the native framebuffer format for efficiency.
o Transfer uses raw framebuffer values, and does not support color flags.
o A concrete Display must implement at least the Transfer function, or initialize a linear frame buffer and call the InitFrameBuffer method.
o An optimized Display driver should override all the primitives with accellerated versions.
o An "index8" display uses a fixed palette and map a truecolor value to an equivalent color in the palette.
o The palette can be chosen freely by a concrete 8-bit Display, which should override the ColorToIndex and IndexToColor methods. These methods are not defined for other formats.
o The default ColorToIndex method assumes a direct-mapped palette with 3 bits each for red and green, and 2 bits for blue.
o Palette animation is not supported.
*)