Home | History | Annotate | Download | only in samplecode
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "sk_tool_utils.h"
      9 #include "SampleCode.h"
     10 #include "SkView.h"
     11 #include "SkCanvas.h"
     12 #include "SkPath.h"
     13 #include "SkRegion.h"
     14 #include "SkShader.h"
     15 #include "SkUtils.h"
     16 #include "SkImage.h"
     17 #include "SkSurface.h"
     18 
     19 #define FAT_PIXEL_COLOR     SK_ColorBLACK
     20 #define PIXEL_CENTER_SIZE   3
     21 #define WIRE_FRAME_COLOR    0xFFFF0000  /*0xFF00FFFF*/
     22 #define WIRE_FRAME_SIZE     1.5f
     23 
     24 static SkScalar apply_grid(SkScalar x) {
     25     const SkScalar grid = 2;
     26     return SkScalarRoundToScalar(x * grid) / grid;
     27 }
     28 
     29 static void apply_grid(SkPoint pts[], int count) {
     30     for (int i = 0; i < count; ++i) {
     31         pts[i].set(apply_grid(pts[i].fX), apply_grid(pts[i].fY));
     32     }
     33 }
     34 
     35 static void erase(SkSurface* surface) {
     36     surface->getCanvas()->clear(SK_ColorTRANSPARENT);
     37 }
     38 
     39 class FatBits {
     40 public:
     41     FatBits() {
     42         fAA = false;
     43         fStyle = kHair_Style;
     44         fGrid = false;
     45         fShowSkeleton = true;
     46         fUseGPU = false;
     47         fUseClip = false;
     48         fRectAsOval = false;
     49         fUseTriangle = false;
     50         fStrokeCap = SkPaint::kButt_Cap;
     51 
     52         fClipRect.set(2, 2, 11, 8 );
     53     }
     54 
     55     int getZoom() const { return fZoom; }
     56 
     57     bool getAA() const { return fAA; }
     58     void setAA(bool aa) { fAA = aa; }
     59 
     60     bool getGrid() const { return fGrid; }
     61     void setGrid(bool g) { fGrid = g; }
     62 
     63     bool getShowSkeleton() const { return fShowSkeleton; }
     64     void setShowSkeleton(bool ss) { fShowSkeleton = ss; }
     65 
     66     bool getUseGPU() const { return fUseGPU; }
     67     void setUseGPU(bool ug) { fUseGPU = ug; }
     68 
     69     bool getTriangle() const { return fUseTriangle; }
     70     void setTriangle(bool ut) { fUseTriangle = ut; }
     71 
     72     void toggleRectAsOval() { fRectAsOval = !fRectAsOval; }
     73 
     74     bool getUseClip() const { return fUseClip; }
     75     void setUseClip(bool uc) { fUseClip = uc; }
     76 
     77     enum Style {
     78         kHair_Style,
     79         kStroke_Style,
     80     };
     81     Style getStyle() const { return fStyle; }
     82     void setStyle(Style s) { fStyle = s; }
     83 
     84     void setWHZ(int width, int height, int zoom) {
     85         fW = width;
     86         fH = height;
     87         fZoom = zoom;
     88         fBounds.set(0, 0, SkIntToScalar(width * zoom), SkIntToScalar(height * zoom));
     89         fMatrix.setScale(SkIntToScalar(zoom), SkIntToScalar(zoom));
     90         fInverse.setScale(SK_Scalar1 / zoom, SK_Scalar1 / zoom);
     91         fShader.reset(sk_tool_utils::create_checkerboard_shader(
     92                               0xFFCCCCCC, 0xFFFFFFFF, zoom));
     93 
     94         SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
     95         fMinSurface.reset(SkSurface::NewRaster(info));
     96         info = info.makeWH(width * zoom, height * zoom);
     97         fMaxSurface.reset(SkSurface::NewRaster(info));
     98     }
     99 
    100     void drawBG(SkCanvas*);
    101     void drawFG(SkCanvas*);
    102     void drawLine(SkCanvas*, SkPoint pts[2]);
    103     void drawRect(SkCanvas* canvas, SkPoint pts[2]);
    104     void drawTriangle(SkCanvas* canvas, SkPoint pts[3]);
    105 
    106     SkPaint::Cap fStrokeCap;
    107 
    108 private:
    109     bool fAA, fGrid, fShowSkeleton, fUseGPU, fUseClip, fRectAsOval, fUseTriangle;
    110     Style fStyle;
    111     int fW, fH, fZoom;
    112     SkMatrix fMatrix, fInverse;
    113     SkRect   fBounds, fClipRect;
    114     SkAutoTUnref<SkShader> fShader;
    115     SkAutoTUnref<SkSurface> fMinSurface;
    116     SkAutoTUnref<SkSurface> fMaxSurface;
    117 
    118     void setupPaint(SkPaint* paint) {
    119         bool aa = this->getAA();
    120         paint->setStrokeCap(fStrokeCap);
    121         switch (fStyle) {
    122             case kHair_Style:
    123                 paint->setStrokeWidth(0);
    124                 break;
    125             case kStroke_Style:
    126                 paint->setStrokeWidth(SK_Scalar1);
    127                 break;
    128         }
    129         paint->setAntiAlias(aa);
    130     }
    131 
    132     void setupSkeletonPaint(SkPaint* paint) {
    133         paint->setStyle(SkPaint::kStroke_Style);
    134         paint->setStrokeWidth(WIRE_FRAME_SIZE);
    135         paint->setColor(fShowSkeleton ? WIRE_FRAME_COLOR : 0);
    136         paint->setAntiAlias(true);
    137     }
    138 
    139     void drawTriangleSkeleton(SkCanvas* max, const SkPoint pts[]);
    140     void drawLineSkeleton(SkCanvas* max, const SkPoint pts[]);
    141     void drawRectSkeleton(SkCanvas* max, const SkRect& r) {
    142         SkPaint paint;
    143         this->setupSkeletonPaint(&paint);
    144         SkPath path;
    145 
    146         if (fUseGPU && fAA) {
    147             SkRect rr = r;
    148             rr.inset(SkIntToScalar(fZoom)/2, SkIntToScalar(fZoom)/2);
    149             path.addRect(rr);
    150             path.moveTo(rr.fLeft, rr.fTop);
    151             path.lineTo(rr.fRight, rr.fBottom);
    152             rr = r;
    153             rr.inset(-SkIntToScalar(fZoom)/2, -SkIntToScalar(fZoom)/2);
    154             path.addRect(rr);
    155         } else {
    156             fRectAsOval ? path.addOval(r) : path.addRect(r);
    157             if (fUseGPU) {
    158                 path.moveTo(r.fLeft, r.fTop);
    159                 path.lineTo(r.fRight, r.fBottom);
    160             }
    161         }
    162         max->drawPath(path, paint);
    163     }
    164 
    165     void copyMinToMax() {
    166         erase(fMaxSurface);
    167         SkCanvas* canvas = fMaxSurface->getCanvas();
    168         canvas->save();
    169         canvas->concat(fMatrix);
    170         fMinSurface->draw(canvas, 0, 0, nullptr);
    171         canvas->restore();
    172 
    173         SkPaint paint;
    174         paint.setXfermodeMode(SkXfermode::kClear_Mode);
    175         for (int iy = 1; iy < fH; ++iy) {
    176             SkScalar y = SkIntToScalar(iy * fZoom);
    177             canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint);
    178         }
    179         for (int ix = 1; ix < fW; ++ix) {
    180             SkScalar x = SkIntToScalar(ix * fZoom);
    181             canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint);
    182         }
    183     }
    184 };
    185 
    186 void FatBits::drawBG(SkCanvas* canvas) {
    187     SkPaint paint;
    188 
    189     paint.setShader(fShader);
    190     canvas->drawRect(fBounds, paint);
    191     paint.setShader(nullptr);
    192 }
    193 
    194 void FatBits::drawFG(SkCanvas* canvas) {
    195     SkPaint inner, outer;
    196 
    197     inner.setAntiAlias(true);
    198     inner.setColor(SK_ColorBLACK);
    199     inner.setStrokeWidth(PIXEL_CENTER_SIZE);
    200 
    201     outer.setAntiAlias(true);
    202     outer.setColor(SK_ColorWHITE);
    203     outer.setStrokeWidth(PIXEL_CENTER_SIZE + 2);
    204 
    205     SkScalar half = SkIntToScalar(fZoom) / 2;
    206     for (int iy = 0; iy < fH; ++iy) {
    207         SkScalar y = SkIntToScalar(iy * fZoom) + half;
    208         for (int ix = 0; ix < fW; ++ix) {
    209             SkScalar x = SkIntToScalar(ix * fZoom) + half;
    210 
    211             canvas->drawPoint(x, y, outer);
    212             canvas->drawPoint(x, y, inner);
    213         }
    214     }
    215 
    216     if (fUseClip) {
    217         SkPaint p;
    218         p.setStyle(SkPaint::kStroke_Style);
    219         p.setColor(SK_ColorLTGRAY);
    220         SkRect r = {
    221             fClipRect.fLeft * fZoom,
    222             fClipRect.fTop * fZoom,
    223             fClipRect.fRight * fZoom,
    224             fClipRect.fBottom * fZoom
    225         };
    226         canvas->drawRect(r, p);
    227     }
    228 }
    229 
    230 void FatBits::drawLineSkeleton(SkCanvas* max, const SkPoint pts[]) {
    231     SkPaint paint;
    232     this->setupSkeletonPaint(&paint);
    233 
    234     SkPath path;
    235     path.moveTo(pts[0]);
    236     path.lineTo(pts[1]);
    237 
    238     switch (fStyle) {
    239         case kHair_Style:
    240             if (fUseGPU) {
    241                 SkPaint p;
    242                 p.setStyle(SkPaint::kStroke_Style);
    243                 p.setStrokeWidth(SK_Scalar1 * fZoom);
    244                 SkPath dst;
    245                 p.getFillPath(path, &dst);
    246                 path.addPath(dst);
    247             }
    248             break;
    249         case kStroke_Style: {
    250             SkPaint p;
    251             p.setStyle(SkPaint::kStroke_Style);
    252             p.setStrokeWidth(SK_Scalar1 * fZoom);
    253             p.setStrokeCap(fStrokeCap);
    254             SkPath dst;
    255             p.getFillPath(path, &dst);
    256             path = dst;
    257 
    258             path.moveTo(pts[0]);
    259             path.lineTo(pts[1]);
    260 
    261             if (fUseGPU) {
    262                 path.moveTo(dst.getPoint(0));
    263                 path.lineTo(dst.getPoint(2));
    264             }
    265         } break;
    266     }
    267     max->drawPath(path, paint);
    268 }
    269 
    270 void FatBits::drawLine(SkCanvas* canvas, SkPoint pts[]) {
    271     SkPaint paint;
    272 
    273     fInverse.mapPoints(pts, 2);
    274 
    275     if (fGrid) {
    276         apply_grid(pts, 2);
    277     }
    278 
    279     erase(fMinSurface);
    280     this->setupPaint(&paint);
    281     paint.setColor(FAT_PIXEL_COLOR);
    282     if (fUseClip) {
    283         fMinSurface->getCanvas()->save();
    284         SkRect r = fClipRect;
    285         r.inset(SK_Scalar1/3, SK_Scalar1/3);
    286         fMinSurface->getCanvas()->clipRect(r, SkRegion::kIntersect_Op, true);
    287     }
    288     fMinSurface->getCanvas()->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
    289     if (fUseClip) {
    290         fMinSurface->getCanvas()->restore();
    291     }
    292     this->copyMinToMax();
    293 
    294     SkCanvas* max = fMaxSurface->getCanvas();
    295 
    296     fMatrix.mapPoints(pts, 2);
    297     this->drawLineSkeleton(max, pts);
    298 
    299     fMaxSurface->draw(canvas, 0, 0, nullptr);
    300 }
    301 
    302 void FatBits::drawRect(SkCanvas* canvas, SkPoint pts[2]) {
    303     SkPaint paint;
    304 
    305     fInverse.mapPoints(pts, 2);
    306 
    307     if (fGrid) {
    308         apply_grid(pts, 2);
    309     }
    310 
    311     SkRect r;
    312     r.set(pts, 2);
    313 
    314     erase(fMinSurface);
    315     this->setupPaint(&paint);
    316     paint.setColor(FAT_PIXEL_COLOR);
    317     {
    318         SkCanvas* c = fMinSurface->getCanvas();
    319         fRectAsOval ? c->drawOval(r, paint) : c->drawRect(r, paint);
    320     }
    321     this->copyMinToMax();
    322 
    323     SkCanvas* max = fMaxSurface->getCanvas();
    324 
    325     fMatrix.mapPoints(pts, 2);
    326     r.set(pts, 2);
    327     this->drawRectSkeleton(max, r);
    328 
    329     fMaxSurface->draw(canvas, 0, 0, nullptr);
    330 }
    331 
    332 void FatBits::drawTriangleSkeleton(SkCanvas* max, const SkPoint pts[]) {
    333     SkPaint paint;
    334     this->setupSkeletonPaint(&paint);
    335 
    336     SkPath path;
    337     path.moveTo(pts[0]);
    338     path.lineTo(pts[1]);
    339     path.lineTo(pts[2]);
    340     path.close();
    341 
    342     max->drawPath(path, paint);
    343 }
    344 
    345 void FatBits::drawTriangle(SkCanvas* canvas, SkPoint pts[3]) {
    346     SkPaint paint;
    347 
    348     fInverse.mapPoints(pts, 3);
    349 
    350     if (fGrid) {
    351         apply_grid(pts, 3);
    352     }
    353 
    354     SkPath path;
    355     path.moveTo(pts[0]);
    356     path.lineTo(pts[1]);
    357     path.lineTo(pts[2]);
    358     path.close();
    359 
    360     erase(fMinSurface);
    361     this->setupPaint(&paint);
    362     paint.setColor(FAT_PIXEL_COLOR);
    363     fMinSurface->getCanvas()->drawPath(path, paint);
    364     this->copyMinToMax();
    365 
    366     SkCanvas* max = fMaxSurface->getCanvas();
    367 
    368     fMatrix.mapPoints(pts, 3);
    369     this->drawTriangleSkeleton(max, pts);
    370 
    371     fMaxSurface->draw(canvas, 0, 0, nullptr);
    372 }
    373 
    374 ///////////////////////////////////////////////////////////////////////////////////////////////////
    375 
    376 class IndexClick : public SkView::Click {
    377     int fIndex;
    378 public:
    379     IndexClick(SkView* v, int index) : SkView::Click(v), fIndex(index) {}
    380 
    381     static int GetIndex(SkView::Click* click) {
    382         return ((IndexClick*)click)->fIndex;
    383     }
    384 };
    385 
    386 class DrawLineView : public SampleView {
    387     enum {
    388         kZoom = 96
    389     };
    390 
    391     FatBits fFB;
    392     SkPoint fPts[3];
    393     bool    fIsRect;
    394 public:
    395     DrawLineView() {
    396         fFB.setWHZ(24, 16, kZoom);
    397         fPts[0].set(1, 1);
    398         fPts[1].set(5, 4);
    399         fPts[2].set(2, 6);
    400         SkMatrix::MakeScale(kZoom, kZoom).mapPoints(fPts, 3);
    401         fIsRect = false;
    402     }
    403 
    404     void setStyle(FatBits::Style s) {
    405         fFB.setStyle(s);
    406         this->inval(nullptr);
    407     }
    408 
    409 protected:
    410     bool onQuery(SkEvent* evt) override {
    411         if (SampleCode::TitleQ(*evt)) {
    412             SampleCode::TitleR(evt, "FatBits");
    413             return true;
    414         }
    415         SkUnichar uni;
    416         if (SampleCode::CharQ(*evt, &uni)) {
    417             switch (uni) {
    418                 case 'c':
    419                     fFB.setUseClip(!fFB.getUseClip());
    420                     this->inval(nullptr);
    421                     return true;
    422                 case 'r':
    423                     fIsRect = !fIsRect;
    424                     this->inval(nullptr);
    425                     return true;
    426                 case 'o':
    427                     fFB.toggleRectAsOval();
    428                     this->inval(nullptr);
    429                     return true;
    430                 case 'x':
    431                     fFB.setGrid(!fFB.getGrid());
    432                     this->inval(nullptr);
    433                     return true;
    434                 case 's':
    435                     if (FatBits::kStroke_Style == fFB.getStyle()) {
    436                         this->setStyle(FatBits::kHair_Style);
    437                     } else {
    438                         this->setStyle(FatBits::kStroke_Style);
    439                     }
    440                     return true;
    441                 case 'k': {
    442                     const SkPaint::Cap caps[] = {
    443                         SkPaint::kButt_Cap, SkPaint::kRound_Cap, SkPaint::kSquare_Cap,
    444                     };
    445                     fFB.fStrokeCap = caps[(fFB.fStrokeCap + 1) % 3];
    446                     this->inval(nullptr);
    447                     return true;
    448                 } break;
    449                 case 'a':
    450                     fFB.setAA(!fFB.getAA());
    451                     this->inval(nullptr);
    452                     return true;
    453                 case 'w':
    454                     fFB.setShowSkeleton(!fFB.getShowSkeleton());
    455                     this->inval(nullptr);
    456                     return true;
    457                 case 'g':
    458                     fFB.setUseGPU(!fFB.getUseGPU());
    459                     this->inval(nullptr);
    460                     return true;
    461                 case 't':
    462                     fFB.setTriangle(!fFB.getTriangle());
    463                     this->inval(nullptr);
    464                     return true;
    465             }
    466         }
    467         return this->INHERITED::onQuery(evt);
    468     }
    469 
    470     void onDrawContent(SkCanvas* canvas) override {
    471         fFB.drawBG(canvas);
    472         if (fFB.getTriangle()) {
    473             fFB.drawTriangle(canvas, fPts);
    474         }
    475         else if (fIsRect) {
    476             fFB.drawRect(canvas, fPts);
    477         } else {
    478             fFB.drawLine(canvas, fPts);
    479         }
    480         fFB.drawFG(canvas);
    481 
    482         {
    483             SkString str;
    484             str.printf("%s %s %s %s",
    485                        fFB.getAA() ? "AA" : "BW",
    486                        FatBits::kHair_Style == fFB.getStyle() ? "Hair" : "Stroke",
    487                        fFB.getUseGPU() ? "GPU" : "CPU",
    488                        fFB.getUseClip() ? "clip" : "noclip");
    489             SkPaint paint;
    490             paint.setAntiAlias(true);
    491             paint.setTextSize(16);
    492             paint.setColor(SK_ColorBLUE);
    493             canvas->drawText(str.c_str(), str.size(), 10, 16, paint);
    494         }
    495     }
    496 
    497     SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
    498         SkPoint pt = { x, y };
    499         int index = -1;
    500         int count = fFB.getTriangle() ? 3 : 2;
    501         SkScalar tol = 12;
    502 
    503         for (int i = 0; i < count; ++i) {
    504             if (fPts[i].equalsWithinTolerance(pt, tol)) {
    505                 index = i;
    506                 break;
    507             }
    508         }
    509         return new IndexClick(this, index);
    510     }
    511 
    512     bool onClick(Click* click) override {
    513         int index = IndexClick::GetIndex(click);
    514         if (index >= 0 && index <= 2) {
    515             fPts[index] = click->fCurr;
    516         } else {
    517             SkScalar dx = click->fCurr.fX - click->fPrev.fX;
    518             SkScalar dy = click->fCurr.fY - click->fPrev.fY;
    519             fPts[0].offset(dx, dy);
    520             fPts[1].offset(dx, dy);
    521             fPts[2].offset(dx, dy);
    522         }
    523         this->inval(nullptr);
    524         return true;
    525     }
    526 
    527 private:
    528 
    529     typedef SampleView INHERITED;
    530 };
    531 
    532 //////////////////////////////////////////////////////////////////////////////
    533 
    534 static SkView* MyFactory() { return new DrawLineView; }
    535 static SkViewRegister reg(MyFactory);
    536