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