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