|  |  | 
|  | /* | 
|  | * Copyright 2012 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  | #include "gm.h" | 
|  |  | 
|  | #include "SkColorPriv.h" | 
|  | #include "SkGeometry.h" | 
|  | #include "SkShader.h" | 
|  |  | 
|  | #define WIRE_FRAME_WIDTH    1.1f | 
|  |  | 
|  | static void tesselate(const SkPath& src, SkPath* dst) { | 
|  | SkPath::Iter iter(src, true); | 
|  | SkPoint pts[4]; | 
|  | SkPath::Verb verb; | 
|  | while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { | 
|  | switch (verb) { | 
|  | case SkPath::kMove_Verb: | 
|  | dst->moveTo(pts[0]); | 
|  | break; | 
|  | case SkPath::kLine_Verb: | 
|  | dst->lineTo(pts[1]); | 
|  | break; | 
|  | case SkPath::kQuad_Verb: { | 
|  | SkPoint p; | 
|  | for (int i = 1; i <= 8; ++i) { | 
|  | SkEvalQuadAt(pts, i / 8.0f, &p, NULL); | 
|  | dst->lineTo(p); | 
|  | } | 
|  | } break; | 
|  | case SkPath::kCubic_Verb: { | 
|  | SkPoint p; | 
|  | for (int i = 1; i <= 8; ++i) { | 
|  | SkEvalCubicAt(pts, i / 8.0f, &p, NULL, NULL); | 
|  | dst->lineTo(p); | 
|  | } | 
|  | } break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void setFade(SkPaint* paint, bool showGL) { | 
|  | paint->setAlpha(showGL ? 0x66 : 0xFF); | 
|  | } | 
|  |  | 
|  | static void setGLFrame(SkPaint* paint) { | 
|  | paint->setColor(0xFFFF0000); | 
|  | paint->setStyle(SkPaint::kStroke_Style); | 
|  | paint->setAntiAlias(true); | 
|  | paint->setStrokeWidth(WIRE_FRAME_WIDTH); | 
|  | } | 
|  |  | 
|  | static void show_mesh(SkCanvas* canvas, const SkRect& r) { | 
|  | SkPaint paint; | 
|  | setGLFrame(&paint); | 
|  |  | 
|  | canvas->drawRect(r, paint); | 
|  | canvas->drawLine(r.fLeft, r.fTop, r.fRight, r.fBottom, paint); | 
|  | } | 
|  |  | 
|  | static void drawLine(SkCanvas* canvas, const SkPoint& p0, const SkPoint& p1, | 
|  | const SkPaint& paint) { | 
|  | canvas->drawLine(p0.fX, p0.fY, p1.fX, p1.fY, paint); | 
|  | } | 
|  |  | 
|  | static void show_mesh(SkCanvas* canvas, const SkPoint pts[], | 
|  | const uint16_t indices[], int count) { | 
|  | SkPaint paint; | 
|  | setGLFrame(&paint); | 
|  |  | 
|  | for (int i = 0; i < count - 2; ++i) { | 
|  | drawLine(canvas, pts[indices[i]], pts[indices[i+1]], paint); | 
|  | drawLine(canvas, pts[indices[i+1]], pts[indices[i+2]], paint); | 
|  | drawLine(canvas, pts[indices[i+2]], pts[indices[i]], paint); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void show_glframe(SkCanvas* canvas, const SkPath& path) { | 
|  | SkPaint paint; | 
|  | setGLFrame(&paint); | 
|  | canvas->drawPath(path, paint); | 
|  | } | 
|  |  | 
|  | static void show_mesh_between(SkCanvas* canvas, const SkPath& p0, const SkPath& p1) { | 
|  | SkPath d0, d1; | 
|  | tesselate(p0, &d0); | 
|  | tesselate(p1, &d1); | 
|  |  | 
|  | SkPoint pts0[256*2], pts1[256]; | 
|  | int count = d0.getPoints(pts0, SK_ARRAY_COUNT(pts0)); | 
|  | int count1 = d1.getPoints(pts1, SK_ARRAY_COUNT(pts1)); | 
|  | SkASSERT(count == count1); | 
|  | memcpy(&pts0[count], pts1, count * sizeof(SkPoint)); | 
|  |  | 
|  | uint16_t indices[256*6]; | 
|  | uint16_t* ndx = indices; | 
|  | for (int i = 0; i < count; ++i) { | 
|  | *ndx++ = i; | 
|  | *ndx++ = i + count; | 
|  | } | 
|  | *ndx++ = 0; | 
|  |  | 
|  | show_mesh(canvas, pts0, indices, ndx - indices); | 
|  | } | 
|  |  | 
|  | static void show_fan(SkCanvas* canvas, const SkPath& path, SkScalar cx, SkScalar cy) { | 
|  | SkPaint paint; | 
|  | setGLFrame(&paint); | 
|  |  | 
|  | canvas->drawPath(path, paint); | 
|  |  | 
|  | SkPoint pts[256]; | 
|  | int count = path.getPoints(pts, SK_ARRAY_COUNT(pts)); | 
|  | for (int i = 0; i < count; ++i) { | 
|  | canvas->drawLine(pts[i].fX, pts[i].fY, cx, cy, paint); | 
|  | } | 
|  | } | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | typedef void (*DrawProc)(SkCanvas* canvas, bool showGL, int flags); | 
|  |  | 
|  | static void draw_line(SkCanvas* canvas, bool showGL, int flags) { | 
|  | SkPaint paint; | 
|  | paint.setAntiAlias(true); | 
|  |  | 
|  | if (showGL) { | 
|  | setGLFrame(&paint); | 
|  | } | 
|  | canvas->drawLine(50, 50, 400, 100, paint); | 
|  | paint.setColor(SK_ColorBLACK); | 
|  |  | 
|  | canvas->rotate(40); | 
|  | setFade(&paint, showGL); | 
|  | paint.setStrokeWidth(40); | 
|  | canvas->drawLine(100, 50, 450, 50, paint); | 
|  | if (showGL) { | 
|  | show_mesh(canvas, SkRect::MakeLTRB(100, 50-20, 450, 50+20)); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void draw_rect(SkCanvas* canvas, bool showGL, int flags) { | 
|  | SkPaint paint; | 
|  | paint.setAntiAlias(true); | 
|  |  | 
|  | SkRect r = SkRect::MakeLTRB(50, 70, 250, 370); | 
|  |  | 
|  | setFade(&paint, showGL); | 
|  | canvas->drawRect(r, paint); | 
|  | if (showGL) { | 
|  | show_mesh(canvas, r); | 
|  | } | 
|  |  | 
|  | canvas->translate(320, 0); | 
|  |  | 
|  | paint.setStyle(SkPaint::kStroke_Style); | 
|  | paint.setStrokeWidth(25); | 
|  | canvas->drawRect(r, paint); | 
|  | if (showGL) { | 
|  | SkScalar rad = paint.getStrokeWidth() / 2; | 
|  | SkPoint pts[8]; | 
|  | r.outset(rad, rad); | 
|  | r.toQuad(&pts[0]); | 
|  | r.inset(rad*2, rad*2); | 
|  | r.toQuad(&pts[4]); | 
|  |  | 
|  | const uint16_t indices[] = { | 
|  | 0, 4, 1, 5, 2, 6, 3, 7, 0, 4 | 
|  | }; | 
|  | show_mesh(canvas, pts, indices, SK_ARRAY_COUNT(indices)); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void draw_oval(SkCanvas* canvas, bool showGL, int flags) { | 
|  | SkPaint paint; | 
|  | paint.setAntiAlias(true); | 
|  |  | 
|  | SkRect r = SkRect::MakeLTRB(50, 70, 250, 370); | 
|  |  | 
|  | setFade(&paint, showGL); | 
|  | canvas->drawOval(r, paint); | 
|  | if (showGL) { | 
|  | switch (flags) { | 
|  | case 0: { | 
|  | SkPath path; | 
|  | path.addOval(r); | 
|  | show_glframe(canvas, path); | 
|  | } break; | 
|  | case 1: | 
|  | case 3: { | 
|  | SkPath src, dst; | 
|  | src.addOval(r); | 
|  | tesselate(src, &dst); | 
|  | show_fan(canvas, dst, r.centerX(), r.centerY()); | 
|  | } break; | 
|  | case 2: { | 
|  | SkPaint p(paint); | 
|  | show_mesh(canvas, r); | 
|  | setGLFrame(&p); | 
|  | paint.setStyle(SkPaint::kFill_Style); | 
|  | canvas->drawCircle(r.centerX(), r.centerY(), 3, p); | 
|  | } break; | 
|  | } | 
|  | } | 
|  |  | 
|  | canvas->translate(320, 0); | 
|  |  | 
|  | paint.setStyle(SkPaint::kStroke_Style); | 
|  | paint.setStrokeWidth(25); | 
|  | canvas->drawOval(r, paint); | 
|  | if (showGL) { | 
|  | switch (flags) { | 
|  | case 0: { | 
|  | SkPath path; | 
|  | SkScalar rad = paint.getStrokeWidth() / 2; | 
|  | r.outset(rad, rad); | 
|  | path.addOval(r); | 
|  | r.inset(rad*2, rad*2); | 
|  | path.addOval(r); | 
|  | show_glframe(canvas, path); | 
|  | } break; | 
|  | case 1: { | 
|  | SkPath path0, path1; | 
|  | SkScalar rad = paint.getStrokeWidth() / 2; | 
|  | r.outset(rad, rad); | 
|  | path0.addOval(r); | 
|  | r.inset(rad*2, rad*2); | 
|  | path1.addOval(r); | 
|  | show_mesh_between(canvas, path0, path1); | 
|  | } break; | 
|  | case 2: { | 
|  | SkPath path; | 
|  | path.addOval(r); | 
|  | show_glframe(canvas, path); | 
|  | SkScalar rad = paint.getStrokeWidth() / 2; | 
|  | r.outset(rad, rad); | 
|  | show_mesh(canvas, r); | 
|  | } break; | 
|  | case 3: { | 
|  | SkScalar rad = paint.getStrokeWidth() / 2; | 
|  | r.outset(rad, rad); | 
|  | SkPaint paint; | 
|  | paint.setAlpha(0x33); | 
|  | canvas->drawRect(r, paint); | 
|  | show_mesh(canvas, r); | 
|  | } break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #include "SkImageDecoder.h" | 
|  |  | 
|  | static void draw_image(SkCanvas* canvas, bool showGL, int flags) { | 
|  | SkPaint paint; | 
|  | paint.setAntiAlias(true); | 
|  | paint.setFilterBitmap(true); | 
|  | setFade(&paint, showGL); | 
|  |  | 
|  | static SkBitmap* gBM; | 
|  | if (NULL == gBM) { | 
|  | gBM = new SkBitmap; | 
|  | SkImageDecoder::DecodeFile("/skimages/startrek.png", gBM); | 
|  | } | 
|  | SkRect r = SkRect::MakeWH(gBM->width(), gBM->height()); | 
|  |  | 
|  | canvas->save(); | 
|  | canvas->translate(30, 30); | 
|  | canvas->scale(0.8f, 0.8f); | 
|  | canvas->drawBitmap(*gBM, 0, 0, &paint); | 
|  | if (showGL) { | 
|  | show_mesh(canvas, r); | 
|  | } | 
|  | canvas->restore(); | 
|  |  | 
|  | canvas->translate(210, 290); | 
|  | canvas->rotate(-35); | 
|  | canvas->drawBitmap(*gBM, 0, 0, &paint); | 
|  | if (showGL) { | 
|  | show_mesh(canvas, r); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void draw_text(SkCanvas* canvas, bool showGL, int flags) { | 
|  | SkPaint paint; | 
|  | paint.setAntiAlias(true); | 
|  | paint.setLCDRenderText(true); | 
|  | const char text[] = "Graphics at Google"; | 
|  | size_t len = strlen(text); | 
|  | setFade(&paint, showGL); | 
|  |  | 
|  | canvas->translate(40, 50); | 
|  | for (int i = 0; i < 10; ++i) { | 
|  | paint.setTextSize(12 + i * 3); | 
|  | canvas->drawText(text, len, 0, 0, paint); | 
|  | if (showGL) { | 
|  | SkRect bounds[256]; | 
|  | SkScalar widths[256]; | 
|  | int count = paint.getTextWidths(text, len, widths, bounds); | 
|  | SkScalar adv = 0; | 
|  | for (int j = 0; j < count; ++j) { | 
|  | bounds[j].offset(adv, 0); | 
|  | show_mesh(canvas, bounds[j]); | 
|  | adv += widths[j]; | 
|  | } | 
|  | } | 
|  | canvas->translate(0, paint.getTextSize() * 3 / 2); | 
|  | } | 
|  | } | 
|  |  | 
|  | static const struct { | 
|  | DrawProc    fProc; | 
|  | const char* fName; | 
|  | } gRec[] = { | 
|  | {   draw_line,  "Lines" }, | 
|  | {   draw_rect,  "Rects" }, | 
|  | {   draw_oval,  "Ovals" }, | 
|  | {   draw_image, "Images" }, | 
|  | {   draw_text,  "Text" }, | 
|  | }; | 
|  |  | 
|  | class TalkGM : public skiagm::GM { | 
|  | DrawProc fProc; | 
|  | SkString fName; | 
|  | bool     fShowGL; | 
|  | int      fFlags; | 
|  |  | 
|  | public: | 
|  | TalkGM(int index, bool showGL, int flags = 0) { | 
|  | fProc = gRec[index].fProc; | 
|  | fName.set(gRec[index].fName); | 
|  | if (showGL) { | 
|  | fName.append("-gl"); | 
|  | } | 
|  | fShowGL = showGL; | 
|  | fFlags = flags; | 
|  | } | 
|  |  | 
|  | protected: | 
|  | virtual SkString onShortName() { | 
|  | return fName; | 
|  | } | 
|  |  | 
|  | virtual SkISize onISize() { | 
|  | return SkISize::Make(640, 480); | 
|  | } | 
|  |  | 
|  | virtual void onDraw(SkCanvas* canvas) { | 
|  | SkISize size = canvas->getDeviceSize(); | 
|  | SkRect dst = SkRect::MakeWH(size.width(), size.height()); | 
|  | SkRect src = SkRect::MakeWH(640, 480); | 
|  | SkMatrix matrix; | 
|  | matrix.setRectToRect(src, dst, SkMatrix::kCenter_ScaleToFit); | 
|  |  | 
|  | canvas->concat(matrix); | 
|  | fProc(canvas, fShowGL, fFlags); | 
|  | } | 
|  |  | 
|  | virtual uint32_t onGetFlags() const SK_OVERRIDE { | 
|  | return  kSkipPDF_Flag | kSkipPicture_Flag | kSkipPipe_Flag | kSkipTiled_Flag; | 
|  | } | 
|  |  | 
|  | private: | 
|  | typedef skiagm::GM INHERITED; | 
|  | }; | 
|  |  | 
|  | ////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | #define GM_CONCAT(X,Y) GM_CONCAT_IMPL(X,Y) | 
|  | #define GM_CONCAT_IMPL(X,Y) X##Y | 
|  |  | 
|  | #define FACTORY_NAME  GM_CONCAT(Factory, __LINE__) | 
|  | #define REGISTRY_NAME  GM_CONCAT(gReg, __LINE__) | 
|  |  | 
|  | #define ADD_GM(Class, args)    \ | 
|  | static skiagm::GM* FACTORY_NAME(void*) { return new Class args; } \ | 
|  | static skiagm::GMRegistry REGISTRY_NAME(FACTORY_NAME); | 
|  |  | 
|  | ADD_GM(TalkGM, (0, false)) | 
|  | ADD_GM(TalkGM, (0, true)) | 
|  | ADD_GM(TalkGM, (1, false)) | 
|  | ADD_GM(TalkGM, (1, true)) | 
|  | ADD_GM(TalkGM, (2, false)) | 
|  | ADD_GM(TalkGM, (2, true)) | 
|  | ADD_GM(TalkGM, (2, true, 1)) | 
|  | ADD_GM(TalkGM, (2, true, 2)) | 
|  | ADD_GM(TalkGM, (2, true, 3)) | 
|  | ADD_GM(TalkGM, (3, false)) | 
|  | ADD_GM(TalkGM, (3, true)) | 
|  | ADD_GM(TalkGM, (4, false)) | 
|  | ADD_GM(TalkGM, (4, true)) | 
|  |  | 
|  | //static GM* MyFactory(void*) { return new TalkGM(0, false); } | 
|  | //static GMRegistry reg(MyFactory); |