SampleFatBits.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. /*
  2. * Copyright 2012 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/SkBlendMode.h"
  8. #include "include/core/SkCanvas.h"
  9. #include "include/core/SkColor.h"
  10. #include "include/core/SkImageInfo.h"
  11. #include "include/core/SkMatrix.h"
  12. #include "include/core/SkPaint.h"
  13. #include "include/core/SkPath.h"
  14. #include "include/core/SkPoint.h"
  15. #include "include/core/SkRect.h"
  16. #include "include/core/SkRefCnt.h"
  17. #include "include/core/SkScalar.h"
  18. #include "include/core/SkShader.h"
  19. #include "include/core/SkString.h"
  20. #include "include/core/SkSurface.h"
  21. #include "include/core/SkTypes.h"
  22. #include "samplecode/Sample.h"
  23. #include "src/core/SkClipOpPriv.h"
  24. #include "src/core/SkPointPriv.h"
  25. #include "tools/ToolUtils.h"
  26. class SkEvent;
  27. #define FAT_PIXEL_COLOR SK_ColorBLACK
  28. #define PIXEL_CENTER_SIZE 3
  29. #define WIRE_FRAME_COLOR 0xFFFF0000 /*0xFF00FFFF*/
  30. #define WIRE_FRAME_SIZE 1.5f
  31. static SkScalar apply_grid(SkScalar x) {
  32. const SkScalar grid = 2;
  33. return SkScalarRoundToScalar(x * grid) / grid;
  34. }
  35. static void apply_grid(SkPoint pts[], int count) {
  36. for (int i = 0; i < count; ++i) {
  37. pts[i].set(apply_grid(pts[i].fX), apply_grid(pts[i].fY));
  38. }
  39. }
  40. static void erase(SkSurface* surface) {
  41. surface->getCanvas()->clear(SK_ColorTRANSPARENT);
  42. }
  43. class FatBits {
  44. public:
  45. FatBits() {
  46. fAA = false;
  47. fStyle = kHair_Style;
  48. fGrid = false;
  49. fShowSkeleton = true;
  50. fUseClip = false;
  51. fRectAsOval = false;
  52. fUseTriangle = false;
  53. fStrokeCap = SkPaint::kButt_Cap;
  54. fClipRect.set(2, 2, 11, 8 );
  55. }
  56. int getZoom() const { return fZoom; }
  57. bool getAA() const { return fAA; }
  58. void setAA(bool aa) { fAA = aa; }
  59. bool getGrid() const { return fGrid; }
  60. void setGrid(bool g) { fGrid = g; }
  61. bool getShowSkeleton() const { return fShowSkeleton; }
  62. void setShowSkeleton(bool ss) { fShowSkeleton = ss; }
  63. bool getTriangle() const { return fUseTriangle; }
  64. void setTriangle(bool ut) { fUseTriangle = ut; }
  65. void toggleRectAsOval() { fRectAsOval = !fRectAsOval; }
  66. void togglePixelColors() {
  67. if (fShader == fShader0) {
  68. fShader = fShader1;
  69. } else {
  70. fShader = fShader0;
  71. }
  72. }
  73. float fStrokeWidth = 1;
  74. bool getUseClip() const { return fUseClip; }
  75. void setUseClip(bool uc) { fUseClip = uc; }
  76. enum Style {
  77. kHair_Style,
  78. kStroke_Style,
  79. };
  80. Style getStyle() const { return fStyle; }
  81. void setStyle(Style s) { fStyle = s; }
  82. void setWHZ(int width, int height, int zoom) {
  83. fW = width;
  84. fH = height;
  85. fZoom = zoom;
  86. fBounds.set(0, 0, SkIntToScalar(width * zoom), SkIntToScalar(height * zoom));
  87. fMatrix.setScale(SkIntToScalar(zoom), SkIntToScalar(zoom));
  88. fInverse.setScale(SK_Scalar1 / zoom, SK_Scalar1 / zoom);
  89. fShader0 = ToolUtils::create_checkerboard_shader(0xFFDDDDDD, 0xFFFFFFFF, zoom);
  90. fShader1 = SkShaders::Color(SK_ColorWHITE);
  91. fShader = fShader0;
  92. SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
  93. fMinSurface = SkSurface::MakeRaster(info);
  94. info = info.makeWH(width * zoom, height * zoom);
  95. fMaxSurface = SkSurface::MakeRaster(info);
  96. }
  97. void drawBG(SkCanvas*);
  98. void drawFG(SkCanvas*);
  99. void drawLine(SkCanvas*, SkPoint pts[2]);
  100. void drawRect(SkCanvas* canvas, SkPoint pts[2]);
  101. void drawTriangle(SkCanvas* canvas, SkPoint pts[3]);
  102. SkPaint::Cap fStrokeCap;
  103. private:
  104. bool fAA, fGrid, fShowSkeleton, fUseClip, fRectAsOval, fUseTriangle;
  105. Style fStyle;
  106. int fW, fH, fZoom;
  107. SkMatrix fMatrix, fInverse;
  108. SkRect fBounds, fClipRect;
  109. sk_sp<SkShader> fShader0;
  110. sk_sp<SkShader> fShader1;
  111. sk_sp<SkShader> fShader;
  112. sk_sp<SkSurface> fMinSurface;
  113. sk_sp<SkSurface> fMaxSurface;
  114. void setupPaint(SkPaint* paint) {
  115. bool aa = this->getAA();
  116. paint->setStrokeCap(fStrokeCap);
  117. switch (fStyle) {
  118. case kHair_Style:
  119. paint->setStrokeWidth(0);
  120. break;
  121. case kStroke_Style:
  122. paint->setStrokeWidth(fStrokeWidth);
  123. break;
  124. }
  125. paint->setAntiAlias(aa);
  126. }
  127. void setupSkeletonPaint(SkPaint* paint) {
  128. paint->setStyle(SkPaint::kStroke_Style);
  129. paint->setStrokeWidth(WIRE_FRAME_SIZE);
  130. paint->setColor(fShowSkeleton ? WIRE_FRAME_COLOR : 0);
  131. paint->setAntiAlias(true);
  132. }
  133. void drawTriangleSkeleton(SkCanvas* max, const SkPoint pts[]);
  134. void drawLineSkeleton(SkCanvas* max, const SkPoint pts[]);
  135. void drawRectSkeleton(SkCanvas* max, const SkRect& r) {
  136. SkPaint paint;
  137. this->setupSkeletonPaint(&paint);
  138. SkPath path;
  139. fRectAsOval ? path.addOval(r) : path.addRect(r);
  140. max->drawPath(path, paint);
  141. }
  142. void copyMinToMax() {
  143. erase(fMaxSurface.get());
  144. SkCanvas* canvas = fMaxSurface->getCanvas();
  145. canvas->save();
  146. canvas->concat(fMatrix);
  147. fMinSurface->draw(canvas, 0, 0, nullptr);
  148. canvas->restore();
  149. SkPaint paint;
  150. paint.setBlendMode(SkBlendMode::kClear);
  151. for (int iy = 1; iy < fH; ++iy) {
  152. SkScalar y = SkIntToScalar(iy * fZoom);
  153. canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint);
  154. }
  155. for (int ix = 1; ix < fW; ++ix) {
  156. SkScalar x = SkIntToScalar(ix * fZoom);
  157. canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint);
  158. }
  159. }
  160. };
  161. void FatBits::drawBG(SkCanvas* canvas) {
  162. SkPaint paint;
  163. paint.setShader(fShader);
  164. canvas->drawRect(fBounds, paint);
  165. paint.setShader(nullptr);
  166. }
  167. void FatBits::drawFG(SkCanvas* canvas) {
  168. SkPaint inner, outer;
  169. inner.setAntiAlias(true);
  170. inner.setColor(SK_ColorBLACK);
  171. inner.setStrokeWidth(PIXEL_CENTER_SIZE);
  172. outer.setAntiAlias(true);
  173. outer.setColor(SK_ColorWHITE);
  174. outer.setStrokeWidth(PIXEL_CENTER_SIZE + 2);
  175. SkScalar half = SkIntToScalar(fZoom) / 2;
  176. for (int iy = 0; iy < fH; ++iy) {
  177. SkScalar y = SkIntToScalar(iy * fZoom) + half;
  178. for (int ix = 0; ix < fW; ++ix) {
  179. SkScalar x = SkIntToScalar(ix * fZoom) + half;
  180. canvas->drawPoint(x, y, outer);
  181. canvas->drawPoint(x, y, inner);
  182. }
  183. }
  184. if (fUseClip) {
  185. SkPaint p;
  186. p.setStyle(SkPaint::kStroke_Style);
  187. p.setColor(SK_ColorLTGRAY);
  188. SkRect r = {
  189. fClipRect.fLeft * fZoom,
  190. fClipRect.fTop * fZoom,
  191. fClipRect.fRight * fZoom,
  192. fClipRect.fBottom * fZoom
  193. };
  194. canvas->drawRect(r, p);
  195. }
  196. }
  197. void FatBits::drawLineSkeleton(SkCanvas* max, const SkPoint pts[]) {
  198. SkPaint paint;
  199. this->setupSkeletonPaint(&paint);
  200. SkPath path;
  201. path.moveTo(pts[0]);
  202. path.lineTo(pts[1]);
  203. if (fStyle == kStroke_Style) {
  204. SkPaint p;
  205. p.setStyle(SkPaint::kStroke_Style);
  206. p.setStrokeWidth(fStrokeWidth * fZoom);
  207. p.setStrokeCap(fStrokeCap);
  208. SkPath dst;
  209. p.getFillPath(path, &dst);
  210. path = dst;
  211. path.moveTo(pts[0]);
  212. path.lineTo(pts[1]);
  213. }
  214. max->drawPath(path, paint);
  215. }
  216. void FatBits::drawLine(SkCanvas* canvas, SkPoint pts[]) {
  217. SkPaint paint;
  218. fInverse.mapPoints(pts, 2);
  219. if (fGrid) {
  220. apply_grid(pts, 2);
  221. }
  222. erase(fMinSurface.get());
  223. this->setupPaint(&paint);
  224. paint.setColor(FAT_PIXEL_COLOR);
  225. if (fUseClip) {
  226. fMinSurface->getCanvas()->save();
  227. SkRect r = fClipRect;
  228. r.inset(SK_Scalar1/3, SK_Scalar1/3);
  229. fMinSurface->getCanvas()->clipRect(r, kIntersect_SkClipOp, true);
  230. }
  231. fMinSurface->getCanvas()->drawLine(pts[0], pts[1], paint);
  232. if (fUseClip) {
  233. fMinSurface->getCanvas()->restore();
  234. }
  235. this->copyMinToMax();
  236. SkCanvas* max = fMaxSurface->getCanvas();
  237. fMatrix.mapPoints(pts, 2);
  238. this->drawLineSkeleton(max, pts);
  239. fMaxSurface->draw(canvas, 0, 0, nullptr);
  240. }
  241. void FatBits::drawRect(SkCanvas* canvas, SkPoint pts[2]) {
  242. SkPaint paint;
  243. fInverse.mapPoints(pts, 2);
  244. if (fGrid) {
  245. apply_grid(pts, 2);
  246. }
  247. SkRect r;
  248. r.set(pts, 2);
  249. erase(fMinSurface.get());
  250. this->setupPaint(&paint);
  251. paint.setColor(FAT_PIXEL_COLOR);
  252. {
  253. SkCanvas* c = fMinSurface->getCanvas();
  254. fRectAsOval ? c->drawOval(r, paint) : c->drawRect(r, paint);
  255. }
  256. this->copyMinToMax();
  257. SkCanvas* max = fMaxSurface->getCanvas();
  258. fMatrix.mapPoints(pts, 2);
  259. r.set(pts, 2);
  260. this->drawRectSkeleton(max, r);
  261. fMaxSurface->draw(canvas, 0, 0, nullptr);
  262. }
  263. void FatBits::drawTriangleSkeleton(SkCanvas* max, const SkPoint pts[]) {
  264. SkPaint paint;
  265. this->setupSkeletonPaint(&paint);
  266. SkPath path;
  267. path.moveTo(pts[0]);
  268. path.lineTo(pts[1]);
  269. path.lineTo(pts[2]);
  270. path.close();
  271. max->drawPath(path, paint);
  272. }
  273. void FatBits::drawTriangle(SkCanvas* canvas, SkPoint pts[3]) {
  274. SkPaint paint;
  275. fInverse.mapPoints(pts, 3);
  276. if (fGrid) {
  277. apply_grid(pts, 3);
  278. }
  279. SkPath path;
  280. path.moveTo(pts[0]);
  281. path.lineTo(pts[1]);
  282. path.lineTo(pts[2]);
  283. path.close();
  284. erase(fMinSurface.get());
  285. this->setupPaint(&paint);
  286. paint.setColor(FAT_PIXEL_COLOR);
  287. fMinSurface->getCanvas()->drawPath(path, paint);
  288. this->copyMinToMax();
  289. SkCanvas* max = fMaxSurface->getCanvas();
  290. fMatrix.mapPoints(pts, 3);
  291. this->drawTriangleSkeleton(max, pts);
  292. fMaxSurface->draw(canvas, 0, 0, nullptr);
  293. }
  294. ///////////////////////////////////////////////////////////////////////////////////////////////////
  295. class IndexClick : public Sample::Click {
  296. int fIndex;
  297. public:
  298. IndexClick(int index) : fIndex(index) {}
  299. static int GetIndex(Sample::Click* click) {
  300. return ((IndexClick*)click)->fIndex;
  301. }
  302. };
  303. class DrawLineView : public Sample {
  304. FatBits fFB;
  305. SkPoint fPts[3];
  306. bool fIsRect;
  307. int fZoom = 64;
  308. public:
  309. DrawLineView() {
  310. fFB.setWHZ(24*2, 16*2, fZoom);
  311. fPts[0].set(1, 1);
  312. fPts[1].set(5, 4);
  313. fPts[2].set(2, 6);
  314. SkMatrix::MakeScale(SkIntToScalar(fZoom)).mapPoints(fPts, 3);
  315. fIsRect = false;
  316. }
  317. void setStyle(FatBits::Style s) {
  318. fFB.setStyle(s);
  319. }
  320. protected:
  321. SkString name() override { return SkString("FatBits"); }
  322. bool onChar(SkUnichar uni) override {
  323. switch (uni) {
  324. case 'c':
  325. fFB.setUseClip(!fFB.getUseClip());
  326. return true;
  327. case 'r':
  328. fIsRect = !fIsRect;
  329. return true;
  330. case 'o':
  331. fFB.toggleRectAsOval();
  332. return true;
  333. case 'x':
  334. fFB.setGrid(!fFB.getGrid());
  335. return true;
  336. case 's':
  337. if (FatBits::kStroke_Style == fFB.getStyle()) {
  338. this->setStyle(FatBits::kHair_Style);
  339. } else {
  340. this->setStyle(FatBits::kStroke_Style);
  341. }
  342. return true;
  343. case 'k': {
  344. const SkPaint::Cap caps[] = {
  345. SkPaint::kButt_Cap, SkPaint::kRound_Cap, SkPaint::kSquare_Cap,
  346. };
  347. fFB.fStrokeCap = caps[(fFB.fStrokeCap + 1) % 3];
  348. return true;
  349. } break;
  350. case 'a':
  351. fFB.setAA(!fFB.getAA());
  352. return true;
  353. case 'w':
  354. fFB.setShowSkeleton(!fFB.getShowSkeleton());
  355. return true;
  356. case 'g':
  357. fFB.togglePixelColors();
  358. return true;
  359. case 't':
  360. fFB.setTriangle(!fFB.getTriangle());
  361. return true;
  362. case '-':
  363. fFB.fStrokeWidth -= 0.125f;
  364. return true;
  365. case '=':
  366. fFB.fStrokeWidth += 0.125f;
  367. return true;
  368. }
  369. return false;
  370. }
  371. void onDrawContent(SkCanvas* canvas) override {
  372. fFB.drawBG(canvas);
  373. if (fFB.getTriangle()) {
  374. fFB.drawTriangle(canvas, fPts);
  375. }
  376. else if (fIsRect) {
  377. fFB.drawRect(canvas, fPts);
  378. } else {
  379. fFB.drawLine(canvas, fPts);
  380. }
  381. fFB.drawFG(canvas);
  382. {
  383. SkString str;
  384. str.printf("%s %s %s",
  385. fFB.getAA() ? "AA" : "BW",
  386. FatBits::kHair_Style == fFB.getStyle() ? "Hair" : "Stroke",
  387. fFB.getUseClip() ? "clip" : "noclip");
  388. SkPaint paint;
  389. paint.setColor(SK_ColorBLUE);
  390. SkFont font(nullptr, 16);
  391. canvas->drawString(str, 10, 16, font, paint);
  392. }
  393. }
  394. Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey modi) override {
  395. SkPoint pt = { x, y };
  396. int index = -1;
  397. int count = fFB.getTriangle() ? 3 : 2;
  398. SkScalar tol = 12;
  399. for (int i = 0; i < count; ++i) {
  400. if (SkPointPriv::EqualsWithinTolerance(fPts[i], pt, tol)) {
  401. index = i;
  402. break;
  403. }
  404. }
  405. return new IndexClick(index);
  406. }
  407. bool onClick(Click* click) override {
  408. int index = IndexClick::GetIndex(click);
  409. if (index >= 0 && index <= 2) {
  410. fPts[index] = click->fCurr;
  411. } else {
  412. SkScalar dx = click->fCurr.fX - click->fPrev.fX;
  413. SkScalar dy = click->fCurr.fY - click->fPrev.fY;
  414. fPts[0].offset(dx, dy);
  415. fPts[1].offset(dx, dy);
  416. fPts[2].offset(dx, dy);
  417. }
  418. return true;
  419. }
  420. private:
  421. typedef Sample INHERITED;
  422. };
  423. //////////////////////////////////////////////////////////////////////////////
  424. DEF_SAMPLE( return new DrawLineView(); )