The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

280 lines
8.5KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #if JUCE_MSVC && JUCE_DEBUG
  18. #pragma optimize ("t", on)
  19. #endif
  20. //==============================================================================
  21. PathFlatteningIterator::PathFlatteningIterator (const Path& path_,
  22. const AffineTransform& transform_,
  23. const float tolerance)
  24. : x2 (0),
  25. y2 (0),
  26. closesSubPath (false),
  27. subPathIndex (-1),
  28. path (path_),
  29. transform (transform_),
  30. points (path_.data.elements),
  31. toleranceSquared (tolerance * tolerance),
  32. isIdentityTransform (transform_.isIdentity())
  33. {
  34. stackPos = stackBase;
  35. }
  36. PathFlatteningIterator::~PathFlatteningIterator()
  37. {
  38. }
  39. bool PathFlatteningIterator::isLastInSubpath() const noexcept
  40. {
  41. return stackPos == stackBase.getData()
  42. && (index >= path.numElements || isMarker (points[index], Path::moveMarker));
  43. }
  44. bool PathFlatteningIterator::next()
  45. {
  46. x1 = x2;
  47. y1 = y2;
  48. float x3 = 0;
  49. float y3 = 0;
  50. float x4 = 0;
  51. float y4 = 0;
  52. for (;;)
  53. {
  54. float type;
  55. if (stackPos == stackBase)
  56. {
  57. if (index >= path.numElements)
  58. return false;
  59. type = points [index++];
  60. if (! isMarker (type, Path::closeSubPathMarker))
  61. {
  62. x2 = points [index++];
  63. y2 = points [index++];
  64. if (isMarker (type, Path::quadMarker))
  65. {
  66. x3 = points [index++];
  67. y3 = points [index++];
  68. if (! isIdentityTransform)
  69. transform.transformPoints (x2, y2, x3, y3);
  70. }
  71. else if (isMarker (type, Path::cubicMarker))
  72. {
  73. x3 = points [index++];
  74. y3 = points [index++];
  75. x4 = points [index++];
  76. y4 = points [index++];
  77. if (! isIdentityTransform)
  78. transform.transformPoints (x2, y2, x3, y3, x4, y4);
  79. }
  80. else
  81. {
  82. if (! isIdentityTransform)
  83. transform.transformPoint (x2, y2);
  84. }
  85. }
  86. }
  87. else
  88. {
  89. type = *--stackPos;
  90. if (! isMarker (type, Path::closeSubPathMarker))
  91. {
  92. x2 = *--stackPos;
  93. y2 = *--stackPos;
  94. if (isMarker (type, Path::quadMarker))
  95. {
  96. x3 = *--stackPos;
  97. y3 = *--stackPos;
  98. }
  99. else if (isMarker (type, Path::cubicMarker))
  100. {
  101. x3 = *--stackPos;
  102. y3 = *--stackPos;
  103. x4 = *--stackPos;
  104. y4 = *--stackPos;
  105. }
  106. }
  107. }
  108. if (isMarker (type, Path::lineMarker))
  109. {
  110. ++subPathIndex;
  111. closesSubPath = (stackPos == stackBase)
  112. && (index < path.numElements)
  113. && (points [index] == Path::closeSubPathMarker)
  114. && x2 == subPathCloseX
  115. && y2 == subPathCloseY;
  116. return true;
  117. }
  118. if (isMarker (type, Path::quadMarker))
  119. {
  120. const size_t offset = (size_t) (stackPos - stackBase);
  121. if (offset >= stackSize - 10)
  122. {
  123. stackSize <<= 1;
  124. stackBase.realloc (stackSize);
  125. stackPos = stackBase + offset;
  126. }
  127. auto m1x = (x1 + x2) * 0.5f;
  128. auto m1y = (y1 + y2) * 0.5f;
  129. auto m2x = (x2 + x3) * 0.5f;
  130. auto m2y = (y2 + y3) * 0.5f;
  131. auto m3x = (m1x + m2x) * 0.5f;
  132. auto m3y = (m1y + m2y) * 0.5f;
  133. auto errorX = m3x - x2;
  134. auto errorY = m3y - y2;
  135. if (errorX * errorX + errorY * errorY > toleranceSquared)
  136. {
  137. *stackPos++ = y3;
  138. *stackPos++ = x3;
  139. *stackPos++ = m2y;
  140. *stackPos++ = m2x;
  141. *stackPos++ = Path::quadMarker;
  142. *stackPos++ = m3y;
  143. *stackPos++ = m3x;
  144. *stackPos++ = m1y;
  145. *stackPos++ = m1x;
  146. *stackPos++ = Path::quadMarker;
  147. }
  148. else
  149. {
  150. *stackPos++ = y3;
  151. *stackPos++ = x3;
  152. *stackPos++ = Path::lineMarker;
  153. *stackPos++ = m3y;
  154. *stackPos++ = m3x;
  155. *stackPos++ = Path::lineMarker;
  156. }
  157. jassert (stackPos < stackBase + stackSize);
  158. }
  159. else if (isMarker (type, Path::cubicMarker))
  160. {
  161. const size_t offset = (size_t) (stackPos - stackBase);
  162. if (offset >= stackSize - 16)
  163. {
  164. stackSize <<= 1;
  165. stackBase.realloc (stackSize);
  166. stackPos = stackBase + offset;
  167. }
  168. auto m1x = (x1 + x2) * 0.5f;
  169. auto m1y = (y1 + y2) * 0.5f;
  170. auto m2x = (x3 + x2) * 0.5f;
  171. auto m2y = (y3 + y2) * 0.5f;
  172. auto m3x = (x3 + x4) * 0.5f;
  173. auto m3y = (y3 + y4) * 0.5f;
  174. auto m4x = (m1x + m2x) * 0.5f;
  175. auto m4y = (m1y + m2y) * 0.5f;
  176. auto m5x = (m3x + m2x) * 0.5f;
  177. auto m5y = (m3y + m2y) * 0.5f;
  178. auto error1X = m4x - x2;
  179. auto error1Y = m4y - y2;
  180. auto error2X = m5x - x3;
  181. auto error2Y = m5y - y3;
  182. if (error1X * error1X + error1Y * error1Y > toleranceSquared
  183. || error2X * error2X + error2Y * error2Y > toleranceSquared)
  184. {
  185. *stackPos++ = y4;
  186. *stackPos++ = x4;
  187. *stackPos++ = m3y;
  188. *stackPos++ = m3x;
  189. *stackPos++ = m5y;
  190. *stackPos++ = m5x;
  191. *stackPos++ = Path::cubicMarker;
  192. *stackPos++ = (m4y + m5y) * 0.5f;
  193. *stackPos++ = (m4x + m5x) * 0.5f;
  194. *stackPos++ = m4y;
  195. *stackPos++ = m4x;
  196. *stackPos++ = m1y;
  197. *stackPos++ = m1x;
  198. *stackPos++ = Path::cubicMarker;
  199. }
  200. else
  201. {
  202. *stackPos++ = y4;
  203. *stackPos++ = x4;
  204. *stackPos++ = Path::lineMarker;
  205. *stackPos++ = m5y;
  206. *stackPos++ = m5x;
  207. *stackPos++ = Path::lineMarker;
  208. *stackPos++ = m4y;
  209. *stackPos++ = m4x;
  210. *stackPos++ = Path::lineMarker;
  211. }
  212. }
  213. else if (isMarker (type, Path::closeSubPathMarker))
  214. {
  215. if (x2 != subPathCloseX || y2 != subPathCloseY)
  216. {
  217. x1 = x2;
  218. y1 = y2;
  219. x2 = subPathCloseX;
  220. y2 = subPathCloseY;
  221. closesSubPath = true;
  222. return true;
  223. }
  224. }
  225. else
  226. {
  227. jassert (isMarker (type, Path::moveMarker));
  228. subPathIndex = -1;
  229. subPathCloseX = x1 = x2;
  230. subPathCloseY = y1 = y2;
  231. }
  232. }
  233. }
  234. #if JUCE_MSVC && JUCE_DEBUG
  235. #pragma optimize ("", on) // resets optimisations to the project defaults
  236. #endif