|
1 /* |
|
2 * Copyright 2013 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 #ifndef GrBezierEffect_DEFINED |
|
9 #define GrBezierEffect_DEFINED |
|
10 |
|
11 #include "GrDrawTargetCaps.h" |
|
12 #include "GrEffect.h" |
|
13 #include "GrVertexEffect.h" |
|
14 #include "GrTypesPriv.h" |
|
15 |
|
16 /** |
|
17 * Shader is based off of Loop-Blinn Quadratic GPU Rendering |
|
18 * The output of this effect is a hairline edge for conics. |
|
19 * Conics specified by implicit equation K^2 - LM. |
|
20 * K, L, and M, are the first three values of the vertex attribute, |
|
21 * the fourth value is not used. Distance is calculated using a |
|
22 * first order approximation from the taylor series. |
|
23 * Coverage for AA is max(0, 1-distance). |
|
24 * |
|
25 * Test were also run using a second order distance approximation. |
|
26 * There were two versions of the second order approx. The first version |
|
27 * is of roughly the form: |
|
28 * f(q) = |f(p)| - ||f'(p)||*||q-p|| - ||f''(p)||*||q-p||^2. |
|
29 * The second is similar: |
|
30 * f(q) = |f(p)| + ||f'(p)||*||q-p|| + ||f''(p)||*||q-p||^2. |
|
31 * The exact version of the equations can be found in the paper |
|
32 * "Distance Approximations for Rasterizing Implicit Curves" by Gabriel Taubin |
|
33 * |
|
34 * In both versions we solve the quadratic for ||q-p||. |
|
35 * Version 1: |
|
36 * gFM is magnitude of first partials and gFM2 is magnitude of 2nd partials (as derived from paper) |
|
37 * builder->fsCodeAppend("\t\tedgeAlpha = (sqrt(gFM*gFM+4.0*func*gF2M) - gFM)/(2.0*gF2M);\n"); |
|
38 * Version 2: |
|
39 * builder->fsCodeAppend("\t\tedgeAlpha = (gFM - sqrt(gFM*gFM-4.0*func*gF2M))/(2.0*gF2M);\n"); |
|
40 * |
|
41 * Also note that 2nd partials of k,l,m are zero |
|
42 * |
|
43 * When comparing the two second order approximations to the first order approximations, |
|
44 * the following results were found. Version 1 tends to underestimate the distances, thus it |
|
45 * basically increases all the error that we were already seeing in the first order |
|
46 * approx. So this version is not the one to use. Version 2 has the opposite effect |
|
47 * and tends to overestimate the distances. This is much closer to what we are |
|
48 * looking for. It is able to render ellipses (even thin ones) without the need to chop. |
|
49 * However, it can not handle thin hyperbolas well and thus would still rely on |
|
50 * chopping to tighten the clipping. Another side effect of the overestimating is |
|
51 * that the curves become much thinner and "ropey". If all that was ever rendered |
|
52 * were "not too thin" curves and ellipses then 2nd order may have an advantage since |
|
53 * only one geometry would need to be rendered. However no benches were run comparing |
|
54 * chopped first order and non chopped 2nd order. |
|
55 */ |
|
56 class GrGLConicEffect; |
|
57 |
|
58 class GrConicEffect : public GrVertexEffect { |
|
59 public: |
|
60 static GrEffectRef* Create(const GrEffectEdgeType edgeType, const GrDrawTargetCaps& caps) { |
|
61 GR_CREATE_STATIC_EFFECT(gConicFillAA, GrConicEffect, (kFillAA_GrEffectEdgeType)); |
|
62 GR_CREATE_STATIC_EFFECT(gConicHairAA, GrConicEffect, (kHairlineAA_GrEffectEdgeType)); |
|
63 GR_CREATE_STATIC_EFFECT(gConicFillBW, GrConicEffect, (kFillBW_GrEffectEdgeType)); |
|
64 switch (edgeType) { |
|
65 case kFillAA_GrEffectEdgeType: |
|
66 if (!caps.shaderDerivativeSupport()) { |
|
67 return NULL; |
|
68 } |
|
69 gConicFillAA->ref(); |
|
70 return gConicFillAA; |
|
71 case kHairlineAA_GrEffectEdgeType: |
|
72 if (!caps.shaderDerivativeSupport()) { |
|
73 return NULL; |
|
74 } |
|
75 gConicHairAA->ref(); |
|
76 return gConicHairAA; |
|
77 case kFillBW_GrEffectEdgeType: |
|
78 gConicFillBW->ref(); |
|
79 return gConicFillBW; |
|
80 default: |
|
81 return NULL; |
|
82 } |
|
83 } |
|
84 |
|
85 virtual ~GrConicEffect(); |
|
86 |
|
87 static const char* Name() { return "Conic"; } |
|
88 |
|
89 inline bool isAntiAliased() const { return GrEffectEdgeTypeIsAA(fEdgeType); } |
|
90 inline bool isFilled() const { return GrEffectEdgeTypeIsFill(fEdgeType); } |
|
91 inline GrEffectEdgeType getEdgeType() const { return fEdgeType; } |
|
92 |
|
93 typedef GrGLConicEffect GLEffect; |
|
94 |
|
95 virtual void getConstantColorComponents(GrColor* color, |
|
96 uint32_t* validFlags) const SK_OVERRIDE { |
|
97 *validFlags = 0; |
|
98 } |
|
99 |
|
100 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; |
|
101 |
|
102 private: |
|
103 GrConicEffect(GrEffectEdgeType); |
|
104 |
|
105 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE; |
|
106 |
|
107 GrEffectEdgeType fEdgeType; |
|
108 |
|
109 GR_DECLARE_EFFECT_TEST; |
|
110 |
|
111 typedef GrVertexEffect INHERITED; |
|
112 }; |
|
113 |
|
114 /////////////////////////////////////////////////////////////////////////////// |
|
115 /** |
|
116 * The output of this effect is a hairline edge for quadratics. |
|
117 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first |
|
118 * two components of the vertex attribute. At the three control points that define |
|
119 * the Quadratic, u, v have the values {0,0}, {1/2, 0}, and {1, 1} respectively. |
|
120 * Coverage for AA is min(0, 1-distance). 3rd & 4th cimponent unused. |
|
121 * Requires shader derivative instruction support. |
|
122 */ |
|
123 class GrGLQuadEffect; |
|
124 |
|
125 class GrQuadEffect : public GrVertexEffect { |
|
126 public: |
|
127 static GrEffectRef* Create(const GrEffectEdgeType edgeType, const GrDrawTargetCaps& caps) { |
|
128 GR_CREATE_STATIC_EFFECT(gQuadFillAA, GrQuadEffect, (kFillAA_GrEffectEdgeType)); |
|
129 GR_CREATE_STATIC_EFFECT(gQuadHairAA, GrQuadEffect, (kHairlineAA_GrEffectEdgeType)); |
|
130 GR_CREATE_STATIC_EFFECT(gQuadFillBW, GrQuadEffect, (kFillBW_GrEffectEdgeType)); |
|
131 switch (edgeType) { |
|
132 case kFillAA_GrEffectEdgeType: |
|
133 if (!caps.shaderDerivativeSupport()) { |
|
134 return NULL; |
|
135 } |
|
136 gQuadFillAA->ref(); |
|
137 return gQuadFillAA; |
|
138 case kHairlineAA_GrEffectEdgeType: |
|
139 if (!caps.shaderDerivativeSupport()) { |
|
140 return NULL; |
|
141 } |
|
142 gQuadHairAA->ref(); |
|
143 return gQuadHairAA; |
|
144 case kFillBW_GrEffectEdgeType: |
|
145 gQuadFillBW->ref(); |
|
146 return gQuadFillBW; |
|
147 default: |
|
148 return NULL; |
|
149 } |
|
150 } |
|
151 |
|
152 virtual ~GrQuadEffect(); |
|
153 |
|
154 static const char* Name() { return "Quad"; } |
|
155 |
|
156 inline bool isAntiAliased() const { return GrEffectEdgeTypeIsAA(fEdgeType); } |
|
157 inline bool isFilled() const { return GrEffectEdgeTypeIsFill(fEdgeType); } |
|
158 inline GrEffectEdgeType getEdgeType() const { return fEdgeType; } |
|
159 |
|
160 typedef GrGLQuadEffect GLEffect; |
|
161 |
|
162 virtual void getConstantColorComponents(GrColor* color, |
|
163 uint32_t* validFlags) const SK_OVERRIDE { |
|
164 *validFlags = 0; |
|
165 } |
|
166 |
|
167 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; |
|
168 |
|
169 private: |
|
170 GrQuadEffect(GrEffectEdgeType); |
|
171 |
|
172 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE; |
|
173 |
|
174 GrEffectEdgeType fEdgeType; |
|
175 |
|
176 GR_DECLARE_EFFECT_TEST; |
|
177 |
|
178 typedef GrVertexEffect INHERITED; |
|
179 }; |
|
180 |
|
181 ////////////////////////////////////////////////////////////////////////////// |
|
182 /** |
|
183 * Shader is based off of "Resolution Independent Curve Rendering using |
|
184 * Programmable Graphics Hardware" by Loop and Blinn. |
|
185 * The output of this effect is a hairline edge for non rational cubics. |
|
186 * Cubics are specified by implicit equation K^3 - LM. |
|
187 * K, L, and M, are the first three values of the vertex attribute, |
|
188 * the fourth value is not used. Distance is calculated using a |
|
189 * first order approximation from the taylor series. |
|
190 * Coverage for AA is max(0, 1-distance). |
|
191 */ |
|
192 class GrGLCubicEffect; |
|
193 |
|
194 class GrCubicEffect : public GrVertexEffect { |
|
195 public: |
|
196 static GrEffectRef* Create(const GrEffectEdgeType edgeType, const GrDrawTargetCaps& caps) { |
|
197 GR_CREATE_STATIC_EFFECT(gCubicFillAA, GrCubicEffect, (kFillAA_GrEffectEdgeType)); |
|
198 GR_CREATE_STATIC_EFFECT(gCubicHairAA, GrCubicEffect, (kHairlineAA_GrEffectEdgeType)); |
|
199 GR_CREATE_STATIC_EFFECT(gCubicFillBW, GrCubicEffect, (kFillBW_GrEffectEdgeType)); |
|
200 switch (edgeType) { |
|
201 case kFillAA_GrEffectEdgeType: |
|
202 if (!caps.shaderDerivativeSupport()) { |
|
203 return NULL; |
|
204 } |
|
205 gCubicFillAA->ref(); |
|
206 return gCubicFillAA; |
|
207 case kHairlineAA_GrEffectEdgeType: |
|
208 if (!caps.shaderDerivativeSupport()) { |
|
209 return NULL; |
|
210 } |
|
211 gCubicHairAA->ref(); |
|
212 return gCubicHairAA; |
|
213 case kFillBW_GrEffectEdgeType: |
|
214 gCubicFillBW->ref(); |
|
215 return gCubicFillBW; |
|
216 default: |
|
217 return NULL; |
|
218 } |
|
219 } |
|
220 |
|
221 virtual ~GrCubicEffect(); |
|
222 |
|
223 static const char* Name() { return "Cubic"; } |
|
224 |
|
225 inline bool isAntiAliased() const { return GrEffectEdgeTypeIsAA(fEdgeType); } |
|
226 inline bool isFilled() const { return GrEffectEdgeTypeIsFill(fEdgeType); } |
|
227 inline GrEffectEdgeType getEdgeType() const { return fEdgeType; } |
|
228 |
|
229 typedef GrGLCubicEffect GLEffect; |
|
230 |
|
231 virtual void getConstantColorComponents(GrColor* color, |
|
232 uint32_t* validFlags) const SK_OVERRIDE { |
|
233 *validFlags = 0; |
|
234 } |
|
235 |
|
236 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; |
|
237 |
|
238 private: |
|
239 GrCubicEffect(GrEffectEdgeType); |
|
240 |
|
241 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE; |
|
242 |
|
243 GrEffectEdgeType fEdgeType; |
|
244 |
|
245 GR_DECLARE_EFFECT_TEST; |
|
246 |
|
247 typedef GrVertexEffect INHERITED; |
|
248 }; |
|
249 |
|
250 #endif |