You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
6.2 KiB
157 lines
6.2 KiB
/*
|
|
* Copyright 2019 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/SkCanvas.h"
|
|
#include "include/core/SkColor.h"
|
|
#include "include/core/SkFilterQuality.h"
|
|
#include "include/core/SkFont.h"
|
|
#include "include/core/SkFontTypes.h"
|
|
#include "include/core/SkImage.h"
|
|
#include "include/core/SkM44.h"
|
|
#include "include/core/SkMatrix.h"
|
|
#include "include/core/SkPaint.h"
|
|
#include "include/core/SkRRect.h"
|
|
#include "include/core/SkRect.h"
|
|
#include "include/core/SkRefCnt.h"
|
|
#include "include/core/SkScalar.h"
|
|
#include "include/core/SkSize.h"
|
|
#include "include/core/SkString.h"
|
|
#include "include/core/SkSurface.h"
|
|
#include "tools/timer/TimeUtils.h"
|
|
|
|
// Mimics https://output.jsbin.com/falefice/1/quiet?CC_POSTER_CIRCLE, which can't be captured as
|
|
// an SKP due to many 3D layers being composited post-SKP capture.
|
|
// See skbug.com/9028
|
|
class PosterCircleGM : public skiagm::GM {
|
|
public:
|
|
PosterCircleGM() : fTime(0.f) {}
|
|
|
|
protected:
|
|
|
|
SkString onShortName() override {
|
|
return SkString("poster_circle");
|
|
}
|
|
|
|
SkISize onISize() override {
|
|
return SkISize::Make(kStageWidth, kStageHeight + 50);
|
|
}
|
|
|
|
bool onAnimate(double nanos) override {
|
|
fTime = TimeUtils::Scaled(1e-9 * nanos, 0.5f);
|
|
return true;
|
|
}
|
|
|
|
void onOnceBeforeDraw() override {
|
|
SkFont font;
|
|
font.setEdging(SkFont::Edging::kAntiAlias);
|
|
font.setEmbolden(true);
|
|
font.setSize(24.f);
|
|
|
|
sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(kPosterSize, kPosterSize);
|
|
for (int i = 0; i < kNumAngles; ++i) {
|
|
SkCanvas* canvas = surface->getCanvas();
|
|
|
|
SkPaint fillPaint;
|
|
fillPaint.setAntiAlias(true);
|
|
fillPaint.setColor(i % 2 == 0 ? SkColorSetRGB(0x99, 0x5C, 0x7F)
|
|
: SkColorSetRGB(0x83, 0x5A, 0x99));
|
|
canvas->drawRRect(SkRRect::MakeRectXY(SkRect::MakeWH(kPosterSize, kPosterSize),
|
|
10.f, 10.f), fillPaint);
|
|
|
|
SkString label;
|
|
label.printf("%d", i);
|
|
SkRect labelBounds;
|
|
font.measureText(label.c_str(), label.size(), SkTextEncoding::kUTF8, &labelBounds);
|
|
SkScalar labelX = 0.5f * kPosterSize - 0.5f * labelBounds.width();
|
|
SkScalar labelY = 0.5f * kPosterSize + 0.5f * labelBounds.height();
|
|
|
|
|
|
SkPaint labelPaint;
|
|
labelPaint.setAntiAlias(true);
|
|
canvas->drawString(label, labelX, labelY, font, labelPaint);
|
|
|
|
fPosterImages[i] = surface->makeImageSnapshot();
|
|
}
|
|
}
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
// See https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/perspective
|
|
// for projection matrix when --webkit-perspective: 800px is used.
|
|
SkM44 proj;
|
|
proj.setRC(3, 2, -1.f / 800.f);
|
|
|
|
for (int pass = 0; pass < 2; ++pass) {
|
|
// Want to draw 90 to 270 first (the back), then 270 to 90 (the front), but do all 3
|
|
// rings backsides, then their frontsides since the front projections overlap across
|
|
// rings. Note: we skip the poster circle's x axis rotation because that complicates the
|
|
// back-to-front drawing order and it isn't necessary to trigger draws aligned with Z.
|
|
bool drawFront = pass > 0;
|
|
|
|
for (int y = 0; y < 3; ++y) {
|
|
float ringY = (y - 1) * (kPosterSize + 10.f);
|
|
for (int i = 0; i < kNumAngles; ++i) {
|
|
// Add an extra 45 degree rotation, which triggers the bug by aligning some of
|
|
// the posters with the z axis.
|
|
SkScalar yDuration = 5.f - y;
|
|
SkScalar yRotation = SkScalarMod(kAngleStep * i +
|
|
360.f * SkScalarMod(fTime / yDuration, yDuration), 360.f);
|
|
// These rotation limits were chosen manually to line up with current projection
|
|
static constexpr SkScalar kBackMinAngle = 70.f;
|
|
static constexpr SkScalar kBackMaxAngle = 290.f;
|
|
if (drawFront) {
|
|
if (yRotation >= kBackMinAngle && yRotation <= kBackMaxAngle) {
|
|
// Back portion during a front draw
|
|
continue;
|
|
}
|
|
} else {
|
|
if (yRotation < kBackMinAngle || yRotation > kBackMaxAngle) {
|
|
// Front portion during a back draw
|
|
continue;
|
|
}
|
|
}
|
|
|
|
canvas->save();
|
|
|
|
// Matrix matches transform: rotateY(<angle>deg) translateZ(200px); nested in an
|
|
// element with the perspective projection matrix above.
|
|
SkM44 model = SkM44::Translate(kStageWidth/2, kStageHeight/2 + 25, 0)
|
|
* proj
|
|
* SkM44::Translate(0, ringY, 0)
|
|
* SkM44::Rotate({0,1,0}, SkDegreesToRadians(yRotation))
|
|
* SkM44::Translate(0, 0, kRingRadius);
|
|
canvas->concat(model);
|
|
|
|
SkRect poster = SkRect::MakeLTRB(-0.5f * kPosterSize, -0.5f * kPosterSize,
|
|
0.5f * kPosterSize, 0.5f * kPosterSize);
|
|
SkPaint fillPaint;
|
|
fillPaint.setAntiAlias(true);
|
|
fillPaint.setAlphaf(0.7f);
|
|
canvas->drawImageRect(fPosterImages[i], poster,
|
|
SkSamplingOptions(SkFilterMode::kLinear), &fillPaint);
|
|
|
|
canvas->restore();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
static const int kAngleStep = 30;
|
|
static const int kNumAngles = 12; // 0 through 330 degrees
|
|
|
|
static const int kStageWidth = 600;
|
|
static const int kStageHeight = 400;
|
|
static const int kRingRadius = 200;
|
|
static const int kPosterSize = 100;
|
|
|
|
sk_sp<SkImage> fPosterImages[kNumAngles];
|
|
SkScalar fTime;
|
|
};
|
|
|
|
DEF_GM(return new PosterCircleGM();)
|