|  | 
 | /* | 
 |  * Copyright 2014 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | // This test only works with the GPU backend. | 
 |  | 
 | #include "gm.h" | 
 |  | 
 | #if SK_SUPPORT_GPU | 
 |  | 
 | #include "GrContext.h" | 
 | #include "GrPathUtils.h" | 
 | #include "GrTest.h" | 
 | #include "SkColorPriv.h" | 
 | #include "SkDevice.h" | 
 | #include "SkGeometry.h" | 
 | #include "SkTLList.h" | 
 |  | 
 | #include "effects/GrConvexPolyEffect.h" | 
 |  | 
 | namespace { | 
 | extern const GrVertexAttrib kAttribs[] = { | 
 |     {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, | 
 | }; | 
 | } | 
 |  | 
 | namespace skiagm { | 
 | /** | 
 |  * This GM directly exercises a GrEffect that draws convex polygons. | 
 |  */ | 
 | class ConvexPolyEffect : public GM { | 
 | public: | 
 |     ConvexPolyEffect() { | 
 |         this->setBGColor(0xFFFFFFFF); | 
 |     } | 
 |  | 
 | protected: | 
 |     virtual SkString onShortName() SK_OVERRIDE { | 
 |         return SkString("convex_poly_effect"); | 
 |     } | 
 |  | 
 |     virtual SkISize onISize() SK_OVERRIDE { | 
 |         return make_isize(720, 800); | 
 |     } | 
 |  | 
 |     virtual uint32_t onGetFlags() const SK_OVERRIDE { | 
 |         // This is a GPU-specific GM. | 
 |         return kGPUOnly_Flag; | 
 |     } | 
 |  | 
 |     virtual void onOnceBeforeDraw() SK_OVERRIDE { | 
 |         SkPath tri; | 
 |         tri.moveTo(5.f, 5.f); | 
 |         tri.lineTo(100.f, 20.f); | 
 |         tri.lineTo(15.f, 100.f); | 
 |  | 
 |         fPaths.addToTail(tri); | 
 |         fPaths.addToTail(SkPath())->reverseAddPath(tri); | 
 |  | 
 |         tri.close(); | 
 |         fPaths.addToTail(tri); | 
 |  | 
 |         SkPath ngon; | 
 |         static const SkScalar kRadius = 50.f; | 
 |         const SkPoint center = { kRadius, kRadius }; | 
 |         for (int i = 0; i < GrConvexPolyEffect::kMaxEdges; ++i) { | 
 |             SkScalar angle = 2 * SK_ScalarPI * i / GrConvexPolyEffect::kMaxEdges; | 
 |             SkPoint point; | 
 |             point.fY = SkScalarSinCos(angle, &point.fX); | 
 |             point.scale(kRadius); | 
 |             point = center + point; | 
 |             if (0 == i) { | 
 |                 ngon.moveTo(point); | 
 |             } else { | 
 |                 ngon.lineTo(point); | 
 |             } | 
 |         } | 
 |  | 
 |         fPaths.addToTail(ngon); | 
 |         SkMatrix scaleM; | 
 |         scaleM.setScale(1.1f, 0.4f); | 
 |         ngon.transform(scaleM); | 
 |         fPaths.addToTail(ngon); | 
 |  | 
 |         // integer edges | 
 |         fRects.addToTail(SkRect::MakeLTRB(5.f, 1.f, 30.f, 25.f)); | 
 |         // half-integer edges | 
 |         fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 24.5f)); | 
 |         // vertically/horizontally thin rects that cover pixel centers | 
 |         fRects.addToTail(SkRect::MakeLTRB(5.25f, 0.5f, 5.75f, 24.5f)); | 
 |         fRects.addToTail(SkRect::MakeLTRB(5.5f,  0.5f, 29.5f, 0.75f)); | 
 |         // vertically/horizontally thin rects that don't cover pixel centers | 
 |         fRects.addToTail(SkRect::MakeLTRB(5.55f, 0.5f, 5.75f, 24.5f)); | 
 |         fRects.addToTail(SkRect::MakeLTRB(5.5f, .05f, 29.5f, .25f)); | 
 |         // small in x and y | 
 |         fRects.addToTail(SkRect::MakeLTRB(5.05f, .55f, 5.45f, .85f)); | 
 |         // inverted in x and y | 
 |         fRects.addToTail(SkRect::MakeLTRB(100.f, 50.5f, 5.f, 0.5f)); | 
 |     } | 
 |  | 
 |     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { | 
 |         GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget(); | 
 |         if (NULL == rt) { | 
 |             return; | 
 |         } | 
 |         GrContext* context = rt->getContext(); | 
 |         if (NULL == context) { | 
 |             return; | 
 |         } | 
 |  | 
 |         SkScalar y = 0; | 
 |         for (SkTLList<SkPath>::Iter iter(fPaths, SkTLList<SkPath>::Iter::kHead_IterStart); | 
 |              NULL != iter.get(); | 
 |              iter.next()) { | 
 |             const SkPath* path = iter.get(); | 
 |             SkScalar x = 0; | 
 |  | 
 |             for (int et = 0; et < kGrEffectEdgeTypeCnt; ++et) { | 
 |                 GrTestTarget tt; | 
 |                 context->getTestTarget(&tt); | 
 |                 if (NULL == tt.target()) { | 
 |                     SkDEBUGFAIL("Couldn't get Gr test target."); | 
 |                     return; | 
 |                 } | 
 |                 GrDrawState* drawState = tt.target()->drawState(); | 
 |                 drawState->setVertexAttribs<kAttribs>(SK_ARRAY_COUNT(kAttribs)); | 
 |  | 
 |                 SkMatrix m; | 
 |                 SkPath p; | 
 |                 m.setTranslate(x, y); | 
 |                 path->transform(m, &p); | 
 |  | 
 |                 GrEffectEdgeType edgeType = (GrEffectEdgeType) et; | 
 |                 SkAutoTUnref<GrEffectRef> effect(GrConvexPolyEffect::Create(edgeType, p)); | 
 |                 if (!effect) { | 
 |                     continue; | 
 |                 } | 
 |                 drawState->addCoverageEffect(effect, 1); | 
 |                 drawState->setIdentityViewMatrix(); | 
 |                 drawState->setRenderTarget(rt); | 
 |                 drawState->setColor(0xff000000); | 
 |  | 
 |                 SkPoint verts[4]; | 
 |                 SkRect bounds = p.getBounds(); | 
 |                 // Make sure any artifacts around the exterior of path are visible by using overly | 
 |                 // conservative bounding geometry. | 
 |                 bounds.outset(5.f, 5.f); | 
 |                 bounds.toQuad(verts); | 
 |  | 
 |                 tt.target()->setVertexSourceToArray(verts, 4); | 
 |                 tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer()); | 
 |                 tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6); | 
 |  | 
 |                 x += SkScalarCeilToScalar(path->getBounds().width() + 10.f); | 
 |             } | 
 |  | 
 |             // Draw AA and non AA paths using normal API for reference. | 
 |             canvas->save(); | 
 |             canvas->translate(x, y); | 
 |             SkPaint paint; | 
 |             canvas->drawPath(*path, paint); | 
 |             canvas->translate(path->getBounds().width() + 10.f, 0); | 
 |             paint.setAntiAlias(true); | 
 |             canvas->drawPath(*path, paint); | 
 |             canvas->restore(); | 
 |  | 
 |             y += SkScalarCeilToScalar(path->getBounds().height() + 20.f); | 
 |         } | 
 |  | 
 |         for (SkTLList<SkRect>::Iter iter(fRects, SkTLList<SkRect>::Iter::kHead_IterStart); | 
 |              NULL != iter.get(); | 
 |              iter.next()) { | 
 |  | 
 |             SkScalar x = 0; | 
 |  | 
 |             for (int et = 0; et < kGrEffectEdgeTypeCnt; ++et) { | 
 |                 GrTestTarget tt; | 
 |                 context->getTestTarget(&tt); | 
 |                 if (NULL == tt.target()) { | 
 |                     SkDEBUGFAIL("Couldn't get Gr test target."); | 
 |                     return; | 
 |                 } | 
 |                 SkRect rect = *iter.get(); | 
 |                 rect.offset(x, y); | 
 |                 GrEffectEdgeType edgeType = (GrEffectEdgeType) et; | 
 |                 SkAutoTUnref<GrEffectRef> effect(GrConvexPolyEffect::Create(edgeType, rect)); | 
 |                 if (!effect) { | 
 |                     continue; | 
 |                 } | 
 |  | 
 |                 GrDrawState* drawState = tt.target()->drawState(); | 
 |                 drawState->setVertexAttribs<kAttribs>(SK_ARRAY_COUNT(kAttribs)); | 
 |                 drawState->addCoverageEffect(effect, 1); | 
 |                 drawState->setIdentityViewMatrix(); | 
 |                 drawState->setRenderTarget(rt); | 
 |                 drawState->setColor(0xff000000); | 
 |  | 
 |                 SkPoint verts[4]; | 
 |                 SkRect bounds = rect; | 
 |                 bounds.outset(5.f, 5.f); | 
 |                 bounds.toQuad(verts); | 
 |  | 
 |                 tt.target()->setVertexSourceToArray(verts, 4); | 
 |                 tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer()); | 
 |                 tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6); | 
 |  | 
 |                 x += SkScalarCeilToScalar(rect.width() + 10.f); | 
 |             } | 
 |  | 
 |             // Draw rect without and with AA using normal API for reference | 
 |             canvas->save(); | 
 |             canvas->translate(x, y); | 
 |             SkPaint paint; | 
 |             canvas->drawRect(*iter.get(), paint); | 
 |             x += SkScalarCeilToScalar(iter.get()->width() + 10.f); | 
 |             paint.setAntiAlias(true); | 
 |             canvas->drawRect(*iter.get(), paint); | 
 |             canvas->restore(); | 
 |  | 
 |             y += SkScalarCeilToScalar(iter.get()->height() + 20.f); | 
 |         } | 
 |     } | 
 |  | 
 | private: | 
 |     SkTLList<SkPath> fPaths; | 
 |     SkTLList<SkRect> fRects; | 
 |  | 
 |     typedef GM INHERITED; | 
 | }; | 
 |  | 
 | DEF_GM( return SkNEW(ConvexPolyEffect); ) | 
 | } | 
 |  | 
 | #endif |