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.

227 lines
9.0KB

  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. //==============================================================================
  21. /**
  22. A table of horizontal scan-line segments - used for rasterising Paths.
  23. @see Path, Graphics
  24. @tags{Graphics}
  25. */
  26. class JUCE_API EdgeTable
  27. {
  28. public:
  29. //==============================================================================
  30. /** Creates an edge table containing a path.
  31. A table is created with a fixed vertical range, and only sections of the path
  32. which lie within this range will be added to the table.
  33. @param clipLimits only the region of the path that lies within this area will be added
  34. @param pathToAdd the path to add to the table
  35. @param transform a transform to apply to the path being added
  36. */
  37. EdgeTable (Rectangle<int> clipLimits,
  38. const Path& pathToAdd,
  39. const AffineTransform& transform);
  40. /** Creates an edge table containing a rectangle. */
  41. explicit EdgeTable (Rectangle<int> rectangleToAdd);
  42. /** Creates an edge table containing a rectangle. */
  43. explicit EdgeTable (Rectangle<float> rectangleToAdd);
  44. /** Creates an edge table containing a rectangle list. */
  45. explicit EdgeTable (const RectangleList<int>& rectanglesToAdd);
  46. /** Creates an edge table containing a rectangle list. */
  47. explicit EdgeTable (const RectangleList<float>& rectanglesToAdd);
  48. /** Creates a copy of another edge table. */
  49. EdgeTable (const EdgeTable&);
  50. /** Copies from another edge table. */
  51. EdgeTable& operator= (const EdgeTable&);
  52. /** Destructor. */
  53. ~EdgeTable();
  54. //==============================================================================
  55. void clipToRectangle (Rectangle<int> r);
  56. void excludeRectangle (Rectangle<int> r);
  57. void clipToEdgeTable (const EdgeTable&);
  58. void clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels);
  59. bool isEmpty() noexcept;
  60. const Rectangle<int>& getMaximumBounds() const noexcept { return bounds; }
  61. void translate (float dx, int dy) noexcept;
  62. /** Scales all the alpha-levels in the table by the given multiplier. */
  63. void multiplyLevels (float factor);
  64. /** Reduces the amount of space the table has allocated.
  65. This will shrink the table down to use as little memory as possible - useful for
  66. read-only tables that get stored and re-used for rendering.
  67. */
  68. void optimiseTable();
  69. //==============================================================================
  70. /** Iterates the lines in the table, for rendering.
  71. This function will iterate each line in the table, and call a user-defined class
  72. to render each pixel or continuous line of pixels that the table contains.
  73. @param iterationCallback this templated class must contain the following methods:
  74. @code
  75. inline void setEdgeTableYPos (int y);
  76. inline void handleEdgeTablePixel (int x, int alphaLevel) const;
  77. inline void handleEdgeTablePixelFull (int x) const;
  78. inline void handleEdgeTableLine (int x, int width, int alphaLevel) const;
  79. inline void handleEdgeTableLineFull (int x, int width) const;
  80. @endcode
  81. (these don't necessarily have to be 'const', but it might help it go faster)
  82. */
  83. template <class EdgeTableIterationCallback>
  84. void iterate (EdgeTableIterationCallback& iterationCallback) const noexcept
  85. {
  86. const int* lineStart = table;
  87. for (int y = 0; y < bounds.getHeight(); ++y)
  88. {
  89. const int* line = lineStart;
  90. lineStart += lineStrideElements;
  91. int numPoints = line[0];
  92. if (--numPoints > 0)
  93. {
  94. int x = *++line;
  95. jassert ((x / scale) >= bounds.getX() && (x / scale) < bounds.getRight());
  96. int levelAccumulator = 0;
  97. iterationCallback.setEdgeTableYPos (bounds.getY() + y);
  98. while (--numPoints >= 0)
  99. {
  100. const int level = *++line;
  101. jassert (isPositiveAndBelow (level, scale));
  102. const int endX = *++line;
  103. jassert (endX >= x);
  104. const int endOfRun = (endX / scale);
  105. if (endOfRun == (x / scale))
  106. {
  107. // small segment within the same pixel, so just save it for the next
  108. // time round..
  109. levelAccumulator += (endX - x) * level;
  110. }
  111. else
  112. {
  113. // plot the fist pixel of this segment, including any accumulated
  114. // levels from smaller segments that haven't been drawn yet
  115. levelAccumulator += (0x100 - (x & 0xff)) * level;
  116. levelAccumulator /= scale;
  117. x /= scale;
  118. if (levelAccumulator > 0)
  119. {
  120. if (levelAccumulator >= 255)
  121. iterationCallback.handleEdgeTablePixelFull (x);
  122. else
  123. iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
  124. }
  125. // if there's a run of similar pixels, do it all in one go..
  126. if (level > 0)
  127. {
  128. jassert (endOfRun <= bounds.getRight());
  129. const int numPix = endOfRun - ++x;
  130. if (numPix > 0)
  131. iterationCallback.handleEdgeTableLine (x, numPix, level);
  132. }
  133. // save the bit at the end to be drawn next time round the loop.
  134. levelAccumulator = (endX & 0xff) * level;
  135. }
  136. x = endX;
  137. }
  138. levelAccumulator /= scale;
  139. if (levelAccumulator > 0)
  140. {
  141. x /= scale;
  142. jassert (x >= bounds.getX() && x < bounds.getRight());
  143. if (levelAccumulator >= 255)
  144. iterationCallback.handleEdgeTablePixelFull (x);
  145. else
  146. iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
  147. }
  148. }
  149. }
  150. }
  151. private:
  152. //==============================================================================
  153. static constexpr auto defaultEdgesPerLine = 32;
  154. static constexpr auto scale = 256;
  155. //==============================================================================
  156. // table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc
  157. struct LineItem
  158. {
  159. int x, level;
  160. bool operator< (const LineItem& other) const noexcept { return x < other.x; }
  161. };
  162. HeapBlock<int> table;
  163. Rectangle<int> bounds;
  164. int maxEdgesPerLine, lineStrideElements;
  165. bool needToCheckEmptiness = true;
  166. void allocate();
  167. void clearLineSizes() noexcept;
  168. void addEdgePoint (int x, int y, int winding);
  169. void addEdgePointPair (int x1, int x2, int y, int winding);
  170. void remapTableForNumEdges (int newNumEdgesPerLine);
  171. void remapWithExtraSpace (int numPointsNeeded);
  172. void intersectWithEdgeTableLine (int y, const int* otherLine);
  173. void clipEdgeTableLineToRange (int* line, int x1, int x2) noexcept;
  174. void sanitiseLevels (bool useNonZeroWinding) noexcept;
  175. static void copyEdgeTableData (int* dest, int destLineStride, const int* src, int srcLineStride, int numLines) noexcept;
  176. JUCE_LEAK_DETECTOR (EdgeTable)
  177. };
  178. } // namespace juce