Audio plugin host https://kx.studio/carla
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.

289 lines
8.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software 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. const float PathFlatteningIterator::defaultTolerance = 0.6f;
  21. //==============================================================================
  22. PathFlatteningIterator::PathFlatteningIterator (const Path& path_,
  23. const AffineTransform& transform_,
  24. const float tolerance)
  25. : x2 (0),
  26. y2 (0),
  27. closesSubPath (false),
  28. subPathIndex (-1),
  29. path (path_),
  30. transform (transform_),
  31. points (path_.data.elements),
  32. toleranceSquared (tolerance * tolerance),
  33. subPathCloseX (0),
  34. subPathCloseY (0),
  35. isIdentityTransform (transform_.isIdentity()),
  36. stackBase (32),
  37. index (0),
  38. stackSize (32)
  39. {
  40. stackPos = stackBase;
  41. }
  42. PathFlatteningIterator::~PathFlatteningIterator()
  43. {
  44. }
  45. bool PathFlatteningIterator::isLastInSubpath() const noexcept
  46. {
  47. return stackPos == stackBase.getData()
  48. && (index >= path.numElements || points [index] == Path::moveMarker);
  49. }
  50. bool PathFlatteningIterator::next()
  51. {
  52. x1 = x2;
  53. y1 = y2;
  54. float x3 = 0;
  55. float y3 = 0;
  56. float x4 = 0;
  57. float y4 = 0;
  58. float type;
  59. for (;;)
  60. {
  61. if (stackPos == stackBase)
  62. {
  63. if (index >= path.numElements)
  64. {
  65. return false;
  66. }
  67. else
  68. {
  69. type = points [index++];
  70. if (type != Path::closeSubPathMarker)
  71. {
  72. x2 = points [index++];
  73. y2 = points [index++];
  74. if (type == Path::quadMarker)
  75. {
  76. x3 = points [index++];
  77. y3 = points [index++];
  78. if (! isIdentityTransform)
  79. transform.transformPoints (x2, y2, x3, y3);
  80. }
  81. else if (type == Path::cubicMarker)
  82. {
  83. x3 = points [index++];
  84. y3 = points [index++];
  85. x4 = points [index++];
  86. y4 = points [index++];
  87. if (! isIdentityTransform)
  88. transform.transformPoints (x2, y2, x3, y3, x4, y4);
  89. }
  90. else
  91. {
  92. if (! isIdentityTransform)
  93. transform.transformPoint (x2, y2);
  94. }
  95. }
  96. }
  97. }
  98. else
  99. {
  100. type = *--stackPos;
  101. if (type != Path::closeSubPathMarker)
  102. {
  103. x2 = *--stackPos;
  104. y2 = *--stackPos;
  105. if (type == Path::quadMarker)
  106. {
  107. x3 = *--stackPos;
  108. y3 = *--stackPos;
  109. }
  110. else if (type == Path::cubicMarker)
  111. {
  112. x3 = *--stackPos;
  113. y3 = *--stackPos;
  114. x4 = *--stackPos;
  115. y4 = *--stackPos;
  116. }
  117. }
  118. }
  119. if (type == Path::lineMarker)
  120. {
  121. ++subPathIndex;
  122. closesSubPath = (stackPos == stackBase)
  123. && (index < path.numElements)
  124. && (points [index] == Path::closeSubPathMarker)
  125. && x2 == subPathCloseX
  126. && y2 == subPathCloseY;
  127. return true;
  128. }
  129. else if (type == Path::quadMarker)
  130. {
  131. const size_t offset = (size_t) (stackPos - stackBase);
  132. if (offset >= stackSize - 10)
  133. {
  134. stackSize <<= 1;
  135. stackBase.realloc (stackSize);
  136. stackPos = stackBase + offset;
  137. }
  138. const float m1x = (x1 + x2) * 0.5f;
  139. const float m1y = (y1 + y2) * 0.5f;
  140. const float m2x = (x2 + x3) * 0.5f;
  141. const float m2y = (y2 + y3) * 0.5f;
  142. const float m3x = (m1x + m2x) * 0.5f;
  143. const float m3y = (m1y + m2y) * 0.5f;
  144. const float errorX = m3x - x2;
  145. const float errorY = m3y - y2;
  146. if (errorX * errorX + errorY * errorY > toleranceSquared)
  147. {
  148. *stackPos++ = y3;
  149. *stackPos++ = x3;
  150. *stackPos++ = m2y;
  151. *stackPos++ = m2x;
  152. *stackPos++ = Path::quadMarker;
  153. *stackPos++ = m3y;
  154. *stackPos++ = m3x;
  155. *stackPos++ = m1y;
  156. *stackPos++ = m1x;
  157. *stackPos++ = Path::quadMarker;
  158. }
  159. else
  160. {
  161. *stackPos++ = y3;
  162. *stackPos++ = x3;
  163. *stackPos++ = Path::lineMarker;
  164. *stackPos++ = m3y;
  165. *stackPos++ = m3x;
  166. *stackPos++ = Path::lineMarker;
  167. }
  168. jassert (stackPos < stackBase + stackSize);
  169. }
  170. else if (type == Path::cubicMarker)
  171. {
  172. const size_t offset = (size_t) (stackPos - stackBase);
  173. if (offset >= stackSize - 16)
  174. {
  175. stackSize <<= 1;
  176. stackBase.realloc (stackSize);
  177. stackPos = stackBase + offset;
  178. }
  179. const float m1x = (x1 + x2) * 0.5f;
  180. const float m1y = (y1 + y2) * 0.5f;
  181. const float m2x = (x3 + x2) * 0.5f;
  182. const float m2y = (y3 + y2) * 0.5f;
  183. const float m3x = (x3 + x4) * 0.5f;
  184. const float m3y = (y3 + y4) * 0.5f;
  185. const float m4x = (m1x + m2x) * 0.5f;
  186. const float m4y = (m1y + m2y) * 0.5f;
  187. const float m5x = (m3x + m2x) * 0.5f;
  188. const float m5y = (m3y + m2y) * 0.5f;
  189. const float error1X = m4x - x2;
  190. const float error1Y = m4y - y2;
  191. const float error2X = m5x - x3;
  192. const float error2Y = m5y - y3;
  193. if (error1X * error1X + error1Y * error1Y > toleranceSquared
  194. || error2X * error2X + error2Y * error2Y > toleranceSquared)
  195. {
  196. *stackPos++ = y4;
  197. *stackPos++ = x4;
  198. *stackPos++ = m3y;
  199. *stackPos++ = m3x;
  200. *stackPos++ = m5y;
  201. *stackPos++ = m5x;
  202. *stackPos++ = Path::cubicMarker;
  203. *stackPos++ = (m4y + m5y) * 0.5f;
  204. *stackPos++ = (m4x + m5x) * 0.5f;
  205. *stackPos++ = m4y;
  206. *stackPos++ = m4x;
  207. *stackPos++ = m1y;
  208. *stackPos++ = m1x;
  209. *stackPos++ = Path::cubicMarker;
  210. }
  211. else
  212. {
  213. *stackPos++ = y4;
  214. *stackPos++ = x4;
  215. *stackPos++ = Path::lineMarker;
  216. *stackPos++ = m5y;
  217. *stackPos++ = m5x;
  218. *stackPos++ = Path::lineMarker;
  219. *stackPos++ = m4y;
  220. *stackPos++ = m4x;
  221. *stackPos++ = Path::lineMarker;
  222. }
  223. }
  224. else if (type == Path::closeSubPathMarker)
  225. {
  226. if (x2 != subPathCloseX || y2 != subPathCloseY)
  227. {
  228. x1 = x2;
  229. y1 = y2;
  230. x2 = subPathCloseX;
  231. y2 = subPathCloseY;
  232. closesSubPath = true;
  233. return true;
  234. }
  235. }
  236. else
  237. {
  238. jassert (type == Path::moveMarker);
  239. subPathIndex = -1;
  240. subPathCloseX = x1 = x2;
  241. subPathCloseY = y1 = y2;
  242. }
  243. }
  244. }
  245. #if JUCE_MSVC && JUCE_DEBUG
  246. #pragma optimize ("", on) // resets optimisations to the project defaults
  247. #endif