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.

286 lines
8.4KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - 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 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-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. if (errorX * errorX + errorY * errorY > toleranceSquared)
  139. {
  140. *stackPos++ = y3;
  141. *stackPos++ = x3;
  142. *stackPos++ = m2y;
  143. *stackPos++ = m2x;
  144. *stackPos++ = Path::quadMarker;
  145. *stackPos++ = m3y;
  146. *stackPos++ = m3x;
  147. *stackPos++ = m1y;
  148. *stackPos++ = m1x;
  149. *stackPos++ = Path::quadMarker;
  150. }
  151. else
  152. {
  153. *stackPos++ = y3;
  154. *stackPos++ = x3;
  155. *stackPos++ = Path::lineMarker;
  156. *stackPos++ = m3y;
  157. *stackPos++ = m3x;
  158. *stackPos++ = Path::lineMarker;
  159. }
  160. jassert (stackPos < stackBase + stackSize);
  161. }
  162. else if (isMarker (type, Path::cubicMarker))
  163. {
  164. const size_t offset = (size_t) (stackPos - stackBase);
  165. if (offset >= stackSize - 16)
  166. {
  167. stackSize <<= 1;
  168. stackBase.realloc (stackSize);
  169. stackPos = stackBase + offset;
  170. }
  171. auto m1x = (x1 + x2) * 0.5f;
  172. auto m1y = (y1 + y2) * 0.5f;
  173. auto m2x = (x3 + x2) * 0.5f;
  174. auto m2y = (y3 + y2) * 0.5f;
  175. auto m3x = (x3 + x4) * 0.5f;
  176. auto m3y = (y3 + y4) * 0.5f;
  177. auto m4x = (m1x + m2x) * 0.5f;
  178. auto m4y = (m1y + m2y) * 0.5f;
  179. auto m5x = (m3x + m2x) * 0.5f;
  180. auto m5y = (m3y + m2y) * 0.5f;
  181. auto error1X = m4x - x2;
  182. auto error1Y = m4y - y2;
  183. auto error2X = m5x - x3;
  184. auto error2Y = m5y - y3;
  185. if (error1X * error1X + error1Y * error1Y > toleranceSquared
  186. || error2X * error2X + error2Y * error2Y > toleranceSquared)
  187. {
  188. *stackPos++ = y4;
  189. *stackPos++ = x4;
  190. *stackPos++ = m3y;
  191. *stackPos++ = m3x;
  192. *stackPos++ = m5y;
  193. *stackPos++ = m5x;
  194. *stackPos++ = Path::cubicMarker;
  195. *stackPos++ = (m4y + m5y) * 0.5f;
  196. *stackPos++ = (m4x + m5x) * 0.5f;
  197. *stackPos++ = m4y;
  198. *stackPos++ = m4x;
  199. *stackPos++ = m1y;
  200. *stackPos++ = m1x;
  201. *stackPos++ = Path::cubicMarker;
  202. }
  203. else
  204. {
  205. *stackPos++ = y4;
  206. *stackPos++ = x4;
  207. *stackPos++ = Path::lineMarker;
  208. *stackPos++ = m5y;
  209. *stackPos++ = m5x;
  210. *stackPos++ = Path::lineMarker;
  211. *stackPos++ = m4y;
  212. *stackPos++ = m4x;
  213. *stackPos++ = Path::lineMarker;
  214. }
  215. }
  216. else if (isMarker (type, Path::closeSubPathMarker))
  217. {
  218. if (x2 != subPathCloseX || y2 != subPathCloseY)
  219. {
  220. x1 = x2;
  221. y1 = y2;
  222. x2 = subPathCloseX;
  223. y2 = subPathCloseY;
  224. closesSubPath = true;
  225. return true;
  226. }
  227. }
  228. else
  229. {
  230. jassert (isMarker (type, Path::moveMarker));
  231. subPathIndex = -1;
  232. subPathCloseX = x1 = x2;
  233. subPathCloseY = y1 = y2;
  234. }
  235. }
  236. }
  237. #if JUCE_MSVC && JUCE_DEBUG
  238. #pragma optimize ("", on) // resets optimisations to the project defaults
  239. #endif
  240. } // namespace juce