OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2014 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 "GrConvexPolyEffect.h" | |
9 | |
10 #include "gl/GrGLEffect.h" | |
11 #include "gl/GrGLSL.h" | |
12 #include "gl/GrGLVertexEffect.h" | |
13 #include "GrTBackendEffectFactory.h" | |
14 | |
15 #include "SkPath.h" | |
16 | |
17 class GrGLConvexPolyEffect : public GrGLEffect { | |
18 public: | |
19 GrGLConvexPolyEffect(const GrBackendEffectFactory&, const GrDrawEffect&); | |
20 | |
21 virtual void emitCode(GrGLShaderBuilder* builder, | |
22 const GrDrawEffect& drawEffect, | |
23 EffectKey key, | |
24 const char* outputColor, | |
25 const char* inputColor, | |
26 const TransformedCoordsArray&, | |
27 const TextureSamplerArray&) SK_OVERRIDE; | |
28 | |
29 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); | |
30 | |
31 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER RIDE; | |
32 | |
33 private: | |
34 GrGLUniformManager::UniformHandle fEdgeUniform; | |
35 SkScalar fPrevEdges[3 * GrConvexPolyEffect::kMaxE dges]; | |
36 typedef GrGLEffect INHERITED; | |
37 }; | |
38 | |
39 GrGLConvexPolyEffect::GrGLConvexPolyEffect(const GrBackendEffectFactory& factory , | |
40 const GrDrawEffect& drawEffect) | |
41 : INHERITED (factory) { | |
42 fPrevEdges[0] = SK_ScalarNaN; | |
43 } | |
44 | |
45 void GrGLConvexPolyEffect::emitCode(GrGLShaderBuilder* builder, | |
46 const GrDrawEffect& drawEffect, | |
47 EffectKey key, | |
48 const char* outputColor, | |
49 const char* inputColor, | |
50 const TransformedCoordsArray&, | |
51 const TextureSamplerArray& samplers) { | |
52 const GrConvexPolyEffect& cpe = drawEffect.castEffect<GrConvexPolyEffect>(); | |
53 | |
54 const char *edgeArrayName; | |
55 fEdgeUniform = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibil ity, | |
56 kVec3f_GrSLType, | |
57 "edges", | |
58 cpe.getEdgeCount(), | |
59 &edgeArrayName); | |
60 builder->fsCodeAppend("\t\tfloat alpha = 1.0;\n"); | |
61 builder->fsCodeAppend("\t\tfloat edge;\n"); | |
62 const char* fragmentPos = builder->fragmentPosition(); | |
63 for (int i = 0; i < cpe.getEdgeCount(); ++i) { | |
64 builder->fsCodeAppendf("\t\tedge = dot(%s[%d], vec3(%s.x, %s.y, 1));\n", | |
65 edgeArrayName, i, fragmentPos, fragmentPos); | |
66 switch (cpe.getEdgeType()) { | |
67 case GrConvexPolyEffect::kFillAA_EdgeType: | |
68 builder->fsCodeAppend("\t\tedge = clamp(edge, 0.0, 1.0);\n"); | |
69 builder->fsCodeAppend("\t\talpha *= edge;\n"); | |
70 break; | |
71 case GrConvexPolyEffect::kFillNoAA_EdgeType: | |
72 builder->fsCodeAppend("\t\tedge = edge >= 0.5 ? 1.0 : 0.0;\n"); | |
73 builder->fsCodeAppend("\t\talpha *= edge;\n"); | |
74 break; | |
75 } | |
76 } | |
77 | |
78 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, | |
79 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_st r()); | |
80 } | |
81 | |
82 void GrGLConvexPolyEffect::setData(const GrGLUniformManager& uman, const GrDrawE ffect& drawEffect) { | |
83 const GrConvexPolyEffect& cpe = drawEffect.castEffect<GrConvexPolyEffect>(); | |
84 size_t byteSize = 3 * cpe.getEdgeCount() * sizeof(SkScalar); | |
85 if (0 != memcmp(fPrevEdges, cpe.getEdges(), byteSize)) { | |
86 uman.set3fv(fEdgeUniform, cpe.getEdgeCount(), cpe.getEdges()); | |
87 memcpy(fPrevEdges, cpe.getEdges(), byteSize); | |
88 } | |
89 } | |
90 | |
91 GrGLEffect::EffectKey GrGLConvexPolyEffect::GenKey(const GrDrawEffect& drawEffec t, | |
92 const GrGLCaps&) { | |
93 const GrConvexPolyEffect& cpe = drawEffect.castEffect<GrConvexPolyEffect>(); | |
94 GR_STATIC_ASSERT(GrConvexPolyEffect::kEdgeTypeCnt <= 4); | |
95 return (cpe.getEdgeCount() << 2) | cpe.getEdgeType(); | |
96 } | |
97 | |
98 ////////////////////////////////////////////////////////////////////////////// | |
99 | |
100 GrEffectRef* GrConvexPolyEffect::Create(EdgeType type, const SkPath& path) { | |
101 if (path.getSegmentMasks() != SkPath::kLine_SegmentMask || | |
102 !path.isConvex() || | |
103 path.isInverseFillType()) { | |
104 return NULL; | |
105 } | |
106 | |
107 if (path.countPoints() > kMaxEdges) { | |
108 return NULL; | |
109 } | |
110 | |
111 SkPoint pts[kMaxEdges]; | |
112 SkScalar edges[3 * kMaxEdges]; | |
113 | |
114 SkPath::Direction dir; | |
115 SkAssertResult(path.cheapComputeDirection(&dir)); | |
116 | |
117 int count = path.getPoints(pts, kMaxEdges); | |
118 int n = 0; | |
119 for (int lastPt = count - 1, i = 0; i < count; lastPt = i++) { | |
120 if (pts[lastPt] != pts[i]) { | |
121 SkVector v = pts[i] - pts[lastPt]; | |
122 v.normalize(); | |
123 if (SkPath::kCCW_Direction == dir) { | |
124 edges[3 * n] = v.fY; | |
125 edges[3 * n + 1] = -v.fX; | |
126 } else { | |
127 edges[3 * n] = -v.fY; | |
128 edges[3 * n + 1] = v.fX; | |
129 } | |
130 edges[3 * n + 2] = -(edges[3 * n] * pts[i].fX + edges[3 * n + 1] * p ts[i].fY); | |
131 ++n; | |
132 } | |
133 } | |
134 return Create(type, n, edges); | |
135 } | |
136 | |
137 GrConvexPolyEffect::~GrConvexPolyEffect() {} | |
138 | |
139 void GrConvexPolyEffect::getConstantColorComponents(GrColor* color, uint32_t* va lidFlags) const { | |
140 *validFlags = 0; | |
141 } | |
142 | |
143 const GrBackendEffectFactory& GrConvexPolyEffect::getFactory() const { | |
144 return GrTBackendEffectFactory<GrConvexPolyEffect>::getInstance(); | |
145 } | |
146 | |
147 GrConvexPolyEffect::GrConvexPolyEffect(EdgeType edgeType, int n, const SkScalar edges[]) | |
148 : fEdgeType(edgeType) | |
149 , fEdgeCount(n) { | |
150 SkASSERT(n <= kMaxEdges); | |
robertphillips
2014/01/29 20:57:55
Should we just clamp n at kMaxEdges? We could docu
bsalomon
2014/01/29 22:19:42
The Create() function is responsible for handling
| |
151 memcpy(fEdges, edges, 3 * n * sizeof(SkScalar)); | |
152 // Outset the edges by 0.5 so that a pixel with center on an edge is 50% cov ered in the AA case | |
153 // and 100% covered in the non-AA case. | |
154 for (int i = 0; i < n; ++i) { | |
155 fEdges[3 * i + 2] += SK_ScalarHalf; | |
156 } | |
157 this->setWillReadFragmentPosition(); | |
158 } | |
159 | |
160 bool GrConvexPolyEffect::onIsEqual(const GrEffect& other) const { | |
161 const GrConvexPolyEffect& cpe = CastEffect<GrConvexPolyEffect>(other); | |
162 // ignore the fact that 0 == -0 and just use memcmp. | |
163 return (cpe.fEdgeType == fEdgeType && cpe.fEdgeCount == fEdgeCount && | |
164 0 == memcmp(cpe.fEdges, fEdges, 3 * fEdgeCount * sizeof(SkScalar))); | |
165 } | |
166 | |
167 ////////////////////////////////////////////////////////////////////////////// | |
168 | |
169 GR_DEFINE_EFFECT_TEST(GrConvexPolyEffect); | |
170 | |
171 GrEffectRef* GrConvexPolyEffect::TestCreate(SkRandom* random, | |
172 GrContext*, | |
173 const GrDrawTargetCaps& caps, | |
174 GrTexture*[]) { | |
175 EdgeType edgeType = static_cast<EdgeType>(random->nextULessThan(kEdgeTypeCnt )); | |
176 int count = random->nextULessThan(kMaxEdges + 1); | |
177 SkScalar edges[kMaxEdges * 3]; | |
178 for (int i = 0; i < 3 * count; ++i) { | |
179 edges[i] = random->nextSScalar1(); | |
robertphillips
2014/01/29 20:57:55
Don't we need to normalize here?
bsalomon
2014/01/29 22:19:42
Done.
| |
180 } | |
181 | |
182 return GrConvexPolyEffect::Create(edgeType, count, edges); | |
183 } | |
184 | |
OLD | NEW |