|  |  | 
|  | /* | 
|  | * Copyright 2011 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  | #include "SampleCode.h" | 
|  | #include "SkView.h" | 
|  | #include "SkCanvas.h" | 
|  | #include "SkCornerPathEffect.h" | 
|  | #include "SkCullPoints.h" | 
|  | #include "SkGradientShader.h" | 
|  | #include "SkPath.h" | 
|  | #include "SkRegion.h" | 
|  | #include "SkShader.h" | 
|  | #include "SkUtils.h" | 
|  | #include "SkRandom.h" | 
|  |  | 
|  | static void addbump(SkPath* path, const SkPoint pts[2], SkScalar bump) { | 
|  | SkVector    tang; | 
|  |  | 
|  | tang.setLength(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY, bump); | 
|  |  | 
|  | path->lineTo(SkScalarHalf(pts[0].fX + pts[1].fX) - tang.fY, | 
|  | SkScalarHalf(pts[0].fY + pts[1].fY) + tang.fX); | 
|  | path->lineTo(pts[1]); | 
|  | } | 
|  |  | 
|  | static void subdivide(SkPath* path, SkScalar bump) { | 
|  | SkPath::Iter    iter(*path, false); | 
|  | SkPoint         pts[4]; | 
|  | SkPath          tmp; | 
|  |  | 
|  | for (;;) | 
|  | switch (iter.next(pts)) { | 
|  | case SkPath::kMove_Verb: | 
|  | tmp.moveTo(pts[0]); | 
|  | break; | 
|  | case SkPath::kLine_Verb: | 
|  | addbump(&tmp, pts, bump); | 
|  | bump = -bump; | 
|  | break; | 
|  | case SkPath::kDone_Verb: | 
|  | goto FINISH; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | FINISH: | 
|  | path->swap(tmp); | 
|  | } | 
|  |  | 
|  | static SkIPoint* getpts(const SkPath& path, int* count) { | 
|  | SkPoint     pts[4]; | 
|  | int         n = 1; | 
|  | SkIPoint*   array; | 
|  |  | 
|  | { | 
|  | SkPath::Iter    iter(path, false); | 
|  | for (;;) | 
|  | switch (iter.next(pts)) { | 
|  | case SkPath::kLine_Verb: | 
|  | n += 1; | 
|  | break; | 
|  | case SkPath::kDone_Verb: | 
|  | goto FINISHED; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | FINISHED: | 
|  | array = new SkIPoint[n]; | 
|  | n = 0; | 
|  |  | 
|  | { | 
|  | SkPath::Iter    iter(path, false); | 
|  | for (;;) | 
|  | switch (iter.next(pts)) { | 
|  | case SkPath::kMove_Verb: | 
|  | array[n++].set(SkScalarRoundToInt(pts[0].fX), | 
|  | SkScalarRoundToInt(pts[0].fY)); | 
|  | break; | 
|  | case SkPath::kLine_Verb: | 
|  | array[n++].set(SkScalarRoundToInt(pts[1].fX), | 
|  | SkScalarRoundToInt(pts[1].fY)); | 
|  | break; | 
|  | case SkPath::kDone_Verb: | 
|  | goto FINISHED2; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | FINISHED2: | 
|  | *count = n; | 
|  | return array; | 
|  | } | 
|  |  | 
|  | static SkScalar nextScalarRange(SkRandom& rand, SkScalar min, SkScalar max) { | 
|  | return min + SkScalarMul(rand.nextUScalar1(), max - min); | 
|  | } | 
|  |  | 
|  | class CullView : public SampleView { | 
|  | public: | 
|  | CullView() { | 
|  | fClip.set(0, 0, SkIntToScalar(160), SkIntToScalar(160)); | 
|  |  | 
|  | SkRandom    rand; | 
|  |  | 
|  | for (int i = 0; i < 50; i++) { | 
|  | SkScalar x = nextScalarRange(rand, -fClip.width()*1, fClip.width()*2); | 
|  | SkScalar y = nextScalarRange(rand, -fClip.height()*1, fClip.height()*2); | 
|  | if (i == 0) | 
|  | fPath.moveTo(x, y); | 
|  | else | 
|  | fPath.lineTo(x, y); | 
|  | } | 
|  |  | 
|  | SkScalar bump = fClip.width()/8; | 
|  | subdivide(&fPath, bump); | 
|  | subdivide(&fPath, bump); | 
|  | subdivide(&fPath, bump); | 
|  | fPoints = getpts(fPath, &fPtCount); | 
|  |  | 
|  | this->setBGColor(0xFFDDDDDD); | 
|  | } | 
|  |  | 
|  | virtual ~CullView() { | 
|  | delete[] fPoints; | 
|  | } | 
|  |  | 
|  | protected: | 
|  | // overrides from SkEventSink | 
|  | virtual bool onQuery(SkEvent* evt) { | 
|  | if (SampleCode::TitleQ(*evt)) { | 
|  | SampleCode::TitleR(evt, "Culling"); | 
|  | return true; | 
|  | } | 
|  | return this->INHERITED::onQuery(evt); | 
|  | } | 
|  |  | 
|  | virtual void onDrawContent(SkCanvas* canvas) { | 
|  | SkAutoCanvasRestore ar(canvas, true); | 
|  |  | 
|  | canvas->translate(  SkScalarHalf(this->width() - fClip.width()), | 
|  | SkScalarHalf(this->height() - fClip.height())); | 
|  |  | 
|  | //     canvas->scale(SK_Scalar1*3, SK_Scalar1*3, 0, 0); | 
|  |  | 
|  | SkPaint paint; | 
|  |  | 
|  | //    paint.setAntiAliasOn(true); | 
|  | paint.setStyle(SkPaint::kStroke_Style); | 
|  |  | 
|  | canvas->drawRect(fClip, paint); | 
|  |  | 
|  | #if 1 | 
|  | paint.setColor(0xFF555555); | 
|  | paint.setStrokeWidth(SkIntToScalar(2)); | 
|  | //        paint.setPathEffect(new SkCornerPathEffect(SkIntToScalar(30)))->unref(); | 
|  | canvas->drawPath(fPath, paint); | 
|  | //        paint.setPathEffect(nullptr); | 
|  | #endif | 
|  |  | 
|  | SkPath  tmp; | 
|  | SkIRect iclip; | 
|  | fClip.round(&iclip); | 
|  |  | 
|  | SkCullPointsPath    cpp(iclip, &tmp); | 
|  |  | 
|  | cpp.moveTo(fPoints[0].fX, fPoints[0].fY); | 
|  | for (int i = 0; i < fPtCount; i++) | 
|  | cpp.lineTo(fPoints[i].fX, fPoints[i].fY); | 
|  |  | 
|  | paint.setColor(SK_ColorRED); | 
|  | paint.setStrokeWidth(SkIntToScalar(3)); | 
|  | paint.setStrokeJoin(SkPaint::kRound_Join); | 
|  | canvas->drawPath(tmp, paint); | 
|  |  | 
|  | this->inval(nullptr); | 
|  | } | 
|  |  | 
|  | private: | 
|  | SkRect      fClip; | 
|  | SkIPoint*   fPoints; | 
|  | SkPath      fPath; | 
|  | int         fPtCount; | 
|  |  | 
|  | typedef SampleView INHERITED; | 
|  | }; | 
|  |  | 
|  | ////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | static SkView* MyFactory() { return new CullView; } | 
|  | static SkViewRegister reg(MyFactory); |