skia2/samplecode/SampleFilterQuality.cpp
Brian Osman 176c3b2e88 Move expensive initialization to onOnceBeforeDraw
This was being triggered at viewer startup, while initalizing the slide
list (and then again when switching to the slide). Removing it
declutters startup, particularly if you're trying to debug raster
drawing code.

Bug: skia:
Change-Id: If21cdd10b0dbda74f4a845031ae3e33f7305a1d7
Reviewed-on: https://skia-review.googlesource.com/22742
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2017-07-12 20:30:50 +00:00

312 lines
9.7 KiB
C++

/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm.h"
#include "Resources.h"
#include "SampleCode.h"
#include "SkAnimTimer.h"
#include "SkCanvas.h"
#include "SkInterpolator.h"
#include "SkGradientShader.h"
#include "SkData.h"
#include "SkPath.h"
#include "SkSurface.h"
#include "SkRandom.h"
#include "SkTime.h"
static sk_sp<SkSurface> make_surface(SkCanvas* canvas, const SkImageInfo& info) {
auto surface = canvas->makeSurface(info);
if (!surface) {
surface = SkSurface::MakeRaster(info);
}
return surface;
}
static sk_sp<SkShader> make_shader(const SkRect& bounds) {
sk_sp<SkImage> image(GetResourceAsImage("mandrill_128.png"));
return image ? image->makeShader() : nullptr;
}
#define N 128
#define ANGLE_DELTA 3
#define SCALE_DELTA (SK_Scalar1 / 32)
static sk_sp<SkImage> make_image() {
SkImageInfo info = SkImageInfo::MakeN32(N, N, kOpaque_SkAlphaType);
auto surface(SkSurface::MakeRaster(info));
SkCanvas* canvas = surface->getCanvas();
canvas->drawColor(SK_ColorWHITE);
SkPath path;
path.setFillType(SkPath::kEvenOdd_FillType);
path.addRect(SkRect::MakeWH(N/2, N));
path.addRect(SkRect::MakeWH(N, N/2));
path.moveTo(0, 0); path.lineTo(N, 0); path.lineTo(0, N); path.close();
SkPaint paint;
paint.setShader(make_shader(SkRect::MakeWH(N, N)));
canvas->drawPath(path, paint);
return surface->makeImageSnapshot();
}
static sk_sp<SkImage> zoom_up(SkSurface* origSurf, SkImage* orig) {
const SkScalar S = 16; // amount to scale up
const int D = 2; // dimension scaling for the offscreen
// since we only view the center, don't need to produce the entire thing
SkImageInfo info = SkImageInfo::MakeN32(orig->width() * D, orig->height() * D,
kOpaque_SkAlphaType);
auto surface(origSurf->makeSurface(info));
SkCanvas* canvas = surface->getCanvas();
canvas->drawColor(SK_ColorWHITE);
canvas->scale(S, S);
canvas->translate(-SkScalarHalf(orig->width()) * (S - D) / S,
-SkScalarHalf(orig->height()) * (S - D) / S);
canvas->drawImage(orig, 0, 0, nullptr);
if (S > 3) {
SkPaint paint;
paint.setColor(SK_ColorWHITE);
for (int i = 1; i < orig->height(); ++i) {
SkScalar y = SkIntToScalar(i);
canvas->drawLine(0, y, SkIntToScalar(orig->width()), y, paint);
}
for (int i = 1; i < orig->width(); ++i) {
SkScalar x = SkIntToScalar(i);
canvas->drawLine(x, 0, x, SkIntToScalar(orig->height()), paint);
}
}
return surface->makeImageSnapshot();
}
struct AnimValue {
SkScalar fValue;
SkScalar fMin;
SkScalar fMax;
SkScalar fMod;
operator SkScalar() const { return fValue; }
void set(SkScalar value, SkScalar min, SkScalar max) {
fValue = value;
fMin = min;
fMax = max;
fMod = 0;
}
void setMod(SkScalar value, SkScalar mod) {
fValue = value;
fMin = 0;
fMax = 0;
fMod = mod;
}
SkScalar inc(SkScalar delta) {
fValue += delta;
return this->fixUp();
}
SkScalar fixUp() {
if (fMod) {
fValue = SkScalarMod(fValue, fMod);
} else {
if (fValue > fMax) {
fValue = fMax;
} else if (fValue < fMin) {
fValue = fMin;
}
}
return fValue;
}
};
static void draw_box_frame(SkCanvas* canvas, int width, int height) {
SkPaint p;
p.setStyle(SkPaint::kStroke_Style);
p.setColor(SK_ColorRED);
SkRect r = SkRect::MakeIWH(width, height);
r.inset(0.5f, 0.5f);
canvas->drawRect(r, p);
canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), p);
canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), p);
}
class FilterQualityView : public SampleView {
sk_sp<SkImage> fImage;
AnimValue fScale, fAngle;
SkSize fCell;
SkInterpolator fTrans;
SkMSec fCurrTime;
bool fShowFatBits;
public:
FilterQualityView() : fTrans(2, 2), fShowFatBits(true) {
fCell.set(256, 256);
fScale.set(1, SK_Scalar1 / 8, 1);
fAngle.setMod(0, 360);
SkScalar values[2];
fTrans.setMirror(true);
fTrans.setReset(true);
fCurrTime = 0;
fTrans.setRepeatCount(999);
values[0] = values[1] = 0;
fTrans.setKeyFrame(0, fCurrTime, values);
values[0] = values[1] = 1;
fTrans.setKeyFrame(1, fCurrTime + 2000, values);
}
protected:
bool onQuery(SkEvent* evt) override {
if (SampleCode::TitleQ(*evt)) {
SampleCode::TitleR(evt, "FilterQuality");
return true;
}
SkUnichar uni;
if (SampleCode::CharQ(*evt, &uni)) {
switch (uni) {
case '1': fAngle.inc(-ANGLE_DELTA); this->inval(nullptr); return true;
case '2': fAngle.inc( ANGLE_DELTA); this->inval(nullptr); return true;
case '3': fScale.inc(-SCALE_DELTA); this->inval(nullptr); return true;
case '4': fScale.inc( SCALE_DELTA); this->inval(nullptr); return true;
case '5': fShowFatBits = !fShowFatBits; this->inval(nullptr); return true;
default: break;
}
}
return this->INHERITED::onQuery(evt);
}
void drawTheImage(SkCanvas* canvas, const SkISize& size, SkFilterQuality filter,
SkScalar dx, SkScalar dy) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setFilterQuality(filter);
SkAutoCanvasRestore acr(canvas, true);
canvas->translate(dx, dy);
canvas->translate(SkScalarHalf(size.width()), SkScalarHalf(size.height()));
canvas->scale(fScale, fScale);
canvas->rotate(fAngle);
canvas->drawImage(fImage.get(), -SkScalarHalf(fImage->width()), -SkScalarHalf(fImage->height()),
&paint);
if (false) {
acr.restore();
draw_box_frame(canvas, size.width(), size.height());
}
}
void drawHere(SkCanvas* canvas, SkFilterQuality filter, SkScalar dx, SkScalar dy) {
SkCanvas* origCanvas = canvas;
SkAutoCanvasRestore acr(canvas, true);
SkISize size = SkISize::Make(fImage->width(), fImage->height());
sk_sp<SkSurface> surface;
if (fShowFatBits) {
// scale up so we don't clip rotations
SkImageInfo info = SkImageInfo::MakeN32(fImage->width() * 2, fImage->height() * 2,
kOpaque_SkAlphaType);
surface = make_surface(canvas, info);
canvas = surface->getCanvas();
canvas->drawColor(SK_ColorWHITE);
size.set(info.width(), info.height());
} else {
canvas->translate(SkScalarHalf(fCell.width() - fImage->width()),
SkScalarHalf(fCell.height() - fImage->height()));
}
this->drawTheImage(canvas, size, filter, dx, dy);
if (surface) {
sk_sp<SkImage> orig(surface->makeImageSnapshot());
sk_sp<SkImage> zoomed(zoom_up(surface.get(), orig.get()));
origCanvas->drawImage(zoomed.get(),
SkScalarHalf(fCell.width() - zoomed->width()),
SkScalarHalf(fCell.height() - zoomed->height()));
}
}
void drawBorders(SkCanvas* canvas) {
SkPaint p;
p.setStyle(SkPaint::kStroke_Style);
p.setColor(SK_ColorBLUE);
SkRect r = SkRect::MakeWH(fCell.width() * 2, fCell.height() * 2);
r.inset(SK_ScalarHalf, SK_ScalarHalf);
canvas->drawRect(r, p);
canvas->drawLine(r.left(), r.centerY(), r.right(), r.centerY(), p);
canvas->drawLine(r.centerX(), r.top(), r.centerX(), r.bottom(), p);
}
void onOnceBeforeDraw() override {
fImage = make_image();
}
void onDrawContent(SkCanvas* canvas) override {
fCell.set(this->height() / 2, this->height() / 2);
SkScalar trans[2];
fTrans.timeToValues(fCurrTime, trans);
for (int y = 0; y < 2; ++y) {
for (int x = 0; x < 2; ++x) {
int index = y * 2 + x;
SkAutoCanvasRestore acr(canvas, true);
canvas->translate(fCell.width() * x, fCell.height() * y);
SkRect r = SkRect::MakeWH(fCell.width(), fCell.height());
r.inset(4, 4);
canvas->clipRect(r);
this->drawHere(canvas, SkFilterQuality(index), trans[0], trans[1]);
}
}
this->drawBorders(canvas);
const SkScalar textX = fCell.width() * 2 + 30;
SkPaint paint;
paint.setAntiAlias(true);
paint.setTextSize(36);
SkString str;
str.appendScalar(fScale);
canvas->drawString(str, textX, 100, paint);
str.reset(); str.appendScalar(fAngle);
canvas->drawString(str, textX, 150, paint);
str.reset(); str.appendScalar(trans[0]);
canvas->drawString(str, textX, 200, paint);
str.reset(); str.appendScalar(trans[1]);
canvas->drawString(str, textX, 250, paint);
}
bool onAnimate(const SkAnimTimer& timer) override {
fCurrTime = timer.msec();
return true;
}
virtual bool handleKey(SkKey key) {
this->inval(nullptr);
return true;
}
private:
typedef SampleView INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
static SkView* MyFactory() { return new FilterQualityView; }
static SkViewRegister reg(MyFactory);