1
2/*
3 * Copyright 2011 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 "SampleCode.h"
9#include "SkView.h"
10#include "SkCanvas.h"
11#include "SkCornerPathEffect.h"
12#include "SkCullPoints.h"
13#include "SkGradientShader.h"
14#include "SkPath.h"
15#include "SkRegion.h"
16#include "SkShader.h"
17#include "SkUtils.h"
18#include "SkRandom.h"
19
20static void addbump(SkPath* path, const SkPoint pts[2], SkScalar bump) {
21    SkVector    tang;
22
23    tang.setLength(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY, bump);
24
25    path->lineTo(SkScalarHalf(pts[0].fX + pts[1].fX) - tang.fY,
26                 SkScalarHalf(pts[0].fY + pts[1].fY) + tang.fX);
27    path->lineTo(pts[1]);
28}
29
30static void subdivide(SkPath* path, SkScalar bump) {
31    SkPath::Iter    iter(*path, false);
32    SkPoint         pts[4];
33    SkPath          tmp;
34
35    for (;;)
36        switch (iter.next(pts)) {
37        case SkPath::kMove_Verb:
38            tmp.moveTo(pts[0]);
39            break;
40        case SkPath::kLine_Verb:
41            addbump(&tmp, pts, bump);
42            bump = -bump;
43            break;
44        case SkPath::kDone_Verb:
45            goto FINISH;
46        default:
47            break;
48        }
49
50FINISH:
51    path->swap(tmp);
52}
53
54static SkIPoint* getpts(const SkPath& path, int* count) {
55    SkPoint     pts[4];
56    int         n = 1;
57    SkIPoint*   array;
58
59    {
60        SkPath::Iter    iter(path, false);
61        for (;;)
62            switch (iter.next(pts)) {
63            case SkPath::kLine_Verb:
64                n += 1;
65                break;
66            case SkPath::kDone_Verb:
67                goto FINISHED;
68            default:
69                break;
70            }
71    }
72
73FINISHED:
74    array = new SkIPoint[n];
75    n = 0;
76
77    {
78        SkPath::Iter    iter(path, false);
79        for (;;)
80            switch (iter.next(pts)) {
81            case SkPath::kMove_Verb:
82                array[n++].set(SkScalarRoundToInt(pts[0].fX),
83                               SkScalarRoundToInt(pts[0].fY));
84                break;
85            case SkPath::kLine_Verb:
86                array[n++].set(SkScalarRoundToInt(pts[1].fX),
87                               SkScalarRoundToInt(pts[1].fY));
88                break;
89            case SkPath::kDone_Verb:
90                goto FINISHED2;
91            default:
92                break;
93            }
94    }
95
96FINISHED2:
97    *count = n;
98    return array;
99}
100
101static SkScalar nextScalarRange(SkRandom& rand, SkScalar min, SkScalar max) {
102    return min + SkScalarMul(rand.nextUScalar1(), max - min);
103}
104
105class CullView : public SampleView {
106public:
107    CullView() {
108        fClip.set(0, 0, SkIntToScalar(160), SkIntToScalar(160));
109
110        SkRandom    rand;
111
112        for (int i = 0; i < 50; i++) {
113            SkScalar x = nextScalarRange(rand, -fClip.width()*1, fClip.width()*2);
114            SkScalar y = nextScalarRange(rand, -fClip.height()*1, fClip.height()*2);
115            if (i == 0)
116                fPath.moveTo(x, y);
117            else
118                fPath.lineTo(x, y);
119        }
120
121        SkScalar bump = fClip.width()/8;
122        subdivide(&fPath, bump);
123        subdivide(&fPath, bump);
124        subdivide(&fPath, bump);
125        fPoints = getpts(fPath, &fPtCount);
126
127        this->setBGColor(0xFFDDDDDD);
128    }
129
130    virtual ~CullView() {
131        delete[] fPoints;
132    }
133
134protected:
135    // overrides from SkEventSink
136    virtual bool onQuery(SkEvent* evt) {
137        if (SampleCode::TitleQ(*evt)) {
138            SampleCode::TitleR(evt, "Culling");
139            return true;
140        }
141        return this->INHERITED::onQuery(evt);
142    }
143
144    virtual void onDrawContent(SkCanvas* canvas) {
145        SkAutoCanvasRestore ar(canvas, true);
146
147        canvas->translate(  SkScalarHalf(this->width() - fClip.width()),
148                            SkScalarHalf(this->height() - fClip.height()));
149
150   //     canvas->scale(SK_Scalar1*3, SK_Scalar1*3, 0, 0);
151
152        SkPaint paint;
153
154    //    paint.setAntiAliasOn(true);
155        paint.setStyle(SkPaint::kStroke_Style);
156
157        canvas->drawRect(fClip, paint);
158
159#if 1
160        paint.setColor(0xFF555555);
161        paint.setStrokeWidth(SkIntToScalar(2));
162//        paint.setPathEffect(new SkCornerPathEffect(SkIntToScalar(30)))->unref();
163        canvas->drawPath(fPath, paint);
164//        paint.setPathEffect(NULL);
165#endif
166
167        SkPath  tmp;
168        SkIRect iclip;
169        fClip.round(&iclip);
170
171        SkCullPointsPath    cpp(iclip, &tmp);
172
173        cpp.moveTo(fPoints[0].fX, fPoints[0].fY);
174        for (int i = 0; i < fPtCount; i++)
175            cpp.lineTo(fPoints[i].fX, fPoints[i].fY);
176
177        paint.setColor(SK_ColorRED);
178        paint.setStrokeWidth(SkIntToScalar(3));
179        paint.setStrokeJoin(SkPaint::kRound_Join);
180        canvas->drawPath(tmp, paint);
181
182        this->inval(NULL);
183    }
184
185private:
186    SkRect      fClip;
187    SkIPoint*   fPoints;
188    SkPath      fPath;
189    int         fPtCount;
190
191    typedef SampleView INHERITED;
192};
193
194//////////////////////////////////////////////////////////////////////////////
195
196static SkView* MyFactory() { return new CullView; }
197static SkViewRegister reg(MyFactory);
198