| |
| /* |
| * 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); |
| } |
| |
| 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); |