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.

296 lines
8.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. #if JUCE_MSVC && JUCE_DEBUG
  21. #pragma optimize ("t", on)
  22. #endif
  23. //==============================================================================
  24. PathFlatteningIterator::PathFlatteningIterator (const Path& pathToUse,
  25. const AffineTransform& t,
  26. float tolerance)
  27. : x2 (0),
  28. y2 (0),
  29. closesSubPath (false),
  30. subPathIndex (-1),
  31. path (pathToUse),
  32. transform (t),
  33. source (path.data.begin()),
  34. toleranceSquared (tolerance * tolerance),
  35. isIdentityTransform (t.isIdentity())
  36. {
  37. stackPos = stackBase;
  38. }
  39. PathFlatteningIterator::~PathFlatteningIterator()
  40. {
  41. }
  42. bool PathFlatteningIterator::isLastInSubpath() const noexcept
  43. {
  44. return stackPos == stackBase.get()
  45. && (source == path.data.end() || isMarker (*source, Path::moveMarker));
  46. }
  47. bool PathFlatteningIterator::next()
  48. {
  49. x1 = x2;
  50. y1 = y2;
  51. float x3 = 0;
  52. float y3 = 0;
  53. float x4 = 0;
  54. float y4 = 0;
  55. for (;;)
  56. {
  57. float type;
  58. if (stackPos == stackBase.get())
  59. {
  60. if (source == path.data.end())
  61. return false;
  62. type = *source++;
  63. if (! isMarker (type, Path::closeSubPathMarker))
  64. {
  65. x2 = *source++;
  66. y2 = *source++;
  67. if (isMarker (type, Path::quadMarker))
  68. {
  69. x3 = *source++;
  70. y3 = *source++;
  71. if (! isIdentityTransform)
  72. transform.transformPoints (x2, y2, x3, y3);
  73. }
  74. else if (isMarker (type, Path::cubicMarker))
  75. {
  76. x3 = *source++;
  77. y3 = *source++;
  78. x4 = *source++;
  79. y4 = *source++;
  80. if (! isIdentityTransform)
  81. transform.transformPoints (x2, y2, x3, y3, x4, y4);
  82. }
  83. else
  84. {
  85. if (! isIdentityTransform)
  86. transform.transformPoint (x2, y2);
  87. }
  88. }
  89. }
  90. else
  91. {
  92. type = *--stackPos;
  93. if (! isMarker (type, Path::closeSubPathMarker))
  94. {
  95. x2 = *--stackPos;
  96. y2 = *--stackPos;
  97. if (isMarker (type, Path::quadMarker))
  98. {
  99. x3 = *--stackPos;
  100. y3 = *--stackPos;
  101. }
  102. else if (isMarker (type, Path::cubicMarker))
  103. {
  104. x3 = *--stackPos;
  105. y3 = *--stackPos;
  106. x4 = *--stackPos;
  107. y4 = *--stackPos;
  108. }
  109. }
  110. }
  111. if (isMarker (type, Path::lineMarker))
  112. {
  113. ++subPathIndex;
  114. closesSubPath = stackPos == stackBase.get()
  115. && source != path.data.end()
  116. && *source == Path::closeSubPathMarker
  117. && x2 == subPathCloseX
  118. && y2 == subPathCloseY;
  119. return true;
  120. }
  121. if (isMarker (type, Path::quadMarker))
  122. {
  123. const size_t offset = (size_t) (stackPos - stackBase);
  124. if (offset >= stackSize - 10)
  125. {
  126. stackSize <<= 1;
  127. stackBase.realloc (stackSize);
  128. stackPos = stackBase + offset;
  129. }
  130. auto m1x = (x1 + x2) * 0.5f;
  131. auto m1y = (y1 + y2) * 0.5f;
  132. auto m2x = (x2 + x3) * 0.5f;
  133. auto m2y = (y2 + y3) * 0.5f;
  134. auto m3x = (m1x + m2x) * 0.5f;
  135. auto m3y = (m1y + m2y) * 0.5f;
  136. auto errorX = m3x - x2;
  137. auto errorY = m3y - y2;
  138. auto outsideTolerance = errorX * errorX + errorY * errorY > toleranceSquared;
  139. auto canBeSubdivided = (m3x != m1x && m3x != m2x)
  140. || (m3y != m1y && m3y != m2y);
  141. if (outsideTolerance && canBeSubdivided)
  142. {
  143. *stackPos++ = y3;
  144. *stackPos++ = x3;
  145. *stackPos++ = m2y;
  146. *stackPos++ = m2x;
  147. *stackPos++ = Path::quadMarker;
  148. *stackPos++ = m3y;
  149. *stackPos++ = m3x;
  150. *stackPos++ = m1y;
  151. *stackPos++ = m1x;
  152. *stackPos++ = Path::quadMarker;
  153. }
  154. else
  155. {
  156. *stackPos++ = y3;
  157. *stackPos++ = x3;
  158. *stackPos++ = Path::lineMarker;
  159. *stackPos++ = m3y;
  160. *stackPos++ = m3x;
  161. *stackPos++ = Path::lineMarker;
  162. }
  163. jassert (stackPos < stackBase + stackSize);
  164. }
  165. else if (isMarker (type, Path::cubicMarker))
  166. {
  167. const size_t offset = (size_t) (stackPos - stackBase);
  168. if (offset >= stackSize - 16)
  169. {
  170. stackSize <<= 1;
  171. stackBase.realloc (stackSize);
  172. stackPos = stackBase + offset;
  173. }
  174. auto m1x = (x1 + x2) * 0.5f;
  175. auto m1y = (y1 + y2) * 0.5f;
  176. auto m2x = (x3 + x2) * 0.5f;
  177. auto m2y = (y3 + y2) * 0.5f;
  178. auto m3x = (x3 + x4) * 0.5f;
  179. auto m3y = (y3 + y4) * 0.5f;
  180. auto m4x = (m1x + m2x) * 0.5f;
  181. auto m4y = (m1y + m2y) * 0.5f;
  182. auto m5x = (m3x + m2x) * 0.5f;
  183. auto m5y = (m3y + m2y) * 0.5f;
  184. auto error1X = m4x - x2;
  185. auto error1Y = m4y - y2;
  186. auto error2X = m5x - x3;
  187. auto error2Y = m5y - y3;
  188. auto outsideTolerance = error1X * error1X + error1Y * error1Y > toleranceSquared
  189. || error2X * error2X + error2Y * error2Y > toleranceSquared;
  190. auto canBeSubdivided = (m4x != m1x && m4x != m2x)
  191. || (m4y != m1y && m4y != m2y)
  192. || (m5x != m3x && m5x != m2x)
  193. || (m5y != m3y && m5y != m2y);
  194. if (outsideTolerance && canBeSubdivided)
  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 (isMarker (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 (isMarker (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
  248. } // namespace juce