DirtRect.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. //////////////////////////////////////////////////////////////////////////////
  19. //
  20. // DirtRect.CPP
  21. //
  22. // History:
  23. // 04/26/96 JMI Started.
  24. //
  25. // 06/19/96 JMI Added intialization constructors.
  26. //
  27. // 07/08/96 JMI Converted to new CList that does not convert your
  28. // template type into a poiter.
  29. //
  30. // 10/30/96 JMI Changed:
  31. // Old label: New label:
  32. // ========= =========
  33. // DRECT RDRect
  34. // PDRECT RDRect*
  35. // CDirtyRect RDirtyRects <-- Yes; now plural.
  36. // CList RList
  37. //
  38. // 11/15/96 JMI Add() was clipping the actual passed in RDRect. Instead
  39. // we now clip an intermediate RDRect so that the user's
  40. // will not be altered.
  41. //
  42. // 01/23/97 JMI Clip() was not considering that an object might need to
  43. // be clipped on both edges (i.e., if the it needed shrink-
  44. // ing on top edge, it was assuming the bottom edge was
  45. // fine).
  46. //
  47. //////////////////////////////////////////////////////////////////////////////
  48. //
  49. // Combines rectangles into possibly more efficient larger rectangles.
  50. // There are four options as to the operation of a RDirtyRects:
  51. // 1) Minimum distance between rectangles in the x direction, default = 0
  52. // (m_sMinDistanceX).
  53. // 2) Minimum distance between rectangles in the y direction, default = 0
  54. // (m_sMinDistanceY).
  55. // 3) Clipping in the x direction, default = -1 (m_sClipX).
  56. // 4) Clipping in the y direction, default = -1 (m_sClipY).
  57. // -1 for any of the above members indicates to RDirtyRects to ignore that
  58. // functionality (e.g., if m_sMinDistanceX == -1, no rectangles will be com-
  59. // bined).
  60. //
  61. // Use Add(...) to add a rectangle to the list.
  62. // Use GetHead(), GetNext(), GetPrev(), and GetTail() to access the
  63. // rectangles.
  64. // Use Empty() to empty the list.
  65. //
  66. // FUTURE STRATEGIES (04/96):
  67. // The Combine function could be optimized. I better storage class (instead
  68. // of list) could be used to somehow sort the rectangles (might not be worth
  69. // small improvement for standard apps, but could be good for things that
  70. // require many, many dirty rectangles).
  71. //
  72. //////////////////////////////////////////////////////////////////////////////
  73. //////////////////////////////////////////////////////////////////////////////
  74. // C Headers.
  75. //////////////////////////////////////////////////////////////////////////////
  76. //////////////////////////////////////////////////////////////////////////////
  77. // Blue headers.
  78. //////////////////////////////////////////////////////////////////////////////
  79. #ifdef PATHS_IN_INCLUDES
  80. #include "BLUE/system.h"
  81. #else
  82. #include "System.h"
  83. #endif // PATHS_IN_INCLUDES
  84. //////////////////////////////////////////////////////////////////////////////
  85. // Green headers.
  86. //////////////////////////////////////////////////////////////////////////////
  87. //////////////////////////////////////////////////////////////////////////////
  88. // Orange headers.
  89. //////////////////////////////////////////////////////////////////////////////
  90. #ifdef PATHS_IN_INCLUDES
  91. #include "ORANGE/DirtRect/DirtRect.h"
  92. #else
  93. #include "DirtRect.h"
  94. #endif // PATHS_IN_INCLUDES
  95. //////////////////////////////////////////////////////////////////////////////
  96. // Yellow headers.
  97. //////////////////////////////////////////////////////////////////////////////
  98. //////////////////////////////////////////////////////////////////////////////
  99. // Module specific macros.
  100. //////////////////////////////////////////////////////////////////////////////
  101. //////////////////////////////////////////////////////////////////////////////
  102. // Module specific typedefs.
  103. //////////////////////////////////////////////////////////////////////////////
  104. //////////////////////////////////////////////////////////////////////////////
  105. // Module specific (static) variables.
  106. //////////////////////////////////////////////////////////////////////////////
  107. //////////////////////////////////////////////////////////////////////////////
  108. // Con/Destruction.
  109. //////////////////////////////////////////////////////////////////////////////
  110. //////////////////////////////////////////////////////////////////////////////
  111. //
  112. // Constructor.
  113. //
  114. //////////////////////////////////////////////////////////////////////////////
  115. RDirtyRects::RDirtyRects()
  116. {
  117. m_sMinDistanceX = 0;
  118. m_sMinDistanceY = 0;
  119. m_sClipX = -1;
  120. m_sClipY = -1;
  121. }
  122. RDirtyRects::RDirtyRects(
  123. short sMinDistX, // Copied into m_sMinDistanceX.
  124. short sMinDistY, // Copied into m_sMinDistanceY.
  125. short sClipX /*= -1*/, // Copied into m_sClipX.
  126. short sClipY /*= -1*/) // Copied into m_sClipY.
  127. {
  128. m_sMinDistanceX = sMinDistX;
  129. m_sMinDistanceY = sMinDistY;
  130. m_sClipX = sClipX;
  131. m_sClipY = sClipY;
  132. }
  133. //////////////////////////////////////////////////////////////////////////////
  134. //
  135. // Destructor.
  136. //
  137. //////////////////////////////////////////////////////////////////////////////
  138. RDirtyRects::~RDirtyRects()
  139. {
  140. Empty();
  141. }
  142. //////////////////////////////////////////////////////////////////////////////
  143. // Implementation.
  144. //////////////////////////////////////////////////////////////////////////////
  145. //////////////////////////////////////////////////////////////////////////////
  146. //
  147. // Add a rectangle to the list of dirty rectangles.
  148. // The rectangle may get combined with another.
  149. // Returns 0 on success.
  150. //
  151. //////////////////////////////////////////////////////////////////////////////
  152. short RDirtyRects::Add(RDRect* pdr)
  153. {
  154. short sRes = 0; // Assume success.
  155. short sClippedOut = FALSE;
  156. RDRect drTemp = *pdr;
  157. if (m_sClipX >= 0)
  158. {
  159. // If not clipped out in x direction . . .
  160. if (Clip(&drTemp.sX, &drTemp.sW, m_sClipX) == 0)
  161. {
  162. }
  163. else
  164. {
  165. sClippedOut = TRUE;
  166. }
  167. }
  168. if (m_sClipY >= 0)
  169. {
  170. // If not clipped out in y direction . . .
  171. if (Clip(&drTemp.sY, &drTemp.sH, m_sClipY) == 0)
  172. {
  173. }
  174. else
  175. {
  176. sClippedOut = TRUE;
  177. }
  178. }
  179. if (sClippedOut == FALSE)
  180. {
  181. if (Combine(&drTemp) == 0)
  182. {
  183. // Combined into an existing rectangle.
  184. }
  185. else
  186. {
  187. // No existing rectangle was close enough.
  188. RDRect* pdrNew = new RDRect;
  189. if (pdrNew != NULL)
  190. {
  191. if (RList<RDRect>::Add(pdrNew) == 0)
  192. {
  193. *pdrNew = drTemp;
  194. }
  195. else
  196. {
  197. TRACE("Add(): Unable to add *RDRect to list.\n");
  198. sRes = -2;
  199. }
  200. // If any errors occurred after allocation . . .
  201. if (sRes != 0)
  202. {
  203. delete pdrNew;
  204. }
  205. }
  206. else
  207. {
  208. TRACE("Add(): Unable to allocate new RDRect.\n");
  209. sRes = -1;
  210. }
  211. }
  212. }
  213. return sRes;
  214. }
  215. //////////////////////////////////////////////////////////////////////////////
  216. //
  217. // Add a rectangle to the list of dirty rectangles.
  218. // The rectangle may get combined with another.
  219. // Returns 0 on success.
  220. //
  221. //////////////////////////////////////////////////////////////////////////////
  222. short RDirtyRects::Add(short sX, short sY, short sW, short sH)
  223. {
  224. RDRect dr = { sX, sY, sW, sH };
  225. return Add(&dr);
  226. }
  227. //////////////////////////////////////////////////////////////////////////////
  228. //
  229. // Empty the list of dirty rectangles.
  230. //
  231. //////////////////////////////////////////////////////////////////////////////
  232. void RDirtyRects::Empty(void)
  233. {
  234. RDRect* pdr = GetHead();
  235. while (pdr != NULL)
  236. {
  237. Remove();
  238. delete pdr;
  239. pdr = GetNext();
  240. }
  241. }
  242. //////////////////////////////////////////////////////////////////////////////
  243. //
  244. // Combine a rectangle with rectangles already in
  245. // the list if possible.
  246. // Returns 0 if combined.
  247. //
  248. //////////////////////////////////////////////////////////////////////////////
  249. short RDirtyRects::Combine(RDRect* pdr)
  250. {
  251. short sRes = 1; // Assume not combined.
  252. // If combinable . . .
  253. if (m_sMinDistanceX >= 0)
  254. {
  255. RDRect* pdrExisting = GetHead();
  256. while (pdrExisting != NULL)
  257. {
  258. if (pdrExisting->sX - (pdr->sX + pdr->sW) <= m_sMinDistanceX)
  259. {
  260. if (pdr->sX < pdrExisting->sX + pdrExisting->sW + m_sMinDistanceX)
  261. {
  262. if (pdrExisting->sY - (pdr->sY + pdr->sH) <= m_sMinDistanceY)
  263. {
  264. if (pdr->sY < pdrExisting->sY + pdrExisting->sH + m_sMinDistanceY)
  265. {
  266. Expand(pdrExisting, pdr);
  267. // Remove temporarily.
  268. Remove();
  269. // This new rectangle may combine further.
  270. // If it does . . .
  271. if (Combine(pdrExisting) == 0)
  272. {
  273. // We can delete it.
  274. delete pdrExisting;
  275. }
  276. else
  277. {
  278. // Re-insert . . .
  279. if (RList<RDRect>::Add(pdrExisting) == 0)
  280. {
  281. // Success.
  282. }
  283. else
  284. {
  285. TRACE("Combine(): Unable to reAdd rectangle.\n");
  286. delete pdrExisting;
  287. }
  288. }
  289. sRes = 0;
  290. break;
  291. }
  292. }
  293. }
  294. }
  295. pdrExisting = GetNext();
  296. }
  297. }
  298. return sRes;
  299. }
  300. //////////////////////////////////////////////////////////////////////////////
  301. //
  302. // Expand pdrExpand by pdrNew.
  303. //
  304. //////////////////////////////////////////////////////////////////////////////
  305. void RDirtyRects::Expand(RDRect* pdrExpand, RDRect* pdrNew)
  306. {
  307. short sExpandRight = pdrExpand->sX + pdrExpand->sW;
  308. short sExpandBottom = pdrExpand->sY + pdrExpand->sH;
  309. short sNewRight = pdrNew->sX + pdrNew->sW;
  310. short sNewBottom = pdrNew->sY + pdrNew->sH;
  311. if (pdrNew->sX < pdrExpand->sX)
  312. {
  313. pdrExpand->sX = pdrNew->sX;
  314. }
  315. if (pdrNew->sY < pdrExpand->sY)
  316. {
  317. pdrExpand->sY = pdrNew->sY;
  318. }
  319. if (sNewRight > sExpandRight)
  320. {
  321. sExpandRight = sNewRight;
  322. }
  323. if (sNewBottom > sExpandBottom)
  324. {
  325. sExpandBottom = sNewBottom;
  326. }
  327. pdrExpand->sW = sExpandRight - pdrExpand->sX;
  328. pdrExpand->sH = sExpandBottom - pdrExpand->sY;
  329. }
  330. //////////////////////////////////////////////////////////////////////////////
  331. //
  332. // Clip sPos + sDistance to 0 to sClipDistance.
  333. // Returns non-zero if clipped out.
  334. //
  335. //////////////////////////////////////////////////////////////////////////////
  336. short RDirtyRects::Clip(short* psPos, short* psDistance, short sClipDistance)
  337. {
  338. short sRes = 0; // Assume not clipped out.
  339. if (*psPos > sClipDistance)
  340. {
  341. sRes = 1;
  342. }
  343. else
  344. {
  345. if (*psPos < 0)
  346. {
  347. // Reduce by *psPos's underflow.
  348. *psDistance += *psPos;
  349. *psPos = 0;
  350. // If clipped out . . .
  351. if (*psDistance <= 0)
  352. {
  353. sRes = 1;
  354. }
  355. }
  356. // Get amount clipped out.
  357. short sClippedEnd = (*psPos + *psDistance) - sClipDistance;
  358. // If anything clipped out . . .
  359. if (sClippedEnd > 0)
  360. {
  361. *psDistance -= sClippedEnd;
  362. // If clipped out . . .
  363. if (*psDistance <= 0)
  364. {
  365. sRes = 1;
  366. }
  367. }
  368. }
  369. return sRes;
  370. }
  371. //////////////////////////////////////////////////////////////////////////////
  372. // EOF
  373. //////////////////////////////////////////////////////////////////////////////