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.

221 lines
8.9KB

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