Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

944 lines
35 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: dither.cxx
  3. *
  4. * This algorithm for color dithering is patent pending and its use is
  5. * restricted to Microsoft products and drivers for Microsoft products.
  6. * Use in non-Microsoft products or in drivers for non-Microsoft products
  7. * is prohibited without the expressed written consent of Microsoft Corp.
  8. *
  9. * The patent application is the primary reference for the operation of the
  10. * color dithering code.
  11. *
  12. * Note that in the comments and variable names, "vertex" means "vertex of
  13. * either the inner (half intensity) or outer (full intensity) color cube."
  14. * Vertices map to colors 0-7 and 9-15 of the Windows standard (required)
  15. * 16-color palette, where vertices 0-7 are the vertices of the inner color
  16. * cube, and 0 plus 9-15 are the vertices of the full color cube. Vertex 8 is
  17. * 75% gray; this could be used in the dither, but that would break apps that
  18. * depend on the exact Windows 3.1 dithering. This code is Window 3.1
  19. * compatible.
  20. *
  21. * Note that as a result of the compatibility requirement, the dither
  22. * produced by this algorithm is the exact same dither as that produced
  23. * by the default Windows 3.1 16 color and 256 color VGA drivers.
  24. *
  25. * Copyright (c) 1992-1999 Microsoft Corporation
  26. \**************************************************************************/
  27. #include "precomp.hxx"
  28. /**************************************************************************\
  29. * This function takes a value from 0 - 255 and uses it to create an
  30. * 8x8 pile of bits in the form of a 1BPP bitmap. It can also take an
  31. * RGB value and make an 8x8 bitmap. These can then be used as brushes
  32. * to simulate color unavaible on the device.
  33. *
  34. * For monochrome the basic algorithm is equivalent to turning on bits
  35. * in the 8x8 array according to the following order:
  36. *
  37. * 00 32 08 40 02 34 10 42
  38. * 48 16 56 24 50 18 58 26
  39. * 12 44 04 36 14 46 06 38
  40. * 60 28 52 20 62 30 54 22
  41. * 03 35 11 43 01 33 09 41
  42. * 51 19 59 27 49 17 57 25
  43. * 15 47 07 39 13 45 05 37
  44. * 63 31 55 23 61 29 53 21
  45. *
  46. * Reference: A Survey of Techniques for the Display of Continous
  47. * Tone Pictures on Bilevel Displays,;
  48. * Jarvis, Judice, & Ninke;
  49. * COMPUTER GRAPHICS AND IMAGE PROCESSING 5, pp 13-40, (1976)
  50. \**************************************************************************/
  51. #define SWAP_RB 0x00000004
  52. #define SWAP_GB 0x00000002
  53. #define SWAP_RG 0x00000001
  54. #define SWAPTHEM(a,b) (ulTemp = a, a = b, b = ulTemp)
  55. // PATTERNSIZE is the number of pixels in a dither pattern.
  56. #define PATTERNSIZE 64
  57. // Tells which row to turn a pel on in when dithering for monochrome bitmaps.
  58. static BYTE ajByte[] = {
  59. 0, 4, 0, 4, 2, 6, 2, 6,
  60. 0, 4, 0, 4, 2, 6, 2, 6,
  61. 1, 5, 1, 5, 3, 7, 3, 7,
  62. 1, 5, 1, 5, 3, 7, 3, 7,
  63. 0, 4, 0, 4, 2, 6, 2, 6,
  64. 0, 4, 0, 4, 2, 6, 2, 6,
  65. 1, 5, 1, 5, 3, 7, 3, 7,
  66. 1, 5, 1, 5, 3, 7, 3, 7
  67. };
  68. // The array of monochrome bits used for monc
  69. static BYTE ajBits[] = {
  70. 0x80, 0x08, 0x08, 0x80, 0x20, 0x02, 0x02, 0x20,
  71. 0x20, 0x02, 0x02, 0x20, 0x80, 0x08, 0x08, 0x80,
  72. 0x40, 0x04, 0x04, 0x40, 0x10, 0x01, 0x01, 0x10,
  73. 0x10, 0x01, 0x01, 0x10, 0x40, 0x04, 0x04, 0x40,
  74. 0x40, 0x04, 0x04, 0x40, 0x10, 0x01, 0x01, 0x10,
  75. 0x10, 0x01, 0x01, 0x10, 0x40, 0x04, 0x04, 0x40,
  76. 0x80, 0x08, 0x08, 0x80, 0x20, 0x02, 0x02, 0x20,
  77. 0x20, 0x02, 0x02, 0x20, 0x80, 0x08, 0x08, 0x80
  78. };
  79. // Translates vertices back to the original subspace. Each row is a subspace,
  80. // as encoded in ulSymmetry, and each column is a vertex between 0 and 15.
  81. BYTE jSwapSubSpace[8*16] = {
  82. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
  83. 0, 2, 1, 3, 4, 6, 5, 7, 8, 10, 9, 11, 12, 14, 13, 15,
  84. 0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15,
  85. 0, 4, 1, 5, 2, 6, 3, 7, 8, 12, 9, 13, 10, 14, 11, 15,
  86. 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15,
  87. 0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15,
  88. 0, 4, 1, 5, 2, 6, 3, 7, 8, 12, 9, 13, 10, 14, 11, 15,
  89. 0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15,
  90. };
  91. // Converts a nibble value in the range 0-15 to a dword value containing the
  92. // nibble value packed 8 times.
  93. // For 8bpp, also translate to 256-color palette index.
  94. ULONG ulNibbleTo8bppDword[16] = {
  95. 0x00000000,
  96. 0x01010101,
  97. 0x02020202,
  98. 0x03030303,
  99. 0x04040404,
  100. 0x05050505,
  101. 0x06060606,
  102. 0xF8F8F8F8,
  103. 0x07070707,
  104. 0xF9F9F9F9,
  105. 0xFAFAFAFA,
  106. 0xFBFBFBFB,
  107. 0xFCFCFCFC,
  108. 0xFDFDFDFD,
  109. 0xFEFEFEFE,
  110. 0xFFFFFFFF
  111. };
  112. // For 4bpp, no translation is necessary.
  113. ULONG ulNibbleTo4bppDword[16] = {
  114. 0x00000000,
  115. 0x01010101,
  116. 0x02020202,
  117. 0x03030303,
  118. 0x04040404,
  119. 0x05050505,
  120. 0x06060606,
  121. 0x07070707,
  122. 0x08080808,
  123. 0x09090909,
  124. 0x0A0A0A0A,
  125. 0x0B0B0B0B,
  126. 0x0C0C0C0C,
  127. 0x0D0D0D0D,
  128. 0x0E0E0E0E,
  129. 0x0F0F0F0F
  130. };
  131. // Specifies where in the dither pattern colors should be placed in order
  132. // of increasing intensity.
  133. // 8bpp specific version.
  134. ULONG aulDither8bppOrder[] = {
  135. 0, 36, 4, 32, 18, 54, 22, 50,
  136. 2, 38, 6, 34, 16, 52, 20, 48,
  137. 9, 45, 13, 41, 27, 63, 31, 59,
  138. 11, 47, 15, 43, 25, 61, 29, 57,
  139. 1, 37, 5, 33, 19, 55, 23, 51,
  140. 3, 39, 7, 35, 17, 53, 21, 49,
  141. 8, 44, 12, 40, 26, 62, 30, 58,
  142. 10, 46, 14, 42, 24, 60, 28, 56,
  143. };
  144. // 4bpp specific version. This is organized in the following form, for
  145. // efficiency: every set of 8 pixels (0-7, 8-15, 16-23, ... ,56-63) is
  146. // placed in the dither pattern in the order: 0 2 4 6 1 3 5 7. This is
  147. // done so that two longs can be combined to put 8 pixels in DIB4 format
  148. // at once (the first dword is shifted left 4, then the two dwords are
  149. // ORed, to produce 0 1 2 3 4 5 6 7 order in memory), which is much faster than
  150. // combining the output of the straight dither ordering.
  151. // The effective dither ordering after we combine each pair of ULONGS at the
  152. // end (the desired dither ordering) matches aulDither8bppOrder (see above).
  153. //
  154. ULONG aulDither4bppOrder[] = {
  155. 0, 34, 2, 32, 17, 51, 19, 49,
  156. 1, 35, 3, 33, 16, 50, 18, 48,
  157. 12, 46, 14, 44, 29, 63, 31, 61,
  158. 13, 47, 15, 45, 28, 62, 30, 60,
  159. 4, 38, 6, 36, 21, 55, 23, 53,
  160. 5, 39, 7, 37, 20, 54, 22, 52,
  161. 8, 42, 10, 40, 25, 59, 27, 57,
  162. 9, 43, 11, 41, 24, 58, 26, 56,
  163. };
  164. // Array to convert to 256 color from 16 color. Maps from index that represents
  165. // a 16-color vertex (color) to value that specifies the color index in the
  166. // 256-color palette.
  167. BYTE ajConvert[] =
  168. {
  169. 0,
  170. 1,
  171. 2,
  172. 3,
  173. 4,
  174. 5,
  175. 6,
  176. 248,
  177. 7,
  178. 249,
  179. 250,
  180. 251,
  181. 252,
  182. 253,
  183. 254,
  184. 255
  185. };
  186. // Describes a single colour tetrahedron vertex for dithering:
  187. typedef struct _VERTEX_DATA {
  188. ULONG ulCount; // Number of pixels in this vertex
  189. ULONG ulVertex; // Vertex number
  190. } VERTEX_DATA; /* vd, pv */
  191. VERTEX_DATA* vComputeSubspaces(ULONG, VERTEX_DATA*);
  192. VOID vDitherColor8bpp(ULONG*, VERTEX_DATA*, VERTEX_DATA*, ULONG);
  193. VOID vDitherColor4bpp(ULONG*, VERTEX_DATA*, VERTEX_DATA*, ULONG);
  194. /******************************Public*Routine******************************\
  195. * vComputeSubspaces
  196. *
  197. * Calculates the subspace data associated with rgb, stores the data at
  198. * pvVertexData, in the form of an array of VERTEX_DATA structures,
  199. * suitable for vDitherColor. Returns a pointer to the byte after the
  200. * last VERTEX_DATA structure.
  201. *
  202. * Ignores the high byte of rgb.
  203. *
  204. \**************************************************************************/
  205. VERTEX_DATA* vComputeSubspaces(
  206. ULONG rgb,
  207. VERTEX_DATA* pvVertexData)
  208. {
  209. ULONG ulRedTemp, ulGreenTemp, ulBlueTemp, ulSymmetry;
  210. ULONG ulRed, ulGre, ulBlu, ulTemp;
  211. ULONG ulVertex0Temp, ulVertex1Temp, ulVertex2Temp, ulVertex3Temp;
  212. // Split the color into red, green, and blue components
  213. ulRedTemp = ((PAL_ULONG *)&rgb)->pal.peRed;
  214. ulGreenTemp = ((PAL_ULONG *)&rgb)->pal.peGreen;
  215. ulBlueTemp = ((PAL_ULONG *)&rgb)->pal.peBlue;
  216. // Sort the RGB so that the point is transformed into subspace 0, and
  217. // keep track of the swaps in ulSymmetry so we can unravel it again
  218. // later. We want r >= g >= b (subspace 0).
  219. ulSymmetry = 0;
  220. if (ulBlueTemp > ulRedTemp) {
  221. SWAPTHEM(ulBlueTemp,ulRedTemp);
  222. ulSymmetry = SWAP_RB;
  223. }
  224. if (ulBlueTemp > ulGreenTemp) {
  225. SWAPTHEM(ulBlueTemp,ulGreenTemp);
  226. ulSymmetry |= SWAP_GB;
  227. }
  228. if (ulGreenTemp > ulRedTemp) {
  229. SWAPTHEM(ulGreenTemp,ulRedTemp);
  230. ulSymmetry |= SWAP_RG;
  231. }
  232. ulSymmetry <<= 4; // for lookup purposes
  233. // Scale the values from 0-255 to 0-64. Note that the scaling is not
  234. // symmetric at the ends; this is done to match Windows 3.1 dithering
  235. ulRed = (ulRedTemp + 1) >> 2;
  236. ulGre = (ulGreenTemp + 1) >> 2;
  237. ulBlu = (ulBlueTemp + 1) >> 2;
  238. // Compute the subsubspace within subspace 0 in which the point lies,
  239. // then calculate the # of pixels to dither in the colors that are the
  240. // four vertexes of the tetrahedron bounding the color we're emulating.
  241. // Only vertices with more than zero pixels are stored, and the
  242. // vertices are stored in order of increasing intensity, saving us the
  243. // need to sort them later
  244. if ((ulRedTemp + ulGreenTemp) > 256) {
  245. // Subsubspace 2 or 3
  246. if ((ulRedTemp + ulBlueTemp) > 256) {
  247. // Subsubspace 3
  248. // Calculate the number of pixels per vertex, still in
  249. // subsubspace 3, then convert to original subspace. The pixel
  250. // counts and vertex numbers are matching pairs, stored in
  251. // ascending intensity order, skipping vertices with zero
  252. // pixels. The vertex intensity order for subsubspace 3 is:
  253. // 7, 9, 0x0B, 0x0F
  254. if ((ulVertex0Temp = (64 - ulRed) << 1) != 0) {
  255. pvVertexData->ulCount = ulVertex0Temp;
  256. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x07];
  257. }
  258. ulVertex2Temp = ulGre - ulBlu;
  259. ulVertex3Temp = (ulRed - 64) + ulBlu;
  260. if ((ulVertex1Temp = ((PATTERNSIZE - ulVertex0Temp) -
  261. ulVertex2Temp) - ulVertex3Temp) != 0) {
  262. pvVertexData->ulCount = ulVertex1Temp;
  263. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x09];
  264. }
  265. if (ulVertex2Temp != 0) {
  266. pvVertexData->ulCount = ulVertex2Temp;
  267. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x0B];
  268. }
  269. if (ulVertex3Temp != 0) {
  270. pvVertexData->ulCount = ulVertex3Temp;
  271. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x0F];
  272. }
  273. } else {
  274. // Subsubspace 2
  275. // Calculate the number of pixels per vertex, still in
  276. // subsubspace 2, then convert to original subspace. The pixel
  277. // counts and vertex numbers are matching pairs, stored in
  278. // ascending intensity order, skipping vertices with zero
  279. // pixels. The vertex intensity order for subsubspace 2 is:
  280. // 3, 7, 9, 0x0B
  281. ulVertex1Temp = ulBlu << 1;
  282. ulVertex2Temp = ulRed - ulGre;
  283. ulVertex3Temp = (ulRed - 32) + (ulGre - 32);
  284. if ((ulVertex0Temp = ((PATTERNSIZE - ulVertex1Temp) -
  285. ulVertex2Temp) - ulVertex3Temp) != 0) {
  286. pvVertexData->ulCount = ulVertex0Temp;
  287. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x03];
  288. }
  289. if (ulVertex1Temp != 0) {
  290. pvVertexData->ulCount = ulVertex1Temp;
  291. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x07];
  292. }
  293. if (ulVertex2Temp != 0) {
  294. pvVertexData->ulCount = ulVertex2Temp;
  295. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x09];
  296. }
  297. if (ulVertex3Temp != 0) {
  298. pvVertexData->ulCount = ulVertex3Temp;
  299. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x0B];
  300. }
  301. }
  302. } else {
  303. // Subsubspace 0 or 1
  304. if (ulRedTemp > 128) {
  305. // Subsubspace 1
  306. // Calculate the number of pixels per vertex, still in
  307. // subsubspace 1, then convert to original subspace. The pixel
  308. // counts and vertex numbers are matching pairs, stored in
  309. // ascending intensity order, skipping vertices with zero
  310. // pixels. The vertex intensity order for subsubspace 1 is:
  311. // 1, 3, 7, 9
  312. if ((ulVertex0Temp = ((32 - ulGre) + (32 - ulRed)) << 1) != 0) {
  313. pvVertexData->ulCount = ulVertex0Temp;
  314. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x01];
  315. }
  316. ulVertex2Temp = ulBlu << 1;
  317. ulVertex3Temp = (ulRed - 32) << 1;
  318. if ((ulVertex1Temp = ((PATTERNSIZE - ulVertex0Temp) -
  319. ulVertex2Temp) - ulVertex3Temp) != 0) {
  320. pvVertexData->ulCount = ulVertex1Temp;
  321. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x03];
  322. }
  323. if (ulVertex2Temp != 0) {
  324. pvVertexData->ulCount = ulVertex2Temp;
  325. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x07];
  326. }
  327. if (ulVertex3Temp != 0) {
  328. pvVertexData->ulCount = ulVertex3Temp;
  329. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x09];
  330. }
  331. } else {
  332. // Subsubspace 0
  333. // Calculate the number of pixels per vertex, still in
  334. // subsubspace 0, then convert to original subspace. The pixel
  335. // counts and vertex numbers are matching pairs, stored in
  336. // ascending intensity order, skipping vertices with zero
  337. // pixels. The vertex intensity order for subsubspace 0 is:
  338. // 0, 1, 3, 7
  339. if ((ulVertex0Temp = (32 - ulRed) << 1) != 0) {
  340. pvVertexData->ulCount = ulVertex0Temp;
  341. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x00];
  342. }
  343. if ((ulVertex1Temp = (ulRed - ulGre) << 1) != 0) {
  344. pvVertexData->ulCount = ulVertex1Temp;
  345. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x01];
  346. }
  347. ulVertex3Temp = ulBlu << 1;
  348. if ((ulVertex2Temp = ((PATTERNSIZE - ulVertex0Temp) -
  349. ulVertex1Temp) - ulVertex3Temp) != 0) {
  350. pvVertexData->ulCount = ulVertex2Temp;
  351. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x03];
  352. }
  353. if (ulVertex3Temp != 0) {
  354. pvVertexData->ulCount = ulVertex3Temp;
  355. pvVertexData++->ulVertex = jSwapSubSpace[ulSymmetry + 0x07];
  356. }
  357. }
  358. }
  359. return(pvVertexData);
  360. }
  361. /******************************Public*Routine******************************\
  362. * vDitherColor8bpp
  363. *
  364. * Dithers the ulNumVertices vertices described by vVertexData into pulDest.
  365. *
  366. \**************************************************************************/
  367. VOID vDitherColor8bpp(
  368. ULONG* pulDest,
  369. VERTEX_DATA* vVertexData,
  370. VERTEX_DATA* pvVertexDataEnd,
  371. ULONG ulNumVertices)
  372. {
  373. ULONG ulTemp, ulNumPixels, ulColor;
  374. VERTEX_DATA *pvMaxVertex, *pvVertexData;
  375. ULONG *pulDitherOrder;
  376. BYTE jColor;
  377. BYTE *pjDither = (BYTE *)pulDest;
  378. if (ulNumVertices > 2) {
  379. // There are 3 or 4 vertices in this dither
  380. if (ulNumVertices == 3) {
  381. // There are 3 vertices in this dither
  382. // Find the vertex with the most pixels, and fill the whole
  383. // destination bitmap with that vertex's color, which is faster
  384. // than dithering it
  385. if (vVertexData[1].ulCount >= vVertexData[2].ulCount) {
  386. pvMaxVertex = &vVertexData[1];
  387. ulTemp = vVertexData[1].ulCount;
  388. } else {
  389. pvMaxVertex = &vVertexData[2];
  390. ulTemp = vVertexData[2].ulCount;
  391. }
  392. } else {
  393. // There are 4 vertices in this dither
  394. // Find the vertex with the most pixels, and fill the whole
  395. // destination bitmap with that vertex's color, which is faster
  396. // than dithering it
  397. if (vVertexData[2].ulCount >= vVertexData[3].ulCount) {
  398. pvMaxVertex = &vVertexData[2];
  399. ulTemp = vVertexData[2].ulCount;
  400. } else {
  401. pvMaxVertex = &vVertexData[3];
  402. ulTemp = vVertexData[3].ulCount;
  403. }
  404. }
  405. if (vVertexData[1].ulCount > ulTemp) {
  406. pvMaxVertex = &vVertexData[1];
  407. ulTemp = vVertexData[1].ulCount;
  408. }
  409. if (vVertexData[0].ulCount > ulTemp) {
  410. pvMaxVertex = &vVertexData[0];
  411. }
  412. // Prepare a dword version of the most common vertex number (color)
  413. ulColor = ulNibbleTo8bppDword[pvMaxVertex->ulVertex];
  414. // Mark that the vertex we're about to do doesn't need to be done
  415. // later
  416. pvMaxVertex->ulVertex = 0xFF;
  417. // Block fill the dither pattern with the more common vertex
  418. *pulDest = ulColor;
  419. *(pulDest+1) = ulColor;
  420. *(pulDest+2) = ulColor;
  421. *(pulDest+3) = ulColor;
  422. *(pulDest+4) = ulColor;
  423. *(pulDest+5) = ulColor;
  424. *(pulDest+6) = ulColor;
  425. *(pulDest+7) = ulColor;
  426. *(pulDest+8) = ulColor;
  427. *(pulDest+9) = ulColor;
  428. *(pulDest+10) = ulColor;
  429. *(pulDest+11) = ulColor;
  430. *(pulDest+12) = ulColor;
  431. *(pulDest+13) = ulColor;
  432. *(pulDest+14) = ulColor;
  433. *(pulDest+15) = ulColor;
  434. // Now dither all the remaining vertices in order 0->2 or 0->3
  435. // (in order of increasing intensity)
  436. pulDitherOrder = aulDither8bppOrder;
  437. pvVertexData = vVertexData;
  438. do {
  439. if (pvVertexData->ulVertex == 0xFF) {
  440. // This is the max vertex, which we already did, but we
  441. // have to account for it in the dither order
  442. pulDitherOrder += pvVertexData->ulCount;
  443. } else {
  444. jColor = (BYTE) ajConvert[pvVertexData->ulVertex];
  445. ulNumPixels = pvVertexData->ulCount;
  446. switch (ulNumPixels & 3) {
  447. case 3:
  448. pjDither[*(pulDitherOrder+2)] = jColor;
  449. case 2:
  450. pjDither[*(pulDitherOrder+1)] = jColor;
  451. case 1:
  452. pjDither[*(pulDitherOrder+0)] = jColor;
  453. pulDitherOrder += ulNumPixels & 3;
  454. case 0:
  455. break;
  456. }
  457. if ((ulNumPixels >>= 2) != 0) {
  458. do {
  459. pjDither[*pulDitherOrder] = jColor;
  460. pjDither[*(pulDitherOrder+1)] = jColor;
  461. pjDither[*(pulDitherOrder+2)] = jColor;
  462. pjDither[*(pulDitherOrder+3)] = jColor;
  463. pulDitherOrder += 4;
  464. } while (--ulNumPixels);
  465. }
  466. }
  467. } while (++pvVertexData < pvVertexDataEnd);
  468. } else if (ulNumVertices == 2) {
  469. // There are exactly two vertices with more than zero pixels; fill
  470. // in the dither array as follows: block fill with vertex with more
  471. // points first, then dither in the other vertex
  472. if (vVertexData[0].ulCount >= vVertexData[1].ulCount) {
  473. // There are no more vertex 1 than vertex 0 pixels, so do
  474. // the block fill with vertex 0
  475. ulColor = ulNibbleTo8bppDword[vVertexData[0].ulVertex];
  476. // Do the dither with vertex 1
  477. jColor = (BYTE) ajConvert[vVertexData[1].ulVertex];
  478. ulNumPixels = vVertexData[1].ulCount;
  479. // Set where to start dithering with vertex 1 (vertex 0 is
  480. // lower intensity, so its pixels come first in the dither
  481. // order)
  482. pulDitherOrder = aulDither8bppOrder + vVertexData[0].ulCount;
  483. } else {
  484. // There are more vertex 1 pixels, so do the block fill
  485. // with vertex 1
  486. ulColor = ulNibbleTo8bppDword[vVertexData[1].ulVertex];
  487. // Do the dither with vertex 0
  488. jColor = (BYTE) ajConvert[vVertexData[0].ulVertex];
  489. ulNumPixels = vVertexData[0].ulCount;
  490. // Set where to start dithering with vertex 0 (vertex 0 is
  491. // lower intensity, so its pixels come first in the dither
  492. // order)
  493. pulDitherOrder = aulDither8bppOrder;
  494. }
  495. // Block fill the dither pattern with the more common vertex
  496. *pulDest = ulColor;
  497. *(pulDest+1) = ulColor;
  498. *(pulDest+2) = ulColor;
  499. *(pulDest+3) = ulColor;
  500. *(pulDest+4) = ulColor;
  501. *(pulDest+5) = ulColor;
  502. *(pulDest+6) = ulColor;
  503. *(pulDest+7) = ulColor;
  504. *(pulDest+8) = ulColor;
  505. *(pulDest+9) = ulColor;
  506. *(pulDest+10) = ulColor;
  507. *(pulDest+11) = ulColor;
  508. *(pulDest+12) = ulColor;
  509. *(pulDest+13) = ulColor;
  510. *(pulDest+14) = ulColor;
  511. *(pulDest+15) = ulColor;
  512. // Dither in the less common vertex
  513. switch (ulNumPixels & 3) {
  514. case 3:
  515. pjDither[*(pulDitherOrder+2)] = jColor;
  516. case 2:
  517. pjDither[*(pulDitherOrder+1)] = jColor;
  518. case 1:
  519. pjDither[*(pulDitherOrder+0)] = jColor;
  520. pulDitherOrder += ulNumPixels & 3;
  521. case 0:
  522. break;
  523. }
  524. if ((ulNumPixels >>= 2) != 0) {
  525. do {
  526. pjDither[*pulDitherOrder] = jColor;
  527. pjDither[*(pulDitherOrder+1)] = jColor;
  528. pjDither[*(pulDitherOrder+2)] = jColor;
  529. pjDither[*(pulDitherOrder+3)] = jColor;
  530. pulDitherOrder += 4;
  531. } while (--ulNumPixels);
  532. }
  533. } else {
  534. // There is only one vertex in this dither
  535. // No sorting or dithering is needed for just one color; we can
  536. // just generate the final DIB directly
  537. ulColor = ulNibbleTo8bppDword[vVertexData[0].ulVertex];
  538. *pulDest = ulColor;
  539. *(pulDest+1) = ulColor;
  540. *(pulDest+2) = ulColor;
  541. *(pulDest+3) = ulColor;
  542. *(pulDest+4) = ulColor;
  543. *(pulDest+5) = ulColor;
  544. *(pulDest+6) = ulColor;
  545. *(pulDest+7) = ulColor;
  546. *(pulDest+8) = ulColor;
  547. *(pulDest+9) = ulColor;
  548. *(pulDest+10) = ulColor;
  549. *(pulDest+11) = ulColor;
  550. *(pulDest+12) = ulColor;
  551. *(pulDest+13) = ulColor;
  552. *(pulDest+14) = ulColor;
  553. *(pulDest+15) = ulColor;
  554. }
  555. }
  556. /******************************Public*Routine******************************\
  557. * vDitherColor4bpp
  558. *
  559. * Dithers the ulNumVertices vertices described by vVertexData into pulDest.
  560. *
  561. \**************************************************************************/
  562. VOID vDitherColor4bpp(
  563. ULONG * pulDest,
  564. VERTEX_DATA * vVertexData,
  565. VERTEX_DATA * pvVertexDataEnd,
  566. ULONG ulNumVertices)
  567. {
  568. ULONG ulTemp, ulNumPixels, ulColor;
  569. VERTEX_DATA *pvMaxVertex, *pvVertexData;
  570. ULONG *pulTemp, *pulDitherOrder;
  571. BYTE jColor;
  572. BYTE ajDither[64];
  573. if (ulNumVertices > 2) {
  574. // There are 3 or 4 vertices in this dither
  575. if (ulNumVertices == 3) {
  576. // There are 3 vertices in this dither
  577. // Find the vertex with the most pixels, and fill the whole
  578. // destination bitmap with that vertex's color, which is faster
  579. // than dithering it
  580. if (vVertexData[1].ulCount >= vVertexData[2].ulCount) {
  581. pvMaxVertex = &vVertexData[1];
  582. ulTemp = vVertexData[1].ulCount;
  583. } else {
  584. pvMaxVertex = &vVertexData[2];
  585. ulTemp = vVertexData[2].ulCount;
  586. }
  587. } else {
  588. // There are 4 vertices in this dither
  589. // Find the vertex with the most pixels, and fill the whole
  590. // destination bitmap with that vertex's color, which is faster
  591. // than dithering it
  592. if (vVertexData[2].ulCount >= vVertexData[3].ulCount) {
  593. pvMaxVertex = &vVertexData[2];
  594. ulTemp = vVertexData[2].ulCount;
  595. } else {
  596. pvMaxVertex = &vVertexData[3];
  597. ulTemp = vVertexData[3].ulCount;
  598. }
  599. }
  600. if (vVertexData[1].ulCount > ulTemp) {
  601. pvMaxVertex = &vVertexData[1];
  602. ulTemp = vVertexData[1].ulCount;
  603. }
  604. if (vVertexData[0].ulCount > ulTemp) {
  605. pvMaxVertex = &vVertexData[0];
  606. }
  607. // Prepare a dword version of the most common vertex number (color)
  608. ulColor = ulNibbleTo4bppDword[pvMaxVertex->ulVertex];
  609. // Mark that the vertex we're about to do doesn't need to be done
  610. // later
  611. pvMaxVertex->ulVertex = 0xFF;
  612. // Block fill the dither pattern with the more common vertex
  613. pulTemp = (ULONG *)ajDither;
  614. *pulTemp = ulColor;
  615. *(pulTemp+1) = ulColor;
  616. *(pulTemp+2) = ulColor;
  617. *(pulTemp+3) = ulColor;
  618. *(pulTemp+4) = ulColor;
  619. *(pulTemp+5) = ulColor;
  620. *(pulTemp+6) = ulColor;
  621. *(pulTemp+7) = ulColor;
  622. *(pulTemp+8) = ulColor;
  623. *(pulTemp+9) = ulColor;
  624. *(pulTemp+10) = ulColor;
  625. *(pulTemp+11) = ulColor;
  626. *(pulTemp+12) = ulColor;
  627. *(pulTemp+13) = ulColor;
  628. *(pulTemp+14) = ulColor;
  629. *(pulTemp+15) = ulColor;
  630. // Now dither all the remaining vertices in order 0->2 or 0->3
  631. // (in order of increasing intensity)
  632. pulDitherOrder = aulDither4bppOrder;
  633. pvVertexData = vVertexData;
  634. do {
  635. if (pvVertexData->ulVertex == 0xFF) {
  636. // This is the max vertex, which we already did, but we
  637. // have to account for it in the dither order
  638. pulDitherOrder += pvVertexData->ulCount;
  639. } else {
  640. jColor = (BYTE) pvVertexData->ulVertex;
  641. ulNumPixels = pvVertexData->ulCount;
  642. switch (ulNumPixels & 3) {
  643. case 3:
  644. ajDither[*(pulDitherOrder+2)] = jColor;
  645. case 2:
  646. ajDither[*(pulDitherOrder+1)] = jColor;
  647. case 1:
  648. ajDither[*(pulDitherOrder+0)] = jColor;
  649. pulDitherOrder += ulNumPixels & 3;
  650. case 0:
  651. break;
  652. }
  653. if ((ulNumPixels >>= 2) != 0) {
  654. do {
  655. ajDither[*pulDitherOrder] = jColor;
  656. ajDither[*(pulDitherOrder+1)] = jColor;
  657. ajDither[*(pulDitherOrder+2)] = jColor;
  658. ajDither[*(pulDitherOrder+3)] = jColor;
  659. pulDitherOrder += 4;
  660. } while (--ulNumPixels);
  661. }
  662. }
  663. } while (++pvVertexData < pvVertexDataEnd);
  664. } else if (ulNumVertices == 2) {
  665. // There are exactly two vertices with more than zero pixels; fill
  666. // in the dither array as follows: block fill with vertex with more
  667. // points first, then dither in the other vertex
  668. if (vVertexData[0].ulCount >= vVertexData[1].ulCount) {
  669. // There are no more vertex 1 than vertex 0 pixels, so do
  670. // the block fill with vertex 0
  671. ulColor = ulNibbleTo4bppDword[vVertexData[0].ulVertex];
  672. // Do the dither with vertex 1
  673. jColor = (BYTE) vVertexData[1].ulVertex;
  674. ulNumPixels = vVertexData[1].ulCount;
  675. // Set where to start dithering with vertex 1 (vertex 0 is
  676. // lower intensity, so its pixels come first in the dither
  677. // order)
  678. pulDitherOrder = aulDither4bppOrder + vVertexData[0].ulCount;
  679. } else {
  680. // There are more vertex 1 pixels, so do the block fill
  681. // with vertex 1
  682. ulColor = ulNibbleTo4bppDword[vVertexData[1].ulVertex];
  683. // Do the dither with vertex 0
  684. jColor = (BYTE) vVertexData[0].ulVertex;
  685. ulNumPixels = vVertexData[0].ulCount;
  686. // Set where to start dithering with vertex 0 (vertex 0 is
  687. // lower intensity, so its pixels come first in the dither
  688. // order)
  689. pulDitherOrder = aulDither4bppOrder;
  690. }
  691. // Block fill the dither pattern with the more common vertex
  692. pulTemp = (ULONG *)ajDither;
  693. *pulTemp = ulColor;
  694. *(pulTemp+1) = ulColor;
  695. *(pulTemp+2) = ulColor;
  696. *(pulTemp+3) = ulColor;
  697. *(pulTemp+4) = ulColor;
  698. *(pulTemp+5) = ulColor;
  699. *(pulTemp+6) = ulColor;
  700. *(pulTemp+7) = ulColor;
  701. *(pulTemp+8) = ulColor;
  702. *(pulTemp+9) = ulColor;
  703. *(pulTemp+10) = ulColor;
  704. *(pulTemp+11) = ulColor;
  705. *(pulTemp+12) = ulColor;
  706. *(pulTemp+13) = ulColor;
  707. *(pulTemp+14) = ulColor;
  708. *(pulTemp+15) = ulColor;
  709. // Dither in the less common vertex
  710. switch (ulNumPixels & 3) {
  711. case 3:
  712. ajDither[*(pulDitherOrder+2)] = jColor;
  713. case 2:
  714. ajDither[*(pulDitherOrder+1)] = jColor;
  715. case 1:
  716. ajDither[*(pulDitherOrder+0)] = jColor;
  717. pulDitherOrder += ulNumPixels & 3;
  718. case 0:
  719. break;
  720. }
  721. if ((ulNumPixels >>= 2) != 0) {
  722. do {
  723. ajDither[*pulDitherOrder] = jColor;
  724. ajDither[*(pulDitherOrder+1)] = jColor;
  725. ajDither[*(pulDitherOrder+2)] = jColor;
  726. ajDither[*(pulDitherOrder+3)] = jColor;
  727. pulDitherOrder += 4;
  728. } while (--ulNumPixels);
  729. }
  730. } else {
  731. // There is only one vertex in this dither
  732. // No sorting or dithering is needed for just one color; we can
  733. // just generate the final DIB directly
  734. ulColor = ulNibbleTo4bppDword[vVertexData[0].ulVertex];
  735. ulColor |= ulColor << 4;
  736. *pulDest = ulColor;
  737. *(pulDest+1) = ulColor;
  738. *(pulDest+2) = ulColor;
  739. *(pulDest+3) = ulColor;
  740. *(pulDest+4) = ulColor;
  741. *(pulDest+5) = ulColor;
  742. *(pulDest+6) = ulColor;
  743. *(pulDest+7) = ulColor;
  744. return;
  745. }
  746. // Now convert the 64 bytes into the 4BPP Engine Format Bitmap
  747. pulTemp = (ULONG *)ajDither;
  748. *pulDest = (*pulTemp << 4) | *(pulTemp + 1);
  749. *(pulDest + 1) = (*(pulTemp + 2) << 4) | *(pulTemp + 3);
  750. *(pulDest + 2) = (*(pulTemp + 4) << 4) | *(pulTemp + 5);
  751. *(pulDest + 3) = (*(pulTemp + 6) << 4) | *(pulTemp + 7);
  752. *(pulDest + 4) = (*(pulTemp + 8) << 4) | *(pulTemp + 9);
  753. *(pulDest + 5) = (*(pulTemp + 10) << 4) | *(pulTemp + 11);
  754. *(pulDest + 6) = (*(pulTemp + 12) << 4) | *(pulTemp + 13);
  755. *(pulDest + 7) = (*(pulTemp + 14) << 4) | *(pulTemp + 15);
  756. }
  757. /******************************Public*Routine******************************\
  758. * EngDitherColor
  759. *
  760. * Dithers an RGB color to an 8X8 approximation using the reserved VGA
  761. * colours.
  762. *
  763. \**************************************************************************/
  764. ULONG EngDitherColor(
  765. HDEV hdev,
  766. ULONG iMode,
  767. ULONG rgb,
  768. ULONG* pul)
  769. {
  770. ULONG ulGrey, ulRed, ulGre, ulBlu, ulTemp, ulRet;
  771. VERTEX_DATA vVertexData[4];
  772. VERTEX_DATA *pvVertexData;
  773. PDEVOBJ po(hdev);
  774. ulRet = DCR_SOLID;
  775. // We handle only 8x8 dithers. If the driver has their value set to
  776. // something else, we have to bail.
  777. if ((po.cxDither() != 8) || (po.cyDither() != 8))
  778. {
  779. WARNING("EngDitherColor works only when driver sets its DEVINFO");
  780. WARNING("cxDither and cyDither values to 8");
  781. }
  782. else
  783. {
  784. // Figure out if we need a full color dither or only a monochrome dither.
  785. // Note: we should get color dithers only at 8bpp and 4bpp, because
  786. // those are the only color depths at which drivers should
  787. // set GCAPS_COLOR_DITHER.
  788. if (iMode != DM_MONOCHROME)
  789. {
  790. // We only handle 8bpp and 4bpp color dithers:
  791. if (po.iDitherFormat() == BMF_8BPP ||
  792. po.iDitherFormat() == BMF_4BPP)
  793. {
  794. // Full color dither
  795. // Calculate what color subspaces are involved in the dither
  796. pvVertexData = vComputeSubspaces(rgb, vVertexData);
  797. // Now that we have found the bounding vertices and the number of
  798. // pixels to dither for each vertex, we can create the dither pattern
  799. // Handle 1, 2, and 3 & 4 vertices per dither separately
  800. ulTemp = (ULONG) (pvVertexData - vVertexData);
  801. // # of vertices with more than
  802. // zero pixels in the dither
  803. if (po.iDitherFormat() == BMF_8BPP)
  804. {
  805. vDitherColor8bpp(pul, vVertexData, pvVertexData, ulTemp);
  806. }
  807. else
  808. {
  809. vDitherColor4bpp(pul, vVertexData, pvVertexData, ulTemp);
  810. }
  811. ulRet = DCR_DRIVER;
  812. }
  813. else
  814. {
  815. WARNING("EngDitherColor works for DM_DEFAULT only when at 8bpp or 4bpp");
  816. }
  817. }
  818. else
  819. {
  820. // Note: we can get monochrome dithers at any colour depth because
  821. // we always set GCAPS_MONO_DITHER.
  822. // For monochrome we will only use the Intensity (grey level)
  823. RtlFillMemory((PVOID) pul, PATTERNSIZE/2, 0); // zero the dither bits
  824. ulRed = (ULONG) ((PALETTEENTRY *) &rgb)->peRed;
  825. ulGre = (ULONG) ((PALETTEENTRY *) &rgb)->peGreen;
  826. ulBlu = (ULONG) ((PALETTEENTRY *) &rgb)->peBlue;
  827. // I = .30R + .59G + .11B
  828. // For convience the following ratios are used:
  829. //
  830. // 77/256 = 30.08%
  831. // 151/256 = 58.98%
  832. // 28/256 = 10.94%
  833. ulGrey = (((ulRed * 77) + (ulGre * 151) + (ulBlu * 28)) >> 8) & 255;
  834. // Convert the RGBI from 0-255 to 0-64 notation.
  835. ulGrey = (ulGrey + 1) >> 2;
  836. while(ulGrey) {
  837. ulGrey--;
  838. pul[ajByte[ulGrey]] |= ((ULONG) ajBits[ulGrey]);
  839. }
  840. ulRet = DCR_DRIVER;
  841. }
  842. }
  843. return(ulRet);
  844. }