line.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. //*****************************************************************************
  2. //
  3. // line.c - Routines for drawing lines.
  4. //
  5. // Copyright (c) 2007-2010 Texas Instruments Incorporated. All rights reserved.
  6. // Software License Agreement
  7. //
  8. // Texas Instruments (TI) is supplying this software for use solely and
  9. // exclusively on TI's microcontroller products. The software is owned by
  10. // TI and/or its suppliers, and is protected under applicable copyright
  11. // laws. You may not combine this software with "viral" open-source
  12. // software in order to form a larger program.
  13. //
  14. // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
  15. // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
  16. // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  17. // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
  18. // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
  19. // DAMAGES, FOR ANY REASON WHATSOEVER.
  20. //
  21. // This is part of revision 6288 of the Stellaris Graphics Library.
  22. //
  23. //*****************************************************************************
  24. #include "debug.h"
  25. #include "grlib.h"
  26. //*****************************************************************************
  27. //
  28. //! \addtogroup primitives_api
  29. //! @{
  30. //
  31. //*****************************************************************************
  32. //*****************************************************************************
  33. //
  34. //! Draws a horizontal line.
  35. //!
  36. //! \param pContext is a pointer to the drawing context to use.
  37. //! \param lX1 is the X coordinate of one end of the line.
  38. //! \param lX2 is the X coordinate of the other end of the line.
  39. //! \param lY is the Y coordinate of the line.
  40. //!
  41. //! This function draws a horizontal line, taking advantage of the fact that
  42. //! the line is horizontal to draw it more efficiently. The clipping of the
  43. //! horizontal line to the clipping rectangle is performed within this routine;
  44. //! the display driver's horizontal line routine is used to perform the actual
  45. //! line drawing.
  46. //!
  47. //! \return None.
  48. //
  49. //*****************************************************************************
  50. void
  51. GrLineDrawH(const tContext *pContext, int lX1, int lX2, int lY)
  52. {
  53. int lTemp;
  54. //
  55. // Check the arguments.
  56. //
  57. ASSERT(pContext);
  58. //
  59. // If the Y coordinate of this line is not in the clipping region, then
  60. // there is nothing to be done.
  61. //
  62. if((lY < pContext->sClipRegion.sYMin) ||
  63. (lY > pContext->sClipRegion.sYMax))
  64. {
  65. return;
  66. }
  67. //
  68. // Swap the X coordinates if the first is larger than the second.
  69. //
  70. if(lX1 > lX2)
  71. {
  72. lTemp = lX1;
  73. lX1 = lX2;
  74. lX2 = lTemp;
  75. }
  76. //
  77. // If the entire line is outside the clipping region, then there is nothing
  78. // to be done.
  79. //
  80. if((lX1 > pContext->sClipRegion.sXMax) ||
  81. (lX2 < pContext->sClipRegion.sXMin))
  82. {
  83. return;
  84. }
  85. //
  86. // Clip the starting coordinate to the left side of the clipping region if
  87. // required.
  88. //
  89. if(lX1 < pContext->sClipRegion.sXMin)
  90. {
  91. lX1 = pContext->sClipRegion.sXMin;
  92. }
  93. //
  94. // Clip the ending coordinate to the right side of the clipping region if
  95. // required.
  96. //
  97. if(lX2 > pContext->sClipRegion.sXMax)
  98. {
  99. lX2 = pContext->sClipRegion.sXMax;
  100. }
  101. //
  102. // Call the low level horizontal line drawing routine.
  103. //
  104. DpyLineDrawH(pContext->pDisplay, lX1, lX2, lY, pContext->ulForeground);
  105. }
  106. //*****************************************************************************
  107. //
  108. //! Draws a vertical line.
  109. //!
  110. //! \param pContext is a pointer to the drawing context to use.
  111. //! \param lX is the X coordinate of the line.
  112. //! \param lY1 is the Y coordinate of one end of the line.
  113. //! \param lY2 is the Y coordinate of the other end of the line.
  114. //!
  115. //! This function draws a vertical line, taking advantage of the fact that the
  116. //! line is vertical to draw it more efficiently. The clipping of the vertical
  117. //! line to the clipping rectangle is performed within this routine; the
  118. //! display driver's vertical line routine is used to perform the actual line
  119. //! drawing.
  120. //!
  121. //! \return None.
  122. //
  123. //*****************************************************************************
  124. void
  125. GrLineDrawV(const tContext *pContext, int lX, int lY1, int lY2)
  126. {
  127. int lTemp;
  128. //
  129. // Check the arguments.
  130. //
  131. ASSERT(pContext);
  132. //
  133. // If the X coordinate of this line is not within the clipping region, then
  134. // there is nothing to be done.
  135. //
  136. if((lX < pContext->sClipRegion.sXMin) ||
  137. (lX > pContext->sClipRegion.sXMax))
  138. {
  139. return;
  140. }
  141. //
  142. // Swap the Y coordinates if the first is larger than the second.
  143. //
  144. if(lY1 > lY2)
  145. {
  146. lTemp = lY1;
  147. lY1 = lY2;
  148. lY2 = lTemp;
  149. }
  150. //
  151. // If the entire line is out of the clipping region, then there is nothing
  152. // to be done.
  153. //
  154. if((lY1 > pContext->sClipRegion.sYMax) ||
  155. (lY2 < pContext->sClipRegion.sYMin))
  156. {
  157. return;
  158. }
  159. //
  160. // Clip the starting coordinate to the top side of the clipping region if
  161. // required.
  162. //
  163. if(lY1 < pContext->sClipRegion.sYMin)
  164. {
  165. lY1 = pContext->sClipRegion.sYMin;
  166. }
  167. //
  168. // Clip the ending coordinate to the bottom side of the clipping region if
  169. // required.
  170. //
  171. if(lY2 > pContext->sClipRegion.sYMax)
  172. {
  173. lY2 = pContext->sClipRegion.sYMax;
  174. }
  175. //
  176. // Call the low level vertical line drawing routine.
  177. //
  178. DpyLineDrawV(pContext->pDisplay, lX, lY1, lY2, pContext->ulForeground);
  179. }
  180. //*****************************************************************************
  181. //
  182. //! Computes the clipping code used by the Cohen-Sutherland clipping algorithm.
  183. //!
  184. //! \param pContext is a pointer to the drawing context to use.
  185. //! \param lX is the X coordinate of the point.
  186. //! \param lY is the Y coordinate of the point.
  187. //!
  188. //! This function computes the clipping code used by the Cohen-Sutherland
  189. //! clipping algorithm. Clipping is performed by classifying the endpoints of
  190. //! the line based on their relation to the clipping region; this determines
  191. //! those relationships.
  192. //!
  193. //! \return Returns the clipping code.
  194. //
  195. //*****************************************************************************
  196. static int
  197. GrClipCodeGet(const tContext *pContext, int lX, int lY)
  198. {
  199. int lCode;
  200. //
  201. // Initialize the clipping code to zero.
  202. //
  203. lCode = 0;
  204. //
  205. // Set bit zero of the clipping code if the Y coordinate is above the
  206. // clipping region.
  207. //
  208. if(lY < pContext->sClipRegion.sYMin)
  209. {
  210. lCode |= 1;
  211. }
  212. //
  213. // Set bit one of the clipping code if the Y coordinate is below the
  214. // clipping region.
  215. //
  216. if(lY > pContext->sClipRegion.sYMax)
  217. {
  218. lCode |= 2;
  219. }
  220. //
  221. // Set bit two of the clipping code if the X coordinate is to the left of
  222. // the clipping region.
  223. //
  224. if(lX < pContext->sClipRegion.sXMin)
  225. {
  226. lCode |= 4;
  227. }
  228. //
  229. // Set bit three of the clipping code if the X coordinate is to the right
  230. // of the clipping region.
  231. //
  232. if(lX > pContext->sClipRegion.sXMax)
  233. {
  234. lCode |= 8;
  235. }
  236. //
  237. // Return the clipping code.
  238. //
  239. return(lCode);
  240. }
  241. //*****************************************************************************
  242. //
  243. //! Clips a line to the clipping region.
  244. //!
  245. //! \param pContext is a pointer to the drawing context to use.
  246. //! \param plX1 is the X coordinate of the start of the line.
  247. //! \param plY1 is the Y coordinate of the start of the line.
  248. //! \param plX2 is the X coordinate of the end of the line.
  249. //! \param plY2 is the Y coordinate of the end of the line.
  250. //!
  251. //! This function clips a line to the extents of the clipping region using the
  252. //! Cohen-Sutherland clipping algorithm. The ends of the line are classified
  253. //! based on their relation to the clipping region, and the codes are used to
  254. //! either trivially accept a line (both end points within the clipping
  255. //! region), trivially reject a line (both end points to one side of the
  256. //! clipping region), or to adjust an endpoint one axis at a time to the edge
  257. //! of the clipping region until the line can either be trivially accepted or
  258. //! trivially rejected.
  259. //!
  260. //! The provided coordinates are modified such that they reside within the
  261. //! extents of the clipping region if the line is not rejected. If it is
  262. //! rejected, the coordinates may be modified during the process of attempting
  263. //! to clip them.
  264. //!
  265. //! \return Returns one if the clipped line lies within the extent of the
  266. //! clipping region and zero if it does not.
  267. //
  268. //*****************************************************************************
  269. static int
  270. GrLineClip(const tContext *pContext, int *plX1, int *plY1, int *plX2,
  271. int *plY2)
  272. {
  273. int lCode, lCode1, lCode2, lX, lY;
  274. //
  275. // Compute the clipping codes for the two endpoints of the line.
  276. //
  277. lCode1 = GrClipCodeGet(pContext, *plX1, *plY1);
  278. lCode2 = GrClipCodeGet(pContext, *plX2, *plY2);
  279. //
  280. // Loop forever. This loop will be explicitly broken out of when the line
  281. // is either trivially accepted or trivially rejected.
  282. //
  283. while(1)
  284. {
  285. //
  286. // If both codes are zero, then both points lie within the extent of
  287. // the clipping region. In this case, trivally accept the line.
  288. //
  289. if((lCode1 == 0) && (lCode2 == 0))
  290. {
  291. return(1);
  292. }
  293. //
  294. // If the intersection of the codes is non-zero, then the line lies
  295. // entirely off one edge of the clipping region. In this case,
  296. // trivally reject the line.
  297. //
  298. if((lCode1 & lCode2) != 0)
  299. {
  300. return(0);
  301. }
  302. //
  303. // Determine the end of the line to move. The first end of the line is
  304. // moved until it is within the clipping region, and then the second
  305. // end of the line is moved until it is also within the clipping
  306. // region.
  307. //
  308. if(lCode1)
  309. {
  310. lCode = lCode1;
  311. }
  312. else
  313. {
  314. lCode = lCode2;
  315. }
  316. //
  317. // See if this end of the line lies above the clipping region.
  318. //
  319. if(lCode & 1)
  320. {
  321. //
  322. // Move this end of the line to the intersection of the line and
  323. // the top of the clipping region.
  324. //
  325. lX = (*plX1 + (((*plX2 - *plX1) *
  326. (pContext->sClipRegion.sYMin - *plY1)) /
  327. (*plY2 - *plY1)));
  328. lY = pContext->sClipRegion.sYMin;
  329. }
  330. //
  331. // Otherwise, see if this end of the line lies below the clipping
  332. // region.
  333. //
  334. else if(lCode & 2)
  335. {
  336. //
  337. // Move this end of the line to the intersection of the line and
  338. // the bottom of the clipping region.
  339. //
  340. lX = (*plX1 + (((*plX2 - *plX1) *
  341. (pContext->sClipRegion.sYMax - *plY1)) /
  342. (*plY2 - *plY1)));
  343. lY = pContext->sClipRegion.sYMax;
  344. }
  345. //
  346. // Otherwise, see if this end of the line lies to the left of the
  347. // clipping region.
  348. //
  349. else if(lCode & 4)
  350. {
  351. //
  352. // Move this end of the line to the intersection of the line and
  353. // the left side of the clipping region.
  354. //
  355. lX = pContext->sClipRegion.sXMin;
  356. lY = (*plY1 + (((*plY2 - *plY1) *
  357. (pContext->sClipRegion.sXMin - *plX1)) /
  358. (*plX2 - *plX1)));
  359. }
  360. //
  361. // Otherwise, this end of the line lies to the right of the clipping
  362. // region.
  363. //
  364. else
  365. {
  366. //
  367. // Move this end of the line to the intersection of the line and
  368. // the right side of the clipping region.
  369. //
  370. lX = pContext->sClipRegion.sXMax;
  371. lY = (*plY1 + (((*plY2 - *plY1) *
  372. (pContext->sClipRegion.sXMax - *plX1)) /
  373. (*plX2 - *plX1)));
  374. }
  375. //
  376. // See which end of the line just moved.
  377. //
  378. if(lCode1)
  379. {
  380. //
  381. // Save the new coordinates for the start of the line.
  382. //
  383. *plX1 = lX;
  384. *plY1 = lY;
  385. //
  386. // Recompute the clipping code for the start of the line.
  387. //
  388. lCode1 = GrClipCodeGet(pContext, lX, lY);
  389. }
  390. else
  391. {
  392. //
  393. // Save the new coordinates for the end of the line.
  394. //
  395. *plX2 = lX;
  396. *plY2 = lY;
  397. //
  398. // Recompute the clipping code for the end of the line.
  399. //
  400. lCode2 = GrClipCodeGet(pContext, lX, lY);
  401. }
  402. }
  403. }
  404. //*****************************************************************************
  405. //
  406. //! Draws a line.
  407. //!
  408. //! \param pContext is a pointer to the drawing context to use.
  409. //! \param lX1 is the X coordinate of the start of the line.
  410. //! \param lY1 is the Y coordinate of the start of the line.
  411. //! \param lX2 is the X coordinate of the end of the line.
  412. //! \param lY2 is the Y coordinate of the end of the line.
  413. //!
  414. //! This function draws a line, utilizing GrLineDrawH() and GrLineDrawV() to
  415. //! draw the line as efficiently as possible. The line is clipped to the
  416. //! clippping rectangle using the Cohen-Sutherland clipping algorithm, and then
  417. //! scan converted using Bresenham's line drawing algorithm.
  418. //!
  419. //! \return None.
  420. //
  421. //*****************************************************************************
  422. void
  423. GrLineDraw(const tContext *pContext, int lX1, int lY1, int lX2, int lY2)
  424. {
  425. int lError, lDeltaX, lDeltaY, lYStep, bSteep;
  426. //
  427. // Check the arguments.
  428. //
  429. ASSERT(pContext);
  430. //
  431. // See if this is a vertical line.
  432. //
  433. if(lX1 == lX2)
  434. {
  435. //
  436. // It is more efficient to avoid Bresenham's algorithm when drawing a
  437. // vertical line, so use the vertical line routine to draw this line.
  438. //
  439. GrLineDrawV(pContext, lX1, lY1, lY2);
  440. //
  441. // The line has ben drawn, so return.
  442. //
  443. return;
  444. }
  445. //
  446. // See if this is a horizontal line.
  447. //
  448. if(lY1 == lY2)
  449. {
  450. //
  451. // It is more efficient to avoid Bresenham's algorithm when drawing a
  452. // horizontal line, so use the horizontal line routien to draw this
  453. // line.
  454. //
  455. GrLineDrawH(pContext, lX1, lX2, lY1);
  456. //
  457. // The line has ben drawn, so return.
  458. //
  459. return;
  460. }
  461. //
  462. // Clip this line if necessary, and return without drawing anything if the
  463. // line does not cross the clipping region.
  464. //
  465. if(GrLineClip(pContext, &lX1, &lY1, &lX2, &lY2) == 0)
  466. {
  467. return;
  468. }
  469. //
  470. // Determine if the line is steep. A steep line has more motion in the Y
  471. // direction than the X direction.
  472. //
  473. if(((lY2 > lY1) ? (lY2 - lY1) : (lY1 - lY2)) >
  474. ((lX2 > lX1) ? (lX2 - lX1) : (lX1 - lX2)))
  475. {
  476. bSteep = 1;
  477. }
  478. else
  479. {
  480. bSteep = 0;
  481. }
  482. //
  483. // If the line is steep, then swap the X and Y coordinates.
  484. //
  485. if(bSteep)
  486. {
  487. lError = lX1;
  488. lX1 = lY1;
  489. lY1 = lError;
  490. lError = lX2;
  491. lX2 = lY2;
  492. lY2 = lError;
  493. }
  494. //
  495. // If the starting X coordinate is larger than the ending X coordinate,
  496. // then swap the start and end coordinates.
  497. //
  498. if(lX1 > lX2)
  499. {
  500. lError = lX1;
  501. lX1 = lX2;
  502. lX2 = lError;
  503. lError = lY1;
  504. lY1 = lY2;
  505. lY2 = lError;
  506. }
  507. //
  508. // Compute the difference between the start and end coordinates in each
  509. // axis.
  510. //
  511. lDeltaX = lX2 - lX1;
  512. lDeltaY = (lY2 > lY1) ? (lY2 - lY1) : (lY1 - lY2);
  513. //
  514. // Initialize the error term to negative half the X delta.
  515. //
  516. lError = -lDeltaX / 2;
  517. //
  518. // Determine the direction to step in the Y axis when required.
  519. //
  520. if(lY1 < lY2)
  521. {
  522. lYStep = 1;
  523. }
  524. else
  525. {
  526. lYStep = -1;
  527. }
  528. //
  529. // Loop through all the points along the X axis of the line.
  530. //
  531. for(; lX1 <= lX2; lX1++)
  532. {
  533. //
  534. // See if this is a steep line.
  535. //
  536. if(bSteep)
  537. {
  538. //
  539. // Plot this point of the line, swapping the X and Y coordinates.
  540. //
  541. DpyPixelDraw(pContext->pDisplay, lY1, lX1, pContext->ulForeground);
  542. }
  543. else
  544. {
  545. //
  546. // Plot this point of the line, using the coordinates as is.
  547. //
  548. DpyPixelDraw(pContext->pDisplay, lX1, lY1, pContext->ulForeground);
  549. }
  550. //
  551. // Increment the error term by the Y delta.
  552. //
  553. lError += lDeltaY;
  554. //
  555. // See if the error term is now greater than zero.
  556. //
  557. if(lError > 0)
  558. {
  559. //
  560. // Take a step in the Y axis.
  561. //
  562. lY1 += lYStep;
  563. //
  564. // Decrement the error term by the X delta.
  565. //
  566. lError -= lDeltaX;
  567. }
  568. }
  569. }
  570. //*****************************************************************************
  571. //
  572. // Close the Doxygen group.
  573. //! @}
  574. //
  575. //*****************************************************************************