blob: a03e8fefe2787ac0977bea09e65f541e8740bab2 [file] [log] [blame] [edit]
/*
* Copyright 2025 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkImage.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathBuilder.h"
#include "include/core/SkPixmap.h"
#include "include/core/SkRRect.h"
#include "include/core/SkRect.h"
#include "include/core/SkSurface.h"
#include "include/private/base/SkAssert.h"
#include "src/core/SkDebugUtils.h"
#include "src/core/SkEdge.h"
#include "src/core/SkEdgeBuilder.h"
#include "tools/viewer/Slide.h"
#include "tools/viewer/ZoomInSlide.h"
#include <vector>
/* This slide visualizes the edges created from bezier curves in SkPath. These edges are the ones
used by the aliased scan converter (e.g. SkScan_Path.cpp).
Hold control to move the control point (which can be used in the path creation).
*/
class EdgeBuilderSlide : public ZoomInSlide {
public:
EdgeBuilderSlide() : ZoomInSlide(kScale, kMaskWidth, kMaskHeight, SkString("EdgeBuilderViz")) {}
SkPath makePath() {
return SkPathBuilder()
.moveTo(0, 0)
//.quadTo({fControl, {10, 20})
.cubicTo(fControl, {8, 6}, {10, 20})
.lineTo({10, 10})
.lineTo({12, 0})
.close()
.detach();
}
void drawUnderGrid(SkCanvas* canvas) override {
SkPaint paint;
paint.setStyle(SkPaint::Style::kFill_Style);
paint.setColor(SK_ColorBLACK);
this->drawScaledPath(canvas, makePath(), paint);
}
void drawOverGrid(SkCanvas* canvas) override {
SkPath path = makePath();
drawHighRezOverlay(canvas, path);
drawEdges(canvas, path);
drawControlPoint(canvas);
}
void drawHighRezOverlay(SkCanvas* canvas, const SkPath& path) {
SkPaint truthPaint;
truthPaint.setStyle(SkPaint::Style::kStroke_Style);
truthPaint.setColor(SK_ColorRED);
truthPaint.setAntiAlias(true);
truthPaint.setStrokeWidth(2.f / kScale);
canvas->drawPath(path, truthPaint);
}
void drawEdges(SkCanvas* canvas, const SkPath& path) {
SkBasicEdgeBuilder builder;
int num = builder.buildEdges(path, nullptr);
SkEdge** edgeList = builder.edgeList();
SkPaint edgePaint;
edgePaint.setColor(SkColorSetRGB(0xFF, 0x8C, 0x00));
edgePaint.setStyle(SkPaint::Style::kStroke_Style);
edgePaint.setStrokeWidth(4.f / kScale);
for (int i = 0; i < num; ++i) {
SkEdge* e = edgeList[i];
while (true) {
float x1 = SkFixedToFloat(e->fX);
float y1 = e->fFirstY;
float y2 = e->fLastY;
float x2 = x1 + SkFixedToFloat(e->fDxDy) * (y2 - y1);
if (x1 == x2 && y1 == y2) {
x2 += 0.2f; // Make "zero height" edges visible.
}
// The y coordinates are implied to be at the half pixel values for y
canvas->drawLine(x1, y1 + 0.5, x2, y2 + 0.5, edgePaint);
if (!e->hasNextSegment()) {
break;
}
e->fX = x2;
if (!e->nextSegment()) {
break;
}
}
}
}
void drawControlPoint(SkCanvas* canvas) {
SkPaint controlPaint;
controlPaint.setStyle(SkPaint::Style::kStroke_Style);
controlPaint.setColor(SK_ColorBLUE);
controlPaint.setAntiAlias(true);
controlPaint.setStrokeWidth(1.f / kScale);
canvas->drawCircle(fControl, 4.f / kScale, controlPaint);
}
void handleClick(const ScaledClick* click) override { fControl = click->currScaled(); }
private:
static constexpr size_t kScale = 32;
// Defines the region of the screen that will be zoomed in on.
// The path under scrutiny will be drawn in this region.
static constexpr int kMaskWidth = 15;
static constexpr int kMaskHeight = 25;
SkPoint fControl = {2.f, 13.f};
};
DEF_SLIDE(return new EdgeBuilderSlide();)