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.

1176 lines
55 KiB

  1. /******************************Module*Header**********************************\
  2. *
  3. * *******************
  4. * * GDI SAMPLE CODE *
  5. * *******************
  6. *
  7. * Module Name: pxrxPoly.c
  8. *
  9. * Content: Draws polygons.
  10. *
  11. * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
  12. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved.
  13. \*****************************************************************************/
  14. #define DBG_TRACK_CODE 0
  15. #include "precomp.h"
  16. #include "pxrx.h"
  17. #define DO_SPANONLY_VERSION 0
  18. #define RIGHT 0
  19. #define LEFT 1
  20. #define ABS(a) ((a) < 0 ? -(a) : (a))
  21. typedef struct _EDGEDATA {
  22. LONG x; // Current x position
  23. LONG dx; // # pixels to advance x on each scan
  24. LONG lError; // Current DDA error
  25. LONG lErrorUp; // DDA error increment on each scan
  26. LONG lErrorDown; // DDA error adjustment
  27. POINTFIX* pptfx; // Points to start of current edge
  28. LONG dptfx; // Delta (in bytes) from pptfx to next point
  29. LONG cy; // Number of scans to go for this edge
  30. } EDGEDATA;
  31. #define GetMoreFifoEntries( numberNeeded ) \
  32. do { \
  33. nSpaces -= numberNeeded; \
  34. if( nSpaces <= 0 ) { \
  35. do { \
  36. nSpaces = 10 + numberNeeded; \
  37. WAIT_FREE_PXRX_DMA_TAGS( nSpaces ); \
  38. nSpaces -= numberNeeded; \
  39. } while( nSpaces <= 0 ); \
  40. } \
  41. } while(0)
  42. /*
  43. #define SETUP_COLOUR_STUFF do { setupColourStuff(ppdev, glintInfo, \
  44. &fgColor, &fgLogicOp, \
  45. &bgColor, &bgLogicOp, \
  46. prb, pptlBrush, \
  47. &config2D, &renderMsg, &invalidatedFGBG); } while(0)
  48. static void setupColourStuff( PDEV *ppdev, GlintDataRec *glintInfo,
  49. ULONG *fgColor_In, ULONG *fgLogicOp_In,
  50. ULONG *bgColor_In, ULONG *bgLogicOp_In,
  51. RBRUSH *prb, POINTL *pptlBrush,
  52. ULONG *config2D_In, ULONG *renderMsg_In, ULONG *invalidatedFGBG_In ) {
  53. ULONG fgColor = *fgColor_In, fgLogicOp = *fgLogicOp_In;
  54. ULONG bgColor = *bgColor_In, bgLogicOp = *bgLogicOp_In;
  55. ULONG config2D = *config2D_In, renderMsg = *renderMsg_In;
  56. ULONG invalidatedFGBG = *invalidatedFGBG_In;
  57. TEMP_MACRO_VARS;
  58. */
  59. #define SETUP_COLOUR_STUFF \
  60. do { \
  61. SET_WRITE_BUFFERS; \
  62. \
  63. if( fgColor != 0xFFFFFFFF ) { \
  64. WAIT_PXRX_DMA_TAGS( 4 ); \
  65. /* Solid colour filled polygon */ \
  66. if( (fgLogicOp == __GLINT_LOGICOP_COPY) && \
  67. (ppdev->cPelSize != GLINTDEPTH8) && (ppdev->cPelSize != GLINTDEPTH32) ) { \
  68. config2D |= __CONFIG2D_CONSTANTSRC; \
  69. } else { \
  70. config2D |= __CONFIG2D_LOGOP_FORE(fgLogicOp) | __CONFIG2D_CONSTANTSRC; \
  71. renderMsg |= __RENDER_VARIABLE_SPANS; \
  72. \
  73. if( LogicopReadDest[fgLogicOp] ) { \
  74. config2D |= __CONFIG2D_FBDESTREAD; \
  75. SET_READ_BUFFERS; \
  76. } \
  77. } \
  78. \
  79. if( LogicOpReadSrc[fgLogicOp] ) \
  80. LOAD_FOREGROUNDCOLOUR( fgColor ); \
  81. \
  82. DISPDBG((DBGLVL, "bGlintFastFillPolygon: solid fill, col = 0x%08x, logicOp = %d", fgColor, fgLogicOp)); \
  83. } else { \
  84. /* Brush filled polygon */ \
  85. BRUSHENTRY *pbe; \
  86. \
  87. pbe = prb->apbe; \
  88. \
  89. if( prb->fl & RBRUSH_2COLOR ) { \
  90. /* Monochrome brush */ \
  91. config2D |= __CONFIG2D_CONSTANTSRC; \
  92. renderMsg |= __RENDER_AREA_STIPPLE_ENABLE; \
  93. \
  94. /* if anything has changed with the brush we must re-realize it. If the brush */ \
  95. /* has been kicked out of the area stipple unit we must fully realize it. If */ \
  96. /* only the alignment has changed we can simply update the alignment for the */ \
  97. /* stipple. */ \
  98. if( (pbe == NULL) || (pbe->prbVerify != prb) ) { \
  99. DISPDBG((DBGLVL, "full brush realise")); \
  100. (*ppdev->pgfnPatRealize)(ppdev, prb, pptlBrush); \
  101. } else if( (prb->ptlBrushOrg.x != pptlBrush->x) || \
  102. (prb->ptlBrushOrg.y != pptlBrush->y) ) { \
  103. DISPDBG((DBGLVL, "changing brush offset")); \
  104. (*ppdev->pgfnMonoOffset)(ppdev, prb, pptlBrush); \
  105. } \
  106. \
  107. fgColor = prb->ulForeColor; \
  108. bgColor = prb->ulBackColor; \
  109. \
  110. if( ((bgLogicOp == __GLINT_LOGICOP_AND) && (bgColor == ppdev->ulWhite)) \
  111. || ((bgLogicOp == __GLINT_LOGICOP_OR ) && (bgColor == 0)) \
  112. || ((bgLogicOp == __GLINT_LOGICOP_XOR) && (bgColor == 0)) ) \
  113. bgLogicOp = __GLINT_LOGICOP_NOOP; \
  114. \
  115. if( ((fgLogicOp != __GLINT_LOGICOP_COPY) || (bgLogicOp != __GLINT_LOGICOP_NOOP)) || \
  116. (ppdev->cPelSize == GLINTDEPTH32) || (ppdev->cPelSize == GLINTDEPTH8) ) { \
  117. config2D |= __CONFIG2D_OPAQUESPANS | __CONFIG2D_LOGOP_FORE(fgLogicOp) | __CONFIG2D_LOGOP_BACK(bgLogicOp); \
  118. renderMsg |= __RENDER_VARIABLE_SPANS; \
  119. } \
  120. \
  121. WAIT_PXRX_DMA_TAGS( 5 ); \
  122. \
  123. if( LogicopReadDest[fgLogicOp] || LogicopReadDest[bgLogicOp] ) { \
  124. config2D |= __CONFIG2D_FBDESTREAD; \
  125. SET_READ_BUFFERS; \
  126. } \
  127. \
  128. if( LogicOpReadSrc[fgLogicOp] ) \
  129. LOAD_FOREGROUNDCOLOUR( fgColor ); \
  130. if( LogicOpReadSrc[bgLogicOp] ) \
  131. LOAD_BACKGROUNDCOLOUR( bgColor ); \
  132. \
  133. DISPDBG((DBGLVL, "bGlintFastFillPolygon: mono pat fill, col = 0x%08x:0x%08x, logicOp = %d:%d", \
  134. fgColor, bgColor, fgLogicOp, bgLogicOp)); \
  135. } else { \
  136. /* Colour brush */ \
  137. POINTL brushOrg; \
  138. \
  139. brushOrg = *pptlBrush; \
  140. if( (fgLogicOp == __GLINT_LOGICOP_COPY) && (ppdev->cPelSize != 0) ) \
  141. brushOrg.x += (8 - (ppdev->xyOffsetDst & 0xFFFF)) & 7; \
  142. \
  143. if( (ppdev->PalLUTType != LUTCACHE_BRUSH) || (pbe == NULL) || (pbe->prbVerify != prb) ) { \
  144. DISPDBG((DBGLVL, "realising brush")); \
  145. (*ppdev->pgfnPatRealize)(ppdev, prb, &brushOrg); \
  146. } else \
  147. if( (prb->ptlBrushOrg.x != brushOrg.x) || (prb->ptlBrushOrg.y != brushOrg.y) || \
  148. (prb->patternBase != ((glintInfo->lutMode >> 18) & 255)) ) { \
  149. ULONG lutMode = glintInfo->lutMode; \
  150. \
  151. DISPDBG((DBGLVL, "resetting LUTMode")); \
  152. \
  153. prb->ptlBrushOrg.x = brushOrg.x; \
  154. prb->ptlBrushOrg.y = brushOrg.y; \
  155. \
  156. DISPDBG((DBGLVL, "setting new LUT offset to %d, %d", (8 - prb->ptlBrushOrg.x) & 7, (8 - prb->ptlBrushOrg.y) & 7)); \
  157. \
  158. lutMode &= ~((7 << 8) | (7 << 12) | (7 << 15) | (255 << 18) | (1 << 26) | (1 << 27)); \
  159. lutMode |= (1 << 8) | (1 << 27) | (prb->patternBase << 18) | \
  160. (((8 - prb->ptlBrushOrg.x) & 7) << 12) | (((8 - prb->ptlBrushOrg.y) & 7) << 15); \
  161. WAIT_PXRX_DMA_TAGS( 1 ); \
  162. LOAD_LUTMODE( lutMode ); \
  163. } else { \
  164. /* we're cached already! */ \
  165. DISPDBG((DBGLVL, "reusing LUT for brush @ %d, origin = (%d,%d)", prb->patternBase, prb->ptlBrushOrg.x, prb->ptlBrushOrg.y)); \
  166. } \
  167. \
  168. WAIT_PXRX_DMA_TAGS( 4 ); \
  169. if( (glintInfo->pxrxFlags & PXRX_FLAGS_DUAL_WRITING) || \
  170. (glintInfo->pxrxFlags & PXRX_FLAGS_STEREO_WRITE) || \
  171. (ppdev->cPelSize == GLINTDEPTH8) || (ppdev->cPelSize == GLINTDEPTH32) ) { \
  172. config2D |= config2D_FillColourDual[fgLogicOp]; \
  173. \
  174. if( LogicopReadDest[fgLogicOp] ) \
  175. SET_READ_BUFFERS; \
  176. \
  177. renderMsg |= __RENDER_VARIABLE_SPANS; \
  178. } else { \
  179. config2D |= config2D_FillColour[fgLogicOp]; \
  180. \
  181. if( fgLogicOp != __GLINT_LOGICOP_COPY ) \
  182. renderMsg |= __RENDER_VARIABLE_SPANS; \
  183. \
  184. if( LogicopReadDest[fgLogicOp] ) { \
  185. SET_READ_BUFFERS; \
  186. } else if( fgLogicOp == __GLINT_LOGICOP_COPY ) { \
  187. LOAD_FBWRITE_ADDR( 1, ppdev->DstPixelOrigin ); \
  188. LOAD_FBWRITE_WIDTH( 1, ppdev->DstPixelDelta ); \
  189. LOAD_FBWRITE_OFFSET( 1, ppdev->xyOffsetDst ); \
  190. } \
  191. } \
  192. \
  193. if( config2D & __CONFIG2D_LUTENABLE ) \
  194. invalidatedFGBG = TRUE; \
  195. \
  196. DISPDBG((DBGLVL, "bGlintFastFillPolygon: colour pat fill, patBase = %d, logicOp = %d", prb->patternBase, fgLogicOp)); \
  197. } \
  198. } \
  199. \
  200. WAIT_PXRX_DMA_TAGS( 1 ); \
  201. LOAD_CONFIG2D( config2D ); \
  202. nSpaces = 0; \
  203. } while( 0 )
  204. /*
  205. ;
  206. *fgColor_In = fgColor;
  207. *fgLogicOp_In = fgLogicOp;
  208. *bgColor_In = bgColor;
  209. *bgLogicOp_In = bgLogicOp;
  210. *config2D_In = config2D;
  211. *renderMsg_In = renderMsg;
  212. *invalidatedFGBG_In = invalidatedFGBG;
  213. }
  214. */
  215. /******************************Public*Routine******************************\
  216. * BOOL bGlintFastFillPolygon
  217. *
  218. * Draws a non-complex, unclipped polygon. 'Non-complex' is defined as
  219. * having only two edges that are monotonic increasing in 'y'. That is,
  220. * the polygon cannot have more than one disconnected segment on any given
  221. * scan. Note that the edges of the polygon can self-intersect, so hourglass
  222. * shapes are permissible. This restriction permits this routine to run two
  223. * simultaneous DDAs, and no sorting of the edges is required.
  224. *
  225. * Note that NT's fill convention is different from that of Win 3.1 or 4.0.
  226. * With the additional complication of fractional end-points, our convention
  227. * is the same as in 'X-Windows'. But a DDA is a DDA is a DDA, so once you
  228. * figure out how we compute the DDA terms for NT, you're golden.
  229. *
  230. * This routine handles patterns only when the glint area stipple can be
  231. * used. The reason for this is that once the stipple initialization is
  232. * done, pattern fills appear to the programmer exactly the same as solid
  233. * fills (with the slight difference of an extra bit in the render command).
  234. *
  235. * We break each polygon down to a sequenze of screen aligned trapeziods, which
  236. * the glint can handle.
  237. *
  238. * Optimisation list follows ....
  239. *
  240. * This routine is in no way the ultimate convex polygon drawing routine
  241. * Some obvious things that would make it faster:
  242. *
  243. * 1) Write it in Assembler
  244. *
  245. * 2) Make the non-complex polygon detection faster. If I could have
  246. * modified memory before the start of after the end of the buffer,
  247. * I could have simplified the detection code. But since I expect
  248. * this buffer to come from GDI, I can't do that. Another thing
  249. * would be to have GDI give a flag on calls that are guaranteed
  250. * to be convex, such as 'Ellipses' and 'RoundRects'. Note that
  251. * the buffer would still have to be scanned to find the top-most
  252. * point.
  253. *
  254. * 3) Implement support for a single sub-path that spans multiple
  255. * path data records, so that we don't have to copy all the points
  256. * to a single buffer like we do in 'fillpath.c'.
  257. *
  258. * 4) Use 'ebp' and/or 'esp' as a general register in the inner loops
  259. * of the Asm loops, and also Pentium-optimize the code. It's safe
  260. * to use 'esp' on NT because it's guaranteed that no interrupts
  261. * will be taken in our thread context, and nobody else looks at the
  262. * stack pointer from our context.
  263. *
  264. * 5) When we get to a part of the polygon where both vertices are of
  265. * equal height, the algorithm essentially starts the polygon again.
  266. * Using the GLINT Continue message could speed things up in certain
  267. * cases.
  268. *
  269. * Returns TRUE if the polygon was drawn; FALSE if the polygon was complex.
  270. *
  271. \**************************************************************************/
  272. BOOL bGlintFastFillPolygon(
  273. PDEV *ppdev,
  274. LONG cEdges, // Includes close figure edge
  275. POINTFIX *pptfxFirst, // Ptr to first point
  276. ULONG fgColor, // Solid color fill
  277. ULONG fgLogicOp, // Logical Operation to perform
  278. ULONG bgLogicOp, // background logic op
  279. CLIPOBJ *pco, // Clip Object.
  280. RBRUSH *prb,
  281. POINTL *pptlBrush ) // Pattern alignment
  282. {
  283. POINTFIX *pptfxLast; // Points to the last point in the polygon array
  284. POINTFIX *pptfxTop; // Points to the top-most point in the polygon
  285. POINTFIX *pptfxScan; // Current edge pointer for finding pptfxTop
  286. LONG cScanEdges; // Number of edges scanned to find pptfxTop
  287. // (doesn't include the closefigure edge)
  288. POINTFIX *pnt[2]; // DDA terms and stuff
  289. POINTFIX *npnt[2]; // DDA terms and stuff
  290. LONG dx[2], dy[2], gdx[2];
  291. ULONG orx, ory; // all values ored, to eliminate complex polygons
  292. LONG count;
  293. LONG nClips; // Number of clipping rectangles to render in
  294. CLIPENUM *pClipRegion = (CLIPENUM *)(ppdev->pvTmpBuffer);
  295. RECTL *pClipList; // List of clip rects
  296. LONG xOffFixed;
  297. ULONG bgColor;
  298. BOOL bTrivialClip, invalidatedFGBG = FALSE;
  299. BOOL invalidatedScissor = FALSE;
  300. ULONG config2D = __CONFIG2D_FBWRITE;
  301. ULONG renderMsg = __RENDER_TRAPEZOID_PRIMITIVE |
  302. __RENDER_FAST_FILL_ENABLE;
  303. LONG nSpaces;
  304. GLINT_DECL;
  305. DISPDBG((DBGLVL, "bGlintFastFillPolygon: "
  306. "Checking polygon for renderability by glint"));
  307. ASSERTDD(cEdges > 1, "Polygon with less than 2 edges");
  308. /////////////////////////////////////////////////////////////////
  309. // See if the polygon is 'non-complex'
  310. pptfxScan = pptfxFirst;
  311. pptfxTop = pptfxFirst; // Assume for now that the first
  312. // point in path is the topmost
  313. pptfxLast = pptfxFirst + cEdges - 1;
  314. orx = pptfxScan->x;
  315. ory = pptfxScan->y;
  316. // 'pptfxScan' will always point to the first point in the current
  317. // edge, and 'cScanEdges' will the number of edges remaining, including
  318. // the current one:
  319. cScanEdges = cEdges - 1; // The number of edges, not counting close figure
  320. if( (pptfxScan + 1)->y > pptfxScan->y )
  321. {
  322. // Collect all downs:
  323. do
  324. {
  325. ory |= (++pptfxScan)->y;
  326. orx |= pptfxScan->x;
  327. if( --cScanEdges == 0 )
  328. {
  329. goto SetUpForFilling;
  330. }
  331. } while( (pptfxScan + 1)->y >= pptfxScan->y );
  332. // Collect all ups:
  333. do
  334. {
  335. ory |= (++pptfxScan)->y;
  336. orx |= pptfxScan->x;
  337. if( --cScanEdges == 0 )
  338. {
  339. goto SetUpForFillingCheck;
  340. }
  341. } while( (pptfxScan + 1)->y <= pptfxScan->y );
  342. // Collect all downs:
  343. pptfxTop = pptfxScan;
  344. do
  345. {
  346. if( (pptfxScan + 1)->y > pptfxFirst->y )
  347. break;
  348. ory |= (++pptfxScan)->y;
  349. orx |= pptfxScan->x;
  350. if( --cScanEdges == 0 )
  351. {
  352. goto SetUpForFilling;
  353. }
  354. } while( (pptfxScan + 1)->y >= pptfxScan->y );
  355. DISPDBG((DBGLVL, "Reject: GLINT can't fill down-up-down polygon"));
  356. return FALSE;
  357. }
  358. else
  359. {
  360. // Collect all ups:
  361. do
  362. {
  363. ory |= (++pptfxTop)->y; // We increment this now because we
  364. orx |= pptfxTop->x; // want it to point to the very last
  365. // point if we early out in the next
  366. // statement...
  367. if( --cScanEdges == 0 )
  368. {
  369. goto SetUpForFilling;
  370. }
  371. } while( (pptfxTop + 1)->y <= pptfxTop->y );
  372. // Collect all downs:
  373. pptfxScan = pptfxTop;
  374. do
  375. {
  376. ory |= (++pptfxScan)->y;
  377. orx |= pptfxScan->x;
  378. if( --cScanEdges == 0 )
  379. {
  380. goto SetUpForFilling;
  381. }
  382. } while( (pptfxScan + 1)->y >= pptfxScan->y );
  383. // Collect all ups:
  384. do
  385. {
  386. if( (pptfxScan + 1)->y < pptfxFirst->y )
  387. {
  388. break;
  389. }
  390. ory |= (++pptfxScan)->y;
  391. orx |= pptfxScan->x;
  392. if( --cScanEdges == 0 )
  393. {
  394. goto SetUpForFilling;
  395. }
  396. } while( (pptfxScan + 1)->y <= pptfxScan->y );
  397. DISPDBG((DBGLVL, "Reject: GLINT can't fill up-down-up polygon"));
  398. return FALSE;
  399. }
  400. SetUpForFillingCheck:
  401. // We check to see if the end of the current edge is higher
  402. // than the top edge we've found so far
  403. if( pptfxScan->y < pptfxTop->y )
  404. {
  405. pptfxTop = pptfxScan;
  406. }
  407. SetUpForFilling:
  408. // can only use block fills for trivial clip so work it out here
  409. bTrivialClip = (pco == NULL) || (pco->iDComplexity == DC_TRIVIAL);
  410. if( DO_SPANONLY_VERSION )
  411. {
  412. goto BreakIntoSpans;
  413. }
  414. if( (ory & 0xffffc00f) || (orx & 0xffff8000) )
  415. {
  416. ULONG neg, posx, posy;
  417. // fractional Y must be done as spans
  418. if( ory & 0xf )
  419. {
  420. goto BreakIntoSpans;
  421. }
  422. // Run through all the vertices and check that none of them
  423. // have a negative component less than -256.
  424. neg = posx = posy = 0;
  425. for( pptfxScan = pptfxFirst; pptfxScan <= pptfxLast; pptfxScan++ )
  426. {
  427. if( pptfxScan->x < 0 )
  428. {
  429. neg |= -pptfxScan->x;
  430. }
  431. else
  432. {
  433. posx |= pptfxScan->x;
  434. }
  435. if( pptfxScan->y < 0 )
  436. {
  437. neg |= -pptfxScan->y;
  438. }
  439. else
  440. {
  441. posy |= pptfxScan->y;
  442. }
  443. }
  444. // We don't want to handle any polygon with a negative vertex
  445. // at <= -256 in either coordinate ???
  446. if( neg & 0xfffff000 )
  447. {
  448. DISPDBG((WRNLVL, "Coords out of range for fast fill"));
  449. return FALSE;
  450. }
  451. }
  452. // The code can handle the polygon now. Lets go ahead and render it!
  453. // Compiler gets its register allocation wrong. This forces it to redo them
  454. GLINT_DECL_INIT;
  455. DISPDBG((DBGLVL, "bGlintFastFillPolygon: "
  456. "Polygon is renderable. Go ahead and render"));
  457. // Work out offset to add to each of the coords downloaded to GLINT
  458. // To get correct results, we need to add on nearly one to each X
  459. // coordinate.
  460. // Also add on offsets to bitmap (This might be an off screen bitmap)
  461. xOffFixed = INTtoFIXED(0) + NEARLY_ONE;
  462. // determine how many passes we require to draw all the clip rects
  463. if( bTrivialClip )
  464. {
  465. // Just draw, no clipping to perform.
  466. pClipList = NULL; // Indicate no clip list
  467. nClips = 1;
  468. }
  469. else
  470. {
  471. if( pco->iDComplexity == DC_RECT )
  472. {
  473. nClips = 1;
  474. pClipList = &pco->rclBounds;
  475. }
  476. else
  477. {
  478. // It may be slow to render the entire polygon for each clip
  479. // rect, especially if the object is very complex. An arbitary
  480. // limit of up to CLIP_LIMIT regions will be rendered by this
  481. // function. Return false if more than CLIP_LIMIT regions.
  482. nClips = CLIPOBJ_cEnumStart(pco,
  483. FALSE,
  484. CT_RECTANGLES,
  485. CD_ANY,
  486. CLIP_LIMIT);
  487. if( nClips == -1 )
  488. {
  489. return FALSE; // More than CLIP_LIMIT.
  490. }
  491. // Put the regions into our clip buffer
  492. if( (CLIPOBJ_bEnum(pco, sizeof (CLIPENUM), (ULONG*)pClipRegion)) ||
  493. (pClipRegion->c != nClips) )
  494. {
  495. DISPDBG((DBGLVL, "bGlintFastFillPolygon: "
  496. "CLIPOBJ_bEnum inconsistency %d = %d",
  497. pClipRegion->c, nClips));
  498. }
  499. pClipList = &(pClipRegion->arcl[0]);
  500. }
  501. config2D |= __CONFIG2D_USERSCISSOR;
  502. }
  503. SETUP_COLOUR_STUFF;
  504. WAIT_PXRX_DMA_TAGS( 11 );
  505. QUEUE_PXRX_DMA_TAG( __GlintTagdY, INTtoFIXED(1) );
  506. DISPDBG((DBGLVL, "Rendering Polygon. %d clipping rectangles", nClips));
  507. if( nClips && pClipList )
  508. {
  509. invalidatedScissor = TRUE;
  510. }
  511. // JME: check for 0 nClips //azn
  512. if( nClips-- )
  513. {
  514. while( 1 )
  515. {
  516. // Need to set up clip rect each pass
  517. if( pClipList )
  518. {
  519. DISPDBG((DBGLVL, "Clip rect = (%d, %d -> %d, %d)",
  520. pClipList->left, pClipList->top,
  521. pClipList->right, pClipList->bottom));
  522. QUEUE_PXRX_DMA_TAG( __GlintTagScissorMinXY,
  523. MAKEDWORD_XY(pClipList->left ,
  524. pClipList->top ) );
  525. QUEUE_PXRX_DMA_TAG( __GlintTagScissorMaxXY,
  526. MAKEDWORD_XY(pClipList->right,
  527. pClipList->bottom) );
  528. pClipList++;
  529. }
  530. // Initialize left and right points (current) to top point.
  531. npnt[LEFT] = pptfxTop;
  532. npnt[RIGHT] = pptfxTop;
  533. while( 1 )
  534. {
  535. // npnt[] is always the valid point to draw from
  536. do
  537. {
  538. pnt[LEFT] = npnt[LEFT];
  539. npnt[LEFT] = pnt[LEFT] - 1;
  540. if (npnt[LEFT] < pptfxFirst)
  541. {
  542. npnt[LEFT] = pptfxLast;
  543. }
  544. // Special case of flat based polygon, need to break now
  545. // as polygon is finished
  546. if (npnt[LEFT] == npnt[RIGHT])
  547. {
  548. goto FinishedPolygon;
  549. }
  550. DISPDBG((DBGLVL, "LEFT: pnt %P npnt %P FIRST %P LAST %P",
  551. pnt[LEFT], npnt[LEFT],
  552. pptfxFirst, pptfxLast));
  553. DISPDBG((DBGLVL, "x 0x%04X y 0x%04X Next: x 0x%04X y 0x%04X",
  554. pnt[LEFT]->x, pnt[LEFT]->y,
  555. npnt[LEFT]->x, npnt[LEFT]->y));
  556. } while( pnt[LEFT]->y == npnt[LEFT]->y );
  557. do {
  558. pnt[RIGHT] = npnt[RIGHT];
  559. npnt[RIGHT] = pnt[RIGHT] + 1;
  560. if (npnt[RIGHT] > pptfxLast)
  561. {
  562. npnt[RIGHT] = pptfxFirst;
  563. }
  564. DISPDBG((DBGLVL, "RIGHT: pnt %P npnt %P FIRST %P LAST %P",
  565. pnt[RIGHT], npnt[RIGHT],
  566. pptfxFirst, pptfxLast));
  567. DISPDBG((DBGLVL, "x 0x%04X y 0x%04X Next: x 0x%04X y 0x%04X",
  568. pnt[RIGHT]->x, pnt[RIGHT]->y,
  569. npnt[RIGHT]->x, npnt[RIGHT]->y));
  570. } while( pnt[RIGHT]->y == npnt[RIGHT]->y );
  571. // Start up new rectangle. Whenever we get to this code, both
  572. // points should have equal y values, and need to be restarted.
  573. DISPDBG((DBGLVL, "New: Top: (0x%04X, 0x%04X)->(0x%04X, 0x%04X)"
  574. " Next: (0x%04X, 0x%04X)->(0x%04X, 0x%04X)",
  575. pnt[LEFT]->x, pnt[LEFT]->y,
  576. pnt[RIGHT]->x, pnt[RIGHT]->y,
  577. npnt[LEFT]->x, npnt[LEFT]->y,
  578. npnt[RIGHT]->x, npnt[RIGHT]->y));
  579. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom,
  580. FIXtoFIXED(pnt[LEFT]->x) + xOffFixed );
  581. QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub,
  582. FIXtoFIXED(pnt[RIGHT]->x) + xOffFixed);
  583. QUEUE_PXRX_DMA_TAG( __GlintTagStartY,
  584. FIXtoFIXED(pnt[RIGHT]->y) );
  585. // We have 2 15.4 coordinates. We need to divide them and
  586. // change them into a 15.16 coordinate. We know the y
  587. // coordinate is not fractional, so we do not loose
  588. // precision by shifting right by 4
  589. dx[LEFT] = (npnt[LEFT]->x - pnt[LEFT]->x) << 12;
  590. dy[LEFT] = (npnt[LEFT]->y - pnt[LEFT]->y) >> 4;
  591. // Need to ensure we round delta down.
  592. // divide rounds towards zero
  593. if( dx[LEFT] < 0 )
  594. {
  595. dx[LEFT] -= dy[LEFT] - 1;
  596. }
  597. gdx[LEFT] = dx[LEFT] / dy[LEFT];
  598. QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, gdx[LEFT] );
  599. dx[RIGHT] = (npnt[RIGHT]->x - pnt[RIGHT]->x) << 12;
  600. dy[RIGHT] = (npnt[RIGHT]->y - pnt[RIGHT]->y) >> 4;
  601. // Need to ensure we round delta down.
  602. // divide rounds towards zero
  603. if( dx[RIGHT] < 0 )
  604. {
  605. dx[RIGHT] -= dy[RIGHT] - 1;
  606. }
  607. gdx[RIGHT] = dx[RIGHT] / dy[RIGHT];
  608. QUEUE_PXRX_DMA_TAG( __GlintTagdXSub, gdx[RIGHT] );
  609. // Work out number of scanlines to render
  610. if (npnt[LEFT]->y < npnt[RIGHT]->y)
  611. {
  612. count = dy[LEFT];
  613. }
  614. else
  615. {
  616. count = dy[RIGHT];
  617. }
  618. QUEUE_PXRX_DMA_TAG( __GlintTagCount, count );
  619. QUEUE_PXRX_DMA_TAG( __GlintTagRender, renderMsg );
  620. SEND_PXRX_DMA_BATCH;
  621. // With lots of luck, top trapezoid should be drawn now!
  622. // Repeatedly draw more trapezoids until points are equal
  623. // If y values are equal, then we can start again from
  624. // scratch.
  625. while( (npnt[LEFT] != npnt[RIGHT]) &&
  626. (npnt[LEFT]->y != npnt[RIGHT]->y) )
  627. {
  628. // Some continues are required for next rectangle
  629. if( npnt[LEFT]->y < npnt[RIGHT]->y )
  630. {
  631. // We have reached npnt[LEFT]. npnt[RIGHT] is still ok
  632. do
  633. {
  634. pnt[LEFT] = npnt[LEFT];
  635. npnt[LEFT] = pnt[LEFT] - 1;
  636. if (npnt[LEFT] < pptfxFirst)
  637. {
  638. npnt[LEFT] = pptfxLast;
  639. }
  640. } while( pnt[LEFT]->y == npnt[LEFT]->y );
  641. // We have a new npnt[LEFT] now.
  642. DISPDBG((DBGLVL, "Dom: Top: x: %x y: %x "
  643. " Next: x: %x y: %x x: %x y: %x",
  644. pnt[LEFT]->x, pnt[LEFT]->y,
  645. npnt[LEFT]->x, npnt[LEFT]->y,
  646. npnt[RIGHT]->x, npnt[RIGHT]->y));
  647. dx[LEFT] = (npnt[LEFT]->x - pnt[LEFT]->x) << 12;
  648. dy[LEFT] = (npnt[LEFT]->y - pnt[LEFT]->y) >> 4;
  649. // Need to ensure we round delta down.
  650. // divide rounds towards zero
  651. if( dx[LEFT] < 0 )
  652. {
  653. dx[LEFT] -= dy[LEFT] - 1;
  654. }
  655. gdx[LEFT] = dx[LEFT] / dy[LEFT];
  656. if( npnt[LEFT]->y < npnt[RIGHT]->y )
  657. {
  658. count = dy[LEFT];
  659. }
  660. else
  661. {
  662. count = (ABS(npnt[RIGHT]->y - pnt[LEFT]->y)) >> 4;
  663. }
  664. WAIT_PXRX_DMA_TAGS( 3 );
  665. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom,
  666. FIXtoFIXED(pnt[LEFT]->x) + xOffFixed );
  667. QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, gdx[LEFT] );
  668. QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewDom, count );
  669. }
  670. else
  671. {
  672. // We have reached npnt[RIGHT]. npnt[LEFT] is still ok
  673. do {
  674. pnt[RIGHT] = npnt[RIGHT];
  675. npnt[RIGHT] = pnt[RIGHT] + 1;
  676. if( npnt[RIGHT] > pptfxLast )
  677. {
  678. npnt[RIGHT] = pptfxFirst;
  679. }
  680. } while( pnt[RIGHT]->y == npnt[RIGHT]->y );
  681. // We have a new npnt[RIGHT] now.
  682. DISPDBG((DBGLVL, "Sub: Top: x: %x y: %x "
  683. " Next: x: %x y: %x x: %x y: %x",
  684. pnt[RIGHT]->x, pnt[RIGHT]->y,
  685. npnt[LEFT]->x, npnt[LEFT]->y,
  686. npnt[RIGHT]->x, npnt[RIGHT]->y));
  687. dx[RIGHT] = (npnt[RIGHT]->x - pnt[RIGHT]->x) << 12;
  688. dy[RIGHT] = (npnt[RIGHT]->y - pnt[RIGHT]->y) >> 4;
  689. // Need to ensure we round delta down.
  690. // divide rounds towards zero
  691. if( dx[RIGHT] < 0 )
  692. {
  693. dx[RIGHT] -= dy[RIGHT] - 1;
  694. }
  695. gdx[RIGHT] = dx[RIGHT] / dy[RIGHT];
  696. if( npnt[RIGHT]->y < npnt[LEFT]->y )
  697. {
  698. count = dy[RIGHT];
  699. }
  700. else
  701. {
  702. count = (ABS(npnt[LEFT]->y - pnt[RIGHT]->y)) >> 4;
  703. }
  704. WAIT_PXRX_DMA_TAGS( 3 );
  705. QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub,
  706. FIXtoFIXED(pnt[RIGHT]->x) + xOffFixed );
  707. QUEUE_PXRX_DMA_TAG( __GlintTagdXSub, gdx[RIGHT] );
  708. QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewSub, count );
  709. }
  710. }
  711. // Repeatedly draw more trapezoids until points are equal
  712. // If y values are equal, then we can start again from
  713. // scratch.
  714. if( npnt[LEFT] == npnt[RIGHT] )
  715. {
  716. break;
  717. }
  718. WAIT_PXRX_DMA_TAGS( 7 ); // 7 entries needed to
  719. // render first trapezoid
  720. }
  721. FinishedPolygon:
  722. if( !nClips-- )
  723. {
  724. break;
  725. }
  726. // entries needed to clip and render first trapezoid
  727. WAIT_PXRX_DMA_TAGS( 2 + 7 );
  728. } // while
  729. } // if
  730. DISPDBG((DBGLVL, "bGlintFastFillPolygon: returning TRUE"));
  731. // Need to send ContinueNewSub(0) to flush the framebuffer ??? //azn
  732. if( invalidatedFGBG )
  733. {
  734. WAIT_PXRX_DMA_DWORDS( 3 );
  735. QUEUE_PXRX_DMA_INDEX2( __GlintTagForegroundColor,
  736. __GlintTagBackgroundColor );
  737. QUEUE_PXRX_DMA_DWORD( glintInfo->foregroundColour );
  738. QUEUE_PXRX_DMA_DWORD( glintInfo->backgroundColour );
  739. }
  740. if( (ppdev->cPelSize == GLINTDEPTH32) && invalidatedScissor )
  741. {
  742. WAIT_PXRX_DMA_TAGS( 1 );
  743. QUEUE_PXRX_DMA_TAG( __GlintTagScissorMaxXY, 0x7FFF7FFF );
  744. }
  745. SEND_PXRX_DMA_BATCH;
  746. return TRUE;
  747. /******************************************************************************/
  748. // This is the code to break the polygon into spans.
  749. BreakIntoSpans:
  750. DISPDBG((DBGLVL, "Breaking into spans"));
  751. {
  752. LONG yTrapezoid; // Top scan for next trapezoid
  753. LONG cyTrapezoid; // Number of scans in current trapezoid
  754. POINTFIX* pptfxOld; // Start point in current edge
  755. LONG yStart; // y-position of start point in current edge
  756. LONG dM; // Edge delta in FIX units in x direction
  757. LONG dN; // Edge delta in FIX units in y direction
  758. LONG iEdge;
  759. LONG lQuotient;
  760. LONG lRemainder;
  761. LONG i;
  762. EDGEDATA aed[2];// DDA terms and stuff
  763. EDGEDATA* ped;
  764. LONG tmpXl, tmpXr;
  765. DWORD continueMessage = 0;
  766. // This span code cannot handle a clip list yet!
  767. if( !bTrivialClip )
  768. {
  769. return FALSE;
  770. }
  771. DISPDBG((DBGLVL, "Starting Spans Code"));
  772. /////////////////////////////////////////////////////////////////
  773. // Some Initialization
  774. yTrapezoid = (pptfxTop->y + 15) >> 4;
  775. // Make sure we initialize the DDAs appropriately:
  776. aed[LEFT].cy = 0;
  777. aed[RIGHT].cy = 0;
  778. // For now, guess as to which is the left and which is the right edge:
  779. aed[LEFT].dptfx = -(LONG) sizeof(POINTFIX);
  780. aed[RIGHT].dptfx = sizeof(POINTFIX);
  781. aed[LEFT].pptfx = pptfxTop;
  782. aed[RIGHT].pptfx = pptfxTop;
  783. DISPDBG((DBGLVL, "bGlintFastFillPolygon: Polygon is renderable. "
  784. "Go ahead and render"));
  785. // Work out offset to add to each of the coords downloaded to GLINT
  786. // To get correct results, we need to add on nearly one to each X
  787. // coordinate.
  788. // Also add on offsets to bitmap (This might be an off screen bitmap)
  789. xOffFixed = INTtoFIXED(0);
  790. WAIT_PXRX_DMA_TAGS( 4 );
  791. QUEUE_PXRX_DMA_TAG( __GlintTagCount, 0 );
  792. QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, 0 );
  793. QUEUE_PXRX_DMA_TAG( __GlintTagdXSub, 0);
  794. QUEUE_PXRX_DMA_TAG( __GlintTagdY, INTtoFIXED(1));
  795. DISPDBG((DBGLVL, "Rendering Polygon"));
  796. nSpaces = 0;
  797. NewTrapezoid:
  798. DISPDBG((DBGLVL, "New Trapezoid"));
  799. /////////////////////////////////////////////////////////////////
  800. // DDA initialization
  801. for( iEdge = 1; iEdge >= 0; iEdge-- )
  802. {
  803. ped = &aed[iEdge];
  804. if( ped->cy == 0 )
  805. {
  806. // Need a new DDA:
  807. do
  808. {
  809. cEdges--;
  810. if( cEdges < 0 )
  811. {
  812. DISPDBG((DBGLVL, "bGlintFastFillPolygon: "
  813. "returning TRUE"));
  814. return TRUE;
  815. }
  816. // Find the next left edge, accounting for wrapping:
  817. pptfxOld = ped->pptfx;
  818. ped->pptfx = (POINTFIX*)((BYTE*) ped->pptfx + ped->dptfx);
  819. if( ped->pptfx < pptfxFirst )
  820. {
  821. ped->pptfx = pptfxLast;
  822. }
  823. else if( ped->pptfx > pptfxLast )
  824. {
  825. ped->pptfx = pptfxFirst;
  826. }
  827. // Have to find the edge that spans yTrapezoid:
  828. ped->cy = ((ped->pptfx->y + 15) >> 4) - yTrapezoid;
  829. // With fractional coordinate end points, we may get edges
  830. // that don't cross any scans, in which case we try the
  831. // next one:
  832. } while( ped->cy <= 0 );
  833. // 'pptfx' now points to the end point of the edge spanning
  834. // the scan 'yTrapezoid'.
  835. dN = ped->pptfx->y - pptfxOld->y;
  836. dM = ped->pptfx->x - pptfxOld->x;
  837. ASSERTDD(dN > 0, "Should be going down only");
  838. // Compute the DDA increment terms:
  839. if( dM < 0 )
  840. {
  841. dM = -dM;
  842. if( dM < dN )
  843. { // Can't be '<='
  844. ped->dx = -1;
  845. ped->lErrorUp = dN - dM;
  846. }
  847. else
  848. {
  849. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  850. ped->dx = -lQuotient; // - dM / dN
  851. ped->lErrorUp = lRemainder; // dM % dN
  852. if( ped->lErrorUp > 0 )
  853. {
  854. ped->dx--;
  855. ped->lErrorUp = dN - ped->lErrorUp;
  856. }
  857. }
  858. }
  859. else
  860. {
  861. if( dM < dN )
  862. { // Can't be '<='
  863. ped->dx = 0;
  864. ped->lErrorUp = dM;
  865. }
  866. else
  867. {
  868. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  869. ped->dx = lQuotient; // dM / dN
  870. ped->lErrorUp = lRemainder; // dM % dN
  871. }
  872. }
  873. ped->lErrorDown = dN; // DDA limit
  874. ped->lError = -1; // Error is initially zero (add dN - 1 for
  875. // the ceiling, but subtract off dN so
  876. // that we can check the sign instead of
  877. // comparing to dN)
  878. ped->x = pptfxOld->x;
  879. yStart = pptfxOld->y;
  880. if( (yStart & 15) != 0 )
  881. {
  882. // Advance to the next integer y coordinate
  883. for( i = 16 - (yStart & 15); i != 0; i-- )
  884. {
  885. ped->x += ped->dx;
  886. ped->lError += ped->lErrorUp;
  887. if( ped->lError >= 0 )
  888. {
  889. ped->lError -= ped->lErrorDown;
  890. ped->x++;
  891. }
  892. }
  893. }
  894. if( (ped->x & 15) != 0 )
  895. {
  896. ped->lError -= ped->lErrorDown * (16 - (ped->x & 15));
  897. ped->x += 15; // We'll want the ceiling in just a bit...
  898. }
  899. // Chop off those fractional bits, convert to GLINT format
  900. // and add in the bitmap offset:
  901. ped->x = ped->x >> 4;
  902. ped->lError >>= 4;
  903. // Convert to GLINT format positions and deltas
  904. ped->x = INTtoFIXED(ped->x) + xOffFixed;
  905. ped->dx = INTtoFIXED(ped->dx);
  906. }
  907. }
  908. cyTrapezoid = min(aed[LEFT].cy, aed[RIGHT].cy); // #scans in this trap
  909. aed[LEFT].cy -= cyTrapezoid;
  910. aed[RIGHT].cy -= cyTrapezoid;
  911. yTrapezoid += cyTrapezoid; // Top scan in next trap
  912. SETUP_COLOUR_STUFF;
  913. // If the left and right edges are vertical, simply output as
  914. // a rectangle:
  915. DISPDBG((DBGLVL, "Generate spans for glint"));
  916. do
  917. {
  918. GetMoreFifoEntries( 4 );
  919. // Reset render position to the top of the trapezoid.
  920. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, aed[RIGHT].x );
  921. QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, aed[LEFT].x );
  922. QUEUE_PXRX_DMA_TAG( __GlintTagStartY,
  923. INTtoFIXED(yTrapezoid - cyTrapezoid) );
  924. QUEUE_PXRX_DMA_TAG( __GlintTagRender, renderMsg );
  925. SEND_PXRX_DMA_BATCH;
  926. continueMessage = __GlintTagContinue;
  927. if( ((aed[LEFT].lErrorUp | aed[RIGHT].lErrorUp) == 0) &&
  928. ((aed[LEFT].dx | aed[RIGHT].dx) == 0) &&
  929. (cyTrapezoid > 1) )
  930. {
  931. //////////////////////////////////////////////////////////////
  932. // Vertical-edge special case
  933. DISPDBG((DBGLVL, "Vertical Edge Special Case"));
  934. GetMoreFifoEntries( 1 );
  935. QUEUE_PXRX_DMA_TAG( continueMessage, cyTrapezoid );
  936. continue;
  937. }
  938. while( TRUE )
  939. {
  940. //////////////////////////////////////////////////////////////
  941. // Run the DDAs
  942. DISPDBG((DBGLVL, "Doing a span 0x%x to 0x%x, 0x%x scans left. "
  943. "Continue %s",
  944. aed[LEFT].x, aed[RIGHT].x, cyTrapezoid,
  945. (continueMessage == __GlintTagContinueNewDom) ? "NewDom" :
  946. ((continueMessage == __GlintTagContinue) ? "" : "NewSub")));
  947. GetMoreFifoEntries( 1 );
  948. QUEUE_PXRX_DMA_TAG( continueMessage, 1 );
  949. // We have finished this trapezoid. Go get the next one!
  950. // Advance the right wall:
  951. tmpXr = aed[RIGHT].x;
  952. aed[RIGHT].x += aed[RIGHT].dx;
  953. aed[RIGHT].lError += aed[RIGHT].lErrorUp;
  954. if( aed[RIGHT].lError >= 0 )
  955. {
  956. aed[RIGHT].lError -= aed[RIGHT].lErrorDown;
  957. aed[RIGHT].x += INTtoFIXED(1);
  958. }
  959. // Advance the left wall:
  960. tmpXl = aed[LEFT].x;
  961. aed[LEFT].x += aed[LEFT].dx;
  962. aed[LEFT].lError += aed[LEFT].lErrorUp;
  963. if( aed[LEFT].lError >= 0 )
  964. {
  965. aed[LEFT].lError -= aed[LEFT].lErrorDown;
  966. aed[LEFT].x += INTtoFIXED(1);
  967. }
  968. if( --cyTrapezoid == 0 )
  969. {
  970. break;
  971. }
  972. // Setup the GLINT X registers if we have changed either end.
  973. if( tmpXr != aed[RIGHT].x )
  974. {
  975. if( tmpXl != aed[LEFT].x )
  976. {
  977. GetMoreFifoEntries( 3 );
  978. QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, aed[LEFT].x );
  979. QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewSub, 0 );
  980. }
  981. else
  982. {
  983. GetMoreFifoEntries( 1 );
  984. }
  985. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, aed[RIGHT].x );
  986. continueMessage = __GlintTagContinueNewDom;
  987. }
  988. else if( tmpXl != aed[LEFT].x )
  989. {
  990. GetMoreFifoEntries( 1 );
  991. QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, aed[LEFT].x );
  992. continueMessage = __GlintTagContinueNewSub;
  993. }
  994. }
  995. } while( 0 );
  996. DISPDBG((DBGLVL, "Generate spans for glint done"));
  997. goto NewTrapezoid;
  998. }
  999. if( invalidatedFGBG )
  1000. {
  1001. WAIT_PXRX_DMA_DWORDS( 3 );
  1002. QUEUE_PXRX_DMA_INDEX2( __GlintTagForegroundColor,
  1003. __GlintTagBackgroundColor );
  1004. QUEUE_PXRX_DMA_DWORD( glintInfo->foregroundColour );
  1005. QUEUE_PXRX_DMA_DWORD( glintInfo->backgroundColour );
  1006. }
  1007. SEND_PXRX_DMA_BATCH;
  1008. return TRUE;
  1009. }