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