blob: f4742d53e4fa7cba99c8fb8413c5bf8817d7e713 [file] [log] [blame]
/*
* Copyright 2020 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrAATriangulator_DEFINED
#define GrAATriangulator_DEFINED
#include "include/core/SkTypes.h"
#if !defined(SK_ENABLE_OPTIMIZE_SIZE)
#include "include/core/SkPoint.h"
#include "include/core/SkScalar.h"
#include "src/base/SkArenaAlloc.h"
#include "src/gpu/ganesh/geometry/GrTriangulator.h"
#include <cstdint>
#include <tuple>
class GrEagerVertexAllocator;
class SkPath;
struct SkRect;
// Triangulates the given path in device space with a mesh of alpha ramps for antialiasing.
class GrAATriangulator : private GrTriangulator {
public:
static int PathToAATriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
GrEagerVertexAllocator* vertexAllocator) {
SkArenaAlloc alloc(kArenaDefaultChunkSize);
GrAATriangulator aaTriangulator(path, &alloc);
aaTriangulator.fRoundVerticesToQuarterPixel = true;
aaTriangulator.fEmitCoverage = true;
bool isLinear;
auto [ polys, success ] = aaTriangulator.pathToPolys(tolerance, clipBounds, &isLinear);
if (!success) {
return 0;
}
return aaTriangulator.polysToAATriangles(polys, vertexAllocator);
}
// Structs used by GrAATriangulator internals.
struct SSEdge;
struct EventList;
struct Event {
Event(SSEdge* edge, const SkPoint& point, uint8_t alpha)
: fEdge(edge), fPoint(point), fAlpha(alpha) {}
SSEdge* fEdge;
SkPoint fPoint;
uint8_t fAlpha;
void apply(VertexList* mesh, const Comparator&, EventList* events, GrAATriangulator*);
};
struct EventComparator {
enum class Op { kLessThan, kGreaterThan };
EventComparator(Op op) : fOp(op) {}
bool operator() (Event* const &e1, Event* const &e2) {
return fOp == Op::kLessThan ? e1->fAlpha < e2->fAlpha
: e1->fAlpha > e2->fAlpha;
}
Op fOp;
};
private:
GrAATriangulator(const SkPath& path, SkArenaAlloc* alloc) : GrTriangulator(path, alloc) {}
// For screenspace antialiasing, the algorithm is modified as follows:
//
// Run steps 1-5 above to produce polygons.
// 5b) Apply fill rules to extract boundary contours from the polygons:
void extractBoundary(EdgeList* boundary, Edge* e) const;
void extractBoundaries(const VertexList& inMesh, VertexList* innerVertices,
const Comparator&);
// 5c) Simplify boundaries to remove "pointy" vertices that cause inversions:
void simplifyBoundary(EdgeList* boundary, const Comparator&);
// 5d) Displace edges by half a pixel inward and outward along their normals. Intersect to find
// new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a
// new antialiased mesh from those vertices:
void strokeBoundary(EdgeList* boundary, VertexList* innerMesh, const Comparator&);
// Run steps 3-6 above on the new mesh, and produce antialiased triangles.
std::tuple<Poly*, bool> tessellate(const VertexList& mesh, const Comparator&) override;
int polysToAATriangles(Poly*, GrEagerVertexAllocator*) const;
// Additional helpers and driver functions.
void makeEvent(SSEdge*, EventList* events) const;
void makeEvent(SSEdge*, Vertex* v, SSEdge* other, Vertex* dest, EventList* events,
const Comparator&) const;
void connectPartners(VertexList* mesh, const Comparator&);
void removeNonBoundaryEdges(const VertexList& mesh) const;
void connectSSEdge(Vertex* v, Vertex* dest, const Comparator&);
bool collapseOverlapRegions(VertexList* mesh, const Comparator&, EventComparator comp);
// FIXME: fOuterMesh should be plumbed through function parameters instead.
mutable VertexList fOuterMesh;
};
#endif // SK_ENABLE_OPTIMIZE_SIZE
#endif // GrAATriangulator_DEFINED