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.

1292 lines
35 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: clipline.cxx
  3. *
  4. * This module handles the clipping of lines to a rectangular region.
  5. *
  6. * Created: 07-Mar-1991 13:31:00
  7. * Author: Eric Kutter [erick]
  8. *
  9. * Copyright (c) 1991-1999 Microsoft Corporation
  10. *
  11. * (General description of its use)
  12. * Given a dda and region.
  13. *
  14. * 0. setup dda
  15. * 1. find first scan
  16. * if (!scan) exit
  17. * find first segment
  18. *enter
  19. * if (done) exit
  20. * 2. do
  21. * {
  22. * 2.A. do
  23. * {
  24. * 2.A.1. find end of segment
  25. * 2.A.2. record segment (check for connection)
  26. * 2.A.3. advance to next segment
  27. * if (segment && (out of room))
  28. * return(TRUE);
  29. * } while (segment)
  30. *
  31. * 2.C advance to next scan
  32. * find first segment
  33. * } while (scan)
  34. *
  35. * set done
  36. *
  37. \**************************************************************************/
  38. #include "precomp.hxx"
  39. //#define CLIPDEBUG
  40. #ifdef CLIPDEBUG
  41. FLONG MSGLEVEL = 5;
  42. #endif
  43. /**************************************************************************\
  44. *
  45. \**************************************************************************/
  46. #ifdef CLIPDEBUG
  47. VOID XCLIPOBJ::DBGDISPLAYSTATE(PSZ psz)
  48. {
  49. DbgPrint("\t%s\n",psz);
  50. DbgPrint("\t\tpcle->ptB = (%ld,%ld), pcle->ptC = (%ld,%ld), pcle->ptF = (%ld,%ld)\n",
  51. pcle->ptB.x,pcle->ptB.y,pcle->ptC.x,pcle->ptC.y,pcle->ptF.x,pcle->ptF.y);
  52. DbgPrint("\t\tiWall = %ld, cScans = %ld\n",enmr.iWall, enmr.cScans);
  53. }
  54. VOID XCLIPOBJ::DBGDISPLAYDDA()
  55. {
  56. DbgPrint("\tDDA: ");
  57. DbgPrint("\t\tpt0 = (%ld,%ld), pt1 = (%ld,%ld)\n",
  58. pcle->dda.lX0,pcle->dda.lY0,pcle->dda.lX1,pcle->dda.lY1);
  59. }
  60. #endif
  61. /******************************Member*Function*****************************\
  62. * EPATHOBJ::vUpdateCosmeticStyleState(pso, pla)
  63. *
  64. * Updates the style state when a path is completely clipped away, for
  65. * cosmetic lines.
  66. *
  67. * History:
  68. * 3-Nov-1992 -by- J. Andrew Goossen [andrewgo]
  69. * Wrote it.
  70. \**************************************************************************/
  71. VOID EPATHOBJ::vUpdateCosmeticStyleState(SURFACE* pSurf, LINEATTRS* pla)
  72. {
  73. DDA_CLIPLINE dda; // For calculating line length in pixels
  74. ULONG xStep; // Advance xStep/xyDensity style units for each
  75. // pel if line is x-styled
  76. ULONG yStep; // Advance yStep/xyDensity units
  77. ULONG xyDensity;
  78. STYLEPOS spTotal2; // Twice the sum of the style array
  79. if (pla->fl & LA_ALTERNATE)
  80. {
  81. // Style information for alternate lines is special:
  82. xStep = 1;
  83. yStep = 1;
  84. xyDensity = 1;
  85. spTotal2 = 2;
  86. }
  87. else
  88. {
  89. // Get styling information about device:
  90. PDEVOBJ po(pSurf->hdev());
  91. xStep = po.xStyleStep();
  92. yStep = po.yStyleStep();
  93. xyDensity = po.denStyleStep();
  94. PFLOAT_LONG pstyle = pla->pstyle + pla->cstyle;
  95. spTotal2 = 0;
  96. while (pstyle > pla->pstyle)
  97. {
  98. pstyle--;
  99. spTotal2 += pstyle->l;
  100. }
  101. ASSERTGDI((spTotal2 & ~0x7fffL) == 0, "Style array too long");
  102. ASSERTGDI(spTotal2 != 0, "Zero style array?");
  103. ASSERTGDI(xyDensity > 0, "Zero xyDensity?");
  104. spTotal2 = 2 * spTotal2 * xyDensity;
  105. }
  106. // Find the beginning of the last subpath in the path:
  107. PATHRECORD* ppr = ppath->pprlast;
  108. while (!(ppr->flags & PD_BEGINSUBPATH))
  109. ppr = ppr->pprprev;
  110. // Initialize the style state appropriately:
  111. ASSERTGDI((ppr->flags & PD_RESETSTYLE) || (ppr == ppath->pprfirst),
  112. "Expected PD_RESETSTYLE on subpaths after first");
  113. STYLEPOS sp = 0;
  114. if (!(ppr->flags & PD_RESETSTYLE))
  115. {
  116. sp = HIWORD(pla->elStyleState.l) * xyDensity
  117. + LOWORD(pla->elStyleState.l);
  118. }
  119. POINTFIX* pptfx0 = &ppr->aptfx[0];
  120. POINTFIX* pptfx1 = &ppr->aptfx[1];
  121. POINTFIX* pptfxEnd = &ppr->aptfx[ppr->count];
  122. // Loop through all PATHRECORDs in path:
  123. while (TRUE)
  124. {
  125. // Loop through all points in PATHRECORD:
  126. while (pptfx1 < pptfxEnd)
  127. {
  128. if (dda.bInit(pptfx0, pptfx1))
  129. {
  130. STYLEPOS spStyleStep;
  131. BOOL bXStyled;
  132. LONG lDelta;
  133. // Determine if x-styled or y-styled:
  134. FIX dx = ABS(pptfx1->x - pptfx0->x);
  135. FIX dy = ABS(pptfx1->y - pptfx0->y);
  136. if (xStep == yStep)
  137. bXStyled = (dx >= dy);
  138. else
  139. {
  140. bXStyled = UInt32x32To64(xStep,dx) >= UInt32x32To64(yStep,dy);
  141. }
  142. // Calculate new style state at the end of this line:
  143. if ((bXStyled && dda.bXMajor()) ||
  144. (!bXStyled && !dda.bXMajor()))
  145. {
  146. spStyleStep = xStep;
  147. lDelta = dda.lX1 - dda.lX0 + 1;
  148. }
  149. else
  150. {
  151. spStyleStep = yStep;
  152. lDelta = dda.lY1 - dda.lY0 + 1;
  153. }
  154. ASSERTGDI(lDelta > 0, "Expected positive lDelta");
  155. if ((lDelta & ~0xffffL) == 0)
  156. {
  157. sp += lDelta * spStyleStep;
  158. if (sp >= spTotal2)
  159. sp %= spTotal2;
  160. }
  161. else
  162. {
  163. ULONGLONG euq = UInt32x32To64((ULONG) lDelta, (ULONG) spStyleStep)
  164. + (ULONGLONG) sp;
  165. DIVREM(euq,(ULONG) spTotal2, (ULONG*) &sp);
  166. }
  167. }
  168. pptfx0 = pptfx1;
  169. pptfx1++;
  170. }
  171. ppr = ppr->pprnext;
  172. if (ppr == (PATHRECORD*) NULL)
  173. break;
  174. pptfx1 = &ppr->aptfx[0];
  175. pptfxEnd = &ppr->aptfx[ppr->count];
  176. }
  177. pla->elStyleState.l = MAKELONG(sp % xyDensity, sp / xyDensity);
  178. }
  179. /******************************Member*Function*****************************\
  180. * VOID XCLIPOBJ::vUpdateStyleState()
  181. *
  182. * Updates the style state (spStyleEnd) for the end of the current line.
  183. *
  184. * History:
  185. * 20-Feb-1992 -by- J. Andrew Goossen [andrewgo]
  186. * Wrote it.
  187. \**************************************************************************/
  188. VOID XCLIPOBJ::vUpdateStyleState()
  189. {
  190. BOOL bXStyled;
  191. LONG lDelta; // Length of line in style-major direction
  192. STYLEPOS spStyleStep; // Step size for style-major direction of line
  193. {
  194. // Determine if x-styled or y-styled
  195. FIX dx = ABS(pcle->ptfx0.x - pcle->pptfx1->x);
  196. FIX dy = ABS(pcle->ptfx0.y - pcle->pptfx1->y);
  197. if (pcle->xStep == pcle->yStep)
  198. bXStyled = (dx >= dy);
  199. else
  200. {
  201. bXStyled = UInt32x32To64(pcle->xStep, dx) >= UInt32x32To64(pcle->yStep, dy);
  202. }
  203. }
  204. // Now calculate new style state at the end of this line:
  205. pcle->spStyleEnd = pcle->spStyleStart;
  206. ASSERTGDI(pcle->spStyleEnd >= 0, "Negative style state");
  207. if (bXStyled)
  208. {
  209. spStyleStep = pcle->xStep;
  210. lDelta = ABS(pcle->lX1 - pcle->lX0) + 1;
  211. }
  212. else
  213. {
  214. spStyleStep = pcle->yStep;
  215. lDelta = ABS(pcle->lY1 - pcle->lY0) + 1;
  216. }
  217. if ((lDelta & ~0xffffL) == 0)
  218. {
  219. pcle->spStyleEnd += lDelta * spStyleStep;
  220. if (pcle->spStyleEnd >= pcle->spTotal2)
  221. pcle->spStyleEnd %= pcle->spTotal2;
  222. }
  223. else
  224. {
  225. WARNING("Long style state comp");
  226. ULONGLONG euq = UInt32x32To64((ULONG) lDelta, (ULONG) spStyleStep)
  227. + (ULONGLONG) pcle->spStyleEnd;
  228. DIVREM(euq, pcle->spTotal2, (PULONG) &pcle->spStyleEnd);
  229. }
  230. }
  231. /******************************Member*Function*****************************\
  232. * BOOL XCLIPOBJ::bEnumStartLine
  233. *
  234. * History:
  235. * 20-Feb-1992 -by- J. Andrew Goossen [andrewgo]
  236. * Adding styling support.
  237. *
  238. * 22-Mar-1991 -by- Eric Kutter [erick]
  239. * Wrote it.
  240. \**************************************************************************/
  241. BOOL XCLIPOBJ::bEnumStartLine(
  242. FLONG flPath)
  243. {
  244. ASSERTGDI((PD_ALL & CLO_ALL) == 0,"PD_ALL and CLIPOBJ_ALL != 0\n");
  245. // reset all flags except CLO_PATHDONE.
  246. pcle->fl = (pcle->fl & CLO_PATHDONE) | flPath;
  247. // initialize the dda
  248. if (!pcle->dda.bInit(&pcle->ptfx0,pcle->pptfx1))
  249. {
  250. vSetLineDone();
  251. return(FALSE);
  252. }
  253. pcle->lX0 = pcle->dda.lX0;
  254. pcle->lY0 = pcle->dda.lY0;
  255. pcle->lX1 = pcle->dda.lX1;
  256. pcle->lY1 = pcle->dda.lY1;
  257. pcle->dda.vUnflip(&pcle->lX0, &pcle->lY0);
  258. pcle->dda.vUnflip(&pcle->lX1, &pcle->lY1);
  259. // if this is the first line of the sub path
  260. if (pcle->fl & PD_BEGINSUBPATH)
  261. {
  262. pcle->ptfxStartSub = pcle->ptfx0;
  263. }
  264. if (bStyling())
  265. {
  266. // the style state at the start of this line is the same as the style
  267. // state for the end of the previous line, unless told differently:
  268. pcle->spStyleStart = pcle->spStyleEnd;
  269. if (pcle->fl & PD_RESETSTYLE)
  270. {
  271. pcle->spStyleStart = 0;
  272. }
  273. // calculate style state at end of this line:
  274. vUpdateStyleState();
  275. }
  276. return(TRUE);
  277. }
  278. /******************************Member*Function*****************************\
  279. * BOOL XCLIPOBJ::bRecordSegment()
  280. *
  281. * Find the exit point of the current segment and record the run. If there
  282. * is not enough room to record the run, return false.
  283. *
  284. * On Entry:
  285. *
  286. * guaranteed intersection with segment
  287. *
  288. * enmr.pscn - current scan
  289. * ptB - entry point into segment
  290. * ptE,ptF - exit intersection from scan
  291. *
  292. * On Exit:
  293. *
  294. * if room to record the run, return TRUE otherwise return false.
  295. *
  296. * iC - exiting index from segment
  297. *
  298. * History:
  299. * 11-Mar-1991 -by- Eric Kutter [erick]
  300. * Wrote it.
  301. \**************************************************************************/
  302. // This is inline since it gets called from only one place:
  303. inline BOOL XCLIPOBJ::bRecordSegment()
  304. {
  305. enmr.iWall += enmr.iOff;
  306. LONG x = xWall(0);
  307. // if line intersects wall before exits scan...
  308. if (bLeftToRight() == (x > pcle->ptE.x))
  309. {
  310. // line exits scan before intersecting next wall...
  311. return(bRecordRun(pcle->iE));
  312. }
  313. else
  314. {
  315. bIntersectWall(x, &pcle->ptC, NULL, &pcle->iC);
  316. return(bRecordRun(pcle->iC));
  317. }
  318. }
  319. /******************************Member*Function*****************************\
  320. * BOOL XCLIPOBJ::bSetup()
  321. *
  322. * If this is the first call for a line, setup the enumeration data structure.
  323. * The first point may need adjusting if the previous line of the sub path
  324. * ended on the same point this line starts.
  325. *
  326. * Otherwise, just the temporary data structure needs to be initialized as
  327. * well as recording the last run that wouldn't fit in the previous call.
  328. *
  329. * If this is the closing line of a sub path, the last point might need to
  330. * be adjusted if it lies on the first point of the first line of the
  331. * sub-path.
  332. *
  333. * On Exit:
  334. *
  335. * bRecordSegment() needs to be called to record the current segment.
  336. *
  337. * true - if segment found
  338. *
  339. * ptB,iStart - begining of current segment
  340. * ptE,ptF,iE - intersection leaving previous scan or first point.
  341. * pscn - first scan to be processed.
  342. *
  343. * History:
  344. * 07-Mar-1991 -by- Eric Kutter [erick]
  345. * Wrote it.
  346. \**************************************************************************/
  347. BOOL XCLIPOBJ::bSetup()
  348. {
  349. // setup CLIPOBJ fields
  350. // Is this the first call for this line
  351. if (!bRecordPending()) // First call
  352. {
  353. // init pclt variables
  354. // setup CLIPOBJ fields
  355. pcle->iE = -1; // last index of previous run
  356. vSetLeftToRight(pcle->lX0 <= pcle->lX1);
  357. if (pcle->lY0 <= pcle->lY1)
  358. pcle->fl |= CLO_TOPTOBOTTOM;
  359. // Check if we have to further clip to the rclBounds (it would be
  360. // nice to have a flag in the CLIPOBJ telling us that we also have
  361. // to clip the rclBounds...)
  362. if ((pcle->lY0 < rclBounds.top && pcle->lY1 < rclBounds.top) ||
  363. (pcle->lY0 >= rclBounds.bottom && pcle->lY1 >= rclBounds.bottom))
  364. return(FALSE);
  365. // Calculate the intersections of the line with rclBounds:
  366. if (bTopToBottom())
  367. {
  368. if (pcle->lY0 < rclBounds.top)
  369. {
  370. POINTL ptlTop;
  371. vIntersectScan(rclBounds.top, NULL, &ptlTop, &pcle->iE);
  372. pcle->lX0 = ptlTop.x;
  373. pcle->lY0 = ptlTop.y;
  374. ASSERTGDI(pcle->lY0 == rclBounds.top, "TtoB top wrong");
  375. }
  376. if (pcle->lY1 >= rclBounds.bottom)
  377. {
  378. POINTL ptlBottom;
  379. LONG iEnd;
  380. vIntersectScan(rclBounds.bottom, &ptlBottom, NULL, &iEnd);
  381. pcle->lX1 = ptlBottom.x;
  382. pcle->lY1 = ptlBottom.y;
  383. ASSERTGDI(pcle->lY1 == rclBounds.bottom - 1, "TtoB bottom wrong");
  384. }
  385. }
  386. else
  387. {
  388. if (pcle->lY1 < rclBounds.top)
  389. {
  390. POINTL ptlTop;
  391. LONG iEnd;
  392. vIntersectScan(rclBounds.top, &ptlTop, NULL, &iEnd);
  393. pcle->lX1 = ptlTop.x;
  394. pcle->lY1 = ptlTop.y;
  395. ASSERTGDI(pcle->lY1 == rclBounds.top, "BtoT top wrong");
  396. }
  397. if (pcle->lY0 >= rclBounds.bottom)
  398. {
  399. POINTL ptlBottom;
  400. vIntersectScan(rclBounds.bottom, NULL, &ptlBottom, &pcle->iE);
  401. pcle->lX0 = ptlBottom.x;
  402. pcle->lY0 = ptlBottom.y;
  403. ASSERTGDI(pcle->lY0 == rclBounds.bottom - 1, "BtoT bottom wrong");
  404. }
  405. }
  406. // Check if we have to further clip to the rclBounds:
  407. if ((pcle->lX0 < rclBounds.left && pcle->lX1 < rclBounds.left) ||
  408. (pcle->lX0 >= rclBounds.right && pcle->lX1 >= rclBounds.right))
  409. return(FALSE);
  410. if (bLeftToRight())
  411. {
  412. if (pcle->lX0 < rclBounds.left)
  413. {
  414. POINTL ptlLeft;
  415. bIntersectWall(rclBounds.left, NULL, &ptlLeft, &pcle->iE);
  416. pcle->lX0 = ptlLeft.x;
  417. pcle->lY0 = ptlLeft.y;
  418. ASSERTGDI(pcle->lX0 == rclBounds.left, "LtoR left wrong");
  419. }
  420. if (pcle->lX1 >= rclBounds.right)
  421. {
  422. POINTL ptlRight;
  423. LONG iEnd;
  424. bIntersectWall(rclBounds.right, &ptlRight, NULL, &iEnd);
  425. pcle->lX1 = ptlRight.x;
  426. pcle->lY1 = ptlRight.y;
  427. ASSERTGDI(pcle->lX1 == rclBounds.right - 1, "LtoR right wrong");
  428. }
  429. }
  430. else
  431. {
  432. if (pcle->lX1 < rclBounds.left)
  433. {
  434. POINTL ptlLeft;
  435. LONG iEnd;
  436. bIntersectWall(rclBounds.left, &ptlLeft, NULL, &iEnd);
  437. pcle->lX1 = ptlLeft.x;
  438. pcle->lY1 = ptlLeft.y;
  439. ASSERTGDI(pcle->lX1 == rclBounds.left, "RtoL left wrong");
  440. }
  441. if (pcle->lX0 >= rclBounds.right)
  442. {
  443. POINTL ptlRight;
  444. bIntersectWall(rclBounds.right, NULL, &ptlRight, &pcle->iE);
  445. pcle->lX0 = ptlRight.x;
  446. pcle->lY0 = ptlRight.y;
  447. ASSERTGDI(pcle->lX0 == rclBounds.right - 1, "RtoL right wrong");
  448. }
  449. }
  450. ASSERTGDI(pcle->lY0 >= rclBounds.top && pcle->lY0 < rclBounds.bottom &&
  451. pcle->lY1 >= rclBounds.top && pcle->lY1 < rclBounds.bottom &&
  452. pcle->lX0 >= rclBounds.left && pcle->lX0 < rclBounds.right &&
  453. pcle->lX1 >= rclBounds.left && pcle->lX1 < rclBounds.right,
  454. "Line out of rclBounds");
  455. pcle->ptF.x = pcle->lX0;
  456. pcle->ptF.y = pcle->lY0;
  457. // setup enmr fields
  458. vSetRecordPending();
  459. // find first segment of first scan containing runs
  460. if (!bFindFirstScan())
  461. return(FALSE);
  462. }
  463. else // following calls for this segment
  464. {
  465. // record the segment that wouldn't fit last time.
  466. // guaranteed success!
  467. bRecordRun(pcle->iC);
  468. // find the next segment to get back in sync with the enumeration.
  469. // if there is no next segment in this scan, find the next scan.
  470. // if there is no next scan containing any segments, return false.
  471. if (bFindNextSegment())
  472. return(TRUE);
  473. // Are there more scans?
  474. if (!bFindNextScan())
  475. return(FALSE);
  476. }
  477. // need to find a segment. If no segment found in scan, goto the next scan.
  478. do
  479. {
  480. if (bFindFirstSegment())
  481. return(TRUE);
  482. } while (bFindNextScan());
  483. // didn't find any. Done with this line.
  484. return(FALSE);
  485. }
  486. /******************************Member*Function*****************************\
  487. * BOOL XCLIPOBJ::bEnumLine()
  488. *
  489. * Fill the CLIPLINE data structure with line segments for the current line.
  490. * If there are too many segments to fit in the structure, TRUE is returned
  491. * and this routine must be called again with the same line. Each new line
  492. * must first be initialized by calling vEnumStartLine.
  493. *
  494. * {
  495. * 1. if (done) exit
  496. *
  497. * 2. do
  498. * {
  499. * 2.A. do
  500. * {
  501. * 2.A.1. find end of segment
  502. * 2.A.2. record segment
  503. * 2.A.3. advance to next segment
  504. * if (segment && (out of room))
  505. * return(TRUE);
  506. * 2.A } while (segments)
  507. *
  508. * 2.C advance to next scan
  509. * 2.D find first segment
  510. * 2. } while (scan)
  511. * 3. return(FALSE)
  512. * }
  513. *
  514. * RETURN:
  515. * TRUE - there are more segments and this routine should be called again
  516. * FALSE - no more segments. Use vEnumStartLine to prepare next line.
  517. *
  518. * History:
  519. * 07-Mar-1991 -by- Eric Kutter [erick]
  520. * Wrote it.
  521. \**************************************************************************/
  522. BOOL XCLIPOBJ::bEnumLine(
  523. ULONG cj,
  524. PCLIPLINE pcl)
  525. {
  526. pcl->ptfxA = pcle->ptfx0;
  527. pcl->ptfxB = *pcle->pptfx1;
  528. pcl->c = 0;
  529. if (bStyling())
  530. pcl->lStyleState = lGetStyleState(pcle->spStyleStart);
  531. // if we have already completed the enumeration
  532. if (bLineDone())
  533. return(FALSE);
  534. // setup the run structure
  535. pcle->cMaxRuns = (cj - offsetof(CLIPLINE,arun)) / sizeof(RUN);
  536. pcle->prun = pcl->arun;
  537. pcle->pcRuns = &pcl->c;
  538. pcle->iPrevStop = LONG_MAX; // If this is a valid stop, there is no way there
  539. // could be anothr run after it anyways.
  540. // there must be room for at least 1 segment, otherwise tell them we are done.
  541. if (pcle->cMaxRuns == 0)
  542. return(FALSE);
  543. // setup intial state.
  544. if (!bSetup())
  545. {
  546. vSetLineDone();
  547. return(FALSE);
  548. }
  549. // enumerate through the scans and segments
  550. for (;;)
  551. {
  552. // enumerate through the segments
  553. do
  554. {
  555. if (!bRecordSegment())
  556. return(TRUE);
  557. } while (bFindNextSegment());
  558. // find the next scan with intersecting segments
  559. do
  560. {
  561. if (!bFindNextScan())
  562. {
  563. vSetLineDone();
  564. return(FALSE);
  565. }
  566. } while (!bFindFirstSegment());
  567. }
  568. }
  569. /******************************Public*Routine******************************\
  570. * BOOL XCLIPOBJ::bFindFirstScan()
  571. *
  572. * if (topdown)
  573. * {
  574. * find first scan ending below first point
  575. * return(does the line intersect the scan)
  576. * }
  577. * else (bottom up
  578. * {
  579. * find first scan ending above point
  580. * return(does the line intersect the scan)
  581. * }
  582. *
  583. * On Entry:
  584. * pcle->ptF.y - first Y coordinate of line
  585. * pcle->lY1 - last Y coordinate of line
  586. *
  587. * On Exit:
  588. * enmr.pscn - current scan
  589. * enmr.cScans - number of scans still to traverse
  590. *
  591. * History:
  592. * 07-Mar-1991 -by- Eric Kutter [erick]
  593. * Wrote it.
  594. \**************************************************************************/
  595. BOOL XCLIPOBJ::bFindFirstScan()
  596. {
  597. if (prgn->cScans <= 2) // empty region
  598. return(FALSE);
  599. enmr.cScans = prgn->cScans - 2; // ignore first and last (no walls)
  600. // Start from the top or bottom?
  601. if (bTopToBottom())
  602. {
  603. enmr.pscn = pscnGet(prgn->pscnHead()); // ignore first scan (empty)
  604. // while the scans are above the start of the line
  605. while (bEmptyScan() || (enmr.pscn->yBottom <= pcle->ptF.y))
  606. {
  607. if (--enmr.cScans == 0)
  608. return(FALSE);
  609. enmr.pscn = pscnGet(enmr.pscn);
  610. }
  611. return(enmr.pscn->yTop <= pcle->lY1); // is the line between scans
  612. }
  613. else // bottom up
  614. {
  615. enmr.pscn = pscnGot(pscnGot(prgn->pscnTail)); // ignore last scan
  616. // while the scans are below the start of the line
  617. while (bEmptyScan() || (enmr.pscn->yTop > pcle->ptF.y))
  618. {
  619. if (--enmr.cScans == 0)
  620. return(FALSE);
  621. enmr.pscn = pscnGot(enmr.pscn);
  622. }
  623. return(enmr.pscn->yBottom > pcle->lY1);
  624. }
  625. }
  626. /******************************Member*Function*****************************\
  627. * BOOL XCLIPOBJ::bFindNextScan()
  628. *
  629. * On Entry:
  630. *
  631. * enmr.pscn - last scan searched
  632. * enmr.cScans - total remaining scans (some may be empty)
  633. *
  634. * On Exit:
  635. *
  636. * if there are more scans to search, return true with:
  637. * enmr.pscn - next scan to search
  638. *
  639. * History:
  640. * 09-Mar-1991 -by- Eric Kutter [erick]
  641. * Wrote it.
  642. \**************************************************************************/
  643. BOOL XCLIPOBJ::bFindNextScan()
  644. {
  645. // Start from the top or bottom?
  646. if (bTopToBottom())
  647. {
  648. do {
  649. if (enmr.cScans == 1) // already on last scan
  650. return(FALSE);
  651. --enmr.cScans;
  652. enmr.pscn = pscnGet(enmr.pscn);
  653. if (enmr.pscn->yTop > pcle->lY1) // does line end before scan?
  654. return(FALSE);
  655. } while (bEmptyScan());
  656. }
  657. else // bottom to top
  658. {
  659. do {
  660. if (enmr.cScans == 1) // already on last scan
  661. return(FALSE);
  662. --enmr.cScans;
  663. enmr.pscn = pscnGot(enmr.pscn);
  664. if (enmr.pscn->yBottom <= pcle->lY1)// does line end before scan?
  665. return(FALSE);
  666. } while (bEmptyScan());
  667. }
  668. return(TRUE);
  669. }
  670. /******************************Member*Function*****************************\
  671. * BOOL XCLIPOBJ::bFindFirstSegment()
  672. *
  673. * On Entry:
  674. *
  675. * enmr.pscn - current scan
  676. * ptF - exit point from previous scan containing segments. For
  677. * the first scan, this is lX0,lY0.
  678. * On Exit:
  679. *
  680. * if no intersections, return FALSE, otherwise
  681. *
  682. * ptB,iStart - intersection entering first segment
  683. * ptE,ptF,iE - intersection exiting scan
  684. * xWall(0) - last wall intersected
  685. *
  686. * History:
  687. * 08-Mar-1991 -by- Eric Kutter [erick]
  688. * Wrote it.
  689. \**************************************************************************/
  690. BOOL XCLIPOBJ::bFindFirstSegment()
  691. {
  692. // setup the intersections entering and leaving the current scan.
  693. pcle->ptB = pcle->ptF;
  694. if (bTopToBottom())
  695. {
  696. pcle->lYEnter = enmr.pscn->yTop;
  697. pcle->lYLeave = enmr.pscn->yBottom;
  698. }
  699. else
  700. {
  701. pcle->lYEnter = enmr.pscn->yBottom;
  702. pcle->lYLeave = enmr.pscn->yTop;
  703. }
  704. if (bTopToBottom() == (pcle->ptB.y < pcle->lYEnter))
  705. {
  706. vIntersectScan(pcle->lYEnter,NULL,&pcle->ptB,&pcle->iStart);
  707. }
  708. else
  709. {
  710. pcle->iStart = pcle->iE;
  711. pcle->lYEnter = pcle->ptB.y;
  712. }
  713. if (bTopToBottom() == (pcle->lY1 >= pcle->lYLeave))
  714. {
  715. vIntersectScan(pcle->lYLeave,&pcle->ptE,&pcle->ptF,&pcle->iE);
  716. }
  717. else
  718. {
  719. // The line ends in this scan:
  720. pcle->ptE.y = pcle->lY1;
  721. pcle->ptE.x = pcle->lX1;
  722. pcle->lYLeave = pcle->lY1 + 1;
  723. // Calculate the iPosition of the line's last pixel in the scan.
  724. // If we didn't have to take into account rclBounds, this would
  725. // simply be pcle->iE = pcle->dda.lX1 - pcle->dda.lX0:
  726. // Unnormalize the (unclipped) start of the line:
  727. EPOINTL eptlStart(pcle->dda.lX0, pcle->dda.lY0);
  728. pcle->dda.vUnflip(&eptlStart.x, &eptlStart.y);
  729. // Compute the length in the line's major direction:
  730. if (pcle->dda.bDFlip())
  731. pcle->iE = ABS(pcle->lY1 - eptlStart.y);
  732. else
  733. pcle->iE = ABS(pcle->lX1 - eptlStart.x);
  734. }
  735. // find first wall intersecting line. Do this by means of a binary search
  736. enmr.iFinal = enmr.pscn->cWalls - 1;
  737. enmr.iWall = 0; // must be 0 for special cases
  738. // Special case if the line enters the scan before the first or after the
  739. // last segment. This makes the general case much simpler.
  740. if (pcle->ptB.x >= xWall(enmr.iFinal))
  741. {
  742. enmr.iWall = enmr.iFinal;
  743. if (bLeftToRight())
  744. return(FALSE);
  745. enmr.iWall++;
  746. }
  747. else if (pcle->ptB.x < xWall(0))
  748. {
  749. if (!bLeftToRight())
  750. return(FALSE);
  751. enmr.iWall--;
  752. }
  753. else
  754. {
  755. // if the line starts somewhere in the middle of the scan find the first
  756. // wall to the right of the entrance via a binary search.
  757. LONG iLow = 0;
  758. LONG iHigh = enmr.iFinal;
  759. for (;;)
  760. {
  761. enmr.iWall = (iLow + iHigh) / 2;
  762. if (pcle->ptB.x < xWall(0)) // to the left
  763. {
  764. // enters after previous wall?
  765. if (pcle->ptB.x >= xWall(-1))
  766. break;
  767. // keep searching
  768. iHigh = enmr.iWall - 1;
  769. }
  770. else
  771. {
  772. // enters before next wall?
  773. if (pcle->ptB.x < xWall(1))
  774. {
  775. ++enmr.iWall;
  776. break;
  777. }
  778. // keep searching
  779. iLow = enmr.iWall + 1;
  780. }
  781. }
  782. // WARNING! SLEEZY! subtract one if left to right.
  783. // sets iWall to wall before entering scan.
  784. enmr.iWall -= bLeftToRight();
  785. }
  786. // set pcle->ptB to first intersection. Already set if starting inside segment.
  787. // If we are starting inside a segment, iWall will be odd if we are moving
  788. // right and even if we are moving left. If we are outside of a segment when
  789. // the scan is entered, compute the intersection with the first wall.
  790. if (bLeftToRight() == (BOOL)(enmr.iWall & 1))
  791. {
  792. enmr.iWall += enmr.iOff;
  793. LONG x = xWall(0);
  794. if (bLeftToRight() == (x > pcle->ptE.x))
  795. {
  796. // line exits scan before intersecting next wall...
  797. return(FALSE);
  798. }
  799. bIntersectWall(x,NULL,&pcle->ptB,&pcle->iStart);
  800. }
  801. return(TRUE);
  802. }
  803. /******************************Member*Function*****************************\
  804. * BOOL XCLIPOBJ::bFindNextSegment()
  805. *
  806. * On Entry:
  807. *
  808. * ptE,ptF - intersection exiting scan
  809. * xWall(0) - exiting wall of previous segment
  810. *
  811. * On Exit:
  812. *
  813. * if no intersections, return FALSE, otherwise
  814. *
  815. * ptB - intersection entering next segment
  816. * ptE,ptF - intersection exiting scan
  817. * xWall(0) - exiting wall of new segment
  818. *
  819. * History:
  820. * 12-Mar-1991 -by- Eric Kutter [erick]
  821. * Wrote it.
  822. \**************************************************************************/
  823. BOOL XCLIPOBJ::bFindNextSegment()
  824. {
  825. // if we are past the last segment...
  826. if (bLeftToRight())
  827. {
  828. if (enmr.iWall >= enmr.iFinal)
  829. return(FALSE);
  830. }
  831. else
  832. {
  833. if (enmr.iWall <= 0)
  834. return(FALSE);
  835. }
  836. // find the intersection
  837. enmr.iWall += enmr.iOff;
  838. LONG x = xWall(0);
  839. if (bLeftToRight() == (x > pcle->ptE.x))
  840. {
  841. // line exits scan before intersecting next wall...
  842. return(FALSE);
  843. }
  844. bIntersectWall(x,NULL,&pcle->ptB,&pcle->iStart);
  845. return(TRUE);
  846. }
  847. /******************************Member*Function*****************************\
  848. * BOOL XCLIPOBJ::bRecordRun(LONG& iStop)
  849. *
  850. * On Entry:
  851. *
  852. * pcle->iStart - index of start - 1
  853. * iStop - index of end of run
  854. *
  855. * On Exit:
  856. *
  857. * iC - same as iStop if can't record
  858. *
  859. * History:
  860. * 12-Mar-1991 -by- Eric Kutter [erick]
  861. * Wrote it.
  862. \**************************************************************************/
  863. BOOL XCLIPOBJ::bRecordRun(LONG& iStop)
  864. {
  865. // don't record if going backwards
  866. if (iStop <= pcle->iStart)
  867. return(TRUE);
  868. // do we append the run?
  869. if (pcle->iStart != pcle->iPrevStop)
  870. {
  871. // Are we out of room?
  872. if (*pcle->pcRuns == pcle->cMaxRuns)
  873. {
  874. pcle->iC = iStop;
  875. return(FALSE);
  876. }
  877. // set the run
  878. pcle->prun->iStop = iStop;
  879. pcle->prun->iStart = pcle->iStart + 1;
  880. // increment the count
  881. (*pcle->pcRuns)++;
  882. pcle->prun++;
  883. }
  884. else // append the run
  885. {
  886. ASSERTGDI(*pcle->pcRuns > 0,"CLIPOBJ::bRecordRun,cruns == 0\n");
  887. pcle->prun[-1].iStop = iStop;
  888. }
  889. pcle->iPrevStop = iStop;
  890. return(TRUE);
  891. }
  892. /******************************Member*Function*****************************\
  893. * VOID XCLIPOBJ::vIntersectScan
  894. *
  895. * On Entry:
  896. *
  897. * y - y coordinate of scan to intersect
  898. *
  899. * On Exit:
  900. *
  901. * ppt0 - last point before intersection (may be NULL)
  902. * ppt1 - first point after intersection
  903. * pi0 - run position for ppt0.
  904. * run position for ppt1 = pi0 + 1;
  905. *
  906. * History:
  907. * 27-Mar-1991 -by- Eric Kutter [erick]
  908. * Wrote it.
  909. \**************************************************************************/
  910. VOID XCLIPOBJ::vIntersectScan(LONG y, PPOINTL ppt0, PPOINTL ppt1, PLONG pi0)
  911. {
  912. if (pcle->dda.bVFlip())
  913. y = -y + 1;
  914. if (!pcle->dda.bDFlip())
  915. vIntersectHorizontal(&pcle->dda,y,ppt0,ppt1,pi0);
  916. else
  917. vIntersectVertical(&pcle->dda,y,ppt0,ppt1,pi0);
  918. }
  919. /******************************Member*Function*****************************\
  920. * BOOL XCLIPOBJ::bIntersectWall
  921. *
  922. * Compute the intersection of the line with the current wall + i.
  923. * The important results are the last pel before the intersection and
  924. * the first pel after the intersection as well as the run index of the
  925. * last pel before the intersection.
  926. *
  927. * On Entry:
  928. *
  929. * x - wall column
  930. *
  931. * On Exit:
  932. *
  933. * always assumes there will be an intersection with the given wall, so
  934. * always returns TRUE
  935. *
  936. * ppt0 - last point before intersection (may be NULL)
  937. * ppt1 - first point after intersection (may be NULL)
  938. * pi0 - run position for ppt0.
  939. * run position for ppt1 = pi0 + 1;
  940. *
  941. * History:
  942. * 27-Mar-1991 -by- Eric Kutter [erick]
  943. * Wrote it.
  944. \**************************************************************************/
  945. BOOL XCLIPOBJ::bIntersectWall(LONG x, PPOINTL ppt0, PPOINTL ppt1, PLONG pi0)
  946. {
  947. if (pcle->dda.bHFlip())
  948. x = -x + 1;
  949. if (!pcle->dda.bDFlip())
  950. vIntersectVertical(&pcle->dda,x,ppt0,ppt1,pi0);
  951. else
  952. vIntersectHorizontal(&pcle->dda,x,ppt0,ppt1,pi0);
  953. return(TRUE);
  954. }
  955. /******************************Public*Routine******************************\
  956. * LONG yCompute(x)
  957. *
  958. * For the given column x, calculate the y-coordinate of the pixel
  959. * on the line that will be lit:
  960. * History:
  961. * 27-Aug-1992 -by- J. Andrew Goossen [andrewgo]
  962. * Wrote it.
  963. \**************************************************************************/
  964. inline LONG DDA_CLIPLINE::yCompute(LONG x)
  965. {
  966. LONGLONG eq = Int32x32To64((LONG) dN, x - ptlOrg.x) + eqGamma;
  967. ASSERTGDI(eq >= 0, "Negative x not expected");
  968. return((LONG) DIV(eq,dM) + ptlOrg.y);
  969. }
  970. /******************************Public*Routine******************************\
  971. * LONG xCompute(y)
  972. *
  973. * For the given row y, calculates the x-coordinate of the rightmost
  974. * pixel that will be lit on the line:
  975. *
  976. * History:
  977. * 27-Aug-1992 -by- J. Andrew Goossen [andrewgo]
  978. * Wrote it.
  979. \**************************************************************************/
  980. inline LONG DDA_CLIPLINE::xCompute(LONG y)
  981. {
  982. LONGLONG eq = Int32x32To64((LONG) dM, y - ptlOrg.y + 1) - eqGamma - 1;
  983. ASSERTGDI(eq >= 0, "Negative y not expected");
  984. return((LONG) DIV(eq,dN) + ptlOrg.x);
  985. }
  986. /******************************Public*Routine******************************\
  987. * VOID vIntersectHorizontal(pdda, yBorder, ppt0, ppt1, pi0)
  988. *
  989. * Calculates ppt0, the last point on the line given by pdda before a
  990. * horizontal bound at yBorder. Also calculates ppt1, the next point on
  991. * the line that would be lit.
  992. *
  993. * History:
  994. * 27-Aug-1992 -by- J. Andrew Goossen [andrewgo]
  995. * Rewrote it.
  996. *
  997. * 12-Mar-1991 -by- Eric Kutter [erick]
  998. * Wrote it.
  999. \**************************************************************************/
  1000. VOID vIntersectHorizontal(
  1001. DDA_CLIPLINE* pdda,
  1002. LONG yBorder,
  1003. POINTL* ppt0, // may be NULL
  1004. POINTL* ppt1, // may be NULL
  1005. LONG* pi0)
  1006. {
  1007. LONG xLast = pdda->xCompute(yBorder - 1);
  1008. // calculation
  1009. if (ppt0 != (POINTL*) NULL)
  1010. {
  1011. ppt0->x = xLast;
  1012. ppt0->y = yBorder - 1;
  1013. pdda->vUnflip(&ppt0->x, &ppt0->y);
  1014. }
  1015. if (ppt1 != (POINTL*) NULL)
  1016. {
  1017. ppt1->x = xLast + 1;
  1018. ppt1->y = yBorder;
  1019. pdda->vUnflip(&ppt1->x, &ppt1->y);
  1020. }
  1021. ASSERTGDI(xLast <= pdda->lX1, "xLast out of bounds");
  1022. *pi0 = xLast - pdda->lX0;
  1023. }
  1024. /******************************Public*Routine******************************\
  1025. * VOID vIntersectVertical(pdda, xBorder, ppt0, ppt1, pi0)
  1026. *
  1027. * Calculates ppt0, the last point on the line given by pdda before a
  1028. * vertical bound at xBorder. Also calculates ppt1, the next point on
  1029. * the line that would be lit.
  1030. *
  1031. * History:
  1032. * 27-Aug-1992 -by- J. Andrew Goossen [andrewgo]
  1033. * Rewrote it.
  1034. *
  1035. * 12-Mar-1991 -by- Eric Kutter [erick]
  1036. * Wrote it.
  1037. \**************************************************************************/
  1038. VOID vIntersectVertical(
  1039. DDA_CLIPLINE* pdda,
  1040. LONG xBorder,
  1041. POINTL* ppt0, // may be NULL
  1042. POINTL* ppt1, // may be NULL
  1043. LONG* pi0)
  1044. {
  1045. // compute the coordinates and run index
  1046. LONG xLast = xBorder - 1;
  1047. if (ppt0 != (POINTL*) NULL)
  1048. {
  1049. ppt0->x = xBorder - 1;
  1050. ppt0->y = pdda->yCompute(xBorder - 1);
  1051. pdda->vUnflip(&ppt0->x, &ppt0->y);
  1052. }
  1053. if (ppt1 != (POINTL*) NULL)
  1054. {
  1055. ppt1->x = xBorder;
  1056. ppt1->y = pdda->yCompute(xBorder);
  1057. pdda->vUnflip(&ppt1->x, &ppt1->y);
  1058. }
  1059. ASSERTGDI(xLast <= pdda->lX1, "xLast out of bounds");
  1060. *pi0 = xLast - pdda->lX0;
  1061. }