OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkRRectsGaussianEdgeShader.h" | 8 #include "SkRRectsGaussianEdgeShader.h" |
9 #include "SkReadBuffer.h" | 9 #include "SkReadBuffer.h" |
10 #include "SkWriteBuffer.h" | 10 #include "SkWriteBuffer.h" |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 this->setWillReadFragmentPosition(); | 97 this->setWillReadFragmentPosition(); |
98 | 98 |
99 fFirstMode = ComputeMode(fFirst); | 99 fFirstMode = ComputeMode(fFirst); |
100 fSecondMode = ComputeMode(fSecond); | 100 fSecondMode = ComputeMode(fSecond); |
101 } | 101 } |
102 | 102 |
103 class GLSLRRectsGaussianEdgeFP : public GrGLSLFragmentProcessor { | 103 class GLSLRRectsGaussianEdgeFP : public GrGLSLFragmentProcessor { |
104 public: | 104 public: |
105 GLSLRRectsGaussianEdgeFP() { } | 105 GLSLRRectsGaussianEdgeFP() { } |
106 | 106 |
| 107 // This method emits code so that, for each shape, the distance from the
edge is returned |
| 108 // in 'outputName' clamped to 0..1 with positive distance being towards
the center of the |
| 109 // shape. The distance will have been normalized by the radius. |
107 void emitModeCode(Mode mode, | 110 void emitModeCode(Mode mode, |
108 GrGLSLFPFragmentBuilder* fragBuilder, | 111 GrGLSLFPFragmentBuilder* fragBuilder, |
109 const char* posName, | 112 const char* posName, |
110 const char* sizesName, | 113 const char* sizesName, |
111 const char* radiiName, | 114 const char* radiiName, |
| 115 const char* padRadName, |
112 const char* outputName, | 116 const char* outputName, |
113 const char indices[2]) { // how to access the params
for the 2 rrects | 117 const char indices[2]) { // how to access the params
for the 2 rrects |
114 | 118 |
115 // positive distance is towards the center of the circle | 119 // positive distance is towards the center of the circle |
116 fragBuilder->codeAppendf("vec2 delta = %s.xy - %s.%s;", | 120 fragBuilder->codeAppendf("vec2 delta = %s.xy - %s.%s;", |
117 fragBuilder->fragmentPosition(), | 121 fragBuilder->fragmentPosition(), posName, i
ndices); |
118 posName, indices); | |
119 | 122 |
120 switch (mode) { | 123 switch (mode) { |
121 case kCircle_Mode: | 124 case kCircle_Mode: |
122 fragBuilder->codeAppendf("%s = %s.%c - length(delta);", | 125 fragBuilder->codeAppendf("%s = clamp((%s.%c - length(delta))/%s.
y, 0.0, 1.0);", |
123 outputName, | 126 outputName, sizesName, indices[0], padR
adName); |
124 sizesName, indices[0]); | |
125 break; | 127 break; |
126 case kRect_Mode: | 128 case kRect_Mode: |
127 fragBuilder->codeAppendf("float xDist = %s.%c - abs(delta.x);", | 129 fragBuilder->codeAppendf( |
128 sizesName, indices[0]); | 130 "vec2 rectDist = vec2(1.0 - clamp((%s.%c - abs(delta.x))/%s.
y, 0.0, 1.0)," |
129 fragBuilder->codeAppendf("float yDist = %s.%c - abs(delta.y);", | 131 "1.0 - clamp((%s.%c - abs(delta.y))/%s.
y, 0.0, 1.0));", |
130 sizesName, indices[1]); | 132 sizesName, indices[0], padRadName, |
131 fragBuilder->codeAppendf("%s = min(xDist, yDist);", outputName); | 133 sizesName, indices[1], padRadName); |
| 134 fragBuilder->codeAppendf("%s = 1.0 - length(rectDist);", outputN
ame); |
132 break; | 135 break; |
133 case kSimpleCircular_Mode: | 136 case kSimpleCircular_Mode: |
134 // For the circular round rect we first compute the distance | 137 // For the circular round rect we first compute the distance |
135 // to the rect. Then we compute a multiplier that is 1 if the | 138 // to the rect. Then we compute a multiplier that is 1 if the |
136 // point is in one of the circular corners. We then compute the | 139 // point is in one of the circular corners. We then compute the |
137 // distance from the corner and then use the multiplier to mask | 140 // distance from the corner and then use the multiplier to mask |
138 // between the two distances. | 141 // between the two distances. |
139 fragBuilder->codeAppendf("float xDist = %s.%c - abs(delta.x);", | 142 fragBuilder->codeAppendf("float xDist = clamp((%s.%c - abs(delta
.x))/%s.y," |
140 sizesName, indices[0]); | 143 " 0.0, 1.0);", |
141 fragBuilder->codeAppendf("float yDist = %s.%c - abs(delta.y);", | 144 sizesName, indices[0], padRadName); |
142 sizesName, indices[1]); | 145 fragBuilder->codeAppendf("float yDist = clamp((%s.%c - abs(delta
.y))/%s.y," |
| 146 "0.0, 1.0);", |
| 147 sizesName, indices[1], padRadName); |
143 fragBuilder->codeAppend("float rectDist = min(xDist, yDist);"); | 148 fragBuilder->codeAppend("float rectDist = min(xDist, yDist);"); |
144 | 149 |
145 fragBuilder->codeAppendf("vec2 cornerCenter = %s.%s - %s.%s;", | 150 fragBuilder->codeAppendf("vec2 cornerCenter = %s.%s - %s.%s;", |
146 sizesName, indices, | 151 sizesName, indices, radiiName, indices)
; |
147 radiiName, indices); | |
148 fragBuilder->codeAppend("delta = vec2(abs(delta.x) - cornerCente
r.x," | 152 fragBuilder->codeAppend("delta = vec2(abs(delta.x) - cornerCente
r.x," |
149 "abs(delta.y) - cornerCente
r.y);"); | 153 "abs(delta.y) - cornerCente
r.y);"); |
150 fragBuilder->codeAppendf("xDist = %s.%c - abs(delta.x);", | 154 fragBuilder->codeAppendf("xDist = %s.%c - abs(delta.x);", radiiN
ame, indices[0]); |
151 radiiName, indices[0]); | 155 fragBuilder->codeAppendf("yDist = %s.%c - abs(delta.y);", radiiN
ame, indices[1]); |
152 fragBuilder->codeAppendf("yDist = %s.%c - abs(delta.y);", | |
153 radiiName, indices[1]); | |
154 fragBuilder->codeAppend("float cornerDist = min(xDist, yDist);")
; | 156 fragBuilder->codeAppend("float cornerDist = min(xDist, yDist);")
; |
155 fragBuilder->codeAppend("float multiplier = step(0.0, cornerDist
);"); | 157 fragBuilder->codeAppend("float multiplier = step(0.0, cornerDist
);"); |
156 | 158 |
157 fragBuilder->codeAppendf("delta += %s.%s;", radiiName, indices); | 159 fragBuilder->codeAppendf("delta += %s.%s;", radiiName, indices); |
158 | 160 |
159 fragBuilder->codeAppendf("cornerDist = 2.0 * %s.%c - length(delt
a);", | 161 fragBuilder->codeAppendf("cornerDist = clamp((2.0 * %s.%c - leng
th(delta))/%s.y," |
160 radiiName, indices[0]); | 162 "0.0, 1.0);", |
| 163 radiiName, indices[0], padRadName); |
161 | 164 |
162 fragBuilder->codeAppendf("%s = (multiplier * cornerDist) +" | 165 fragBuilder->codeAppendf("%s = (multiplier * cornerDist) +" |
163 "((1.0-multiplier) * rectDist);", | 166 "((1.0-multiplier) * rectDist);", |
164 outputName); | 167 outputName); |
165 break; | 168 break; |
166 } | 169 } |
167 } | 170 } |
168 | 171 |
169 void emitCode(EmitArgs& args) override { | 172 void emitCode(EmitArgs& args) override { |
170 const RRectsGaussianEdgeFP& fp = args.fFp.cast<RRectsGaussianEdgeFP>
(); | 173 const RRectsGaussianEdgeFP& fp = args.fFp.cast<RRectsGaussianEdgeFP>
(); |
171 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; | 174 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; |
172 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; | 175 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; |
173 | 176 |
174 const char* positionsUniName = nullptr; | 177 const char* positionsUniName = nullptr; |
175 fPositionsUni = uniformHandler->addUniform(kFragment_GrShaderFlag, | 178 fPositionsUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
176 kVec4f_GrSLType, kDefault
_GrSLPrecision, | 179 kVec4f_GrSLType, kDefault
_GrSLPrecision, |
177 "Positions", &positionsUn
iName); | 180 "Positions", &positionsUn
iName); |
178 const char* sizesUniName = nullptr; | 181 const char* sizesUniName = nullptr; |
179 fSizesUni = uniformHandler->addUniform(kFragment_GrShaderFlag, | 182 fSizesUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
180 kVec4f_GrSLType, kDefault_GrS
LPrecision, | 183 kVec4f_GrSLType, kDefault_GrS
LPrecision, |
181 "Sizes", &sizesUniName); | 184 "Sizes", &sizesUniName); |
182 const char* radiiUniName = nullptr; | 185 const char* radiiUniName = nullptr; |
183 fRadiiUni = uniformHandler->addUniform(kFragment_GrShaderFlag, | 186 if (fp.fFirstMode == kSimpleCircular_Mode || fp.fSecondMode == kSimp
leCircular_Mode) { |
184 kVec4f_GrSLType, kDefault_GrS
LPrecision, | 187 fRadiiUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
185 "Radii", &radiiUniName); | 188 kVec4f_GrSLType, kDefault
_GrSLPrecision, |
| 189 "Radii", &radiiUniName); |
| 190 } |
186 const char* padRadUniName = nullptr; | 191 const char* padRadUniName = nullptr; |
187 fPadRadUni = uniformHandler->addUniform(kFragment_GrShaderFlag, | 192 fPadRadUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
188 kVec2f_GrSLType, kDefault_Gr
SLPrecision, | 193 kVec2f_GrSLType, kDefault_Gr
SLPrecision, |
189 "PadRad", &padRadUniName); | 194 "PadRad", &padRadUniName); |
190 | 195 |
191 fragBuilder->codeAppend("float firstDist;"); | 196 fragBuilder->codeAppend("float firstDist;"); |
192 fragBuilder->codeAppend("{"); | 197 fragBuilder->codeAppend("{"); |
193 this->emitModeCode(fp.firstMode(), fragBuilder, | 198 this->emitModeCode(fp.firstMode(), fragBuilder, |
194 positionsUniName, sizesUniName, radiiUniName, "fi
rstDist", "xy"); | 199 positionsUniName, sizesUniName, radiiUniName, |
| 200 padRadUniName, "firstDist", "xy"); |
195 fragBuilder->codeAppend("}"); | 201 fragBuilder->codeAppend("}"); |
196 | 202 |
197 fragBuilder->codeAppend("float secondDist;"); | 203 fragBuilder->codeAppend("float secondDist;"); |
198 fragBuilder->codeAppend("{"); | 204 fragBuilder->codeAppend("{"); |
199 this->emitModeCode(fp.secondMode(), fragBuilder, | 205 this->emitModeCode(fp.secondMode(), fragBuilder, |
200 positionsUniName, sizesUniName, radiiUniName, "se
condDist", "zw"); | 206 positionsUniName, sizesUniName, radiiUniName, |
| 207 padRadUniName, "secondDist", "zw"); |
201 fragBuilder->codeAppend("}"); | 208 fragBuilder->codeAppend("}"); |
202 | 209 |
203 // Here use the sign of the distance to the two round rects to mask
off the different | 210 fragBuilder->codeAppendf("float dist = %s.y * firstDist * secondDist
;", |
204 // cases. | 211 padRadUniName); |
205 fragBuilder->codeAppend("float in1 = step(0.0f, firstDist);"); | |
206 fragBuilder->codeAppend("float in2 = step(0.0f, secondDist);"); | |
207 fragBuilder->codeAppend("float dist = " | |
208 "in1*in2 * min(firstDis
t, secondDist);" | |
209 "in1*(1.0-in2) * firstDist +" | |
210 "(1.0-in1)*in2 * secondDist;"
); | |
211 | 212 |
212 // Finally use the distance to apply the Gaussian edge | 213 // Finally use the distance to apply the Gaussian edge |
| 214 // TODO: we undo the multiply by the radius here - we should just sk
ip both |
213 fragBuilder->codeAppendf("float factor = 1.0 - clamp((dist - %s.x)/%
s.y, 0.0, 1.0);", | 215 fragBuilder->codeAppendf("float factor = 1.0 - clamp((dist - %s.x)/%
s.y, 0.0, 1.0);", |
214 padRadUniName, padRadUniName); | 216 padRadUniName, padRadUniName); |
215 fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.01
8;"); | 217 fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.01
8;"); |
216 fragBuilder->codeAppendf("%s = vec4(%s.rgb, factor);", | 218 fragBuilder->codeAppendf("%s = vec4(%s.rgb, factor);", |
217 args.fOutputColor, args.fInputColor); | 219 args.fOutputColor, args.fInputColor); |
218 } | 220 } |
219 | 221 |
220 static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, | 222 static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, |
221 GrProcessorKeyBuilder* b) { | 223 GrProcessorKeyBuilder* b) { |
222 const RRectsGaussianEdgeFP& fp = proc.cast<RRectsGaussianEdgeFP>(); | 224 const RRectsGaussianEdgeFP& fp = proc.cast<RRectsGaussianEdgeFP>(); |
(...skipping 13 matching lines...) Expand all Loading... |
236 first.getBounds().centerY(), | 238 first.getBounds().centerY(), |
237 second.getBounds().centerX(), | 239 second.getBounds().centerX(), |
238 second.getBounds().centerY()); | 240 second.getBounds().centerY()); |
239 | 241 |
240 pdman.set4f(fSizesUni, | 242 pdman.set4f(fSizesUni, |
241 0.5f * first.rect().width(), | 243 0.5f * first.rect().width(), |
242 0.5f * first.rect().height(), | 244 0.5f * first.rect().height(), |
243 0.5f * second.rect().width(), | 245 0.5f * second.rect().width(), |
244 0.5f * second.rect().height()); | 246 0.5f * second.rect().height()); |
245 | 247 |
246 // This is a bit of overkill since fX should equal fY for both round
rects but it | 248 if (edgeFP.firstMode() == kSimpleCircular_Mode || |
247 // makes the shader code simpler. | 249 edgeFP.secondMode() == kSimpleCircular_Mode) { |
248 pdman.set4f(fRadiiUni, | 250 // This is a bit of overkill since fX should equal fY for both r
ound rects but it |
249 0.5f * first.getSimpleRadii().fX, | 251 // makes the shader code simpler. |
250 0.5f * first.getSimpleRadii().fY, | 252 pdman.set4f(fRadiiUni, |
251 0.5f * second.getSimpleRadii().fX, | 253 0.5f * first.getSimpleRadii().fX, |
252 0.5f * second.getSimpleRadii().fY); | 254 0.5f * first.getSimpleRadii().fY, |
| 255 0.5f * second.getSimpleRadii().fX, |
| 256 0.5f * second.getSimpleRadii().fY); |
| 257 } |
253 | 258 |
254 pdman.set2f(fPadRadUni, edgeFP.pad(), edgeFP.radius()); | 259 pdman.set2f(fPadRadUni, edgeFP.pad(), edgeFP.radius()); |
255 } | 260 } |
256 | 261 |
257 private: | 262 private: |
258 // The centers of the two round rects (x1, y1, x2, y2) | 263 // The centers of the two round rects (x1, y1, x2, y2) |
259 GrGLSLProgramDataManager::UniformHandle fPositionsUni; | 264 GrGLSLProgramDataManager::UniformHandle fPositionsUni; |
260 | 265 |
261 // The half widths and half heights of the two round rects (w1/2, h1/2,
w2/2, h2/2) | 266 // The half widths and half heights of the two round rects (w1/2, h1/2,
w2/2, h2/2) |
262 // For circles we still upload both width & height to simplify things | 267 // For circles we still upload both width & height to simplify things |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 return sk_make_sp<SkRRectsGaussianEdgeShaderImpl>(first, second, radius, pad
); | 431 return sk_make_sp<SkRRectsGaussianEdgeShaderImpl>(first, second, radius, pad
); |
427 } | 432 } |
428 | 433 |
429 /////////////////////////////////////////////////////////////////////////////// | 434 /////////////////////////////////////////////////////////////////////////////// |
430 | 435 |
431 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkRRectsGaussianEdgeShader) | 436 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkRRectsGaussianEdgeShader) |
432 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRRectsGaussianEdgeShaderImpl) | 437 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRRectsGaussianEdgeShaderImpl) |
433 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END | 438 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
434 | 439 |
435 /////////////////////////////////////////////////////////////////////////////// | 440 /////////////////////////////////////////////////////////////////////////////// |
OLD | NEW |