blob: bf4ef0dbed6683131784beb76e0acce3bbb5108e [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.com7d970c72010-04-22 16:07:49 +0000330// SkImageDecoder::DecodeFile("/skimages/marker.png", &bm);
reed@android.com2736a692010-01-28 21:24:01 +0000331 SkImageDecoder::DecodeFile("/skimages/logo.gif", &bm);
reed@android.com2ee7c642009-10-28 14:25:34 +0000332 // SkImageDecoder::DecodeFile("/beach_shot.JPG", &bm);
reed@android.com4408cca2009-10-27 02:24:03 +0000333 fBitmap = bm;
reed@android.comd2abab62009-10-20 21:27:15 +0000334
335 SkRect bounds, texture;
336 texture.set(0, 0, SkIntToScalar(fBitmap.width()),
337 SkIntToScalar(fBitmap.height()));
338 bounds = texture;
339
340// fMesh.init(bounds, fBitmap.width() / 40, fBitmap.height() / 40, texture);
reed@android.com2736a692010-01-28 21:24:01 +0000341 fMesh.init(bounds, fBitmap.width()/16, fBitmap.height()/16, texture);
reed@android.comd2abab62009-10-20 21:27:15 +0000342 fOrig = fMesh;
reed@android.com2ee7c642009-10-28 14:25:34 +0000343
344 fP0.set(0, 0);
345 fP1 = fP0;
reed@android.com2736a692010-01-28 21:24:01 +0000346
347 fMatrix.setScale(2, 2);
348 fMatrix.invert(&fInverse);
reed@android.comd2abab62009-10-20 21:27:15 +0000349 }
350
351protected:
352 // overrides from SkEventSink
353 virtual bool onQuery(SkEvent* evt) {
354 if (SampleCode::TitleQ(*evt)) {
355 SampleCode::TitleR(evt, "Warp");
356 return true;
357 }
358 return this->INHERITED::onQuery(evt);
359 }
360
reed@android.com2736a692010-01-28 21:24:01 +0000361 static SkPoint apply_warp(const SkVector& drag, SkScalar dragLength,
362 const SkPoint& dragStart, const SkPoint& dragCurr,
363 const SkPoint& orig) {
364 SkVector delta = orig - dragCurr;
365 SkScalar length = SkPoint::Normalize(&delta);
366 if (length <= kNearlyZero) {
367 return orig;
368 }
369
370 const SkScalar period = 20;
371 const SkScalar mag = dragLength / 3;
372
373 SkScalar d = length / (period);
374 d = mag * SkScalarSin(d) / d;
375 SkScalar dx = delta.fX * d;
376 SkScalar dy = delta.fY * d;
377 SkScalar px = orig.fX + dx;
378 SkScalar py = orig.fY + dy;
379 return SkPoint::Make(px, py);
380 }
381
382 static SkPoint apply_warp2(const SkVector& drag, SkScalar dragLength,
383 const SkPoint& dragStart, const SkPoint& dragCurr,
384 const SkPoint& orig) {
385 SkVector delta = orig - dragCurr;
386 SkScalar length = SkPoint::Normalize(&delta);
387 if (length <= kNearlyZero) {
388 return orig;
389 }
390
reed@android.com7d970c72010-04-22 16:07:49 +0000391 const SkScalar period = 10 + dragLength/4;
reed@android.com2736a692010-01-28 21:24:01 +0000392 const SkScalar mag = dragLength / 3;
393
394 SkScalar d = length / (period);
395 if (d > SK_ScalarPI) {
396 d = SK_ScalarPI;
397 }
398
399 d = -mag * SkScalarSin(d);
400
401 SkScalar dx = delta.fX * d;
402 SkScalar dy = delta.fY * d;
403 SkScalar px = orig.fX + dx;
404 SkScalar py = orig.fY + dy;
405 return SkPoint::Make(px, py);
406 }
407
408 typedef SkPoint (*WarpProc)(const SkVector& drag, SkScalar dragLength,
409 const SkPoint& dragStart, const SkPoint& dragCurr,
410 const SkPoint& orig);
411
reed@android.comd2abab62009-10-20 21:27:15 +0000412 void warp(const SkPoint& p0, const SkPoint& p1) {
reed@android.com2736a692010-01-28 21:24:01 +0000413 WarpProc proc = apply_warp2;
414 SkPoint delta = p1 - p0;
415 SkScalar length = SkPoint::Normalize(&delta);
416 for (int y = 0; y < fMesh.rows(); y++) {
417 for (int x = 0; x < fMesh.cols(); x++) {
418 fMesh.pt(x, y) = proc(delta, length, p0, p1, fOrig.pt(x, y));
419 }
420 }
reed@android.com2ee7c642009-10-28 14:25:34 +0000421 fP0 = p0;
422 fP1 = p1;
reed@android.comd2abab62009-10-20 21:27:15 +0000423 }
424
425 virtual void onDraw(SkCanvas* canvas) {
reed@android.com3f2025f2009-10-29 17:37:56 +0000426 canvas->drawColor(SK_ColorLTGRAY);
427 // test_bigblur(canvas); return;
reed@android.comd2abab62009-10-20 21:27:15 +0000428
reed@android.com2736a692010-01-28 21:24:01 +0000429 canvas->concat(fMatrix);
430
reed@android.comd2abab62009-10-20 21:27:15 +0000431 SkPaint paint;
432 paint.setFilterBitmap(true);
433 paint.setShader(SkShader::CreateBitmapShader(fBitmap,
434 SkShader::kClamp_TileMode,
435 SkShader::kClamp_TileMode))->unref();
reed@android.com2736a692010-01-28 21:24:01 +0000436 fMesh.draw(canvas, paint); //return;
reed@android.comd2abab62009-10-20 21:27:15 +0000437
438 paint.setShader(NULL);
439 paint.setColor(SK_ColorRED);
reed@android.com2736a692010-01-28 21:24:01 +0000440 fMesh.draw(canvas, paint);
reed@android.com2ee7c642009-10-28 14:25:34 +0000441
reed@android.com2736a692010-01-28 21:24:01 +0000442 // test_drag(canvas, fBitmap, fP0, fP1);
reed@android.comd2abab62009-10-20 21:27:15 +0000443 }
444
445 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
446 return new Click(this);
447 }
448
449 virtual bool onClick(Click* click) {
reed@android.com2736a692010-01-28 21:24:01 +0000450 SkPoint pts[2] = { click->fOrig, click->fCurr };
451 fInverse.mapPoints(pts, 2);
452 this->warp(pts[0], pts[1]);
reed@android.comd2abab62009-10-20 21:27:15 +0000453 this->inval(NULL);
454 return true;
455 }
456
457private:
458 SkIRect fBase, fRect;
reed@android.com2ee7c642009-10-28 14:25:34 +0000459 SkPoint fP0, fP1;
reed@android.comd2abab62009-10-20 21:27:15 +0000460 typedef SkView INHERITED;
461};
462
463//////////////////////////////////////////////////////////////////////////////
464
465static SkView* MyFactory() { return new WarpView; }
466static SkViewRegister reg(MyFactory);
467