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