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.

1934 lines
65 KiB

  1. /******************************Module*Header**********************************\
  2. *
  3. * *******************
  4. * * GDI SAMPLE CODE *
  5. * *******************
  6. *
  7. * Module Name: fastfill.c
  8. *
  9. * Draws fast solid-coloured, unclipped, non-complex rectangles.
  10. *
  11. * Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
  12. * Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
  13. \*****************************************************************************/
  14. #include "precomp.h"
  15. #include "gdi.h"
  16. //-----------------------------------------------------------------------------
  17. //
  18. // BOOL bFillPolygon()
  19. //
  20. // Draws a non-complex, unclipped polygon. 'Non-complex' is defined as
  21. // having only two edges that are monotonic increasing in 'y'. That is,
  22. // the polygon cannot have more than one disconnected segment on any given
  23. // scan. Note that the edges of the polygon can self-intersect, so hourglass
  24. // shapes are permissible. This restriction permits this routine to run two
  25. // simultaneous DDAs(Digital Differential Analyzer), and no sorting of the
  26. // edges is required.
  27. //
  28. // Note that NT's fill convention is different from that of Win 3.1 or 4.0.
  29. // With the additional complication of fractional end-points, our convention
  30. // is the same as in 'X-Windows'.
  31. //
  32. // This routine handles patterns only when the Permedia2 area stipple can be
  33. // used. The reason for this is that once the stipple initialization is
  34. // done, pattern fills appear to the programmer exactly the same as solid
  35. // fills (with the slight difference of an extra bit in the render command).
  36. //
  37. // We break each polygon down to a sequenze of screen aligned trapeziods, which
  38. // the Permedia2 can handle.
  39. //
  40. // Optimisation list follows ....
  41. //
  42. // This routine is in no way the ultimate convex polygon drawing routine
  43. // Some obvious things that would make it faster:
  44. //
  45. // 1) Write it in Assembler
  46. //
  47. // 2) Make the non-complex polygon detection faster. If I could have
  48. // modified memory before the start of after the end of the buffer,
  49. // I could have simplified the detection code. But since I expect
  50. // this buffer to come from GDI, I can't do that. Another thing
  51. // would be to have GDI give a flag on calls that are guaranteed
  52. // to be convex, such as 'Ellipses' and 'RoundRects'. Note that
  53. // the buffer would still have to be scanned to find the top-most
  54. // point.
  55. //
  56. // 3) Implement support for a single sub-path that spans multiple
  57. // path data records, so that we don't have to copy all the points
  58. // to a single buffer like we do in 'fillpath.c'.
  59. //
  60. // 4) Use 'ebp' and/or 'esp' as a general register in the inner loops
  61. // of the Asm loops, and also Pentium-optimize the code. It's safe
  62. // to use 'esp' on NT because it's guaranteed that no interrupts
  63. // will be taken in our thread context, and nobody else looks at the
  64. // stack pointer from our context.
  65. //
  66. // 5) When we get to a part of the polygon where both vertices are of
  67. // equal height, the algorithm essentially starts the polygon again.
  68. // Using the Permedia2 Continue message could speed things up in certain
  69. // cases.
  70. //
  71. // Returns TRUE if the polygon was drawn; FALSE if the polygon was complex.
  72. //
  73. // Note: the point data (POINTFX) GDI passed to us in 28.4 format. Permedia 2
  74. // hardware uses 12.15 format. So most of the time, we need to do a
  75. // x = (x + 15) >> 4 to bring it back to normal interger format and then
  76. // convert it to 12.15 format when we set the register value
  77. //
  78. // Parameters:
  79. // ppdev-------Pointer to PDev
  80. // pSurfDst----Destination surface
  81. // lEdges------Number of edges, includes close figure edge
  82. // pptfxFirst--Pointer to the first point in the data buffer. There are total
  83. // "lEdges" points
  84. // iSolidColor-Solid color fill
  85. // ulRop4------ROP4
  86. // pco---------Clip Object.
  87. // prb---------Realized brush
  88. // pptlBrush---Pattern alignment
  89. //
  90. //-----------------------------------------------------------------------------
  91. BOOL
  92. bFillPolygon(PDev* ppdev,
  93. Surf* pSurfDst,
  94. LONG lEdges,
  95. POINTFIX* pptfxFirst,
  96. ULONG ulSolidColor,
  97. ULONG ulRop4,
  98. CLIPOBJ* pco,
  99. RBrush* prb,
  100. POINTL* pptlBrush)
  101. {
  102. POINTFIX* pptfxLast; // Points to the last point in the polygon
  103. // array
  104. POINTFIX* pptfxTop; // Points to the top-most point in the polygon
  105. POINTFIX* pptfxScan; // Current edge pointer for finding pptfxTop
  106. POINTFIX* aPtrFixTop[2]; // DDA terms and stuff
  107. POINTFIX* aPtrFixNext[2]; // DDA terms and stuff
  108. BOOL bRC = FALSE; // Return code for this function
  109. BOOL bSingleColor; // Only one color pass
  110. BOOL bTrivialClip; // Trivial Clip or not
  111. ClipEnum* pClipRegion = (ClipEnum*)(ppdev->pvTmpBuffer);
  112. // Buffer for storing clipping region
  113. DWORD dwAsMode[2]; // The area stipple mode and the color for that
  114. // pass
  115. DWORD dwColorMode; // Current color mode
  116. DWORD dwColorReg; // Current color register mode
  117. DWORD dwLogicMode; // Current logic op mode
  118. DWORD dwReadMode; // Current register read mode
  119. DWORD dwRenderBits; // Current render bits
  120. LONG lCount; // Number of scan lines to render
  121. LONG alDX[2]; //
  122. LONG alDY[2];
  123. LONG lNumOfPass; // Number of passes required to render
  124. LONG lScanEdges; // Number of edges scanned to find pptfxTop
  125. // (doesn't include the closefigure edge)
  126. LONG alDxDy[2];
  127. RECTL* pClipList; // List of clip rects
  128. ULONG ulBgColor; // Background color
  129. ULONG ulBgLogicOp = ulRop3ToLogicop(ulRop4 >> 8);
  130. ULONG ulBrushColor = ulSolidColor;
  131. // Current fill color
  132. ULONG ulColor[2]; // On multiple color passes we need to know how
  133. // to set up
  134. ULONG ulFgColor; // Foreground color
  135. ULONG ulFgLogicOp = ulRop3ToLogicop(ulRop4 & 0xFF);
  136. ULONG ulOrX; // We do logic OR for all values to eliminate
  137. ULONG ulOrY; // complex polygons
  138. GFNPB pb; // Functional block for lower level function
  139. ULONG* pBuffer;
  140. PERMEDIA_DECL;
  141. pb.ppdev = ppdev;
  142. DBG_GDI((6, "bFillPolygon called, rop4 = %x, fg ulFgLogicOp =%d, bg = %d",
  143. ulRop4, ulFgLogicOp, ulBgLogicOp));
  144. ASSERTDD(lEdges > 1, "Polygon with less than 2 edges");
  145. //
  146. // See if the polygon is 'non-complex'
  147. // Assume for now that the first point in path is the top-most
  148. //
  149. pptfxScan = pptfxFirst;
  150. pptfxTop = pptfxFirst;
  151. pptfxLast = pptfxFirst + lEdges - 1;
  152. //
  153. // Initialize our logic OR op counters
  154. //
  155. ulOrX = pptfxScan->x;
  156. ulOrY = pptfxScan->y;
  157. //
  158. // 'pptfxScan' will always point to the first point in the current
  159. // edge, and 'lScanEdges' will be the number of edges remaining, including
  160. // the current one, but not counting close figure
  161. //
  162. lScanEdges = lEdges - 1;
  163. //
  164. // First phase: Velidate input point data to see if we can handle it or not
  165. //
  166. // Check if the 2nd edge point is lower than current edge point
  167. //
  168. // Note: the (0,0) is at the up-left corner in this coordinate system
  169. // So the bigger the Y value, the lower the point
  170. //
  171. if ( (pptfxScan + 1)->y > pptfxScan->y )
  172. {
  173. //
  174. // The edge goes down, that is, the 2nd point is lower than the 1st
  175. // point. Collect all downs: that is, collect all the X and Y until
  176. // the edge goes up
  177. //
  178. do
  179. {
  180. ulOrY |= (++pptfxScan)->y;
  181. ulOrX |= pptfxScan->x;
  182. //
  183. // If no more edge left, we are done
  184. //
  185. if ( --lScanEdges == 0 )
  186. {
  187. goto SetUpForFilling;
  188. }
  189. } while ( (pptfxScan + 1)->y >= pptfxScan->y );
  190. //
  191. // From this point, the edge goes up, that is, the next point is higher
  192. // than current point
  193. // Collect all ups: Collect all the X and Y until the edge goes down
  194. //
  195. do
  196. {
  197. ulOrY |= (++pptfxScan)->y;
  198. ulOrX |= pptfxScan->x;
  199. //
  200. // If no more edge left, we are done
  201. //
  202. if ( --lScanEdges == 0 )
  203. {
  204. goto SetUpForFillingCheck;
  205. }
  206. } while ( (pptfxScan + 1)->y <= pptfxScan->y );
  207. //
  208. // Reset pptfxTop to the current point which is at top again compare
  209. // with the next point
  210. // Collect all downs:
  211. //
  212. pptfxTop = pptfxScan;
  213. do
  214. {
  215. //
  216. // If the next edge point is lower than the 1st point, stop
  217. //
  218. if ( (pptfxScan + 1)->y > pptfxFirst->y )
  219. {
  220. break;
  221. }
  222. ulOrY |= (++pptfxScan)->y;
  223. ulOrX |= pptfxScan->x;
  224. //
  225. // If no more edge left, we are done
  226. //
  227. if ( --lScanEdges == 0 )
  228. {
  229. goto SetUpForFilling;
  230. }
  231. } while ( (pptfxScan + 1)->y >= pptfxScan->y );
  232. //
  233. // If we fallen here, it means we are given down-up-down polygon.
  234. // We can't handle it and return FALSE to let GDI do it.
  235. //
  236. DBG_GDI((7, "Reject: can't fill down-up-down polygon"));
  237. goto ReturnBack;
  238. }// if ( (pptfxScan + 1)->y>pptfxScan->y ), 2nd point is lower than 1st one
  239. else
  240. {
  241. //
  242. // The edge goes up, that is, the 2nd point is higher than the 1st
  243. // point. Collect all ups: that is, collect all the X and Y until
  244. // the edge goes down.
  245. // Note: we keeps changing the value of "pptfxTop" so that after
  246. // this "while" loop, "pptfxTop" points to the TOPEST point
  247. //
  248. do
  249. {
  250. ulOrY |= (++pptfxTop)->y; // We increment this now because we
  251. ulOrX |= pptfxTop->x; // want it to point to the very last
  252. //
  253. // If no more edge left, we are done
  254. //
  255. if ( --lScanEdges == 0 )
  256. {
  257. goto SetUpForFilling;
  258. }
  259. } while ( (pptfxTop + 1)->y <= pptfxTop->y );
  260. //
  261. // Form this point, the edge goes down, that is, the next point is
  262. // lower than current point. Collect all downs: that is, collect all
  263. // the X and Y until the edge goes up
  264. // Note: here we keep changing "pptfxScan" so that after this loop,
  265. // "pptfxScan" points to the current scan line, which also is the
  266. // lowest point
  267. //
  268. pptfxScan = pptfxTop;
  269. do
  270. {
  271. ulOrY |= (++pptfxScan)->y;
  272. ulOrX |= pptfxScan->x;
  273. //
  274. // If no more edge left, we are done
  275. //
  276. if ( --lScanEdges == 0 )
  277. {
  278. goto SetUpForFilling;
  279. }
  280. } while ( (pptfxScan + 1)->y >= pptfxScan->y );
  281. //
  282. // Up to this point, the edge is about to go up again.
  283. // Collect all ups:
  284. //
  285. do
  286. {
  287. //
  288. // If the edge going down again, just qute because we can't
  289. // fill up-down-up polygon
  290. //
  291. if ( (pptfxScan + 1)->y < pptfxFirst->y )
  292. {
  293. break;
  294. }
  295. ulOrY |= (++pptfxScan)->y;
  296. ulOrX |= pptfxScan->x;
  297. //
  298. // If no more edge left, we are done
  299. //
  300. if ( --lScanEdges == 0 )
  301. {
  302. goto SetUpForFilling;
  303. }
  304. } while ( (pptfxScan + 1)->y <= pptfxScan->y );
  305. //
  306. // If we fallen here, it means we are given up-down-up polygon.
  307. // We can't handle it and return FALSE to let GDI do it.
  308. //
  309. DBG_GDI((7, "Reject: Can't fill up-down-up polygon"));
  310. goto ReturnBack;
  311. }// if (pptfxScan + 1)->y<=pptfxScan->y), 2nd point is higher than 1st one
  312. //
  313. // Phase 2: Now we have validated the input point and think we can fill it
  314. //
  315. SetUpForFillingCheck:
  316. //
  317. // We check to see if the end of the current edge is higher than the top
  318. // edge we've found so far. If yes, then let pptfxTop point to the end of
  319. // current edge which is the highest.
  320. //
  321. //
  322. if ( pptfxScan->y < pptfxTop->y )
  323. {
  324. pptfxTop = pptfxScan;
  325. }
  326. SetUpForFilling:
  327. //
  328. // Can only use block fills for trivial clip so work it out here
  329. //
  330. bTrivialClip = (pco == NULL) || (pco->iDComplexity == DC_TRIVIAL);
  331. if ( (ulOrY & 0xffffc00f) || (ulOrX & 0xffff8000) )
  332. {
  333. ULONG ulNeg;
  334. ULONG ulPosX;
  335. ULONG ulPosY;
  336. //
  337. // Fractional Y must be done as spans
  338. //
  339. if ( ulOrY & 0xf )
  340. {
  341. bRC = bFillSpans(ppdev, pSurfDst, lEdges, pptfxFirst,
  342. pptfxTop, pptfxLast,
  343. ulSolidColor, ulRop4, pco, prb, pptlBrush);
  344. goto ReturnBack;
  345. }
  346. //
  347. // Run through all the vertices and check that none of them
  348. // have a negative component less than -256.
  349. //
  350. ulNeg = 0;
  351. ulPosX = 0;
  352. ulPosY = 0;
  353. for ( pptfxScan = pptfxFirst; pptfxScan <= pptfxLast; ++pptfxScan )
  354. {
  355. if ( pptfxScan->x < 0 )
  356. {
  357. ulNeg |= -pptfxScan->x;
  358. }
  359. else
  360. {
  361. ulPosX |= pptfxScan->x;
  362. }
  363. if ( pptfxScan->y < 0 )
  364. {
  365. ulNeg |= -pptfxScan->y;
  366. }
  367. else
  368. {
  369. ulPosY |= pptfxScan->y;
  370. }
  371. }
  372. //
  373. // We don't want to handle any polygon with a negative vertex
  374. // at <= -256 in either coordinate.
  375. //
  376. if ( ulNeg & 0xfffff000 )
  377. {
  378. DBG_GDI((1, "Coords out of range for fast fill"));
  379. goto ReturnBack;
  380. }
  381. if ( (ulPosX > 2047) || (ulPosY > 1023) )
  382. {
  383. DBG_GDI((1, "Coords out of range for Permedia2 fast fill"));
  384. goto ReturnBack;
  385. }
  386. }// if ( (ulOrY & 0xffffc00f) || (ulOrX & 0xffff8000) )
  387. //
  388. // Now we are ready to fill
  389. //
  390. InputBufferReserve(ppdev, 2, &pBuffer);
  391. pBuffer[0] = __Permedia2TagFBWindowBase;
  392. pBuffer[1] = pSurfDst->ulPixOffset;
  393. pBuffer += 2;
  394. InputBufferCommit(ppdev, pBuffer);
  395. DBG_GDI((7, "bFillPolygon: Polygon is renderable. Go ahead and render"));
  396. if ( ulFgLogicOp == K_LOGICOP_COPY )
  397. {
  398. dwColorMode = __PERMEDIA_DISABLE;
  399. dwLogicMode = __PERMEDIA_CONSTANT_FB_WRITE;
  400. dwReadMode = PM_FBREADMODE_PARTIAL(pSurfDst->ulPackedPP)
  401. | PM_FBREADMODE_PACKEDDATA(__PERMEDIA_DISABLE);
  402. //
  403. // Check to see if it is a non-solid fill brush fill
  404. //
  405. if ( (ulBrushColor == 0xffffffff)
  406. ||(!bTrivialClip) )
  407. {
  408. //
  409. // Non-solid brush, not too much we can do
  410. //
  411. dwRenderBits = __RENDER_TRAPEZOID_PRIMITIVE;
  412. dwColorReg = __Permedia2TagFBWriteData;
  413. }// Non-solid brush
  414. else
  415. {
  416. //
  417. // For solid brush, We can use fast fills, so load the fb block
  418. // color register.
  419. //
  420. dwColorReg = __Permedia2TagFBBlockColor;
  421. dwRenderBits = __RENDER_FAST_FILL_ENABLE
  422. | __RENDER_TRAPEZOID_PRIMITIVE;
  423. //
  424. // Setup color data based on current color mode we are in
  425. //
  426. if ( ppdev->cPelSize == 1 )
  427. {
  428. //
  429. // We are in 16 bit packed mode. So the color data must be
  430. // repeated in both halves of the FBBlockColor register
  431. //
  432. ASSERTDD((ulSolidColor & 0xFFFF0000) == 0,
  433. "bFillPolygon: upper bits are not zero");
  434. ulSolidColor |= (ulSolidColor << 16);
  435. }
  436. else if ( ppdev->cPelSize == 0 )
  437. {
  438. //
  439. // We are in 8 bit packed mode. So the color data must be
  440. // repeated in all 4 bytes of the FBBlockColor register
  441. //
  442. ASSERTDD((ulSolidColor & 0xFFFFFF00) == 0,
  443. "bFillPolygon: upper bits are not zero");
  444. ulSolidColor |= ulSolidColor << 8;
  445. ulSolidColor |= ulSolidColor << 16;
  446. }
  447. //
  448. // Ensure that the last access was a write before loading
  449. // BlockColor
  450. //
  451. InputBufferReserve(ppdev, 2, &pBuffer);
  452. pBuffer[0] = __Permedia2TagFBBlockColor;
  453. pBuffer[1] = ulSolidColor;
  454. pBuffer += 2;
  455. InputBufferCommit(ppdev, pBuffer);
  456. }// Solid brush case
  457. }// LOGICOP_COPY
  458. else
  459. {
  460. dwColorReg = __Permedia2TagConstantColor;
  461. dwColorMode = __COLOR_DDA_FLAT_SHADE;
  462. dwLogicMode = P2_ENABLED_LOGICALOP(ulFgLogicOp);
  463. dwReadMode = PM_FBREADMODE_PARTIAL(pSurfDst->ulPackedPP)
  464. | LogicopReadDest[ulFgLogicOp];
  465. dwRenderBits = __RENDER_TRAPEZOID_PRIMITIVE;
  466. }// Non-COPY LogicOP
  467. //
  468. // Determine how many passes we need to draw all the clip rects
  469. //
  470. if ( bTrivialClip )
  471. {
  472. //
  473. // Just draw, no clipping to perform.
  474. //
  475. pClipList = NULL; // Indicate no clip list
  476. lNumOfPass = 1;
  477. }
  478. else
  479. {
  480. if ( pco->iDComplexity == DC_RECT )
  481. {
  482. //
  483. // For DC_RECT, we can do it in one pass
  484. //
  485. lNumOfPass = 1;
  486. pClipList = &pco->rclBounds;
  487. }
  488. else
  489. {
  490. //
  491. // It may be slow to render the entire polygon for each clip rect,
  492. // especially if the object is very complex. An arbitary limit of
  493. // up to CLIP_LIMIT regions will be rendered by this function.
  494. // Return false if more than CLIP_LIMIT regions.
  495. //
  496. lNumOfPass = CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY,
  497. CLIP_LIMIT);
  498. if ( lNumOfPass == -1 )
  499. {
  500. goto ReturnBack; // More than CLIP_LIMIT.
  501. }
  502. //
  503. // Put the regions into our clip buffer
  504. //
  505. if ( (CLIPOBJ_bEnum(pco, sizeof(ClipEnum), (ULONG*)pClipRegion))
  506. ||(pClipRegion->c != lNumOfPass) )
  507. {
  508. DBG_GDI((7, "CLIPOBJ_bEnum inconsistency. %d = %d",
  509. pClipRegion->c, lNumOfPass));
  510. }
  511. pClipList = &(pClipRegion->arcl[0]);
  512. }// Non-DC_RECT case
  513. //
  514. // For non-trivial clipping, we can use SCISSOR to implement it
  515. //
  516. InputBufferReserve(ppdev, 2, &pBuffer);
  517. pBuffer[0] = __Permedia2TagScissorMode;
  518. pBuffer[1] = SCREEN_SCISSOR_DEFAULT | USER_SCISSOR_ENABLE;
  519. pBuffer += 2;
  520. InputBufferCommit(ppdev, pBuffer);
  521. }// Non-trivial clipping
  522. bSingleColor = TRUE;
  523. if ( ulBrushColor != 0xFFFFFFFF )
  524. {
  525. //
  526. // Solid brush case, just set the color register as the color
  527. //
  528. InputBufferReserve(ppdev, 2, &pBuffer);
  529. pBuffer[0] = dwColorReg;
  530. pBuffer[1] = ulSolidColor;
  531. pBuffer += 2;
  532. InputBufferCommit(ppdev, pBuffer);
  533. }// Solid brush case
  534. else
  535. {
  536. //
  537. // For non-solid brush, we need to realize brush first
  538. //
  539. BrushEntry* pbe;
  540. //
  541. // Turn on the area stipple.
  542. //
  543. dwRenderBits |= __RENDER_AREA_STIPPLE_ENABLE;
  544. //
  545. // If anything has changed with the brush we must re-realize it. If the
  546. // brush has been kicked out of the area stipple unit we must fully
  547. // realize it. If only the alignment has changed we can simply update
  548. // the alignment for the stipple.
  549. //
  550. pbe = prb->pbe;
  551. pb.prbrush = prb;
  552. pb.pptlBrush = pptlBrush;
  553. if ( (pbe == NULL) || (pbe->prbVerify != prb) )
  554. {
  555. DBG_GDI((7, "full brush realize"));
  556. vPatRealize(&pb);
  557. }
  558. else if ( (prb->ptlBrushOrg.x != pptlBrush->x)
  559. ||(prb->ptlBrushOrg.y != pptlBrush->y) )
  560. {
  561. DBG_GDI((7, "changing brush offset"));
  562. vMonoOffset(&pb);
  563. }
  564. ulFgColor = prb->ulForeColor;
  565. ulBgColor = prb->ulBackColor;
  566. if ( (ulBgLogicOp == K_LOGICOP_NOOP)
  567. ||((ulFgLogicOp == K_LOGICOP_XOR) && (ulBgColor == 0)) )
  568. {
  569. //
  570. // Either we have a transparent bitmap or it can be assumed to be
  571. // transparent (XOR with bg=0)
  572. //
  573. InputBufferReserve(ppdev, 4, &pBuffer);
  574. pBuffer[0] = dwColorReg;
  575. pBuffer[1] = ulFgColor;
  576. pBuffer[2] = __Permedia2TagAreaStippleMode;
  577. pBuffer[3] = prb->areaStippleMode;
  578. pBuffer += 4;
  579. InputBufferCommit(ppdev, pBuffer);
  580. }// Transparent bitmap
  581. else if ( (ulFgLogicOp == K_LOGICOP_XOR) && (ulFgColor == 0) )
  582. {
  583. //
  584. // We have a transparent foreground! (XOR with fg=0)
  585. //
  586. InputBufferReserve(ppdev, 4, &pBuffer);
  587. pBuffer[0] = dwColorReg;
  588. pBuffer[1] = ulBgColor;
  589. pBuffer[2] = __Permedia2TagAreaStippleMode;
  590. pBuffer[3] = prb->areaStippleMode | AREA_STIPPLE_INVERT_PAT;
  591. pBuffer += 4;
  592. InputBufferCommit(ppdev, pBuffer);
  593. }// Transparent foreground
  594. else
  595. {
  596. //
  597. // Not using a transparent pattern
  598. //
  599. bSingleColor = FALSE;
  600. ulColor[0] = ulFgColor;
  601. ulColor[1] = ulBgColor;
  602. dwAsMode[0] = prb->areaStippleMode;
  603. dwAsMode[1] = dwAsMode[0] | AREA_STIPPLE_INVERT_PAT;
  604. //
  605. // Double the number of passes, one for fg one for bg
  606. //
  607. lNumOfPass <<= 1;
  608. }// No transparent
  609. }// if ( ulBrushColor == 0xFFFFFFFF ), non-solid brush
  610. InputBufferReserve(ppdev, 6, &pBuffer);
  611. pBuffer[0] = __Permedia2TagColorDDAMode;
  612. pBuffer[1] = dwColorMode;
  613. pBuffer[2] = __Permedia2TagFBReadMode;
  614. pBuffer[3] = dwReadMode;
  615. pBuffer[4] = __Permedia2TagLogicalOpMode;
  616. pBuffer[5] = dwLogicMode;
  617. pBuffer += 6;
  618. InputBufferCommit(ppdev, pBuffer);
  619. DBG_GDI((7, "Rendering Polygon in %d passes. with %s",
  620. lNumOfPass, bSingleColor ? "Single Color" : "Two Color"));
  621. lNumOfPass--;
  622. while ( 1 )
  623. {
  624. //
  625. // Per pass initialization
  626. //
  627. if ( bSingleColor )
  628. {
  629. //
  630. // Need to set up clip rect each pass
  631. //
  632. if ( pClipList )
  633. {
  634. InputBufferReserve(ppdev, 4, &pBuffer);
  635. pBuffer[0] = __Permedia2TagScissorMinXY;
  636. pBuffer[1] = ((pClipList->left)<< SCISSOR_XOFFSET)
  637. | ((pClipList->top)<< SCISSOR_YOFFSET);
  638. pBuffer[2] = __Permedia2TagScissorMaxXY;
  639. pBuffer[3] = ((pClipList->right)<< SCISSOR_XOFFSET)
  640. | ((pClipList->bottom)<< SCISSOR_YOFFSET);
  641. pBuffer += 4;
  642. InputBufferCommit(ppdev, pBuffer);
  643. pClipList++;
  644. }
  645. }// Single color
  646. else
  647. {
  648. //
  649. // Need to set up clip rect every other pass and change color and
  650. // inversion mode every pass
  651. //
  652. if ( (pClipList) && (lNumOfPass & 1) )
  653. {
  654. InputBufferReserve(ppdev, 4, &pBuffer);
  655. pBuffer[0] = __Permedia2TagScissorMinXY;
  656. pBuffer[1] = ((pClipList->left)<< SCISSOR_XOFFSET)
  657. | ((pClipList->top)<< SCISSOR_YOFFSET);
  658. pBuffer[2] = __Permedia2TagScissorMaxXY;
  659. pBuffer[3] = ((pClipList->right)<< SCISSOR_XOFFSET)
  660. | ((pClipList->bottom)<< SCISSOR_YOFFSET);
  661. pBuffer += 4;
  662. InputBufferCommit(ppdev, pBuffer);
  663. pClipList++;
  664. }
  665. InputBufferReserve(ppdev, 4, &pBuffer);
  666. pBuffer[0] = dwColorReg;
  667. pBuffer[1] = ulColor[lNumOfPass & 1];
  668. pBuffer[2] = __Permedia2TagAreaStippleMode;
  669. pBuffer[3] = dwAsMode[lNumOfPass & 1];
  670. pBuffer += 4;
  671. InputBufferCommit(ppdev, pBuffer);
  672. }// Non-single color mode
  673. //
  674. // Initialize left and right points (current) to top point.
  675. //
  676. aPtrFixNext[LEFT] = pptfxTop;
  677. aPtrFixNext[RIGHT] = pptfxTop;
  678. while ( 1 )
  679. {
  680. //
  681. // aPtrFixNext[] is always the valid point to draw from
  682. //
  683. do
  684. {
  685. aPtrFixTop[LEFT] = aPtrFixNext[LEFT];
  686. aPtrFixNext[LEFT] = aPtrFixTop[LEFT] - 1;
  687. if ( aPtrFixNext[LEFT] < pptfxFirst )
  688. {
  689. aPtrFixNext[LEFT] = pptfxLast;
  690. }
  691. //
  692. // Special case of flat based polygon, need to break now as
  693. // polygon is finished
  694. //
  695. if ( aPtrFixNext[LEFT] == aPtrFixNext[RIGHT] )
  696. {
  697. goto FinishedPolygon;
  698. }
  699. DBG_GDI((7, "LEFT: aPtrFixTop %x aPtrFixNext %x",
  700. aPtrFixTop[LEFT], aPtrFixNext[LEFT]));
  701. DBG_GDI((7, "FIRST %x LAST %x",
  702. pptfxFirst, pptfxLast));
  703. DBG_GDI((7, "X %x Y %x Next: X %x Y %x",
  704. aPtrFixTop[LEFT]->x, aPtrFixTop[LEFT]->y,
  705. aPtrFixNext[LEFT]->x, aPtrFixNext[LEFT]->y));
  706. } while ( aPtrFixTop[LEFT]->y == aPtrFixNext[LEFT]->y );
  707. do
  708. {
  709. aPtrFixTop[RIGHT] = aPtrFixNext[RIGHT];
  710. aPtrFixNext[RIGHT] = aPtrFixTop[RIGHT] + 1;
  711. if ( aPtrFixNext[RIGHT] > pptfxLast )
  712. {
  713. aPtrFixNext[RIGHT] = pptfxFirst;
  714. }
  715. DBG_GDI((7, "RIGHT: aPtrFixTop %x aPtrFixNext %x FIRST %x",
  716. aPtrFixTop[RIGHT], aPtrFixNext[RIGHT], pptfxFirst));
  717. DBG_GDI((7, " LAST %x X %x Y %x Next: X %x Y %x",
  718. pptfxLast, aPtrFixTop[RIGHT]->x, aPtrFixTop[RIGHT]->y,
  719. aPtrFixNext[RIGHT]->x, aPtrFixNext[RIGHT]->y));
  720. } while ( aPtrFixTop[RIGHT]->y == aPtrFixNext[RIGHT]->y );
  721. //
  722. // Start up new rectangle. Whenever we get to this code, both
  723. // points should have equal y values, and need to be restarted.
  724. // Note: To get correct results, we need to add on nearly one to
  725. // each X coordinate.
  726. //
  727. DBG_GDI((7, "New: Top: x: %x y: %x x: %x y: %x",
  728. aPtrFixTop[LEFT]->x, aPtrFixTop[LEFT]->y,
  729. aPtrFixTop[RIGHT]->x, aPtrFixTop[RIGHT]->y));
  730. DBG_GDI((7, " Next: x: %x y: %x x: %x y: %x",
  731. aPtrFixNext[LEFT]->x, aPtrFixNext[LEFT]->y,
  732. aPtrFixNext[RIGHT]->x, aPtrFixNext[RIGHT]->y));
  733. InputBufferReserve(ppdev, 6, &pBuffer);
  734. pBuffer[0] = __Permedia2TagStartXDom;
  735. pBuffer[1] = FIXtoFIXED(aPtrFixTop[LEFT]->x) + NEARLY_ONE;
  736. pBuffer[2] = __Permedia2TagStartXSub;
  737. pBuffer[3] = FIXtoFIXED(aPtrFixTop[RIGHT]->x)+ NEARLY_ONE;
  738. pBuffer[4] = __Permedia2TagStartY;
  739. pBuffer[5] = FIXtoFIXED(aPtrFixTop[RIGHT]->y);
  740. pBuffer += 6;
  741. InputBufferCommit(ppdev, pBuffer);
  742. //
  743. // We have 2 15.4 coordinates. We need to divide them and change
  744. // them into a 15.16 coordinate. We know the y coordinate is not
  745. // fractional, so we do not loose precision by shifting right by 4
  746. //
  747. alDX[LEFT] = (aPtrFixNext[LEFT]->x - aPtrFixTop[LEFT]->x) << 12;
  748. alDY[LEFT] = (aPtrFixNext[LEFT]->y - aPtrFixTop[LEFT]->y) >> 4;
  749. //
  750. // Need to ensure we round delta down. divide rounds towards zero
  751. //
  752. if ( alDX[LEFT] < 0 )
  753. {
  754. alDX[LEFT] -= alDY[LEFT] - 1;
  755. }
  756. alDxDy[LEFT] = alDX[LEFT] / alDY[LEFT];
  757. InputBufferReserve(ppdev, 8, &pBuffer);
  758. pBuffer[0] = __Permedia2TagdXDom;
  759. pBuffer[1] = alDxDy[LEFT];
  760. alDX[RIGHT] = (aPtrFixNext[RIGHT]->x - aPtrFixTop[RIGHT]->x) << 12;
  761. alDY[RIGHT] = (aPtrFixNext[RIGHT]->y - aPtrFixTop[RIGHT]->y) >> 4;
  762. //
  763. // Need to ensure we round delta down. divide rounds towards zero
  764. //
  765. if ( alDX[RIGHT] < 0 )
  766. {
  767. alDX[RIGHT] -= alDY[RIGHT] - 1;
  768. }
  769. alDxDy[RIGHT] = alDX[RIGHT] / alDY[RIGHT];
  770. pBuffer[2] = __Permedia2TagdXSub;
  771. pBuffer[3] = alDxDy[RIGHT];
  772. //
  773. // Work out number of scanlines to render
  774. //
  775. if ( aPtrFixNext[LEFT]->y < aPtrFixNext[RIGHT]->y )
  776. {
  777. lCount = alDY[LEFT];
  778. }
  779. else
  780. {
  781. lCount = alDY[RIGHT];
  782. }
  783. pBuffer[4] = __Permedia2TagCount;
  784. pBuffer[5] = lCount;
  785. pBuffer[6] = __Permedia2TagRender;
  786. pBuffer[7] = dwRenderBits;
  787. pBuffer += 8;
  788. InputBufferCommit(ppdev, pBuffer);
  789. //
  790. // With lots of luck, top trapezoid should be drawn now!
  791. // Repeatedly draw more trapezoids until points are equal
  792. // If y values are equal, then we can start again from
  793. // scratch.
  794. //
  795. while ( (aPtrFixNext[LEFT] != aPtrFixNext[RIGHT])
  796. &&(aPtrFixNext[LEFT]->y != aPtrFixNext[RIGHT]->y) )
  797. {
  798. //
  799. // Some continues are required for next rectangle
  800. //
  801. if ( aPtrFixNext[LEFT]->y < aPtrFixNext[RIGHT]->y )
  802. {
  803. //
  804. // We have reached aPtrFixNext[LEFT]. aPtrFixNext[RIGHT]
  805. // is still ok
  806. //
  807. do
  808. {
  809. aPtrFixTop[LEFT] = aPtrFixNext[LEFT];
  810. aPtrFixNext[LEFT] = aPtrFixTop[LEFT] - 1;
  811. if ( aPtrFixNext[LEFT] < pptfxFirst )
  812. {
  813. aPtrFixNext[LEFT] = pptfxLast;
  814. }
  815. } while ( aPtrFixTop[LEFT]->y == aPtrFixNext[LEFT]->y );
  816. //
  817. // We have a new aPtrFixNext[LEFT] now.
  818. //
  819. DBG_GDI((7, "Dom: Top: x: %x y: %x",
  820. aPtrFixTop[LEFT]->x, aPtrFixTop[LEFT]->y));
  821. DBG_GDI((7, "Next: x: %x y: %x x: %x y: %x",
  822. aPtrFixNext[LEFT]->x, aPtrFixNext[LEFT]->y,
  823. aPtrFixNext[RIGHT]->x, aPtrFixNext[RIGHT]->y));
  824. alDX[LEFT] = (aPtrFixNext[LEFT]->x
  825. - aPtrFixTop[LEFT]->x) << 12;
  826. alDY[LEFT] = (aPtrFixNext[LEFT]->y
  827. - aPtrFixTop[LEFT]->y) >> 4;
  828. //
  829. // Need to ensure we round delta down. Divide rounds
  830. // towards zero
  831. //
  832. if ( alDX[LEFT] < 0 )
  833. {
  834. alDX[LEFT] -= alDY[LEFT] - 1;
  835. }
  836. alDxDy[LEFT] = alDX[LEFT] / alDY[LEFT];
  837. if ( aPtrFixNext[LEFT]->y < aPtrFixNext[RIGHT]->y )
  838. {
  839. lCount = alDY[LEFT];
  840. }
  841. else
  842. {
  843. lCount = (abs(aPtrFixNext[RIGHT]->y
  844. - aPtrFixTop[LEFT]->y)) >> 4;
  845. }
  846. InputBufferReserve(ppdev, 6, &pBuffer);
  847. pBuffer[0] = __Permedia2TagStartXDom;
  848. pBuffer[1] = FIXtoFIXED(aPtrFixTop[LEFT]->x) + NEARLY_ONE;
  849. pBuffer[2] = __Permedia2TagdXDom;
  850. pBuffer[3] = alDxDy[LEFT];
  851. pBuffer[4] = __Permedia2TagContinueNewDom;
  852. pBuffer[5] = lCount;
  853. pBuffer += 6;
  854. InputBufferCommit(ppdev, pBuffer);
  855. }// if ( aPtrFixNext[LEFT]->y < aPtrFixNext[RIGHT]->y )
  856. else
  857. {
  858. //
  859. // We have reached aPtrFixNext[RIGHT]. aPtrFixNext[LEFT]
  860. // is still ok
  861. //
  862. do
  863. {
  864. aPtrFixTop[RIGHT] = aPtrFixNext[RIGHT];
  865. aPtrFixNext[RIGHT] = aPtrFixTop[RIGHT] + 1;
  866. if ( aPtrFixNext[RIGHT] > pptfxLast )
  867. {
  868. aPtrFixNext[RIGHT] = pptfxFirst;
  869. }
  870. } while ( aPtrFixTop[RIGHT]->y == aPtrFixNext[RIGHT]->y );
  871. //
  872. // We have a new aPtrFixNext[RIGHT] now.
  873. //
  874. DBG_GDI((7, "Sub: Top: x: %x y: %x",
  875. aPtrFixTop[RIGHT]->x, aPtrFixTop[RIGHT]->y));
  876. DBG_GDI((7, "Next: x: %x y: %x x: %x y: %x",
  877. aPtrFixNext[LEFT]->x, aPtrFixNext[LEFT]->y,
  878. aPtrFixNext[RIGHT]->x, aPtrFixNext[RIGHT]->y));
  879. alDX[RIGHT] = (aPtrFixNext[RIGHT]->x
  880. - aPtrFixTop[RIGHT]->x) << 12;
  881. alDY[RIGHT] = (aPtrFixNext[RIGHT]->y
  882. - aPtrFixTop[RIGHT]->y) >> 4;
  883. //
  884. // Need to ensure we round delta down. divide rounds
  885. // towards zero
  886. //
  887. if ( alDX[RIGHT] < 0 )
  888. {
  889. alDX[RIGHT] -= alDY[RIGHT] - 1;
  890. }
  891. alDxDy[RIGHT] = alDX[RIGHT] / alDY[RIGHT];
  892. if ( aPtrFixNext[RIGHT]->y < aPtrFixNext[LEFT]->y )
  893. {
  894. lCount = alDY[RIGHT];
  895. }
  896. else
  897. {
  898. lCount = (abs(aPtrFixNext[LEFT]->y
  899. - aPtrFixTop[RIGHT]->y)) >> 4;
  900. }
  901. InputBufferReserve(ppdev, 6, &pBuffer);
  902. pBuffer[0] = __Permedia2TagStartXSub;
  903. pBuffer[1] = FIXtoFIXED(aPtrFixTop[RIGHT]->x) + NEARLY_ONE;
  904. pBuffer[2] = __Permedia2TagdXSub;
  905. pBuffer[3] = alDxDy[RIGHT];
  906. pBuffer[4] = __Permedia2TagContinueNewSub;
  907. pBuffer[5] = lCount;
  908. pBuffer += 6;
  909. InputBufferCommit(ppdev, pBuffer);
  910. }// if !( aPtrFixNext[LEFT]->y < aPtrFixNext[RIGHT]->y )
  911. }// Loop through next trapezoids
  912. //
  913. // Repeatedly draw more trapezoids until points are equal
  914. // If y values are equal, then we can start again from
  915. // scratch.
  916. //
  917. if ( aPtrFixNext[LEFT] == aPtrFixNext[RIGHT] )
  918. {
  919. break;
  920. }
  921. }// loop through all the trapezoids
  922. FinishedPolygon:
  923. if ( !lNumOfPass-- )
  924. {
  925. break;
  926. }
  927. }// Loop through all the polygons
  928. if ( pClipList )
  929. {
  930. //
  931. // Reset scissor mode to its default state.
  932. //
  933. InputBufferReserve(ppdev, 2, &pBuffer);
  934. pBuffer[0] = __Permedia2TagScissorMode;
  935. pBuffer[1] = SCREEN_SCISSOR_DEFAULT;
  936. pBuffer += 2;
  937. InputBufferCommit(ppdev, pBuffer);
  938. }
  939. DBG_GDI((6, "bFillPolygon: returning TRUE"));
  940. bRC = TRUE;
  941. ReturnBack:
  942. InputBufferReserve(ppdev, 12, &pBuffer);
  943. pBuffer[0] = __Permedia2TagColorDDAMode;
  944. pBuffer[1] = __PERMEDIA_DISABLE;
  945. pBuffer[2] = __Permedia2TagdY;
  946. pBuffer[3] = INTtoFIXED(1);
  947. pBuffer[4] = __Permedia2TagContinue;
  948. pBuffer[5] = 0;
  949. pBuffer[6] = __Permedia2TagContinueNewDom;
  950. pBuffer[7] = 0;
  951. pBuffer[8] = __Permedia2TagdXDom;
  952. pBuffer[9] = 0;
  953. pBuffer[10] = __Permedia2TagdXSub;
  954. pBuffer[11] = 0;
  955. pBuffer += 12;
  956. InputBufferCommit(ppdev, pBuffer);
  957. return bRC;
  958. }// bFillPolygon()
  959. //-----------------------------------------------------------------------------
  960. //
  961. // BOOL bFillSpan()
  962. //
  963. // This is the code to break the polygon into spans.
  964. //
  965. // Parameters:
  966. // ppdev-------Pointer to PDev
  967. // pSurfDst----Destination surface
  968. // lEdges------Number of edges, includes close figure edge
  969. // pptfxFirst--Pointer to the first point in the data buffer. There are total
  970. // "lEdges" points
  971. // pptfxTop----Pointer to the toppest point in the polygon array.
  972. // pptfxLast---Pointer to the last point in the polygon array.
  973. // iSolidColor-Solid color fill
  974. // ulRop4------ROP4
  975. // pco---------Clip Object.
  976. // prb---------Realized brush
  977. // pptlBrush---Pattern alignment
  978. //
  979. //-----------------------------------------------------------------------------
  980. BOOL
  981. bFillSpans(PDev* ppdev,
  982. Surf* pSurfDst,
  983. LONG lEdges,
  984. POINTFIX* pptfxFirst,
  985. POINTFIX* pptfxTop,
  986. POINTFIX* pptfxLast,
  987. ULONG ulSolidColor,
  988. ULONG ulRop4,
  989. CLIPOBJ* pco,
  990. RBrush* prb,
  991. POINTL* pptlBrush)
  992. {
  993. GFNPB pb; // Parameter block
  994. POINTFIX* pptfxOld; // Start point in current edge
  995. EDGEDATA aEd[2]; // Left and right edge
  996. EDGEDATA aEdTmp[2]; // DDA terms and stuff
  997. EDGEDATA* pEdgeData;
  998. BOOL bTrivialClip; // Trivial Clip or not
  999. DWORD dwAsMode[2]; // The area stipple mode and the color for that
  1000. // pass
  1001. DWORD dwColorMode; // Current color mode
  1002. DWORD dwColorReg; // Current color register mode
  1003. DWORD dwContinueMsg = 0;
  1004. // Current "Continue" register settings
  1005. DWORD dwLogicMode; // Current logic op mode
  1006. DWORD dwRenderBits; // Current render bits
  1007. DWORD dwReadMode; // Current register read mode
  1008. LONG lCurrentSpan; // Current Span
  1009. LONG lDX; // Edge delta in FIX units in x direction
  1010. LONG lDY; // Edge delta in FIX units in y direction
  1011. LONG lNumColors; // Number of colors
  1012. LONG lNumOfPass; // Number of passes required to render
  1013. LONG lNumScan; // Number of scans in current trapezoid
  1014. LONG lQuotient; // Quotient
  1015. LONG lRemainder; // Remainder
  1016. LONG lStartY; // y-position of start point in current edge
  1017. LONG lTempNumScan; // Temporary variable for number of spans
  1018. LONG lTmpLeftX; // Temporary variable
  1019. LONG lTmpRightX; // Temporary variable
  1020. ULONG ulBgColor; // Background color
  1021. ULONG ulBgLogicOp = ulRop3ToLogicop(ulRop4 >> 8);
  1022. ULONG ulBrushColor = ulSolidColor;
  1023. ULONG ulColor[2]; // On multiple color passes we need to know how
  1024. // to set up
  1025. ULONG ulFgColor; // Foreground color
  1026. ULONG ulFgLogicOp = ulRop3ToLogicop(ulRop4 & 0xFF);
  1027. ULONG* pBuffer;
  1028. PERMEDIA_DECL;
  1029. bTrivialClip = (pco == NULL) || (pco->iDComplexity == DC_TRIVIAL);
  1030. pb.ppdev = ppdev;
  1031. //
  1032. // This span code cannot handle a clip list yet!
  1033. //
  1034. if ( !bTrivialClip )
  1035. {
  1036. return FALSE;
  1037. }
  1038. DBG_GDI((7, "Starting Spans Code"));
  1039. //
  1040. // Setup window base first
  1041. //
  1042. InputBufferReserve(ppdev, 2, &pBuffer);
  1043. pBuffer[0] = __Permedia2TagFBWindowBase;
  1044. pBuffer[1] = pSurfDst->ulPixOffset;
  1045. pBuffer += 2;
  1046. InputBufferCommit(ppdev, pBuffer);
  1047. //
  1048. // Some Initialization. First trapezoid starts from the topest point
  1049. // which is pointed by "pptfxTop".
  1050. // Here we convert it from 28.4 to normal interger
  1051. //
  1052. lCurrentSpan = (pptfxTop->y + 15) >> 4;
  1053. //
  1054. // Make sure we initialize the DDAs appropriately:
  1055. //
  1056. aEd[LEFT].lNumOfScanToGo = 0; // Number of scans to go for this left edge
  1057. aEd[RIGHT].lNumOfScanToGo = 0; // Number of scans to go for this right edge
  1058. //
  1059. // For now, guess as to which is the left and which is the right edge
  1060. //
  1061. aEd[LEFT].lPtfxDelta = -(LONG)sizeof(POINTFIX); // Delta (in bytes) from
  1062. aEd[RIGHT].lPtfxDelta = sizeof(POINTFIX); // pptfx to next point
  1063. aEd[LEFT].pptfx = pptfxTop; // Points to start of
  1064. aEd[RIGHT].pptfx = pptfxTop; // current edge
  1065. DBG_GDI((7, "bFillPolygon: Polygon is renderable. Go render"));
  1066. if ( ulFgLogicOp == K_LOGICOP_COPY )
  1067. {
  1068. dwColorMode = __PERMEDIA_DISABLE;
  1069. dwLogicMode = __PERMEDIA_CONSTANT_FB_WRITE;
  1070. dwReadMode = PM_FBREADMODE_PARTIAL(pSurfDst->ulPackedPP)
  1071. | PM_FBREADMODE_PACKEDDATA(__PERMEDIA_DISABLE);
  1072. //
  1073. // If block fills not available or using the area stipple for mono
  1074. // pattern, then use constant color.
  1075. //
  1076. if ( ulBrushColor == 0xffffffff )
  1077. {
  1078. dwColorReg = __Permedia2TagFBWriteData;
  1079. dwRenderBits = __RENDER_TRAPEZOID_PRIMITIVE;
  1080. } // Non-solid brush
  1081. else
  1082. {
  1083. //
  1084. // We can use fast fills, so load the fb block color register.
  1085. //
  1086. dwColorReg = __Permedia2TagFBBlockColor;
  1087. dwRenderBits = __RENDER_FAST_FILL_ENABLE
  1088. | __RENDER_TRAPEZOID_PRIMITIVE;
  1089. //
  1090. // Replicate colour for block fill colour.
  1091. //
  1092. if ( ppdev->cPelSize < 2 )
  1093. {
  1094. ulSolidColor |= ulSolidColor << 16;
  1095. if ( ppdev->cPelSize == 0 )
  1096. {
  1097. ulSolidColor |= ulSolidColor << 8;
  1098. }
  1099. }
  1100. //
  1101. // Ensure that the last access was a write before loading
  1102. // BlockColor
  1103. //
  1104. InputBufferReserve(ppdev, 2, &pBuffer);
  1105. pBuffer[0] = __Permedia2TagFBBlockColor;
  1106. pBuffer[1] = ulSolidColor;
  1107. pBuffer += 2;
  1108. InputBufferCommit(ppdev, pBuffer);
  1109. }// Solid brush
  1110. }// K_LOGICOP_COPY
  1111. else
  1112. {
  1113. dwColorMode = __COLOR_DDA_FLAT_SHADE;
  1114. dwLogicMode = P2_ENABLED_LOGICALOP(ulFgLogicOp);
  1115. dwReadMode = PM_FBREADMODE_PARTIAL(pSurfDst->ulPackedPP)
  1116. | LogicopReadDest[ulFgLogicOp];
  1117. dwColorReg = __Permedia2TagConstantColor;
  1118. dwRenderBits = __RENDER_TRAPEZOID_PRIMITIVE;
  1119. }// NON_COPY
  1120. //
  1121. // To get correct results, we need to add on nearly one to each X
  1122. // coordinate.
  1123. //
  1124. if ( ulBrushColor != 0xFFFFFFFF )
  1125. {
  1126. //
  1127. // This is a solid brush
  1128. //
  1129. lNumColors = 1;
  1130. if ( dwColorMode == __PERMEDIA_DISABLE )
  1131. {
  1132. //
  1133. // This is from LOGICOP_COPY mode according to the dwColorMode we
  1134. // set above
  1135. //
  1136. // Note: ColorDDAMode is DISABLED at initialisation time so
  1137. // there is no need to re-load it here.
  1138. //
  1139. InputBufferReserve(ppdev, 6, &pBuffer);
  1140. pBuffer[0] = __Permedia2TagFBReadMode;
  1141. pBuffer[1] = dwReadMode;
  1142. pBuffer[2] = __Permedia2TagLogicalOpMode;
  1143. pBuffer[3] = dwLogicMode;
  1144. pBuffer[4] = dwColorReg;
  1145. pBuffer[5] = ulSolidColor;
  1146. pBuffer += 6;
  1147. InputBufferCommit(ppdev, pBuffer);
  1148. }// Disable color DDA, LOGIC_COPY
  1149. else
  1150. {
  1151. //
  1152. // This is from NON-COPY logicop mode according to the dwColorMode
  1153. // we set above
  1154. //
  1155. InputBufferReserve(ppdev, 8, &pBuffer);
  1156. pBuffer[0] = __Permedia2TagColorDDAMode;
  1157. pBuffer[1] = dwColorMode;
  1158. pBuffer[2] = __Permedia2TagFBReadMode;
  1159. pBuffer[3] = dwReadMode;
  1160. pBuffer[4] = __Permedia2TagLogicalOpMode;
  1161. pBuffer[5] = dwLogicMode;
  1162. pBuffer[6] = dwColorReg;
  1163. pBuffer[7] = ulSolidColor;
  1164. pBuffer += 8;
  1165. InputBufferCommit(ppdev, pBuffer);
  1166. }// Enable colorDDA, NON-COPY mode
  1167. }// Solid brush case
  1168. else
  1169. {
  1170. //
  1171. // For non-solid brush case, we need to realize brush
  1172. //
  1173. BrushEntry* pbe;
  1174. //
  1175. // Turn on the area stipple.
  1176. //
  1177. dwRenderBits |= __RENDER_AREA_STIPPLE_ENABLE;
  1178. //
  1179. // If anything has changed with the brush we must re-realize it. If
  1180. // the brush has been kicked out of the area stipple unit we must
  1181. // fully realize it. If only the alignment has changed we can
  1182. // simply update the alignment for the stipple.
  1183. //
  1184. DBG_GDI((7, "Brush found"));
  1185. ASSERTDD(prb != NULL,
  1186. "Caller should pass in prb for non-solid brush");
  1187. pbe = prb->pbe;
  1188. pb.prbrush = prb;
  1189. pb.pptlBrush = pptlBrush;
  1190. if ( (pbe == NULL) || (pbe->prbVerify != prb) )
  1191. {
  1192. DBG_GDI((7, "full brush realize"));
  1193. vPatRealize(&pb);
  1194. }
  1195. else if ( (prb->ptlBrushOrg.x != pptlBrush->x)
  1196. ||(prb->ptlBrushOrg.y != pptlBrush->y) )
  1197. {
  1198. DBG_GDI((7, "changing brush offset"));
  1199. vMonoOffset(&pb);
  1200. }
  1201. ulFgColor = prb->ulForeColor;
  1202. ulBgColor = prb->ulBackColor;
  1203. if ( dwColorMode == __PERMEDIA_DISABLE )
  1204. {
  1205. //
  1206. // ColorDDAMode is DISABLED at initialisation time so there is
  1207. // no need to re-load it here.
  1208. //
  1209. InputBufferReserve(ppdev, 4, &pBuffer);
  1210. pBuffer[0] = __Permedia2TagFBReadMode;
  1211. pBuffer[1] = dwReadMode;
  1212. pBuffer[2] = __Permedia2TagLogicalOpMode;
  1213. pBuffer[3] = dwLogicMode;
  1214. pBuffer += 4;
  1215. InputBufferCommit(ppdev, pBuffer);
  1216. }
  1217. else
  1218. {
  1219. InputBufferReserve(ppdev, 6, &pBuffer);
  1220. pBuffer[0] = __Permedia2TagColorDDAMode;
  1221. pBuffer[1] = dwColorMode;
  1222. pBuffer[2] = __Permedia2TagFBReadMode;
  1223. pBuffer[3] = dwReadMode;
  1224. pBuffer[4] = __Permedia2TagLogicalOpMode;
  1225. pBuffer[5] = dwLogicMode;
  1226. pBuffer += 6;
  1227. InputBufferCommit(ppdev, pBuffer);
  1228. }
  1229. if ( (ulBgLogicOp == K_LOGICOP_NOOP)
  1230. ||((ulFgLogicOp == K_LOGICOP_XOR) && (ulBgColor == 0)) )
  1231. {
  1232. //
  1233. // Either we have a transparent bitmap or it can be assumed to
  1234. // be transparent (XOR with bg=0)
  1235. //
  1236. DBG_GDI((7, "transparant bg"));
  1237. lNumColors = 1;
  1238. InputBufferReserve(ppdev, 4, &pBuffer);
  1239. pBuffer[0] = dwColorReg;
  1240. pBuffer[1] = ulFgColor;
  1241. pBuffer[2] = __Permedia2TagAreaStippleMode;
  1242. pBuffer[3] = prb->areaStippleMode;
  1243. pBuffer += 4;
  1244. InputBufferCommit(ppdev, pBuffer);
  1245. }
  1246. else if ( (ulFgLogicOp == K_LOGICOP_XOR) && (ulFgColor == 0) )
  1247. {
  1248. //
  1249. // We have a transparent foreground! (XOR with fg=0)
  1250. //
  1251. DBG_GDI((7, "transparant fg"));
  1252. lNumColors = 1;
  1253. InputBufferReserve(ppdev, 4, &pBuffer);
  1254. pBuffer[0] = dwColorReg;
  1255. pBuffer[1] = ulBgColor;
  1256. pBuffer[2] = __Permedia2TagAreaStippleMode;
  1257. pBuffer[3] = prb->areaStippleMode |AREA_STIPPLE_INVERT_PAT;
  1258. pBuffer += 4;
  1259. InputBufferCommit(ppdev, pBuffer);
  1260. }
  1261. else
  1262. {
  1263. //
  1264. // Not using a transparent pattern
  1265. //
  1266. DBG_GDI((7, "2 color"));
  1267. lNumColors = 2;
  1268. ulColor[0] = ulFgColor;
  1269. ulColor[1] = ulBgColor;
  1270. dwAsMode[0] = prb->areaStippleMode;
  1271. dwAsMode[1] = dwAsMode[0] | AREA_STIPPLE_INVERT_PAT;
  1272. }
  1273. }// Non-solid brush case
  1274. InputBufferReserve(ppdev, 2, &pBuffer);
  1275. pBuffer[0] = __Permedia2TagCount;
  1276. pBuffer[1] = 0;
  1277. pBuffer += 2;
  1278. InputBufferCommit(ppdev, pBuffer);
  1279. //
  1280. // dxDom, dXSub and dY are initialised to 0, 0, and 1, so we don't need
  1281. // to re-load them here.
  1282. //
  1283. DBG_GDI((7, "Rendering Polygon. %d Colors", lNumColors));
  1284. NewTrapezoid:
  1285. DBG_GDI((7, "New Trapezoid"));
  1286. //
  1287. // DDA initialization
  1288. // Here we start with LEFT(1) edge and then RIGHT(0) edge
  1289. //
  1290. for ( int iEdge = 1; iEdge >= 0; --iEdge )
  1291. {
  1292. pEdgeData = &aEd[iEdge];
  1293. if ( pEdgeData->lNumOfScanToGo == 0 )
  1294. {
  1295. //
  1296. // No more scan lines left to go. Need a new DDA
  1297. // loop until we have some scan lines to go
  1298. //
  1299. do
  1300. {
  1301. lEdges--;
  1302. if ( lEdges < 0 )
  1303. {
  1304. //
  1305. // This is the only return point for this
  1306. // "BreakIntoSpans", that is, we return TRUE when there
  1307. // is no more edge left. We are done.
  1308. //
  1309. DBG_GDI((7, "bFillPolygon: returning TRUE"));
  1310. return TRUE;
  1311. }// if no more edge left
  1312. //
  1313. // Find the next left edge, accounting for wrapping. Before
  1314. // that, save the old edge in "pptfxOld"
  1315. //
  1316. pptfxOld = pEdgeData->pptfx;
  1317. //
  1318. // Get next point
  1319. //
  1320. pEdgeData->pptfx = (POINTFIX*)((BYTE*)pEdgeData->pptfx
  1321. + pEdgeData->lPtfxDelta);
  1322. //
  1323. // Checking the end point cases
  1324. //
  1325. if ( pEdgeData->pptfx < pptfxFirst )
  1326. {
  1327. pEdgeData->pptfx = pptfxLast;
  1328. }
  1329. else if ( pEdgeData->pptfx > pptfxLast )
  1330. {
  1331. pEdgeData->pptfx = pptfxFirst;
  1332. }
  1333. //
  1334. // Have to find the edge that spans lCurrentSpan.
  1335. // Note: we need to convert it to normal interger first
  1336. //
  1337. pEdgeData->lNumOfScanToGo = ((pEdgeData->pptfx->y + 15) >> 4)
  1338. - lCurrentSpan;
  1339. //
  1340. // With fractional coordinate end points, we may get edges
  1341. // that don't cross any scans, in which case we try the
  1342. // next one
  1343. //
  1344. } while ( pEdgeData->lNumOfScanToGo <= 0 );
  1345. //
  1346. // 'pEdgeData->pptfx' now points to the end point of the edge
  1347. // spanning the scan 'lCurrentSpan'.
  1348. // Calculate dx(lDX) and dy(lDY)
  1349. //
  1350. lDY = pEdgeData->pptfx->y - pptfxOld->y;
  1351. lDX = pEdgeData->pptfx->x - pptfxOld->x;
  1352. ASSERTDD(lDY > 0, "Should be going down only");
  1353. //
  1354. // Compute the DDA increment terms
  1355. //
  1356. if ( lDX < 0 )
  1357. {
  1358. //
  1359. // X is moving from right to left because it is negative
  1360. //
  1361. lDX = -lDX;
  1362. if ( lDX < lDY ) // Can't be '<='
  1363. {
  1364. pEdgeData->lXAdvance = -1;
  1365. pEdgeData->lErrorUp = lDY - lDX;
  1366. }
  1367. else
  1368. {
  1369. QUOTIENT_REMAINDER(lDX, lDY, lQuotient, lRemainder);
  1370. pEdgeData->lXAdvance = -lQuotient; // - lDX / lDY
  1371. pEdgeData->lErrorUp = lRemainder; // lDX % lDY
  1372. if ( pEdgeData->lErrorUp > 0 )
  1373. {
  1374. pEdgeData->lXAdvance--;
  1375. pEdgeData->lErrorUp = lDY - pEdgeData->lErrorUp;
  1376. }
  1377. }
  1378. }// lDX is negative
  1379. else
  1380. {
  1381. //
  1382. // X is moving from left to right
  1383. //
  1384. if ( lDX < lDY ) // Can't be '<='
  1385. {
  1386. pEdgeData->lXAdvance = 0;
  1387. pEdgeData->lErrorUp = lDX;
  1388. }
  1389. else
  1390. {
  1391. QUOTIENT_REMAINDER(lDX, lDY, lQuotient, lRemainder);
  1392. pEdgeData->lXAdvance = lQuotient; // lDX / lDY
  1393. pEdgeData->lErrorUp = lRemainder; // lDX % lDY
  1394. }
  1395. } // lDX is positive
  1396. pEdgeData->lErrorDown = lDY; // DDA limit
  1397. //
  1398. // Error is initially zero (add lDY -1 for the ceiling, but
  1399. // subtract off lDY so that we can check the sign instead of
  1400. // comparing to lDY)
  1401. //
  1402. pEdgeData->lError = -1;
  1403. //
  1404. // Current edge X starting point
  1405. //
  1406. pEdgeData->lCurrentXPos = pptfxOld->x;
  1407. //
  1408. // Current edge Y starting point
  1409. //
  1410. lStartY = pptfxOld->y;
  1411. //
  1412. // Check if the floating part of the Y coordinate is 0
  1413. // Note: lStartY is still in 28.4 format
  1414. //
  1415. if ( (lStartY & 15) != 0 )
  1416. {
  1417. //
  1418. // Advance to the next integer y coordinate
  1419. // Note: here "pEdgeData->x += pEdgeData->lXAdvance" only
  1420. // increase its fraction part
  1421. //
  1422. for ( int i = 16 - (lStartY & 15); i != 0; --i )
  1423. {
  1424. pEdgeData->lCurrentXPos += pEdgeData->lXAdvance;
  1425. pEdgeData->lError += pEdgeData->lErrorUp;
  1426. if ( pEdgeData->lError >= 0 )
  1427. {
  1428. pEdgeData->lError -= pEdgeData->lErrorDown;
  1429. pEdgeData->lCurrentXPos++;
  1430. }
  1431. }
  1432. }// Handle fraction part of the coordinate
  1433. if ( (pEdgeData->lCurrentXPos & 15) != 0 )
  1434. {
  1435. //
  1436. // We'll want the ceiling in just a bit...
  1437. //
  1438. pEdgeData->lError -= pEdgeData->lErrorDown
  1439. * (16 - (pEdgeData->lCurrentXPos & 15));
  1440. pEdgeData->lCurrentXPos += 15;
  1441. }
  1442. //
  1443. // Chop off those fractional bits, convert to regular format
  1444. //
  1445. pEdgeData->lCurrentXPos = pEdgeData->lCurrentXPos >> 4;
  1446. pEdgeData->lError >>= 4;
  1447. //
  1448. // Convert to Permedia2 format positions and deltas
  1449. // Note: all the data in pEdgeData, aEd are in Permedia2 format now
  1450. //
  1451. pEdgeData->lCurrentXPos = INTtoFIXED(pEdgeData->lCurrentXPos)
  1452. + NEARLY_ONE;
  1453. pEdgeData->lXAdvance = INTtoFIXED(pEdgeData->lXAdvance);
  1454. }// If there is no more scan line left
  1455. }// Looping throught the LEFT and RIGHT edges
  1456. //
  1457. // Number of scans in this trap
  1458. // Note: here aEd[LEFT].lNumOfScanToGo and aEd[RIGHT].lNumOfScanToGo are
  1459. // already in normal interger mode since we have done:
  1460. // pEdgeData->lNumOfScanToGo = ((pEdgeData->pptfx->y + 15) >> 4)
  1461. // - lCurrentSpan; above
  1462. //
  1463. lNumScan = min(aEd[LEFT].lNumOfScanToGo, aEd[RIGHT].lNumOfScanToGo);
  1464. aEd[LEFT].lNumOfScanToGo -= lNumScan;
  1465. aEd[RIGHT].lNumOfScanToGo -= lNumScan;
  1466. lCurrentSpan += lNumScan; // Top scan in next trap
  1467. //
  1468. // If the left and right edges are vertical, simply output as a rectangle
  1469. //
  1470. DBG_GDI((7, "Generate spans"));
  1471. lNumOfPass = 0;
  1472. while ( ++lNumOfPass <= lNumColors )
  1473. {
  1474. DBG_GDI((7, "Pass %d lNumColors %d", lNumOfPass, lNumColors));
  1475. if ( lNumColors == 2 )
  1476. {
  1477. //
  1478. // Two colours, so we need to save and restore aEd values
  1479. // and set the color and stipple mode.
  1480. //
  1481. InputBufferReserve(ppdev, 4, &pBuffer);
  1482. if ( lNumOfPass == 1 )
  1483. {
  1484. //
  1485. // Pass 1, set color reg as foreground color
  1486. //
  1487. aEdTmp[LEFT] = aEd[LEFT];
  1488. aEdTmp[RIGHT] = aEd[RIGHT];
  1489. lTempNumScan = lNumScan;
  1490. pBuffer[0] = dwColorReg;
  1491. pBuffer[1] = ulColor[0];
  1492. pBuffer[2] = __Permedia2TagAreaStippleMode;
  1493. pBuffer[3] = dwAsMode[0];
  1494. DBG_GDI((7, "Pass 1, Stipple set"));
  1495. }
  1496. else
  1497. {
  1498. //
  1499. // Pass 2, set color reg as background color
  1500. //
  1501. aEd[LEFT] = aEdTmp[LEFT];
  1502. aEd[RIGHT] = aEdTmp[RIGHT];
  1503. lNumScan = lTempNumScan;
  1504. pBuffer[0] = dwColorReg;
  1505. pBuffer[1] = ulColor[1];
  1506. pBuffer[2] = __Permedia2TagAreaStippleMode;
  1507. pBuffer[3] = dwAsMode[1];
  1508. DBG_GDI((7, "Pass 2, Stipple set, New trap started"));
  1509. }
  1510. pBuffer += 4;
  1511. InputBufferCommit(ppdev, pBuffer);
  1512. }// if (nColor == 2)
  1513. InputBufferReserve(ppdev, 8, &pBuffer);
  1514. //
  1515. // Reset render position to the top of the trapezoid.
  1516. // Note: here aEd[RIGHT].x etc. are alreadu in 12.15 mode since
  1517. // we have done
  1518. // "pEdgeData->x = INTtoFIXED(pEdgeData->x);" and
  1519. // "pEdgeData->lXAdvance = INTtoFIXED(pEdgeData->lXAdvance);" above
  1520. //
  1521. pBuffer[0] = __Permedia2TagStartXDom;
  1522. pBuffer[1] = aEd[RIGHT].lCurrentXPos;
  1523. pBuffer[2] = __Permedia2TagStartXSub;
  1524. pBuffer[3] = aEd[LEFT].lCurrentXPos;
  1525. pBuffer[4] = __Permedia2TagStartY;
  1526. pBuffer[5] = INTtoFIXED(lCurrentSpan - lNumScan);
  1527. pBuffer[6] = __Permedia2TagRender;
  1528. pBuffer[7] = dwRenderBits;
  1529. pBuffer += 8;
  1530. InputBufferCommit(ppdev, pBuffer);
  1531. dwContinueMsg = __Permedia2TagContinue;
  1532. if ( ((aEd[LEFT].lErrorUp | aEd[RIGHT].lErrorUp) == 0)
  1533. &&((aEd[LEFT].lXAdvance| aEd[RIGHT].lXAdvance) == 0)
  1534. &&(lNumScan > 1) )
  1535. {
  1536. //
  1537. // Vertical-edge special case
  1538. //
  1539. DBG_GDI((7, "Vertical Edge Special Case"));
  1540. //
  1541. // Tell the hardware that we have "lNumScan" scan lines
  1542. // to fill
  1543. //
  1544. InputBufferReserve(ppdev, 2, &pBuffer);
  1545. pBuffer[0] = dwContinueMsg;
  1546. pBuffer[1] = lNumScan;
  1547. pBuffer += 2;
  1548. InputBufferCommit(ppdev, pBuffer);
  1549. continue;
  1550. }
  1551. while ( TRUE )
  1552. {
  1553. //
  1554. // Run the DDAs
  1555. //
  1556. DBG_GDI((7, "Doing a span 0x%x to 0x%x, 0x%x scans left.Continue%s",
  1557. aEd[LEFT].lCurrentXPos, aEd[RIGHT].lCurrentXPos, lNumScan,
  1558. (dwContinueMsg == __Permedia2TagContinueNewDom) ? "NewDom":
  1559. ((dwContinueMsg == __Permedia2TagContinue)? "":"NewSub")));
  1560. //
  1561. // Tell the hardware that we have "1" scan lines to fill
  1562. //
  1563. InputBufferReserve(ppdev, 2, &pBuffer);
  1564. pBuffer[0] = dwContinueMsg;
  1565. pBuffer[1] = 1;
  1566. pBuffer += 2;
  1567. InputBufferCommit(ppdev, pBuffer);
  1568. //
  1569. // We have finished this trapezoid. Go get the next one
  1570. //
  1571. // Advance the right wall
  1572. //
  1573. lTmpRightX = aEd[RIGHT].lCurrentXPos;
  1574. aEd[RIGHT].lCurrentXPos += aEd[RIGHT].lXAdvance;
  1575. aEd[RIGHT].lError += aEd[RIGHT].lErrorUp;
  1576. if ( aEd[RIGHT].lError >= 0 )
  1577. {
  1578. aEd[RIGHT].lError -= aEd[RIGHT].lErrorDown;
  1579. aEd[RIGHT].lCurrentXPos += INTtoFIXED(1);
  1580. }
  1581. //
  1582. // Advance the left wall
  1583. //
  1584. lTmpLeftX = aEd[LEFT].lCurrentXPos;
  1585. aEd[LEFT].lCurrentXPos += aEd[LEFT].lXAdvance;
  1586. aEd[LEFT].lError += aEd[LEFT].lErrorUp;
  1587. if ( aEd[LEFT].lError >= 0 )
  1588. {
  1589. aEd[LEFT].lError -= aEd[LEFT].lErrorDown;
  1590. aEd[LEFT].lCurrentXPos += INTtoFIXED(1);
  1591. }
  1592. if ( --lNumScan == 0 )
  1593. {
  1594. break;
  1595. }
  1596. //
  1597. // Setup the X registers if we have changed either end.
  1598. //
  1599. if ( lTmpRightX != aEd[RIGHT].lCurrentXPos )
  1600. {
  1601. if ( lTmpLeftX != aEd[LEFT].lCurrentXPos )
  1602. {
  1603. InputBufferReserve(ppdev, 6, &pBuffer);
  1604. pBuffer[0] = __Permedia2TagStartXSub;
  1605. pBuffer[1] = aEd[LEFT].lCurrentXPos;
  1606. pBuffer[2] = __Permedia2TagContinueNewSub;
  1607. pBuffer[3] = 0;
  1608. pBuffer[4] = __Permedia2TagStartXDom;
  1609. pBuffer[5] = aEd[RIGHT].lCurrentXPos;
  1610. pBuffer += 6;
  1611. InputBufferCommit(ppdev, pBuffer);
  1612. }
  1613. else
  1614. {
  1615. InputBufferReserve(ppdev, 2, &pBuffer);
  1616. pBuffer[0] = __Permedia2TagStartXDom;
  1617. pBuffer[1] = aEd[RIGHT].lCurrentXPos;
  1618. pBuffer += 2;
  1619. InputBufferCommit(ppdev, pBuffer);
  1620. }
  1621. dwContinueMsg = __Permedia2TagContinueNewDom;
  1622. }
  1623. else if ( lTmpLeftX != aEd[LEFT].lCurrentXPos )
  1624. {
  1625. InputBufferReserve(ppdev, 2, &pBuffer);
  1626. pBuffer[0] = __Permedia2TagStartXSub;
  1627. pBuffer[1] = aEd[LEFT].lCurrentXPos;
  1628. pBuffer += 2;
  1629. InputBufferCommit(ppdev, pBuffer);
  1630. dwContinueMsg = __Permedia2TagContinueNewSub;
  1631. }
  1632. }// while ( TRUE )
  1633. }// while ( ++lNumOfPass <= lNumColors )
  1634. DBG_GDI((7, "Generate spans done"));
  1635. goto NewTrapezoid;
  1636. }// bFillSpans()