blob: bc0b7bcd3a1178e7e182b9391cab60bde7f1090c [file] [log] [blame]
reed@google.com9f72d542012-09-08 16:52:23 +00001
2/*
3 * Copyright 2012 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "gm.h"
9
10#include "SkColorPriv.h"
11#include "SkGeometry.h"
12#include "SkShader.h"
13
14static void tesselate(const SkPath& src, SkPath* dst) {
15 SkPath::Iter iter(src, true);
16 SkPoint pts[4];
17 SkPath::Verb verb;
18 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
19 switch (verb) {
20 case SkPath::kMove_Verb:
21 dst->moveTo(pts[0]);
22 break;
23 case SkPath::kLine_Verb:
24 dst->lineTo(pts[1]);
25 break;
26 case SkPath::kQuad_Verb: {
27 SkPoint p;
28 for (int i = 1; i <= 8; ++i) {
29 SkEvalQuadAt(pts, i / 8.0f, &p, NULL);
30 dst->lineTo(p);
31 }
32 } break;
33 case SkPath::kCubic_Verb: {
34 SkPoint p;
35 for (int i = 1; i <= 8; ++i) {
36 SkEvalCubicAt(pts, i / 8.0f, &p, NULL, NULL);
37 dst->lineTo(p);
38 }
39 } break;
40 }
41 }
42}
43
44static void setFade(SkPaint* paint, bool showGL) {
45 paint->setAlpha(showGL ? 0x66 : 0xFF);
46}
47
48static void setGLFrame(SkPaint* paint) {
49 paint->setColor(0xFFFF0000);
50 paint->setStyle(SkPaint::kStroke_Style);
51 paint->setAntiAlias(true);
52 paint->setStrokeWidth(1.1f);
53}
54
55static void show_mesh(SkCanvas* canvas, const SkRect& r) {
56 SkPaint paint;
57 setGLFrame(&paint);
58
59 canvas->drawRect(r, paint);
60 canvas->drawLine(r.fLeft, r.fTop, r.fRight, r.fBottom, paint);
61}
62
63static void drawLine(SkCanvas* canvas, const SkPoint& p0, const SkPoint& p1,
64 const SkPaint& paint) {
65 canvas->drawLine(p0.fX, p0.fY, p1.fX, p1.fY, paint);
66}
67
68static void show_mesh(SkCanvas* canvas, const SkPoint pts[],
69 const uint16_t indices[], int count) {
70 SkPaint paint;
71 setGLFrame(&paint);
72
73 for (int i = 0; i < count - 2; ++i) {
74 drawLine(canvas, pts[indices[i]], pts[indices[i+1]], paint);
75 drawLine(canvas, pts[indices[i+1]], pts[indices[i+2]], paint);
76 drawLine(canvas, pts[indices[i+2]], pts[indices[i]], paint);
77 }
78}
79
80static void show_glframe(SkCanvas* canvas, const SkPath& path) {
81 SkPaint paint;
82 setGLFrame(&paint);
83 canvas->drawPath(path, paint);
84}
85
86static void show_mesh_between(SkCanvas* canvas, const SkPath& p0, const SkPath& p1) {
87 SkPath d0, d1;
88 tesselate(p0, &d0);
89 tesselate(p1, &d1);
90
91 SkPoint pts0[256*2], pts1[256];
92 int count = d0.getPoints(pts0, SK_ARRAY_COUNT(pts0));
93 int count1 = d1.getPoints(pts1, SK_ARRAY_COUNT(pts1));
94 SkASSERT(count == count1);
95 memcpy(&pts0[count], pts1, count * sizeof(SkPoint));
96
97 uint16_t indices[256*6];
98 uint16_t* ndx = indices;
99 for (int i = 0; i < count; ++i) {
100 *ndx++ = i;
101 *ndx++ = i + count;
102 }
103 *ndx++ = 0;
104
105 show_mesh(canvas, pts0, indices, ndx - indices);
106}
107
108static void show_fan(SkCanvas* canvas, const SkPath& path, SkScalar cx, SkScalar cy) {
109 SkPaint paint;
110 setGLFrame(&paint);
111
112 canvas->drawPath(path, paint);
113
114 SkPoint pts[256];
115 int count = path.getPoints(pts, SK_ARRAY_COUNT(pts));
116 for (int i = 0; i < count; ++i) {
117 canvas->drawLine(pts[i].fX, pts[i].fY, cx, cy, paint);
118 }
119}
120
121///////////////////////////////////////////////////////////////////////////////
122
123typedef void (*DrawProc)(SkCanvas* canvas, bool showGL, int flags);
124
125static void draw_line(SkCanvas* canvas, bool showGL, int flags) {
126 SkPaint paint;
127 paint.setAntiAlias(true);
128
129 canvas->drawLine(50, 50, 400, 100, paint);
130
131 canvas->rotate(40);
132 setFade(&paint, showGL);
133 paint.setStrokeWidth(40);
134 canvas->drawLine(100, 50, 450, 50, paint);
135 if (showGL) {
136 show_mesh(canvas, SkRect::MakeLTRB(100, 50-20, 450, 50+20));
137 }
138}
139
140static void draw_rect(SkCanvas* canvas, bool showGL, int flags) {
141 SkPaint paint;
142 paint.setAntiAlias(true);
143
reed@google.comb5671782012-09-08 20:00:36 +0000144 SkRect r = SkRect::MakeLTRB(50, 70, 250, 370);
reed@google.com9f72d542012-09-08 16:52:23 +0000145
146 setFade(&paint, showGL);
147 canvas->drawRect(r, paint);
148 if (showGL) {
149 show_mesh(canvas, r);
150 }
151
152 canvas->translate(320, 0);
153
154 paint.setStyle(SkPaint::kStroke_Style);
155 paint.setStrokeWidth(25);
156 canvas->drawRect(r, paint);
157 if (showGL) {
158 SkScalar rad = paint.getStrokeWidth() / 2;
159 SkPoint pts[8];
160 r.outset(rad, rad);
161 r.toQuad(&pts[0]);
162 r.inset(rad*2, rad*2);
163 r.toQuad(&pts[4]);
164
165 const uint16_t indices[] = {
166 0, 4, 1, 5, 2, 6, 3, 7, 0, 4
167 };
168 show_mesh(canvas, pts, indices, SK_ARRAY_COUNT(indices));
169 }
170}
171
172static void draw_oval(SkCanvas* canvas, bool showGL, int flags) {
173 SkPaint paint;
174 paint.setAntiAlias(true);
175
reed@google.comb5671782012-09-08 20:00:36 +0000176 SkRect r = SkRect::MakeLTRB(50, 70, 250, 370);
reed@google.com9f72d542012-09-08 16:52:23 +0000177
178 setFade(&paint, showGL);
179 canvas->drawOval(r, paint);
180 if (showGL) {
181 switch (flags) {
182 case 0: {
183 SkPath path;
184 path.addOval(r);
185 show_glframe(canvas, path);
186 } break;
reed@google.comb5671782012-09-08 20:00:36 +0000187 case 1:
188 case 2: {
reed@google.com9f72d542012-09-08 16:52:23 +0000189 SkPath src, dst;
190 src.addOval(r);
191 tesselate(src, &dst);
192 show_fan(canvas, dst, r.centerX(), r.centerY());
193 } break;
194 }
195 }
196
197 canvas->translate(320, 0);
198
199 paint.setStyle(SkPaint::kStroke_Style);
200 paint.setStrokeWidth(25);
201 canvas->drawOval(r, paint);
202 if (showGL) {
203 switch (flags) {
204 case 0: {
205 SkPath path;
206 SkScalar rad = paint.getStrokeWidth() / 2;
207 r.outset(rad, rad);
208 path.addOval(r);
209 r.inset(rad*2, rad*2);
210 path.addOval(r);
211 show_glframe(canvas, path);
212 } break;
213 case 1: {
214 SkPath path0, path1;
215 SkScalar rad = paint.getStrokeWidth() / 2;
216 r.outset(rad, rad);
217 path0.addOval(r);
218 r.inset(rad*2, rad*2);
219 path1.addOval(r);
220 show_mesh_between(canvas, path0, path1);
221 } break;
reed@google.comb5671782012-09-08 20:00:36 +0000222 case 2: {
223 SkScalar rad = paint.getStrokeWidth() / 2;
224 r.outset(rad, rad);
225 SkPaint paint;
226 paint.setAlpha(0x33);
227 canvas->drawRect(r, paint);
228 show_mesh(canvas, r);
229 } break;
reed@google.com9f72d542012-09-08 16:52:23 +0000230 }
231 }
232}
233
reed@google.comb5671782012-09-08 20:00:36 +0000234#include "SkImageDecoder.h"
reed@google.com9f72d542012-09-08 16:52:23 +0000235static void draw_image(SkCanvas* canvas, bool showGL, int flags) {
236 SkPaint paint;
237 paint.setAntiAlias(true);
reed@google.comb5671782012-09-08 20:00:36 +0000238 paint.setFilterBitmap(true);
239 setFade(&paint, showGL);
240
241 SkBitmap bm;
242 SkImageDecoder::DecodeFile("/skimages/startrek.png", &bm);
243 SkRect r = SkRect::MakeWH(bm.width(), bm.height());
244
245 canvas->save();
246 canvas->translate(30, 30);
247 canvas->scale(0.8f, 0.8f);
248 canvas->drawBitmap(bm, 0, 0, &paint);
249 if (showGL) {
250 show_mesh(canvas, r);
251 }
252 canvas->restore();
253
254 canvas->translate(210, 290);
255 canvas->rotate(-35);
256 canvas->drawBitmap(bm, 0, 0, &paint);
257 if (showGL) {
258 show_mesh(canvas, r);
259 }
reed@google.com9f72d542012-09-08 16:52:23 +0000260}
261
262static void draw_text(SkCanvas* canvas, bool showGL, int flags) {
263 SkPaint paint;
264 paint.setAntiAlias(true);
reed@google.comb5671782012-09-08 20:00:36 +0000265 const char text[] = "Graphics at Google";
266 size_t len = strlen(text);
267 setFade(&paint, showGL);
268
269 canvas->translate(40, 50);
270 for (int i = 0; i < 10; ++i) {
271 paint.setTextSize(12 + i * 3);
272 canvas->drawText(text, len, 0, 0, paint);
273 if (showGL) {
274 SkRect bounds[256];
275 SkScalar widths[256];
276 int count = paint.getTextWidths(text, len, widths, bounds);
277 SkScalar adv = 0;
278 for (int j = 0; j < count; ++j) {
279 bounds[j].offset(adv, 0);
280 show_mesh(canvas, bounds[j]);
281 adv += widths[j];
282 }
283 }
284 canvas->translate(0, paint.getTextSize() * 3 / 2);
285 }
reed@google.com9f72d542012-09-08 16:52:23 +0000286}
287
288static const struct {
289 DrawProc fProc;
290 const char* fName;
291} gRec[] = {
292 { draw_line, "Lines" },
293 { draw_rect, "Rects" },
294 { draw_oval, "Ovals" },
295 { draw_image, "Images" },
296 { draw_text, "Text" },
297};
298
299class TalkGM : public skiagm::GM {
300 DrawProc fProc;
301 SkString fName;
302 bool fShowGL;
303 int fFlags;
304
305public:
306 TalkGM(int index, bool showGL, int flags = 0) {
307 fProc = gRec[index].fProc;
308 fName.set(gRec[index].fName);
309 if (showGL) {
310 fName.append("-gl");
311 }
312 fShowGL = showGL;
313 fFlags = flags;
314 }
315
316protected:
317 virtual SkString onShortName() {
318 return fName;
319 }
320
321 virtual SkISize onISize() {
322 return SkISize::Make(640, 480);
323 }
324
325 virtual void onDraw(SkCanvas* canvas) {
326 SkRect dst = SkRect::MakeWH(canvas->getDevice()->width(), canvas->getDevice()->height());
327 SkRect src = SkRect::MakeWH(640, 480);
328 SkMatrix matrix;
329 matrix.setRectToRect(src, dst, SkMatrix::kCenter_ScaleToFit);
330
331 canvas->concat(matrix);
332 fProc(canvas, fShowGL, fFlags);
333 }
334
335private:
336 typedef skiagm::GM INHERITED;
337};
338
339//////////////////////////////////////////////////////////////////////////////
340
341#define GM_CONCAT(X,Y) GM_CONCAT_IMPL(X,Y)
342#define GM_CONCAT_IMPL(X,Y) X##Y
343
344#define FACTORY_NAME GM_CONCAT(Factory, __LINE__)
345#define REGISTRY_NAME GM_CONCAT(gReg, __LINE__)
346
347#define ADD_GM(Class, args) \
348 static skiagm::GM* FACTORY_NAME(void*) { return new Class args; } \
349 static skiagm::GMRegistry REGISTRY_NAME(FACTORY_NAME);
350
351ADD_GM(TalkGM, (0, false))
352ADD_GM(TalkGM, (0, true))
353ADD_GM(TalkGM, (1, false))
354ADD_GM(TalkGM, (1, true))
355ADD_GM(TalkGM, (2, false))
356ADD_GM(TalkGM, (2, true))
357ADD_GM(TalkGM, (2, true, 1))
reed@google.comb5671782012-09-08 20:00:36 +0000358ADD_GM(TalkGM, (2, true, 2))
reed@google.com9f72d542012-09-08 16:52:23 +0000359ADD_GM(TalkGM, (3, false))
360ADD_GM(TalkGM, (3, true))
361ADD_GM(TalkGM, (4, false))
362ADD_GM(TalkGM, (4, true))
363
364//static GM* MyFactory(void*) { return new TalkGM(0, false); }
365//static GMRegistry reg(MyFactory);
366
367