convexpolyeffect.cpp revision f0b0cda76fce5756aa12df4b807349e6dd85fd20
1
2/*
3 * Copyright 2014 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
9// This test only works with the GPU backend.
10
11#include "gm.h"
12
13#if SK_SUPPORT_GPU
14
15#include "GrContext.h"
16#include "GrPathUtils.h"
17#include "GrTest.h"
18#include "SkColorPriv.h"
19#include "SkDevice.h"
20#include "SkGeometry.h"
21#include "SkTLList.h"
22
23#include "effects/GrConvexPolyEffect.h"
24
25namespace {
26extern const GrVertexAttrib kAttribs[] = {
27    {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
28};
29}
30
31namespace skiagm {
32/**
33 * This GM directly exercises a GrEffect that draws convex polygons.
34 */
35class ConvexPolyEffect : public GM {
36public:
37    ConvexPolyEffect() {
38        this->setBGColor(0xFFFFFFFF);
39    }
40
41protected:
42    virtual SkString onShortName() SK_OVERRIDE {
43        return SkString("convex_poly_effect");
44    }
45
46    virtual SkISize onISize() SK_OVERRIDE {
47        return make_isize(475, 800);
48    }
49
50    virtual uint32_t onGetFlags() const SK_OVERRIDE {
51        // This is a GPU-specific GM.
52        return kGPUOnly_Flag;
53    }
54
55    virtual void onOnceBeforeDraw() SK_OVERRIDE {
56        SkPath tri;
57        tri.moveTo(5.f, 5.f);
58        tri.lineTo(100.f, 20.f);
59        tri.lineTo(15.f, 100.f);
60
61        fPaths.addToTail(tri);
62        fPaths.addToTail(SkPath())->reverseAddPath(tri);
63
64        tri.close();
65        fPaths.addToTail(tri);
66
67        SkPath ngon;
68        static const SkScalar kRadius = 50.f;
69        const SkPoint center = { kRadius, kRadius };
70        for (int i = 0; i < GrConvexPolyEffect::kMaxEdges; ++i) {
71            SkScalar angle = 2 * SK_ScalarPI * i / GrConvexPolyEffect::kMaxEdges;
72            SkPoint point;
73            point.fY = SkScalarSinCos(angle, &point.fX);
74            point.scale(kRadius);
75            point = center + point;
76            if (0 == i) {
77                ngon.moveTo(point);
78            } else {
79                ngon.lineTo(point);
80            }
81        }
82
83        fPaths.addToTail(ngon);
84        SkMatrix scaleM;
85        scaleM.setScale(1.1f, 0.4f);
86        ngon.transform(scaleM);
87        fPaths.addToTail(ngon);
88
89        // integer edges
90        fRects.addToTail(SkRect::MakeLTRB(5.f, 1.f, 30.f, 25.f));
91        // half-integer edges
92        fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 24.5f));
93        // vertically/horizontally thin rects that cover pixel centers
94        fRects.addToTail(SkRect::MakeLTRB(5.25f, 0.5f, 5.75f, 24.5f));
95        fRects.addToTail(SkRect::MakeLTRB(5.5f,  0.5f, 29.5f, 0.75f));
96        // vertically/horizontally thin rects that don't cover pixel centers
97        fRects.addToTail(SkRect::MakeLTRB(5.55f, 0.5f, 5.75f, 24.5f));
98        fRects.addToTail(SkRect::MakeLTRB(5.5f, .05f, 29.5f, .25f));
99        // small in x and y
100        fRects.addToTail(SkRect::MakeLTRB(5.05f, .55f, 5.45f, .85f));
101        // inverted in x and y
102        fRects.addToTail(SkRect::MakeLTRB(100.f, 50.5f, 5.f, 0.5f));
103
104    }
105
106    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
107        SkBaseDevice* device = canvas->getTopDevice();
108        GrRenderTarget* rt = device->accessRenderTarget();
109        if (NULL == rt) {
110            return;
111        }
112        GrContext* context = rt->getContext();
113        if (NULL == context) {
114            return;
115        }
116
117        SkScalar y = 0;
118        for (SkTLList<SkPath>::Iter iter(fPaths, SkTLList<SkPath>::Iter::kHead_IterStart);
119             NULL != iter.get();
120             iter.next()) {
121            const SkPath* path = iter.get();
122            SkScalar x = 0;
123
124            for (int et = 0; et < GrConvexPolyEffect::kEdgeTypeCnt; ++et) {
125                GrTestTarget tt;
126                context->getTestTarget(&tt);
127                if (NULL == tt.target()) {
128                    SkDEBUGFAIL("Couldn't get Gr test target.");
129                    return;
130                }
131                GrDrawState* drawState = tt.target()->drawState();
132                drawState->setVertexAttribs<kAttribs>(SK_ARRAY_COUNT(kAttribs));
133
134                SkMatrix m;
135                SkPath p;
136                m.setTranslate(x, y);
137                path->transform(m, &p);
138
139                GrConvexPolyEffect::EdgeType edgeType = (GrConvexPolyEffect::EdgeType) et;
140                SkAutoTUnref<GrEffectRef> effect(GrConvexPolyEffect::Create(edgeType, p));
141                if (!effect) {
142                    SkDEBUGFAIL("Couldn't create convex poly effect.");
143                    return;
144                }
145                drawState->addCoverageEffect(effect, 1);
146                drawState->setIdentityViewMatrix();
147                drawState->setRenderTarget(rt);
148                drawState->setColor(0xff000000);
149
150                SkPoint verts[4];
151                SkRect bounds = p.getBounds();
152                // Make sure any artifacts around the exterior of path are visible by using overly
153                // conservative bounding geometry.
154                bounds.outset(5.f, 5.f);
155                bounds.toQuad(verts);
156
157                tt.target()->setVertexSourceToArray(verts, 4);
158                tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
159                tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
160
161                x += SkScalarCeilToScalar(path->getBounds().width() + 10.f);
162            }
163
164            // Draw AA and non AA paths using normal API for reference.
165            canvas->save();
166            canvas->translate(x, y);
167            SkPaint paint;
168            canvas->drawPath(*path, paint);
169            canvas->translate(path->getBounds().width() + 10.f, 0);
170            paint.setAntiAlias(true);
171            canvas->drawPath(*path, paint);
172            canvas->restore();
173
174            y += SkScalarCeilToScalar(path->getBounds().height() + 20.f);
175        }
176
177        // Draw rects. We only have specialized effect code for the AA case, so don't do non-AA.
178        for (SkTLList<SkRect>::Iter iter(fRects, SkTLList<SkRect>::Iter::kHead_IterStart);
179             NULL != iter.get();
180             iter.next()) {
181
182            SkScalar x = 0;
183
184            GrTestTarget tt;
185            context->getTestTarget(&tt);
186            if (NULL == tt.target()) {
187                SkDEBUGFAIL("Couldn't get Gr test target.");
188                return;
189            }
190
191            SkRect rect = *iter.get();
192            rect.offset(x, y);
193            SkAutoTUnref<GrEffectRef> effect(GrConvexPolyEffect::CreateForAAFillRect(rect));
194            if (!effect) {
195                SkDEBUGFAIL("Couldn't create convex poly effect.");
196                return;
197            }
198
199            GrDrawState* drawState = tt.target()->drawState();
200            drawState->setVertexAttribs<kAttribs>(SK_ARRAY_COUNT(kAttribs));
201            drawState->addCoverageEffect(effect, 1);
202            drawState->setIdentityViewMatrix();
203            drawState->setRenderTarget(rt);
204            drawState->setColor(0xff000000);
205
206            SkPoint verts[4];
207            SkRect bounds = rect;
208            bounds.outset(5.f, 5.f);
209            bounds.toQuad(verts);
210
211            tt.target()->setVertexSourceToArray(verts, 4);
212            tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
213            tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
214
215            x += SkScalarCeilToScalar(rect.width() + 10.f);
216
217            // Draw AA rect using normal API for reference
218            canvas->save();
219            canvas->translate(x, y);
220            SkPaint paint;
221            paint.setAntiAlias(true);
222            canvas->drawRect(*iter.get(), paint);
223            canvas->restore();
224
225            y += SkScalarCeilToScalar(rect.height() + 20.f);
226        }
227    }
228
229private:
230    SkTLList<SkPath> fPaths;
231    SkTLList<SkRect> fRects;
232
233    typedef GM INHERITED;
234};
235
236DEF_GM( return SkNEW(ConvexPolyEffect); )
237}
238
239#endif
240