skia2/gm/drawquadset.cpp
Ben Wagner 7fde8e1728 IWYU for gms.
This almost gets gms to be iwyu clean. The last bit is around gm.cpp
and the tracing framework and its use of atomic. Will also need a way
of keeping things from regressing, which is difficult due to needing to
do this outside-in.

Change-Id: I1393531e99da8b0f1a29f55c53c86d53f459af7d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/211593
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
2019-05-02 17:48:53 +00:00

245 lines
9.1 KiB
C++

/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm/gm.h"
#include "include/core/SkBlendMode.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkScalar.h"
#include "include/core/SkShader.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkTileMode.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkTypes.h"
#include "include/effects/SkGradientShader.h"
#include "include/gpu/GrContext.h"
#include "include/private/GrTypesPriv.h"
#include "src/gpu/GrClip.h"
#include "src/gpu/GrPaint.h"
#include "src/gpu/GrRenderTargetContext.h"
#include "src/gpu/SkGr.h"
#include <utility>
static constexpr SkScalar kTileWidth = 40;
static constexpr SkScalar kTileHeight = 30;
static constexpr int kRowCount = 4;
static constexpr int kColCount = 3;
static void draw_text(SkCanvas* canvas, const char* text) {
canvas->drawString(text, 0, 0, SkFont(nullptr, 12), SkPaint());
}
static void draw_gradient_tiles(SkCanvas* canvas, bool alignGradients) {
// Always draw the same gradient
static constexpr SkPoint pts[] = { {0.f, 0.f}, {0.25f * kTileWidth, 0.25f * kTileHeight} };
static constexpr SkColor colors[] = { SK_ColorBLUE, SK_ColorWHITE };
GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
GrContext* context = canvas->getGrContext();
auto gradient = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kMirror);
SkPaint paint;
paint.setShader(gradient);
for (int i = 0; i < kRowCount; ++i) {
for (int j = 0; j < kColCount; ++j) {
SkRect tile = SkRect::MakeWH(kTileWidth, kTileHeight);
if (alignGradients) {
tile.offset(j * kTileWidth, i * kTileHeight);
} else {
canvas->save();
canvas->translate(j * kTileWidth, i * kTileHeight);
}
unsigned aa = SkCanvas::kNone_QuadAAFlags;
if (i == 0) {
aa |= SkCanvas::kTop_QuadAAFlag;
}
if (i == kRowCount - 1) {
aa |= SkCanvas::kBottom_QuadAAFlag;
}
if (j == 0) {
aa |= SkCanvas::kLeft_QuadAAFlag;
}
if (j == kColCount - 1) {
aa |= SkCanvas::kRight_QuadAAFlag;
}
if (rtc) {
// Use non-public API to leverage general GrPaint capabilities
SkMatrix view = canvas->getTotalMatrix();
GrPaint grPaint;
SkPaintToGrPaint(context, rtc->colorSpaceInfo(), paint, view, &grPaint);
rtc->fillRectWithEdgeAA(GrNoClip(), std::move(grPaint), GrAA::kYes,
static_cast<GrQuadAAFlags>(aa), view, tile);
} else {
// Fallback to solid color on raster backend since the public API only has color
SkColor color = alignGradients ? SK_ColorBLUE
: (i * kColCount + j) % 2 == 0 ? SK_ColorBLUE
: SK_ColorWHITE;
canvas->experimental_DrawEdgeAAQuad(
tile, nullptr, static_cast<SkCanvas::QuadAAFlags>(aa), color,
SkBlendMode::kSrcOver);
}
if (!alignGradients) {
// Pop off the matrix translation when drawing unaligned
canvas->restore();
}
}
}
}
static void draw_color_tiles(SkCanvas* canvas, bool multicolor) {
for (int i = 0; i < kRowCount; ++i) {
for (int j = 0; j < kColCount; ++j) {
SkRect tile = SkRect::MakeXYWH(j * kTileWidth, i * kTileHeight, kTileWidth, kTileHeight);
SkColor4f color;
if (multicolor) {
color = {(i + 1.f) / kRowCount, (j + 1.f) / kColCount, .4f, 1.f};
} else {
color = {.2f, .8f, .3f, 1.f};
}
unsigned aa = SkCanvas::kNone_QuadAAFlags;
if (i == 0) {
aa |= SkCanvas::kTop_QuadAAFlag;
}
if (i == kRowCount - 1) {
aa |= SkCanvas::kBottom_QuadAAFlag;
}
if (j == 0) {
aa |= SkCanvas::kLeft_QuadAAFlag;
}
if (j == kColCount - 1) {
aa |= SkCanvas::kRight_QuadAAFlag;
}
canvas->experimental_DrawEdgeAAQuad(
tile, nullptr, static_cast<SkCanvas::QuadAAFlags>(aa), color.toSkColor(),
SkBlendMode::kSrcOver);
}
}
}
static void draw_tile_boundaries(SkCanvas* canvas, const SkMatrix& local) {
// Draw grid of red lines at interior tile boundaries.
static constexpr SkScalar kLineOutset = 10.f;
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(SK_ColorRED);
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(0.f);
for (int x = 1; x < kColCount; ++x) {
SkPoint pts[] = {{x * kTileWidth, 0}, {x * kTileWidth, kRowCount * kTileHeight}};
local.mapPoints(pts, 2);
SkVector v = pts[1] - pts[0];
v.setLength(v.length() + kLineOutset);
canvas->drawLine(pts[1] - v, pts[0] + v, paint);
}
for (int y = 1; y < kRowCount; ++y) {
SkPoint pts[] = {{0, y * kTileHeight}, {kTileWidth * kColCount, y * kTileHeight}};
local.mapPoints(pts, 2);
SkVector v = pts[1] - pts[0];
v.setLength(v.length() + kLineOutset);
canvas->drawLine(pts[1] - v, pts[0] + v, paint);
}
}
// Tile renderers (column variation)
typedef void (*TileRenderer)(SkCanvas*);
static TileRenderer kTileSets[] = {
[](SkCanvas* canvas) { draw_gradient_tiles(canvas, /* aligned */ false); },
[](SkCanvas* canvas) { draw_gradient_tiles(canvas, /* aligned */ true); },
[](SkCanvas* canvas) { draw_color_tiles(canvas, /* multicolor */ false); },
[](SkCanvas* canvas) { draw_color_tiles(canvas, /* multicolor */true); },
};
static const char* kTileSetNames[] = { "Local", "Aligned", "Green", "Multicolor" };
static_assert(SK_ARRAY_COUNT(kTileSets) == SK_ARRAY_COUNT(kTileSetNames), "Count mismatch");
namespace skiagm {
class DrawQuadSetGM : public GM {
private:
SkString onShortName() final { return SkString("draw_quad_set"); }
SkISize onISize() override { return SkISize::Make(800, 800); }
void onDraw(SkCanvas* canvas) override {
SkMatrix rowMatrices[5];
// Identity
rowMatrices[0].setIdentity();
// Translate/scale
rowMatrices[1].setTranslate(5.5f, 20.25f);
rowMatrices[1].postScale(.9f, .7f);
// Rotation
rowMatrices[2].setRotate(20.0f);
rowMatrices[2].preTranslate(15.f, -20.f);
// Skew
rowMatrices[3].setSkew(.5f, .25f);
rowMatrices[3].preTranslate(-30.f, 0.f);
// Perspective
SkPoint src[4];
SkRect::MakeWH(kColCount * kTileWidth, kRowCount * kTileHeight).toQuad(src);
SkPoint dst[4] = {{0, 0},
{kColCount * kTileWidth + 10.f, 15.f},
{kColCount * kTileWidth - 28.f, kRowCount * kTileHeight + 40.f},
{25.f, kRowCount * kTileHeight - 15.f}};
SkAssertResult(rowMatrices[4].setPolyToPoly(src, dst, 4));
rowMatrices[4].preTranslate(0.f, +10.f);
static const char* matrixNames[] = { "Identity", "T+S", "Rotate", "Skew", "Perspective" };
static_assert(SK_ARRAY_COUNT(matrixNames) == SK_ARRAY_COUNT(rowMatrices), "Count mismatch");
// Print a column header
canvas->save();
canvas->translate(110.f, 20.f);
for (size_t j = 0; j < SK_ARRAY_COUNT(kTileSetNames); ++j) {
draw_text(canvas, kTileSetNames[j]);
canvas->translate(kColCount * kTileWidth + 30.f, 0.f);
}
canvas->restore();
canvas->translate(0.f, 40.f);
// Render all tile variations
for (size_t i = 0; i < SK_ARRAY_COUNT(rowMatrices); ++i) {
canvas->save();
canvas->translate(10.f, 0.5f * kRowCount * kTileHeight);
draw_text(canvas, matrixNames[i]);
canvas->translate(100.f, -0.5f * kRowCount * kTileHeight);
for (size_t j = 0; j < SK_ARRAY_COUNT(kTileSets); ++j) {
canvas->save();
draw_tile_boundaries(canvas, rowMatrices[i]);
canvas->concat(rowMatrices[i]);
kTileSets[j](canvas);
// Undo the local transformation
canvas->restore();
// And advance to the next column
canvas->translate(kColCount * kTileWidth + 30.f, 0.f);
}
// Reset back to the left edge
canvas->restore();
// And advance to the next row
canvas->translate(0.f, kRowCount * kTileHeight + 20.f);
}
}
};
DEF_GM(return new DrawQuadSetGM();)
} // namespace skiagm