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 18typedef void (*DrawAtlasProc)(SkCanvas*, SkImage*, const SkRSXform[], const SkRect[], 19 const SkColor[], int, const SkRect*, const SkPaint*); 20 21static 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 27static 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 42static 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 68class 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 140public: 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 173protected: 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 200private: 201 typedef SkDrawable INHERITED; 202}; 203 204class DrawAtlasView : public SampleView { 205 const char* fName; 206 DrawAtlasDrawable* fDrawable; 207 208public: 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 217protected: 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(); 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 249private: 250 typedef SampleView INHERITED; 251}; 252 253////////////////////////////////////////////////////////////////////////////// 254 255DEF_SAMPLE( return new DrawAtlasView("DrawAtlas", draw_atlas); ) 256DEF_SAMPLE( return new DrawAtlasView("DrawAtlasSim", draw_atlas_sim); ) 257