Home | History | Annotate | Download | only in gm
      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