1 /* 2 * Copyright 2011 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 "DecodeFile.h" 9 #include "SampleCode.h" 10 #include "SkAnimTimer.h" 11 #include "SkView.h" 12 #include "SkCanvas.h" 13 #include "SkGradientShader.h" 14 #include "SkGraphics.h" 15 #include "SkPath.h" 16 #include "SkRandom.h" 17 #include "SkRegion.h" 18 #include "SkShader.h" 19 #include "SkUtils.h" 20 #include "SkColorPriv.h" 21 #include "SkColorFilter.h" 22 #include "SkTime.h" 23 #include "SkTypeface.h" 24 #include "SkVertices.h" 25 26 #include "SkOSFile.h" 27 #include "SkStream.h" 28 29 #include "SkGeometry.h" // private include :( 30 31 static sk_sp<SkShader> make_shader0(SkIPoint* size) { 32 SkBitmap bm; 33 34 // decode_file("/skimages/progressivejpg.jpg", &bm); 35 decode_file("/skimages/logo.png", &bm); 36 size->set(bm.width(), bm.height()); 37 return SkShader::MakeBitmapShader(bm, SkShader::kClamp_TileMode, 38 SkShader::kClamp_TileMode); 39 } 40 41 static sk_sp<SkShader> make_shader1(const SkIPoint& size) { 42 SkPoint pts[] = { { 0, 0, }, 43 { SkIntToScalar(size.fX), SkIntToScalar(size.fY) } }; 44 SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED }; 45 return SkGradientShader::MakeLinear(pts, colors, nullptr, 46 SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode); 47 } 48 49 /////////////////////////////////////////////////////////////////////////////// 50 51 class Patch { 52 public: 53 Patch() { sk_bzero(fPts, sizeof(fPts)); } 54 ~Patch() {} 55 56 void setPatch(const SkPoint pts[12]) { 57 memcpy(fPts, pts, 12 * sizeof(SkPoint)); 58 fPts[12] = pts[0]; // the last shall be first 59 } 60 void setBounds(int w, int h) { fW = w; fH = h; } 61 62 void draw(SkCanvas*, const SkPaint&, int segsU, int segsV, 63 bool doTextures, bool doColors); 64 65 private: 66 SkPoint fPts[13]; 67 int fW, fH; 68 }; 69 70 static void eval_patch_edge(const SkPoint cubic[], SkPoint samples[], int segs) { 71 SkScalar t = 0; 72 SkScalar dt = SK_Scalar1 / segs; 73 74 samples[0] = cubic[0]; 75 for (int i = 1; i < segs; i++) { 76 t += dt; 77 SkEvalCubicAt(cubic, t, &samples[i], nullptr, nullptr); 78 } 79 } 80 81 static void eval_sheet(const SkPoint edge[], int nu, int nv, int iu, int iv, 82 SkPoint* pt) { 83 const int TL = 0; 84 const int TR = nu; 85 const int BR = TR + nv; 86 const int BL = BR + nu; 87 88 SkScalar u = SkIntToScalar(iu) / nu; 89 SkScalar v = SkIntToScalar(iv) / nv; 90 91 SkScalar uv = u * v; 92 SkScalar Uv = (1 - u) * v; 93 SkScalar uV = u * (1 - v); 94 SkScalar UV = (1 - u) * (1 - v); 95 96 SkScalar x0 = UV * edge[TL].fX + uV * edge[TR].fX + Uv * edge[BL].fX + uv * edge[BR].fX; 97 SkScalar y0 = UV * edge[TL].fY + uV * edge[TR].fY + Uv * edge[BL].fY + uv * edge[BR].fY; 98 99 SkScalar x = (1 - v) * edge[TL+iu].fX + u * edge[TR+iv].fX + 100 v * edge[BR+nu-iu].fX + (1 - u) * edge[BL+nv-iv].fX - x0; 101 SkScalar y = (1 - v) * edge[TL+iu].fY + u * edge[TR+iv].fY + 102 v * edge[BR+nu-iu].fY + (1 - u) * edge[BL+nv-iv].fY - y0; 103 pt->set(x, y); 104 } 105 106 static SkColor make_color(SkScalar s, SkScalar t) { 107 return SkColorSetARGB(0xFF, SkUnitScalarClampToByte(s), SkUnitScalarClampToByte(t), 0); 108 } 109 110 void Patch::draw(SkCanvas* canvas, const SkPaint& paint, int nu, int nv, 111 bool doTextures, bool doColors) { 112 if (nu < 1 || nv < 1) { 113 return; 114 } 115 116 int i, npts = (nu + nv) * 2; 117 SkAutoSTMalloc<16, SkPoint> storage(npts + 1); 118 SkPoint* edge0 = storage.get(); 119 SkPoint* edge1 = edge0 + nu; 120 SkPoint* edge2 = edge1 + nv; 121 SkPoint* edge3 = edge2 + nu; 122 123 // evaluate the edge points 124 eval_patch_edge(fPts + 0, edge0, nu); 125 eval_patch_edge(fPts + 3, edge1, nv); 126 eval_patch_edge(fPts + 6, edge2, nu); 127 eval_patch_edge(fPts + 9, edge3, nv); 128 edge3[nv] = edge0[0]; // the last shall be first 129 130 for (i = 0; i < npts; i++) { 131 // canvas->drawLine(edge0[i].fX, edge0[i].fY, edge0[i+1].fX, edge0[i+1].fY, paint); 132 } 133 134 int row, vertCount = (nu + 1) * (nv + 1); 135 SkAutoTMalloc<SkPoint> vertStorage(vertCount); 136 SkPoint* verts = vertStorage.get(); 137 138 // first row 139 memcpy(verts, edge0, (nu + 1) * sizeof(SkPoint)); 140 // rows 141 SkPoint* r = verts; 142 for (row = 1; row < nv; row++) { 143 r += nu + 1; 144 r[0] = edge3[nv - row]; 145 for (int col = 1; col < nu; col++) { 146 eval_sheet(edge0, nu, nv, col, row, &r[col]); 147 } 148 r[nu] = edge1[row]; 149 } 150 // last row 151 SkPoint* last = verts + nv * (nu + 1); 152 for (i = 0; i <= nu; i++) { 153 last[i] = edge2[nu - i]; 154 } 155 156 // canvas->drawPoints(verts, vertCount, paint); 157 158 int stripCount = (nu + 1) * 2; 159 SkAutoTMalloc<SkPoint> stripStorage(stripCount * 2); 160 SkAutoTMalloc<SkColor> colorStorage(stripCount); 161 SkPoint* strip = stripStorage.get(); 162 SkPoint* tex = strip + stripCount; 163 SkColor* colors = colorStorage.get(); 164 SkScalar t = 0; 165 const SkScalar ds = SK_Scalar1 * fW / nu; 166 const SkScalar dt = SK_Scalar1 * fH / nv; 167 r = verts; 168 for (row = 0; row < nv; row++) { 169 SkPoint* upper = r; 170 SkPoint* lower = r + nu + 1; 171 r = lower; 172 SkScalar s = 0; 173 for (i = 0; i <= nu; i++) { 174 strip[i*2 + 0] = *upper++; 175 strip[i*2 + 1] = *lower++; 176 tex[i*2 + 0].set(s, t); 177 tex[i*2 + 1].set(s, t + dt); 178 colors[i*2 + 0] = make_color(s/fW, t/fH); 179 colors[i*2 + 1] = make_color(s/fW, (t + dt)/fH); 180 s += ds; 181 } 182 t += dt; 183 canvas->drawVertices(SkVertices::MakeCopy(SkVertices::kTriangleStrip_VertexMode, stripCount, 184 strip, doTextures ? tex : nullptr, 185 doColors ? colors : nullptr), 186 SkBlendMode::kModulate, paint); 187 } 188 } 189 190 static void drawpatches(SkCanvas* canvas, const SkPaint& paint, int nu, int nv, 191 Patch* patch) { 192 SkAutoCanvasRestore ar(canvas, true); 193 194 patch->draw(canvas, paint, nu, nv, false, false); 195 canvas->translate(SkIntToScalar(180), 0); 196 patch->draw(canvas, paint, nu, nv, true, false); 197 canvas->translate(SkIntToScalar(180), 0); 198 patch->draw(canvas, paint, nu, nv, false, true); 199 canvas->translate(SkIntToScalar(180), 0); 200 patch->draw(canvas, paint, nu, nv, true, true); 201 } 202 203 const SkScalar DX = 20; 204 const SkScalar DY = 0; 205 206 class PatchView : public SampleView { 207 SkScalar fAngle; 208 sk_sp<SkShader> fShader0; 209 sk_sp<SkShader> fShader1; 210 SkIPoint fSize0, fSize1; 211 SkPoint fPts[12]; 212 213 public: 214 PatchView() : fAngle(0) { 215 fShader0 = make_shader0(&fSize0); 216 fSize1 = fSize0; 217 if (fSize0.fX == 0 || fSize0.fY == 0) { 218 fSize1.set(2, 2); 219 } 220 fShader1 = make_shader1(fSize1); 221 222 const SkScalar S = SkIntToScalar(50); 223 const SkScalar T = SkIntToScalar(40); 224 fPts[0].set(S*0, T); 225 fPts[1].set(S*1, T); 226 fPts[2].set(S*2, T); 227 fPts[3].set(S*3, T); 228 fPts[4].set(S*3, T*2); 229 fPts[5].set(S*3, T*3); 230 fPts[6].set(S*3, T*4); 231 fPts[7].set(S*2, T*4); 232 fPts[8].set(S*1, T*4); 233 fPts[9].set(S*0, T*4); 234 fPts[10].set(S*0, T*3); 235 fPts[11].set(S*0, T*2); 236 237 this->setBGColor(SK_ColorGRAY); 238 } 239 240 protected: 241 // overrides from SkEventSink 242 bool onQuery(SkEvent* evt) override { 243 if (SampleCode::TitleQ(*evt)) { 244 SampleCode::TitleR(evt, "Patch"); 245 return true; 246 } 247 return this->INHERITED::onQuery(evt); 248 } 249 250 void onDrawContent(SkCanvas* canvas) override { 251 const int nu = 10; 252 const int nv = 10; 253 254 SkPaint paint; 255 paint.setDither(true); 256 paint.setFilterQuality(kLow_SkFilterQuality); 257 258 canvas->translate(DX, DY); 259 260 Patch patch; 261 262 paint.setShader(fShader0); 263 if (fSize0.fX == 0) { 264 fSize0.fX = 1; 265 } 266 if (fSize0.fY == 0) { 267 fSize0.fY = 1; 268 } 269 patch.setBounds(fSize0.fX, fSize0.fY); 270 271 patch.setPatch(fPts); 272 drawpatches(canvas, paint, nu, nv, &patch); 273 274 paint.setShader(nullptr); 275 paint.setAntiAlias(true); 276 paint.setStrokeWidth(SkIntToScalar(5)); 277 canvas->drawPoints(SkCanvas::kPoints_PointMode, SK_ARRAY_COUNT(fPts), fPts, paint); 278 279 canvas->translate(0, SkIntToScalar(300)); 280 281 paint.setAntiAlias(false); 282 paint.setShader(fShader1); 283 if (true) { 284 SkMatrix m; 285 m.setSkew(1, 0); 286 paint.setShader(paint.getShader()->makeWithLocalMatrix(m)); 287 } 288 if (true) { 289 SkMatrix m; 290 m.setRotate(fAngle); 291 paint.setShader(paint.getShader()->makeWithLocalMatrix(m)); 292 } 293 patch.setBounds(fSize1.fX, fSize1.fY); 294 drawpatches(canvas, paint, nu, nv, &patch); 295 } 296 297 bool onAnimate(const SkAnimTimer& timer) override { 298 fAngle = timer.scaled(60, 360); 299 return true; 300 } 301 302 class PtClick : public Click { 303 public: 304 int fIndex; 305 PtClick(SkView* view, int index) : Click(view), fIndex(index) {} 306 }; 307 308 static bool hittest(const SkPoint& pt, SkScalar x, SkScalar y) { 309 return SkPoint::Length(pt.fX - x, pt.fY - y) < SkIntToScalar(5); 310 } 311 312 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override { 313 x -= DX; 314 y -= DY; 315 for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); i++) { 316 if (hittest(fPts[i], x, y)) { 317 return new PtClick(this, (int)i); 318 } 319 } 320 return this->INHERITED::onFindClickHandler(x, y, modi); 321 } 322 323 bool onClick(Click* click) override { 324 fPts[((PtClick*)click)->fIndex].set(click->fCurr.fX - DX, click->fCurr.fY - DY); 325 this->inval(nullptr); 326 return true; 327 } 328 329 private: 330 typedef SampleView INHERITED; 331 }; 332 333 ////////////////////////////////////////////////////////////////////////////// 334 335 static SkView* MyFactory() { return new PatchView; } 336 static SkViewRegister reg(MyFactory); 337