1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SampleCode.h"
9#include "SkView.h"
10#include "SkCanvas.h"
11#include "SkGradientShader.h"
12#include "SkPath.h"
13#include "SkRegion.h"
14#include "SkShader.h"
15#include "SkUtils.h"
16#include "SkImageDecoder.h"
17
18#include "SkBlurMaskFilter.h"
19#include "SkTableMaskFilter.h"
20
21#define kNearlyZero     (SK_Scalar1 / 8092)
22
23static void test_bigblur(SkCanvas* canvas) {
24    canvas->drawColor(SK_ColorBLACK);
25
26    SkBitmap orig, mask;
27    SkImageDecoder::DecodeFile("/skimages/app_icon.png", &orig);
28
29    SkMaskFilter* mf = SkBlurMaskFilter::Create(8, SkBlurMaskFilter::kNormal_BlurStyle);
30    SkPaint paint;
31    paint.setMaskFilter(mf)->unref();
32    SkIPoint offset;
33    orig.extractAlpha(&mask, &paint, &offset);
34
35    paint.setColor(0xFFBB8800);
36    paint.setColor(SK_ColorWHITE);
37
38    int i;
39    canvas->save();
40    float gamma = 0.8;
41    for (i = 0; i < 5; i++) {
42        paint.setMaskFilter(SkTableMaskFilter::CreateGamma(gamma))->unref();
43        canvas->drawBitmap(mask, 0, 0, &paint);
44        paint.setMaskFilter(NULL);
45        canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
46        gamma -= 0.1;
47        canvas->translate(120, 0);
48    }
49    canvas->restore();
50    canvas->translate(0, 160);
51
52    for (i = 0; i < 5; i++) {
53        paint.setMaskFilter(SkTableMaskFilter::CreateClip(i*30, 255 - 20))->unref();
54        canvas->drawBitmap(mask, 0, 0, &paint);
55        paint.setMaskFilter(NULL);
56        canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
57        canvas->translate(120, 0);
58    }
59
60#if 0
61    paint.setColor(0xFFFFFFFF);
62    canvas->drawBitmap(mask, 0, 0, &paint);
63    paint.setMaskFilter(NULL);
64    canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
65
66    canvas->translate(120, 0);
67
68    canvas->drawBitmap(mask, 0, 0, &paint);
69    canvas->drawBitmap(mask, 0, 0, &paint);
70    canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
71
72    canvas->translate(120, 0);
73
74    canvas->drawBitmap(mask, 0, 0, &paint);
75    canvas->drawBitmap(mask, 0, 0, &paint);
76    canvas->drawBitmap(mask, 0, 0, &paint);
77    canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
78
79    canvas->translate(120, 0);
80
81    canvas->drawBitmap(mask, 0, 0, &paint);
82    canvas->drawBitmap(mask, 0, 0, &paint);
83    canvas->drawBitmap(mask, 0, 0, &paint);
84    canvas->drawBitmap(mask, 0, 0, &paint);
85    canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
86
87    canvas->translate(120, 0);
88
89    canvas->drawBitmap(mask, 0, 0, &paint);
90    canvas->drawBitmap(mask, 0, 0, &paint);
91    canvas->drawBitmap(mask, 0, 0, &paint);
92    canvas->drawBitmap(mask, 0, 0, &paint);
93    canvas->drawBitmap(mask, 0, 0, &paint);
94    canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
95#endif
96}
97
98#include "SkMeshUtils.h"
99
100static SkPoint SkMakePoint(SkScalar x, SkScalar y) {
101    SkPoint pt;
102    pt.set(x, y);
103    return pt;
104}
105
106static SkPoint SkPointInterp(const SkPoint& a, const SkPoint& b, SkScalar t) {
107    return SkMakePoint(SkScalarInterp(a.fX, b.fX, t),
108                       SkScalarInterp(a.fY, b.fY, t));
109}
110
111#include "SkBoundaryPatch.h"
112
113static void set_cubic(SkPoint pts[4], SkScalar x0, SkScalar y0,
114                      SkScalar x3, SkScalar y3, SkScalar scale = 1) {
115    SkPoint tmp, tmp2;
116
117    pts[0].set(x0, y0);
118    pts[3].set(x3, y3);
119
120    tmp = SkPointInterp(pts[0], pts[3], SK_Scalar1/3);
121    tmp2 = pts[0] - tmp;
122    tmp2.rotateCW();
123    tmp2.scale(scale);
124    pts[1] = tmp + tmp2;
125
126    tmp = SkPointInterp(pts[0], pts[3], 2*SK_Scalar1/3);
127    tmp2 = pts[3] - tmp;
128    tmp2.rotateCW();
129    tmp2.scale(scale);
130    pts[2] = tmp + tmp2;
131}
132
133static void test_patch(SkCanvas* canvas, const SkBitmap& bm, SkScalar scale) {
134    SkCubicBoundary cubic;
135    set_cubic(cubic.fPts + 0, 0, 0, 100, 0, scale);
136    set_cubic(cubic.fPts + 3, 100, 0, 100, 100, scale);
137    set_cubic(cubic.fPts + 6, 100, 100,  0, 100, -scale);
138    set_cubic(cubic.fPts + 9, 0, 100, 0, 0, 0);
139
140    SkBoundaryPatch patch;
141    patch.setBoundary(&cubic);
142
143    const int Rows = 16;
144    const int Cols = 16;
145    SkPoint pts[Rows * Cols];
146    patch.evalPatch(pts, Rows, Cols);
147
148    SkPaint paint;
149    paint.setAntiAlias(true);
150    paint.setFilterBitmap(true);
151    paint.setStrokeWidth(1);
152    paint.setStrokeCap(SkPaint::kRound_Cap);
153
154    canvas->translate(50, 50);
155    canvas->scale(3, 3);
156
157    SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint);
158}
159
160static void test_drag(SkCanvas* canvas, const SkBitmap& bm,
161                      const SkPoint& p0, const SkPoint& p1) {
162    SkCubicBoundary cubic;
163    set_cubic(cubic.fPts + 0, 0, 0, 100, 0, 0);
164    set_cubic(cubic.fPts + 3, 100, 0, 100, 100, 0);
165    set_cubic(cubic.fPts + 6, 100, 100,  0, 100, 0);
166    set_cubic(cubic.fPts + 9, 0, 100, 0, 0, 0);
167
168#if 0
169    cubic.fPts[1] += p1 - p0;
170    cubic.fPts[2] += p1 - p0;
171#else
172    SkScalar dx = p1.fX - p0.fX;
173    if (dx > 0) dx = 0;
174    SkScalar dy = p1.fY - p0.fY;
175    if (dy > 0) dy = 0;
176
177    cubic.fPts[1].fY += dy;
178    cubic.fPts[2].fY += dy;
179    cubic.fPts[10].fX += dx;
180    cubic.fPts[11].fX += dx;
181#endif
182
183    SkBoundaryPatch patch;
184    patch.setBoundary(&cubic);
185
186    const int Rows = 16;
187    const int Cols = 16;
188    SkPoint pts[Rows * Cols];
189    patch.evalPatch(pts, Rows, Cols);
190
191    SkPaint paint;
192    paint.setAntiAlias(true);
193    paint.setFilterBitmap(true);
194    paint.setStrokeWidth(1);
195    paint.setStrokeCap(SkPaint::kRound_Cap);
196
197    canvas->translate(50, 50);
198    canvas->scale(3, 3);
199
200    SkAutoCanvasRestore acr(canvas, true);
201
202    SkRect r = { 0, 0, 100, 100 };
203    canvas->clipRect(r);
204    SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint);
205}
206
207///////////////////////////////////////////////////////////////////////////////
208
209class Mesh {
210public:
211    Mesh();
212    ~Mesh();
213
214    Mesh& operator=(const Mesh& src);
215
216    void init(const SkRect& bounds, int rows, int cols,
217              const SkRect& texture);
218
219    const SkRect& bounds() const { return fBounds; }
220
221    int rows() const { return fRows; }
222    int cols() const { return fCols; }
223    SkPoint& pt(int row, int col) {
224        return fPts[row * (fRows + 1) + col];
225    }
226
227    void draw(SkCanvas*, const SkPaint&);
228    void drawWireframe(SkCanvas* canvas, const SkPaint& paint);
229
230private:
231    SkRect      fBounds;
232    int         fRows, fCols;
233    SkPoint*    fPts;
234    SkPoint*    fTex;   // just points into fPts, not separately allocated
235    int         fCount;
236    uint16_t*   fIndices;
237    int         fIndexCount;
238};
239
240Mesh::Mesh() : fPts(NULL), fCount(0), fIndices(NULL), fIndexCount(0) {}
241
242Mesh::~Mesh() {
243    delete[] fPts;
244    delete[] fIndices;
245}
246
247Mesh& Mesh::operator=(const Mesh& src) {
248    delete[] fPts;
249    delete[] fIndices;
250
251    fBounds = src.fBounds;
252    fRows = src.fRows;
253    fCols = src.fCols;
254
255    fCount = src.fCount;
256    fPts = new SkPoint[fCount * 2];
257    fTex = fPts + fCount;
258    memcpy(fPts, src.fPts, fCount * 2 * sizeof(SkPoint));
259
260    delete[] fIndices;
261    fIndexCount = src.fIndexCount;
262    fIndices = new uint16_t[fIndexCount];
263    memcpy(fIndices, src.fIndices, fIndexCount * sizeof(uint16_t));
264
265    return *this;
266}
267
268void Mesh::init(const SkRect& bounds, int rows, int cols,
269                const SkRect& texture) {
270    SkASSERT(rows > 0 && cols > 0);
271
272    fBounds = bounds;
273    fRows = rows;
274    fCols = cols;
275
276    delete[] fPts;
277    fCount = (rows + 1) * (cols + 1);
278    fPts = new SkPoint[fCount * 2];
279    fTex = fPts + fCount;
280
281    delete[] fIndices;
282    fIndexCount = rows * cols * 6;
283    fIndices = new uint16_t[fIndexCount];
284
285    SkPoint* pts = fPts;
286    const SkScalar dx = bounds.width() / rows;
287    const SkScalar dy = bounds.height() / cols;
288    SkPoint* tex = fTex;
289    const SkScalar dtx = texture.width() / rows;
290    const SkScalar dty = texture.height() / cols;
291    uint16_t* idx = fIndices;
292    int index = 0;
293    for (int y = 0; y <= cols; y++) {
294        for (int x = 0; x <= rows; x++) {
295            pts->set(bounds.fLeft + x*dx, bounds.fTop + y*dy);
296            pts += 1;
297            tex->set(texture.fLeft + x*dtx, texture.fTop + y*dty);
298            tex += 1;
299
300            if (y < cols && x < rows) {
301                *idx++ = index;
302                *idx++ = index + rows + 1;
303                *idx++ = index + 1;
304
305                *idx++ = index + 1;
306                *idx++ = index + rows + 1;
307                *idx++ = index + rows + 2;
308
309                index += 1;
310            }
311        }
312        index += 1;
313    }
314}
315
316void Mesh::draw(SkCanvas* canvas, const SkPaint& paint) {
317    canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount,
318                         fPts, fTex, NULL, NULL, fIndices, fIndexCount,
319                         paint);
320}
321
322void Mesh::drawWireframe(SkCanvas* canvas, const SkPaint& paint) {
323    canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount,
324                         fPts, NULL, NULL, NULL, fIndices, fIndexCount,
325                         paint);
326}
327
328///////////////////////////////////////////////////////////////////////////////
329
330class WarpView : public SkView {
331    Mesh        fMesh, fOrig;
332    SkBitmap    fBitmap;
333    SkMatrix    fMatrix, fInverse;
334public:
335    WarpView() {
336        SkBitmap bm;
337//        SkImageDecoder::DecodeFile("/skimages/marker.png", &bm);
338        SkImageDecoder::DecodeFile("/skimages/logo.gif", &bm);
339   //     SkImageDecoder::DecodeFile("/beach_shot.JPG", &bm);
340        fBitmap = bm;
341
342        SkRect bounds, texture;
343        texture.set(0, 0, SkIntToScalar(fBitmap.width()),
344                    SkIntToScalar(fBitmap.height()));
345        bounds = texture;
346
347//        fMesh.init(bounds, fBitmap.width() / 40, fBitmap.height() / 40, texture);
348        fMesh.init(bounds, fBitmap.width()/16, fBitmap.height()/16, texture);
349        fOrig = fMesh;
350
351        fP0.set(0, 0);
352        fP1 = fP0;
353
354        fMatrix.setScale(2, 2);
355        fMatrix.invert(&fInverse);
356    }
357
358protected:
359    // overrides from SkEventSink
360    virtual bool onQuery(SkEvent* evt) {
361        if (SampleCode::TitleQ(*evt)) {
362            SampleCode::TitleR(evt, "Warp");
363            return true;
364        }
365        return this->INHERITED::onQuery(evt);
366    }
367
368    static SkPoint apply_warp(const SkVector& drag, SkScalar dragLength,
369                              const SkPoint& dragStart, const SkPoint& dragCurr,
370                              const SkPoint& orig) {
371        SkVector delta = orig - dragCurr;
372        SkScalar length = SkPoint::Normalize(&delta);
373        if (length <= kNearlyZero) {
374            return orig;
375        }
376
377        const SkScalar period = 20;
378        const SkScalar mag = dragLength / 3;
379
380        SkScalar d = length / (period);
381        d = mag * SkScalarSin(d) / d;
382        SkScalar dx = delta.fX * d;
383        SkScalar dy = delta.fY * d;
384        SkScalar px = orig.fX + dx;
385        SkScalar py = orig.fY + dy;
386        return SkPoint::Make(px, py);
387    }
388
389    static SkPoint apply_warp2(const SkVector& drag, SkScalar dragLength,
390                              const SkPoint& dragStart, const SkPoint& dragCurr,
391                              const SkPoint& orig) {
392        SkVector delta = orig - dragCurr;
393        SkScalar length = SkPoint::Normalize(&delta);
394        if (length <= kNearlyZero) {
395            return orig;
396        }
397
398        const SkScalar period = 10 + dragLength/4;
399        const SkScalar mag = dragLength / 3;
400
401        SkScalar d = length / (period);
402        if (d > SK_ScalarPI) {
403            d = SK_ScalarPI;
404        }
405
406        d = -mag * SkScalarSin(d);
407
408        SkScalar dx = delta.fX * d;
409        SkScalar dy = delta.fY * d;
410        SkScalar px = orig.fX + dx;
411        SkScalar py = orig.fY + dy;
412        return SkPoint::Make(px, py);
413    }
414
415    typedef SkPoint (*WarpProc)(const SkVector& drag, SkScalar dragLength,
416                             const SkPoint& dragStart, const SkPoint& dragCurr,
417                             const SkPoint& orig);
418
419    void warp(const SkPoint& p0, const SkPoint& p1) {
420        WarpProc proc = apply_warp2;
421        SkPoint delta = p1 - p0;
422        SkScalar length = SkPoint::Normalize(&delta);
423        for (int y = 0; y < fMesh.rows(); y++) {
424            for (int x = 0; x < fMesh.cols(); x++) {
425                fMesh.pt(x, y) = proc(delta, length, p0, p1, fOrig.pt(x, y));
426            }
427        }
428        fP0 = p0;
429        fP1 = p1;
430    }
431
432    virtual void onDraw(SkCanvas* canvas) {
433        canvas->drawColor(SK_ColorLTGRAY);
434     //   test_bigblur(canvas); return;
435
436        canvas->concat(fMatrix);
437
438        SkPaint paint;
439        paint.setFilterBitmap(true);
440        paint.setShader(SkShader::CreateBitmapShader(fBitmap,
441                                                     SkShader::kClamp_TileMode,
442                                                     SkShader::kClamp_TileMode))->unref();
443        fMesh.draw(canvas, paint); //return;
444
445        paint.setShader(NULL);
446        paint.setColor(SK_ColorRED);
447        fMesh.draw(canvas, paint);
448
449    //    test_drag(canvas, fBitmap, fP0, fP1);
450    }
451
452    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
453        return new Click(this);
454    }
455
456    virtual bool onClick(Click* click) {
457        SkPoint pts[2] = { click->fOrig, click->fCurr };
458        fInverse.mapPoints(pts, 2);
459        this->warp(pts[0], pts[1]);
460        this->inval(NULL);
461        return true;
462    }
463
464private:
465    SkIRect    fBase, fRect;
466    SkPoint     fP0, fP1;
467    typedef SkView INHERITED;
468};
469
470//////////////////////////////////////////////////////////////////////////////
471
472static SkView* MyFactory() { return new WarpView; }
473static SkViewRegister reg(MyFactory);
474