2
0

cga.pp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. {$MODE objfpc}
  2. {$ASMMODE intel}
  3. Unit CGA;
  4. Interface
  5. Procedure CGAText;
  6. Procedure CGA320;
  7. Procedure CGA640;
  8. Procedure CGADump(q : PByte);
  9. Procedure CGASetPalette(palette, border : Integer);
  10. Procedure CGAPrecalc;
  11. Implementation
  12. Uses
  13. go32, crt;
  14. Const
  15. palette : Array[0..15, 0..2] Of Byte = (
  16. ( 0, 0, 0), ( 0, 0,42), ( 0,42, 0), ( 0,42,42), (42, 0, 0), (42, 0,42), (42,21, 0), (42,42,42),
  17. (21,21,21), (21,21,63), (21,63,21), (21,63,63), (63,21,21), (63,21,63), (63,63,21), (63,63,63));
  18. cgaback : Array[0..3, 0..12] Of Integer = (
  19. ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15),
  20. ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14),
  21. ( 0, 1, 3, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15),
  22. ( 0, 1, 2, 4, 6, 8, 9, 10, 11, 12, 13, 14, 15));
  23. Type
  24. Float = Extended;
  25. TCGAVideoBuffer = Array[0..16383] Of Byte;
  26. PCGAPrecalc = ^TCGAPrecalc;
  27. TCGAPrecalc = Array[0..15{r}, 0..15{g}, 0..15{b}, 0..3{y}, 0..3{x}] Of Byte;
  28. PCGAPrecalcError = ^TCGAPrecalcError;
  29. TCGAPrecalcError = Array[0..15{r}, 0..15{g}, 0..15{b}] Of Integer;
  30. Var
  31. cgapal : Array[0..3] Of Integer;
  32. videobuf : TCGAVideoBuffer;
  33. precalcbuf : Array[0..12, 0..3] Of PCGAPrecalc; {3.25mb}
  34. precalcerror : Array[0..12, 0..3] Of PCGAPrecalcError; {0.8125mb}
  35. error : Integer;
  36. lastpalette, lastback : Integer;
  37. Procedure CGA320;
  38. Var
  39. regs : TRealRegs;
  40. Begin
  41. regs.ax := $0004;
  42. RealIntr($10, regs);
  43. lastpalette := -1;
  44. lastback := -1;
  45. End;
  46. Procedure CGA640;
  47. Var
  48. regs : TRealRegs;
  49. Begin
  50. regs.ax := $0004;
  51. RealIntr($10, regs);
  52. End;
  53. Procedure CGAText;
  54. Var
  55. regs : TRealRegs;
  56. Begin
  57. regs.ax := $0003;
  58. RealIntr($10, regs);
  59. End;
  60. Procedure CGASetPalette(palette, border : Integer);
  61. Var
  62. regs : TRealRegs;
  63. Begin
  64. If (palette = lastpalette) And (border = lastback) Then
  65. Exit;
  66. lastpalette := palette;
  67. lastback := border;
  68. regs.ah := $0B;
  69. regs.bh := 1;
  70. regs.bl := palette And 1;
  71. RealIntr($10, regs);
  72. If (palette And 2) = 0 Then
  73. Inc(border, 16);
  74. regs.ah := $0B;
  75. regs.bh := 0;
  76. regs.bl := border;
  77. RealIntr($10, regs);
  78. End;
  79. Procedure CGABlitToScreen(p : Pointer); Assembler;
  80. Asm
  81. mov edi, $B8000
  82. push es
  83. mov ax, fs
  84. mov es, ax
  85. mov esi, [p]
  86. mov ecx, 16192/4
  87. rep movsd
  88. pop es
  89. End;
  90. Function CGACalc2(r, g, b : Integer; dx, dy : Integer; back, pal : Integer) : Integer;{ Inline;}
  91. Begin
  92. CGACalc2 := precalcbuf[back, pal]^[r Shr 4, g Shr 4, b Shr 4, dy, dx];
  93. End;
  94. Procedure CGACalc(r, g, b : Integer; {dx, dy : Integer;}
  95. Var dither, best1, best2 : Integer);
  96. Var
  97. I, J : Integer;
  98. mindist : Float;
  99. dist : Float;
  100. r1, g1, b1 : Integer;
  101. tmp : Integer;
  102. { dither : Integer;} {0-none; 1-50%; 2-25%; 3-12.5%; 4-37.5%}
  103. Begin
  104. r := Round(r*63 / 15);
  105. g := Round(g*63 / 15);
  106. b := Round(b*63 / 15);
  107. mindist := $7FFFFFFF;
  108. For I := 0 To 3 Do
  109. Begin
  110. dist := Sqr(r - palette[cgapal[I], 0]) +
  111. Sqr(g - palette[cgapal[I], 1]) +
  112. Sqr(b - palette[cgapal[I], 2]);
  113. If dist < mindist Then
  114. Begin
  115. mindist := dist;
  116. best1 := I;
  117. dither := 0;
  118. End;
  119. End;
  120. For J := 0 To 3 Do
  121. Begin
  122. r1 := palette[cgapal[J], 0];
  123. g1 := palette[cgapal[J], 1];
  124. b1 := palette[cgapal[J], 2];
  125. For I := 0 To 3 Do
  126. Begin
  127. If I = J Then
  128. Continue;
  129. dist := Sqr(r - (palette[cgapal[I], 0] + r1)*0.5) +
  130. Sqr(g - (palette[cgapal[I], 1] + g1)*0.5) +
  131. Sqr(b - (palette[cgapal[I], 2] + b1)*0.5);
  132. If dist < mindist Then
  133. Begin
  134. mindist := dist;
  135. best1 := J;
  136. best2 := I;
  137. dither := 1;
  138. End;
  139. dist := Sqr(r - (0.25*palette[cgapal[I], 0] + 0.75*r1)) +
  140. Sqr(g - (0.25*palette[cgapal[I], 1] + 0.75*g1)) +
  141. Sqr(b - (0.25*palette[cgapal[I], 2] + 0.75*b1));
  142. If dist < mindist Then
  143. Begin
  144. mindist := dist;
  145. best1 := J;
  146. best2 := I;
  147. dither := 2;
  148. End;
  149. dist := Sqr(r - (0.125*palette[cgapal[I], 0] + 0.875*r1)) +
  150. Sqr(g - (0.125*palette[cgapal[I], 1] + 0.875*g1)) +
  151. Sqr(b - (0.125*palette[cgapal[I], 2] + 0.875*b1));
  152. If dist < mindist Then
  153. Begin
  154. mindist := dist;
  155. best1 := J;
  156. best2 := I;
  157. dither := 3;
  158. End;
  159. dist := Sqr(r - (0.375*palette[cgapal[I], 0] + 0.625*r1)) +
  160. Sqr(g - (0.375*palette[cgapal[I], 1] + 0.625*g1)) +
  161. Sqr(b - (0.375*palette[cgapal[I], 2] + 0.625*b1));
  162. If dist < mindist Then
  163. Begin
  164. mindist := dist;
  165. best1 := J;
  166. best2 := I;
  167. dither := 4;
  168. End;
  169. End;
  170. End;
  171. error:=error+round(Sqrt(mindist) * 290);
  172. Case dither Of
  173. 0 : best2 := best1;
  174. 1 : Begin
  175. If best1 > best2 Then
  176. Begin
  177. tmp := best1;
  178. best1 := best2;
  179. best2 := tmp;
  180. End;
  181. End;
  182. End;
  183. End;
  184. Function CGACalcError(s : PByte; back, pal : Integer) : Integer;
  185. Var
  186. X, Y : Integer;
  187. r, g, b : Integer;
  188. Begin
  189. CGACalcError := 0;
  190. For Y := 0 To 199 {Div 4} Do
  191. Begin
  192. For X := 0 To 319 {Div 4} Do
  193. Begin
  194. b := s[0];
  195. g := s[1];
  196. r := s[2];
  197. inc(CGACalcError,precalcerror[back, pal]^[b Shr 4, g Shr 4, r Shr 4]);
  198. Inc(s, 4{ + 4 + 4 + 4});
  199. End;
  200. // Inc(s, 320*4*3);
  201. End;
  202. End;
  203. Procedure CGADump2(s, d : PByte; back, pal : Integer);
  204. Var
  205. I : Integer;
  206. src, dest : PByte;
  207. X, Y : Integer;
  208. r1, g1, b1 : Integer;
  209. r2, g2, b2 : Integer;
  210. r3, g3, b3 : Integer;
  211. r4, g4, b4 : Integer;
  212. Begin
  213. error := 0;
  214. src := s;
  215. dest := d;
  216. For Y := 0 To 99 Do
  217. Begin
  218. For X := 0 To 79 Do
  219. Begin
  220. b1 := src[0];
  221. g1 := src[1];
  222. r1 := src[2];
  223. b2 := src[4];
  224. g2 := src[5];
  225. r2 := src[6];
  226. b3 := src[8];
  227. g3 := src[9];
  228. r3 := src[10];
  229. b4 := src[12];
  230. g4 := src[13];
  231. r4 := src[14];
  232. dest^ := (CGACalc2(r1, g1, b1, 0, (Y And 1) Shl 1, back, pal) Shl 6) Or
  233. (CGACalc2(r2, g2, b2, 1, (Y And 1) Shl 1, back, pal) Shl 4) Or
  234. (CGACalc2(r3, g3, b3, 2, (Y And 1) Shl 1, back, pal) Shl 2) Or
  235. (CGACalc2(r4, g4, b4, 3, (Y And 1) Shl 1, back, pal));
  236. Inc(src, 4*4);
  237. Inc(dest);
  238. End;
  239. Inc(src, 320*4);
  240. End;
  241. src := s + 320*4;
  242. dest := d + 8192;
  243. For Y := 0 To 99 Do
  244. Begin
  245. For X := 0 To 79 Do
  246. Begin
  247. b1 := src[0];
  248. g1 := src[1];
  249. r1 := src[2];
  250. b2 := src[4];
  251. g2 := src[5];
  252. r2 := src[6];
  253. b3 := src[8];
  254. g3 := src[9];
  255. r3 := src[10];
  256. b4 := src[12];
  257. g4 := src[13];
  258. r4 := src[14];
  259. dest^ := (CGACalc2(r1, g1, b1, 0, ((Y And 1) Shl 1) + 1, back, pal) Shl 6) Or
  260. (CGACalc2(r2, g2, b2, 1, ((Y And 1) Shl 1) + 1, back, pal) Shl 4) Or
  261. (CGACalc2(r3, g3, b3, 2, ((Y And 1) Shl 1) + 1, back, pal) Shl 2) Or
  262. (CGACalc2(r4, g4, b4, 3, ((Y And 1) Shl 1) + 1, back, pal));
  263. Inc(src, 4*4);
  264. Inc(dest);
  265. End;
  266. Inc(src, 320*4);
  267. End;
  268. End;
  269. Procedure CGADump(q : PByte);
  270. Var
  271. pal, back : Integer;
  272. bestpal, bestback : Integer;
  273. besterror : Integer;
  274. Begin
  275. besterror := $7FFFFFFF;
  276. For pal := 0 To 3 Do
  277. Begin
  278. For back := 0 To 12 Do
  279. Begin
  280. error := CGACalcError(q, back, pal);
  281. If error < besterror Then
  282. Begin
  283. besterror := error;
  284. bestpal := pal;
  285. bestback := back;
  286. End;
  287. End;
  288. End;
  289. CGADump2(q, videobuf, bestback, bestpal);
  290. CGASetPalette(bestpal, cgaback[bestpal, bestback]);
  291. CGABlitToScreen(@videobuf);
  292. End;
  293. Procedure CGAPrecalc;
  294. Var
  295. pal, back : Integer;
  296. r, g, b : Integer;
  297. x, y : Integer;
  298. dither : Integer;
  299. best1, best2 : Integer;
  300. res : Integer;
  301. Begin
  302. For pal := 0 To 3 Do
  303. Begin
  304. Case pal Of
  305. 0 : Begin
  306. cgapal[1] := 10;
  307. cgapal[2] := 12;
  308. cgapal[3] := 14;
  309. End;
  310. 1 : Begin
  311. cgapal[1] := 11;
  312. cgapal[2] := 13;
  313. cgapal[3] := 15;
  314. End;
  315. 2 : Begin
  316. cgapal[1] := 2;
  317. cgapal[2] := 4;
  318. cgapal[3] := 6;
  319. End;
  320. 3 : Begin
  321. cgapal[1] := 3;
  322. cgapal[2] := 5;
  323. cgapal[3] := 7;
  324. End;
  325. End;
  326. For back := 0 To 12 Do
  327. Begin
  328. If (precalcbuf[back, pal] = Nil) And (precalcerror[back, pal] = Nil) Then
  329. Begin
  330. New(precalcbuf[back, pal]);
  331. New(precalcerror[back, pal]);
  332. End
  333. Else
  334. Continue;
  335. cgapal[0] := cgaback[pal, back];
  336. error := 0;
  337. Write(pal, back:3, ' ');
  338. TextAttr := cgapal[0];
  339. Write('*');
  340. TextAttr := cgapal[1];
  341. Write('*');
  342. TextAttr := cgapal[2];
  343. Write('*');
  344. TextAttr := cgapal[3];
  345. Writeln('*');
  346. TextAttr := 7;
  347. For r := 0 To 15 Do
  348. For g := 0 To 15 Do
  349. For b := 0 To 15 Do
  350. Begin
  351. error := 0;
  352. CGACalc(r, g, b, dither, best1, best2);
  353. precalcerror[back, pal]^[r, g, b] := error;
  354. For y := 0 To 3 Do
  355. For x := 0 To 3 Do
  356. Begin
  357. Case dither Of
  358. 0 : res := best1;
  359. 1 : Begin
  360. If ((x + y) And 1) <> 0 Then
  361. res := best1
  362. Else
  363. res := best2;
  364. End;
  365. 2 : Begin
  366. If ((x And 1) = 0) And ((y And 1) = 0) Then
  367. res := best2
  368. Else
  369. res := best1;
  370. End;
  371. 3 : Begin
  372. If (x = y) And ((x And 1) = 0) Then
  373. res := best2
  374. Else
  375. res := best1;
  376. End;
  377. 4 : Begin
  378. If (((x And 1) = 0) And ((y And 1) = 0)) Or (x = y) Then
  379. res := best2
  380. Else
  381. res := best1;
  382. End;
  383. End;
  384. precalcbuf[back, pal]^[r, g, b, y, x] := res;
  385. End;
  386. End;
  387. //Function CGACalc(r, g, b : Integer; dx, dy : Integer) : Integer;
  388. End;
  389. End;
  390. End;
  391. Begin
  392. FillChar(precalcbuf, SizeOf(precalcbuf), 0);
  393. FillChar(precalcerror, SizeOf(precalcerror), 0);
  394. End.