| /* |
| * 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 |