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