The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

224 lines
8.8KB

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