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