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.

422 lines
13 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: fastfill.c
  3. *
  4. * Fills solid-coloured, unclipped, non-complex rectangles.
  5. *
  6. * Copyright (c) 1993-1994 Microsoft Corporation
  7. \**************************************************************************/
  8. #include "precomp.h"
  9. #define RIGHT 0
  10. #define LEFT 1
  11. #define SWAP(a, b, tmp) { tmp = a; a = b; b = tmp; }
  12. typedef struct _EDGEDATA {
  13. LONG x; // Current x position
  14. LONG dx; // # pixels to advance x on each scan
  15. LONG lError; // Current DDA error
  16. LONG lErrorUp; // DDA error increment on each scan
  17. LONG lErrorDown; // DDA error adjustment
  18. POINTFIX* pptfx; // Points to start of current edge
  19. LONG dptfx; // Delta (in bytes) from pptfx to next point
  20. LONG cy; // Number of scans to go for this edge
  21. } EDGEDATA; /* ed, ped */
  22. /******************************Public*Routine******************************\
  23. * bFastFill
  24. *
  25. * Draws a non-complex, unclipped polygon.
  26. *
  27. * Returns TRUE if the polygon was drawn; FALSE if the polygon was complex.
  28. *
  29. \**************************************************************************/
  30. BOOL bFastFill(
  31. PPDEV ppdev,
  32. LONG cEdges, // Includes close figure edge
  33. POINTFIX* pptfxFirst,
  34. ULONG ulHwMix,
  35. ULONG iSolidColor)
  36. {
  37. LONG yTrapezoid; // Top scan for next trapezoid
  38. LONG cyTrapezoid; // Number of scans in current trapezoid
  39. LONG yStart; // y-position of start point in current edge
  40. LONG dM; // Edge delta in FIX units in x direction
  41. LONG dN; // Edge delta in FIX units in y direction
  42. LONG i;
  43. POINTFIX* pptfxLast; // Points to the last point in the polygon array
  44. POINTFIX* pptfxTop; // Points to the top-most point in the polygon
  45. POINTFIX* pptfxOld; // Start point in current edge
  46. POINTFIX* pptfxScan; // Current edge pointer for finding pptfxTop
  47. LONG cScanEdges; // Number of edges scanned to find pptfxTop
  48. // (doesn't include the closefigure edge)
  49. LONG iEdge;
  50. LONG lQuotient;
  51. LONG lRemainder;
  52. EDGEDATA aed[2]; // DDA terms and stuff
  53. EDGEDATA* ped;
  54. pptfxScan = pptfxFirst;
  55. pptfxTop = pptfxFirst; // Assume for now that the first
  56. // point in path is the topmost
  57. pptfxLast = pptfxFirst + cEdges - 1;
  58. // 'pptfxScan' will always point to the first point in the current
  59. // edge, and 'cScanEdges' will the number of edges remaining, including
  60. // the current one:
  61. cScanEdges = cEdges - 1; // The number of edges, not counting close figure
  62. if ((pptfxScan + 1)->y > pptfxScan->y)
  63. {
  64. // Collect all downs:
  65. do {
  66. if (--cScanEdges == 0)
  67. goto SetUpForFilling;
  68. pptfxScan++;
  69. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  70. // Collect all ups:
  71. do {
  72. if (--cScanEdges == 0)
  73. goto SetUpForFillingCheck;
  74. pptfxScan++;
  75. } while ((pptfxScan + 1)->y <= pptfxScan->y);
  76. // Collect all downs:
  77. pptfxTop = pptfxScan;
  78. do {
  79. if ((pptfxScan + 1)->y > pptfxFirst->y)
  80. break;
  81. if (--cScanEdges == 0)
  82. goto SetUpForFilling;
  83. pptfxScan++;
  84. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  85. return(FALSE);
  86. }
  87. else
  88. {
  89. // Collect all ups:
  90. do {
  91. pptfxTop++; // We increment this now because we
  92. // want it to point to the very last
  93. // point if we early out in the next
  94. // statement...
  95. if (--cScanEdges == 0)
  96. goto SetUpForFilling;
  97. } while ((pptfxTop + 1)->y <= pptfxTop->y);
  98. // Collect all downs:
  99. pptfxScan = pptfxTop;
  100. do {
  101. if (--cScanEdges == 0)
  102. goto SetUpForFilling;
  103. pptfxScan++;
  104. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  105. // Collect all ups:
  106. do {
  107. if ((pptfxScan + 1)->y < pptfxFirst->y)
  108. break;
  109. if (--cScanEdges == 0)
  110. goto SetUpForFilling;
  111. pptfxScan++;
  112. } while ((pptfxScan + 1)->y <= pptfxScan->y);
  113. return(FALSE);
  114. }
  115. SetUpForFillingCheck:
  116. // We check to see if the end of the current edge is higher
  117. // than the top edge we've found so far:
  118. if ((pptfxScan + 1)->y < pptfxTop->y)
  119. pptfxTop = pptfxScan + 1;
  120. SetUpForFilling:
  121. yTrapezoid = (pptfxTop->y + 15) >> 4;
  122. // We initialize the hardware for the colour, mix, pixel operation,
  123. // rectangle height of one, and the y position for the first scan:
  124. IO_FIFO_WAIT(ppdev, 5);
  125. IO_CUR_Y(ppdev, yTrapezoid);
  126. IO_FRGD_COLOR(ppdev, (INT) iSolidColor);
  127. IO_FRGD_MIX(ppdev, FOREGROUND_COLOR | (WORD) ulHwMix);
  128. IO_PIX_CNTL(ppdev, ALL_ONES);
  129. IO_MIN_AXIS_PCNT(ppdev, 0);
  130. // Make sure we initialize the DDAs appropriately:
  131. aed[LEFT].cy = 0;
  132. aed[RIGHT].cy = 0;
  133. // For now, guess as to which is the left and which is the right edge:
  134. aed[LEFT].dptfx = -(LONG) sizeof(POINTFIX);
  135. aed[RIGHT].dptfx = sizeof(POINTFIX);
  136. aed[LEFT].pptfx = pptfxTop;
  137. aed[RIGHT].pptfx = pptfxTop;
  138. NextEdge:
  139. // We loop through this routine on a per-trapezoid basis.
  140. for (iEdge = 1; iEdge >= 0; iEdge--)
  141. {
  142. ped = &aed[iEdge];
  143. if (ped->cy == 0)
  144. {
  145. // Need a new DDA:
  146. do {
  147. cEdges--;
  148. if (cEdges < 0)
  149. return(TRUE);
  150. // Find the next left edge, accounting for wrapping:
  151. pptfxOld = ped->pptfx;
  152. ped->pptfx = (POINTFIX*) ((BYTE*) ped->pptfx + ped->dptfx);
  153. if (ped->pptfx < pptfxFirst)
  154. ped->pptfx = pptfxLast;
  155. else if (ped->pptfx > pptfxLast)
  156. ped->pptfx = pptfxFirst;
  157. // Have to find the edge that spans yTrapezoid:
  158. ped->cy = ((ped->pptfx->y + 15) >> 4) - yTrapezoid;
  159. // With fractional coordinate end points, we may get edges
  160. // that don't cross any scans, in which case we try the
  161. // next one:
  162. } while (ped->cy <= 0);
  163. // 'pptfx' now points to the end point of the edge spanning
  164. // the scan 'yTrapezoid'.
  165. dN = ped->pptfx->y - pptfxOld->y;
  166. dM = ped->pptfx->x - pptfxOld->x;
  167. ASSERTDD(dN > 0, "Should be going down only");
  168. // Compute the DDA increment terms:
  169. if (dM < 0)
  170. {
  171. dM = -dM;
  172. if (dM < dN) // Can't be '<='
  173. {
  174. ped->dx = -1;
  175. ped->lErrorUp = dN - dM;
  176. }
  177. else
  178. {
  179. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  180. ped->dx = -lQuotient; // - dM / dN
  181. ped->lErrorUp = lRemainder; // dM % dN
  182. if (ped->lErrorUp > 0)
  183. {
  184. ped->dx--;
  185. ped->lErrorUp = dN - ped->lErrorUp;
  186. }
  187. }
  188. }
  189. else
  190. {
  191. if (dM < dN) // Can't be '<='
  192. {
  193. ped->dx = 0;
  194. ped->lErrorUp = dM;
  195. }
  196. else
  197. {
  198. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  199. ped->dx = lQuotient; // dM / dN
  200. ped->lErrorUp = lRemainder; // dM % dN
  201. }
  202. }
  203. ped->lErrorDown = dN; // DDA limit
  204. ped->lError = -1; // Error is initially zero (add dN - 1 for
  205. // the ceiling, but subtract off dN so that
  206. // we can check the sign instead of comparing
  207. // to dN)
  208. ped->x = pptfxOld->x;
  209. yStart = pptfxOld->y;
  210. if ((yStart & 15) != 0)
  211. {
  212. // Advance to the next integer y coordinate
  213. for (i = 16 - (yStart & 15); i != 0; i--)
  214. {
  215. ped->x += ped->dx;
  216. ped->lError += ped->lErrorUp;
  217. if (ped->lError >= 0)
  218. {
  219. ped->lError -= ped->lErrorDown;
  220. ped->x++;
  221. }
  222. }
  223. }
  224. if ((ped->x & 15) != 0)
  225. {
  226. ped->lError -= ped->lErrorDown * (16 - (ped->x & 15));
  227. ped->x += 15; // We'll want the ceiling in just a bit...
  228. }
  229. // Chop off those fractional bits:
  230. ped->x >>= 4;
  231. ped->lError >>= 4;
  232. }
  233. }
  234. cyTrapezoid = min(aed[LEFT].cy, aed[RIGHT].cy); // # of scans in this trap
  235. aed[LEFT].cy -= cyTrapezoid;
  236. aed[RIGHT].cy -= cyTrapezoid;
  237. yTrapezoid += cyTrapezoid; // Top scan in next trap
  238. // If the left and right edges are vertical, simply output as
  239. // a rectangle:
  240. if (((aed[LEFT].lErrorUp | aed[RIGHT].lErrorUp) == 0) &&
  241. ((aed[LEFT].dx | aed[RIGHT].dx) == 0) &&
  242. (cyTrapezoid > 1))
  243. {
  244. LONG lWidth;
  245. ContinueVertical:
  246. lWidth = aed[RIGHT].x - aed[LEFT].x - 1;
  247. if (lWidth >= 0)
  248. {
  249. IO_FIFO_WAIT(ppdev, 5);
  250. IO_MAJ_AXIS_PCNT(ppdev, lWidth);
  251. IO_MIN_AXIS_PCNT(ppdev, cyTrapezoid - 1);
  252. IO_CUR_X(ppdev, aed[LEFT].x);
  253. IO_CMD(ppdev, RECTANGLE_FILL | DRAWING_DIR_TBLRXM |
  254. DRAW | DIR_TYPE_XY |
  255. LAST_PIXEL_ON | MULTIPLE_PIXELS |
  256. WRITE);
  257. IO_MIN_AXIS_PCNT(ppdev, 0);
  258. }
  259. else if (lWidth == -1)
  260. {
  261. // If the rectangle was too thin to light any pels, we still
  262. // have to advance the y current position:
  263. IO_FIFO_WAIT(ppdev, 1);
  264. IO_CUR_Y(ppdev, yTrapezoid - cyTrapezoid + 1);
  265. }
  266. else
  267. {
  268. LONG lTmp;
  269. POINTFIX* pptfxTmp;
  270. SWAP(aed[LEFT].x, aed[RIGHT].x, lTmp);
  271. SWAP(aed[LEFT].cy, aed[RIGHT].cy, lTmp);
  272. SWAP(aed[LEFT].dptfx, aed[RIGHT].dptfx, lTmp);
  273. SWAP(aed[LEFT].pptfx, aed[RIGHT].pptfx, pptfxTmp);
  274. goto ContinueVertical;
  275. }
  276. goto NextEdge;
  277. }
  278. while (TRUE)
  279. {
  280. LONG lWidth;
  281. // The very first time through, make sure we set x:
  282. lWidth = aed[RIGHT].x - aed[LEFT].x - 1;
  283. if (lWidth >= 0)
  284. {
  285. IO_FIFO_WAIT(ppdev, 3);
  286. IO_MAJ_AXIS_PCNT(ppdev, lWidth);
  287. IO_CUR_X(ppdev, aed[LEFT].x);
  288. IO_CMD(ppdev, RECTANGLE_FILL | DRAWING_DIR_TBLRXM |
  289. DRAW | DIR_TYPE_XY |
  290. LAST_PIXEL_ON | MULTIPLE_PIXELS |
  291. WRITE);
  292. ContinueAfterZero:
  293. // Advance the right wall:
  294. aed[RIGHT].x += aed[RIGHT].dx;
  295. aed[RIGHT].lError += aed[RIGHT].lErrorUp;
  296. if (aed[RIGHT].lError >= 0)
  297. {
  298. aed[RIGHT].lError -= aed[RIGHT].lErrorDown;
  299. aed[RIGHT].x++;
  300. }
  301. // Advance the left wall:
  302. aed[LEFT].x += aed[LEFT].dx;
  303. aed[LEFT].lError += aed[LEFT].lErrorUp;
  304. if (aed[LEFT].lError >= 0)
  305. {
  306. aed[LEFT].lError -= aed[LEFT].lErrorDown;
  307. aed[LEFT].x++;
  308. }
  309. cyTrapezoid--;
  310. if (cyTrapezoid == 0)
  311. goto NextEdge;
  312. }
  313. else if (lWidth == -1)
  314. {
  315. IO_FIFO_WAIT(ppdev, 1);
  316. IO_CUR_Y(ppdev, yTrapezoid - cyTrapezoid + 1);
  317. goto ContinueAfterZero;
  318. }
  319. else
  320. {
  321. // We certainly don't want to optimize for this case because we
  322. // should rarely get self-intersecting polygons (if we're slow,
  323. // the app gets what it deserves):
  324. LONG lTmp;
  325. POINTFIX* pptfxTmp;
  326. SWAP(aed[LEFT].x, aed[RIGHT].x, lTmp);
  327. SWAP(aed[LEFT].dx, aed[RIGHT].dx, lTmp);
  328. SWAP(aed[LEFT].lError, aed[RIGHT].lError, lTmp);
  329. SWAP(aed[LEFT].lErrorUp, aed[RIGHT].lErrorUp, lTmp);
  330. SWAP(aed[LEFT].lErrorDown, aed[RIGHT].lErrorDown, lTmp);
  331. SWAP(aed[LEFT].cy, aed[RIGHT].cy, lTmp);
  332. SWAP(aed[LEFT].dptfx, aed[RIGHT].dptfx, lTmp);
  333. SWAP(aed[LEFT].pptfx, aed[RIGHT].pptfx, pptfxTmp);
  334. continue;
  335. }
  336. }
  337. }