Add clipShader with perspective GM
Bug: skia:10206 Change-Id: Iad24cb1134e8f501bce6434ea8511b21039abea2 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/293565 Commit-Queue: Mike Reed <reed@google.com> Reviewed-by: Mike Reed <reed@google.com> Auto-Submit: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
89dd4e774d
commit
88b3b15eec
@ -290,3 +290,156 @@ DEF_SIMPLE_GM(clip_shader_nested, canvas, 256, 256) {
|
||||
canvas->drawRect(SkRect::MakeWH(w, h), p);
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Where is canvas->concat(persp) called relative to the clipShader calls.
|
||||
enum ConcatPerspective {
|
||||
kConcatBeforeClips,
|
||||
kConcatAfterClips,
|
||||
kConcatBetweenClips
|
||||
};
|
||||
// Order in which clipShader(image) and clipShader(gradient) are specified; only meaningful
|
||||
// when CanvasPerspective is kConcatBetweenClips.
|
||||
enum ClipOrder {
|
||||
kClipImageFirst,
|
||||
kClipGradientFirst,
|
||||
|
||||
kDoesntMatter = kClipImageFirst
|
||||
};
|
||||
// Which shaders have perspective applied as a local matrix.
|
||||
enum LocalMatrix {
|
||||
kNoLocalMat,
|
||||
kImageWithLocalMat,
|
||||
kGradientWithLocalMat,
|
||||
kBothWithLocalMat
|
||||
};
|
||||
struct Config {
|
||||
ConcatPerspective fConcat;
|
||||
ClipOrder fOrder;
|
||||
LocalMatrix fLM;
|
||||
};
|
||||
|
||||
static void draw_banner(SkCanvas* canvas, Config config) {
|
||||
SkString banner;
|
||||
banner.append("Persp: ");
|
||||
|
||||
if (config.fConcat == kConcatBeforeClips || config.fLM == kBothWithLocalMat) {
|
||||
banner.append("Both Clips");
|
||||
} else {
|
||||
SkASSERT((config.fConcat == kConcatBetweenClips && config.fLM == kNoLocalMat) ||
|
||||
(config.fConcat == kConcatAfterClips && (config.fLM == kImageWithLocalMat ||
|
||||
config.fLM == kGradientWithLocalMat)));
|
||||
if ((config.fConcat == kConcatBetweenClips && config.fOrder == kClipImageFirst) ||
|
||||
config.fLM == kGradientWithLocalMat) {
|
||||
banner.append("Gradient");
|
||||
} else {
|
||||
SkASSERT(config.fOrder == kClipGradientFirst || config.fLM == kImageWithLocalMat);
|
||||
banner.append("Image");
|
||||
}
|
||||
}
|
||||
if (config.fLM != kNoLocalMat) {
|
||||
banner.append(" (w/ LM, should equal top row)");
|
||||
}
|
||||
|
||||
static const SkFont kFont(ToolUtils::create_portable_typeface(), 12);
|
||||
canvas->drawString(banner.c_str(), 20.f, -30.f, kFont, SkPaint());
|
||||
};
|
||||
|
||||
} // anonymous
|
||||
|
||||
DEF_SIMPLE_GM(clip_shader_persp, canvas, 1370, 1030) {
|
||||
// Each draw has a clipShader(image-shader), a clipShader(gradient-shader), a concat(persp-mat),
|
||||
// and each shader may or may not be wrapped with a perspective local matrix.
|
||||
|
||||
// Pairs of configs that should match in appearance where first config doesn't use a local
|
||||
// matrix (top row of GM) and the second does (bottom row of GM).
|
||||
Config matches[][2] = {
|
||||
// Everything has perspective
|
||||
{{kConcatBeforeClips, kDoesntMatter, kNoLocalMat},
|
||||
{kConcatAfterClips, kDoesntMatter, kBothWithLocalMat}},
|
||||
// Image shader has perspective
|
||||
{{kConcatBetweenClips, kClipGradientFirst, kNoLocalMat},
|
||||
{kConcatAfterClips, kDoesntMatter, kImageWithLocalMat}},
|
||||
// Gradient shader has perspective
|
||||
{{kConcatBetweenClips, kClipImageFirst, kNoLocalMat},
|
||||
{kConcatAfterClips, kDoesntMatter, kGradientWithLocalMat}}
|
||||
};
|
||||
|
||||
// The image that is drawn
|
||||
auto img = GetResourceAsImage("images/yellow_rose.png");
|
||||
// Scale factor always applied to the image shader so that it tiles
|
||||
SkMatrix scale = SkMatrix::Scale(1.f / 4.f, 1.f / 4.f);
|
||||
// The perspective matrix applied wherever needed
|
||||
SkPoint src[4];
|
||||
SkRect::Make(img->dimensions()).toQuad(src);
|
||||
SkPoint dst[4] = {{0, 80.f},
|
||||
{img->width() + 28.f, -100.f},
|
||||
{img->width() - 28.f, img->height() + 100.f},
|
||||
{0.f, img->height() - 80.f}};
|
||||
SkMatrix persp;
|
||||
SkAssertResult(persp.setPolyToPoly(src, dst, 4));
|
||||
|
||||
SkMatrix perspScale = SkMatrix::Concat(persp, scale);
|
||||
|
||||
auto drawConfig = [&](Config config) {
|
||||
canvas->save();
|
||||
|
||||
draw_banner(canvas, config);
|
||||
|
||||
// Make clipShaders (possibly with local matrices)
|
||||
bool gradLM = config.fLM == kGradientWithLocalMat || config.fLM == kBothWithLocalMat;
|
||||
const SkColor gradColors[] = {SK_ColorBLACK, SkColorSetARGB(128, 128, 128, 128)};
|
||||
auto gradShader = SkGradientShader::MakeRadial({0.5f * img->width(), 0.5f * img->height()},
|
||||
0.1f * img->width(), gradColors, nullptr, 2,
|
||||
SkTileMode::kRepeat, 0,
|
||||
gradLM ? &persp : nullptr);
|
||||
bool imageLM = config.fLM == kImageWithLocalMat || config.fLM == kBothWithLocalMat;
|
||||
auto imgShader = img->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
|
||||
imageLM ? perspScale : scale);
|
||||
|
||||
// Perspective before any clipShader
|
||||
if (config.fConcat == kConcatBeforeClips) {
|
||||
canvas->concat(persp);
|
||||
}
|
||||
|
||||
// First clipshader
|
||||
canvas->clipShader(config.fOrder == kClipImageFirst ? imgShader : gradShader);
|
||||
|
||||
// Perspective between clipShader
|
||||
if (config.fConcat == kConcatBetweenClips) {
|
||||
canvas->concat(persp);
|
||||
}
|
||||
|
||||
// Second clipShader
|
||||
canvas->clipShader(config.fOrder == kClipImageFirst ? gradShader : imgShader);
|
||||
|
||||
// Perspective after clipShader
|
||||
if (config.fConcat == kConcatAfterClips) {
|
||||
canvas->concat(persp);
|
||||
}
|
||||
|
||||
// Actual draw and clip boundary are the same for all configs
|
||||
canvas->clipRect(SkRect::MakeIWH(img->width(), img->height()));
|
||||
canvas->clear(SK_ColorBLACK);
|
||||
canvas->drawImage(img, 0, 0);
|
||||
|
||||
canvas->restore();
|
||||
};
|
||||
|
||||
SkIRect grid = persp.mapRect(SkRect::Make(img->dimensions())).roundOut();
|
||||
grid.fLeft -= 20; // manual adjust to look nicer
|
||||
|
||||
canvas->translate(10.f, 10.f);
|
||||
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(matches); ++i) {
|
||||
canvas->save();
|
||||
canvas->translate(-grid.fLeft, -grid.fTop);
|
||||
drawConfig(matches[i][0]);
|
||||
canvas->translate(0.f, grid.height());
|
||||
drawConfig(matches[i][1]);
|
||||
canvas->restore();
|
||||
|
||||
canvas->translate(grid.width(), 0.f);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user