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.

juce_EdgeTable.h 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 7 technical preview.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For the technical preview this file cannot be licensed commercially.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. namespace juce
  14. {
  15. //==============================================================================
  16. /**
  17. A table of horizontal scan-line segments - used for rasterising Paths.
  18. @see Path, Graphics
  19. @tags{Graphics}
  20. */
  21. class JUCE_API EdgeTable
  22. {
  23. public:
  24. //==============================================================================
  25. /** Creates an edge table containing a path.
  26. A table is created with a fixed vertical range, and only sections of the path
  27. which lie within this range will be added to the table.
  28. @param clipLimits only the region of the path that lies within this area will be added
  29. @param pathToAdd the path to add to the table
  30. @param transform a transform to apply to the path being added
  31. */
  32. EdgeTable (Rectangle<int> clipLimits,
  33. const Path& pathToAdd,
  34. const AffineTransform& transform);
  35. /** Creates an edge table containing a rectangle. */
  36. explicit EdgeTable (Rectangle<int> rectangleToAdd);
  37. /** Creates an edge table containing a rectangle. */
  38. explicit EdgeTable (Rectangle<float> rectangleToAdd);
  39. /** Creates an edge table containing a rectangle list. */
  40. explicit EdgeTable (const RectangleList<int>& rectanglesToAdd);
  41. /** Creates an edge table containing a rectangle list. */
  42. explicit EdgeTable (const RectangleList<float>& rectanglesToAdd);
  43. /** Creates a copy of another edge table. */
  44. EdgeTable (const EdgeTable&);
  45. /** Copies from another edge table. */
  46. EdgeTable& operator= (const EdgeTable&);
  47. /** Destructor. */
  48. ~EdgeTable();
  49. //==============================================================================
  50. void clipToRectangle (Rectangle<int> r);
  51. void excludeRectangle (Rectangle<int> r);
  52. void clipToEdgeTable (const EdgeTable&);
  53. void clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels);
  54. bool isEmpty() noexcept;
  55. const Rectangle<int>& getMaximumBounds() const noexcept { return bounds; }
  56. void translate (float dx, int dy) noexcept;
  57. /** Scales all the alpha-levels in the table by the given multiplier. */
  58. void multiplyLevels (float factor);
  59. /** Reduces the amount of space the table has allocated.
  60. This will shrink the table down to use as little memory as possible - useful for
  61. read-only tables that get stored and re-used for rendering.
  62. */
  63. void optimiseTable();
  64. //==============================================================================
  65. /** Iterates the lines in the table, for rendering.
  66. This function will iterate each line in the table, and call a user-defined class
  67. to render each pixel or continuous line of pixels that the table contains.
  68. @param iterationCallback this templated class must contain the following methods:
  69. @code
  70. inline void setEdgeTableYPos (int y);
  71. inline void handleEdgeTablePixel (int x, int alphaLevel) const;
  72. inline void handleEdgeTablePixelFull (int x) const;
  73. inline void handleEdgeTableLine (int x, int width, int alphaLevel) const;
  74. inline void handleEdgeTableLineFull (int x, int width) const;
  75. @endcode
  76. (these don't necessarily have to be 'const', but it might help it go faster)
  77. */
  78. template <class EdgeTableIterationCallback>
  79. void iterate (EdgeTableIterationCallback& iterationCallback) const noexcept
  80. {
  81. const int* lineStart = table;
  82. for (int y = 0; y < bounds.getHeight(); ++y)
  83. {
  84. const int* line = lineStart;
  85. lineStart += lineStrideElements;
  86. int numPoints = line[0];
  87. if (--numPoints > 0)
  88. {
  89. int x = *++line;
  90. jassert ((x / scale) >= bounds.getX() && (x / scale) < bounds.getRight());
  91. int levelAccumulator = 0;
  92. iterationCallback.setEdgeTableYPos (bounds.getY() + y);
  93. while (--numPoints >= 0)
  94. {
  95. const int level = *++line;
  96. jassert (isPositiveAndBelow (level, scale));
  97. const int endX = *++line;
  98. jassert (endX >= x);
  99. const int endOfRun = (endX / scale);
  100. if (endOfRun == (x / scale))
  101. {
  102. // small segment within the same pixel, so just save it for the next
  103. // time round..
  104. levelAccumulator += (endX - x) * level;
  105. }
  106. else
  107. {
  108. // plot the fist pixel of this segment, including any accumulated
  109. // levels from smaller segments that haven't been drawn yet
  110. levelAccumulator += (0x100 - (x & 0xff)) * level;
  111. levelAccumulator /= scale;
  112. x /= scale;
  113. if (levelAccumulator > 0)
  114. {
  115. if (levelAccumulator >= 255)
  116. iterationCallback.handleEdgeTablePixelFull (x);
  117. else
  118. iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
  119. }
  120. // if there's a run of similar pixels, do it all in one go..
  121. if (level > 0)
  122. {
  123. jassert (endOfRun <= bounds.getRight());
  124. const int numPix = endOfRun - ++x;
  125. if (numPix > 0)
  126. iterationCallback.handleEdgeTableLine (x, numPix, level);
  127. }
  128. // save the bit at the end to be drawn next time round the loop.
  129. levelAccumulator = (endX & 0xff) * level;
  130. }
  131. x = endX;
  132. }
  133. levelAccumulator /= scale;
  134. if (levelAccumulator > 0)
  135. {
  136. x /= scale;
  137. jassert (x >= bounds.getX() && x < bounds.getRight());
  138. if (levelAccumulator >= 255)
  139. iterationCallback.handleEdgeTablePixelFull (x);
  140. else
  141. iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
  142. }
  143. }
  144. }
  145. }
  146. private:
  147. //==============================================================================
  148. static constexpr auto defaultEdgesPerLine = 32;
  149. static constexpr auto scale = 256;
  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 = true;
  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 remapWithExtraSpace (int numPointsNeeded);
  167. void intersectWithEdgeTableLine (int y, const int* otherLine);
  168. void clipEdgeTableLineToRange (int* line, int x1, int x2) noexcept;
  169. void sanitiseLevels (bool useNonZeroWinding) noexcept;
  170. static void copyEdgeTableData (int* dest, int destLineStride, const int* src, int srcLineStride, int numLines) noexcept;
  171. JUCE_LEAK_DETECTOR (EdgeTable)
  172. };
  173. } // namespace juce