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.

1517 lines
49 KiB

  1. /******************************Module*Header**********************************\
  2. *
  3. * *******************
  4. * * GDI SAMPLE CODE *
  5. * *******************
  6. *
  7. * Module Name: fillpath.c
  8. *
  9. * Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
  10. * Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
  11. \*****************************************************************************/
  12. // LATER identify convex polygons and special-case?
  13. // LATER identify vertical edges and special-case?
  14. // LATER move pointed-to variables into automatics in search loops
  15. // LATER punt to the engine with segmented framebuffer callbacks
  16. // LATER handle complex clipping
  17. // LATER coalesce rectangles
  18. #include "precomp.h"
  19. #include "log.h"
  20. #include "gdi.h"
  21. #include "clip.h"
  22. #define ALLOC_TAG ALLOC_TAG_IF2P
  23. //-----------------------------Public*Routine----------------------------------
  24. //
  25. // DrvFillPath
  26. //
  27. // This function fills the specified path with the specified brush and ROP.
  28. // This function detects single convex polygons, and will call to separate
  29. // faster convex polygon code for those cases. This routine also detects
  30. // polygons that are really rectangles, and handles those separately as well.
  31. //
  32. // Parameters
  33. // pso---------Points to a SURFOBJ structure that defines the surface on which
  34. // to draw.
  35. // ppo---------Points to a PATHOBJ structure that defines the path to be filled
  36. // The PATHOBJ_Xxx service routines are provided to enumerate the
  37. // lines, Bezier curves, and other data that make up the path.
  38. // pco---------Points to a CLIPOBJ structure. The CLIPOBJ_Xxx service routines
  39. // are provided to enumerate the clip region as a set of rectangles.
  40. // pbo---------Points to a BRUSHOBJ structure that defines the pattern and
  41. // colors to fill with.
  42. // pptlBrushOrg-Points to a POINTL structure that defines the brush origin,
  43. // which is used to align the brush pattern on the device.
  44. // mix---------Defines the foreground and background raster operations to use
  45. // for the brush.
  46. // flOptions---Specifies either FP_WINDINGMODE, indicating that a winding mode
  47. // fill should be performed, or FP_ALTERNATEMODE, indicating that
  48. // an alternating mode fill should be performed. All other flags
  49. // should be ignored.
  50. //
  51. // Return Value
  52. // The return value is TRUE if the driver is able to fill the path. If the
  53. // path or clipping is too complex to be handled by the driver and should be
  54. // handled by GDI, the return value is FALSE, and an error code is not logged.
  55. // If the driver encounters an unexpected error, such as not being able to
  56. // realize the brush, the return value is DDI_ERROR, and an error code is
  57. // logged.
  58. //
  59. // Comments
  60. // GDI can call DrvFillPath to fill a path on a device-managed surface. When
  61. // deciding whether to call this function, GDI compares the fill requirements
  62. // with the following flags in the flGraphicsCaps member of the DEVINFO
  63. // structure: GCAPS_BEZIERS, GCAPS_ALTERNATEFILL, and GCAPS_WINDINGFILL.
  64. //
  65. // The mix mode defines how the incoming pattern should be mixed with the data
  66. // already on the device surface. The MIX data type consists of two ROP2 values
  67. // packed into a single ULONG. The low-order byte defines the foreground raster
  68. // operation; the next byte defines the background raster operation.
  69. //
  70. // Multiple polygons in a path cannot be treated as being disjoint; The fill
  71. // must consider all the points in the path. That is, if the path contains
  72. // multiple polygons, you cannot simply draw one polygon after the other
  73. // (unless they don't overlap).
  74. //
  75. // This function is an optional entry point for the driver. but is recommended
  76. // for good performance. To get GDI to call this function, not only do you
  77. // have to HOOK_FILLPATH, you have to set GCAPS_ALTERNATEFILL and/or
  78. // GCAPS_WINDINGFILL.
  79. //
  80. //-----------------------------------------------------------------------------
  81. BOOL
  82. DrvFillPath(SURFOBJ* pso,
  83. PATHOBJ* ppo,
  84. CLIPOBJ* pco,
  85. BRUSHOBJ* pbo,
  86. POINTL* pptlBrush,
  87. MIX mix,
  88. FLONG flOptions)
  89. {
  90. GFNPB pb;
  91. BYTE jClipping; // Clipping type
  92. EDGE* pCurrentEdge;
  93. EDGE AETHead; // Dummy head/tail node & sentinel for Active Edge
  94. // Table
  95. EDGE* pAETHead; // Pointer to AETHead
  96. EDGE GETHead; // Dummy head/tail node & sentinel for Global Edge
  97. // Table
  98. EDGE* pGETHead; // Pointer to GETHead
  99. EDGE* pFreeEdges = NULL; // Pointer to memory free for use to store edges
  100. ULONG ulNumRects; // # of rectangles to draw currently in rectangle
  101. // list
  102. RECTL* prclRects; // Pointer to start of rectangle draw list
  103. INT iCurrentY; // Scan line for which we're currently scanning out
  104. // the fill
  105. BOOL bMore;
  106. PATHDATA pd;
  107. RECTL ClipRect;
  108. PDev* ppdev;
  109. BOOL bRetVal=FALSE; // FALSE until proven TRUE
  110. BOOL bMemAlloced=FALSE; // FALSE until proven TRUE
  111. FLONG flFirstRecord;
  112. POINTFIX* pPtFxTmp;
  113. ULONG ulPtFxTmp;
  114. POINTFIX aptfxBuf[NUM_BUFFER_POINTS];
  115. ULONG ulRop4;
  116. DBG_GDI((6, "DrvFillPath called"));
  117. pb.psurfDst = (Surf*)pso->dhsurf;
  118. pb.pco = pco;
  119. ppdev = pb.psurfDst->ppdev;
  120. pb.ppdev = ppdev;
  121. pb.ulRop4 = gaMix[mix & 0xFF] | (gaMix[mix >> 8] << 8);
  122. ulRop4 = pb.ulRop4;
  123. //@@BEGIN_DDKSPLIT
  124. #if MULTITHREADED
  125. if(pb.ppdev->ulLockCount)
  126. {
  127. DBG_GDI((MT_LOG_LEVEL, "DrvBitBlt: re-entered! %d", pb.ppdev->ulLockCount));
  128. }
  129. EngAcquireSemaphore(pb.ppdev->hsemLock);
  130. pb.ppdev->ulLockCount++;
  131. #endif
  132. //@@END_DDKSPLIT
  133. vCheckGdiContext(ppdev);
  134. //
  135. // There's nothing to do if there are only one or two points
  136. //
  137. if ( ppo->cCurves <= 2 )
  138. {
  139. goto ReturnTrue;
  140. }
  141. //
  142. // Pass the surface off to GDI if it's a device bitmap that we've uploaded
  143. // to the system memory.
  144. //
  145. if ( pb.psurfDst->flags == SF_SM )
  146. {
  147. DBG_GDI((1, "dest surface is in system memory. Punt it back"));
  148. //@@BEGIN_DDKSPLIT
  149. #if MULTITHREADED
  150. pb.ppdev->ulLockCount--;
  151. EngReleaseSemaphore(pb.ppdev->hsemLock);
  152. #endif
  153. //@@END_DDKSPLIT
  154. return ( EngFillPath(pso, ppo, pco, pbo, pptlBrush, mix, flOptions));
  155. }
  156. //
  157. // Set up the clipping
  158. //
  159. if ( pco == (CLIPOBJ*)NULL )
  160. {
  161. //
  162. // No CLIPOBJ provided, so we don't have to worry about clipping
  163. //
  164. jClipping = DC_TRIVIAL;
  165. }
  166. else
  167. {
  168. //
  169. // Use the CLIPOBJ-provided clipping
  170. //
  171. jClipping = pco->iDComplexity;
  172. }
  173. //
  174. // Now we are sure the surface we are going to draw is in the video memory
  175. //
  176. // Set default fill as solid fill
  177. //
  178. pb.pgfn = vSolidFillWithRop;
  179. pb.solidColor = 0; //Assume we don't need a pattern
  180. pb.prbrush = NULL;
  181. //
  182. // It is too difficult to determine interaction between
  183. // multiple paths, if there is more than one, skip this
  184. //
  185. PATHOBJ_vEnumStart(ppo);
  186. bMore = PATHOBJ_bEnum(ppo, &pd);
  187. //
  188. // First we need to check if we need a pattern or not
  189. //
  190. if ( (((ulRop4 & 0xff00) >> 8) != (ulRop4 & 0x00ff))
  191. || ((((ulRop4 >> 4) ^ (ulRop4)) & 0xf0f) != 0) )
  192. {
  193. pb.solidColor = pbo->iSolidColor;
  194. //
  195. // Check to see if it is a non-solid brush (-1)
  196. //
  197. if ( pbo->iSolidColor == -1 )
  198. {
  199. //
  200. // Get the driver's realized brush
  201. //
  202. pb.prbrush = (RBrush*)pbo->pvRbrush;
  203. //
  204. // If it hasn't been realized, do it
  205. // Note: GDI will call DrvRealizeBrsuh to fullfill this task. So the
  206. // driver should have this function ready
  207. //
  208. if ( pb.prbrush == NULL )
  209. {
  210. DBG_GDI((7, "Realizing brush"));
  211. pb.prbrush = (RBrush*)BRUSHOBJ_pvGetRbrush(pbo);
  212. if ( pb.prbrush == NULL )
  213. {
  214. //
  215. // If we can't realize it, nothing we can do
  216. //
  217. //@@BEGIN_DDKSPLIT
  218. #if MULTITHREADED
  219. pb.ppdev->ulLockCount--;
  220. EngReleaseSemaphore(pb.ppdev->hsemLock);
  221. #endif
  222. //@@END_DDKSPLIT
  223. return(FALSE);
  224. }
  225. DBG_GDI((7, "Brsuh realizing done"));
  226. }// Realize brush
  227. pb.pptlBrush = pptlBrush;
  228. //
  229. // Check if brush pattern is 1 BPP or not
  230. // Note: This is set in DrvRealizeBrush
  231. //
  232. if ( pb.prbrush->fl & RBRUSH_2COLOR )
  233. {
  234. //
  235. // 1 BPP pattern. Do a Mono fill
  236. //
  237. pb.pgfn = vMonoPatFill;
  238. }
  239. else
  240. {
  241. //
  242. // Pattern is more than 1 BPP. Do color pattern fill
  243. //
  244. pb.pgfn = vPatFill;
  245. DBG_GDI((7, "Skip Fast Fill Color Pattern"));
  246. //
  247. // P2 can not handle fast filled patterns
  248. //
  249. goto SkipFastFill;
  250. }
  251. }// Handle non-solid brush
  252. }// Blackness check
  253. //
  254. // For solid brush, we can use FastFill
  255. //
  256. if ( bMore )
  257. {
  258. //
  259. // FastFill only knows how to take a single contiguous buffer
  260. // of points. Unfortunately, GDI sometimes hands us paths
  261. // that are split over multiple path data records. Convex
  262. // figures such as Ellipses, Pies and RoundRects are almost
  263. // always given in multiple records. Since probably 90% of
  264. // multiple record paths could still be done by FastFill, for
  265. // those cases we simply copy the points into a contiguous
  266. // buffer...
  267. //
  268. // First make sure that the entire path would fit in the
  269. // temporary buffer, and make sure the path isn't comprised
  270. // of more than one subpath:
  271. //
  272. if ( (ppo->cCurves >= NUM_BUFFER_POINTS)
  273. ||(pd.flags & PD_ENDSUBPATH) )
  274. {
  275. goto SkipFastFill;
  276. }
  277. pPtFxTmp = &aptfxBuf[0];
  278. //
  279. // Copy one vertex over to pPtFxTmp from pd(path data)
  280. //
  281. RtlCopyMemory(pPtFxTmp, pd.pptfx, sizeof(POINTFIX) * pd.count);
  282. //
  283. // Move the memory pointer over to next structure
  284. //
  285. pPtFxTmp += pd.count;
  286. ulPtFxTmp = pd.count;
  287. flFirstRecord = pd.flags; // Remember PD_BEGINSUBPATH flag
  288. //
  289. // Loop to get all the vertex info. After the loop, all the vertex info
  290. // will be in array aptfxBuf[]
  291. //
  292. do
  293. {
  294. bMore = PATHOBJ_bEnum(ppo, &pd);
  295. RtlCopyMemory(pPtFxTmp, pd.pptfx, sizeof(POINTFIX) * pd.count);
  296. ulPtFxTmp += pd.count;
  297. pPtFxTmp += pd.count;
  298. } while ( !(pd.flags & PD_ENDSUBPATH) );
  299. //
  300. // Fake up the path data record
  301. //
  302. pd.pptfx = &aptfxBuf[0];
  303. pd.count = ulPtFxTmp;
  304. pd.flags |= flFirstRecord;
  305. //
  306. // If there's more than one subpath, we can't call FastFill
  307. //
  308. DBG_GDI((7, "More than one subpath!"));
  309. if ( bMore )
  310. {
  311. goto SkipFastFill;
  312. }
  313. }// if ( bMore )
  314. //
  315. // Fast polygon fill
  316. //
  317. if ( bFillPolygon(ppdev, (Surf*)pso->dhsurf, pd.count,
  318. pd.pptfx, pb.solidColor,
  319. ulRop4,
  320. pco, pb.prbrush, pptlBrush) )
  321. {
  322. DBG_GDI((7, "Fast Fill Succeeded"));
  323. InputBufferFlush(ppdev);
  324. //@@BEGIN_DDKSPLIT
  325. #if MULTITHREADED
  326. pb.ppdev->ulLockCount--;
  327. EngReleaseSemaphore(pb.ppdev->hsemLock);
  328. #endif
  329. //@@END_DDKSPLIT
  330. return (TRUE);
  331. }
  332. SkipFastFill:
  333. DBG_GDI((7, "Fast Fill Skipped"));
  334. if ( jClipping != DC_TRIVIAL )
  335. {
  336. if ( jClipping != DC_RECT )
  337. {
  338. DBG_GDI((7, "Complex Clipping"));
  339. //
  340. // There is complex clipping; let GDI fill the path
  341. //
  342. goto ReturnFalse;
  343. }
  344. //
  345. // Clip to the clip rectangle
  346. //
  347. ClipRect = pco->rclBounds;
  348. }
  349. else
  350. {
  351. //
  352. // So the y-clipping code doesn't do any clipping
  353. // We don't blow the values out when we scale up to GIQ
  354. //
  355. ClipRect.top = (LONG_MIN + 1) / 16; // +1 to avoid compiler problem
  356. ClipRect.bottom = LONG_MAX / 16;
  357. }
  358. //
  359. // Set up working storage in the temporary buffer, storage for list of
  360. // rectangles to draw
  361. // Note: ppdev->pvTmpBuffer is allocated in DrvEnableSurface() in enable.c
  362. // The purpose of using ppdev->pvTmpBuffer is to save us from having to
  363. // allocate and free the temp space inside high frequency calls. It was
  364. // allocated for TMP_BUFFER_SIZE bytes and will be freed in
  365. // DrvDeleteSurface()
  366. //
  367. prclRects = (RECTL*)ppdev->pvTmpBuffer;
  368. if ( !bMore )
  369. {
  370. RECTL* pTmpRect;
  371. INT cPoints = pd.count;
  372. //
  373. // The count can't be less than three, because we got all the edges
  374. // in this subpath, and above we checked that there were at least
  375. // three edges
  376. //
  377. // If the count is four, check to see if the polygon is really a
  378. // rectangle since we can really speed that up. We'll also check for
  379. // five with the first and last points the same.
  380. //
  381. // ??? we have already done the memcpy for the pd data. shall we use it
  382. //
  383. if ( ( cPoints == 4 )
  384. ||( ( cPoints == 5 )
  385. &&(pd.pptfx[0].x == pd.pptfx[4].x)
  386. &&(pd.pptfx[0].y == pd.pptfx[4].y) ) )
  387. {
  388. //
  389. // Get storage space for this temp rectangle
  390. //
  391. pTmpRect = prclRects;
  392. //
  393. // We have to start somewhere to assume that most
  394. // applications specify the top left point first
  395. // We want to check that the first two points are
  396. // either vertically or horizontally aligned. If
  397. // they are then we check that the last point [3]
  398. // is either horizontally or vertically aligned,
  399. // and finally that the 3rd point [2] is aligned
  400. // with both the first point and the last point
  401. //
  402. pTmpRect->top = pd.pptfx[0].y - 1 & FIX_MASK;
  403. pTmpRect->left = pd.pptfx[0].x - 1 & FIX_MASK;
  404. pTmpRect->right = pd.pptfx[1].x - 1 & FIX_MASK;
  405. //
  406. // Check if the first two points are vertically alligned
  407. //
  408. if ( pTmpRect->left ^ pTmpRect->right )
  409. {
  410. //
  411. // The first two points are not vertically alligned
  412. // Let's see if these two points are horizontal alligned
  413. //
  414. if ( pTmpRect->top ^ (pd.pptfx[1].y - 1 & FIX_MASK) )
  415. {
  416. //
  417. // The first two points are not horizontally alligned
  418. // So it is not a rectangle
  419. //
  420. goto not_rectangle;
  421. }
  422. //
  423. // Up to now, the first two points are horizontally alligned,
  424. // but not vertically alligned. We need to check if the first
  425. // point vertically alligned with the 4th point
  426. //
  427. if ( pTmpRect->left ^ (pd.pptfx[3].x - 1 & FIX_MASK) )
  428. {
  429. //
  430. // The first point is not vertically alligned with the 4th
  431. // point either. So this is not a rectangle
  432. //
  433. goto not_rectangle;
  434. }
  435. //
  436. // Check if the 2nd point and the 3rd point are vertically aligned
  437. //
  438. if ( pTmpRect->right ^ (pd.pptfx[2].x - 1 & FIX_MASK) )
  439. {
  440. //
  441. // The 2nd point and the 3rd point are not vertically aligned
  442. // So this is not a rectangle
  443. //
  444. goto not_rectangle;
  445. }
  446. //
  447. // Check to see if the 3rd and 4th points are horizontally
  448. // alligned. If not, then it is not a rectangle
  449. //
  450. pTmpRect->bottom = pd.pptfx[2].y - 1 & FIX_MASK;
  451. if ( pTmpRect->bottom ^ (pd.pptfx[3].y - 1 & FIX_MASK) )
  452. {
  453. goto not_rectangle;
  454. }
  455. }// Check if the first two points are vertically alligned
  456. else
  457. {
  458. //
  459. // The first two points are vertically alligned. Now we need to
  460. // check if the 1st point and the 4th point are horizontally
  461. // aligned. If not, then this is not a rectangle
  462. //
  463. if ( pTmpRect->top ^ (pd.pptfx[3].y - 1 & FIX_MASK) )
  464. {
  465. goto not_rectangle;
  466. }
  467. //
  468. // Check if the 2nd point and the 3rd point are horizontally
  469. // aligned. If not, then this is not a rectangle
  470. //
  471. pTmpRect->bottom = pd.pptfx[1].y - 1 & FIX_MASK;
  472. if ( pTmpRect->bottom ^ (pd.pptfx[2].y - 1 & FIX_MASK) )
  473. {
  474. goto not_rectangle;
  475. }
  476. //
  477. // Check if the 3rd point and the 4th point are vertically
  478. // aligned. If not, then this is not a rectangle
  479. //
  480. pTmpRect->right = pd.pptfx[2].x - 1 & FIX_MASK;
  481. if ( pTmpRect->right ^ (pd.pptfx[3].x - 1 & FIX_MASK) )
  482. {
  483. goto not_rectangle;
  484. }
  485. }
  486. //
  487. // We have a rectangle now. Do some adjustment here first
  488. // If the left is greater than the right then
  489. // swap them so the blt code won't have problem
  490. //
  491. if ( pTmpRect->left > pTmpRect->right )
  492. {
  493. FIX temp;
  494. temp = pTmpRect->left;
  495. pTmpRect->left = pTmpRect->right;
  496. pTmpRect->right = temp;
  497. }
  498. else
  499. {
  500. //
  501. // If left == right there's nothing to draw
  502. //
  503. if ( pTmpRect->left == pTmpRect->right )
  504. {
  505. DBG_GDI((7, "Nothing to draw"));
  506. goto ReturnTrue;
  507. }
  508. }// Adjust right and left edge
  509. //
  510. // Shift the values to get pixel coordinates
  511. //
  512. pTmpRect->left = (pTmpRect->left >> FIX_SHIFT) + 1;
  513. pTmpRect->right = (pTmpRect->right >> FIX_SHIFT) + 1;
  514. //
  515. // Adjust the top and bottom coordiantes if necessary
  516. //
  517. if ( pTmpRect->top > pTmpRect->bottom )
  518. {
  519. FIX temp;
  520. temp = pTmpRect->top;
  521. pTmpRect->top = pTmpRect->bottom;
  522. pTmpRect->bottom = temp;
  523. }
  524. else
  525. {
  526. if ( pTmpRect->top == pTmpRect->bottom )
  527. {
  528. DBG_GDI((7, "Nothing to draw"));
  529. goto ReturnTrue;
  530. }
  531. }
  532. //
  533. // Shift the values to get pixel coordinates
  534. //
  535. pTmpRect->top = (pTmpRect->top >> FIX_SHIFT) + 1;
  536. pTmpRect->bottom = (pTmpRect->bottom >> FIX_SHIFT) + 1;
  537. //
  538. // Finally, check for clipping
  539. //
  540. if ( jClipping == DC_RECT )
  541. {
  542. //
  543. // Clip to the clip rectangle
  544. //
  545. if ( !bIntersect(pTmpRect, &ClipRect, pTmpRect) )
  546. {
  547. //
  548. // Totally clipped, nothing to do
  549. //
  550. DBG_GDI((7, "Nothing to draw"));
  551. goto ReturnTrue;
  552. }
  553. }
  554. //
  555. // If we get here then the polygon is a rectangle,
  556. // set count to 1 and goto bottom to draw it
  557. //
  558. ulNumRects = 1;
  559. goto draw_remaining_rectangles;
  560. }// Check to see if it is a rectangle
  561. not_rectangle:
  562. ;
  563. }// if ( !bMore )
  564. //
  565. // Do we have enough memory for all the edges?
  566. // LATER does cCurves include closure????
  567. //
  568. if ( ppo->cCurves > MAX_EDGES )
  569. {
  570. //
  571. // Try to allocate enough memory
  572. //
  573. pFreeEdges = (EDGE*)ENGALLOCMEM(0, (ppo->cCurves * sizeof(EDGE)),
  574. ALLOC_TAG);
  575. if ( pFreeEdges == NULL )
  576. {
  577. DBG_GDI((1, "Can't allocate memory for %d edges", ppo->cCurves));
  578. //
  579. // Too many edges; let GDI fill the path
  580. //
  581. goto ReturnFalse;
  582. }
  583. else
  584. {
  585. //
  586. // Set a flag to indicate that we have allocate the memory so that
  587. // we can free it later
  588. //
  589. bMemAlloced = TRUE;
  590. }
  591. }// if ( ppo->cCurves > MAX_EDGES )
  592. else
  593. {
  594. //
  595. // If the total number of edges doesn't exceed the MAX_EDGES, then just
  596. // use our handy temporary buffer (it's big enough)
  597. //
  598. pFreeEdges = (EDGE*)((BYTE*)ppdev->pvTmpBuffer + RECT_BYTES);
  599. }
  600. //
  601. // Initialize an empty list of rectangles to fill
  602. //
  603. ulNumRects = 0;
  604. //
  605. // Enumerate the path edges and build a Global Edge Table (GET) from them
  606. // in YX-sorted order.
  607. //
  608. pGETHead = &GETHead;
  609. if ( !bConstructGET(pGETHead, pFreeEdges, ppo, &pd, bMore, &ClipRect) )
  610. {
  611. DBG_GDI((7, "Outside Range"));
  612. goto ReturnFalse; // outside GDI's 2**27 range
  613. }
  614. //
  615. // Create an empty AET with the head node also a tail sentinel
  616. //
  617. pAETHead = &AETHead;
  618. AETHead.pNext = pAETHead; // Mark that the AET is empty
  619. AETHead.X = 0x7FFFFFFF; // This is greater than any valid X value, so
  620. // searches will always terminate
  621. //
  622. // Top scan of polygon is the top of the first edge we come to
  623. //
  624. iCurrentY = ((EDGE*)GETHead.pNext)->Y;
  625. //
  626. // Loop through all the scans in the polygon, adding edges from the GET to
  627. // the Active Edge Table (AET) as we come to their starts, and scanning out
  628. // the AET at each scan into a rectangle list. Each time it fills up, the
  629. // rectangle list is passed to the filling routine, and then once again at
  630. // the end if any rectangles remain undrawn. We continue so long as there
  631. // are edges to be scanned out
  632. //
  633. while ( 1 )
  634. {
  635. //
  636. // Advance the edges in the AET one scan, discarding any that have
  637. // reached the end (if there are any edges in the AET)
  638. //
  639. if ( AETHead.pNext != pAETHead )
  640. {
  641. vAdvanceAETEdges(pAETHead);
  642. }
  643. //
  644. // If the AET is empty, done if the GET is empty, else jump ahead to
  645. // the next edge in the GET; if the AET isn't empty, re-sort the AET
  646. //
  647. if ( AETHead.pNext == pAETHead )
  648. {
  649. if ( GETHead.pNext == pGETHead )
  650. {
  651. //
  652. // Done if there are no edges in either the AET or the GET
  653. //
  654. break;
  655. }
  656. //
  657. // There are no edges in the AET, so jump ahead to the next edge in
  658. // the GET
  659. //
  660. iCurrentY = ((EDGE*)GETHead.pNext)->Y;
  661. }
  662. else
  663. {
  664. //
  665. // Re-sort the edges in the AET by X coordinate, if there are at
  666. // least two edges in the AET (there could be one edge if the
  667. // balancing edge hasn't yet been added from the GET)
  668. //
  669. if ( ((EDGE*)AETHead.pNext)->pNext != pAETHead )
  670. {
  671. vXSortAETEdges(pAETHead);
  672. }
  673. }
  674. //
  675. // Move any new edges that start on this scan from the GET to the AET;
  676. // bother calling only if there's at least one edge to add
  677. //
  678. if ( ((EDGE*)GETHead.pNext)->Y == iCurrentY )
  679. {
  680. vMoveNewEdges(pGETHead, pAETHead, iCurrentY);
  681. }
  682. //
  683. // Scan the AET into rectangles to fill (there's always at least one
  684. // edge pair in the AET)
  685. //
  686. pCurrentEdge = (EDGE*)AETHead.pNext; // point to the first edge
  687. do
  688. {
  689. INT iLeftEdge;
  690. //
  691. // The left edge of any given edge pair is easy to find; it's just
  692. // wherever we happen to be currently
  693. //
  694. iLeftEdge = pCurrentEdge->X;
  695. //
  696. // Find the matching right edge according to the current fill rule
  697. //
  698. if ( (flOptions & FP_WINDINGMODE) != 0 )
  699. {
  700. INT iWindingCount;
  701. //
  702. // Do winding fill; scan across until we've found equal numbers
  703. // of up and down edges
  704. //
  705. iWindingCount = pCurrentEdge->iWindingDirection;
  706. do
  707. {
  708. pCurrentEdge = (EDGE*)pCurrentEdge->pNext;
  709. iWindingCount += pCurrentEdge->iWindingDirection;
  710. } while ( iWindingCount != 0 );
  711. }
  712. else
  713. {
  714. //
  715. // Odd-even fill; the next edge is the matching right edge
  716. //
  717. pCurrentEdge = (EDGE*)pCurrentEdge->pNext;
  718. }
  719. //
  720. // See if the resulting span encompasses at least one pixel, and
  721. // add it to the list of rectangles to draw if so
  722. //
  723. if ( iLeftEdge < pCurrentEdge->X )
  724. {
  725. //
  726. // We've got an edge pair to add to the list to be filled; see
  727. // if there's room for one more rectangle
  728. //
  729. if ( ulNumRects >= MAX_PATH_RECTS )
  730. {
  731. //
  732. // No more room; draw the rectangles in the list and reset
  733. // it to empty
  734. //
  735. pb.lNumRects = ulNumRects;
  736. pb.pRects = prclRects;
  737. pb.pgfn(&pb);
  738. //
  739. // Reset the list to empty
  740. //
  741. ulNumRects = 0;
  742. }
  743. //
  744. // Add the rectangle representing the current edge pair
  745. //
  746. if ( jClipping == DC_RECT )
  747. {
  748. //
  749. // Clipped
  750. // Clip to left
  751. //
  752. prclRects[ulNumRects].left = max(iLeftEdge, ClipRect.left);
  753. //
  754. // Clip to right
  755. //
  756. prclRects[ulNumRects].right =
  757. min(pCurrentEdge->X, ClipRect.right);
  758. //
  759. // Draw only if not fully clipped
  760. //
  761. if ( prclRects[ulNumRects].left
  762. < prclRects[ulNumRects].right )
  763. {
  764. prclRects[ulNumRects].top = iCurrentY;
  765. prclRects[ulNumRects].bottom = iCurrentY + 1;
  766. ulNumRects++;
  767. }
  768. }
  769. else
  770. {
  771. //
  772. // Unclipped
  773. //
  774. prclRects[ulNumRects].top = iCurrentY;
  775. prclRects[ulNumRects].bottom = iCurrentY + 1;
  776. prclRects[ulNumRects].left = iLeftEdge;
  777. prclRects[ulNumRects].right = pCurrentEdge->X;
  778. ulNumRects++;
  779. }
  780. }
  781. } while ( (pCurrentEdge = (EDGE*)pCurrentEdge->pNext) != pAETHead );
  782. iCurrentY++; // next scan
  783. }// Loop through all the scans in the polygon
  784. //
  785. // Draw the remaining rectangles, if there are any
  786. //
  787. draw_remaining_rectangles:
  788. if ( ulNumRects > 0 )
  789. {
  790. pb.lNumRects = ulNumRects;
  791. pb.pRects = prclRects;
  792. pb.pgfn(&pb);
  793. }
  794. ReturnTrue:
  795. DBG_GDI((7, "Drawn"));
  796. bRetVal = TRUE; // done successfully
  797. ReturnFalse:
  798. //
  799. // bRetVal is originally false. If you jumped to ReturnFalse from somewhere,
  800. // then it will remain false, and be returned.
  801. //
  802. if ( bMemAlloced )
  803. {
  804. //
  805. // We did allocate memory, so release it
  806. //
  807. ENGFREEMEM(pFreeEdges);
  808. }
  809. DBG_GDI((6, "Returning %s", bRetVal ? "True" : "False"));
  810. InputBufferFlush(ppdev);
  811. //@@BEGIN_DDKSPLIT
  812. #if MULTITHREADED
  813. pb.ppdev->ulLockCount--;
  814. EngReleaseSemaphore(pb.ppdev->hsemLock);
  815. #endif
  816. //@@END_DDKSPLIT
  817. return (bRetVal);
  818. }// DrvFillPath()
  819. //-----------------------------------------------------------------------------
  820. //
  821. // void vAdvanceAETEdges(EDGE* pAETHead)
  822. //
  823. // Advance the edges in the AET to the next scan, dropping any for which we've
  824. // done all scans. Assumes there is at least one edge in the AET.
  825. //
  826. //-----------------------------------------------------------------------------
  827. VOID
  828. vAdvanceAETEdges(EDGE* pAETHead)
  829. {
  830. EDGE* pLastEdge;
  831. EDGE* pCurrentEdge;
  832. pLastEdge = pAETHead;
  833. pCurrentEdge = (EDGE*)pLastEdge->pNext;
  834. do
  835. {
  836. //
  837. // Count down this edge's remaining scans
  838. //
  839. if ( --pCurrentEdge->iScansLeft == 0 )
  840. {
  841. //
  842. // We've done all scans for this edge; drop this edge from the AET
  843. //
  844. pLastEdge->pNext = pCurrentEdge->pNext;
  845. }
  846. else
  847. {
  848. //
  849. // Advance the edge's X coordinate for a 1-scan Y advance
  850. // Advance by the minimum amount
  851. //
  852. pCurrentEdge->X += pCurrentEdge->iXWhole;
  853. //
  854. // Advance the error term and see if we got one extra pixel this
  855. // time
  856. //
  857. pCurrentEdge->iErrorTerm += pCurrentEdge->iErrorAdjustUp;
  858. if ( pCurrentEdge->iErrorTerm >= 0 )
  859. {
  860. //
  861. // The error term turned over, so adjust the error term and
  862. // advance the extra pixel
  863. //
  864. pCurrentEdge->iErrorTerm -= pCurrentEdge->iErrorAdjustDown;
  865. pCurrentEdge->X += pCurrentEdge->iXDirection;
  866. }
  867. pLastEdge = pCurrentEdge;
  868. }
  869. } while ((pCurrentEdge = (EDGE *)pLastEdge->pNext) != pAETHead);
  870. }// vAdvanceAETEdges()
  871. //-----------------------------------------------------------------------------
  872. //
  873. // VOID vXSortAETEdges(EDGE* pAETHead)
  874. //
  875. // X-sort the AET, because the edges may have moved around relative to
  876. // one another when we advanced them. We'll use a multipass bubble
  877. // sort, which is actually okay for this application because edges
  878. // rarely move relative to one another, so we usually do just one pass.
  879. // Also, this makes it easy to keep just a singly-linked list. Assumes there
  880. // are at least two edges in the AET.
  881. //
  882. //-----------------------------------------------------------------------------
  883. VOID
  884. vXSortAETEdges(EDGE *pAETHead)
  885. {
  886. BOOL bEdgesSwapped;
  887. EDGE* pLastEdge;
  888. EDGE* pCurrentEdge;
  889. EDGE* pNextEdge;
  890. do
  891. {
  892. bEdgesSwapped = FALSE;
  893. pLastEdge = pAETHead;
  894. pCurrentEdge = (EDGE *)pLastEdge->pNext;
  895. pNextEdge = (EDGE *)pCurrentEdge->pNext;
  896. do
  897. {
  898. if ( pNextEdge->X < pCurrentEdge->X )
  899. {
  900. //
  901. // Next edge is to the left of the current edge; swap them
  902. //
  903. pLastEdge->pNext = pNextEdge;
  904. pCurrentEdge->pNext = pNextEdge->pNext;
  905. pNextEdge->pNext = pCurrentEdge;
  906. bEdgesSwapped = TRUE;
  907. //
  908. // Continue sorting before the edge we just swapped; it might
  909. // move farther yet
  910. //
  911. pCurrentEdge = pNextEdge;
  912. }
  913. pLastEdge = pCurrentEdge;
  914. pCurrentEdge = (EDGE *)pLastEdge->pNext;
  915. } while ( (pNextEdge = (EDGE*)pCurrentEdge->pNext) != pAETHead );
  916. } while ( bEdgesSwapped );
  917. }// vXSortAETEdges()
  918. //-----------------------------------------------------------------------------
  919. //
  920. // VOID vMoveNewEdges(EDGE* pGETHead, EDGE* pAETHead, INT iCurrentY)
  921. //
  922. // Moves all edges that start on the current scan from the GET to the AET in
  923. // X-sorted order. Parameters are pointer to head of GET and pointer to dummy
  924. // edge at head of AET, plus current scan line. Assumes there's at least one
  925. // edge to be moved.
  926. //
  927. //-----------------------------------------------------------------------------
  928. VOID
  929. vMoveNewEdges(EDGE* pGETHead,
  930. EDGE* pAETHead,
  931. INT iCurrentY)
  932. {
  933. EDGE* pCurrentEdge = pAETHead;
  934. EDGE* pGETNext = (EDGE*)pGETHead->pNext;
  935. do
  936. {
  937. //
  938. // Scan through the AET until the X-sorted insertion point for this
  939. // edge is found. We can continue from where the last search left
  940. // off because the edges in the GET are in X sorted order, as is
  941. // the AET. The search always terminates because the AET sentinel
  942. // is greater than any valid X
  943. //
  944. while ( pGETNext->X > ((EDGE *)pCurrentEdge->pNext)->X )
  945. {
  946. pCurrentEdge = (EDGE*)pCurrentEdge->pNext;
  947. }
  948. //
  949. // We've found the insertion point; add the GET edge to the AET, and
  950. // remove it from the GET
  951. //
  952. pGETHead->pNext = pGETNext->pNext;
  953. pGETNext->pNext = pCurrentEdge->pNext;
  954. pCurrentEdge->pNext = pGETNext;
  955. pCurrentEdge = pGETNext; // continue insertion search for the next
  956. // GET edge after the edge we just added
  957. pGETNext = (EDGE*)pGETHead->pNext;
  958. } while (pGETNext->Y == iCurrentY);
  959. }// vMoveNewEdges()
  960. //-----------------------------------------------------------------------------
  961. //
  962. // BOOL (EDGE* pGETHead, EDGE* pAETHead, INT iCurrentY)
  963. //
  964. // Build the Global Edge Table from the path. There must be enough memory in
  965. // the free edge area to hold all edges. The GET is constructed in Y-X order,
  966. // and has a head/tail/sentinel node at pGETHead.
  967. //
  968. //-----------------------------------------------------------------------------
  969. BOOL
  970. bConstructGET(EDGE* pGETHead,
  971. EDGE* pFreeEdges,
  972. PATHOBJ* ppo,
  973. PATHDATA* pd,
  974. BOOL bMore,
  975. RECTL* pClipRect)
  976. {
  977. POINTFIX pfxPathStart; // point that started the current subpath
  978. POINTFIX pfxPathPrevious; // point before the current point in a subpath;
  979. // starts the current edge
  980. //
  981. // Create an empty GET with the head node also a tail sentinel
  982. //
  983. pGETHead->pNext = pGETHead; // mark that the GET is empty
  984. pGETHead->Y = 0x7FFFFFFF; // this is greater than any valid Y value, so
  985. // Searches will always terminate
  986. //
  987. // Note: PATHOBJ_vEnumStart is implicitly performed by engine
  988. // already and first path is enumerated by the caller
  989. // so here we don't need to call it again.
  990. //
  991. next_subpath:
  992. //
  993. // Make sure the PATHDATA is not empty (is this necessary)???
  994. //
  995. if ( pd->count != 0 )
  996. {
  997. //
  998. // If first point starts a subpath, remember it as such
  999. // and go on to the next point, so we can get an edge
  1000. //
  1001. if ( pd->flags & PD_BEGINSUBPATH )
  1002. {
  1003. //
  1004. // The first point starts the subpath; Remember it
  1005. //
  1006. pfxPathStart = *pd->pptfx; // the subpath starts here
  1007. pfxPathPrevious = *pd->pptfx; // this point starts the next edge
  1008. pd->pptfx++; // advance to the next point
  1009. pd->count--; // count off this point
  1010. }
  1011. //
  1012. // Add edges in PATHDATA to GET, in Y-X sorted order
  1013. //
  1014. while ( pd->count-- )
  1015. {
  1016. if ( (pFreeEdges =
  1017. pAddEdgeToGET(pGETHead, pFreeEdges, &pfxPathPrevious,
  1018. pd->pptfx, pClipRect)) == NULL )
  1019. {
  1020. goto ReturnFalse;
  1021. }
  1022. pfxPathPrevious = *pd->pptfx; // current point becomes previous
  1023. pd->pptfx++; // advance to the next point
  1024. }// Loop through all the points
  1025. //
  1026. // If last point ends the subpath, insert the edge that
  1027. // connects to first point (is this built in already?)
  1028. //
  1029. if ( pd->flags & PD_ENDSUBPATH )
  1030. {
  1031. if ( (pFreeEdges = pAddEdgeToGET(pGETHead, pFreeEdges, &pfxPathPrevious,
  1032. &pfxPathStart, pClipRect)) == NULL )
  1033. {
  1034. goto ReturnFalse;
  1035. }
  1036. }
  1037. }// if ( pd->count != 0 )
  1038. //
  1039. // The initial loop conditions preclude a do, while or for
  1040. //
  1041. if ( bMore )
  1042. {
  1043. bMore = PATHOBJ_bEnum(ppo, pd);
  1044. goto next_subpath;
  1045. }
  1046. return(TRUE); // done successfully
  1047. ReturnFalse:
  1048. return(FALSE); // failed
  1049. }// bConstructGET()
  1050. //-----------------------------------------------------------------------------
  1051. //
  1052. // EDGE* pAddEdgeToGET(EDGE* pGETHead, EDGE* pFreeEdge, POINTFIX* ppfxEdgeStart,
  1053. // POINTFIX* ppfxEdgeEnd, RECTL* pClipRect)
  1054. //
  1055. // Adds the edge described by the two passed-in points to the Global Edge
  1056. // Table (GET), if the edge spans at least one pixel vertically.
  1057. //
  1058. //-----------------------------------------------------------------------------
  1059. EDGE*
  1060. pAddEdgeToGET(EDGE* pGETHead,
  1061. EDGE* pFreeEdge,
  1062. POINTFIX* ppfxEdgeStart,
  1063. POINTFIX* ppfxEdgeEnd,
  1064. RECTL* pClipRect)
  1065. {
  1066. int iYStart;
  1067. int iYEnd;
  1068. int iXStart;
  1069. int iXEnd;
  1070. int iYHeight;
  1071. int iXWidth;
  1072. int yJump;
  1073. int yTop;
  1074. //
  1075. // Set the winding-rule direction of the edge, and put the endpoints in
  1076. // top-to-bottom order
  1077. //
  1078. iYHeight = ppfxEdgeEnd->y - ppfxEdgeStart->y;
  1079. if ( iYHeight == 0 )
  1080. {
  1081. //
  1082. // Zero height; ignore this edge
  1083. //
  1084. return(pFreeEdge);
  1085. }
  1086. else if ( iYHeight > 0 )
  1087. {
  1088. //
  1089. // Top-to-bottom
  1090. //
  1091. iXStart = ppfxEdgeStart->x;
  1092. iYStart = ppfxEdgeStart->y;
  1093. iXEnd = ppfxEdgeEnd->x;
  1094. iYEnd = ppfxEdgeEnd->y;
  1095. pFreeEdge->iWindingDirection = 1;
  1096. }
  1097. else
  1098. {
  1099. iYHeight = -iYHeight;
  1100. iXEnd = ppfxEdgeStart->x;
  1101. iYEnd = ppfxEdgeStart->y;
  1102. iXStart = ppfxEdgeEnd->x;
  1103. iYStart = ppfxEdgeEnd->y;
  1104. pFreeEdge->iWindingDirection = -1;
  1105. }
  1106. if ( iYHeight & 0x80000000 )
  1107. {
  1108. //
  1109. // Too large; outside 2**27 GDI range
  1110. //
  1111. return(NULL);
  1112. }
  1113. //
  1114. // Set the error term and adjustment factors, all in GIQ coordinates for
  1115. // now
  1116. //
  1117. iXWidth = iXEnd - iXStart;
  1118. if ( iXWidth >= 0 )
  1119. {
  1120. //
  1121. // Left to right, so we change X as soon as we move at all
  1122. //
  1123. pFreeEdge->iXDirection = 1;
  1124. pFreeEdge->iErrorTerm = -1;
  1125. }
  1126. else
  1127. {
  1128. //
  1129. // Right to left, so we don't change X until we've moved a full GIQ
  1130. // coordinate
  1131. //
  1132. iXWidth = -iXWidth;
  1133. pFreeEdge->iXDirection = -1;
  1134. pFreeEdge->iErrorTerm = -iYHeight;
  1135. }
  1136. if ( iXWidth & 0x80000000 )
  1137. {
  1138. //
  1139. // Too large; outside 2**27 GDI range
  1140. //
  1141. return(NULL);
  1142. }
  1143. if ( iXWidth >= iYHeight )
  1144. {
  1145. //
  1146. // Calculate base run length (minimum distance advanced in X for a 1-
  1147. // scan advance in Y)
  1148. //
  1149. pFreeEdge->iXWhole = iXWidth / iYHeight;
  1150. //
  1151. // Add sign back into base run length if going right to left
  1152. //
  1153. if ( pFreeEdge->iXDirection == -1 )
  1154. {
  1155. pFreeEdge->iXWhole = -pFreeEdge->iXWhole;
  1156. }
  1157. pFreeEdge->iErrorAdjustUp = iXWidth % iYHeight;
  1158. }
  1159. else
  1160. {
  1161. //
  1162. // Base run length is 0, because line is closer to vertical than
  1163. // horizontal
  1164. //
  1165. pFreeEdge->iXWhole = 0;
  1166. pFreeEdge->iErrorAdjustUp = iXWidth;
  1167. }
  1168. pFreeEdge->iErrorAdjustDown = iYHeight;
  1169. //
  1170. // Calculate the number of pixels spanned by this edge, accounting for
  1171. // clipping
  1172. //
  1173. // Top true pixel scan in GIQ coordinates
  1174. // Shifting to divide and multiply by 16 is okay because the clip rect
  1175. // always contains positive numbers
  1176. //
  1177. yTop = max(pClipRect->top << 4, (iYStart + 15) & ~0x0F);
  1178. //
  1179. // Initial scan line on which to fill edge
  1180. //
  1181. pFreeEdge->Y = yTop >> 4;
  1182. //
  1183. // Calculate # of scans to actually fill, accounting for clipping
  1184. //
  1185. if ( (pFreeEdge->iScansLeft = min(pClipRect->bottom, ((iYEnd + 15) >> 4))
  1186. - pFreeEdge->Y) <= 0 )
  1187. {
  1188. //
  1189. // No pixels at all are spanned, so we can ignore this edge
  1190. //
  1191. return(pFreeEdge);
  1192. }
  1193. //
  1194. // If the edge doesn't start on a pixel scan (that is, it starts at a
  1195. // fractional GIQ coordinate), advance it to the first pixel scan it
  1196. // intersects. Ditto if there's top clipping. Also clip to the bottom if
  1197. // needed
  1198. //
  1199. if ( iYStart != yTop )
  1200. {
  1201. //
  1202. // Jump ahead by the Y distance in GIQ coordinates to the first pixel
  1203. // to draw
  1204. //
  1205. yJump = yTop - iYStart;
  1206. //
  1207. // Advance x the minimum amount for the number of scans traversed
  1208. //
  1209. iXStart += pFreeEdge->iXWhole * yJump;
  1210. vAdjustErrorTerm(&pFreeEdge->iErrorTerm, pFreeEdge->iErrorAdjustUp,
  1211. pFreeEdge->iErrorAdjustDown, yJump, &iXStart,
  1212. pFreeEdge->iXDirection);
  1213. }
  1214. //
  1215. // Turn the calculations into pixel rather than GIQ calculations
  1216. //
  1217. // Move the X coordinate to the nearest pixel, and adjust the error term
  1218. // accordingly
  1219. // Dividing by 16 with a shift is okay because X is always positive
  1220. pFreeEdge->X = (iXStart + 15) >> 4; // convert from GIQ to pixel coordinates
  1221. //
  1222. // LATER adjust only if needed (if prestepped above)?
  1223. //
  1224. if ( pFreeEdge->iXDirection == 1 )
  1225. {
  1226. //
  1227. // Left to right
  1228. //
  1229. pFreeEdge->iErrorTerm -= pFreeEdge->iErrorAdjustDown
  1230. * (((iXStart + 15) & ~0x0F) - iXStart);
  1231. }
  1232. else
  1233. {
  1234. //
  1235. // Right to left
  1236. //
  1237. pFreeEdge->iErrorTerm -= pFreeEdge->iErrorAdjustDown
  1238. * ((iXStart - 1) & 0x0F);
  1239. }
  1240. //
  1241. // Scale the error term down 16 times to switch from GIQ to pixels.
  1242. // Shifts work to do the multiplying because these values are always
  1243. // non-negative
  1244. //
  1245. pFreeEdge->iErrorTerm >>= 4;
  1246. //
  1247. // Insert the edge into the GET in YX-sorted order. The search always ends
  1248. // because the GET has a sentinel with a greater-than-possible Y value
  1249. //
  1250. while ( (pFreeEdge->Y > ((EDGE*)pGETHead->pNext)->Y)
  1251. ||( (pFreeEdge->Y == ((EDGE*)pGETHead->pNext)->Y)
  1252. &&(pFreeEdge->X > ((EDGE*)pGETHead->pNext)->X) ) )
  1253. {
  1254. pGETHead = (EDGE*)pGETHead->pNext;
  1255. }
  1256. pFreeEdge->pNext = pGETHead->pNext; // link the edge into the GET
  1257. pGETHead->pNext = pFreeEdge;
  1258. //
  1259. // Point to the next edge storage location for next time
  1260. //
  1261. return(++pFreeEdge);
  1262. }// pAddEdgeToGET()
  1263. //-----------------------------------------------------------------------------
  1264. //
  1265. // void vAdjustErrorTerm(int *pErrorTerm, int iErrorAdjustUp,
  1266. // int iErrorAdjustDown, int yJump, int *pXStart,
  1267. // int iXDirection)
  1268. // Adjust the error term for a skip ahead in y. This is in ASM because there's
  1269. // a multiply/divide that may involve a larger than 32-bit value.
  1270. //
  1271. //-----------------------------------------------------------------------------
  1272. void
  1273. vAdjustErrorTerm(int* pErrorTerm,
  1274. int iErrorAdjustUp,
  1275. int iErrorAdjustDown,
  1276. int yJump,
  1277. int* pXStart,
  1278. int iXDirection)
  1279. {
  1280. #if defined(_X86_) || defined(i386)
  1281. //
  1282. // Adjust the error term up by the number of y coordinates we'll skip
  1283. // *pErrorTerm += iErrorAdjustUp * yJump;
  1284. //
  1285. _asm mov ebx,pErrorTerm
  1286. _asm mov eax,iErrorAdjustUp
  1287. _asm mul yJump
  1288. _asm add eax,[ebx]
  1289. _asm adc edx,-1 // the error term starts out negative
  1290. //
  1291. // See if the error term turned over even once while skipping
  1292. //
  1293. _asm js short NoErrorTurnover
  1294. //
  1295. // # of times we'll turn over the error term and step an extra x
  1296. // coordinate while skipping
  1297. // NumAdjustDowns = (*pErrorTerm / iErrorAdjustDown) + 1;
  1298. //
  1299. _asm div iErrorAdjustDown
  1300. _asm inc eax
  1301. //
  1302. // Note that EDX is the remainder; (EDX - iErrorAdjustDown) is where
  1303. // the error term ends up ultimately
  1304. //
  1305. // Advance x appropriately for the # of times the error term
  1306. // turned over
  1307. // if (iXDirection == 1)
  1308. // {
  1309. // *pXStart += NumAdjustDowns;
  1310. // }
  1311. // else
  1312. // {
  1313. // *pXStart -= NumAdjustDowns;
  1314. // }
  1315. //
  1316. _asm mov ecx,pXStart
  1317. _asm cmp iXDirection,1
  1318. _asm jz short GoingRight
  1319. _asm neg eax
  1320. GoingRight:
  1321. _asm add [ecx],eax
  1322. // Adjust the error term down to its proper post-skip value
  1323. // *pErrorTerm -= iErrorAdjustDown * NumAdjustDowns;
  1324. _asm sub edx,iErrorAdjustDown
  1325. _asm mov eax,edx // put into EAX for storing to pErrorTerm next
  1326. NoErrorTurnover:
  1327. _asm mov [ebx],eax
  1328. #else
  1329. //
  1330. // LONGLONGS are 64 bit integers (We hope!) as the multiply could
  1331. // overflow 32 bit integers. If 64 bit ints are unsupported, the
  1332. // LONGLONG will end up as a double. Hopefully there will be no
  1333. // noticable difference in accuracy.
  1334. LONGLONG NumAdjustDowns;
  1335. LONGLONG tmpError = *pErrorTerm;
  1336. //
  1337. // Adjust the error term up by the number of y coordinates we'll skip
  1338. //
  1339. tmpError += (LONGLONG)iErrorAdjustUp * (LONGLONG)yJump;
  1340. //
  1341. // See if the error term turned over even once while skipping
  1342. //
  1343. if ( tmpError >= 0 )
  1344. {
  1345. //
  1346. // # of times we'll turn over the error term and step an extra x
  1347. // coordinate while skipping
  1348. //
  1349. NumAdjustDowns = (tmpError / (LONGLONG)iErrorAdjustDown) + 1;
  1350. //
  1351. // Advance x appropriately for the # of times the error term
  1352. // turned over
  1353. //
  1354. if ( iXDirection == 1 )
  1355. {
  1356. *pXStart += (LONG)NumAdjustDowns;
  1357. }
  1358. else
  1359. {
  1360. *pXStart -= (LONG) NumAdjustDowns;
  1361. }
  1362. //
  1363. // Adjust the error term down to its proper post-skip value
  1364. //
  1365. tmpError -= (LONGLONG)iErrorAdjustDown * NumAdjustDowns;
  1366. }
  1367. *pErrorTerm = (LONG)tmpError;
  1368. #endif // X86
  1369. }// vAdjustErrorTerm()