blob: 606144cac6afd4e02e61563be0b884dd602819e4 [file] [log] [blame]
reed@android.comd2abab62009-10-20 21:27:15 +00001#include "SampleCode.h"
2#include "SkView.h"
3#include "SkCanvas.h"
4#include "SkGradientShader.h"
5#include "SkPath.h"
6#include "SkRegion.h"
7#include "SkShader.h"
8#include "SkUtils.h"
9#include "SkImageDecoder.h"
10
reed@android.com3f2025f2009-10-29 17:37:56 +000011#include "SkBlurMaskFilter.h"
12#include "SkTableMaskFilter.h"
13
reed@android.com2736a692010-01-28 21:24:01 +000014#define kNearlyZero (SK_Scalar1 / 8092)
15
reed@android.com3f2025f2009-10-29 17:37:56 +000016static void test_bigblur(SkCanvas* canvas) {
17 canvas->drawColor(SK_ColorBLACK);
18
19 SkBitmap orig, mask;
20 SkImageDecoder::DecodeFile("/skimages/app_icon.png", &orig);
21
22 SkMaskFilter* mf = SkBlurMaskFilter::Create(8, SkBlurMaskFilter::kNormal_BlurStyle);
23 SkPaint paint;
24 paint.setMaskFilter(mf)->unref();
25 SkIPoint offset;
26 orig.extractAlpha(&mask, &paint, &offset);
27
28 paint.setColor(0xFFBB8800);
29 paint.setColor(SK_ColorWHITE);
30
31 int i;
32 canvas->save();
33 float gamma = 0.8;
34 for (i = 0; i < 5; i++) {
35 paint.setMaskFilter(SkTableMaskFilter::CreateGamma(gamma))->unref();
36 canvas->drawBitmap(mask, 0, 0, &paint);
37 paint.setMaskFilter(NULL);
38 canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
39 gamma -= 0.1;
40 canvas->translate(120, 0);
41 }
42 canvas->restore();
43 canvas->translate(0, 160);
44
45 for (i = 0; i < 5; i++) {
46 paint.setMaskFilter(SkTableMaskFilter::CreateClip(i*30, 255 - 20))->unref();
47 canvas->drawBitmap(mask, 0, 0, &paint);
48 paint.setMaskFilter(NULL);
49 canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
50 canvas->translate(120, 0);
51 }
52
53#if 0
54 paint.setColor(0xFFFFFFFF);
55 canvas->drawBitmap(mask, 0, 0, &paint);
56 paint.setMaskFilter(NULL);
57 canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
58
59 canvas->translate(120, 0);
60
61 canvas->drawBitmap(mask, 0, 0, &paint);
62 canvas->drawBitmap(mask, 0, 0, &paint);
63 canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
64
65 canvas->translate(120, 0);
66
67 canvas->drawBitmap(mask, 0, 0, &paint);
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(mask, 0, 0, &paint);
78 canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
79
80 canvas->translate(120, 0);
81
82 canvas->drawBitmap(mask, 0, 0, &paint);
83 canvas->drawBitmap(mask, 0, 0, &paint);
84 canvas->drawBitmap(mask, 0, 0, &paint);
85 canvas->drawBitmap(mask, 0, 0, &paint);
86 canvas->drawBitmap(mask, 0, 0, &paint);
87 canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
88#endif
89}
90
reed@android.com2ee7c642009-10-28 14:25:34 +000091#include "SkMeshUtils.h"
92
reed@android.com4408cca2009-10-27 02:24:03 +000093static SkPoint SkMakePoint(SkScalar x, SkScalar y) {
94 SkPoint pt;
95 pt.set(x, y);
96 return pt;
97}
98
99static SkPoint SkPointInterp(const SkPoint& a, const SkPoint& b, SkScalar t) {
100 return SkMakePoint(SkScalarInterp(a.fX, b.fX, t),
101 SkScalarInterp(a.fY, b.fY, t));
102}
103
104#include "SkBoundaryPatch.h"
105
reed@android.com4408cca2009-10-27 02:24:03 +0000106static void set_cubic(SkPoint pts[4], SkScalar x0, SkScalar y0,
107 SkScalar x3, SkScalar y3, SkScalar scale = 1) {
108 SkPoint tmp, tmp2;
109
110 pts[0].set(x0, y0);
111 pts[3].set(x3, y3);
112
113 tmp = SkPointInterp(pts[0], pts[3], SK_Scalar1/3);
114 tmp2 = pts[0] - tmp;
115 tmp2.rotateCW();
116 tmp2.scale(scale);
117 pts[1] = tmp + tmp2;
118
119 tmp = SkPointInterp(pts[0], pts[3], 2*SK_Scalar1/3);
120 tmp2 = pts[3] - tmp;
121 tmp2.rotateCW();
122 tmp2.scale(scale);
123 pts[2] = tmp + tmp2;
124}
125
reed@android.com4408cca2009-10-27 02:24:03 +0000126static void test_patch(SkCanvas* canvas, const SkBitmap& bm, SkScalar scale) {
reed@android.com2ee7c642009-10-28 14:25:34 +0000127 SkCubicBoundary cubic;
128 set_cubic(cubic.fPts + 0, 0, 0, 100, 0, scale);
129 set_cubic(cubic.fPts + 3, 100, 0, 100, 100, scale);
130 set_cubic(cubic.fPts + 6, 100, 100, 0, 100, -scale);
131 set_cubic(cubic.fPts + 9, 0, 100, 0, 0, 0);
reed@android.com4408cca2009-10-27 02:24:03 +0000132
reed@android.com4408cca2009-10-27 02:24:03 +0000133 SkBoundaryPatch patch;
reed@android.com2ee7c642009-10-28 14:25:34 +0000134 patch.setBoundary(&cubic);
135
136 const int Rows = 16;
137 const int Cols = 16;
reed@android.com4408cca2009-10-27 02:24:03 +0000138 SkPoint pts[Rows * Cols];
reed@android.com2ee7c642009-10-28 14:25:34 +0000139 patch.evalPatch(pts, Rows, Cols);
reed@android.com4408cca2009-10-27 02:24:03 +0000140
141 SkPaint paint;
142 paint.setAntiAlias(true);
reed@android.com2ee7c642009-10-28 14:25:34 +0000143 paint.setFilterBitmap(true);
reed@android.com4408cca2009-10-27 02:24:03 +0000144 paint.setStrokeWidth(1);
145 paint.setStrokeCap(SkPaint::kRound_Cap);
reed@android.com2ee7c642009-10-28 14:25:34 +0000146
reed@android.com4408cca2009-10-27 02:24:03 +0000147 canvas->translate(50, 50);
148 canvas->scale(3, 3);
reed@android.com2ee7c642009-10-28 14:25:34 +0000149
150 SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint);
151}
reed@android.com4408cca2009-10-27 02:24:03 +0000152
reed@android.com2ee7c642009-10-28 14:25:34 +0000153static void test_drag(SkCanvas* canvas, const SkBitmap& bm,
154 const SkPoint& p0, const SkPoint& p1) {
155 SkCubicBoundary cubic;
156 set_cubic(cubic.fPts + 0, 0, 0, 100, 0, 0);
157 set_cubic(cubic.fPts + 3, 100, 0, 100, 100, 0);
158 set_cubic(cubic.fPts + 6, 100, 100, 0, 100, 0);
159 set_cubic(cubic.fPts + 9, 0, 100, 0, 0, 0);
160
161#if 0
162 cubic.fPts[1] += p1 - p0;
163 cubic.fPts[2] += p1 - p0;
164#else
165 SkScalar dx = p1.fX - p0.fX;
166 if (dx > 0) dx = 0;
167 SkScalar dy = p1.fY - p0.fY;
168 if (dy > 0) dy = 0;
169
170 cubic.fPts[1].fY += dy;
171 cubic.fPts[2].fY += dy;
172 cubic.fPts[10].fX += dx;
173 cubic.fPts[11].fX += dx;
174#endif
175
176 SkBoundaryPatch patch;
177 patch.setBoundary(&cubic);
178
179 const int Rows = 16;
180 const int Cols = 16;
181 SkPoint pts[Rows * Cols];
182 patch.evalPatch(pts, Rows, Cols);
183
184 SkPaint paint;
185 paint.setAntiAlias(true);
186 paint.setFilterBitmap(true);
187 paint.setStrokeWidth(1);
188 paint.setStrokeCap(SkPaint::kRound_Cap);
189
190 canvas->translate(50, 50);
191 canvas->scale(3, 3);
192
193 SkAutoCanvasRestore acr(canvas, true);
194
195 SkRect r = { 0, 0, 100, 100 };
196 canvas->clipRect(r);
197 SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint);
reed@android.com4408cca2009-10-27 02:24:03 +0000198}
reed@android.com80b4ebe2009-10-21 19:41:10 +0000199
200///////////////////////////////////////////////////////////////////////////////
201
reed@android.comd2abab62009-10-20 21:27:15 +0000202class Mesh {
203public:
204 Mesh();
205 ~Mesh();
206
207 Mesh& operator=(const Mesh& src);
208
209 void init(const SkRect& bounds, int rows, int cols,
210 const SkRect& texture);
211
reed@android.com80b4ebe2009-10-21 19:41:10 +0000212 const SkRect& bounds() const { return fBounds; }
213
reed@android.comd2abab62009-10-20 21:27:15 +0000214 int rows() const { return fRows; }
215 int cols() const { return fCols; }
216 SkPoint& pt(int row, int col) {
217 return fPts[row * (fRows + 1) + col];
218 }
219
220 void draw(SkCanvas*, const SkPaint&);
221 void drawWireframe(SkCanvas* canvas, const SkPaint& paint);
222
223private:
reed@android.com80b4ebe2009-10-21 19:41:10 +0000224 SkRect fBounds;
reed@android.comd2abab62009-10-20 21:27:15 +0000225 int fRows, fCols;
226 SkPoint* fPts;
227 SkPoint* fTex; // just points into fPts, not separately allocated
228 int fCount;
229 uint16_t* fIndices;
230 int fIndexCount;
231};
232
233Mesh::Mesh() : fPts(NULL), fCount(0), fIndices(NULL), fIndexCount(0) {}
234
235Mesh::~Mesh() {
236 delete[] fPts;
237 delete[] fIndices;
238}
239
240Mesh& Mesh::operator=(const Mesh& src) {
241 delete[] fPts;
242 delete[] fIndices;
243
reed@android.com80b4ebe2009-10-21 19:41:10 +0000244 fBounds = src.fBounds;
reed@android.comd2abab62009-10-20 21:27:15 +0000245 fRows = src.fRows;
246 fCols = src.fCols;
247
248 fCount = src.fCount;
249 fPts = new SkPoint[fCount * 2];
250 fTex = fPts + fCount;
251 memcpy(fPts, src.fPts, fCount * 2 * sizeof(SkPoint));
252
253 delete[] fIndices;
254 fIndexCount = src.fIndexCount;
255 fIndices = new uint16_t[fIndexCount];
256 memcpy(fIndices, src.fIndices, fIndexCount * sizeof(uint16_t));
257
258 return *this;
259}
260
261void Mesh::init(const SkRect& bounds, int rows, int cols,
262 const SkRect& texture) {
263 SkASSERT(rows > 0 && cols > 0);
264
reed@android.com80b4ebe2009-10-21 19:41:10 +0000265 fBounds = bounds;
reed@android.comd2abab62009-10-20 21:27:15 +0000266 fRows = rows;
267 fCols = cols;
268
269 delete[] fPts;
270 fCount = (rows + 1) * (cols + 1);
271 fPts = new SkPoint[fCount * 2];
272 fTex = fPts + fCount;
273
274 delete[] fIndices;
275 fIndexCount = rows * cols * 6;
276 fIndices = new uint16_t[fIndexCount];
277
278 SkPoint* pts = fPts;
279 const SkScalar dx = bounds.width() / rows;
280 const SkScalar dy = bounds.height() / cols;
281 SkPoint* tex = fTex;
282 const SkScalar dtx = texture.width() / rows;
283 const SkScalar dty = texture.height() / cols;
284 uint16_t* idx = fIndices;
285 int index = 0;
286 for (int y = 0; y <= cols; y++) {
287 for (int x = 0; x <= rows; x++) {
288 pts->set(bounds.fLeft + x*dx, bounds.fTop + y*dy);
289 pts += 1;
290 tex->set(texture.fLeft + x*dtx, texture.fTop + y*dty);
291 tex += 1;
292
293 if (y < cols && x < rows) {
294 *idx++ = index;
295 *idx++ = index + rows + 1;
296 *idx++ = index + 1;
297
298 *idx++ = index + 1;
299 *idx++ = index + rows + 1;
300 *idx++ = index + rows + 2;
301
302 index += 1;
303 }
304 }
305 index += 1;
306 }
307}
308
309void Mesh::draw(SkCanvas* canvas, const SkPaint& paint) {
310 canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount,
311 fPts, fTex, NULL, NULL, fIndices, fIndexCount,
312 paint);
313}
314
315void Mesh::drawWireframe(SkCanvas* canvas, const SkPaint& paint) {
316 canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount,
317 fPts, NULL, NULL, NULL, fIndices, fIndexCount,
318 paint);
319}
320
321///////////////////////////////////////////////////////////////////////////////
322
323class WarpView : public SkView {
324 Mesh fMesh, fOrig;
325 SkBitmap fBitmap;
reed@android.com2736a692010-01-28 21:24:01 +0000326 SkMatrix fMatrix, fInverse;
reed@android.comd2abab62009-10-20 21:27:15 +0000327public:
328 WarpView() {
329 SkBitmap bm;
reed@android.com2736a692010-01-28 21:24:01 +0000330 SkImageDecoder::DecodeFile("/skimages/logo.gif", &bm);
reed@android.com2ee7c642009-10-28 14:25:34 +0000331 // SkImageDecoder::DecodeFile("/beach_shot.JPG", &bm);
reed@android.com4408cca2009-10-27 02:24:03 +0000332 fBitmap = bm;
reed@android.comd2abab62009-10-20 21:27:15 +0000333
334 SkRect bounds, texture;
335 texture.set(0, 0, SkIntToScalar(fBitmap.width()),
336 SkIntToScalar(fBitmap.height()));
337 bounds = texture;
338
339// fMesh.init(bounds, fBitmap.width() / 40, fBitmap.height() / 40, texture);
reed@android.com2736a692010-01-28 21:24:01 +0000340 fMesh.init(bounds, fBitmap.width()/16, fBitmap.height()/16, texture);
reed@android.comd2abab62009-10-20 21:27:15 +0000341 fOrig = fMesh;
reed@android.com2ee7c642009-10-28 14:25:34 +0000342
343 fP0.set(0, 0);
344 fP1 = fP0;
reed@android.com2736a692010-01-28 21:24:01 +0000345
346 fMatrix.setScale(2, 2);
347 fMatrix.invert(&fInverse);
reed@android.comd2abab62009-10-20 21:27:15 +0000348 }
349
350protected:
351 // overrides from SkEventSink
352 virtual bool onQuery(SkEvent* evt) {
353 if (SampleCode::TitleQ(*evt)) {
354 SampleCode::TitleR(evt, "Warp");
355 return true;
356 }
357 return this->INHERITED::onQuery(evt);
358 }
359
reed@android.com2736a692010-01-28 21:24:01 +0000360 static SkPoint apply_warp(const SkVector& drag, SkScalar dragLength,
361 const SkPoint& dragStart, const SkPoint& dragCurr,
362 const SkPoint& orig) {
363 SkVector delta = orig - dragCurr;
364 SkScalar length = SkPoint::Normalize(&delta);
365 if (length <= kNearlyZero) {
366 return orig;
367 }
368
369 const SkScalar period = 20;
370 const SkScalar mag = dragLength / 3;
371
372 SkScalar d = length / (period);
373 d = mag * SkScalarSin(d) / d;
374 SkScalar dx = delta.fX * d;
375 SkScalar dy = delta.fY * d;
376 SkScalar px = orig.fX + dx;
377 SkScalar py = orig.fY + dy;
378 return SkPoint::Make(px, py);
379 }
380
381 static SkPoint apply_warp2(const SkVector& drag, SkScalar dragLength,
382 const SkPoint& dragStart, const SkPoint& dragCurr,
383 const SkPoint& orig) {
384 SkVector delta = orig - dragCurr;
385 SkScalar length = SkPoint::Normalize(&delta);
386 if (length <= kNearlyZero) {
387 return orig;
388 }
389
390 const SkScalar period = 20;
391 const SkScalar mag = dragLength / 3;
392
393 SkScalar d = length / (period);
394 if (d > SK_ScalarPI) {
395 d = SK_ScalarPI;
396 }
397
398 d = -mag * SkScalarSin(d);
399
400 SkScalar dx = delta.fX * d;
401 SkScalar dy = delta.fY * d;
402 SkScalar px = orig.fX + dx;
403 SkScalar py = orig.fY + dy;
404 return SkPoint::Make(px, py);
405 }
406
407 typedef SkPoint (*WarpProc)(const SkVector& drag, SkScalar dragLength,
408 const SkPoint& dragStart, const SkPoint& dragCurr,
409 const SkPoint& orig);
410
reed@android.comd2abab62009-10-20 21:27:15 +0000411 void warp(const SkPoint& p0, const SkPoint& p1) {
reed@android.com2736a692010-01-28 21:24:01 +0000412 WarpProc proc = apply_warp2;
413 SkPoint delta = p1 - p0;
414 SkScalar length = SkPoint::Normalize(&delta);
415 for (int y = 0; y < fMesh.rows(); y++) {
416 for (int x = 0; x < fMesh.cols(); x++) {
417 fMesh.pt(x, y) = proc(delta, length, p0, p1, fOrig.pt(x, y));
418 }
419 }
reed@android.com2ee7c642009-10-28 14:25:34 +0000420 fP0 = p0;
421 fP1 = p1;
reed@android.comd2abab62009-10-20 21:27:15 +0000422 }
423
424 virtual void onDraw(SkCanvas* canvas) {
reed@android.com3f2025f2009-10-29 17:37:56 +0000425 canvas->drawColor(SK_ColorLTGRAY);
426 // test_bigblur(canvas); return;
reed@android.comd2abab62009-10-20 21:27:15 +0000427
reed@android.com2736a692010-01-28 21:24:01 +0000428 canvas->concat(fMatrix);
429
reed@android.comd2abab62009-10-20 21:27:15 +0000430 SkPaint paint;
431 paint.setFilterBitmap(true);
432 paint.setShader(SkShader::CreateBitmapShader(fBitmap,
433 SkShader::kClamp_TileMode,
434 SkShader::kClamp_TileMode))->unref();
reed@android.com2736a692010-01-28 21:24:01 +0000435 fMesh.draw(canvas, paint); //return;
reed@android.comd2abab62009-10-20 21:27:15 +0000436
437 paint.setShader(NULL);
438 paint.setColor(SK_ColorRED);
reed@android.com2736a692010-01-28 21:24:01 +0000439 fMesh.draw(canvas, paint);
reed@android.com2ee7c642009-10-28 14:25:34 +0000440
reed@android.com2736a692010-01-28 21:24:01 +0000441 // test_drag(canvas, fBitmap, fP0, fP1);
reed@android.comd2abab62009-10-20 21:27:15 +0000442 }
443
444 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
445 return new Click(this);
446 }
447
448 virtual bool onClick(Click* click) {
reed@android.com2736a692010-01-28 21:24:01 +0000449 SkPoint pts[2] = { click->fOrig, click->fCurr };
450 fInverse.mapPoints(pts, 2);
451 this->warp(pts[0], pts[1]);
reed@android.comd2abab62009-10-20 21:27:15 +0000452 this->inval(NULL);
453 return true;
454 }
455
456private:
457 SkIRect fBase, fRect;
reed@android.com2ee7c642009-10-28 14:25:34 +0000458 SkPoint fP0, fP1;
reed@android.comd2abab62009-10-20 21:27:15 +0000459 typedef SkView INHERITED;
460};
461
462//////////////////////////////////////////////////////////////////////////////
463
464static SkView* MyFactory() { return new WarpView; }
465static SkViewRegister reg(MyFactory);
466