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