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