PerlinPatch.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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. #include "include/core/SkCanvas.h"
  8. #include "include/effects/SkGradientShader.h"
  9. #include "include/effects/SkPerlinNoiseShader.h"
  10. #include "samplecode/Sample.h"
  11. #include "src/utils/SkPatchUtils.h"
  12. #include "tools/ModifierKey.h"
  13. static void draw_control_points(SkCanvas* canvas, const SkPoint cubics[12]) {
  14. //draw control points
  15. SkPaint paint;
  16. SkPoint bottom[SkPatchUtils::kNumPtsCubic];
  17. SkPatchUtils::GetBottomCubic(cubics, bottom);
  18. SkPoint top[SkPatchUtils::kNumPtsCubic];
  19. SkPatchUtils::GetTopCubic(cubics, top);
  20. SkPoint left[SkPatchUtils::kNumPtsCubic];
  21. SkPatchUtils::GetLeftCubic(cubics, left);
  22. SkPoint right[SkPatchUtils::kNumPtsCubic];
  23. SkPatchUtils::GetRightCubic(cubics, right);
  24. paint.setColor(SK_ColorBLACK);
  25. paint.setStrokeWidth(0.5f);
  26. SkPoint corners[4] = { bottom[0], bottom[3], top[0], top[3] };
  27. canvas->drawPoints(SkCanvas::kLines_PointMode, 4, bottom, paint);
  28. canvas->drawPoints(SkCanvas::kLines_PointMode, 2, bottom + 1, paint);
  29. canvas->drawPoints(SkCanvas::kLines_PointMode, 4, top, paint);
  30. canvas->drawPoints(SkCanvas::kLines_PointMode, 4, left, paint);
  31. canvas->drawPoints(SkCanvas::kLines_PointMode, 4, right, paint);
  32. canvas->drawPoints(SkCanvas::kLines_PointMode, 2, top + 1, paint);
  33. canvas->drawPoints(SkCanvas::kLines_PointMode, 2, left + 1, paint);
  34. canvas->drawPoints(SkCanvas::kLines_PointMode, 2, right + 1, paint);
  35. paint.setStrokeWidth(2);
  36. paint.setColor(SK_ColorRED);
  37. canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, corners, paint);
  38. paint.setColor(SK_ColorBLUE);
  39. canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, bottom + 1, paint);
  40. paint.setColor(SK_ColorCYAN);
  41. canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, top + 1, paint);
  42. paint.setColor(SK_ColorYELLOW);
  43. canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, left + 1, paint);
  44. paint.setColor(SK_ColorGREEN);
  45. canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, right + 1, paint);
  46. }
  47. // These are actually half the total width and hieghts
  48. const SkScalar TexWidth = 100.0f;
  49. const SkScalar TexHeight = 100.0f;
  50. class PerlinPatchView : public Sample {
  51. sk_sp<SkShader> fShader0;
  52. sk_sp<SkShader> fShader1;
  53. sk_sp<SkShader> fShaderCompose;
  54. SkScalar fXFreq;
  55. SkScalar fYFreq;
  56. SkScalar fSeed;
  57. SkPoint fPts[SkPatchUtils::kNumCtrlPts];
  58. SkScalar fTexX;
  59. SkScalar fTexY;
  60. SkScalar fTexScale;
  61. SkMatrix fInvMatrix;
  62. bool fShowGrid = false;
  63. public:
  64. PerlinPatchView() : fXFreq(0.025f), fYFreq(0.025f), fSeed(0.0f),
  65. fTexX(100.0), fTexY(50.0), fTexScale(1.0f) {
  66. const SkScalar s = 2;
  67. // The order of the colors and points is clockwise starting at upper-left corner.
  68. //top points
  69. fPts[0].set(100 * s, 100 * s);
  70. fPts[1].set(150 * s, 50 * s);
  71. fPts[2].set(250 * s, 150 * s);
  72. fPts[3].set(300 * s, 100 * s);
  73. //right points
  74. fPts[4].set(275 * s, 150 * s);
  75. fPts[5].set(350 * s, 250 * s);
  76. //bottom points
  77. fPts[6].set(300 * s, 300 * s);
  78. fPts[7].set(250 * s, 250 * s);
  79. //left points
  80. fPts[8].set(150 * s, 350 * s);
  81. fPts[9].set(100 * s, 300 * s);
  82. fPts[10].set(50 * s, 250 * s);
  83. fPts[11].set(150 * s, 150 * s);
  84. const SkColor colors[SkPatchUtils::kNumCorners] = {
  85. 0xFF5555FF, 0xFF8888FF, 0xFFCCCCFF
  86. };
  87. const SkPoint points[2] = { SkPoint::Make(0.0f, 0.0f),
  88. SkPoint::Make(100.0f, 100.0f) };
  89. fShader0 = SkGradientShader::MakeLinear(points,
  90. colors,
  91. nullptr,
  92. 3,
  93. SkTileMode::kMirror,
  94. 0,
  95. nullptr);
  96. }
  97. protected:
  98. SkString name() override { return SkString("PerlinPatch"); }
  99. bool onChar(SkUnichar uni) override {
  100. switch (uni) {
  101. case 'g': fShowGrid = !fShowGrid; return true;
  102. default: break;
  103. }
  104. return false;
  105. }
  106. bool onAnimate(double nanos) override {
  107. fSeed += 0.005f;
  108. return true;
  109. }
  110. void onDrawContent(SkCanvas* canvas) override {
  111. if (!canvas->getTotalMatrix().invert(&fInvMatrix)) {
  112. return;
  113. }
  114. SkPaint paint;
  115. SkScalar texWidth = fTexScale * TexWidth;
  116. SkScalar texHeight = fTexScale * TexHeight;
  117. const SkPoint texCoords[SkPatchUtils::kNumCorners] = {
  118. { fTexX - texWidth, fTexY - texHeight},
  119. { fTexX + texWidth, fTexY - texHeight},
  120. { fTexX + texWidth, fTexY + texHeight},
  121. { fTexX - texWidth, fTexY + texHeight}}
  122. ;
  123. SkScalar scaleFreq = 2.0;
  124. fShader1 = SkPerlinNoiseShader::MakeImprovedNoise(fXFreq/scaleFreq, fYFreq/scaleFreq, 4,
  125. fSeed);
  126. fShaderCompose = SkShaders::Blend(SkBlendMode::kSrcOver, fShader0, fShader1);
  127. paint.setShader(fShaderCompose);
  128. const SkPoint* tex = texCoords;
  129. if (fShowGrid) {
  130. tex = nullptr;
  131. }
  132. canvas->drawPatch(fPts, nullptr, tex, SkBlendMode::kSrc, paint);
  133. draw_control_points(canvas, fPts);
  134. }
  135. class PtClick : public Click {
  136. public:
  137. int fIndex;
  138. PtClick(int index) : fIndex(index) {}
  139. };
  140. static bool hittest(const SkPoint& pt, SkScalar x, SkScalar y) {
  141. return SkPoint::Length(pt.fX - x, pt.fY - y) < SkIntToScalar(5);
  142. }
  143. Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey modi) override {
  144. if (ModifierKey::kShift == modi) {
  145. return new PtClick(-1);
  146. }
  147. if (ModifierKey::kControl == modi) {
  148. return new PtClick(-2);
  149. }
  150. SkPoint clickPoint = {x, y};
  151. fInvMatrix.mapPoints(&clickPoint, 1);
  152. for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); i++) {
  153. if (hittest(fPts[i], clickPoint.fX, clickPoint.fY)) {
  154. return new PtClick((int)i);
  155. }
  156. }
  157. return nullptr;
  158. }
  159. bool onClick(Click* click) override {
  160. PtClick* ptClick = (PtClick*)click;
  161. if (ptClick->fIndex >= 0) {
  162. fPts[ptClick->fIndex].set(click->fCurr.fX , click->fCurr.fY );
  163. } else if (-1 == ptClick->fIndex) {
  164. SkScalar xDiff = click->fPrev.fX - click->fCurr.fX;
  165. SkScalar yDiff = click->fPrev.fY - click->fCurr.fY;
  166. fTexX += xDiff * fTexScale;
  167. fTexY += yDiff * fTexScale;
  168. } else if (-2 == ptClick->fIndex) {
  169. SkScalar yDiff = click->fCurr.fY - click->fPrev.fY;
  170. fTexScale += yDiff / 10.0f;
  171. fTexScale = SkTMax(0.1f, SkTMin(20.f, fTexScale));
  172. }
  173. return true;
  174. }
  175. private:
  176. typedef Sample INHERITED;
  177. };
  178. DEF_SAMPLE( return new PerlinPatchView(); )