SamplePatch.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  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. #include "include/core/SkCanvas.h"
  8. #include "include/core/SkColorFilter.h"
  9. #include "include/core/SkColorPriv.h"
  10. #include "include/core/SkContourMeasure.h"
  11. #include "include/core/SkGraphics.h"
  12. #include "include/core/SkPath.h"
  13. #include "include/core/SkRegion.h"
  14. #include "include/core/SkShader.h"
  15. #include "include/core/SkStream.h"
  16. #include "include/core/SkTime.h"
  17. #include "include/core/SkTypeface.h"
  18. #include "include/core/SkVertices.h"
  19. #include "include/effects/SkGradientShader.h"
  20. #include "include/effects/SkOpPathEffect.h"
  21. #include "include/private/SkTDArray.h"
  22. #include "include/utils/SkRandom.h"
  23. #include "samplecode/DecodeFile.h"
  24. #include "samplecode/Sample.h"
  25. #include "src/core/SkGeometry.h"
  26. #include "src/core/SkOSFile.h"
  27. #include "src/utils/SkUTF.h"
  28. #include "tools/Resources.h"
  29. #include "tools/timer/TimeUtils.h"
  30. namespace {
  31. static sk_sp<SkShader> make_shader0(SkIPoint* size) {
  32. SkBitmap bm;
  33. decode_file(GetResourceAsData("images/dog.jpg"), &bm);
  34. *size = SkIPoint{bm.width(), bm.height()};
  35. return bm.makeShader();
  36. }
  37. static sk_sp<SkShader> make_shader1(const SkIPoint& size) {
  38. SkPoint pts[] = { { 0, 0, },
  39. { SkIntToScalar(size.fX), SkIntToScalar(size.fY) } };
  40. SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
  41. return SkGradientShader::MakeLinear(pts, colors, nullptr,
  42. SK_ARRAY_COUNT(colors), SkTileMode::kMirror);
  43. }
  44. class Patch {
  45. public:
  46. Patch() { sk_bzero(fPts, sizeof(fPts)); }
  47. ~Patch() {}
  48. void setPatch(const SkPoint pts[12]) {
  49. memcpy(fPts, pts, 12 * sizeof(SkPoint));
  50. fPts[12] = pts[0]; // the last shall be first
  51. }
  52. void setBounds(int w, int h) { fW = w; fH = h; }
  53. void draw(SkCanvas*, const SkPaint&, int segsU, int segsV,
  54. bool doTextures, bool doColors);
  55. private:
  56. SkPoint fPts[13];
  57. int fW, fH;
  58. };
  59. static void eval_patch_edge(const SkPoint cubic[], SkPoint samples[], int segs) {
  60. SkScalar t = 0;
  61. SkScalar dt = SK_Scalar1 / segs;
  62. samples[0] = cubic[0];
  63. for (int i = 1; i < segs; i++) {
  64. t += dt;
  65. SkEvalCubicAt(cubic, t, &samples[i], nullptr, nullptr);
  66. }
  67. }
  68. static void eval_sheet(const SkPoint edge[], int nu, int nv, int iu, int iv,
  69. SkPoint* pt) {
  70. const int TL = 0;
  71. const int TR = nu;
  72. const int BR = TR + nv;
  73. const int BL = BR + nu;
  74. SkScalar u = SkIntToScalar(iu) / nu;
  75. SkScalar v = SkIntToScalar(iv) / nv;
  76. SkScalar uv = u * v;
  77. SkScalar Uv = (1 - u) * v;
  78. SkScalar uV = u * (1 - v);
  79. SkScalar UV = (1 - u) * (1 - v);
  80. SkScalar x0 = UV * edge[TL].fX + uV * edge[TR].fX + Uv * edge[BL].fX + uv * edge[BR].fX;
  81. SkScalar y0 = UV * edge[TL].fY + uV * edge[TR].fY + Uv * edge[BL].fY + uv * edge[BR].fY;
  82. SkScalar x = (1 - v) * edge[TL+iu].fX + u * edge[TR+iv].fX +
  83. v * edge[BR+nu-iu].fX + (1 - u) * edge[BL+nv-iv].fX - x0;
  84. SkScalar y = (1 - v) * edge[TL+iu].fY + u * edge[TR+iv].fY +
  85. v * edge[BR+nu-iu].fY + (1 - u) * edge[BL+nv-iv].fY - y0;
  86. pt->set(x, y);
  87. }
  88. static SkColor make_color(SkScalar s, SkScalar t) {
  89. return SkColorSetARGB(0xFF, SkUnitScalarClampToByte(s), SkUnitScalarClampToByte(t), 0);
  90. }
  91. void Patch::draw(SkCanvas* canvas, const SkPaint& paint, int nu, int nv,
  92. bool doTextures, bool doColors) {
  93. if (nu < 1 || nv < 1) {
  94. return;
  95. }
  96. int i, npts = (nu + nv) * 2;
  97. SkAutoSTMalloc<16, SkPoint> storage(npts + 1);
  98. SkPoint* edge0 = storage.get();
  99. SkPoint* edge1 = edge0 + nu;
  100. SkPoint* edge2 = edge1 + nv;
  101. SkPoint* edge3 = edge2 + nu;
  102. // evaluate the edge points
  103. eval_patch_edge(fPts + 0, edge0, nu);
  104. eval_patch_edge(fPts + 3, edge1, nv);
  105. eval_patch_edge(fPts + 6, edge2, nu);
  106. eval_patch_edge(fPts + 9, edge3, nv);
  107. edge3[nv] = edge0[0]; // the last shall be first
  108. for (i = 0; i < npts; i++) {
  109. // canvas->drawLine(edge0[i].fX, edge0[i].fY, edge0[i+1].fX, edge0[i+1].fY, paint);
  110. }
  111. int row, vertCount = (nu + 1) * (nv + 1);
  112. SkAutoTMalloc<SkPoint> vertStorage(vertCount);
  113. SkPoint* verts = vertStorage.get();
  114. // first row
  115. memcpy(verts, edge0, (nu + 1) * sizeof(SkPoint));
  116. // rows
  117. SkPoint* r = verts;
  118. for (row = 1; row < nv; row++) {
  119. r += nu + 1;
  120. r[0] = edge3[nv - row];
  121. for (int col = 1; col < nu; col++) {
  122. eval_sheet(edge0, nu, nv, col, row, &r[col]);
  123. }
  124. r[nu] = edge1[row];
  125. }
  126. // last row
  127. SkPoint* last = verts + nv * (nu + 1);
  128. for (i = 0; i <= nu; i++) {
  129. last[i] = edge2[nu - i];
  130. }
  131. // canvas->drawPoints(verts, vertCount, paint);
  132. int stripCount = (nu + 1) * 2;
  133. SkAutoTMalloc<SkPoint> stripStorage(stripCount * 2);
  134. SkAutoTMalloc<SkColor> colorStorage(stripCount);
  135. SkPoint* strip = stripStorage.get();
  136. SkPoint* tex = strip + stripCount;
  137. SkColor* colors = colorStorage.get();
  138. SkScalar t = 0;
  139. const SkScalar ds = SK_Scalar1 * fW / nu;
  140. const SkScalar dt = SK_Scalar1 * fH / nv;
  141. r = verts;
  142. for (row = 0; row < nv; row++) {
  143. SkPoint* upper = r;
  144. SkPoint* lower = r + nu + 1;
  145. r = lower;
  146. SkScalar s = 0;
  147. for (i = 0; i <= nu; i++) {
  148. strip[i*2 + 0] = *upper++;
  149. strip[i*2 + 1] = *lower++;
  150. tex[i*2 + 0].set(s, t);
  151. tex[i*2 + 1].set(s, t + dt);
  152. colors[i*2 + 0] = make_color(s/fW, t/fH);
  153. colors[i*2 + 1] = make_color(s/fW, (t + dt)/fH);
  154. s += ds;
  155. }
  156. t += dt;
  157. canvas->drawVertices(SkVertices::MakeCopy(SkVertices::kTriangleStrip_VertexMode, stripCount,
  158. strip, doTextures ? tex : nullptr,
  159. doColors ? colors : nullptr),
  160. SkBlendMode::kModulate, paint);
  161. }
  162. }
  163. static void drawpatches(SkCanvas* canvas, const SkPaint& paint, int nu, int nv,
  164. Patch* patch) {
  165. SkAutoCanvasRestore ar(canvas, true);
  166. patch->draw(canvas, paint, nu, nv, false, false);
  167. canvas->translate(SkIntToScalar(180), 0);
  168. patch->draw(canvas, paint, nu, nv, true, false);
  169. canvas->translate(SkIntToScalar(180), 0);
  170. patch->draw(canvas, paint, nu, nv, false, true);
  171. canvas->translate(SkIntToScalar(180), 0);
  172. patch->draw(canvas, paint, nu, nv, true, true);
  173. }
  174. static constexpr SkScalar DX = 20;
  175. static constexpr SkScalar DY = 0;
  176. static constexpr SkScalar kS = 50;
  177. static constexpr SkScalar kT = 40;
  178. struct PatchView : public Sample {
  179. sk_sp<SkShader> fShader0;
  180. sk_sp<SkShader> fShader1;
  181. SkScalar fAngle = 0;
  182. SkIPoint fSize0 = {0, 0},
  183. fSize1 = {0, 0};
  184. SkPoint fPts[12] = {
  185. {kS * 0, kT * 1},
  186. {kS * 1, kT * 1},
  187. {kS * 2, kT * 1},
  188. {kS * 3, kT * 1},
  189. {kS * 3, kT * 2},
  190. {kS * 3, kT * 3},
  191. {kS * 3, kT * 4},
  192. {kS * 2, kT * 4},
  193. {kS * 1, kT * 4},
  194. {kS * 0, kT * 4},
  195. {kS * 0, kT * 3},
  196. {kS * 0, kT * 2},
  197. };
  198. void onOnceBeforeDraw() override {
  199. fShader0 = make_shader0(&fSize0);
  200. fSize1 = fSize0;
  201. if (fSize0.fX == 0 || fSize0.fY == 0) {
  202. fSize1.set(2, 2);
  203. }
  204. fShader1 = make_shader1(fSize1);
  205. this->setBGColor(SK_ColorGRAY);
  206. }
  207. SkString name() override { return SkString("Patch"); }
  208. void onDrawContent(SkCanvas* canvas) override {
  209. const int nu = 10;
  210. const int nv = 10;
  211. SkPaint paint;
  212. paint.setDither(true);
  213. paint.setFilterQuality(kLow_SkFilterQuality);
  214. canvas->translate(DX, DY);
  215. Patch patch;
  216. paint.setShader(fShader0);
  217. if (fSize0.fX == 0) {
  218. fSize0.fX = 1;
  219. }
  220. if (fSize0.fY == 0) {
  221. fSize0.fY = 1;
  222. }
  223. patch.setBounds(fSize0.fX, fSize0.fY);
  224. patch.setPatch(fPts);
  225. drawpatches(canvas, paint, nu, nv, &patch);
  226. paint.setShader(nullptr);
  227. paint.setAntiAlias(true);
  228. paint.setStrokeWidth(SkIntToScalar(5));
  229. canvas->drawPoints(SkCanvas::kPoints_PointMode, SK_ARRAY_COUNT(fPts), fPts, paint);
  230. canvas->translate(0, SkIntToScalar(300));
  231. paint.setAntiAlias(false);
  232. paint.setShader(fShader1);
  233. {
  234. SkMatrix m;
  235. m.setSkew(1, 0);
  236. paint.setShader(paint.getShader()->makeWithLocalMatrix(m));
  237. }
  238. {
  239. SkMatrix m;
  240. m.setRotate(fAngle);
  241. paint.setShader(paint.getShader()->makeWithLocalMatrix(m));
  242. }
  243. patch.setBounds(fSize1.fX, fSize1.fY);
  244. drawpatches(canvas, paint, nu, nv, &patch);
  245. }
  246. bool onAnimate(double nanos) override {
  247. fAngle = TimeUtils::Scaled(1e-9 * nanos, 60, 360);
  248. return true;
  249. }
  250. class PtClick : public Click {
  251. public:
  252. int fIndex;
  253. PtClick(int index) : fIndex(index) {}
  254. };
  255. static bool hittest(const SkPoint& pt, SkScalar x, SkScalar y) {
  256. return SkPoint::Length(pt.fX - x, pt.fY - y) < SkIntToScalar(5);
  257. }
  258. Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey modi) override {
  259. x -= DX;
  260. y -= DY;
  261. for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); i++) {
  262. if (hittest(fPts[i], x, y)) {
  263. return new PtClick((int)i);
  264. }
  265. }
  266. return nullptr;
  267. }
  268. bool onClick(Click* click) override {
  269. fPts[((PtClick*)click)->fIndex].set(click->fCurr.fX - DX, click->fCurr.fY - DY);
  270. return true;
  271. }
  272. private:
  273. typedef Sample INHERITED;
  274. };
  275. } // namespace
  276. DEF_SAMPLE( return new PatchView(); )
  277. //////////////////////////////////////////////////////////////////////////////
  278. namespace {
  279. static sk_sp<SkVertices> make_verts(const SkPath& path, SkScalar width) {
  280. auto meas = SkContourMeasureIter(path, false).next();
  281. if (!meas) {
  282. return nullptr;
  283. }
  284. const SkPoint src[2] = {
  285. { 0, -width/2 }, { 0, width/2 },
  286. };
  287. SkTDArray<SkPoint> pts;
  288. const SkScalar step = 2;
  289. for (SkScalar distance = 0; distance < meas->length(); distance += step) {
  290. SkMatrix mx;
  291. if (!meas->getMatrix(distance, &mx)) {
  292. continue;
  293. }
  294. SkPoint* dst = pts.append(2);
  295. mx.mapPoints(dst, src, 2);
  296. }
  297. int vertCount = pts.count();
  298. int indexCount = 0; // no texture
  299. unsigned flags = SkVertices::kHasColors_BuilderFlag |
  300. SkVertices::kIsNonVolatile_BuilderFlag;
  301. SkVertices::Builder builder(SkVertices::kTriangleStrip_VertexMode,
  302. vertCount, indexCount, flags);
  303. memcpy(builder.positions(), pts.begin(), vertCount * sizeof(SkPoint));
  304. SkRandom rand;
  305. for (int i = 0; i < vertCount; ++i) {
  306. builder.colors()[i] = rand.nextU() | 0xFF000000;
  307. }
  308. SkDebugf("vert count = %d\n", vertCount);
  309. return builder.detach();
  310. }
  311. class PseudoInkView : public Sample {
  312. enum { N = 100 };
  313. SkPath fPath;
  314. sk_sp<SkVertices> fVertices[N];
  315. SkPaint fSkeletonP, fStrokeP, fVertsP;
  316. bool fDirty = true;
  317. public:
  318. PseudoInkView() {
  319. fSkeletonP.setStyle(SkPaint::kStroke_Style);
  320. fSkeletonP.setAntiAlias(true);
  321. fStrokeP.setStyle(SkPaint::kStroke_Style);
  322. fStrokeP.setStrokeWidth(30);
  323. fStrokeP.setColor(0x44888888);
  324. }
  325. protected:
  326. SkString name() override { return SkString("PseudoInk"); }
  327. bool onAnimate(double nanos) override { return true; }
  328. void onDrawContent(SkCanvas* canvas) override {
  329. if (fDirty) {
  330. for (int i = 0; i < N; ++i) {
  331. fVertices[i] = make_verts(fPath, 30);
  332. }
  333. fDirty = false;
  334. }
  335. for (int i = 0; i < N; ++i) {
  336. canvas->drawVertices(fVertices[i], SkBlendMode::kSrc, fVertsP);
  337. canvas->translate(1, 1);
  338. }
  339. // canvas->drawPath(fPath, fStrokeP);
  340. // canvas->drawPath(fPath, fSkeletonP);
  341. }
  342. Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey modi) override {
  343. Click* click = new Click();
  344. fPath.reset();
  345. fPath.moveTo(x, y);
  346. return click;
  347. }
  348. bool onClick(Click* click) override {
  349. switch (click->fState) {
  350. case InputState::kMove:
  351. fPath.lineTo(click->fCurr);
  352. fDirty = true;
  353. break;
  354. default:
  355. break;
  356. }
  357. return true;
  358. }
  359. private:
  360. typedef Sample INHERITED;
  361. };
  362. } // namespace
  363. DEF_SAMPLE( return new PseudoInkView(); )
  364. namespace {
  365. // Show stroking options using patheffects (and pathops)
  366. // and why strokeandfill is a hacks
  367. class ManyStrokesView : public Sample {
  368. SkPath fPath;
  369. sk_sp<SkPathEffect> fPE[6];
  370. public:
  371. ManyStrokesView() {
  372. fPE[0] = SkStrokePathEffect::Make(20, SkPaint::kRound_Join, SkPaint::kRound_Cap);
  373. auto p0 = SkStrokePathEffect::Make(25, SkPaint::kRound_Join, SkPaint::kRound_Cap);
  374. auto p1 = SkStrokePathEffect::Make(20, SkPaint::kRound_Join, SkPaint::kRound_Cap);
  375. fPE[1] = SkMergePathEffect::Make(p0, p1, SkPathOp::kDifference_SkPathOp);
  376. fPE[2] = SkMergePathEffect::Make(nullptr, p1, SkPathOp::kDifference_SkPathOp);
  377. fPE[3] = SkMergePathEffect::Make(nullptr, p1, SkPathOp::kUnion_SkPathOp);
  378. fPE[4] = SkMergePathEffect::Make(p0, nullptr, SkPathOp::kDifference_SkPathOp);
  379. fPE[5] = SkMergePathEffect::Make(p0, nullptr, SkPathOp::kIntersect_SkPathOp);
  380. }
  381. protected:
  382. SkString name() override { return SkString("ManyStrokes"); }
  383. bool onAnimate(double nanos) override { return true; }
  384. void dodraw(SkCanvas* canvas, sk_sp<SkPathEffect> pe, SkScalar x, SkScalar y,
  385. const SkPaint* ptr = nullptr) {
  386. SkPaint paint;
  387. paint.setAntiAlias(true);
  388. paint.setPathEffect(pe);
  389. canvas->save();
  390. canvas->translate(x, y);
  391. canvas->drawPath(fPath, ptr ? *ptr : paint);
  392. paint.setPathEffect(nullptr);
  393. paint.setStyle(SkPaint::kStroke_Style);
  394. paint.setColor(SK_ColorGREEN);
  395. canvas->drawPath(fPath, paint);
  396. canvas->restore();
  397. }
  398. void onDrawContent(SkCanvas* canvas) override {
  399. SkPaint p;
  400. p.setColor(0);
  401. this->dodraw(canvas, nullptr, 0, 0, &p);
  402. this->dodraw(canvas, fPE[0], 300, 0);
  403. this->dodraw(canvas, fPE[1], 0, 300);
  404. this->dodraw(canvas, fPE[2], 300, 300);
  405. this->dodraw(canvas, fPE[3], 600, 300);
  406. this->dodraw(canvas, fPE[4], 900, 0);
  407. this->dodraw(canvas, fPE[5], 900, 300);
  408. p.setColor(SK_ColorBLACK);
  409. p.setStyle(SkPaint::kStrokeAndFill_Style);
  410. p.setStrokeJoin(SkPaint::kRound_Join);
  411. p.setStrokeCap(SkPaint::kRound_Cap);
  412. p.setStrokeWidth(20);
  413. this->dodraw(canvas, nullptr, 600, 0, &p);
  414. }
  415. Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey modi) override {
  416. Click* click = new Click();
  417. fPath.reset();
  418. fPath.moveTo(x, y);
  419. return click;
  420. }
  421. bool onClick(Click* click) override {
  422. switch (click->fState) {
  423. case InputState::kMove:
  424. fPath.lineTo(click->fCurr);
  425. break;
  426. default:
  427. break;
  428. }
  429. return true;
  430. }
  431. private:
  432. typedef Sample INHERITED;
  433. };
  434. } // namespace
  435. DEF_SAMPLE( return new ManyStrokesView(); )