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.

1204 lines
36 KiB

  1. /******************************************************************************\
  2. *
  3. * $Workfile: fastfill.c $
  4. *
  5. * Fast routine for drawing polygons that aren't complex in shape.
  6. *
  7. * Copyright (c) 1993-1997 Microsoft Corporation
  8. * Copyright (c) 1996-1997 Cirrus Logic, Inc.,
  9. *
  10. * $Log: S:/projects/drivers/ntsrc/display/fastfill.c_v $
  11. *
  12. * Rev 1.5 28 Jan 1997 13:46:30 PLCHU
  13. *
  14. *
  15. * Rev 1.3 10 Jan 1997 15:39:44 PLCHU
  16. *
  17. *
  18. * Rev 1.2 Nov 07 1996 16:48:02 unknown
  19. *
  20. *
  21. * Rev 1.1 Oct 10 1996 15:37:30 unknown
  22. *
  23. *
  24. * Rev 1.1 12 Aug 1996 16:53:14 frido
  25. * Removed unaccessed local variables.
  26. *
  27. * chu01 : 01-02-97 5480 BitBLT enhancement
  28. *
  29. \******************************************************************************/
  30. #include "precomp.h"
  31. #define RIGHT 0
  32. #define LEFT 1
  33. typedef struct _TRAPEZOIDDATA TRAPEZOIDDATA; // Handy forward declaration
  34. typedef VOID (FNTRAPEZOID)(TRAPEZOIDDATA*, LONG, LONG);
  35. // Prototype for trapezoid
  36. // drawing routines
  37. typedef struct _EDGEDATA {
  38. LONG x; // Current x position
  39. LONG dx; // # pixels to advance x on each scan
  40. LONG lError; // Current DDA error
  41. LONG lErrorUp; // DDA error increment on each scan
  42. LONG dN; // Signed delta-y in fixed point form (also known
  43. // as the DDA error adjustment, and used to be
  44. // called 'lErrorDown')
  45. LONG dM; // Signed delta-x in fixed point form
  46. POINTFIX* pptfx; // Points to start of current edge
  47. LONG dptfx; // Delta (in bytes) from pptfx to next point
  48. LONG cy; // Number of scans to go for this edge
  49. LONG bNew; // Set to TRUE when a new DDA must be started
  50. // for the edge.
  51. } EDGEDATA; /* ed, ped */
  52. typedef struct _TRAPEZOIDDATA {
  53. FNTRAPEZOID* pfnTrap; // Pointer to appropriate trapezoid drawing routine,
  54. // or trapezoid clip routine
  55. FNTRAPEZOID* pfnTrapClip;// Pointer to appropriate trapezoid drawing routine
  56. // if doing clipping
  57. PDEV* ppdev; // Pointer to PDEV
  58. EDGEDATA aed[2]; // DDA information for both edges
  59. POINTL ptlBrush; // Brush alignment
  60. LONG yClipTop; // Top of clip rectangle
  61. LONG yClipBottom;// Bottom of clip rectangle
  62. LONG xClipLeft; // Left edge of clip rectangle
  63. LONG xClipRight; // Right edge of clip rectangle
  64. BOOL bClip; // Are we clipping?
  65. } TRAPEZOIDDATA; /* td, ptd */
  66. /******************************Public*Routine******************************\
  67. * VOID vClipTrapezoid
  68. *
  69. * Clips a trapezoid.
  70. *
  71. * NOTE: This routine assumes that the polygon's dimensions are small
  72. * enough that its QUOTIENT_REMAINDER calculations won't overflow.
  73. * This means that large polygons must never make it here.
  74. *
  75. \**************************************************************************/
  76. VOID vClipTrapezoid(
  77. TRAPEZOIDDATA* ptd,
  78. LONG yTrapTop,
  79. LONG cyTrapezoid)
  80. {
  81. LONG yTrapBottom;
  82. LONG dN;
  83. LONG lNum;
  84. LONG xDelta;
  85. LONG lError;
  86. DISPDBG((2, "vClipTrapezoid"));
  87. yTrapBottom = yTrapTop + cyTrapezoid;
  88. if (yTrapTop < ptd->yClipTop)
  89. {
  90. if ((ptd->aed[LEFT].bNew) &&
  91. (yTrapBottom + ptd->aed[LEFT].cy > ptd->yClipTop))
  92. {
  93. dN = ptd->aed[LEFT].dN;
  94. lNum = ptd->aed[LEFT].dM * (ptd->yClipTop - yTrapTop)
  95. + (ptd->aed[LEFT].lError + dN);
  96. if (lNum >= 0)
  97. {
  98. QUOTIENT_REMAINDER(lNum, dN, xDelta, lError);
  99. }
  100. else
  101. {
  102. lNum = -lNum;
  103. QUOTIENT_REMAINDER(lNum, dN, xDelta, lError);
  104. xDelta = -xDelta;
  105. if (lError != 0)
  106. {
  107. xDelta--;
  108. lError = dN - lError;
  109. }
  110. }
  111. ptd->aed[LEFT].x += xDelta;
  112. ptd->aed[LEFT].lError = lError - dN;
  113. }
  114. if ((ptd->aed[RIGHT].bNew) &&
  115. (yTrapBottom + ptd->aed[RIGHT].cy > ptd->yClipTop))
  116. {
  117. dN = ptd->aed[RIGHT].dN;
  118. lNum = ptd->aed[RIGHT].dM * (ptd->yClipTop - yTrapTop)
  119. + (ptd->aed[RIGHT].lError + dN);
  120. if (lNum >= 0)
  121. {
  122. QUOTIENT_REMAINDER(lNum, dN, xDelta, lError);
  123. }
  124. else
  125. {
  126. lNum = -lNum;
  127. QUOTIENT_REMAINDER(lNum, dN, xDelta, lError);
  128. xDelta = -xDelta;
  129. if (lError != 0)
  130. {
  131. xDelta--;
  132. lError = dN - lError;
  133. }
  134. }
  135. ptd->aed[RIGHT].x += xDelta;
  136. ptd->aed[RIGHT].lError = lError - dN;
  137. }
  138. }
  139. // If this trapezoid vertically intersects our clip rectangle, draw it:
  140. if ((yTrapBottom > ptd->yClipTop) &&
  141. (yTrapTop < ptd->yClipBottom))
  142. {
  143. if (yTrapTop <= ptd->yClipTop)
  144. {
  145. yTrapTop = ptd->yClipTop;
  146. // Have to let trapezoid drawer know that it has to load
  147. // its DDAs for very first trapezoid drawn:
  148. ptd->aed[RIGHT].bNew = TRUE;
  149. ptd->aed[LEFT].bNew = TRUE;
  150. }
  151. if (yTrapBottom >= ptd->yClipBottom)
  152. {
  153. yTrapBottom = ptd->yClipBottom;
  154. }
  155. ptd->pfnTrapClip(ptd, yTrapTop, yTrapBottom - yTrapTop);
  156. }
  157. }
  158. /******************************Public*Routine******************************\
  159. * VOID vIoSolidTrapezoid
  160. *
  161. * Draws a solid trapezoid using a software DDA.
  162. *
  163. \**************************************************************************/
  164. VOID vIoSolidTrapezoid(
  165. TRAPEZOIDDATA* ptd,
  166. LONG yTrapezoid,
  167. LONG cyTrapezoid)
  168. {
  169. PDEV* ppdev;
  170. LONG xOffset;
  171. LONG lLeftError;
  172. LONG xLeft;
  173. LONG lRightError;
  174. LONG xRight;
  175. LONG lTmp;
  176. EDGEDATA edTmp;
  177. BYTE* pjPorts;
  178. LONG lDelta;
  179. DISPDBG((2, "vIoSolidTrapezoid"));
  180. ppdev = ptd->ppdev;
  181. pjPorts = ppdev->pjPorts;
  182. lDelta = ppdev->lDelta;
  183. xOffset = ppdev->xOffset;
  184. yTrapezoid += ppdev->yOffset;
  185. yTrapezoid *= lDelta;
  186. // If the left and right edges are vertical, simply output as
  187. // a rectangle:
  188. if (((ptd->aed[LEFT].lErrorUp | ptd->aed[RIGHT].lErrorUp) == 0) &&
  189. ((ptd->aed[LEFT].dx | ptd->aed[RIGHT].dx) == 0))
  190. {
  191. /////////////////////////////////////////////////////////////////
  192. // Vertical-edge special case
  193. xLeft = ptd->aed[LEFT].x + xOffset;
  194. xRight = ptd->aed[RIGHT].x + xOffset;
  195. if (xLeft > xRight)
  196. {
  197. SWAP(xLeft, xRight, lTmp);
  198. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  199. }
  200. if (ptd->bClip)
  201. {
  202. xLeft = max(xLeft, ptd->xClipLeft + xOffset);
  203. xRight = min(xRight, ptd->xClipRight + xOffset);
  204. }
  205. if (xLeft < xRight)
  206. {
  207. CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts);
  208. CP_IO_XCNT(ppdev, pjPorts, (PELS_TO_BYTES(xRight - xLeft) - 1));
  209. CP_IO_YCNT(ppdev, pjPorts, (cyTrapezoid - 1));
  210. CP_IO_DST_ADDR_ABS(ppdev, pjPorts, (yTrapezoid + PELS_TO_BYTES(xLeft)));
  211. CP_IO_START_BLT(ppdev, pjPorts);
  212. }
  213. }
  214. else
  215. {
  216. lLeftError = ptd->aed[LEFT].lError;
  217. xLeft = ptd->aed[LEFT].x + xOffset;
  218. lRightError = ptd->aed[RIGHT].lError;
  219. xRight = ptd->aed[RIGHT].x + xOffset;
  220. while (TRUE)
  221. {
  222. LONG xLeftClipped;
  223. LONG xRightClipped;
  224. if (ptd->bClip)
  225. {
  226. xLeftClipped = max(xLeft, ptd->xClipLeft + xOffset);
  227. xRightClipped = min(xRight, ptd->xClipRight + xOffset);
  228. }
  229. else
  230. {
  231. xLeftClipped = xLeft;
  232. xRightClipped = xRight;
  233. }
  234. /////////////////////////////////////////////////////////////////
  235. // Run the DDAs
  236. if (xLeftClipped < xRightClipped)
  237. {
  238. CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts);
  239. CP_IO_XCNT(ppdev, pjPorts, (PELS_TO_BYTES(xRightClipped - xLeftClipped) - 1));
  240. CP_IO_YCNT(ppdev, pjPorts, 0);
  241. CP_IO_DST_ADDR_ABS(ppdev, pjPorts, (yTrapezoid + PELS_TO_BYTES(xLeftClipped)));
  242. CP_IO_START_BLT(ppdev, pjPorts);
  243. }
  244. else if (xLeft > xRight)
  245. {
  246. // We don't bother optimizing this case because we should
  247. // rarely get self-intersecting polygons (if we're slow,
  248. // the app gets what it deserves).
  249. SWAP(xLeft, xRight, lTmp);
  250. SWAP(lLeftError, lRightError, lTmp);
  251. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  252. continue;
  253. }
  254. // Advance the right wall:
  255. xRight += ptd->aed[RIGHT].dx;
  256. lRightError += ptd->aed[RIGHT].lErrorUp;
  257. if (lRightError >= 0)
  258. {
  259. lRightError -= ptd->aed[RIGHT].dN;
  260. xRight++;
  261. }
  262. // Advance the left wall:
  263. xLeft += ptd->aed[LEFT].dx;
  264. lLeftError += ptd->aed[LEFT].lErrorUp;
  265. if (lLeftError >= 0)
  266. {
  267. lLeftError -= ptd->aed[LEFT].dN;
  268. xLeft++;
  269. }
  270. cyTrapezoid--;
  271. if (cyTrapezoid == 0)
  272. break;
  273. yTrapezoid += lDelta;
  274. }
  275. ptd->aed[LEFT].lError = lLeftError;
  276. ptd->aed[LEFT].x = xLeft - xOffset;
  277. ptd->aed[RIGHT].lError = lRightError;
  278. ptd->aed[RIGHT].x = xRight - xOffset;
  279. }
  280. }
  281. /******************************Public*Routine******************************\
  282. * VOID vIoTrapezoidSetup
  283. *
  284. * Initialize the hardware and some state for doing trapezoids.
  285. *
  286. \**************************************************************************/
  287. VOID vIoTrapezoidSetup(
  288. PDEV* ppdev,
  289. ULONG rop4,
  290. ULONG ulSolidColor,
  291. RBRUSH* prb,
  292. POINTL* pptlBrush,
  293. TRAPEZOIDDATA* ptd,
  294. RECTL* prclClip) // NULL if no clipping
  295. {
  296. BYTE* pjPorts = ppdev->pjPorts;
  297. LONG cBpp = ppdev->cBpp;
  298. LONG lDelta = ppdev->lDelta;
  299. BYTE jHwRop;
  300. DISPDBG((2, "vIoTrapezoidSetup"));
  301. ptd->ppdev = ppdev;
  302. jHwRop = gajHwMixFromRop2[(rop4 >> 2) & 0xf];
  303. /////////////////////////////////////////////////////////////////
  304. // Setup the hardware for solid colours
  305. ptd->pfnTrap = vIoSolidTrapezoid;
  306. // We initialize the hardware for the color, rop, start address,
  307. // and blt mode
  308. if (cBpp == 1)
  309. {
  310. ulSolidColor |= ulSolidColor << 8;
  311. ulSolidColor |= ulSolidColor << 16;
  312. }
  313. else if (cBpp == 2)
  314. {
  315. ulSolidColor |= ulSolidColor << 16;
  316. }
  317. CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts);
  318. CP_IO_ROP(ppdev, pjPorts, jHwRop);
  319. CP_IO_SRC_ADDR(ppdev, pjPorts, ppdev->ulSolidColorOffset);
  320. CP_IO_DST_Y_OFFSET(ppdev, pjPorts, lDelta);
  321. CP_IO_BLT_MODE(ppdev, pjPorts, ENABLE_COLOR_EXPAND |
  322. ENABLE_8x8_PATTERN_COPY |
  323. ppdev->jModeColor);
  324. CP_IO_FG_COLOR(ppdev, pjPorts, ulSolidColor);
  325. if (prclClip != NULL)
  326. {
  327. ptd->pfnTrapClip = ptd->pfnTrap;
  328. ptd->pfnTrap = vClipTrapezoid;
  329. ptd->yClipTop = prclClip->top;
  330. ptd->yClipBottom = prclClip->bottom;
  331. ptd->xClipLeft = prclClip->left;
  332. ptd->xClipRight = prclClip->right;
  333. ptd->bClip = TRUE;
  334. }
  335. else
  336. {
  337. ptd->bClip = FALSE;
  338. }
  339. }
  340. /******************************Public*Routine******************************\
  341. * VOID vMmSolidTrapezoid
  342. *
  343. * Draws a solid trapezoid using a software DDA.
  344. *
  345. \**************************************************************************/
  346. VOID vMmSolidTrapezoid(
  347. TRAPEZOIDDATA* ptd,
  348. LONG yTrapezoid,
  349. LONG cyTrapezoid)
  350. {
  351. PDEV* ppdev;
  352. LONG xOffset;
  353. LONG lLeftError;
  354. LONG xLeft;
  355. LONG lRightError;
  356. LONG xRight;
  357. LONG lTmp;
  358. EDGEDATA edTmp;
  359. BYTE* pjBase;
  360. LONG lDelta;
  361. DISPDBG((2, "vMmSolidTrapezoid"));
  362. ppdev = ptd->ppdev;
  363. pjBase = ppdev->pjBase;
  364. lDelta = ppdev->lDelta;
  365. xOffset = ppdev->xOffset;
  366. yTrapezoid += ppdev->yOffset;
  367. yTrapezoid *= lDelta;
  368. // If the left and right edges are vertical, simply output as
  369. // a rectangle:
  370. if (((ptd->aed[LEFT].lErrorUp | ptd->aed[RIGHT].lErrorUp) == 0) &&
  371. ((ptd->aed[LEFT].dx | ptd->aed[RIGHT].dx) == 0))
  372. {
  373. /////////////////////////////////////////////////////////////////
  374. // Vertical-edge special case
  375. xLeft = ptd->aed[LEFT].x + xOffset;
  376. xRight = ptd->aed[RIGHT].x + xOffset;
  377. if (xLeft > xRight)
  378. {
  379. SWAP(xLeft, xRight, lTmp);
  380. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  381. }
  382. if (ptd->bClip)
  383. {
  384. xLeft = max(xLeft, ptd->xClipLeft + xOffset);
  385. xRight = min(xRight, ptd->xClipRight + xOffset);
  386. }
  387. if (xLeft < xRight)
  388. {
  389. CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
  390. CP_MM_XCNT(ppdev, pjBase, (PELS_TO_BYTES(xRight - xLeft) - 1));
  391. CP_MM_YCNT(ppdev, pjBase, (cyTrapezoid - 1));
  392. CP_MM_DST_ADDR_ABS(ppdev, pjBase, (yTrapezoid + PELS_TO_BYTES(xLeft)));
  393. CP_MM_START_BLT(ppdev, pjBase);
  394. }
  395. }
  396. else
  397. {
  398. lLeftError = ptd->aed[LEFT].lError;
  399. xLeft = ptd->aed[LEFT].x + xOffset;
  400. lRightError = ptd->aed[RIGHT].lError;
  401. xRight = ptd->aed[RIGHT].x + xOffset;
  402. CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
  403. CP_MM_YCNT(ppdev, pjBase, 0);
  404. while (TRUE)
  405. {
  406. LONG xLeftClipped;
  407. LONG xRightClipped;
  408. if (ptd->bClip)
  409. {
  410. xLeftClipped = max(xLeft, ptd->xClipLeft + xOffset);
  411. xRightClipped = min(xRight, ptd->xClipRight + xOffset);
  412. }
  413. else
  414. {
  415. xLeftClipped = xLeft;
  416. xRightClipped = xRight;
  417. }
  418. /////////////////////////////////////////////////////////////////
  419. // Run the DDAs
  420. if (xLeftClipped < xRightClipped)
  421. {
  422. CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
  423. CP_MM_XCNT(ppdev, pjBase, (PELS_TO_BYTES(xRightClipped - xLeftClipped) - 1));
  424. //CP_MM_YCNT(ppdev, pjBase, 0);
  425. CP_MM_DST_ADDR_ABS(ppdev, pjBase, (yTrapezoid + PELS_TO_BYTES(xLeftClipped)));
  426. CP_MM_START_BLT(ppdev, pjBase);
  427. }
  428. else if (xLeft > xRight)
  429. {
  430. // We don't bother optimizing this case because we should
  431. // rarely get self-intersecting polygons (if we're slow,
  432. // the app gets what it deserves).
  433. SWAP(xLeft, xRight, lTmp);
  434. SWAP(lLeftError, lRightError, lTmp);
  435. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  436. continue;
  437. }
  438. // Advance the right wall:
  439. xRight += ptd->aed[RIGHT].dx;
  440. lRightError += ptd->aed[RIGHT].lErrorUp;
  441. if (lRightError >= 0)
  442. {
  443. lRightError -= ptd->aed[RIGHT].dN;
  444. xRight++;
  445. }
  446. // Advance the left wall:
  447. xLeft += ptd->aed[LEFT].dx;
  448. lLeftError += ptd->aed[LEFT].lErrorUp;
  449. if (lLeftError >= 0)
  450. {
  451. lLeftError -= ptd->aed[LEFT].dN;
  452. xLeft++;
  453. }
  454. cyTrapezoid--;
  455. if (cyTrapezoid == 0)
  456. break;
  457. yTrapezoid += lDelta;
  458. }
  459. ptd->aed[LEFT].lError = lLeftError;
  460. ptd->aed[LEFT].x = xLeft - xOffset;
  461. ptd->aed[RIGHT].lError = lRightError;
  462. ptd->aed[RIGHT].x = xRight - xOffset;
  463. }
  464. }
  465. /******************************Public*Routine******************************\
  466. * VOID vMmTrapezoidSetup
  467. *
  468. * Initialize the hardware and some state for doing trapezoids.
  469. *
  470. \**************************************************************************/
  471. VOID vMmTrapezoidSetup(
  472. PDEV* ppdev,
  473. ULONG rop4,
  474. ULONG ulSolidColor,
  475. RBRUSH* prb,
  476. POINTL* pptlBrush,
  477. TRAPEZOIDDATA* ptd,
  478. RECTL* prclClip) // NULL if no clipping
  479. {
  480. BYTE* pjBase = ppdev->pjBase;
  481. LONG cBpp = ppdev->cBpp;
  482. LONG lDelta = ppdev->lDelta;
  483. BYTE jHwRop;
  484. DISPDBG((2, "vMmTrapezoidSetup"));
  485. ptd->ppdev = ppdev;
  486. jHwRop = gajHwMixFromRop2[(rop4 >> 2) & 0xf];
  487. /////////////////////////////////////////////////////////////////
  488. // Setup the hardware for solid colours
  489. ptd->pfnTrap = vMmSolidTrapezoid;
  490. // We initialize the hardware for the color, rop, start address,
  491. // and blt mode
  492. if (cBpp == 1)
  493. {
  494. ulSolidColor |= ulSolidColor << 8;
  495. ulSolidColor |= ulSolidColor << 16;
  496. }
  497. else if (cBpp == 2)
  498. {
  499. ulSolidColor |= ulSolidColor << 16;
  500. }
  501. CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
  502. CP_MM_ROP(ppdev, pjBase, jHwRop);
  503. CP_MM_SRC_ADDR(ppdev, pjBase, ppdev->ulSolidColorOffset);
  504. CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta);
  505. CP_MM_BLT_MODE(ppdev, pjBase, ENABLE_COLOR_EXPAND |
  506. ENABLE_8x8_PATTERN_COPY |
  507. ppdev->jModeColor);
  508. CP_MM_FG_COLOR(ppdev, pjBase, ulSolidColor);
  509. if (prclClip != NULL)
  510. {
  511. ptd->pfnTrapClip = ptd->pfnTrap;
  512. ptd->pfnTrap = vClipTrapezoid;
  513. ptd->yClipTop = prclClip->top;
  514. ptd->yClipBottom = prclClip->bottom;
  515. ptd->xClipLeft = prclClip->left;
  516. ptd->xClipRight = prclClip->right;
  517. ptd->bClip = TRUE;
  518. }
  519. else
  520. {
  521. ptd->bClip = FALSE;
  522. }
  523. }
  524. // chu01
  525. /******************************Public*Routine******************************\
  526. *
  527. * B i t B L T E n h a n c e m e n t F o r C L - G D 5 4 8 0
  528. *
  529. \**************************************************************************/
  530. /******************************Public*Routine******************************\
  531. * VOID vMmSolidTrapezoid80
  532. *
  533. * Draws a solid trapezoid using a software DDA. This is for CL-GD5480 with
  534. * enhanced BitBLT features.
  535. *
  536. \**************************************************************************/
  537. VOID vMmSolidTrapezoid80(
  538. TRAPEZOIDDATA* ptd,
  539. LONG yTrapezoid,
  540. LONG cyTrapezoid)
  541. {
  542. PDEV* ppdev;
  543. LONG xOffset;
  544. LONG lLeftError;
  545. LONG xLeft;
  546. LONG lRightError;
  547. LONG xRight;
  548. LONG lTmp;
  549. EDGEDATA edTmp;
  550. BYTE* pjBase;
  551. LONG lDelta;
  552. DISPDBG((2, "vMmSolidTrapezoid80")) ;
  553. ppdev = ptd->ppdev ;
  554. pjBase = ppdev->pjBase ;
  555. lDelta = ppdev->lDelta ;
  556. xOffset = ppdev->xOffset ;
  557. yTrapezoid += ppdev->yOffset ;
  558. // If the left and right edges are vertical, simply output as
  559. // a rectangle:
  560. if (((ptd->aed[LEFT].lErrorUp | ptd->aed[RIGHT].lErrorUp) == 0) &&
  561. ((ptd->aed[LEFT].dx | ptd->aed[RIGHT].dx) == 0))
  562. {
  563. /////////////////////////////////////////////////////////////////
  564. // Vertical-edge special case
  565. xLeft = ptd->aed[LEFT].x + xOffset;
  566. xRight = ptd->aed[RIGHT].x + xOffset;
  567. if (xLeft > xRight)
  568. {
  569. SWAP(xLeft, xRight, lTmp);
  570. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  571. }
  572. if (ptd->bClip)
  573. {
  574. xLeft = max(xLeft, ptd->xClipLeft + xOffset);
  575. xRight = min(xRight, ptd->xClipRight + xOffset);
  576. }
  577. if (xLeft < xRight)
  578. {
  579. CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase) ;
  580. CP_MM_XCNT(ppdev, pjBase, (xRight - xLeft) - 1) ;
  581. CP_MM_YCNT(ppdev, pjBase, (cyTrapezoid - 1)) ;
  582. CP_MM_DST_ADDR_ABS(ppdev, pjBase, 0);
  583. CP_MM_DST_Y(ppdev, pjBase, yTrapezoid) ;
  584. CP_MM_DST_X(ppdev, pjBase, xLeft) ;
  585. }
  586. }
  587. else
  588. {
  589. lLeftError = ptd->aed[LEFT].lError;
  590. xLeft = ptd->aed[LEFT].x + xOffset;
  591. lRightError = ptd->aed[RIGHT].lError;
  592. xRight = ptd->aed[RIGHT].x + xOffset;
  593. CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
  594. CP_MM_YCNT(ppdev, pjBase, 0);
  595. while (TRUE)
  596. {
  597. LONG xLeftClipped;
  598. LONG xRightClipped;
  599. if (ptd->bClip)
  600. {
  601. xLeftClipped = max(xLeft, ptd->xClipLeft + xOffset);
  602. xRightClipped = min(xRight, ptd->xClipRight + xOffset);
  603. }
  604. else
  605. {
  606. xLeftClipped = xLeft;
  607. xRightClipped = xRight;
  608. }
  609. /////////////////////////////////////////////////////////////////
  610. // Run the DDAs
  611. if (xLeftClipped < xRightClipped)
  612. {
  613. CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase) ;
  614. CP_MM_XCNT(ppdev, pjBase, (xRightClipped - xLeftClipped) - 1) ;
  615. // CP_MM_YCNT(ppdev, pjBase, 0) ;
  616. CP_MM_DST_ADDR_ABS(ppdev, pjBase, 0) ;
  617. CP_MM_DST_Y(ppdev, pjBase, yTrapezoid) ;
  618. CP_MM_DST_X(ppdev, pjBase, xLeftClipped) ;
  619. }
  620. else if (xLeft > xRight)
  621. {
  622. // We don't bother optimizing this case because we should
  623. // rarely get self-intersecting polygons (if we're slow,
  624. // the app gets what it deserves).
  625. SWAP(xLeft, xRight, lTmp);
  626. SWAP(lLeftError, lRightError, lTmp);
  627. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  628. continue;
  629. }
  630. // Advance the right wall:
  631. xRight += ptd->aed[RIGHT].dx;
  632. lRightError += ptd->aed[RIGHT].lErrorUp;
  633. if (lRightError >= 0)
  634. {
  635. lRightError -= ptd->aed[RIGHT].dN;
  636. xRight++;
  637. }
  638. // Advance the left wall:
  639. xLeft += ptd->aed[LEFT].dx;
  640. lLeftError += ptd->aed[LEFT].lErrorUp;
  641. if (lLeftError >= 0)
  642. {
  643. lLeftError -= ptd->aed[LEFT].dN;
  644. xLeft++;
  645. }
  646. cyTrapezoid--;
  647. if (cyTrapezoid == 0)
  648. break;
  649. yTrapezoid += 1 ;
  650. }
  651. ptd->aed[LEFT].lError = lLeftError;
  652. ptd->aed[LEFT].x = xLeft - xOffset;
  653. ptd->aed[RIGHT].lError = lRightError;
  654. ptd->aed[RIGHT].x = xRight - xOffset;
  655. }
  656. }
  657. /******************************Public*Routine******************************\
  658. * VOID vMmTrapezoidSetup80
  659. *
  660. * Initialize the hardware and some state for doing trapezoids. This is for
  661. * CL-GD5480 with enhanced BitBLT features.
  662. *
  663. \**************************************************************************/
  664. VOID vMmTrapezoidSetup80(
  665. PDEV* ppdev,
  666. ULONG rop4,
  667. ULONG ulSolidColor,
  668. RBRUSH* prb,
  669. POINTL* pptlBrush,
  670. TRAPEZOIDDATA* ptd,
  671. RECTL* prclClip) // NULL if no clipping
  672. {
  673. BYTE* pjBase = ppdev->pjBase ;
  674. LONG cBpp = ppdev->cBpp ;
  675. LONG lDelta = ppdev->lDelta ;
  676. ULONG jHwRop ;
  677. DWORD jExtMode = 0 ;
  678. DISPDBG((2, "vMmTrapezoidSetup80")) ;
  679. ptd->ppdev = ppdev ;
  680. jHwRop = gajHwPackedMixFromRop2[(rop4 >> 2) & 0xf] ;
  681. /////////////////////////////////////////////////////////////////
  682. // Setup the hardware for solid colours
  683. ptd->pfnTrap = vMmSolidTrapezoid80 ;
  684. // We initialize the hardware for the color, rop, start address,
  685. // and blt mode
  686. if (cBpp == 1)
  687. {
  688. ulSolidColor |= ulSolidColor << 8 ;
  689. ulSolidColor |= ulSolidColor << 16 ;
  690. }
  691. else if (cBpp == 2)
  692. {
  693. ulSolidColor |= ulSolidColor << 16 ;
  694. }
  695. CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase) ;
  696. CP_MM_SRC_ADDR(ppdev, pjBase, ppdev->ulSolidColorOffset) ;
  697. CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta);
  698. jExtMode = ( ENABLE_XY_POSITION_PACKED |
  699. ENABLE_COLOR_EXPAND |
  700. ENABLE_8x8_PATTERN_COPY |
  701. ppdev->jModeColor ) ;
  702. CP_MM_BLT_MODE_PACKED(ppdev, pjBase, jExtMode | jHwRop) ;
  703. CP_MM_FG_COLOR(ppdev, pjBase, ulSolidColor) ;
  704. if (prclClip != NULL)
  705. {
  706. ptd->pfnTrapClip = ptd->pfnTrap ;
  707. ptd->pfnTrap = vClipTrapezoid ;
  708. ptd->yClipTop = prclClip->top ;
  709. ptd->yClipBottom = prclClip->bottom ;
  710. ptd->xClipLeft = prclClip->left ;
  711. ptd->xClipRight = prclClip->right ;
  712. ptd->bClip = TRUE;
  713. }
  714. else
  715. {
  716. ptd->bClip = FALSE;
  717. }
  718. }
  719. /******************************Public*Routine******************************\
  720. * BOOL bFastFill
  721. *
  722. * Draws a non-complex, unclipped polygon. 'Non-complex' is defined as
  723. * having only two edges that are monotonic increasing in 'y'. That is,
  724. * the polygon cannot have more than one disconnected segment on any given
  725. * scan. Note that the edges of the polygon can self-intersect, so hourglass
  726. * shapes are permissible. This restriction permits this routine to run two
  727. * simultaneous DDAs, and no sorting of the edges is required.
  728. *
  729. * Note that NT's fill convention is different from that of Win 3.1 or Win95.
  730. * With the additional complication of fractional end-points, our convention
  731. * is the same as in 'X-Windows'. But a DDA is a DDA is a DDA, so once you
  732. * figure out how we compute the DDA terms for NT, you're golden.
  733. *
  734. * This routine handles patterns only when the S3 hardware patterns can be
  735. * used. The reason for this is that once the S3 pattern initialization is
  736. * done, pattern fills appear to the programmer exactly the same as solid
  737. * fills (with the slight difference that different registers and commands
  738. * are used). Handling 'vIoFillPatSlow' style patterns in this routine
  739. * would be non-trivial...
  740. *
  741. * We take advantage of the fact that the S3 automatically advances the
  742. * current 'y' to the following scan whenever a rectangle is output so that
  743. * we have to write to the accelerator three times for every scan: one for
  744. * the new 'x', one for the new 'width', and one for the drawing command.
  745. *
  746. * Returns TRUE if the polygon was drawn; FALSE if the polygon was complex.
  747. *
  748. \**************************************************************************/
  749. BOOL bFastFill(
  750. PDEV* ppdev,
  751. LONG cEdges, // Includes close figure edge
  752. POINTFIX* pptfxFirst,
  753. ULONG rop4,
  754. ULONG iSolidColor,
  755. RBRUSH* prb,
  756. POINTL* pptlBrush,
  757. RECTL* prclClip) // NULL if no clipping
  758. {
  759. LONG yTrapezoid; // Top scan for next trapezoid
  760. LONG cyTrapezoid; // Number of scans in current trapezoid
  761. LONG yStart; // y-position of start point in current edge
  762. LONG dM; // Edge delta in FIX units in x direction
  763. LONG dN; // Edge delta in FIX units in y direction
  764. LONG i;
  765. POINTFIX* pptfxLast; // Points to the last point in the polygon array
  766. POINTFIX* pptfxTop; // Points to the top-most point in the polygon
  767. POINTFIX* pptfxOld; // Start point in current edge
  768. POINTFIX* pptfxScan; // Current edge pointer for finding pptfxTop
  769. LONG cScanEdges; // Number of edges scanned to find pptfxTop
  770. // (doesn't include the closefigure edge)
  771. LONG iEdge;
  772. LONG lQuotient;
  773. LONG lRemainder;
  774. TRAPEZOIDDATA td; // Edge data and stuff
  775. EDGEDATA* ped; // Points to current edge being processed
  776. /////////////////////////////////////////////////////////////////
  777. // See if the polygon is convex
  778. pptfxScan = pptfxFirst;
  779. pptfxTop = pptfxFirst; // Assume for now that the first
  780. // point in path is the topmost
  781. pptfxLast = pptfxFirst + cEdges - 1;
  782. if (cEdges <= 2)
  783. goto ReturnTrue;
  784. // 'pptfxScan' will always point to the first point in the current
  785. // edge, and 'cScanEdges' will the number of edges remaining, including
  786. // the current one:
  787. cScanEdges = cEdges - 1; // The number of edges, not counting close figure
  788. if ((pptfxScan + 1)->y > pptfxScan->y)
  789. {
  790. // Collect all downs:
  791. do {
  792. if (--cScanEdges == 0)
  793. goto SetUpForFilling;
  794. pptfxScan++;
  795. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  796. // Collect all ups:
  797. do {
  798. if (--cScanEdges == 0)
  799. goto SetUpForFillingCheck;
  800. pptfxScan++;
  801. } while ((pptfxScan + 1)->y <= pptfxScan->y);
  802. // Collect all downs:
  803. pptfxTop = pptfxScan;
  804. do {
  805. if ((pptfxScan + 1)->y > pptfxFirst->y)
  806. break;
  807. if (--cScanEdges == 0)
  808. goto SetUpForFilling;
  809. pptfxScan++;
  810. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  811. goto ReturnFalse;
  812. }
  813. else
  814. {
  815. // Collect all ups:
  816. do {
  817. pptfxTop++; // We increment this now because we
  818. // want it to point to the very last
  819. // point if we early out in the next
  820. // statement...
  821. if (--cScanEdges == 0)
  822. goto SetUpForFilling;
  823. } while ((pptfxTop + 1)->y <= pptfxTop->y);
  824. // Collect all downs:
  825. pptfxScan = pptfxTop;
  826. do {
  827. if (--cScanEdges == 0)
  828. goto SetUpForFilling;
  829. pptfxScan++;
  830. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  831. // Collect all ups:
  832. do {
  833. if ((pptfxScan + 1)->y < pptfxFirst->y)
  834. break;
  835. if (--cScanEdges == 0)
  836. goto SetUpForFilling;
  837. pptfxScan++;
  838. } while ((pptfxScan + 1)->y <= pptfxScan->y);
  839. goto ReturnFalse;
  840. }
  841. SetUpForFillingCheck:
  842. // We check to see if the end of the current edge is higher
  843. // than the top edge we've found so far:
  844. if ((pptfxScan + 1)->y < pptfxTop->y)
  845. pptfxTop = pptfxScan + 1;
  846. SetUpForFilling:
  847. /////////////////////////////////////////////////////////////////
  848. // Some Initialization
  849. td.aed[LEFT].pptfx = pptfxTop;
  850. td.aed[RIGHT].pptfx = pptfxTop;
  851. yTrapezoid = (pptfxTop->y + 15) >> 4;
  852. // Make sure we initialize the DDAs appropriately:
  853. td.aed[LEFT].cy = 0;
  854. td.aed[RIGHT].cy = 0;
  855. // Guess as to the ordering of the points:
  856. td.aed[LEFT].dptfx = sizeof(POINTFIX);
  857. td.aed[RIGHT].dptfx = -(LONG) sizeof(POINTFIX);
  858. if (ppdev->flCaps & CAPS_MM_IO)
  859. {
  860. // chu01
  861. if ((ppdev->flCaps & CAPS_COMMAND_LIST) && (ppdev->pCommandList != NULL))
  862. {
  863. vMmTrapezoidSetup80(ppdev, rop4, iSolidColor, prb, pptlBrush, &td,
  864. prclClip) ;
  865. }
  866. else
  867. vMmTrapezoidSetup(ppdev, rop4, iSolidColor, prb, pptlBrush, &td,
  868. prclClip) ;
  869. }
  870. else
  871. {
  872. vIoTrapezoidSetup(ppdev, rop4, iSolidColor, prb, pptlBrush, &td,
  873. prclClip);
  874. }
  875. NewTrapezoid:
  876. /////////////////////////////////////////////////////////////////
  877. // DDA initialization
  878. for (iEdge = 1; iEdge >= 0; iEdge--)
  879. {
  880. ped = &td.aed[iEdge];
  881. ped->bNew = FALSE;
  882. if (ped->cy == 0)
  883. {
  884. // Our trapezoid drawing routine may want to be notified when
  885. // it will have to reset its DDA to start a new edge:
  886. ped->bNew = TRUE;
  887. // Need a new DDA:
  888. do {
  889. cEdges--;
  890. if (cEdges < 0)
  891. goto ReturnTrue;
  892. // Find the next left edge, accounting for wrapping:
  893. pptfxOld = ped->pptfx;
  894. ped->pptfx = (POINTFIX*) ((BYTE*) ped->pptfx + ped->dptfx);
  895. if (ped->pptfx < pptfxFirst)
  896. ped->pptfx = pptfxLast;
  897. else if (ped->pptfx > pptfxLast)
  898. ped->pptfx = pptfxFirst;
  899. // Have to find the edge that spans yTrapezoid:
  900. ped->cy = ((ped->pptfx->y + 15) >> 4) - yTrapezoid;
  901. // With fractional coordinate end points, we may get edges
  902. // that don't cross any scans, in which case we try the
  903. // next one:
  904. } while (ped->cy <= 0);
  905. // 'pptfx' now points to the end point of the edge spanning
  906. // the scan 'yTrapezoid'.
  907. dN = ped->pptfx->y - pptfxOld->y;
  908. dM = ped->pptfx->x - pptfxOld->x;
  909. ASSERTDD(dN > 0, "Should be going down only");
  910. // Compute the DDA increment terms:
  911. ped->dM = dM; // Not used for software trapezoid
  912. if (dM < 0)
  913. {
  914. dM = -dM;
  915. if (dM < dN) // Can't be '<='
  916. {
  917. ped->dx = -1;
  918. ped->lErrorUp = dN - dM;
  919. }
  920. else
  921. {
  922. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  923. ped->dx = -lQuotient; // - dM / dN
  924. ped->lErrorUp = lRemainder; // dM % dN
  925. if (ped->lErrorUp > 0)
  926. {
  927. ped->dx--;
  928. ped->lErrorUp = dN - ped->lErrorUp;
  929. }
  930. }
  931. }
  932. else
  933. {
  934. if (dM < dN) // Can't be '<='
  935. {
  936. ped->dx = 0;
  937. ped->lErrorUp = dM;
  938. }
  939. else
  940. {
  941. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  942. ped->dx = lQuotient; // dM / dN
  943. ped->lErrorUp = lRemainder; // dM % dN
  944. }
  945. }
  946. ped->dN = dN; // DDA limit
  947. ped->lError = -1; // Error is initially zero (add dN - 1 for
  948. // the ceiling, but subtract off dN so that
  949. // we can check the sign instead of comparing
  950. // to dN)
  951. ped->x = pptfxOld->x;
  952. yStart = pptfxOld->y;
  953. if ((yStart & 15) != 0)
  954. {
  955. // Advance to the next integer y coordinate
  956. for (i = 16 - (yStart & 15); i != 0; i--)
  957. {
  958. ped->x += ped->dx;
  959. ped->lError += ped->lErrorUp;
  960. if (ped->lError >= 0)
  961. {
  962. ped->lError -= ped->dN;
  963. ped->x++;
  964. }
  965. }
  966. }
  967. if ((ped->x & 15) != 0)
  968. {
  969. ped->lError -= ped->dN * (16 - (ped->x & 15));
  970. ped->x += 15; // We'll want the ceiling in just a bit...
  971. }
  972. // Chop off those fractional bits:
  973. ped->x >>= 4;
  974. ped->lError >>= 4;
  975. }
  976. }
  977. cyTrapezoid = min(td.aed[LEFT].cy, td.aed[RIGHT].cy); // # of scans in this trap
  978. td.aed[LEFT].cy -= cyTrapezoid;
  979. td.aed[RIGHT].cy -= cyTrapezoid;
  980. td.pfnTrap(&td, yTrapezoid, cyTrapezoid);
  981. yTrapezoid += cyTrapezoid;
  982. goto NewTrapezoid;
  983. ReturnTrue:
  984. return(TRUE);
  985. ReturnFalse:
  986. return(FALSE);
  987. }