sharedcorners.cpp 5.5 KB

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