Source code of Windows XP (NT5)
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.

383 lines
12 KiB

  1. /*-----------------------------------------------------------------------------+
  2. | BLTPROP.C |
  3. | |
  4. | Emulates the 16 bit BLTPROP.ASM for WIN32 |
  5. | |
  6. | (C) Copyright Microsoft Corporation 1993. All rights reserved. |
  7. | |
  8. | Revision History |
  9. | 21-Oct-1992 MikeTri Created |
  10. | 09-Apr-1993 GeraintD Added error propagation
  11. | |
  12. +-----------------------------------------------------------------------------*/
  13. #include <windows.h>
  14. #include <stdlib.h>
  15. #include "mplayer.h"
  16. #include "bltprop.h"
  17. /*
  18. * 256 colour to 16 colour dithering by error propagation
  19. *
  20. * This function takes an 8-bit DIB using 256 colours and converts
  21. * it to a DIB that uses only 16 distinct colours.
  22. *
  23. * We take a pixel and convert it to one of the 16 standard vga colours
  24. * by taking each component and comparing it against a low and high
  25. * threshold. Less than the low gets 0 of that component; between low
  26. * and high gets an intensity of 128, and above the high threshold gets
  27. * an intensity of 255 for that component. (the standard 16 colours
  28. * have the 8 combinations of 0 or 128 for each component, and the
  29. * 8 combinations of 0 or 255 for each component - there are no colours
  30. * combining intensities of 255 and 128). So if any of our colours
  31. * are above the high threshold, we use 255 for any non-0 intensity.
  32. * We also have 2 grey levels that are picked out if all colour intensities
  33. * are less than a given threshold.
  34. *
  35. * The conversion is done by building an 8-bit value with bits set to
  36. * indicate if each component is above either of the two thresholds,
  37. * and then using this as a palette index. We thus use an output colour
  38. * table that contains 256 entries, though only 16 distinct colours.
  39. *
  40. * Having converted the pixel into the new palette index, we calculate the
  41. * difference for each r,g,b component between the original and the final
  42. * colour. We then add a fraction of this error to the adjacent pixels
  43. * along, down and diagonally. These error values are added to the
  44. * red, green and blue values for the adjacent pixels before comparing
  45. * against the thresholds in the colour conversion process.
  46. */
  47. /*
  48. * y error propagation - this contains the error for each component that
  49. * we wish to pass to the line below. Thus there is one entry for each
  50. * colour component for each pixel. The same max line length is assumed
  51. * in the win-16 version.
  52. */
  53. #define MAXBITMAPWIDTH 1500
  54. typedef struct _colour_error {
  55. int red_error;
  56. int green_error;
  57. int blue_error;
  58. } colour_error, *pcolour_error;
  59. colour_error y_error[MAXBITMAPWIDTH];
  60. /*
  61. * we take the difference between the actual and desired components,
  62. * multiply up by SCALE_UP, and then pass the result divided by SCALE_X
  63. * to both the pixel across and below, and divided by SCALE_Z to the pixel
  64. * diagonally across and below. (Below of course, means further down the
  65. * DIB, and therefore higher up the screen)
  66. */
  67. #define SCALE_UP 8
  68. #define SCALE_X 32
  69. #define SCALE_Z 64
  70. /*
  71. * The final pixel has the following form:
  72. *
  73. * bits 7x543210
  74. * | ||||||
  75. * | |||||+-- set iff RED > HiThresh
  76. * | ||||+--- set iff RED > LoThresh
  77. * | |||+---- set iff GREEN > HiThresh
  78. * | ||+----- set iff GREEN > LoThresh
  79. * | |+------ set iff BLUE > HiThresh
  80. * | +------- set iff BLUE > LoThresh
  81. * +--------- set iff all colors > GrayThresh
  82. */
  83. #define RED_HITHRESH 0x01
  84. #define RED_LOTHRESH 0x02
  85. #define GREEN_HITHRESH 0x04
  86. #define GREEN_LOTHRESH 0x08
  87. #define BLUE_HITHRESH 0x10
  88. #define BLUE_LOTHRESH 0x20
  89. #define GRAY_THRESH 0x80
  90. #define ALL_HITHRESH (RED_HITHRESH | GREEN_HITHRESH | BLUE_HITHRESH)
  91. #define ALL_LOTHRESH (RED_LOTHRESH | GREEN_LOTHRESH | BLUE_LOTHRESH)
  92. /*
  93. * convert a palette index in the above threshold format into the
  94. * rgb component values.
  95. */
  96. RGBQUAD
  97. ThresholdToRGB(int PalIndex)
  98. {
  99. RGBQUAD rgbq;
  100. BYTE RGBVal;
  101. /* Special case greys */
  102. if (PalIndex == (GRAY_THRESH | ALL_LOTHRESH)) {
  103. rgbq.rgbRed = rgbq.rgbGreen = rgbq.rgbBlue = 0xc0;
  104. } else if (PalIndex == GRAY_THRESH) {
  105. rgbq.rgbRed = rgbq.rgbGreen = rgbq.rgbBlue = 0x80;
  106. } else {
  107. rgbq.rgbRed = 0;
  108. rgbq.rgbGreen = 0;
  109. rgbq.rgbBlue = 0;
  110. /*
  111. * if any components are above hi-threshold, then
  112. * use the high threshold for all non-zero components; otherwise
  113. * use the low threshold for all non-zero components.
  114. */
  115. if (PalIndex & ALL_HITHRESH) {
  116. RGBVal = 0xff;
  117. } else {
  118. RGBVal = 0x80;
  119. }
  120. if (PalIndex & (RED_HITHRESH | RED_LOTHRESH)) {
  121. rgbq.rgbRed = RGBVal;
  122. }
  123. if (PalIndex & (GREEN_HITHRESH | GREEN_LOTHRESH)) {
  124. rgbq.rgbGreen = RGBVal;
  125. }
  126. if (PalIndex & (BLUE_HITHRESH | BLUE_LOTHRESH)) {
  127. rgbq.rgbBlue = RGBVal;
  128. }
  129. }
  130. return (rgbq);
  131. }
  132. /*
  133. * copy a dib from pbSrc to pbDst reducing to 16 distinct colours
  134. */
  135. void FAR PASCAL BltProp(LPBITMAPINFOHEADER pbiSrc,
  136. LPBYTE pbSrc,
  137. UINT SrcX,
  138. UINT SrcY,
  139. UINT SrcXE,
  140. UINT SrcYE,
  141. LPBITMAPINFOHEADER pbiDst,
  142. LPBYTE pbDst,
  143. UINT DstX,
  144. UINT DstY)
  145. {
  146. UINT count, row, column;
  147. BYTE TempByte;
  148. BYTE ColourTableIndex;
  149. int RedVal;
  150. int GreenVal;
  151. int BlueVal;
  152. colour_error x_error, z_error;
  153. int scaled_error, scaled_x, scaled_z;
  154. RGBQUAD rgbq;
  155. LPBITMAPINFO ColourTable;
  156. DPF2("BltProp");
  157. /*
  158. * clear the y_error to zero at start of bitmap
  159. */
  160. for (count = 0; count < SrcXE; count++) {
  161. y_error[count].red_error = 0;
  162. y_error[count].green_error = 0;
  163. y_error[count].blue_error = 0;
  164. }
  165. /*****************************************************************************\
  166. *
  167. * Loop through the bitmap picking up the pixel r,g,b values, adjust for
  168. * the error propagated and then compare the components against the two
  169. * threshold values. The resulting byte has the following form:
  170. *
  171. * bits 7x543210
  172. * | ||||||
  173. * | |||||+-- set iff RED > HiThresh
  174. * | ||||+--- set iff RED > LoThresh
  175. * | |||+---- set iff GREEN > HiThresh
  176. * | ||+----- set iff GREEN > LoThresh
  177. * | |+------ set iff BLUE > HiThresh
  178. * | +------- set iff BLUE > LoThresh
  179. * +--------- set iff all colors > GrayThresh
  180. *
  181. * This is an index into the 256-entry colour table generated below (that
  182. * uses only 16 distinct colours).
  183. *
  184. * After creating the correct colour, we calculate the difference between
  185. * this colour and the original, and propagate that error forwards and down.
  186. *
  187. \*****************************************************************************/
  188. /* offset source, dest pointers by SrcX rows */
  189. pbSrc += (SrcY * pbiSrc->biWidth) + SrcX;
  190. pbDst += (DstY * pbiDst->biWidth) + DstX;
  191. ColourTable = (LPBITMAPINFO)pbiSrc;
  192. for (row=0; row < SrcYE ; row++) {
  193. /* clear x error for start of row */
  194. x_error.red_error = 0;
  195. x_error.green_error = 0;
  196. x_error.blue_error = 0;
  197. z_error.red_error = 0;
  198. z_error.green_error = 0;
  199. z_error.blue_error = 0;
  200. for (column = 0; column < SrcXE; column++) {
  201. /* pick up the source palette index and get rgb components */
  202. ColourTableIndex = *pbSrc++;
  203. RedVal = ColourTable->bmiColors[ColourTableIndex].rgbRed;
  204. GreenVal = ColourTable->bmiColors[ColourTableIndex].rgbGreen;
  205. BlueVal = ColourTable->bmiColors[ColourTableIndex].rgbBlue;
  206. /* add on error - x-error is propagated from
  207. * previous column. y-error is passed down from pixel above.
  208. * z-error is passed diagonally and has already been added
  209. * into y-error for this pixel.
  210. */
  211. RedVal += x_error.red_error + y_error[column].red_error;
  212. GreenVal += x_error.green_error + y_error[column].green_error;
  213. BlueVal += x_error.blue_error + y_error[column].blue_error;
  214. /*
  215. * As we move along the line, y_error[] for the pixels
  216. * ahead of us contains the error to be added to the pixels
  217. * on this row. y_error[] for the pixels we have done contains
  218. * the error to be propagated to those pixels on the row
  219. * below.
  220. *
  221. * Now that we have picked up the error for this pixel, we
  222. * can start accumulating errors for this column on the
  223. * row below. We start with the z_error from the previous pixel
  224. * and then add in (later) the y_error from the current pixel.
  225. */
  226. y_error[column] = z_error;
  227. TempByte = 0x00; // Our "new" bitmap entry, once it has been munged
  228. /*
  229. * set threshold bits for each component based on adjusted colours
  230. */
  231. if (RedVal > LoThresh) {
  232. TempByte |= RED_LOTHRESH;
  233. if (RedVal > HiThresh){
  234. TempByte |= RED_HITHRESH;
  235. }
  236. }
  237. if (GreenVal > LoThresh) {
  238. TempByte |= GREEN_LOTHRESH;
  239. if (GreenVal > HiThresh){
  240. TempByte |= GREEN_HITHRESH;
  241. }
  242. }
  243. if (BlueVal > LoThresh) {
  244. TempByte |= BLUE_LOTHRESH;
  245. if (BlueVal > HiThresh){
  246. TempByte |= BLUE_HITHRESH;
  247. }
  248. }
  249. /* set grey scale bit if all colours > grey threshold */
  250. if (
  251. (RedVal > GrayThresh)
  252. && (BlueVal > GrayThresh)
  253. && (GreenVal > GrayThresh)
  254. ) {
  255. TempByte |= GRAY_THRESH;
  256. }
  257. /* we now have palette index into new colour table */
  258. *pbDst++ = TempByte;
  259. /*
  260. * calculate difference for each component between
  261. * desired colour (after error adjustment) and actual
  262. * colour. Remember to add in to the y-error, since this
  263. * already contains the z_error from the previous cell.
  264. * Hold the z_error for this cell, since we can't add this
  265. * to the next y_error until we have used it for the next cell
  266. * on this row.
  267. *
  268. * do the scaling on the absolute values and then
  269. * put the sign back in afterwards - to make sure
  270. * we handle small negative numbers ok.
  271. */
  272. rgbq = ThresholdToRGB(TempByte);
  273. scaled_error = (RedVal - rgbq.rgbRed) * SCALE_UP;
  274. scaled_x = abs(scaled_error) / SCALE_X;
  275. scaled_z = abs(scaled_error) / SCALE_Z;
  276. x_error.red_error = (scaled_error > 0) ? scaled_x : -scaled_x;
  277. z_error.red_error = (scaled_error > 0) ? scaled_z : -scaled_z;
  278. y_error[column].red_error += x_error.red_error;
  279. scaled_error = (GreenVal - rgbq.rgbGreen) * SCALE_UP;
  280. scaled_x = abs(scaled_error) / SCALE_X;
  281. scaled_z = abs(scaled_error) / SCALE_Z;
  282. x_error.green_error = (scaled_error > 0) ? scaled_x : -scaled_x;
  283. z_error.green_error = (scaled_error > 0) ? scaled_z : -scaled_z;
  284. y_error[column].green_error += x_error.green_error;
  285. scaled_error = (BlueVal - rgbq.rgbBlue) * SCALE_UP;
  286. scaled_x = abs(scaled_error) / SCALE_X;
  287. scaled_z = abs(scaled_error) / SCALE_Z;
  288. x_error.blue_error = (scaled_error > 0) ? scaled_x : -scaled_x;
  289. z_error.blue_error = (scaled_error > 0) ? scaled_z : -scaled_z;
  290. y_error[column].blue_error += x_error.blue_error;
  291. }
  292. /* advance source and dest pointers from end of rectangle to start of
  293. * next line
  294. */
  295. pbSrc += pbiSrc->biWidth - SrcXE;
  296. pbDst += pbiDst->biWidth - SrcXE;
  297. }
  298. DPF2("BltProp - finished first loop");
  299. /*****************************************************************************\
  300. *
  301. * This part generates a new output colour table entry that is accessed by the
  302. * modified bitmap generated above, and updates the destination DIB colour
  303. * table with that new entry.
  304. *
  305. \*****************************************************************************/
  306. ColourTable = (LPBITMAPINFO)pbiDst;
  307. for (count=0; count<256; count++ ) {
  308. /* Update the original colour table within the destination DIB */
  309. ColourTable->bmiColors[count] = ThresholdToRGB(count);
  310. }
  311. DPF2("BltProp - finished second loop");
  312. }
  313.