|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- /*
- ==============================================================================
-
- This file is part of the JUCE 7 technical preview.
- Copyright (c) 2022 - Raw Material Software Limited
-
- You may use this code under the terms of the GPL v3
- (see www.gnu.org/licenses).
-
- For the technical preview this file cannot be licensed commercially.
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
-
- //==============================================================================
- /**
- A table of horizontal scan-line segments - used for rasterising Paths.
-
- @see Path, Graphics
-
- @tags{Graphics}
- */
- class JUCE_API EdgeTable
- {
- public:
- //==============================================================================
- /** Creates an edge table containing a path.
-
- A table is created with a fixed vertical range, and only sections of the path
- which lie within this range will be added to the table.
-
- @param clipLimits only the region of the path that lies within this area will be added
- @param pathToAdd the path to add to the table
- @param transform a transform to apply to the path being added
- */
- EdgeTable (Rectangle<int> clipLimits,
- const Path& pathToAdd,
- const AffineTransform& transform);
-
- /** Creates an edge table containing a rectangle. */
- explicit EdgeTable (Rectangle<int> rectangleToAdd);
-
- /** Creates an edge table containing a rectangle. */
- explicit EdgeTable (Rectangle<float> rectangleToAdd);
-
- /** Creates an edge table containing a rectangle list. */
- explicit EdgeTable (const RectangleList<int>& rectanglesToAdd);
-
- /** Creates an edge table containing a rectangle list. */
- explicit EdgeTable (const RectangleList<float>& rectanglesToAdd);
-
- /** Creates a copy of another edge table. */
- EdgeTable (const EdgeTable&);
-
- /** Copies from another edge table. */
- EdgeTable& operator= (const EdgeTable&);
-
- /** Destructor. */
- ~EdgeTable();
-
- //==============================================================================
- void clipToRectangle (Rectangle<int> r);
- void excludeRectangle (Rectangle<int> r);
- void clipToEdgeTable (const EdgeTable&);
- void clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels);
- bool isEmpty() noexcept;
- const Rectangle<int>& getMaximumBounds() const noexcept { return bounds; }
- void translate (float dx, int dy) noexcept;
-
- /** Scales all the alpha-levels in the table by the given multiplier. */
- void multiplyLevels (float factor);
-
- /** Reduces the amount of space the table has allocated.
-
- This will shrink the table down to use as little memory as possible - useful for
- read-only tables that get stored and re-used for rendering.
- */
- void optimiseTable();
-
-
- //==============================================================================
- /** Iterates the lines in the table, for rendering.
-
- This function will iterate each line in the table, and call a user-defined class
- to render each pixel or continuous line of pixels that the table contains.
-
- @param iterationCallback this templated class must contain the following methods:
- @code
- inline void setEdgeTableYPos (int y);
- inline void handleEdgeTablePixel (int x, int alphaLevel) const;
- inline void handleEdgeTablePixelFull (int x) const;
- inline void handleEdgeTableLine (int x, int width, int alphaLevel) const;
- inline void handleEdgeTableLineFull (int x, int width) const;
- @endcode
- (these don't necessarily have to be 'const', but it might help it go faster)
- */
- template <class EdgeTableIterationCallback>
- void iterate (EdgeTableIterationCallback& iterationCallback) const noexcept
- {
- const int* lineStart = table;
-
- for (int y = 0; y < bounds.getHeight(); ++y)
- {
- const int* line = lineStart;
- lineStart += lineStrideElements;
- int numPoints = line[0];
-
- if (--numPoints > 0)
- {
- int x = *++line;
- jassert ((x / scale) >= bounds.getX() && (x / scale) < bounds.getRight());
- int levelAccumulator = 0;
-
- iterationCallback.setEdgeTableYPos (bounds.getY() + y);
-
- while (--numPoints >= 0)
- {
- const int level = *++line;
- jassert (isPositiveAndBelow (level, scale));
- const int endX = *++line;
- jassert (endX >= x);
- const int endOfRun = (endX / scale);
-
- if (endOfRun == (x / scale))
- {
- // small segment within the same pixel, so just save it for the next
- // time round..
- levelAccumulator += (endX - x) * level;
- }
- else
- {
- // plot the fist pixel of this segment, including any accumulated
- // levels from smaller segments that haven't been drawn yet
- levelAccumulator += (0x100 - (x & 0xff)) * level;
- levelAccumulator /= scale;
- x /= scale;
-
- if (levelAccumulator > 0)
- {
- if (levelAccumulator >= 255)
- iterationCallback.handleEdgeTablePixelFull (x);
- else
- iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
- }
-
- // if there's a run of similar pixels, do it all in one go..
- if (level > 0)
- {
- jassert (endOfRun <= bounds.getRight());
- const int numPix = endOfRun - ++x;
-
- if (numPix > 0)
- iterationCallback.handleEdgeTableLine (x, numPix, level);
- }
-
- // save the bit at the end to be drawn next time round the loop.
- levelAccumulator = (endX & 0xff) * level;
- }
-
- x = endX;
- }
-
- levelAccumulator /= scale;
-
- if (levelAccumulator > 0)
- {
- x /= scale;
- jassert (x >= bounds.getX() && x < bounds.getRight());
-
- if (levelAccumulator >= 255)
- iterationCallback.handleEdgeTablePixelFull (x);
- else
- iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
- }
- }
- }
- }
-
- private:
- //==============================================================================
- static constexpr auto defaultEdgesPerLine = 32;
- static constexpr auto scale = 256;
-
- //==============================================================================
- // table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc
- struct LineItem
- {
- int x, level;
-
- bool operator< (const LineItem& other) const noexcept { return x < other.x; }
- };
-
- HeapBlock<int> table;
- Rectangle<int> bounds;
- int maxEdgesPerLine, lineStrideElements;
- bool needToCheckEmptiness = true;
-
- void allocate();
- void clearLineSizes() noexcept;
- void addEdgePoint (int x, int y, int winding);
- void addEdgePointPair (int x1, int x2, int y, int winding);
- void remapTableForNumEdges (int newNumEdgesPerLine);
- void remapWithExtraSpace (int numPointsNeeded);
- void intersectWithEdgeTableLine (int y, const int* otherLine);
- void clipEdgeTableLineToRange (int* line, int x1, int x2) noexcept;
- void sanitiseLevels (bool useNonZeroWinding) noexcept;
- static void copyEdgeTableData (int* dest, int destLineStride, const int* src, int srcLineStride, int numLines) noexcept;
-
- JUCE_LEAK_DETECTOR (EdgeTable)
- };
-
- } // namespace juce
|