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 "SampleCode.h"
      9 #include "SkAnimTimer.h"
     10 #include "SkView.h"
     11 #include "SkCanvas.h"
     12 #include "SkDrawable.h"
     13 #include "SkPath.h"
     14 #include "SkRandom.h"
     15 #include "SkRSXform.h"
     16 #include "SkSurface.h"
     17 
     18 typedef void (*DrawAtlasProc)(SkCanvas*, SkImage*, const SkRSXform[], const SkRect[],
     19                               const SkColor[], int, const SkRect*, const SkPaint*);
     20 
     21 static void draw_atlas(SkCanvas* canvas, SkImage* atlas, const SkRSXform xform[],
     22                        const SkRect tex[], const SkColor colors[], int count, const SkRect* cull,
     23                        const SkPaint* paint) {
     24     canvas->drawAtlas(atlas, xform, tex, colors, count, SkBlendMode::kModulate, cull, paint);
     25 }
     26 
     27 static void draw_atlas_sim(SkCanvas* canvas, SkImage* atlas, const SkRSXform xform[],
     28                            const SkRect tex[], const SkColor colors[], int count, const SkRect* cull,
     29                            const SkPaint* paint) {
     30     for (int i = 0; i < count; ++i) {
     31         SkMatrix matrix;
     32         matrix.setRSXform(xform[i]);
     33 
     34         canvas->save();
     35         canvas->concat(matrix);
     36         canvas->drawImageRect(atlas, tex[i], tex[i].makeOffset(-tex[i].x(), -tex[i].y()), paint,
     37                               SkCanvas::kFast_SrcRectConstraint);
     38         canvas->restore();
     39     }
     40 }
     41 
     42 static sk_sp<SkImage> make_atlas(int atlasSize, int cellSize) {
     43     SkImageInfo info = SkImageInfo::MakeN32Premul(atlasSize, atlasSize);
     44     auto surface(SkSurface::MakeRaster(info));
     45     SkCanvas* canvas = surface->getCanvas();
     46 
     47     SkPaint paint;
     48     paint.setAntiAlias(true);
     49     SkRandom rand;
     50 
     51     const SkScalar half = cellSize * SK_ScalarHalf;
     52     const char* s = "01234567890!@#$%^&*=+<>?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
     53     paint.setTextSize(28);
     54     paint.setTextAlign(SkPaint::kCenter_Align);
     55     int i = 0;
     56     for (int y = 0; y < atlasSize; y += cellSize) {
     57         for (int x = 0; x < atlasSize; x += cellSize) {
     58             paint.setColor(rand.nextU());
     59             paint.setAlpha(0xFF);
     60             int index = i % strlen(s);
     61             canvas->drawText(&s[index], 1, x + half, y + half + half/2, paint);
     62             i += 1;
     63         }
     64     }
     65     return surface->makeImageSnapshot();
     66 }
     67 
     68 class DrawAtlasDrawable : public SkDrawable {
     69     enum {
     70         kMaxScale = 2,
     71         kCellSize = 32,
     72         kAtlasSize = 512,
     73     };
     74 
     75     struct Rec {
     76         SkPoint     fCenter;
     77         SkVector    fVelocity;
     78         SkScalar    fScale;
     79         SkScalar    fDScale;
     80         SkScalar    fRadian;
     81         SkScalar    fDRadian;
     82         SkScalar    fAlpha;
     83         SkScalar    fDAlpha;
     84 
     85         void advance(const SkRect& bounds) {
     86             fCenter += fVelocity;
     87             if (fCenter.fX > bounds.right()) {
     88                 SkASSERT(fVelocity.fX > 0);
     89                 fVelocity.fX = -fVelocity.fX;
     90             } else if (fCenter.fX < bounds.left()) {
     91                 SkASSERT(fVelocity.fX < 0);
     92                 fVelocity.fX = -fVelocity.fX;
     93             }
     94             if (fCenter.fY > bounds.bottom()) {
     95                 if (fVelocity.fY > 0) {
     96                     fVelocity.fY = -fVelocity.fY;
     97                 }
     98             } else if (fCenter.fY < bounds.top()) {
     99                 if (fVelocity.fY < 0) {
    100                     fVelocity.fY = -fVelocity.fY;
    101                 }
    102             }
    103 
    104             fScale += fDScale;
    105             if (fScale > 2 || fScale < SK_Scalar1/2) {
    106                 fDScale = -fDScale;
    107             }
    108 
    109             fRadian += fDRadian;
    110             fRadian = SkScalarMod(fRadian, 2 * SK_ScalarPI);
    111 
    112             fAlpha += fDAlpha;
    113             if (fAlpha > 1) {
    114                 fAlpha = 1;
    115                 fDAlpha = -fDAlpha;
    116             } else if (fAlpha < 0) {
    117                 fAlpha = 0;
    118                 fDAlpha = -fDAlpha;
    119             }
    120         }
    121 
    122         SkRSXform asRSXform() const {
    123             return SkRSXform::MakeFromRadians(fScale, fRadian, fCenter.x(), fCenter.y(),
    124                                               SkScalarHalf(kCellSize), SkScalarHalf(kCellSize));
    125         }
    126     };
    127 
    128     DrawAtlasProc fProc;
    129 
    130     enum {
    131         N = 256,
    132     };
    133 
    134     sk_sp<SkImage> fAtlas;
    135     Rec         fRec[N];
    136     SkRect      fTex[N];
    137     SkRect      fBounds;
    138     bool        fUseColors;
    139 
    140 public:
    141     DrawAtlasDrawable(DrawAtlasProc proc, const SkRect& r)
    142         : fProc(proc), fBounds(r), fUseColors(false)
    143     {
    144         SkRandom rand;
    145         fAtlas = make_atlas(kAtlasSize, kCellSize);
    146         const SkScalar kMaxSpeed = 5;
    147         const SkScalar cell = SkIntToScalar(kCellSize);
    148         int i = 0;
    149         for (int y = 0; y < kAtlasSize; y += kCellSize) {
    150             for (int x = 0; x < kAtlasSize; x += kCellSize) {
    151                 const SkScalar sx = SkIntToScalar(x);
    152                 const SkScalar sy = SkIntToScalar(y);
    153                 fTex[i].setXYWH(sx, sy, cell, cell);
    154 
    155                 fRec[i].fCenter.set(sx + cell/2, sy + 3*cell/4);
    156                 fRec[i].fVelocity.fX = rand.nextSScalar1() * kMaxSpeed;
    157                 fRec[i].fVelocity.fY = rand.nextSScalar1() * kMaxSpeed;
    158                 fRec[i].fScale = 1;
    159                 fRec[i].fDScale = rand.nextSScalar1() / 16;
    160                 fRec[i].fRadian = 0;
    161                 fRec[i].fDRadian = rand.nextSScalar1() / 8;
    162                 fRec[i].fAlpha = rand.nextUScalar1();
    163                 fRec[i].fDAlpha = rand.nextSScalar1() / 10;
    164                 i += 1;
    165             }
    166         }
    167     }
    168 
    169     void toggleUseColors() {
    170         fUseColors = !fUseColors;
    171     }
    172 
    173 protected:
    174     void onDraw(SkCanvas* canvas) override {
    175         SkRSXform xform[N];
    176         SkColor colors[N];
    177 
    178         for (int i = 0; i < N; ++i) {
    179             fRec[i].advance(fBounds);
    180             xform[i] = fRec[i].asRSXform();
    181             if (fUseColors) {
    182                 colors[i] = SkColorSetARGB((int)(fRec[i].fAlpha * 0xFF), 0xFF, 0xFF, 0xFF);
    183             }
    184         }
    185         SkPaint paint;
    186         paint.setFilterQuality(kLow_SkFilterQuality);
    187 
    188         const SkRect cull = this->getBounds();
    189         const SkColor* colorsPtr = fUseColors ? colors : nullptr;
    190         fProc(canvas, fAtlas.get(), xform, fTex, colorsPtr, N, &cull, &paint);
    191     }
    192 
    193     SkRect onGetBounds() override {
    194         const SkScalar border = kMaxScale * kCellSize;
    195         SkRect r = fBounds;
    196         r.outset(border, border);
    197         return r;
    198     }
    199 
    200 private:
    201     typedef SkDrawable INHERITED;
    202 };
    203 
    204 class DrawAtlasView : public SampleView {
    205     const char*         fName;
    206     DrawAtlasDrawable*  fDrawable;
    207 
    208 public:
    209     DrawAtlasView(const char name[], DrawAtlasProc proc) : fName(name) {
    210         fDrawable = new DrawAtlasDrawable(proc, SkRect::MakeWH(640, 480));
    211     }
    212 
    213     ~DrawAtlasView() override {
    214         fDrawable->unref();
    215     }
    216 
    217 protected:
    218     bool onQuery(SkEvent* evt) override {
    219         if (SampleCode::TitleQ(*evt)) {
    220             SampleCode::TitleR(evt, fName);
    221             return true;
    222         }
    223         SkUnichar uni;
    224         if (SampleCode::CharQ(*evt, &uni)) {
    225             switch (uni) {
    226                 case 'C': fDrawable->toggleUseColors(); this->inval(nullptr); return true;
    227                 default: break;
    228             }
    229         }
    230         return this->INHERITED::onQuery(evt);
    231     }
    232 
    233     void onDrawContent(SkCanvas* canvas) override {
    234         canvas->drawDrawable(fDrawable);
    235     }
    236 
    237     bool onAnimate(const SkAnimTimer&) override {
    238         return true;
    239     }
    240 #if 0
    241     // TODO: switch over to use this for our animation
    242     bool onAnimate(const SkAnimTimer& timer) override {
    243         SkScalar angle = SkDoubleToScalar(fmod(timer.secs() * 360 / 24, 360));
    244         fAnimatingDrawable->setSweep(angle);
    245         return true;
    246     }
    247 #endif
    248 
    249 private:
    250     typedef SampleView INHERITED;
    251 };
    252 
    253 //////////////////////////////////////////////////////////////////////////////
    254 
    255 DEF_SAMPLE( return new DrawAtlasView("DrawAtlas", draw_atlas); )
    256 DEF_SAMPLE( return new DrawAtlasView("DrawAtlasSim", draw_atlas_sim); )
    257