blob: f05fa746f4aa681dcf452e8990b0f4c98cfa7384 [file]
/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrInnerFanTriangulator_DEFINED
#define GrInnerFanTriangulator_DEFINED
#if !defined(SK_ENABLE_OPTIMIZE_SIZE)
#include "gr_triangulator.hpp"
#include <optional>
namespace rive
{
// Triangulates the inner polygon(s) of a path (i.e., the triangle fan for a
// Redbook rendering method). When combined with the outer curves and grout
// triangles, these produce a complete path. If a groutCollector is not
// provided, pathToPolys fails upon self intersection.
class GrInnerFanTriangulator : private GrTriangulator
{
public:
using GroutTriangleList = GrTriangulator::BreadcrumbTriangleList;
GrInnerFanTriangulator(const RawPath& path,
const AABB& pathBounds,
TrivialBlockAllocator* alloc) :
GrTriangulator(
// Sweep along the longer dimension of pathBounds so the sweep line
// crosses fewer edges.
pathBounds.width() > pathBounds.height()
? Comparator::Direction::kHorizontal
: Comparator::Direction::kVertical,
alloc)
{
fPreserveCollinearVertices = true;
fCollectBreadcrumbTriangles = true;
bool isLinear;
auto [polys, success] =
GrTriangulator::pathToPolys(path, 0, AABB{}, &isLinear);
if (success)
{
m_polys = polys;
}
}
// The mesh is fill-rule-independent; the fill rule only filters it at
// output, so it's supplied per call rather than baked in. This lets one
// triangulator be cached and reused regardless of fill rule.
size_t maxVertexCount(FillRule fillRule) const
{
return m_polys != nullptr ? countMaxTriangleVertices(m_polys, fillRule)
: 0;
}
// Emits the interior triangulation as weight-expanded retrofitted cubic
// patches, merging into patches of up to 3 edge-adjacent triangles.
// Returns the number of patches emitted.
size_t polysToRetrofitCubicPatches(
FillRule fillRule,
gpu::WindingFaces windingFaces,
const RetrofitCubicPatchEmitter& emitPatch) const
{
if (m_polys == nullptr)
{
return 0;
}
return GrTriangulator::polysToRetrofitCubicPatches(m_polys,
fillRule,
windingFaces,
emitPatch);
}
// Number of patches polysToRetrofitCubicPatches() emits for this
// triangulation. Lazily computed and cached because it requires the full
// (nontrivial) triangle traversal and shared-edge detection.
size_t retrofitCubicPatchCount(FillRule fillRule) const
{
std::optional<size_t>& cached = fillRule == FillRule::evenOdd
? m_evenOddPatchCount
: m_nonZeroPatchCount;
if (!cached.has_value())
{
cached = polysToRetrofitCubicPatches(fillRule,
gpu::WindingFaces::all,
[](const Vec2D*, size_t) {});
}
return *cached;
}
size_t polysToTriangles(
uint16_t pathID,
FillRule fillRule,
bool reverseTriangles,
bool negateWinding,
gpu::WindingFaces windingFaces,
gpu::WriteOnlyMappedMemory<gpu::TriangleVertex>* mappedMemory) const
{
if (m_polys == nullptr)
{
return 0;
}
return GrTriangulator::polysToTriangles(m_polys,
maxVertexCount(fillRule),
fillRule,
pathID,
reverseTriangles,
negateWinding,
windingFaces,
mappedMemory);
}
const GroutTriangleList& groutList() const { return fBreadcrumbList; }
private:
Poly* m_polys = nullptr;
// Lazily-computed retrofitCubicPatchCount() cache: one slot per fill rule
// the triangulator sees (nonZero -- which clockwise maps to -- and
// evenOdd).
mutable std::optional<size_t> m_nonZeroPatchCount;
mutable std::optional<size_t> m_evenOddPatchCount;
};
} // namespace rive
#else
// Stub out GrInnerFanTriangulator::GroutTriangleList for function declarations.
namespace GrInnerFanTriangulator
{
struct GroutTriangleList
{
GroutTriangleList() = delete;
};
}; // namespace GrInnerFanTriangulator
#endif // SK_ENABLE_OPTIMIZE_SIZE
#endif // GrInnerFanTriangulator_DEFINED