skia2/samplecode/SampleStrokeVerb.cpp

224 lines
6.5 KiB
C++
Raw Normal View History

/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkTypes.h"
#if SK_SUPPORT_GPU
#include "include/core/SkCanvas.h"
#include "include/core/SkFont.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "samplecode/Sample.h"
#include "src/core/SkGeometry.h"
enum class VerbType {
kTriangles,
kQuadratics,
kCubics,
kConics
};
static const char* verb_type_name(VerbType verbType) {
switch (verbType) {
case VerbType::kTriangles: return "kTriangles";
case VerbType::kQuadratics: return "kQuadratics";
case VerbType::kCubics: return "kCubics";
case VerbType::kConics: return "kConics";
}
SkUNREACHABLE;
};
/**
* This sample visualizes simple strokes.
*/
class CCPRGeometryView : public Sample {
void onOnceBeforeDraw() override { this->updatePath(); }
void onDrawContent(SkCanvas*) override;
Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override;
bool onClick(Sample::Click*) override;
bool onChar(SkUnichar) override;
SkString name() override { return SkString("StrokeVerb"); }
class Click;
void updateAndInval() { this->updatePath(); }
void updatePath();
VerbType fVerbType = VerbType::kCubics;
SkPoint fPoints[4] = {
{100.05f, 100.05f}, {400.75f, 100.05f}, {400.75f, 300.95f}, {100.05f, 300.95f}};
float fConicWeight = .5;
float fStrokeWidth = 40;
SkPaint::Join fStrokeJoin = SkPaint::kMiter_Join;
SkPaint::Cap fStrokeCap = SkPaint::kButt_Cap;
SkPath fPath;
};
void CCPRGeometryView::onDrawContent(SkCanvas* canvas) {
canvas->clear(SK_ColorBLACK);
SkPaint outlinePaint;
outlinePaint.setColor(0xff808080);
outlinePaint.setStyle(SkPaint::kStroke_Style);
outlinePaint.setStrokeWidth(fStrokeWidth);
outlinePaint.setStrokeJoin(fStrokeJoin);
outlinePaint.setStrokeCap(fStrokeCap);
outlinePaint.setAntiAlias(true);
canvas->drawPath(fPath, outlinePaint);
SkString caption;
caption.appendf("VerbType_%s", verb_type_name(fVerbType));
if (VerbType::kCubics == fVerbType) {
caption.appendf(" (%s)", SkCubicTypeName(SkClassifyCubic(fPoints)));
} else if (VerbType::kConics == fVerbType) {
caption.appendf(" (w=%f)", fConicWeight);
}
caption.appendf(" (stroke_width=%f)", fStrokeWidth);
SkPaint pointsPaint;
pointsPaint.setColor(SK_ColorBLUE);
pointsPaint.setStrokeWidth(8);
pointsPaint.setAntiAlias(true);
if (VerbType::kCubics == fVerbType) {
canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, fPoints, pointsPaint);
} else {
canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, fPoints, pointsPaint);
canvas->drawPoints(SkCanvas::kPoints_PointMode, 1, fPoints + 3, pointsPaint);
}
SkFont font(nullptr, 20);
SkPaint captionPaint;
captionPaint.setColor(SK_ColorWHITE);
canvas->drawString(caption, 10, 30, font, captionPaint);
}
void CCPRGeometryView::updatePath() {
fPath.reset();
fPath.moveTo(fPoints[0]);
switch (fVerbType) {
case VerbType::kCubics:
fPath.cubicTo(fPoints[1], fPoints[2], fPoints[3]);
break;
case VerbType::kQuadratics:
fPath.quadTo(fPoints[1], fPoints[3]);
break;
case VerbType::kConics:
fPath.conicTo(fPoints[1], fPoints[3], fConicWeight);
break;
case VerbType::kTriangles:
fPath.lineTo(fPoints[1]);
fPath.lineTo(fPoints[3]);
fPath.close();
break;
}
}
class CCPRGeometryView::Click : public Sample::Click {
public:
Click(int ptIdx) : fPtIdx(ptIdx) {}
void doClick(SkPoint points[]) {
if (fPtIdx >= 0) {
points[fPtIdx] += fCurr - fPrev;
} else {
for (int i = 0; i < 4; ++i) {
points[i] += fCurr - fPrev;
}
}
}
private:
int fPtIdx;
};
Sample::Click* CCPRGeometryView::onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) {
for (int i = 0; i < 4; ++i) {
if (VerbType::kCubics != fVerbType && 2 == i) {
continue;
}
if (fabs(x - fPoints[i].x()) < 20 && fabsf(y - fPoints[i].y()) < 20) {
return new Click(i);
}
}
return new Click(-1);
}
bool CCPRGeometryView::onClick(Sample::Click* click) {
Click* myClick = (Click*)click;
myClick->doClick(fPoints);
this->updateAndInval();
return true;
}
bool CCPRGeometryView::onChar(SkUnichar unichar) {
if (unichar >= '1' && unichar <= '4') {
fVerbType = VerbType(unichar - '1');
this->updateAndInval();
return true;
}
float* valueToScale = nullptr;
if (VerbType::kConics == fVerbType) {
valueToScale = &fConicWeight;
} else {
valueToScale = &fStrokeWidth;
}
if (valueToScale) {
if (unichar == '+') {
*valueToScale *= 2;
this->updateAndInval();
return true;
}
if (unichar == '+' || unichar == '=') {
*valueToScale *= 5/4.f;
this->updateAndInval();
return true;
}
if (unichar == '-') {
*valueToScale *= 4/5.f;
this->updateAndInval();
return true;
}
if (unichar == '_') {
*valueToScale *= .5f;
this->updateAndInval();
return true;
}
}
if (unichar == 'D') {
SkDebugf(" SkPoint fPoints[4] = {\n");
SkDebugf(" {%ff, %ff},\n", fPoints[0].x(), fPoints[0].y());
SkDebugf(" {%ff, %ff},\n", fPoints[1].x(), fPoints[1].y());
SkDebugf(" {%ff, %ff},\n", fPoints[2].x(), fPoints[2].y());
SkDebugf(" {%ff, %ff}\n", fPoints[3].x(), fPoints[3].y());
SkDebugf(" };\n");
return true;
}
if (unichar == 'J') {
fStrokeJoin = (SkPaint::Join)((fStrokeJoin + 1) % 3);
this->updateAndInval();
return true;
}
if (unichar == 'C') {
fStrokeCap = (SkPaint::Cap)((fStrokeCap + 1) % 3);
this->updateAndInval();
return true;
}
return false;
}
DEF_SAMPLE(return new CCPRGeometryView;)
#endif // SK_SUPPORT_GPU