blob: 92955f855641bf874dd977c85e8d65dd85056bf7 [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.com80b4ebe2009-10-21 19:41:10 +000011
12///////////////////////////////////////////////////////////////////////////////
13
reed@android.comd2abab62009-10-20 21:27:15 +000014class Mesh {
15public:
16 Mesh();
17 ~Mesh();
18
19 Mesh& operator=(const Mesh& src);
20
21 void init(const SkRect& bounds, int rows, int cols,
22 const SkRect& texture);
23
reed@android.com80b4ebe2009-10-21 19:41:10 +000024 const SkRect& bounds() const { return fBounds; }
25
reed@android.comd2abab62009-10-20 21:27:15 +000026 int rows() const { return fRows; }
27 int cols() const { return fCols; }
28 SkPoint& pt(int row, int col) {
29 return fPts[row * (fRows + 1) + col];
30 }
31
32 void draw(SkCanvas*, const SkPaint&);
33 void drawWireframe(SkCanvas* canvas, const SkPaint& paint);
34
35private:
reed@android.com80b4ebe2009-10-21 19:41:10 +000036 SkRect fBounds;
reed@android.comd2abab62009-10-20 21:27:15 +000037 int fRows, fCols;
38 SkPoint* fPts;
39 SkPoint* fTex; // just points into fPts, not separately allocated
40 int fCount;
41 uint16_t* fIndices;
42 int fIndexCount;
43};
44
45Mesh::Mesh() : fPts(NULL), fCount(0), fIndices(NULL), fIndexCount(0) {}
46
47Mesh::~Mesh() {
48 delete[] fPts;
49 delete[] fIndices;
50}
51
52Mesh& Mesh::operator=(const Mesh& src) {
53 delete[] fPts;
54 delete[] fIndices;
55
reed@android.com80b4ebe2009-10-21 19:41:10 +000056 fBounds = src.fBounds;
reed@android.comd2abab62009-10-20 21:27:15 +000057 fRows = src.fRows;
58 fCols = src.fCols;
59
60 fCount = src.fCount;
61 fPts = new SkPoint[fCount * 2];
62 fTex = fPts + fCount;
63 memcpy(fPts, src.fPts, fCount * 2 * sizeof(SkPoint));
64
65 delete[] fIndices;
66 fIndexCount = src.fIndexCount;
67 fIndices = new uint16_t[fIndexCount];
68 memcpy(fIndices, src.fIndices, fIndexCount * sizeof(uint16_t));
69
70 return *this;
71}
72
73void Mesh::init(const SkRect& bounds, int rows, int cols,
74 const SkRect& texture) {
75 SkASSERT(rows > 0 && cols > 0);
76
reed@android.com80b4ebe2009-10-21 19:41:10 +000077 fBounds = bounds;
reed@android.comd2abab62009-10-20 21:27:15 +000078 fRows = rows;
79 fCols = cols;
80
81 delete[] fPts;
82 fCount = (rows + 1) * (cols + 1);
83 fPts = new SkPoint[fCount * 2];
84 fTex = fPts + fCount;
85
86 delete[] fIndices;
87 fIndexCount = rows * cols * 6;
88 fIndices = new uint16_t[fIndexCount];
89
90 SkPoint* pts = fPts;
91 const SkScalar dx = bounds.width() / rows;
92 const SkScalar dy = bounds.height() / cols;
93 SkPoint* tex = fTex;
94 const SkScalar dtx = texture.width() / rows;
95 const SkScalar dty = texture.height() / cols;
96 uint16_t* idx = fIndices;
97 int index = 0;
98 for (int y = 0; y <= cols; y++) {
99 for (int x = 0; x <= rows; x++) {
100 pts->set(bounds.fLeft + x*dx, bounds.fTop + y*dy);
101 pts += 1;
102 tex->set(texture.fLeft + x*dtx, texture.fTop + y*dty);
103 tex += 1;
104
105 if (y < cols && x < rows) {
106 *idx++ = index;
107 *idx++ = index + rows + 1;
108 *idx++ = index + 1;
109
110 *idx++ = index + 1;
111 *idx++ = index + rows + 1;
112 *idx++ = index + rows + 2;
113
114 index += 1;
115 }
116 }
117 index += 1;
118 }
119}
120
121void Mesh::draw(SkCanvas* canvas, const SkPaint& paint) {
122 canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount,
123 fPts, fTex, NULL, NULL, fIndices, fIndexCount,
124 paint);
125}
126
127void Mesh::drawWireframe(SkCanvas* canvas, const SkPaint& paint) {
128 canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount,
129 fPts, NULL, NULL, NULL, fIndices, fIndexCount,
130 paint);
131}
132
133///////////////////////////////////////////////////////////////////////////////
134
135class WarpView : public SkView {
136 Mesh fMesh, fOrig;
137 SkBitmap fBitmap;
138public:
139 WarpView() {
140 SkBitmap bm;
141 SkImageDecoder::DecodeFile("/skimages/nytimes.png", &bm);
142 SkIRect subset = { 0, 0, 420, 420 };
143 bm.extractSubset(&fBitmap, subset);
144
145 SkRect bounds, texture;
146 texture.set(0, 0, SkIntToScalar(fBitmap.width()),
147 SkIntToScalar(fBitmap.height()));
148 bounds = texture;
149
150// fMesh.init(bounds, fBitmap.width() / 40, fBitmap.height() / 40, texture);
reed@android.com80b4ebe2009-10-21 19:41:10 +0000151 fMesh.init(bounds, 30, 30, texture);
reed@android.comd2abab62009-10-20 21:27:15 +0000152 fOrig = fMesh;
153 }
154
155protected:
156 // overrides from SkEventSink
157 virtual bool onQuery(SkEvent* evt) {
158 if (SampleCode::TitleQ(*evt)) {
159 SampleCode::TitleR(evt, "Warp");
160 return true;
161 }
162 return this->INHERITED::onQuery(evt);
163 }
164
reed@android.com80b4ebe2009-10-21 19:41:10 +0000165 static SkPoint make_pt(SkScalar x, SkScalar y) {
166 SkPoint pt;
167 pt.set(x, y);
168 return pt;
169 }
170
171 static SkScalar mapx0(SkScalar min, SkScalar max, SkScalar x0, SkScalar x1,
172 SkScalar x) {
173 if (x < x0) {
174 SkASSERT(x0 > min);
175 return x1 - SkScalarMulDiv(x1 - min, x0 - x, x0 - min);
176 } else {
177 SkASSERT(max > x0);
178 return x1 + SkScalarMulDiv(max - x1, x - x0, max - x0);
179 }
180 }
181
182 static SkScalar mapx1(SkScalar min, SkScalar max, SkScalar x0, SkScalar x1,
183 SkScalar x) {
184 SkScalar newx;
185 if (x < x0) {
186 SkASSERT(x0 > min);
187 newx = x1 - SkScalarMulDiv(x1 - min, x0 - x, x0 - min);
188 } else {
189 SkASSERT(max > x0);
190 newx = x1 + SkScalarMulDiv(max - x1, x - x0, max - x0);
191 }
192 return x + (newx - x) * 0.5f;
193 }
194
195 static SkPoint mappt(const SkRect& r, const SkPoint& p0, const SkPoint& p1,
196 const SkPoint& pt) {
197 return make_pt(mapx0(r.fLeft, r.fRight, p0.fX, p1.fX, pt.fX),
198 mapx0(r.fTop, r.fBottom, p0.fY, p1.fY, pt.fY));
199 }
200
reed@android.comd2abab62009-10-20 21:27:15 +0000201 void warp(const SkPoint& p0, const SkPoint& p1) {
reed@android.com80b4ebe2009-10-21 19:41:10 +0000202 const SkRect& bounds = fOrig.bounds();
reed@android.comd2abab62009-10-20 21:27:15 +0000203 int rows = fMesh.rows();
204 int cols = fMesh.cols();
205
reed@android.com80b4ebe2009-10-21 19:41:10 +0000206 SkRect r = bounds;
207 r.inset(bounds.width() / 256, bounds.height() / 256);
208 if (r.contains(p0)) {
209 for (int y = 1; y < cols; y++) {
210 for (int x = 1; x < rows; x++) {
211 fMesh.pt(x, y) = mappt(bounds, p0, p1, fOrig.pt(x, y));
212 }
reed@android.comd2abab62009-10-20 21:27:15 +0000213 }
214 }
215 }
216
217 virtual void onDraw(SkCanvas* canvas) {
218 canvas->drawColor(SK_ColorGRAY);
219
220 SkPaint paint;
221 paint.setFilterBitmap(true);
222 paint.setShader(SkShader::CreateBitmapShader(fBitmap,
223 SkShader::kClamp_TileMode,
224 SkShader::kClamp_TileMode))->unref();
225 fMesh.draw(canvas, paint);
226
227 paint.setShader(NULL);
228 paint.setColor(SK_ColorRED);
reed@android.com80b4ebe2009-10-21 19:41:10 +0000229 // fMesh.draw(canvas, paint);
reed@android.comd2abab62009-10-20 21:27:15 +0000230 }
231
232 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
233 return new Click(this);
234 }
235
236 virtual bool onClick(Click* click) {
237 this->warp(click->fOrig, click->fCurr);
238 this->inval(NULL);
239 return true;
240 }
241
242private:
243 SkIRect fBase, fRect;
244
245 typedef SkView INHERITED;
246};
247
248//////////////////////////////////////////////////////////////////////////////
249
250static SkView* MyFactory() { return new WarpView; }
251static SkViewRegister reg(MyFactory);
252