blob: 2e55db2ed08f66336f8ccf1d7ad0648e4e549989 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SampleCode.h"
2#include "SkView.h"
3#include "SkCanvas.h"
4#include "SkGradientShader.h"
5#include "SkGraphics.h"
6#include "SkImageDecoder.h"
7#include "SkPath.h"
8#include "SkPorterDuff.h"
9#include "SkRandom.h"
10#include "SkRegion.h"
11#include "SkShader.h"
12#include "SkUtils.h"
13#include "SkXfermode.h"
14#include "SkShaderExtras.h"
15#include "SkColorPriv.h"
16#include "SkColorFilter.h"
17#include "SkTime.h"
18#include "SkTypeface.h"
19
20#include "SkImageRef.h"
21#include "SkOSFile.h"
22#include "SkStream.h"
23
24#include "SkGeometry.h" // private include :(
25
26static void drawtriangle(SkCanvas* canvas, const SkPaint& paint,
27 const SkPoint pts[3]) {
28 SkPath path;
29
30 path.moveTo(pts[0]);
31 path.lineTo(pts[1]);
32 path.lineTo(pts[2]);
33
34 canvas->drawPath(path, paint);
35}
36
37static SkShader* make_shader0(SkIPoint* size) {
38 SkBitmap bm;
39
40// SkImageDecoder::DecodeFile("/skimages/progressivejpg.jpg", &bm);
41 SkImageDecoder::DecodeFile("/skimages/beach.jpg", &bm);
42 size->set(bm.width(), bm.height());
43 return SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode,
44 SkShader::kClamp_TileMode);
45}
46
47static SkShader* make_shader1(const SkIPoint& size) {
48 SkPoint pts[] = { 0, 0, SkIntToScalar(size.fX), SkIntToScalar(size.fY) };
49 SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
50 return SkGradientShader::CreateLinear(pts, colors, NULL,
51 SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode, NULL);
52}
53
54///////////////////////////////////////////////////////////////////////////////
55
56class Patch {
57public:
58 Patch() { bzero(fPts, sizeof(fPts)); }
59 ~Patch() {}
60
61 void setPatch(const SkPoint pts[12]) {
62 memcpy(fPts, pts, 12 * sizeof(SkPoint));
63 fPts[12] = pts[0]; // the last shall be first
64 }
65 void setBounds(int w, int h) { fW = w; fH = h; }
66
67 void draw(SkCanvas*, const SkPaint&, int segsU, int segsV,
68 bool doTextures, bool doColors);
69
70private:
71 SkPoint fPts[13];
72 int fW, fH;
73};
74
75static void eval_patch_edge(const SkPoint cubic[], SkPoint samples[], int segs) {
76 SkScalar t = 0;
77 SkScalar dt = SK_Scalar1 / segs;
78
79 samples[0] = cubic[0];
80 for (int i = 1; i < segs; i++) {
81 t += dt;
82 SkEvalCubicAt(cubic, t, &samples[i], NULL, NULL);
83 }
84}
85
86static void eval_sheet(const SkPoint edge[], int nu, int nv, int iu, int iv,
87 SkPoint* pt) {
88 const int TL = 0;
89 const int TR = nu;
90 const int BR = TR + nv;
91 const int BL = BR + nu;
92
93 SkScalar u = SkIntToScalar(iu) / nu;
94 SkScalar v = SkIntToScalar(iv) / nv;
95
96 SkScalar uv = SkScalarMul(u, v);
97 SkScalar Uv = SkScalarMul(SK_Scalar1 - u, v);
98 SkScalar uV = SkScalarMul(u, SK_Scalar1 - v);
99 SkScalar UV = SkScalarMul(SK_Scalar1 - u, SK_Scalar1 - v);
100
101 SkScalar x0 = SkScalarMul(UV, edge[TL].fX) + SkScalarMul(uV, edge[TR].fX) +
102 SkScalarMul(Uv, edge[BL].fX) + SkScalarMul(uv, edge[BR].fX);
103 SkScalar y0 = SkScalarMul(UV, edge[TL].fY) + SkScalarMul(uV, edge[TR].fY) +
104 SkScalarMul(Uv, edge[BL].fY) + SkScalarMul(uv, edge[BR].fY);
105
106 SkScalar x = SkScalarMul(SK_Scalar1 - v, edge[TL+iu].fX) +
107 SkScalarMul(u, edge[TR+iv].fX) +
108 SkScalarMul(v, edge[BR+nu-iu].fX) +
109 SkScalarMul(SK_Scalar1 - u, edge[BL+nv-iv].fX) - x0;
110 SkScalar y = SkScalarMul(SK_Scalar1 - v, edge[TL+iu].fY) +
111 SkScalarMul(u, edge[TR+iv].fY) +
112 SkScalarMul(v, edge[BR+nu-iu].fY) +
113 SkScalarMul(SK_Scalar1 - u, edge[BL+nv-iv].fY) - y0;
114 pt->set(x, y);
115}
116
117static int ScalarTo255(SkScalar v) {
118 int scale = SkScalarToFixed(v) >> 8;
119 if (scale < 0) {
120 scale = 0;
121 } else if (scale > 255) {
122 scale = 255;
123 }
124 return scale;
125}
126
127static SkColor make_color(SkScalar s, SkScalar t) {
128 int cs = ScalarTo255(s);
129 int ct = ScalarTo255(t);
130 return SkColorSetARGB(0xFF, cs, 0, 0) + SkColorSetARGB(0, 0, ct, 0);
131}
132
133void Patch::draw(SkCanvas* canvas, const SkPaint& paint, int nu, int nv,
134 bool doTextures, bool doColors) {
135 if (nu < 1 || nv < 1) {
136 return;
137 }
138
139 int i, npts = (nu + nv) * 2;
140 SkAutoSTMalloc<16, SkPoint> storage(npts + 1);
141 SkPoint* edge0 = storage.get();
142 SkPoint* edge1 = edge0 + nu;
143 SkPoint* edge2 = edge1 + nv;
144 SkPoint* edge3 = edge2 + nu;
145
146 // evaluate the edge points
147 eval_patch_edge(fPts + 0, edge0, nu);
148 eval_patch_edge(fPts + 3, edge1, nv);
149 eval_patch_edge(fPts + 6, edge2, nu);
150 eval_patch_edge(fPts + 9, edge3, nv);
151 edge3[nv] = edge0[0]; // the last shall be first
152
153 for (i = 0; i < npts; i++) {
154// canvas->drawLine(edge0[i].fX, edge0[i].fY, edge0[i+1].fX, edge0[i+1].fY, paint);
155 }
156
157 int row, vertCount = (nu + 1) * (nv + 1);
158 SkAutoTMalloc<SkPoint> vertStorage(vertCount);
159 SkPoint* verts = vertStorage.get();
160
161 // first row
162 memcpy(verts, edge0, (nu + 1) * sizeof(SkPoint));
163 // rows
164 SkPoint* r = verts;
165 for (row = 1; row < nv; row++) {
166 r += nu + 1;
167 r[0] = edge3[nv - row];
168 for (int col = 1; col < nu; col++) {
169 eval_sheet(edge0, nu, nv, col, row, &r[col]);
170 }
171 r[nu] = edge1[row];
172 }
173 // last row
174 SkPoint* last = verts + nv * (nu + 1);
175 for (i = 0; i <= nu; i++) {
176 last[i] = edge2[nu - i];
177 }
178
179// canvas->drawPoints(verts, vertCount, paint);
180
181 int stripCount = (nu + 1) * 2;
182 SkAutoTMalloc<SkPoint> stripStorage(stripCount * 2);
183 SkAutoTMalloc<SkColor> colorStorage(stripCount);
184 SkPoint* strip = stripStorage.get();
185 SkPoint* tex = strip + stripCount;
186 SkColor* colors = colorStorage.get();
187 SkScalar t = 0;
188 const SkScalar ds = SK_Scalar1 * fW / nu;
189 const SkScalar dt = SK_Scalar1 * fH / nv;
190 r = verts;
191 for (row = 0; row < nv; row++) {
192 SkPoint* upper = r;
193 SkPoint* lower = r + nu + 1;
194 r = lower;
195 SkScalar s = 0;
196 for (i = 0; i <= nu; i++) {
197 strip[i*2 + 0] = *upper++;
198 strip[i*2 + 1] = *lower++;
199 tex[i*2 + 0].set(s, t);
200 tex[i*2 + 1].set(s, t + dt);
201 colors[i*2 + 0] = make_color(s/fW, t/fH);
202 colors[i*2 + 1] = make_color(s/fW, (t + dt)/fH);
203 s += ds;
204 }
205 t += dt;
206 canvas->drawVertices(SkCanvas::kTriangleStrip_VertexMode, stripCount,
207 strip, doTextures ? tex : NULL,
208 doColors ? colors : NULL, NULL,
209 NULL, 0, paint);
210 }
211}
212
213static void drawpatches(SkCanvas* canvas, const SkPaint& paint, int nu, int nv,
214 Patch* patch) {
215
216 SkAutoCanvasRestore ar(canvas, true);
217
218 patch->draw(canvas, paint, 10, 10, false, false);
219 canvas->translate(SkIntToScalar(300), 0);
220 patch->draw(canvas, paint, 10, 10, true, false);
221 canvas->translate(SkIntToScalar(300), 0);
222 patch->draw(canvas, paint, 10, 10, false, true);
223 canvas->translate(SkIntToScalar(300), 0);
224 patch->draw(canvas, paint, 10, 10, true, true);
225}
226
227class PatchView : public SkView {
228 SkShader* fShader0;
229 SkShader* fShader1;
230 SkIPoint fSize0, fSize1;
231 SkPoint fPts[12];
232
233public:
234 PatchView() {
235 fShader0 = make_shader0(&fSize0);
236 fSize1 = fSize0;
237 if (fSize0.fX == 0 || fSize0.fY == 0) {
238 fSize1.set(2, 2);
239 }
240 fShader1 = make_shader1(fSize1);
241
242 const SkScalar S = SkIntToScalar(90);
243 const SkScalar T = SkIntToScalar(64);
244 fPts[0].set(S*1, T);
245 fPts[1].set(S*2, T);
246 fPts[2].set(S*3, T);
247 fPts[3].set(S*4, T);
248 fPts[4].set(S*4, T*2);
249 fPts[5].set(S*4, T*3);
250 fPts[6].set(S*4, T*4);
251 fPts[7].set(S*3, T*4);
252 fPts[8].set(S*2, T*4);
253 fPts[9].set(S*1, T*4);
254 fPts[10].set(S*1, T*3);
255 fPts[11].set(S*1, T*2);
256 }
257
258 virtual ~PatchView() {
259 fShader0->safeUnref();
260 fShader1->safeUnref();
261 }
262
263protected:
264 // overrides from SkEventSink
265 virtual bool onQuery(SkEvent* evt) {
266 if (SampleCode::TitleQ(*evt))
267 {
268 SkString str("Patch");
269 SampleCode::TitleR(evt, str.c_str());
270 return true;
271 }
272 return this->INHERITED::onQuery(evt);
273 }
274
275 void drawBG(SkCanvas* canvas) {
276 canvas->drawColor(SK_ColorGRAY);
277 }
278
279 virtual void onDraw(SkCanvas* canvas) {
280 this->drawBG(canvas);
281
282 SkPaint paint;
283 paint.setDither(true);
284 paint.setFilterBitmap(true);
285
286 if (false) {
287 SkPath p;
288 p.moveTo(0, 0);
289 p.lineTo(SkIntToScalar(30000), SkIntToScalar(30000));
290 paint.setStyle(SkPaint::kStroke_Style);
291 paint.setStrokeWidth(SkIntToScalar(4));
292 paint.setAntiAlias(true);
293 canvas->scale(SkIntToScalar(3), SkIntToScalar(3));
294 canvas->drawPath(p, paint);
295 return;
296 }
297
298 if (false) {
299 for (int dy = -1; dy <= 2; dy++) {
300 canvas->save();
301 if (dy == 2) {
302 canvas->translate(0, SK_Scalar1/2);
303 } else {
304 canvas->translate(0, SkIntToScalar(dy)/100);
305 }
306
307 SkBitmap bm;
308 bm.setConfig(SkBitmap::kARGB_8888_Config, 20, 20);
309 bm.allocPixels();
310 SkCanvas c(bm);
311 SkRect r = { 0, 0, 20*SK_Scalar1, SK_Scalar1 };
312 for (int y = 0; y < 20; y++) {
313 SkPaint p;
314 p.setARGB(0xFF, y*5&0xFF, y*13&0xFF, y*29&0xFF);
315 c.drawRect(r, p);
316 r.offset(0, SK_Scalar1);
317 }
318 SkIRect src;
319 SkRect dst;
320
321 static const int srcPts[] = {
322 // 2, 0, 15, 2,
323 2, 2, 15, 16,
324 17, 2, 2, 16,
325 19, 2, 1, 16,
326 // 2, 18, 15, 2
327 };
328 static const double dstPts[] = {
329 // 7, 262 15, 24.5,
330 7, 286.5, 15, 16,
331 22, 286.5, 5, 16,
332 27, 286.5, 1, 16,
333 // 7, 302.5, 15, 24.5
334 };
335
336 SkPaint p;
337// p.setFilterBitmap(true);
338 const int* s = srcPts;
339 const double* d = dstPts;
340 for (int i = 0; i < 3; i++) {
341 src.set(s[0], s[1], s[0]+s[2], s[1]+s[3]);
342 dst.set(SkDoubleToScalar(d[0]),
343 SkDoubleToScalar(d[1]),
344 SkDoubleToScalar(d[0]+d[2]),
345 SkDoubleToScalar(d[1]+d[3]));
346 canvas->drawBitmapRect(bm, &src, dst, &p);
347 canvas->translate(SkDoubleToScalar(1), 0);
348 s += 4;
349 d += 4;
350 }
351 canvas->restore();
352 canvas->translate(SkIntToScalar(32), 0);
353 }
354 return;
355 }
356
357 Patch patch;
358
359 paint.setShader(fShader0);
360 if (fSize0.fX == 0) {
361 fSize0.fX = 1;
362 }
363 if (fSize0.fY == 0) {
364 fSize0.fY = 1;
365 }
366 patch.setBounds(fSize0.fX, fSize0.fY);
367
368 patch.setPatch(fPts);
369 drawpatches(canvas, paint, 10, 10, &patch);
370
371 paint.setShader(NULL);
372 paint.setAntiAlias(true);
373 paint.setStrokeWidth(SkIntToScalar(5));
374 canvas->drawPoints(SkCanvas::kPoints_PointMode, SK_ARRAY_COUNT(fPts),
375 fPts, paint);
376
377 canvas->translate(0, SkIntToScalar(300));
378
379 paint.setAntiAlias(false);
380 paint.setShader(fShader1);
381 patch.setBounds(fSize1.fX, fSize1.fY);
382 drawpatches(canvas, paint, 10, 10, &patch);
383 }
384
385 class PtClick : public Click {
386 public:
387 int fIndex;
388 PtClick(SkView* view, int index) : Click(view), fIndex(index) {}
389 };
390
391 static bool hittest(const SkPoint& pt, SkScalar x, SkScalar y) {
392 return SkPoint::Length(pt.fX - x, pt.fY - y) < SkIntToScalar(5);
393 }
394
395 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
396 for (int i = 0; i < SK_ARRAY_COUNT(fPts); i++) {
397 if (hittest(fPts[i], x, y)) {
398 return new PtClick(this, i);
399 }
400 }
401 return this->INHERITED::onFindClickHandler(x, y);
402 }
403
404 virtual bool onClick(Click* click) {
405 fPts[((PtClick*)click)->fIndex].set(click->fCurr.fX, click->fCurr.fY);
406 this->inval(NULL);
407 return true;
408 }
409
410private:
411 typedef SkView INHERITED;
412};
413
414//////////////////////////////////////////////////////////////////////////////
415
416static SkView* MyFactory() { return new PatchView; }
417static SkViewRegister reg(MyFactory);
418