blob: 16c0bc82beb219e87a3d4924bb9433ba99507906 [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.com2ee7c642009-10-28 14:25:34 +000011#include "SkMeshUtils.h"
12
reed@android.com4408cca2009-10-27 02:24:03 +000013static SkPoint SkMakePoint(SkScalar x, SkScalar y) {
14 SkPoint pt;
15 pt.set(x, y);
16 return pt;
17}
18
19static SkPoint SkPointInterp(const SkPoint& a, const SkPoint& b, SkScalar t) {
20 return SkMakePoint(SkScalarInterp(a.fX, b.fX, t),
21 SkScalarInterp(a.fY, b.fY, t));
22}
23
24#include "SkBoundaryPatch.h"
25
reed@android.com4408cca2009-10-27 02:24:03 +000026static void set_cubic(SkPoint pts[4], SkScalar x0, SkScalar y0,
27 SkScalar x3, SkScalar y3, SkScalar scale = 1) {
28 SkPoint tmp, tmp2;
29
30 pts[0].set(x0, y0);
31 pts[3].set(x3, y3);
32
33 tmp = SkPointInterp(pts[0], pts[3], SK_Scalar1/3);
34 tmp2 = pts[0] - tmp;
35 tmp2.rotateCW();
36 tmp2.scale(scale);
37 pts[1] = tmp + tmp2;
38
39 tmp = SkPointInterp(pts[0], pts[3], 2*SK_Scalar1/3);
40 tmp2 = pts[3] - tmp;
41 tmp2.rotateCW();
42 tmp2.scale(scale);
43 pts[2] = tmp + tmp2;
44}
45
reed@android.com4408cca2009-10-27 02:24:03 +000046static void test_patch(SkCanvas* canvas, const SkBitmap& bm, SkScalar scale) {
reed@android.com2ee7c642009-10-28 14:25:34 +000047 SkCubicBoundary cubic;
48 set_cubic(cubic.fPts + 0, 0, 0, 100, 0, scale);
49 set_cubic(cubic.fPts + 3, 100, 0, 100, 100, scale);
50 set_cubic(cubic.fPts + 6, 100, 100, 0, 100, -scale);
51 set_cubic(cubic.fPts + 9, 0, 100, 0, 0, 0);
reed@android.com4408cca2009-10-27 02:24:03 +000052
reed@android.com4408cca2009-10-27 02:24:03 +000053 SkBoundaryPatch patch;
reed@android.com2ee7c642009-10-28 14:25:34 +000054 patch.setBoundary(&cubic);
55
56 const int Rows = 16;
57 const int Cols = 16;
reed@android.com4408cca2009-10-27 02:24:03 +000058 SkPoint pts[Rows * Cols];
reed@android.com2ee7c642009-10-28 14:25:34 +000059 patch.evalPatch(pts, Rows, Cols);
reed@android.com4408cca2009-10-27 02:24:03 +000060
61 SkPaint paint;
62 paint.setAntiAlias(true);
reed@android.com2ee7c642009-10-28 14:25:34 +000063 paint.setFilterBitmap(true);
reed@android.com4408cca2009-10-27 02:24:03 +000064 paint.setStrokeWidth(1);
65 paint.setStrokeCap(SkPaint::kRound_Cap);
reed@android.com2ee7c642009-10-28 14:25:34 +000066
reed@android.com4408cca2009-10-27 02:24:03 +000067 canvas->translate(50, 50);
68 canvas->scale(3, 3);
reed@android.com2ee7c642009-10-28 14:25:34 +000069
70 SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint);
71}
reed@android.com4408cca2009-10-27 02:24:03 +000072
reed@android.com2ee7c642009-10-28 14:25:34 +000073static void test_drag(SkCanvas* canvas, const SkBitmap& bm,
74 const SkPoint& p0, const SkPoint& p1) {
75 SkCubicBoundary cubic;
76 set_cubic(cubic.fPts + 0, 0, 0, 100, 0, 0);
77 set_cubic(cubic.fPts + 3, 100, 0, 100, 100, 0);
78 set_cubic(cubic.fPts + 6, 100, 100, 0, 100, 0);
79 set_cubic(cubic.fPts + 9, 0, 100, 0, 0, 0);
80
81#if 0
82 cubic.fPts[1] += p1 - p0;
83 cubic.fPts[2] += p1 - p0;
84#else
85 SkScalar dx = p1.fX - p0.fX;
86 if (dx > 0) dx = 0;
87 SkScalar dy = p1.fY - p0.fY;
88 if (dy > 0) dy = 0;
89
90 cubic.fPts[1].fY += dy;
91 cubic.fPts[2].fY += dy;
92 cubic.fPts[10].fX += dx;
93 cubic.fPts[11].fX += dx;
94#endif
95
96 SkBoundaryPatch patch;
97 patch.setBoundary(&cubic);
98
99 const int Rows = 16;
100 const int Cols = 16;
101 SkPoint pts[Rows * Cols];
102 patch.evalPatch(pts, Rows, Cols);
103
104 SkPaint paint;
105 paint.setAntiAlias(true);
106 paint.setFilterBitmap(true);
107 paint.setStrokeWidth(1);
108 paint.setStrokeCap(SkPaint::kRound_Cap);
109
110 canvas->translate(50, 50);
111 canvas->scale(3, 3);
112
113 SkAutoCanvasRestore acr(canvas, true);
114
115 SkRect r = { 0, 0, 100, 100 };
116 canvas->clipRect(r);
117 SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint);
reed@android.com4408cca2009-10-27 02:24:03 +0000118}
reed@android.com80b4ebe2009-10-21 19:41:10 +0000119
120///////////////////////////////////////////////////////////////////////////////
121
reed@android.comd2abab62009-10-20 21:27:15 +0000122class Mesh {
123public:
124 Mesh();
125 ~Mesh();
126
127 Mesh& operator=(const Mesh& src);
128
129 void init(const SkRect& bounds, int rows, int cols,
130 const SkRect& texture);
131
reed@android.com80b4ebe2009-10-21 19:41:10 +0000132 const SkRect& bounds() const { return fBounds; }
133
reed@android.comd2abab62009-10-20 21:27:15 +0000134 int rows() const { return fRows; }
135 int cols() const { return fCols; }
136 SkPoint& pt(int row, int col) {
137 return fPts[row * (fRows + 1) + col];
138 }
139
140 void draw(SkCanvas*, const SkPaint&);
141 void drawWireframe(SkCanvas* canvas, const SkPaint& paint);
142
143private:
reed@android.com80b4ebe2009-10-21 19:41:10 +0000144 SkRect fBounds;
reed@android.comd2abab62009-10-20 21:27:15 +0000145 int fRows, fCols;
146 SkPoint* fPts;
147 SkPoint* fTex; // just points into fPts, not separately allocated
148 int fCount;
149 uint16_t* fIndices;
150 int fIndexCount;
151};
152
153Mesh::Mesh() : fPts(NULL), fCount(0), fIndices(NULL), fIndexCount(0) {}
154
155Mesh::~Mesh() {
156 delete[] fPts;
157 delete[] fIndices;
158}
159
160Mesh& Mesh::operator=(const Mesh& src) {
161 delete[] fPts;
162 delete[] fIndices;
163
reed@android.com80b4ebe2009-10-21 19:41:10 +0000164 fBounds = src.fBounds;
reed@android.comd2abab62009-10-20 21:27:15 +0000165 fRows = src.fRows;
166 fCols = src.fCols;
167
168 fCount = src.fCount;
169 fPts = new SkPoint[fCount * 2];
170 fTex = fPts + fCount;
171 memcpy(fPts, src.fPts, fCount * 2 * sizeof(SkPoint));
172
173 delete[] fIndices;
174 fIndexCount = src.fIndexCount;
175 fIndices = new uint16_t[fIndexCount];
176 memcpy(fIndices, src.fIndices, fIndexCount * sizeof(uint16_t));
177
178 return *this;
179}
180
181void Mesh::init(const SkRect& bounds, int rows, int cols,
182 const SkRect& texture) {
183 SkASSERT(rows > 0 && cols > 0);
184
reed@android.com80b4ebe2009-10-21 19:41:10 +0000185 fBounds = bounds;
reed@android.comd2abab62009-10-20 21:27:15 +0000186 fRows = rows;
187 fCols = cols;
188
189 delete[] fPts;
190 fCount = (rows + 1) * (cols + 1);
191 fPts = new SkPoint[fCount * 2];
192 fTex = fPts + fCount;
193
194 delete[] fIndices;
195 fIndexCount = rows * cols * 6;
196 fIndices = new uint16_t[fIndexCount];
197
198 SkPoint* pts = fPts;
199 const SkScalar dx = bounds.width() / rows;
200 const SkScalar dy = bounds.height() / cols;
201 SkPoint* tex = fTex;
202 const SkScalar dtx = texture.width() / rows;
203 const SkScalar dty = texture.height() / cols;
204 uint16_t* idx = fIndices;
205 int index = 0;
206 for (int y = 0; y <= cols; y++) {
207 for (int x = 0; x <= rows; x++) {
208 pts->set(bounds.fLeft + x*dx, bounds.fTop + y*dy);
209 pts += 1;
210 tex->set(texture.fLeft + x*dtx, texture.fTop + y*dty);
211 tex += 1;
212
213 if (y < cols && x < rows) {
214 *idx++ = index;
215 *idx++ = index + rows + 1;
216 *idx++ = index + 1;
217
218 *idx++ = index + 1;
219 *idx++ = index + rows + 1;
220 *idx++ = index + rows + 2;
221
222 index += 1;
223 }
224 }
225 index += 1;
226 }
227}
228
229void Mesh::draw(SkCanvas* canvas, const SkPaint& paint) {
230 canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount,
231 fPts, fTex, NULL, NULL, fIndices, fIndexCount,
232 paint);
233}
234
235void Mesh::drawWireframe(SkCanvas* canvas, const SkPaint& paint) {
236 canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount,
237 fPts, NULL, NULL, NULL, fIndices, fIndexCount,
238 paint);
239}
240
241///////////////////////////////////////////////////////////////////////////////
242
reed@android.com4408cca2009-10-27 02:24:03 +0000243static SkScalar gScale = 0;
reed@android.com2ee7c642009-10-28 14:25:34 +0000244static SkScalar gDScale = 0.02;
reed@android.com4408cca2009-10-27 02:24:03 +0000245
reed@android.comd2abab62009-10-20 21:27:15 +0000246class WarpView : public SkView {
247 Mesh fMesh, fOrig;
248 SkBitmap fBitmap;
249public:
250 WarpView() {
251 SkBitmap bm;
reed@android.com2ee7c642009-10-28 14:25:34 +0000252 SkImageDecoder::DecodeFile("/skimages/beach.jpg", &bm);
253 // SkImageDecoder::DecodeFile("/beach_shot.JPG", &bm);
reed@android.com4408cca2009-10-27 02:24:03 +0000254 fBitmap = bm;
reed@android.comd2abab62009-10-20 21:27:15 +0000255
256 SkRect bounds, texture;
257 texture.set(0, 0, SkIntToScalar(fBitmap.width()),
258 SkIntToScalar(fBitmap.height()));
259 bounds = texture;
260
261// fMesh.init(bounds, fBitmap.width() / 40, fBitmap.height() / 40, texture);
reed@android.com80b4ebe2009-10-21 19:41:10 +0000262 fMesh.init(bounds, 30, 30, texture);
reed@android.comd2abab62009-10-20 21:27:15 +0000263 fOrig = fMesh;
reed@android.com2ee7c642009-10-28 14:25:34 +0000264
265 fP0.set(0, 0);
266 fP1 = fP0;
reed@android.comd2abab62009-10-20 21:27:15 +0000267 }
268
269protected:
270 // overrides from SkEventSink
271 virtual bool onQuery(SkEvent* evt) {
272 if (SampleCode::TitleQ(*evt)) {
273 SampleCode::TitleR(evt, "Warp");
274 return true;
275 }
276 return this->INHERITED::onQuery(evt);
277 }
278
279 void warp(const SkPoint& p0, const SkPoint& p1) {
reed@android.com2ee7c642009-10-28 14:25:34 +0000280 fP0 = p0;
281 fP1 = p1;
reed@android.comd2abab62009-10-20 21:27:15 +0000282 }
283
284 virtual void onDraw(SkCanvas* canvas) {
285 canvas->drawColor(SK_ColorGRAY);
286
287 SkPaint paint;
288 paint.setFilterBitmap(true);
289 paint.setShader(SkShader::CreateBitmapShader(fBitmap,
290 SkShader::kClamp_TileMode,
291 SkShader::kClamp_TileMode))->unref();
reed@android.com4408cca2009-10-27 02:24:03 +0000292 // fMesh.draw(canvas, paint);
reed@android.comd2abab62009-10-20 21:27:15 +0000293
294 paint.setShader(NULL);
295 paint.setColor(SK_ColorRED);
reed@android.com80b4ebe2009-10-21 19:41:10 +0000296 // fMesh.draw(canvas, paint);
reed@android.com2ee7c642009-10-28 14:25:34 +0000297
298#if 0
reed@android.com4408cca2009-10-27 02:24:03 +0000299 test_patch(canvas, fBitmap, gScale);
300 gScale += gDScale;
301 if (gScale > 2) {
302 gDScale = -gDScale;
303 } else if (gScale < -2) {
304 gDScale = -gDScale;
305 }
306 this->inval(NULL);
reed@android.com2ee7c642009-10-28 14:25:34 +0000307#else
308 test_drag(canvas, fBitmap, fP0, fP1);
309#endif
reed@android.comd2abab62009-10-20 21:27:15 +0000310 }
311
312 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
313 return new Click(this);
314 }
315
316 virtual bool onClick(Click* click) {
317 this->warp(click->fOrig, click->fCurr);
318 this->inval(NULL);
319 return true;
320 }
321
322private:
323 SkIRect fBase, fRect;
reed@android.com2ee7c642009-10-28 14:25:34 +0000324 SkPoint fP0, fP1;
reed@android.comd2abab62009-10-20 21:27:15 +0000325 typedef SkView INHERITED;
326};
327
328//////////////////////////////////////////////////////////////////////////////
329
330static SkView* MyFactory() { return new WarpView; }
331static SkViewRegister reg(MyFactory);
332