blob: 885bb24e72c9388b50d00850548d5da07ab051ee [file] [log] [blame]
/*
* Copyright 2022 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef skgpu_tessellate_MidpointContourParser_DEFINED
#define skgpu_tessellate_MidpointContourParser_DEFINED
#include "include/core/SkPath.h"
#include "include/core/SkPoint.h"
#include "src/core/SkPathPriv.h"
#include <cstdint>
namespace skgpu::tess {
// Parses out each contour in a path and tracks the midpoint. Example usage:
//
// MidpointContourParser parser;
// while (parser.parseNextContour()) {
// SkPoint midpoint = parser.currentMidpoint();
// for (auto [verb, pts] : parser.currentContour()) {
// ...
// }
// }
//
class MidpointContourParser {
public:
MidpointContourParser(const SkPath& path)
: fPath(path)
, fVerbs(SkPathPriv::VerbData(fPath))
, fNumRemainingVerbs(fPath.countVerbs())
, fPoints(SkPathPriv::PointData(fPath))
, fWeights(SkPathPriv::ConicWeightData(fPath)) {}
// Advances the internal state to the next contour in the path. Returns false if there are no
// more contours.
bool parseNextContour() {
bool hasGeometry = false;
for (; fVerbsIdx < fNumRemainingVerbs; ++fVerbsIdx) {
switch (fVerbs[fVerbsIdx]) {
case SkPath::kMove_Verb:
if (!hasGeometry) {
fMidpoint = {0,0};
fMidpointWeight = 0;
this->advance(); // Resets fPtsIdx to 0 and advances fPoints.
fPtsIdx = 1; // Increment fPtsIdx past the kMove.
continue;
}
if (fPoints[0] != fPoints[fPtsIdx - 1]) {
// There's an implicit close at the end. Add the start point to our mean.
fMidpoint += fPoints[0];
++fMidpointWeight;
}
return true;
default:
continue;
case SkPath::kLine_Verb:
++fPtsIdx;
break;
case SkPath::kConic_Verb:
++fWtsIdx;
[[fallthrough]];
case SkPath::kQuad_Verb:
fPtsIdx += 2;
break;
case SkPath::kCubic_Verb:
fPtsIdx += 3;
break;
}
fMidpoint += fPoints[fPtsIdx - 1];
++fMidpointWeight;
hasGeometry = true;
}
if (hasGeometry && fPoints[0] != fPoints[fPtsIdx - 1]) {
// There's an implicit close at the end. Add the start point to our mean.
fMidpoint += fPoints[0];
++fMidpointWeight;
}
return hasGeometry;
}
// Allows for iterating the current contour using a range-for loop.
SkPathPriv::Iterate currentContour() {
return SkPathPriv::Iterate(fVerbs, fVerbs + fVerbsIdx, fPoints, fWeights);
}
SkPoint currentMidpoint() { return fMidpoint * (1.f / fMidpointWeight); }
private:
void advance() {
fVerbs += fVerbsIdx;
fNumRemainingVerbs -= fVerbsIdx;
fVerbsIdx = 0;
fPoints += fPtsIdx;
fPtsIdx = 0;
fWeights += fWtsIdx;
fWtsIdx = 0;
}
const SkPath& fPath;
const uint8_t* fVerbs;
int fNumRemainingVerbs = 0;
int fVerbsIdx = 0;
const SkPoint* fPoints;
int fPtsIdx = 0;
const float* fWeights;
int fWtsIdx = 0;
SkPoint fMidpoint;
int fMidpointWeight;
};
} // namespace skgpu::tess
#endif // skgpu_tessellate_MidpointContourParser_DEFINED