Displays.Mod 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE Displays; (** AUTHOR "pjm"; PURPOSE "Abstract display device driver"; *)
  3. IMPORT SYSTEM, Plugins;
  4. CONST
  5. (** formats for Transfer. value = bytes per pixel. *)
  6. index8* = 1; color565* = 2; color888* = 3; color8888* = 4;
  7. (** operations for Transfer. *)
  8. get* = 0; set* = 1;
  9. (** color components. *)
  10. red* = 00FF0000H; green* = 0000FF00H; blue* = 000000FFH;
  11. trans* = LONGINT(80000000H); (** transparency for Mask. *)
  12. invert* = 40000000H; (** inverting. *)
  13. (*alpha = 0C0000000H; (** alpha blending. *)*)
  14. BufSize = 65536;
  15. VAR
  16. reverse*:BOOLEAN;
  17. TYPE
  18. Display* = OBJECT (Plugins.Plugin)
  19. VAR
  20. width*, height*: LONGINT; (** dimensions of visible display. *)
  21. offscreen*: LONGINT; (** number of non-visible lines at the bottom of the display. *)
  22. format*: LONGINT; (** format for Transfer. *)
  23. unit*: LONGINT; (** approximate square pixel size = unit/36000 mm. *)
  24. fbadr-: ADDRESS; fbsize-, fbstride-: LONGINT; (** frame buffer address, size and stride *)
  25. (** Transfer a block of pixels in "raw" display format to (op = set) or from (op = get) the display. Pixels in the rectangular area are transferred from left to right and top to bottom. The pixels are transferred to or from "buf", starting at "ofs". The line byte increment is "stride", which may be positive, negative or zero. *)
  26. PROCEDURE Transfer*(VAR buf: ARRAY OF CHAR; ofs, stride, x, y, w, h, op: LONGINT);
  27. VAR bufadr, buflow, bufhigh, dispadr,w0,b,d: ADDRESS;
  28. BEGIN
  29. IF w > 0 THEN
  30. ASSERT(fbadr # 0);
  31. bufadr := ADDRESSOF(buf[ofs]);
  32. dispadr := fbadr + y * fbstride + x * format;
  33. IF reverse THEN
  34. dispadr := fbadr + (height-y-1) * fbstride + (width-x-1) * format;
  35. END;
  36. ASSERT((dispadr >= fbadr) & ((y+h-1)*fbstride + (x+w-1)*format <= fbsize)); (* display index check *)
  37. w := w * format; (* convert to bytes *)
  38. CASE op OF
  39. set:
  40. IF reverse THEN
  41. WHILE h > 0 DO
  42. w0 := w DIV format; b:= bufadr; d := dispadr;
  43. WHILE w0 > 0 DO
  44. SYSTEM.MOVE(b, d, format);
  45. INC(b,format);
  46. DEC(d, format);
  47. DEC(w0);
  48. END;
  49. INC(bufadr, stride); DEC(dispadr, fbstride);
  50. DEC(h)
  51. END
  52. ELSE
  53. WHILE h > 0 DO
  54. SYSTEM.MOVE(bufadr, dispadr, w);
  55. INC(bufadr, stride); INC(dispadr, fbstride);
  56. DEC(h)
  57. END
  58. END;
  59. |get:
  60. IF reverse THEN
  61. buflow := ADDRESSOF(buf[0]); bufhigh := buflow + LEN(buf);
  62. WHILE h > 0 DO
  63. ASSERT((bufadr >= buflow) & (bufadr+w <= bufhigh)); (* index check *)
  64. w0 := w DIV format; b:= bufadr; d := dispadr;
  65. WHILE w0 > 0 DO
  66. SYSTEM.MOVE(d, b, format);
  67. INC(b,format);
  68. DEC(d, format);
  69. DEC(w0);
  70. END;
  71. INC(bufadr, stride); DEC(dispadr, fbstride);
  72. DEC(h)
  73. END;
  74. ELSE
  75. buflow := ADDRESSOF(buf[0]); bufhigh := buflow + LEN(buf);
  76. WHILE h > 0 DO
  77. ASSERT((bufadr >= buflow) & (bufadr+w <= bufhigh)); (* index check *)
  78. SYSTEM.MOVE(dispadr, bufadr, w);
  79. INC(bufadr, stride); INC(dispadr, fbstride);
  80. DEC(h)
  81. END;
  82. END;
  83. ELSE (* skip *)
  84. END
  85. END
  86. END Transfer;
  87. (** Fill a rectangle in color "col". *)
  88. PROCEDURE Fill*(col, x, y, w, h: LONGINT);
  89. BEGIN
  90. Fill0(SELF, col, x, y, w, h)
  91. END Fill;
  92. (** Equivalent to Fill(col, x, y, 1, 1). *)
  93. PROCEDURE Dot*(col, x, y: LONGINT);
  94. BEGIN
  95. Fill(col, x, y, 1, 1)
  96. END Dot;
  97. (** Transfer a block of pixels from a 1-bit mask to the display. Pixels in the rectangular area are transferred from left to right and top to bottom. The pixels are transferred from "buf", starting at bit offset "bitofs". The line byte increment is "stride", which may be positive, negative or zero. "fg" and "bg" specify the colors for value 1 and 0 pixels respectively. *)
  98. PROCEDURE Mask*(VAR buf: ARRAY OF CHAR; bitof, stride, fg, bg, x, y, w, h: LONGINT);
  99. CONST SetSize = MAX (SET) + 1;
  100. VAR p: ADDRESS; i, bitofs: LONGINT; s: SET;
  101. BEGIN
  102. IF (w > 0) & (h > 0) THEN
  103. i := LONGINT(ADDRESSOF(buf[0]) MOD SIZEOF(SET));
  104. bitofs := bitof + i * 8;
  105. p := ADDRESSOF(buf[0])-i + bitofs DIV SetSize * SIZEOF (SET); (* p always aligned to 32-bit boundary *)
  106. bitofs := bitofs MOD SetSize; stride := stride*8;
  107. LOOP
  108. SYSTEM.GET(p, s); i := bitofs;
  109. LOOP
  110. IF (i MOD SetSize) IN s THEN
  111. IF fg >= 0 THEN Dot(fg, SHORT(x+i-bitofs), y) END
  112. ELSE
  113. IF bg >= 0 THEN Dot(bg, SHORT (x+i-bitofs), y) END
  114. END;
  115. INC(i);
  116. IF i-bitofs = w THEN EXIT END;
  117. IF i MOD SetSize = 0 THEN SYSTEM.GET(p+i DIV 8, s) END
  118. END;
  119. DEC(h);
  120. IF h = 0 THEN EXIT END;
  121. INC(y); INC(bitofs, stride);
  122. IF (bitofs >= SetSize) OR (bitofs < 0) THEN (* moved outside s *)
  123. INC(p, bitofs DIV SetSize * SIZEOF (SET)); bitofs := bitofs MOD SetSize
  124. END
  125. END
  126. END
  127. END Mask;
  128. (** Copy source block sx, sy, w, h to destination dx, dy. Overlap is allowed. *)
  129. PROCEDURE Copy*(sx, sy, w, h, dx, dy: LONGINT);
  130. BEGIN
  131. Copy0(SELF, sx, sy, w, h, dx, dy)
  132. END Copy;
  133. (** Update the visible display (if caching is used). *)
  134. PROCEDURE Update*;
  135. END Update;
  136. (** Map a color value to an 8-bit CLUT index. Only used if format = index8. *)
  137. PROCEDURE ColorToIndex*(col: LONGINT): LONGINT;
  138. BEGIN
  139. (* default implementation is not very useful and should be overridden. *)
  140. RETURN SYSTEM.VAL(LONGINT,
  141. SYSTEM.VAL(SET, ASH(col, 7-23)) * {5..7} +
  142. SYSTEM.VAL(SET, ASH(col, 4-15)) * {2..4} +
  143. SYSTEM.VAL(SET, ASH(col, 1-7)) * {0..1})
  144. END ColorToIndex;
  145. (** Map an 8-bit CLUT index to a color value. Only used if format = index8. *)
  146. PROCEDURE IndexToColor*(index: LONGINT): LONGINT;
  147. BEGIN
  148. (* default implementation is not very useful and should be overridden. *)
  149. RETURN
  150. ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {5..7}), 23-7) +
  151. ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {2..4}), 15-4) +
  152. ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {0..1}), 7-1)
  153. END IndexToColor;
  154. (** Initialize a linear frame buffer for Transfer. *)
  155. PROCEDURE InitFrameBuffer*(adr: ADDRESS; size, stride: LONGINT);
  156. BEGIN
  157. ASSERT((height+offscreen)*stride <= size);
  158. fbadr := adr; fbsize := size; fbstride := stride;
  159. END InitFrameBuffer;
  160. (*
  161. (** Draw a line. *)
  162. PROCEDURE Line*(col, x1, y1, x2, y2: LONGINT); (* error term, major, minor? *)
  163. BEGIN
  164. HALT(99)
  165. END Line;
  166. (* Like Mask, but replicate the mask in the specified rectangular area. *)
  167. PROCEDURE ReplMask*(VAR buf: ARRAY OF CHAR; bitofs, stride, fg, bg, px, py, pw, ph, x, y, w, h: LONGINT);
  168. BEGIN
  169. HALT(99)
  170. END ReplMask;
  171. *)
  172. (** Finalize the display. Further calls to display methods are not allowed, and may cause exceptions. *)
  173. PROCEDURE Finalize*;
  174. BEGIN (* should really be exclusive with Transfer, but we assume the caller keeps to the rules above *)
  175. fbadr := 0; fbsize := 0
  176. END Finalize;
  177. END Display;
  178. VAR
  179. registry*: Plugins.Registry;
  180. buf: POINTER TO ARRAY OF CHAR;
  181. PROCEDURE Fill0(d: Display; col, x, y, w, h: LONGINT);
  182. VAR j, w0, h0, s: LONGINT; p: ADDRESS; t, c: SET; invert: BOOLEAN;
  183. BEGIN {EXCLUSIVE}
  184. IF (w > 0) & (h > 0) & (col >= 0) THEN (* opaque or invert *)
  185. invert := ASH(col, 1) < 0;
  186. IF buf = NIL THEN NEW(buf, BufSize) END;
  187. CASE d.format OF
  188. index8:
  189. s := 4; col := d.ColorToIndex(col);
  190. c := SYSTEM.VAL(SET, ASH(col, 24) + ASH(col, 16) + ASH(col, 8) + col)
  191. |color565:
  192. s := 4;
  193. col := SYSTEM.VAL(LONGINT,
  194. SYSTEM.VAL(SET, ASH(col, 15-23)) * {11..15} +
  195. SYSTEM.VAL(SET, ASH(col, 10-15)) * {5..10} +
  196. SYSTEM.VAL(SET, ASH(col, 4-7)) * {0..4});
  197. c := SYSTEM.VAL(SET, ASH(col MOD 10000H, 16) + col MOD 10000H)
  198. |color888:
  199. s := 3; c := SYSTEM.VAL(SET, col MOD 1000000H)
  200. |color8888:
  201. s := 4; c := SYSTEM.VAL(SET, col MOD 1000000H)
  202. END;
  203. w0 := w*d.format; h0 := (LEN(buf^)-3) DIV w0; (* -3 for 32-bit loops below *)
  204. ASSERT(h0 > 0);
  205. IF h < h0 THEN h0 := h END;
  206. IF ~invert THEN
  207. p := ADDRESSOF(buf[0]);
  208. FOR j := 0 TO (w0*h0-1) DIV s DO SYSTEM.PUT32(p, c); INC(p, s) END
  209. ELSE
  210. IF c = {} THEN c := {0..31} END
  211. END;
  212. LOOP
  213. IF invert THEN
  214. d.Transfer(buf^, 0, w0, x, y, w, h0, get);
  215. p := ADDRESSOF(buf[0]);
  216. FOR j := 0 TO (w0*h0-1) DIV s DO
  217. t := SYSTEM.VAL (SET, SYSTEM.GET32(p)); SYSTEM.PUT32(p, t / c); INC(p, s)
  218. END
  219. END;
  220. d.Transfer(buf^, 0, w0, x, y, w, h0, set);
  221. DEC(h, h0);
  222. IF h <= 0 THEN EXIT END;
  223. INC(y, h0);
  224. IF h < h0 THEN h0 := h END
  225. END
  226. END
  227. END Fill0;
  228. PROCEDURE Copy0(d: Display; sx, sy, w, h, dx, dy: LONGINT);
  229. VAR w0, h0, s: LONGINT;
  230. BEGIN {EXCLUSIVE}
  231. IF (w > 0) & (h > 0) THEN
  232. IF buf = NIL THEN NEW(buf, BufSize) END;
  233. w0 := w*d.format; h0 := LEN(buf^) DIV w0;
  234. ASSERT(h0 > 0);
  235. IF (sy >= dy) OR (h <= h0) THEN
  236. s := 1
  237. ELSE
  238. s := -1; INC(sy, h-h0); INC(dy, h-h0)
  239. END;
  240. LOOP
  241. IF h < h0 THEN
  242. IF s = -1 THEN INC(sy, h0-h); INC(dy, h0-h) END;
  243. h0 := h
  244. END;
  245. d.Transfer(buf^, 0, w0, sx, sy, w, h0, get);
  246. d.Transfer(buf^, 0, w0, dx, dy, w, h0, set);
  247. DEC(h, h0);
  248. IF h <= 0 THEN EXIT END;
  249. INC(sy, s*h0); INC(dy, s*h0)
  250. END
  251. END
  252. END Copy0;
  253. PROCEDURE Reverse*;
  254. BEGIN
  255. reverse := ~reverse;
  256. END Reverse;
  257. BEGIN
  258. NEW(registry, "Displays", "Display drivers");
  259. buf := NIL;
  260. reverse := FALSE;
  261. END Displays.
  262. (**
  263. o The display origin (0,0) is at the top left.
  264. o The display is "width" pixels wide and "height" pixels high.
  265. o The offscreen area is a possibly empty extension below the visible display. Its height is "offscreen" pixels.
  266. o Rectangles are specified with the top left corner as pinpoint.
  267. o No clipping is performed.
  268. o The offset and stride parameters must always specify values inside the supplied buffer (otherwise results undefined).
  269. o Accessing coordinates outside the display space (including offscreen) is undefined.
  270. o "Undefined" in this case means a trap could occur, or garbage can be displayed, but memory will never be corrupted.
  271. 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.
  272. 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.
  273. o The "trans" flag means the color is transparent and drawing in this color has no effect. It is defined for Mask only.
  274. o The transfer "format" should be chosen close to the native framebuffer format for efficiency.
  275. o Transfer uses raw framebuffer values, and does not support color flags.
  276. o A concrete Display must implement at least the Transfer function, or initialize a linear frame buffer and call the InitFrameBuffer method.
  277. o An optimized Display driver should override all the primitives with accellerated versions.
  278. o An "index8" display uses a fixed palette and map a truecolor value to an equivalent color in the palette.
  279. 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.
  280. o The default ColorToIndex method assumes a direct-mapped palette with 3 bits each for red and green, and 2 bits for blue.
  281. o Palette animation is not supported.
  282. *)