blob: 64b74d7126816643017d467b97abe7eb8ccec32a [file] [log] [blame]
Chris Dalton04a1de52018-03-14 02:04:09 -06001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
9#include "include/core/SkPaint.h"
10#include "include/core/SkPath.h"
11#include "include/core/SkPoint.h"
12#include "tools/ToolUtils.h"
Hal Canary8a001442018-09-19 11:31:27 -040013
Chris Dalton04a1de52018-03-14 02:04:09 -060014#include <array>
15#include <vector>
16
17namespace skiagm {
18
19static constexpr int kPadSize = 20;
20static constexpr int kBoxSize = 100;
21static constexpr SkPoint kJitters[] = {{0, 0}, {.5f, .5f}, {2/3.f, 1/3.f}};
22
23// Tests various corners of different angles falling on the same pixel, particularly to ensure
24// analytic AA is working properly.
25class SharedCornersGM : public GM {
26public:
Mike Kleinea3f0142019-03-20 11:12:10 -050027 SharedCornersGM() { this->setBGColor(ToolUtils::color_to_565(0xFF1A65D7)); }
Chris Dalton04a1de52018-03-14 02:04:09 -060028
29protected:
30 SkString onShortName() override {
31 return SkString("sharedcorners");
32 }
33
34 SkISize onISize() override {
35 constexpr int numRows = 3 * 2;
36 constexpr int numCols = (1 + SK_ARRAY_COUNT(kJitters)) * 2;
37 return SkISize::Make(numCols * (kBoxSize + kPadSize) + kPadSize,
38 numRows * (kBoxSize + kPadSize) + kPadSize);
39 }
40
41 void onOnceBeforeDraw() override {
42 fFillPaint.setColor(SK_ColorWHITE);
43 fFillPaint.setAntiAlias(true);
44
45 fWireFramePaint = fFillPaint;
46 fWireFramePaint.setStyle(SkPaint::kStroke_Style);
47
48 }
49
50 void onDraw(SkCanvas* canvas) override {
51 canvas->translate(kPadSize, kPadSize);
52 canvas->save();
53
54 // Adjacent rects.
55 this->drawTriangleBoxes(canvas,
56 {{0, 0}, {40, 0}, {80, 0}, {120, 0},
57 {0, 20}, {40, 20}, {80, 20}, {120, 20},
58 {40, 40}, {80, 40},
59 {40, 60}, {80, 60}},
60 {{{0, 1, 4}}, {{1, 5, 4}},
61 {{5, 1, 6}}, {{1, 2, 6}},
62 {{2, 3, 6}}, {{3, 7, 6}},
63 {{8, 5, 9}}, {{5, 6, 9}},
64 {{10, 8, 11}}, {{8, 9, 11}}});
65
66 // Obtuse angles.
67 this->drawTriangleBoxes(canvas,
68 {{ 0, 0}, {10, 0}, {20, 0},
69 { 0, 2}, {20, 2},
70 {10, 4},
71 { 0, 6}, {20, 6},
72 { 0, 8}, {10, 8}, {20, 8}},
73 {{{3, 1, 4}}, {{4, 5, 3}}, {{6, 5, 7}}, {{7, 9, 6}},
74 {{0, 1, 3}}, {{1, 2, 4}},
75 {{3, 5, 6}}, {{5, 4, 7}},
76 {{6, 9, 8}}, {{9, 7, 10}}});
77
78 canvas->restore();
79 canvas->translate((kBoxSize + kPadSize) * 4, 0);
80
81 // Right angles.
82 this->drawTriangleBoxes(canvas,
83 {{0, 0}, {-1, 0}, {0, -1}, {1, 0}, {0, 1}},
84 {{{0, 1, 2}}, {{0, 2, 3}}, {{0, 3, 4}}, {{0, 4, 1}}});
85
86 // Acute angles.
87 SkRandom rand;
88 std::vector<SkPoint> pts;
89 std::vector<std::array<int, 3>> indices;
90 SkScalar theta = 0;
91 pts.push_back({0, 0});
92 while (theta < 2*SK_ScalarPI) {
93 pts.push_back({SkScalarCos(theta), SkScalarSin(theta)});
94 if (pts.size() > 2) {
95 indices.push_back({{0, (int)pts.size() - 2, (int)pts.size() - 1}});
96 }
97 theta += rand.nextRangeF(0, SK_ScalarPI/3);
98 }
99 indices.push_back({{0, (int)pts.size() - 1, 1}});
100 this->drawTriangleBoxes(canvas, pts, indices);
101 }
102
103 void drawTriangleBoxes(SkCanvas* canvas, const std::vector<SkPoint>& points,
104 const std::vector<std::array<int, 3>>& triangles) {
105 SkPath path;
106 path.setFillType(SkPath::kEvenOdd_FillType);
107 path.setIsVolatile(true);
108 for (const std::array<int, 3>& triangle : triangles) {
109 path.moveTo(points[triangle[0]]);
110 path.lineTo(points[triangle[1]]);
111 path.lineTo(points[triangle[2]]);
112 path.close();
113 }
114 SkScalar scale = kBoxSize / SkTMax(path.getBounds().height(), path.getBounds().width());
115 path.transform(SkMatrix::MakeScale(scale, scale));
116
117 this->drawRow(canvas, path);
118 canvas->translate(0, kBoxSize + kPadSize);
119
120 SkMatrix rot;
121 rot.setRotate(45, path.getBounds().centerX(), path.getBounds().centerY());
122 path.transform(rot);
123 this->drawRow(canvas, path);
124 canvas->translate(0, kBoxSize + kPadSize);
125
126 rot.setRotate(-45 - 69.38111f, path.getBounds().centerX(), path.getBounds().centerY());
127 path.transform(rot);
128 this->drawRow(canvas, path);
129 canvas->translate(0, kBoxSize + kPadSize);
130 }
131
132 void drawRow(SkCanvas* canvas, const SkPath& path) {
133 SkAutoCanvasRestore acr(canvas, true);
134 const SkRect& bounds = path.getBounds();
135 canvas->translate((kBoxSize - bounds.width()) / 2 - bounds.left(),
136 (kBoxSize - bounds.height()) / 2 - bounds.top());
137
138 canvas->drawPath(path, fWireFramePaint);
139 canvas->translate(kBoxSize + kPadSize, 0);
140
141 for (SkPoint jitter : kJitters) {
142 {
143 SkAutoCanvasRestore acr(canvas, true);
144 canvas->translate(jitter.x(), jitter.y());
145 canvas->drawPath(path, fFillPaint);
146 }
147 canvas->translate(kBoxSize + kPadSize, 0);
148 }
149 }
150
151 SkPaint fWireFramePaint;
152 SkPaint fFillPaint;
153};
154
155DEF_GM(return new SharedCornersGM;)
156
157}