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.

1886 lines
56 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * One-pixel-wide solid anti-aliased lines
  8. *
  9. * Abstract:
  10. *
  11. * Draws anti-aliased solid-color lines which are one pixel wide.
  12. * Supports clipping against complex clipping regions.
  13. *
  14. * History:
  15. *
  16. * 3/31/1999 AMatos
  17. * Created it.
  18. * 08/17/1999 AGodfrey
  19. * Separated aliased from antialiased.
  20. *
  21. \**************************************************************************/
  22. #include "precomp.hpp"
  23. #pragma optimize("a", on)
  24. // Antialiased lines are usually drawn using aarasterizer.cpp
  25. // rather than aaline.cpp. If aaline.cpp is to be used, define
  26. // AAONEPIXELLINE_SUPPORT
  27. #ifdef AAONEPIXELLINE_SUPPORT
  28. //------------------------------------------------------------------------
  29. // Global array that stores all the different options of drawing functions.
  30. // If the order of the functions change, the offset constants must also
  31. // change.
  32. //------------------------------------------------------------------------
  33. #define FUNC_X_MAJOR 0
  34. #define FUNC_Y_MAJOR 1
  35. #define FUNC_CLIP_OFFSET 2
  36. typedef VOID (OnePixelLineDDAAntiAliased::*DDAFunc)(DpScanBuffer*);
  37. DDAFunc gDrawFunctions[] = {
  38. OnePixelLineDDAAntiAliased::DrawXMajor,
  39. OnePixelLineDDAAntiAliased::DrawYMajor,
  40. OnePixelLineDDAAntiAliased::DrawXMajorClip,
  41. OnePixelLineDDAAntiAliased::DrawYMajorClip,
  42. };
  43. //------------------------------------------------------------------------
  44. // Constants used for manipulating fixed point and doing all the bitwise
  45. // operations on the aliased and antialiased DDA. I know some of these
  46. // are already defined elsewhere, but I do it again here as it might be nice to
  47. // keep this independent of the rest of gdiplus.
  48. //------------------------------------------------------------------------
  49. // Fixed point
  50. #define RealToFix GpRealToFix4
  51. #define FBITS 4
  52. #define FMASK 0xf
  53. #define FINVMASK 0xfffffff0
  54. #define FSIZE 16
  55. #define FHALF 8
  56. #define FHALFMASK 7
  57. // Antialiasing constants
  58. #define MAXALPHA 255
  59. #define MAXERROR 0x08000000
  60. #define TESTABOVE 0xf8000000
  61. #define TESTBELOW 0x07ffffff
  62. #define MAXHALF 0x04000000
  63. #define CONVERTALPHA 19
  64. /**************************************************************************\
  65. *
  66. * Function Description:
  67. *
  68. * Does all the DDA setup that is common to aliased and antialiased
  69. * lines.
  70. *
  71. * Arguments:
  72. *
  73. * [IN] point1 - end point
  74. * [IN] point2 - end point
  75. * [IN] drawLast - FALSE if the line is to be end-exclusive
  76. * Return Value:
  77. *
  78. * Returns TRUE if the drawing should continue, meaning the line
  79. * has non-zero length.
  80. *
  81. * Created:
  82. *
  83. * 03/31/1999 AMatos
  84. *
  85. \**************************************************************************/
  86. BOOL
  87. OnePixelLineDDAAntiAliased::SetupCommon(
  88. GpPointF *point1,
  89. GpPointF *point2,
  90. BOOL drawLast
  91. )
  92. {
  93. // Turn the points into fixed 28.4
  94. INT x1 = RealToFix(point1->X);
  95. INT x2 = RealToFix(point2->X);
  96. REAL rDeltaX = point2->X - point1->X;
  97. REAL rDeltaY = point2->Y - point1->Y;
  98. if( rDeltaX == 0 && rDeltaY == 0 )
  99. {
  100. return FALSE;
  101. }
  102. INT xDir = 1;
  103. if(rDeltaX < 0)
  104. {
  105. rDeltaX = -rDeltaX;
  106. xDir = -1;
  107. }
  108. INT y1 = RealToFix(point1->Y);
  109. INT y2 = RealToFix(point2->Y);
  110. INT yDir = 1;
  111. if( rDeltaY < 0)
  112. {
  113. rDeltaY = -rDeltaY;
  114. yDir = -1;
  115. }
  116. Flipped = FALSE;
  117. if( rDeltaY >= rDeltaX )
  118. {
  119. // y-major
  120. InvDelta = 1.0F/rDeltaY;
  121. // Invert the endpoints if necessary
  122. if(yDir == -1)
  123. {
  124. INT tmp = y1;
  125. y1 = y2;
  126. y2 = tmp;
  127. tmp = x1;
  128. x1 = x2;
  129. x2 = tmp;
  130. xDir = -xDir;
  131. Flipped = TRUE;
  132. }
  133. // Determine the Slope
  134. Slope = xDir*rDeltaX*InvDelta;
  135. // Initialize the Start and End points
  136. IsXMajor = FALSE;
  137. MajorStart = y1;
  138. MajorEnd = y2;
  139. MinorStart = x1;
  140. MinorEnd = x2;
  141. MinorDir = xDir;
  142. // This will help us for the AntiAliased x-major case.
  143. SwitchFirstLast = 1;
  144. // Mark that we'll use the y-major functions.
  145. DrawFuncIndex = FUNC_Y_MAJOR;
  146. }
  147. else
  148. {
  149. // x-major
  150. InvDelta = 1.0F/rDeltaX;
  151. // Invert the endpoints if necessary
  152. if(xDir == -1)
  153. {
  154. INT tmp = x1;
  155. x1 = x2;
  156. x2 = tmp;
  157. tmp = y1;
  158. y1 = y2;
  159. y2 = tmp;
  160. yDir = -yDir;
  161. Flipped = TRUE;
  162. }
  163. Slope = yDir*rDeltaY*InvDelta;
  164. // Initialize the rest
  165. IsXMajor = TRUE;
  166. MajorStart = x1;
  167. MajorEnd = x2;
  168. MinorStart = y1;
  169. MinorEnd = y2;
  170. MinorDir = yDir;
  171. // This will help us for the AntiAliased x-major case.
  172. SwitchFirstLast = MinorDir;
  173. // Mark that we'll use the x-major functions.
  174. DrawFuncIndex = FUNC_X_MAJOR;
  175. }
  176. // Initialize the Deltas. In fixed point.
  177. DMajor = MajorEnd - MajorStart;
  178. DMinor = (MinorEnd - MinorStart)*MinorDir;
  179. // Mark if we're drawing end-exclusive
  180. IsEndExclusive = drawLast;
  181. return TRUE;
  182. }
  183. /**************************************************************************\
  184. *
  185. * Function Description:
  186. *
  187. * Does the part of the DDA setup that is specific for anti-aliased lines.
  188. *
  189. * Arguments:
  190. * Return Value:
  191. *
  192. * Always returns TRUE. It must return a BOOL because it must have the
  193. * same signature as the aliased case.
  194. *
  195. * Created:
  196. *
  197. * 03/31/1999 AMatos
  198. *
  199. \**************************************************************************/
  200. BOOL
  201. OnePixelLineDDAAntiAliased::SetupAntiAliased()
  202. {
  203. const REAL maxError = MAXERROR;
  204. // Find the integer major positions for the beginning and
  205. // the end of the line.
  206. INT major, minor;
  207. INT majorEnd, minorEnd;
  208. major = (MajorStart + FHALF) >> FBITS;
  209. majorEnd = (MajorEnd + FHALF) >> FBITS;
  210. // Check for the simple case of a one pixel long line
  211. if(majorEnd == major)
  212. {
  213. AlphaFirst = (MAXALPHA*(MajorEnd - MajorStart)*MinorDir) >> FBITS;
  214. MajorStart = major;
  215. MajorEnd = majorEnd;
  216. MinorStart = (MinorStart + FHALF) >> FBITS;
  217. return TRUE;
  218. }
  219. // Store the fraction of the first pixel covered due to
  220. // the start point.
  221. FracStart = (major << FBITS) - MajorStart;
  222. // Advance the minor coordinate to the integer major
  223. MinorStart += GpFloor(Slope*FracStart);
  224. // Calculate the length across the line in the minor direction
  225. INT halfWidth = RealToFix(LineLength*InvDelta) >> 1;
  226. // Make sure thar startX and endX don't end up being the
  227. // same pixel, which our code does not handle. Theoretically
  228. // this cannot happen when the width of the line is 1, but
  229. // let's make sure it doesn't happen because of some roundoff
  230. // Error.
  231. if( halfWidth < FHALF )
  232. {
  233. halfWidth = FHALF;
  234. }
  235. INT endMinor = MinorEnd + MinorDir*halfWidth;
  236. // Calculate the Error up from the Slope. It needs to be that
  237. // way so that the Error up will work when the 0-1 interval
  238. // is mapped to the interval 0 to 0x8000000. See comments below.
  239. ErrorUp = GpFloor(Slope*maxError);
  240. ErrorDown = MinorDir*MAXERROR;
  241. // For a given aa one pixel wide line, there can be up to three pixels
  242. // baing painted across the line. We call these the first, middle and
  243. // last lines. So all variable with such prefixes refer to one
  244. // of these three. firstX and lastX are the positions of these lines.
  245. // In the x-major case, unlike the y-major, we might need to switch
  246. // who is the first and who is the second line depending on the
  247. // direction, so that the order that each line fills the scan
  248. // remains the same. That's why we multiply halfWidth by yDir.
  249. halfWidth *= SwitchFirstLast;
  250. MinorFirst = MinorStart - halfWidth;
  251. MinorLast = MinorStart + halfWidth;
  252. // Calculate the initial Error. The Error is mapped so that 1 is
  253. // taken to MAXERROR. So we find how mush we are into the
  254. // pixel in X, which is a number between 0 and 16 (n.4). We then
  255. // multiply this by MAXERROR and shift it from fized point. Finally we add
  256. // MAXHALF so that the 0-1 interval is mapped to 0 to MAXERROR
  257. // instead of from -MAXHALF and MAXHALF .
  258. const INT convError = MAXERROR >> FBITS;
  259. ErrorFirst = (MinorFirst - ((MinorFirst + FHALF) & FINVMASK))*
  260. convError + MAXHALF;
  261. ErrorLast = (MinorLast - ((MinorLast + FHALF) & FINVMASK))*
  262. convError + MAXHALF ;
  263. // Now calculate the alpha's for the first pixel. This is
  264. // done from the Error. Since the Error is between
  265. // 0 and MAXERROR-1, if we shift it back by 19 (CONVERTALPHA)
  266. // we have a number between 0 and 255. We the multiply by
  267. // yFrac which takes into account that the end of the line
  268. // also cuts the coverage down. At the end we convert from
  269. // 28.4. alphaFirst is the alpha of for the first pixel across the
  270. // aa line, alpha Mid is for the middle if there is one, and
  271. // AlphaLast is for the last pixel.
  272. FracStart = FracStart + FHALF;
  273. // Convert from 28.4 rounding
  274. MinorFirst = (MinorFirst + FHALF) >> FBITS;
  275. MinorLast = (MinorLast + FHALF) >> FBITS;
  276. // Store the fraction for the last pixel
  277. FracEnd = MajorEnd - (majorEnd << FBITS) + FHALF;
  278. // Store the initial values in integer coordinates
  279. MajorStart = major;
  280. MajorEnd = majorEnd;
  281. MinorStart = MinorFirst;
  282. MinorEnd = (endMinor + FHALF) >> FBITS;
  283. // Now do some initializations specific for the x-major and
  284. // y-major cases. These can't be done in the drawing routine
  285. // because those are reused during clipping.
  286. if(!IsXMajor)
  287. {
  288. // Calculate the coverage values at the initial pixel.
  289. AlphaFirst = ((MAXALPHA - (ErrorFirst >> CONVERTALPHA))*
  290. FracStart) >> FBITS;
  291. AlphaLast = ((ErrorLast >> CONVERTALPHA)*FracStart) >> FBITS;
  292. AlphaMid = (MAXALPHA*FracStart) >> FBITS;
  293. }
  294. else
  295. {
  296. // Depending if we are going up or down, the alpha is calculated
  297. // a different way from the coverage. In each case we want to
  298. // estimate the coverage as the area from the current position to
  299. // the end of the pixel, but which end varies. This is stored
  300. // in the following biases. We don't have to do this for the
  301. // y-major line because of the switch between first and last line
  302. // explained above.
  303. AlphaBiasLast = ((1 - MinorDir) >> 1)*TESTBELOW;
  304. AlphaBiasFirst = ((1 + MinorDir) >> 1)*TESTBELOW;
  305. AlphaFirst = ((AlphaBiasFirst - MinorDir*ErrorFirst)*FracStart) >> FBITS;
  306. AlphaLast = ((AlphaBiasLast + MinorDir*ErrorLast)*FracStart) >> FBITS;
  307. // If there is a middle line on the first X value, take xFrac into
  308. // account. Otherwise, the middle line's alpha is always MAXALPHA.
  309. if(MinorDir*(MinorLast - MinorFirst) < 2)
  310. {
  311. AlphaMid = MAXALPHA;
  312. }
  313. else
  314. {
  315. AlphaMid = MAXALPHA*FracStart >> FBITS;
  316. }
  317. // Both the first and last DDAs start with the same
  318. // major positions, given by the first pixel.
  319. MajorFirst = MajorLast = MajorStart;
  320. }
  321. return TRUE;
  322. }
  323. /**************************************************************************\
  324. *
  325. * Function Description:
  326. *
  327. * Draws a y major anti-aliased line. Does not support clipping, it assumes that
  328. * it is completely inside any clipping area.
  329. *
  330. * Arguments:
  331. *
  332. * [IN] DpScanBuffer - The scan buffer for accessing the surface.
  333. * Return Value:
  334. *
  335. *
  336. * Created:
  337. *
  338. * 03/31/1999 AMatos
  339. *
  340. \**************************************************************************/
  341. VOID
  342. OnePixelLineDDAAntiAliased::DrawYMajor(
  343. DpScanBuffer *scan
  344. )
  345. {
  346. ARGB *buffer;
  347. // Treat the special case where the line is just
  348. // one pixel long.
  349. if( MajorEnd == MajorStart)
  350. {
  351. buffer = scan->NextBuffer( MinorStart, MajorStart, 1);
  352. *buffer = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaFirst));
  353. return;
  354. }
  355. // Get the number of pixels not counting the last one.
  356. // Which requires special endpoint treatment.
  357. INT numPixels = MajorEnd - MajorStart;
  358. BOOL endDone = FALSE;
  359. // There can be two or three pixels across the line
  360. INT pixelWidth = MinorLast - MinorFirst + 1;
  361. while(numPixels)
  362. {
  363. numPixels--;
  364. last_pixel:
  365. // Get the scanline buffer buffer
  366. buffer = scan->NextBuffer(MinorFirst, MajorStart, pixelWidth);
  367. // Write the value of the first DDA
  368. *buffer++ = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaFirst));
  369. // If there is a middle line, write its value.
  370. if(pixelWidth > 2)
  371. {
  372. *buffer++ = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaMid));
  373. }
  374. // Write the value of the last (2nd or 3rd) DDA
  375. *buffer++ = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaLast));
  376. // Update the errors of both DDAs
  377. ErrorFirst+= ErrorUp;
  378. ErrorLast += ErrorUp;
  379. MajorStart++;
  380. if(ErrorFirst & TESTABOVE)
  381. {
  382. ErrorFirst -= ErrorDown;
  383. MinorFirst += MinorDir;
  384. }
  385. if(ErrorLast & TESTABOVE)
  386. {
  387. ErrorLast -= ErrorDown;
  388. MinorLast += MinorDir;
  389. }
  390. // Calculate the new alphas for the next scan, and
  391. // the new line width.
  392. AlphaFirst = MAXALPHA - (ErrorFirst >> CONVERTALPHA);
  393. AlphaLast = (ErrorLast >> CONVERTALPHA);
  394. AlphaMid = MAXALPHA;
  395. pixelWidth = MinorLast - MinorFirst + 1;
  396. }
  397. // The last scan requires special treatment since its coverage
  398. // must be multiplied my the stored end coverage. So so this
  399. // multiplication and go back to the body of the loop above
  400. // to draw the last scan.
  401. if(!endDone)
  402. {
  403. AlphaFirst = (AlphaFirst*FracEnd) >> FBITS;
  404. AlphaLast = (AlphaLast*FracEnd) >> FBITS;
  405. AlphaMid = (AlphaMid*FracEnd) >> FBITS;
  406. endDone = TRUE;
  407. goto last_pixel;
  408. }
  409. }
  410. /**************************************************************************\
  411. *
  412. * Function Description:
  413. *
  414. * Draws a x major anti-aliased line. Does not support clipping, it assumes that
  415. * it is completely inside any clipping area.
  416. *
  417. * Arguments:
  418. *
  419. * [IN] DpScanBuffer - The scan buffer for accessing the surface.
  420. * Return Value:
  421. *
  422. *
  423. * Created:
  424. *
  425. * 03/31/1999 AMatos
  426. *
  427. \**************************************************************************/
  428. VOID
  429. OnePixelLineDDAAntiAliased::DrawXMajor(
  430. DpScanBuffer *scan
  431. )
  432. {
  433. ARGB *buffer;
  434. INT maxWidth = scan->GetSurface()->Width;
  435. // Treat the special case where the line is just
  436. // one pixel long.
  437. if( MajorEnd == MajorStart)
  438. {
  439. buffer = scan->NextBuffer( MajorStart, MinorStart, 1);
  440. *buffer = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaFirst));
  441. return;
  442. }
  443. // For an x-major one-pixel wide line, there can be up to
  444. // three different scans being painted for the same x
  445. // position. But in our case we can't draw to these all at
  446. // the same time since some surfaces can only be accessed
  447. // one scan at a time. So the algorithm used here does all the
  448. // drawing to one scan at each time. But on the first scan, only
  449. // the first line should be drawn, on the second one both the
  450. // first and middle (if there is a middle) and only then all
  451. // the lines. So correct the Error of the last line so that
  452. // it'll only be drawn when we are at the second or third scan line.
  453. // Also correct the alpha since it'll also be crecremented for
  454. // each scan line.
  455. ErrorLast += MinorDir*(MinorLast - MinorFirst)*ErrorDown;
  456. AlphaLast += (MinorLast - MinorFirst)*ErrorDown;
  457. // Get the pointer to the buffer
  458. buffer = scan->NextBuffer(MajorLast, MinorStart, maxWidth);
  459. INT width = 0;
  460. INT alpha;
  461. INT middleMajor;
  462. while(MajorLast <= MajorEnd)
  463. {
  464. // Fill the scan with the portion corresponding to the
  465. // last line, which shoudl comes first on the scan. This is
  466. // why we use the class member SwitchFirstLast, so we can decide
  467. // based on the line direction which DDA will be the first and last
  468. // so that the last one (paradoxically) always comes first on the
  469. // scan. Keep doing it untill the last line chages scan. Check for
  470. // the end to multiply by the last pixel's coverage.
  471. while(!(ErrorLast & TESTABOVE))
  472. {
  473. if(MajorLast == MajorEnd)
  474. {
  475. AlphaLast = (AlphaLast*FracEnd) >> FBITS;
  476. // Increment the error to correct for the
  477. // decrementing below, since we didn't leave the
  478. // loop because the error became above 0.
  479. ErrorLast += ErrorDown;
  480. }
  481. *buffer++ = GpColor::PremultiplyWithCoverage(Color,
  482. static_cast<BYTE>(AlphaLast >> CONVERTALPHA));
  483. ErrorLast += ErrorUp;
  484. AlphaLast = AlphaBiasLast + MinorDir*ErrorLast;
  485. width++;
  486. MajorLast++;
  487. }
  488. // We changed scans on the last DDA, so update the errors
  489. ErrorLast -= ErrorDown;
  490. AlphaLast -= MinorDir*ErrorDown;
  491. // Fill in the middle part if there is one
  492. middleMajor = MajorLast;
  493. while(middleMajor < MajorFirst)
  494. {
  495. if( middleMajor == MajorEnd)
  496. {
  497. AlphaMid = (AlphaMid*FracEnd) >> FBITS;
  498. }
  499. *buffer++ = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaMid));
  500. AlphaMid = MAXALPHA;
  501. width++;
  502. middleMajor++;
  503. }
  504. // Fill the scan with the portion corresponding to the
  505. // first line, which comes last. Keep doing it untill the
  506. // last line chages scan.
  507. while(!(ErrorFirst & TESTABOVE))
  508. {
  509. if(MajorFirst == MajorEnd)
  510. {
  511. AlphaFirst = (AlphaFirst*FracEnd) >> FBITS;
  512. // Since we can have at most three more scans
  513. // increment ErrorFirst so that we never go in here again
  514. ErrorFirst += 4*ErrorDown;
  515. }
  516. *buffer++ = GpColor::PremultiplyWithCoverage(
  517. Color,
  518. static_cast<BYTE>(AlphaFirst >> CONVERTALPHA));
  519. ErrorFirst += ErrorUp;
  520. AlphaFirst = AlphaBiasFirst - MinorDir*ErrorFirst;
  521. width++;
  522. MajorFirst++;
  523. }
  524. // Update the errors on the first scan
  525. ErrorFirst -= ErrorDown;
  526. AlphaFirst += MinorDir*ErrorDown;
  527. // Write the buffer and update the minor variables
  528. scan->UpdateWidth(width);
  529. MinorStart += MinorDir;
  530. if (MajorLast <= MajorEnd)
  531. {
  532. buffer = scan->NextBuffer(MajorLast, MinorStart, maxWidth);
  533. }
  534. width = 0;
  535. }
  536. scan->UpdateWidth(width);
  537. }
  538. /**************************************************************************\
  539. *
  540. * Function Description:
  541. *
  542. * Draws a y major line taking clipping into account. It uses the member
  543. * variables MajorIn, MajorOut, MinorIn, MinorOut of the class as the
  544. * clip rectangle. It advances untill the line is in the clip rectangle and
  545. * draws untill it gets out or the end point is reached. In the first case,
  546. * it leaves the DDA in a state so that it can be called again with another
  547. * clipping rectangle.
  548. *
  549. * Arguments:
  550. *
  551. * [IN] DpScanBuffer - The scan buffer for accessing the surface.
  552. * Return Value:
  553. *
  554. *
  555. * Created:
  556. *
  557. * 03/31/1999 AMatos
  558. *
  559. \**************************************************************************/
  560. VOID
  561. OnePixelLineDDAAntiAliased::DrawYMajorClip(
  562. DpScanBuffer *scan
  563. )
  564. {
  565. ARGB *buffer;
  566. // Treat the special case where the line is just
  567. // one pixel long.
  568. if( MajorEnd == MajorStart)
  569. {
  570. // Check if the point is inside the rectangle
  571. if((MajorStart >= MajorIn) &&
  572. (MajorStart <= MajorOut) &&
  573. ((MinorStart - MinorIn)*MinorDir >= 0) &&
  574. ((MinorOut - MinorStart)*MinorDir >= 0))
  575. {
  576. buffer = scan->NextBuffer( MinorStart, MajorStart, 1);
  577. *buffer = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaFirst));
  578. }
  579. return;
  580. }
  581. // Align the major start coordinate with the edge of the
  582. // cliprectangle
  583. INT numScans = MajorIn - MajorStart;
  584. while(numScans > 0)
  585. {
  586. ErrorFirst+= ErrorUp;
  587. ErrorLast += ErrorUp;
  588. MajorStart++;
  589. numScans--;
  590. if(ErrorFirst & MAXERROR)
  591. {
  592. ErrorFirst -= ErrorDown;
  593. MinorFirst += MinorDir;
  594. }
  595. if(ErrorLast & MAXERROR)
  596. {
  597. ErrorLast -= ErrorDown;
  598. MinorLast += MinorDir;
  599. }
  600. // Calculate the new alphas for the next line, and
  601. // the width.
  602. AlphaFirst = MAXALPHA - (ErrorFirst >> CONVERTALPHA);
  603. AlphaLast = (ErrorLast >> CONVERTALPHA);
  604. AlphaMid = MAXALPHA;
  605. }
  606. // Save the end values
  607. INT saveMajor2 = MajorEnd;
  608. INT saveFracEnd = FracEnd;
  609. // If the end major coordinate is outside of the rectangle,
  610. // mark that the DDA should stop at the edge
  611. if(MajorEnd > MajorOut)
  612. {
  613. MajorEnd = MajorOut;
  614. FracEnd = FSIZE;
  615. }
  616. // Number of pixels to draw, not counting the last
  617. INT numPixels = MajorEnd - MajorStart;
  618. BOOL endDone = FALSE;
  619. // There can be two or three pixels across the line
  620. INT pixelWidth = MinorLast - MinorFirst + 1;
  621. // Do the DDA loop. Two loops are implemented here. The
  622. // first one is used in the case that the x coordinate of
  623. // the rectangle is close enough to the constant-y edges
  624. // of the clip rectangle. In this case, it's a pain, since
  625. // we have to check each pixel that we are writing if it's
  626. // not outside. Thus, as soon as we notice that we are
  627. // far from the edges we go to the other loop that doesn't
  628. // check all that. All it checks is if it got close enough
  629. // to the other edge, in which case it comes back to this
  630. // loop, using the label last_part. firstOutDist, firstInDist,
  631. // lastOutDist and lastInDist keeps track of the number of
  632. // pixels between the first and last DDAs and the In and
  633. // Out y-constant edges of the rectangle.
  634. INT firstOutDist = (MinorOut - MinorFirst)*MinorDir;
  635. last_part:
  636. INT firstInDist = (MinorFirst - MinorIn)*MinorDir;
  637. INT lastInDist = (MinorLast - MinorIn)*MinorDir;
  638. INT lastOutDist = (MinorOut - MinorLast)*MinorDir;
  639. while(numPixels > 0)
  640. {
  641. numPixels--;
  642. last_pixel:
  643. // Check if it's ok to write the first pixel
  644. if(firstInDist >= 0 && firstOutDist >= 0)
  645. {
  646. buffer = scan->NextBuffer(MinorFirst, MajorStart, 1);
  647. *buffer++ = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaFirst));
  648. }
  649. else
  650. {
  651. // If the first DDA is out, and we are going in the
  652. // positive direction, then the whole line is out and
  653. // we are done
  654. if(firstOutDist < 0 && MinorDir == 1)
  655. {
  656. goto end;
  657. }
  658. }
  659. // If the line has 3 pixels across
  660. if(pixelWidth > 2)
  661. {
  662. // Check if it's ok to write the second pixel
  663. if(firstInDist >= -MinorDir && firstOutDist >= MinorDir)
  664. {
  665. buffer = scan->NextBuffer(MinorFirst+1, MajorStart, 1);
  666. *buffer++ = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaMid));
  667. }
  668. }
  669. // Now check if it's ok to write the last one
  670. if(lastInDist >= 0 && lastOutDist >= 0)
  671. {
  672. buffer = scan->NextBuffer(MinorLast, MajorStart, 1);
  673. *buffer++ = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaLast));
  674. }
  675. else
  676. {
  677. // If the first DDA is out, and we are going in the
  678. // negative direction, then the whole line is out and
  679. // we are done
  680. if(lastOutDist < 0 && MinorDir == -1)
  681. {
  682. goto end;
  683. }
  684. }
  685. // Update the errors
  686. ErrorFirst+= ErrorUp;
  687. ErrorLast += ErrorUp;
  688. MajorStart++;
  689. if(ErrorFirst & TESTABOVE)
  690. {
  691. ErrorFirst -= ErrorDown;
  692. MinorFirst += MinorDir;
  693. firstInDist++;
  694. firstOutDist--;
  695. }
  696. if(ErrorLast & TESTABOVE)
  697. {
  698. ErrorLast -= ErrorDown;
  699. MinorLast += MinorDir;
  700. lastInDist++;
  701. lastOutDist--;
  702. }
  703. // Calculate the new alphas for the next line, and
  704. // the width.
  705. AlphaFirst = MAXALPHA - (ErrorFirst >> CONVERTALPHA);
  706. AlphaLast = (ErrorLast >> CONVERTALPHA);
  707. AlphaMid = MAXALPHA;
  708. pixelWidth = MinorLast - MinorFirst + 1;
  709. // Check to see if we can 'upgrade' to the next loop
  710. if(firstInDist >= 3 && firstOutDist >= 3)
  711. {
  712. break;
  713. }
  714. }
  715. while(numPixels > 0)
  716. {
  717. numPixels--;
  718. // Get the scanline buffer buffer
  719. buffer = scan->NextBuffer(MinorFirst, MajorStart, pixelWidth);
  720. // Write the value of the first DDA
  721. *buffer++ = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaFirst));
  722. // If there is a middle line, write its value.
  723. if(pixelWidth > 2)
  724. {
  725. *buffer++ = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaMid));
  726. }
  727. // Write the value of the last (2nd or 3rd) DDA
  728. *buffer++ = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaLast));
  729. // Update the DDA
  730. ErrorFirst+= ErrorUp;
  731. ErrorLast += ErrorUp;
  732. MajorStart++;
  733. if(ErrorFirst & TESTABOVE)
  734. {
  735. ErrorFirst -= ErrorDown;
  736. MinorFirst += MinorDir;
  737. firstOutDist--;
  738. }
  739. if(ErrorLast & TESTABOVE)
  740. {
  741. ErrorLast -= ErrorDown;
  742. MinorLast += MinorDir;
  743. }
  744. // Calculate the new alphas for the next line, and
  745. // the width.
  746. AlphaFirst = MAXALPHA - (ErrorFirst >> CONVERTALPHA);
  747. AlphaLast = (ErrorLast >> CONVERTALPHA);
  748. AlphaMid = MAXALPHA;
  749. pixelWidth = MinorLast - MinorFirst + 1;
  750. // Now check if it's time to go to the other loop
  751. // because we are too close to the out edge
  752. if(firstOutDist < 3)
  753. {
  754. goto last_part;
  755. }
  756. }
  757. // Now if we haven't gotten here yet, do the last pixel
  758. // and go once more through the loop.
  759. if(!endDone)
  760. {
  761. AlphaFirst = (AlphaFirst*FracEnd) >> FBITS;
  762. AlphaLast = (AlphaLast*FracEnd) >> FBITS;
  763. AlphaMid = (AlphaMid*FracEnd) >> FBITS;
  764. endDone = TRUE;
  765. goto last_pixel;
  766. }
  767. end:
  768. MajorEnd = saveMajor2;
  769. FracEnd = saveFracEnd;
  770. }
  771. /**************************************************************************\
  772. *
  773. * Function Description:
  774. *
  775. * Draws a x major line taking clipping into account. It uses the member
  776. * variables MajorIn, MajorOut, MinorIn, MinorOut of the class as the
  777. * clip rectangle. It advances untill the line is in the clip rectangle and
  778. * draws untill it gets out or the end point is reached. In the first case,
  779. * it leaves the DDA in a state so that it can be called again with another
  780. * clipping rectangle.
  781. *
  782. * Arguments:
  783. *
  784. * [IN] DpScanBuffer - The scan buffer for accessing the surface.
  785. * Return Value:
  786. *
  787. *
  788. * Created:
  789. *
  790. * 03/31/1999 AMatos
  791. *
  792. \**************************************************************************/
  793. VOID
  794. OnePixelLineDDAAntiAliased::DrawXMajorClip(
  795. DpScanBuffer *scan
  796. )
  797. {
  798. ARGB *buffer;
  799. INT maxWidth = scan->GetSurface()->Width;
  800. // Treat the special case where the line is just
  801. // one pixel long.
  802. if( MajorEnd == MajorStart)
  803. {
  804. // Check to see if the point is inside the rectangle
  805. if((MajorStart >= MajorIn) &&
  806. (MajorStart <= MajorOut) &&
  807. ((MinorStart - MinorIn)*MinorDir >= 0) &&
  808. ((MinorOut - MinorStart)*MinorDir >= 0))
  809. {
  810. buffer = scan->NextBuffer( MajorStart, MinorStart, 1);
  811. *buffer = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaFirst));
  812. }
  813. return;
  814. }
  815. // Save the real end and its fraction
  816. INT saveMajor2 = MajorEnd;
  817. INT saveFracEnd = FracEnd;
  818. // If the end major coordinate is out, mark that we must stop
  819. // before. Also make the fraction be one, since the last
  820. // one drawn now should not have a fraction
  821. if(MajorOut < MajorEnd)
  822. {
  823. MajorEnd = MajorOut;
  824. FracEnd = FSIZE;
  825. }
  826. // Advance until the last DDA is in the right scan line and
  827. // is aligned with the In y-constant edge of the rectnagle
  828. INT numScans = (MinorIn - MinorLast)*MinorDir;
  829. while((numScans > 0 && MajorLast <= MajorEnd) || MajorLast < MajorIn)
  830. {
  831. ErrorLast += ErrorUp;
  832. if(ErrorLast & TESTABOVE)
  833. {
  834. ErrorLast -= ErrorDown;
  835. MinorLast += MinorDir;
  836. numScans--;
  837. }
  838. MajorLast++;
  839. // Calculate the alpha for the current pixel
  840. AlphaLast = AlphaBiasLast + MinorDir*ErrorLast;
  841. }
  842. // Do the same for the first DDA
  843. numScans = (MinorIn - MinorFirst)*MinorDir;
  844. while((numScans > 0 && MajorFirst <= MajorEnd) || MajorFirst < MajorIn)
  845. {
  846. ErrorFirst += ErrorUp;
  847. if(ErrorFirst & TESTABOVE)
  848. {
  849. ErrorFirst -= ErrorDown;
  850. MinorFirst += MinorDir;
  851. numScans--;
  852. }
  853. MajorFirst++;
  854. AlphaFirst = AlphaBiasFirst - MinorDir*ErrorFirst;
  855. }
  856. // If there is no middle line in the first x-position,
  857. // make the middle alpha full, since the start coverage
  858. // won't apply
  859. if((MinorLast - MinorFirst) < 2)
  860. {
  861. AlphaMid = MAXALPHA;
  862. }
  863. MinorStart = MinorFirst;
  864. // The same way that was done in the non-clipping case,
  865. // mock arround with the error so we won't draw the
  866. // last DDA until the first DDA is in the same scan line,
  867. // or has caught up. We need to adjust the alpha and minor
  868. // positions for this DDA to, so that when we start
  869. // drawing they will have the right value
  870. ErrorLast += MinorDir*(MinorLast - MinorFirst)*ErrorDown;
  871. AlphaLast += (MinorLast - MinorFirst)*ErrorDown;
  872. MinorLast -= (MinorLast - MinorFirst);
  873. // Get the pointer to the buffer
  874. buffer = scan->NextBuffer(MajorLast, MinorStart, maxWidth);
  875. INT width = 0;
  876. INT alpha;
  877. INT middleMajor;
  878. while(MajorLast <= MajorEnd)
  879. {
  880. // Fill the scan with the portion corresponding to the
  881. // last line, which should come first. Keep doing it
  882. // until the last line changes scan.
  883. while(!(ErrorLast & TESTABOVE))
  884. {
  885. // Check if we passed or are at the last pixel
  886. if(MajorLast >= MajorEnd)
  887. {
  888. if(MajorLast == MajorEnd)
  889. {
  890. // If we are at, just update the alpha
  891. AlphaLast = (AlphaLast*FracEnd) >> FBITS;
  892. }
  893. else
  894. {
  895. // If we passed, we don't want to draw anymore.
  896. // Just adjust the error, alpha and minor so they
  897. // will be right when they are corrected after this
  898. // loop for the next scan
  899. ErrorLast += ErrorDown;
  900. AlphaLast -= MinorDir*ErrorDown;
  901. MinorLast -= MinorDir;
  902. break;
  903. }
  904. }
  905. *buffer++ = GpColor::PremultiplyWithCoverage(Color,
  906. static_cast<BYTE>(AlphaLast >> CONVERTALPHA));
  907. ErrorLast += ErrorUp;
  908. AlphaLast = AlphaBiasLast + MinorDir*ErrorLast;
  909. width++;
  910. MajorLast++;
  911. }
  912. // Correct the values for the next scan
  913. ErrorLast -= ErrorDown;
  914. AlphaLast -= MinorDir*ErrorDown;
  915. MinorLast += MinorDir;
  916. // Fill in the middle part.
  917. middleMajor = MajorLast;
  918. while(middleMajor < MajorFirst)
  919. {
  920. if( middleMajor == MajorEnd)
  921. {
  922. AlphaMid = (AlphaMid*FracEnd) >> FBITS;
  923. }
  924. *buffer++ = GpColor::PremultiplyWithCoverage(Color, static_cast<BYTE>(AlphaMid));
  925. AlphaMid = MAXALPHA;
  926. width++;
  927. middleMajor++;
  928. }
  929. // Fill the scan with the portion corresponding to the
  930. // first line, which should come first. Keep doing it
  931. // until the last line changes scan.
  932. while(!(ErrorFirst & TESTABOVE))
  933. {
  934. // Check for the end pixel, just like we
  935. // did for the last DDA
  936. if(MajorFirst >= MajorEnd)
  937. {
  938. if(MajorFirst == MajorEnd)
  939. {
  940. AlphaFirst = (AlphaFirst*FracEnd) >> FBITS;
  941. }
  942. else
  943. {
  944. ErrorFirst += ErrorDown;
  945. AlphaFirst -= MinorDir*ErrorDown;
  946. MinorFirst -= MinorDir;
  947. break;
  948. }
  949. }
  950. *buffer++ = GpColor::PremultiplyWithCoverage(
  951. Color,
  952. static_cast<BYTE>(AlphaFirst >> CONVERTALPHA));
  953. ErrorFirst += ErrorUp;
  954. AlphaFirst = AlphaBiasFirst - MinorDir*ErrorFirst;
  955. width++;
  956. MajorFirst++;
  957. }
  958. // Correct the values for the next scan
  959. ErrorFirst -= ErrorDown;
  960. AlphaFirst += MinorDir*ErrorDown;
  961. MinorFirst += MinorDir;
  962. scan->UpdateWidth(width);
  963. // Check to see if we have come to the end of the rectangle
  964. // through the minor coordinate crossing the Out edge
  965. // in the x-constant direction
  966. if(MinorStart == MinorOut)
  967. {
  968. MinorStart += MinorDir;
  969. break;
  970. }
  971. // Update the minor coordinate and get the next buffer
  972. // if we aren't done yet.
  973. MinorStart += MinorDir;
  974. if (MajorLast <= MajorEnd)
  975. {
  976. buffer = scan->NextBuffer(MajorLast, MinorStart, maxWidth);
  977. }
  978. width = 0;
  979. }
  980. scan->UpdateWidth(width);
  981. // Restore the old values
  982. MajorEnd = saveMajor2;
  983. FracEnd = saveFracEnd;
  984. }
  985. //--------------------------------------------------------------------
  986. // Auxiliary functions
  987. //--------------------------------------------------------------------
  988. /**************************************************************************\
  989. *
  990. * Function Description:
  991. *
  992. * Clips the line against a rectangle. It assumes that the line endpoints
  993. * are stored in the class in floating point format. This sets an
  994. * order in which this function can be called. It must be after the
  995. * SetupCommon function and before the specific setups for antialiasing
  996. * and aliasing. This is a pain, but it's better than requirering on of
  997. * these to have to know about clipping. The clipping here is done by
  998. * using the Slope and InvSlope members of the class to advance the
  999. * endpoints to the rectangle edges. Thus the function also assumes that
  1000. * Slope and InvSlope have been calculated.
  1001. *
  1002. * Arguments:
  1003. *
  1004. * [IN] clipRect - The rectangle to clip against
  1005. * Return Value:
  1006. *
  1007. *
  1008. * Created:
  1009. *
  1010. * 03/31/1999 AMatos
  1011. *
  1012. \**************************************************************************/
  1013. BOOL
  1014. OnePixelLineDDAAntiAliased::ClipRectangle(
  1015. const GpRect* clipRect
  1016. )
  1017. {
  1018. INT clipBottom, clipTop, clipLeft, clipRight;
  1019. // Set the major and minor edges ef the clipping
  1020. // region, converting to fixed point 28.4. Note that
  1021. // we don't convert to the pixel center, but to a
  1022. // that goes all the way up to the pixel edges. This
  1023. // makes a difference for antialiasing. We don't go all
  1024. // the way to the edge since some rounding rules could
  1025. // endup lihgting the next pixel outside of the clipping
  1026. // area. That's why we add/subtract 7 instead of 8.
  1027. // The right and bottom are exclusive.
  1028. INT majorMin = (clipRect->GetLeft() << FBITS) - FHALFMASK;
  1029. INT majorMax = ((clipRect->GetRight() - 1) << FBITS) + FHALFMASK;
  1030. INT minorMax = ((clipRect->GetBottom() - 1) << FBITS) + FHALFMASK;
  1031. INT minorMin = (clipRect->GetTop() << FBITS) - FHALFMASK;
  1032. if(!IsXMajor)
  1033. {
  1034. INT tmp;
  1035. tmp = majorMin;
  1036. majorMin = minorMin;
  1037. minorMin = tmp;
  1038. tmp = majorMax;
  1039. majorMax = minorMax;
  1040. minorMax = tmp;
  1041. }
  1042. // First clip in the major coordinate
  1043. BOOL minOut, maxOut;
  1044. minOut = MajorStart < majorMin;
  1045. maxOut = MajorEnd > majorMax;
  1046. if( minOut || maxOut )
  1047. {
  1048. if(MajorStart > majorMax || MajorEnd < majorMin)
  1049. {
  1050. return FALSE;
  1051. }
  1052. if(minOut)
  1053. {
  1054. MinorStart += GpFloor((majorMin - MajorStart)*Slope);
  1055. MajorStart = majorMin;
  1056. }
  1057. if(maxOut)
  1058. {
  1059. MinorEnd += GpFloor((majorMax - MajorEnd)*Slope);
  1060. MajorEnd = majorMax;
  1061. // If we clipped the last point, we don't need to be IsEndExclusive
  1062. // anymore, as the last point now is not the line's last
  1063. // point but some in the middle.
  1064. IsEndExclusive = FALSE;
  1065. }
  1066. }
  1067. // Now clip the minor coordinate
  1068. INT *pMajor1, *pMinor1, *pMajor2, *pMinor2;
  1069. if(MinorDir == 1)
  1070. {
  1071. pMajor1 = &MajorStart;
  1072. pMajor2 = &MajorEnd;
  1073. pMinor1 = &MinorStart;
  1074. pMinor2 = &MinorEnd;
  1075. }
  1076. else
  1077. {
  1078. pMajor1 = &MajorEnd;
  1079. pMajor2 = &MajorStart;
  1080. pMinor1 = &MinorEnd;
  1081. pMinor2 = &MinorStart;
  1082. }
  1083. minOut = *pMinor1 < minorMin;
  1084. maxOut = *pMinor2 > minorMax;
  1085. if(minOut || maxOut)
  1086. {
  1087. if(*pMinor1 > minorMax || *pMinor2 < minorMin)
  1088. {
  1089. return FALSE;
  1090. }
  1091. if(minOut)
  1092. {
  1093. *pMajor1 += GpFloor((minorMin - *pMinor1)*InvSlope);
  1094. *pMinor1 = minorMin;
  1095. }
  1096. if(maxOut)
  1097. {
  1098. *pMajor2 += GpFloor((minorMax - *pMinor2)*InvSlope);
  1099. *pMinor2 = minorMax;
  1100. // If we clipped the last point, we don't need to be endExclusive
  1101. // anymore, as the last point now is not the line's last
  1102. // point but some in the middle.
  1103. IsEndExclusive = FALSE;
  1104. }
  1105. }
  1106. return(TRUE);
  1107. }
  1108. /**************************************************************************\
  1109. *
  1110. * Function Description:
  1111. *
  1112. * Draws a one-pixe-wide line with a solid color. Calls on the
  1113. * OnePixelLineDDAAntiAliased class to do the actual drawing.
  1114. *
  1115. * Arguments:
  1116. *
  1117. * [IN] scan - The DpScanBuffer to access the drawing surface
  1118. * [IN] clipRect - A single rectangle that includes all the clipping
  1119. * region. If there is no clipping, should be set to NULL.
  1120. * [IN] clipRegionIn - A complex clipping region. If the clipping region is
  1121. * simple, this should be NULL, and clipRect will be used.
  1122. * [IN] point1 - line end point
  1123. * [IN] point2 - line end point
  1124. * [IN] inColor - the solid color
  1125. * [IN] drawLast - FALSE if the line is to be end-exclusive.
  1126. * [IN] antiAliased - TRUE if the line should be antialiased.
  1127. *
  1128. * Return Value:
  1129. *
  1130. * GpStatus - Ok or failure status
  1131. *
  1132. * Created:
  1133. *
  1134. * 03/31/1999 AMatos
  1135. *
  1136. \**************************************************************************/
  1137. GpStatus
  1138. DrawSolidLineOnePixelAntiAliased(
  1139. DpScanBuffer *scan,
  1140. const GpRect *clipRect,
  1141. const DpClipRegion* clipRegionIn,
  1142. GpPointF *point1,
  1143. GpPointF *point2,
  1144. ARGB inColor,
  1145. BOOL drawLast
  1146. )
  1147. {
  1148. // Take out the const for now because the Enumeration method
  1149. // is not const.
  1150. DpClipRegion *clipRegion = const_cast<DpClipRegion*>(clipRegionIn);
  1151. // Setup the common part of the DDA
  1152. OnePixelLineDDAAntiAliased dda;
  1153. if(!dda.SetupCommon(point1, point2, drawLast))
  1154. {
  1155. return Ok;
  1156. }
  1157. // Calculate the length of the line. Since we only use
  1158. // it to determine the width, it shouldn't matter that
  1159. // we convert the deltas from 28.4 before the multiplication.
  1160. INT d1 = dda.DMajor >> FBITS;
  1161. INT d2 = dda.DMinor >> FBITS;
  1162. dda.LineLength = (REAL)sqrt((double)(d1*d1 + d2*d2));
  1163. // Store the color, not premultiplied
  1164. dda.Color = inColor;
  1165. // Now handle the different clipping cases
  1166. if(!clipRect)
  1167. {
  1168. // This is easy, there is no clipping so just draw.
  1169. if(!dda.SetupAntiAliased())
  1170. {
  1171. return Ok;
  1172. }
  1173. (dda.*(gDrawFunctions[dda.DrawFuncIndex]))(scan);
  1174. return Ok;
  1175. }
  1176. else
  1177. {
  1178. // The inverse of the Slope might be needed.
  1179. // Can't use the inverse slope if the slope is zero.
  1180. if(dda.Slope==0.0F)
  1181. {
  1182. dda.InvSlope=0.0F;
  1183. }
  1184. else
  1185. {
  1186. dda.InvSlope = (1.0F/dda.Slope);
  1187. }
  1188. // First of all clip against the bounding rectangle
  1189. if(!dda.ClipRectangle(clipRect))
  1190. {
  1191. return Ok;
  1192. }
  1193. // Do the specific setup
  1194. if(!dda.SetupAntiAliased())
  1195. {
  1196. return Ok;
  1197. }
  1198. // For each clip rectangle we store it's limits in
  1199. // an array of four elements. We then index this array using
  1200. // the variables below which depend on the slope and
  1201. // direction of the line in the following way: majorIn is edge crossed
  1202. // to go into the rect in the major direction, majorOut is the edge
  1203. // crossed to go out of the rect in the major direction, and so on.
  1204. // The same for xIn, xOut, yIn, yOut.
  1205. INT majorIn, majorOut, minorIn, minorOut;
  1206. INT xIn, xOut, yIn, yOut;
  1207. // Direction to enumerate the rectangles which depends on the
  1208. // line
  1209. DpClipRegion::Direction enumDirection;
  1210. INT clipBounds[4];
  1211. // We store all our info in terms of major and minor
  1212. // direction, but to deal with cliping rectangles we
  1213. // need to know them in terms of x and y, so calculate
  1214. // xDir, yDir, the advance slope.
  1215. REAL xAdvanceRate;
  1216. INT xDir, yDir;
  1217. INT yEndLine;
  1218. // If the line crosses a span completely, (xStart, yStart)
  1219. // is the position where it enters the span and (xEnd, yEnd)
  1220. // is the position that it leaves. If it starts inside the
  1221. // span, then (xStart, yStart) is the start point
  1222. REAL yStart, xStart, xEnd, yEnd;
  1223. if(dda.IsXMajor)
  1224. {
  1225. // Calculate the in-out indices
  1226. majorIn = xIn = 0;
  1227. majorOut = xOut = 2;
  1228. if(dda.MinorDir == 1)
  1229. {
  1230. minorIn = 1;
  1231. minorOut = 3;
  1232. enumDirection = DpClipRegion::TopLeftToBottomRight;
  1233. }
  1234. else
  1235. {
  1236. minorIn = 3;
  1237. minorOut = 1;
  1238. enumDirection = DpClipRegion::BottomLeftToTopRight;
  1239. }
  1240. yIn = minorIn;
  1241. yOut = minorOut;
  1242. // Make (xStart, yStart) be the initial point
  1243. yStart = (REAL)dda.MinorStart;
  1244. xStart = (REAL)dda.MajorStart;
  1245. xAdvanceRate = dda.InvSlope;
  1246. xDir = 1;
  1247. yDir = dda.MinorDir;
  1248. yEndLine = dda.MinorEnd;
  1249. }
  1250. else
  1251. {
  1252. majorIn = yIn = 1;
  1253. majorOut = yOut = 3;
  1254. if(dda.MinorDir == 1)
  1255. {
  1256. minorIn = 0;
  1257. minorOut = 2;
  1258. enumDirection = DpClipRegion::TopLeftToBottomRight;
  1259. }
  1260. else
  1261. {
  1262. minorIn = 2;
  1263. minorOut = 0;
  1264. enumDirection = DpClipRegion::TopRightToBottomLeft;
  1265. }
  1266. xIn = minorIn;
  1267. xOut = minorOut;
  1268. // Make (xStart, yStart) be the initial point
  1269. yStart = (REAL)dda.MajorStart;
  1270. xStart = (REAL)dda.MinorStart;
  1271. xAdvanceRate = dda.Slope;
  1272. xDir = dda.MinorDir;
  1273. yDir = 1;
  1274. yEndLine = dda.MajorEnd;
  1275. }
  1276. // Update the drawing function to the correct
  1277. // slipping version
  1278. dda.DrawFuncIndex += FUNC_CLIP_OFFSET;
  1279. if(!clipRegion)
  1280. {
  1281. // In this case there is only a single rect, so just
  1282. // draw clipped to that
  1283. // Store the rectangle in an array so we can atribute the
  1284. // right values to the MajorIn, majorOut, etc... variables.
  1285. // Remember that bottom and right are exclusive.
  1286. clipBounds[0] = clipRect->GetLeft();
  1287. clipBounds[1] = clipRect->GetTop();
  1288. clipBounds[2] = clipRect->GetRight() - 1;
  1289. clipBounds[3] = clipRect->GetBottom() - 1;
  1290. dda.MajorIn = clipBounds[majorIn];
  1291. dda.MajorOut = clipBounds[majorOut];
  1292. dda.MinorIn = clipBounds[minorIn];
  1293. dda.MinorOut = clipBounds[minorOut];
  1294. (dda.*(gDrawFunctions[dda.DrawFuncIndex]))(scan);
  1295. return Ok;
  1296. }
  1297. else
  1298. {
  1299. BOOL agregating = FALSE;
  1300. INT agregateBounds[4];
  1301. // We have a complex clipping region. So what we'll do
  1302. // is clip against each individual rectangle in the
  1303. // cliping region.
  1304. clipRegion->StartEnumeration(GpFloor(yStart), enumDirection);
  1305. GpRect rect;
  1306. // Get the first rectangle.
  1307. INT numRects = 1;
  1308. clipRegion->Enumerate(&rect, numRects);
  1309. clipBounds[0] = rect.GetLeft();
  1310. clipBounds[1] = rect.GetTop();
  1311. clipBounds[2] = rect.GetRight() - 1;
  1312. clipBounds[3] = rect.GetBottom() - 1;
  1313. // Store the y position into the span
  1314. INT currSpanYMin = clipBounds[yIn];
  1315. // We need some special treatment for the case where the
  1316. // line is horizontal, since is this case it's not going
  1317. // to cross different spans. And it it's not in the current
  1318. // span, it's totally clipped out.
  1319. if(dda.IsXMajor && dda.ErrorUp == 0)
  1320. {
  1321. if(yStart >= clipBounds[1] && yStart <= clipBounds[3])
  1322. {
  1323. xStart = (REAL)dda.MajorStart;
  1324. xEnd = (REAL)dda.MajorEnd;
  1325. }
  1326. else
  1327. {
  1328. return Ok;
  1329. }
  1330. }
  1331. else
  1332. {
  1333. if(yStart < clipBounds[1] || yStart > clipBounds[3])
  1334. {
  1335. xStart = xStart + (clipBounds[yIn] - yStart)*xAdvanceRate;
  1336. yStart = (REAL)clipBounds[yIn];
  1337. }
  1338. xEnd = xStart + (clipBounds[yOut] - yStart)*xAdvanceRate;
  1339. }
  1340. yEnd = (REAL)clipBounds[yOut];
  1341. while(1)
  1342. {
  1343. // Get to the first rectangle on the span that crosses the
  1344. // line
  1345. while((xStart - clipBounds[xOut])*xDir > 0)
  1346. {
  1347. numRects = 1;
  1348. clipRegion->Enumerate(&rect, numRects);
  1349. clipBounds[0] = rect.GetLeft();
  1350. clipBounds[1] = rect.GetTop();
  1351. clipBounds[2] = rect.GetRight() - 1;
  1352. clipBounds[3] = rect.GetBottom() - 1;
  1353. if(numRects != 1)
  1354. {
  1355. goto draw_agregated;
  1356. }
  1357. if(clipBounds[yIn] != currSpanYMin)
  1358. {
  1359. goto process_next_span;
  1360. }
  1361. }
  1362. // Draw on all the rectangles that intersect the
  1363. // line
  1364. if((xStart - clipBounds[xIn])*xDir > 0 &&
  1365. (clipBounds[xOut] - xEnd)*xDir > 0)
  1366. {
  1367. if(agregating)
  1368. {
  1369. if((clipBounds[xIn] - agregateBounds[xIn])*xDir < 0)
  1370. {
  1371. agregateBounds[xIn] = clipBounds[xIn];
  1372. }
  1373. if((clipBounds[xOut] - agregateBounds[xOut])*xDir > 0)
  1374. {
  1375. agregateBounds[xOut] = clipBounds[xOut];
  1376. }
  1377. agregateBounds[yOut] = clipBounds[yOut];
  1378. }
  1379. else
  1380. {
  1381. agregateBounds[0] = clipBounds[0];
  1382. agregateBounds[1] = clipBounds[1];
  1383. agregateBounds[2] = clipBounds[2];
  1384. agregateBounds[3] = clipBounds[3];
  1385. agregating = TRUE;
  1386. }
  1387. }
  1388. else
  1389. {
  1390. if(agregating)
  1391. {
  1392. dda.MajorIn = agregateBounds[majorIn];
  1393. dda.MajorOut = agregateBounds[majorOut];
  1394. dda.MinorIn = agregateBounds[minorIn];
  1395. dda.MinorOut = agregateBounds[minorOut];
  1396. (dda.*(gDrawFunctions[dda.DrawFuncIndex]))(scan);
  1397. agregating = FALSE;
  1398. }
  1399. while((xEnd - clipBounds[xIn])*xDir > 0)
  1400. {
  1401. dda.MajorIn = clipBounds[majorIn];
  1402. dda.MajorOut = clipBounds[majorOut];
  1403. dda.MinorIn = clipBounds[minorIn];
  1404. dda.MinorOut = clipBounds[minorOut];
  1405. (dda.*(gDrawFunctions[dda.DrawFuncIndex]))(scan);
  1406. if(dda.MajorStart > dda.MajorEnd)
  1407. {
  1408. return Ok;
  1409. }
  1410. numRects = 1;
  1411. clipRegion->Enumerate(&rect, numRects);
  1412. clipBounds[0] = rect.GetLeft();
  1413. clipBounds[1] = rect.GetTop();
  1414. clipBounds[2] = rect.GetRight() - 1;
  1415. clipBounds[3] = rect.GetBottom() - 1;
  1416. if(numRects != 1)
  1417. {
  1418. goto draw_agregated;
  1419. }
  1420. if(clipBounds[yIn] != currSpanYMin)
  1421. {
  1422. goto process_next_span;
  1423. }
  1424. }
  1425. }
  1426. // Get to the next span
  1427. while(clipBounds[yIn] == currSpanYMin)
  1428. {
  1429. numRects = 1;
  1430. clipRegion->Enumerate(&rect, numRects);
  1431. clipBounds[0] = rect.GetLeft();
  1432. clipBounds[1] = rect.GetTop();
  1433. clipBounds[2] = rect.GetRight() - 1;
  1434. clipBounds[3] = rect.GetBottom() - 1;
  1435. if(numRects != 1)
  1436. {
  1437. goto draw_agregated;
  1438. }
  1439. }
  1440. process_next_span:
  1441. if((clipBounds[yIn] - yEndLine)*yDir > 0)
  1442. {
  1443. // We are done.
  1444. goto draw_agregated;
  1445. }
  1446. if((clipBounds[yIn] - yEnd)*yDir == 1)
  1447. {
  1448. xStart = xEnd;
  1449. }
  1450. else
  1451. {
  1452. if(agregating)
  1453. {
  1454. dda.MajorIn = agregateBounds[majorIn];
  1455. dda.MajorOut = agregateBounds[majorOut];
  1456. dda.MinorIn = agregateBounds[minorIn];
  1457. dda.MinorOut = agregateBounds[minorOut];
  1458. (dda.*(gDrawFunctions[dda.DrawFuncIndex]))(scan);
  1459. if(dda.MajorStart > dda.MajorEnd)
  1460. {
  1461. return Ok;
  1462. }
  1463. agregating = FALSE;
  1464. }
  1465. xStart = xStart + (clipBounds[yIn] - yStart)*xAdvanceRate;
  1466. }
  1467. yStart = (REAL)clipBounds[yIn];
  1468. xEnd = xStart + (clipBounds[yOut] - yStart)*xAdvanceRate;
  1469. yEnd = (REAL)clipBounds[yOut];
  1470. currSpanYMin = GpFloor(yStart);
  1471. }
  1472. draw_agregated:
  1473. if(agregating)
  1474. {
  1475. dda.MajorIn = agregateBounds[majorIn];
  1476. dda.MajorOut = agregateBounds[majorOut];
  1477. dda.MinorIn = agregateBounds[minorIn];
  1478. dda.MinorOut = agregateBounds[minorOut];
  1479. (dda.*(gDrawFunctions[dda.DrawFuncIndex]))(scan);
  1480. }
  1481. }
  1482. }
  1483. return Ok;
  1484. }
  1485. #endif // AAONEPIXELLINE_SUPPORT
  1486. #pragma optimize("a", off)