Home | History | Annotate | Download | only in samplecode
      1 /*
      2  * Copyright 2015 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 
      8 #include "Resources.h"
      9 #include "Sample.h"
     10 #include "SkAnimTimer.h"
     11 #include "SkCanvas.h"
     12 #include "SkInterpolator.h"
     13 #include "SkFont.h"
     14 #include "SkGradientShader.h"
     15 #include "SkData.h"
     16 #include "SkPath.h"
     17 #include "SkSurface.h"
     18 #include "SkRandom.h"
     19 #include "SkTime.h"
     20 
     21 static sk_sp<SkSurface> make_surface(SkCanvas* canvas, const SkImageInfo& info) {
     22     auto surface = canvas->makeSurface(info);
     23     if (!surface) {
     24         surface = SkSurface::MakeRaster(info);
     25     }
     26     return surface;
     27 }
     28 
     29 static sk_sp<SkShader> make_shader(const SkRect& bounds) {
     30     sk_sp<SkImage> image(GetResourceAsImage("images/mandrill_128.png"));
     31     return image ? image->makeShader() : nullptr;
     32 }
     33 
     34 #define N   128
     35 #define ANGLE_DELTA 3
     36 #define SCALE_DELTA (SK_Scalar1 / 32)
     37 
     38 static sk_sp<SkImage> make_image() {
     39     SkImageInfo info = SkImageInfo::MakeN32(N, N, kOpaque_SkAlphaType);
     40     auto surface(SkSurface::MakeRaster(info));
     41     SkCanvas* canvas = surface->getCanvas();
     42     canvas->drawColor(SK_ColorWHITE);
     43 
     44     SkPath path;
     45     path.setFillType(SkPath::kEvenOdd_FillType);
     46 
     47     path.addRect(SkRect::MakeWH(N/2, N));
     48     path.addRect(SkRect::MakeWH(N, N/2));
     49     path.moveTo(0, 0); path.lineTo(N, 0); path.lineTo(0, N); path.close();
     50 
     51     SkPaint paint;
     52     paint.setShader(make_shader(SkRect::MakeWH(N, N)));
     53 
     54     canvas->drawPath(path, paint);
     55     return surface->makeImageSnapshot();
     56 }
     57 
     58 static sk_sp<SkImage> zoom_up(SkSurface* origSurf, SkImage* orig) {
     59     const SkScalar S = 16;    // amount to scale up
     60     const int D = 2;    // dimension scaling for the offscreen
     61     // since we only view the center, don't need to produce the entire thing
     62 
     63     SkImageInfo info = SkImageInfo::MakeN32(orig->width() * D, orig->height() * D,
     64                                             kOpaque_SkAlphaType);
     65     auto surface(origSurf->makeSurface(info));
     66     SkCanvas* canvas = surface->getCanvas();
     67     canvas->drawColor(SK_ColorWHITE);
     68     canvas->scale(S, S);
     69     canvas->translate(-SkScalarHalf(orig->width()) * (S - D) / S,
     70                       -SkScalarHalf(orig->height()) * (S - D) / S);
     71     canvas->drawImage(orig, 0, 0, nullptr);
     72 
     73     if (S > 3) {
     74         SkPaint paint;
     75         paint.setColor(SK_ColorWHITE);
     76         for (int i = 1; i < orig->height(); ++i) {
     77             SkScalar y = SkIntToScalar(i);
     78             canvas->drawLine(0, y, SkIntToScalar(orig->width()), y, paint);
     79         }
     80         for (int i = 1; i < orig->width(); ++i) {
     81             SkScalar x = SkIntToScalar(i);
     82             canvas->drawLine(x, 0, x, SkIntToScalar(orig->height()), paint);
     83         }
     84     }
     85     return surface->makeImageSnapshot();
     86 }
     87 
     88 struct AnimValue {
     89     SkScalar fValue;
     90     SkScalar fMin;
     91     SkScalar fMax;
     92     SkScalar fMod;
     93 
     94     operator SkScalar() const { return fValue; }
     95 
     96     void set(SkScalar value, SkScalar min, SkScalar max) {
     97         fValue = value;
     98         fMin = min;
     99         fMax = max;
    100         fMod = 0;
    101     }
    102 
    103     void setMod(SkScalar value, SkScalar mod) {
    104         fValue = value;
    105         fMin = 0;
    106         fMax = 0;
    107         fMod = mod;
    108     }
    109 
    110     SkScalar inc(SkScalar delta) {
    111         fValue += delta;
    112         return this->fixUp();
    113     }
    114 
    115     SkScalar fixUp() {
    116         if (fMod) {
    117             fValue = SkScalarMod(fValue, fMod);
    118         } else {
    119             if (fValue > fMax) {
    120                 fValue = fMax;
    121             } else if (fValue < fMin) {
    122                 fValue = fMin;
    123             }
    124         }
    125         return fValue;
    126     }
    127 };
    128 
    129 static void draw_box_frame(SkCanvas* canvas, int width, int height) {
    130     SkPaint p;
    131     p.setStyle(SkPaint::kStroke_Style);
    132     p.setColor(SK_ColorRED);
    133     SkRect r = SkRect::MakeIWH(width, height);
    134     r.inset(0.5f, 0.5f);
    135     canvas->drawRect(r, p);
    136     canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), p);
    137     canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), p);
    138 }
    139 
    140 class FilterQualityView : public Sample {
    141     sk_sp<SkImage>  fImage;
    142     AnimValue       fScale, fAngle;
    143     SkSize          fCell;
    144     SkInterpolator  fTrans;
    145     SkMSec          fCurrTime;
    146     bool            fShowFatBits;
    147 
    148 public:
    149     FilterQualityView() : fTrans(2, 2), fShowFatBits(true) {
    150         fCell.set(256, 256);
    151 
    152         fScale.set(1, SK_Scalar1 / 8, 1);
    153         fAngle.setMod(0, 360);
    154 
    155         SkScalar values[2];
    156         fTrans.setMirror(true);
    157         fTrans.setReset(true);
    158 
    159         fCurrTime = 0;
    160 
    161         fTrans.setRepeatCount(999);
    162         values[0] = values[1] = 0;
    163         fTrans.setKeyFrame(0, fCurrTime, values);
    164         values[0] = values[1] = 1;
    165         fTrans.setKeyFrame(1, fCurrTime + 2000, values);
    166     }
    167 
    168 protected:
    169     bool onQuery(Sample::Event* evt) override {
    170         if (Sample::TitleQ(*evt)) {
    171             Sample::TitleR(evt, "FilterQuality");
    172             return true;
    173         }
    174         SkUnichar uni;
    175         if (Sample::CharQ(*evt, &uni)) {
    176             switch (uni) {
    177                 case '1': fAngle.inc(-ANGLE_DELTA); return true;
    178                 case '2': fAngle.inc( ANGLE_DELTA); return true;
    179                 case '3': fScale.inc(-SCALE_DELTA); return true;
    180                 case '4': fScale.inc( SCALE_DELTA); return true;
    181                 case '5': fShowFatBits = !fShowFatBits; return true;
    182                 default: break;
    183             }
    184         }
    185         return this->INHERITED::onQuery(evt);
    186     }
    187 
    188     void drawTheImage(SkCanvas* canvas, const SkISize& size, SkFilterQuality filter,
    189                       SkScalar dx, SkScalar dy) {
    190         SkPaint paint;
    191         paint.setAntiAlias(true);
    192         paint.setFilterQuality(filter);
    193 
    194         SkAutoCanvasRestore acr(canvas, true);
    195 
    196         canvas->translate(dx, dy);
    197 
    198         canvas->translate(SkScalarHalf(size.width()), SkScalarHalf(size.height()));
    199         canvas->scale(fScale, fScale);
    200         canvas->rotate(fAngle);
    201         canvas->drawImage(fImage.get(), -SkScalarHalf(fImage->width()), -SkScalarHalf(fImage->height()),
    202                           &paint);
    203 
    204         if (false) {
    205             acr.restore();
    206             draw_box_frame(canvas, size.width(), size.height());
    207         }
    208     }
    209 
    210     void drawHere(SkCanvas* canvas, SkFilterQuality filter, SkScalar dx, SkScalar dy) {
    211         SkCanvas* origCanvas = canvas;
    212         SkAutoCanvasRestore acr(canvas, true);
    213 
    214         SkISize size = SkISize::Make(fImage->width(), fImage->height());
    215 
    216         sk_sp<SkSurface> surface;
    217         if (fShowFatBits) {
    218             // scale up so we don't clip rotations
    219             SkImageInfo info = SkImageInfo::MakeN32(fImage->width() * 2, fImage->height() * 2,
    220                                                     kOpaque_SkAlphaType);
    221             surface = make_surface(canvas, info);
    222             canvas = surface->getCanvas();
    223             canvas->drawColor(SK_ColorWHITE);
    224             size.set(info.width(), info.height());
    225         } else {
    226             canvas->translate(SkScalarHalf(fCell.width() - fImage->width()),
    227                               SkScalarHalf(fCell.height() - fImage->height()));
    228         }
    229         this->drawTheImage(canvas, size, filter, dx, dy);
    230 
    231         if (surface) {
    232             sk_sp<SkImage> orig(surface->makeImageSnapshot());
    233             sk_sp<SkImage> zoomed(zoom_up(surface.get(), orig.get()));
    234             origCanvas->drawImage(zoomed.get(),
    235                                   SkScalarHalf(fCell.width() - zoomed->width()),
    236                                   SkScalarHalf(fCell.height() - zoomed->height()));
    237         }
    238     }
    239 
    240     void drawBorders(SkCanvas* canvas) {
    241         SkPaint p;
    242         p.setStyle(SkPaint::kStroke_Style);
    243         p.setColor(SK_ColorBLUE);
    244 
    245         SkRect r = SkRect::MakeWH(fCell.width() * 2, fCell.height() * 2);
    246         r.inset(SK_ScalarHalf, SK_ScalarHalf);
    247         canvas->drawRect(r, p);
    248         canvas->drawLine(r.left(), r.centerY(), r.right(), r.centerY(), p);
    249         canvas->drawLine(r.centerX(), r.top(), r.centerX(), r.bottom(), p);
    250     }
    251 
    252     void onOnceBeforeDraw() override {
    253         fImage = make_image();
    254     }
    255 
    256     void onDrawContent(SkCanvas* canvas) override {
    257         fCell.set(this->height() / 2, this->height() / 2);
    258 
    259         SkScalar trans[2];
    260         fTrans.timeToValues(fCurrTime, trans);
    261 
    262         for (int y = 0; y < 2; ++y) {
    263             for (int x = 0; x < 2; ++x) {
    264                 int index = y * 2 + x;
    265                 SkAutoCanvasRestore acr(canvas, true);
    266                 canvas->translate(fCell.width() * x, fCell.height() * y);
    267                 SkRect r = SkRect::MakeWH(fCell.width(), fCell.height());
    268                 r.inset(4, 4);
    269                 canvas->clipRect(r);
    270                 this->drawHere(canvas, SkFilterQuality(index), trans[0], trans[1]);
    271             }
    272         }
    273 
    274         this->drawBorders(canvas);
    275 
    276         const SkScalar textX = fCell.width() * 2 + 30;
    277 
    278         SkFont font(nullptr, 36);
    279         SkPaint paint;
    280         canvas->drawString(SkStringPrintf("%.8g", (float)fScale), textX, 100, font, paint);
    281         canvas->drawString(SkStringPrintf("%.8g", (float)fAngle), textX, 150, font, paint);
    282         canvas->drawString(SkStringPrintf("%.8g", trans[0]     ), textX, 200, font, paint);
    283         canvas->drawString(SkStringPrintf("%.8g", trans[1]     ), textX, 250, font, paint);
    284     }
    285 
    286     bool onAnimate(const SkAnimTimer& timer) override {
    287         fCurrTime = timer.msec();
    288         return true;
    289     }
    290 
    291 private:
    292     typedef Sample INHERITED;
    293 };
    294 
    295 //////////////////////////////////////////////////////////////////////////////
    296 
    297 DEF_SAMPLE( return new FilterQualityView(); )
    298