OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 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 "GrOvalRenderer.h" | 8 #include "GrOvalRenderer.h" |
9 | 9 |
10 #include "GrEffect.h" | 10 #include "GrEffect.h" |
(...skipping 14 matching lines...) Expand all Loading... |
25 | 25 |
26 struct CircleVertex { | 26 struct CircleVertex { |
27 GrPoint fPos; | 27 GrPoint fPos; |
28 GrPoint fOffset; | 28 GrPoint fOffset; |
29 SkScalar fOuterRadius; | 29 SkScalar fOuterRadius; |
30 SkScalar fInnerRadius; | 30 SkScalar fInnerRadius; |
31 }; | 31 }; |
32 | 32 |
33 struct EllipseVertex { | 33 struct EllipseVertex { |
34 GrPoint fPos; | 34 GrPoint fPos; |
35 SkScalar fOuterXRadius; | |
36 SkScalar fInnerXRadius; | |
37 GrPoint fOuterOffset; | |
38 GrPoint fInnerOffset; | |
39 }; | |
40 | |
41 struct RRectVertex { | |
42 GrPoint fPos; | |
43 GrPoint fOffset; | 35 GrPoint fOffset; |
44 GrPoint fOuterRadii; | 36 GrPoint fOuterRadii; |
45 GrPoint fInnerRadii; | 37 GrPoint fInnerRadii; |
46 }; | 38 }; |
47 | 39 |
48 inline bool circle_stays_circle(const SkMatrix& m) { | 40 inline bool circle_stays_circle(const SkMatrix& m) { |
49 return m.isSimilarity(); | 41 return m.isSimilarity(); |
50 } | 42 } |
51 | 43 |
52 } | 44 } |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 GrContext* context, | 148 GrContext* context, |
157 const GrDrawTargetCaps&, | 149 const GrDrawTargetCaps&, |
158 GrTexture* textures[]) { | 150 GrTexture* textures[]) { |
159 return CircleEdgeEffect::Create(random->nextBool()); | 151 return CircleEdgeEffect::Create(random->nextBool()); |
160 } | 152 } |
161 | 153 |
162 /////////////////////////////////////////////////////////////////////////////// | 154 /////////////////////////////////////////////////////////////////////////////// |
163 | 155 |
164 /** | 156 /** |
165 * The output of this effect is a modulation of the input color and coverage for
an axis-aligned | 157 * The output of this effect is a modulation of the input color and coverage for
an axis-aligned |
166 * ellipse, specified as outer and inner radii, and outer and inner offsets fro
m center. | 158 * ellipse, specified as a 2D offset from center, and the reciprocals of the out
er and inner radii, |
| 159 * in both x and y directions. |
| 160 * |
| 161 * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0. |
167 */ | 162 */ |
168 | 163 |
169 class EllipseEdgeEffect : public GrEffect { | 164 class EllipseEdgeEffect : public GrEffect { |
170 public: | 165 public: |
171 static GrEffectRef* Create(bool stroke) { | 166 static GrEffectRef* Create(bool stroke) { |
172 GR_CREATE_STATIC_EFFECT(gEllipseStrokeEdge, EllipseEdgeEffect, (true)); | 167 GR_CREATE_STATIC_EFFECT(gEllipseStrokeEdge, EllipseEdgeEffect, (true)); |
173 GR_CREATE_STATIC_EFFECT(gEllipseFillEdge, EllipseEdgeEffect, (false)); | 168 GR_CREATE_STATIC_EFFECT(gEllipseFillEdge, EllipseEdgeEffect, (false)); |
174 | 169 |
175 if (stroke) { | 170 if (stroke) { |
176 gEllipseStrokeEdge->ref(); | 171 gEllipseStrokeEdge->ref(); |
(...skipping 25 matching lines...) Expand all Loading... |
202 : INHERITED (factory) {} | 197 : INHERITED (factory) {} |
203 | 198 |
204 virtual void emitCode(GrGLShaderBuilder* builder, | 199 virtual void emitCode(GrGLShaderBuilder* builder, |
205 const GrDrawEffect& drawEffect, | 200 const GrDrawEffect& drawEffect, |
206 EffectKey key, | 201 EffectKey key, |
207 const char* outputColor, | 202 const char* outputColor, |
208 const char* inputColor, | 203 const char* inputColor, |
209 const TextureSamplerArray& samplers) SK_OVERRIDE { | 204 const TextureSamplerArray& samplers) SK_OVERRIDE { |
210 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip
seEdgeEffect>(); | 205 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip
seEdgeEffect>(); |
211 | 206 |
| 207 const char *vsOffsetName, *fsOffsetName; |
212 const char *vsRadiiName, *fsRadiiName; | 208 const char *vsRadiiName, *fsRadiiName; |
213 const char *vsOffsetsName, *fsOffsetsName; | |
214 | 209 |
215 builder->addVarying(kVec2f_GrSLType, "EllipseRadii", &vsRadiiName, &
fsRadiiName); | 210 builder->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName
, &fsOffsetName); |
216 const SkString* attr0Name = | 211 const SkString* attr0Name = |
217 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[0]); | 212 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[0]); |
218 builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr0Name->c_str
()); | 213 builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName, attr0Name->c_st
r()); |
219 | 214 |
220 builder->addVarying(kVec4f_GrSLType, "EllipseOffsets", &vsOffsetsNam
e, &fsOffsetsName); | 215 builder->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, &
fsRadiiName); |
221 const SkString* attr1Name = | 216 const SkString* attr1Name = |
222 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[1]); | 217 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[1]); |
223 builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetsName, attr1Name->c_s
tr()); | 218 builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr1Name->c_str
()); |
224 | 219 |
225 // get length of offset | 220 // for outer curve |
226 builder->fsCodeAppendf("\tfloat dOuter = length(%s.xy);\n", fsOffset
sName); | 221 builder->fsCodeAppendf("\tvec2 scaledOffset = %s*%s.xy;\n", fsOffset
Name, fsRadiiName); |
227 // compare outer lengths against xOuterRadius | 222 builder->fsCodeAppend("\tfloat test = dot(scaledOffset, scaledOffset
) - 1.0;\n"); |
228 builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.x-dOuter, 0.0,
1.0);\n", | 223 builder->fsCodeAppendf("\tvec2 grad = 2.0*scaledOffset*%s.xy;\n", fs
RadiiName); |
229 fsRadiiName); | 224 builder->fsCodeAppend("\tfloat invlen = inversesqrt(dot(grad, grad))
;\n"); |
| 225 builder->fsCodeAppend("\tfloat edgeAlpha = clamp(0.5-test*invlen, 0.
0, 1.0);\n"); |
230 | 226 |
| 227 // for inner curve |
231 if (ellipseEffect.isStroked()) { | 228 if (ellipseEffect.isStroked()) { |
232 builder->fsCodeAppendf("\tfloat dInner = length(%s.zw);\n", fsOf
fsetsName); | 229 builder->fsCodeAppendf("\tscaledOffset = %s*%s.zw;\n", fsOffsetN
ame, fsRadiiName); |
233 | 230 builder->fsCodeAppend("\ttest = dot(scaledOffset, scaledOffset)
- 1.0;\n"); |
234 // compare inner lengths against xInnerRadius | 231 builder->fsCodeAppendf("\tgrad = 2.0*scaledOffset*%s.zw;\n", fsR
adiiName); |
235 builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.y,
0.0, 1.0);\n", | 232 builder->fsCodeAppend("\tinvlen = inversesqrt(dot(grad, grad));\
n"); |
236 fsRadiiName); | 233 builder->fsCodeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0
, 1.0);\n"); |
237 builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n"); | |
238 } | 234 } |
239 | 235 |
240 SkString modulate; | 236 SkString modulate; |
241 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); | 237 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); |
242 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()
); | 238 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()
); |
243 } | 239 } |
244 | 240 |
245 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG
LCaps&) { | 241 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG
LCaps&) { |
246 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip
seEdgeEffect>(); | 242 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip
seEdgeEffect>(); |
247 | 243 |
(...skipping 30 matching lines...) Expand all Loading... |
278 | 274 |
279 GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random, | 275 GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random, |
280 GrContext* context, | 276 GrContext* context, |
281 const GrDrawTargetCaps&, | 277 const GrDrawTargetCaps&, |
282 GrTexture* textures[]) { | 278 GrTexture* textures[]) { |
283 return EllipseEdgeEffect::Create(random->nextBool()); | 279 return EllipseEdgeEffect::Create(random->nextBool()); |
284 } | 280 } |
285 | 281 |
286 /////////////////////////////////////////////////////////////////////////////// | 282 /////////////////////////////////////////////////////////////////////////////// |
287 | 283 |
288 /** | |
289 * The output of this effect is a modulation of the input color and coverage for
an axis-aligned | |
290 * ellipse, specified as an offset vector from center and reciprocals of outer a
nd inner radii in | |
291 * both x and y directions. | |
292 * | |
293 * This uses a slightly different algorithm than the EllipseEdgeEffect, above. R
ather than | |
294 * scaling an ellipse to be a circle, it attempts to find the distance from the
offset point to the | |
295 * ellipse by determining where the line through the origin and offset point wou
ld cross the | |
296 * ellipse, and computing the distance to that. This is slower but works better
for roundrects | |
297 * because the straight edges will be more accurate. | |
298 */ | |
299 | |
300 class AltEllipseEdgeEffect : public GrEffect { | |
301 public: | |
302 static GrEffectRef* Create(bool stroke) { | |
303 // we go through this so we only have one copy of each effect (stroked/f
illed) | |
304 GR_CREATE_STATIC_EFFECT(gAltEllipseStrokeEdge, AltEllipseEdgeEffect, (tr
ue)); | |
305 GR_CREATE_STATIC_EFFECT(gAltEllipseFillEdge, AltEllipseEdgeEffect, (fals
e)); | |
306 | |
307 if (stroke) { | |
308 gAltEllipseStrokeEdge->ref(); | |
309 return gAltEllipseStrokeEdge; | |
310 } else { | |
311 gAltEllipseFillEdge->ref(); | |
312 return gAltEllipseFillEdge; | |
313 } | |
314 } | |
315 | |
316 virtual void getConstantColorComponents(GrColor* color, | |
317 uint32_t* validFlags) const SK_OVERR
IDE { | |
318 *validFlags = 0; | |
319 } | |
320 | |
321 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { | |
322 return GrTBackendEffectFactory<AltEllipseEdgeEffect>::getInstance(); | |
323 } | |
324 | |
325 virtual ~AltEllipseEdgeEffect() {} | |
326 | |
327 static const char* Name() { return "RRectEdge"; } | |
328 | |
329 inline bool isStroked() const { return fStroke; } | |
330 | |
331 class GLEffect : public GrGLEffect { | |
332 public: | |
333 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) | |
334 : INHERITED (factory) {} | |
335 | |
336 virtual void emitCode(GrGLShaderBuilder* builder, | |
337 const GrDrawEffect& drawEffect, | |
338 EffectKey key, | |
339 const char* outputColor, | |
340 const char* inputColor, | |
341 const TextureSamplerArray& samplers) SK_OVERRIDE { | |
342 const AltEllipseEdgeEffect& rrectEffect = drawEffect.castEffect<AltE
llipseEdgeEffect>(); | |
343 | |
344 const char *vsOffsetName, *fsOffsetName; | |
345 const char *vsRadiiName, *fsRadiiName; | |
346 | |
347 builder->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName
, &fsOffsetName); | |
348 const SkString* attr0Name = | |
349 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[0]); | |
350 builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName, attr0Name->c_st
r()); | |
351 | |
352 builder->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, &
fsRadiiName); | |
353 const SkString* attr1Name = | |
354 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[1]); | |
355 builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr1Name->c_str
()); | |
356 | |
357 builder->fsCodeAppend("\tfloat edgeAlpha;\n"); | |
358 // get length of offset | |
359 builder->fsCodeAppendf("\tfloat len = length(%s.xy);\n", fsOffsetNam
e); | |
360 | |
361 // for outer curve | |
362 builder->fsCodeAppendf("\tvec2 offset = %s.xy*%s.xy;\n", | |
363 fsOffsetName, fsRadiiName); | |
364 builder->fsCodeAppendf("\tfloat t = inversesqrt(dot(offset.xy, offse
t.xy));\n"); | |
365 builder->fsCodeAppend("\tedgeAlpha = clamp(len*t - len, 0.0, 1.0);\n
"); | |
366 | |
367 // for inner curve | |
368 if (rrectEffect.isStroked()) { | |
369 builder->fsCodeAppendf("\toffset = %s.xy*%s.zw;\n", | |
370 fsOffsetName, fsRadiiName); | |
371 builder->fsCodeAppendf("\tt = inversesqrt(dot(offset.xy, offset.
xy));\n"); | |
372 builder->fsCodeAppend("\tedgeAlpha *= clamp(len - len*t, 0.0, 1.
0);\n"); | |
373 } | |
374 | |
375 SkString modulate; | |
376 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); | |
377 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()
); | |
378 } | |
379 | |
380 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG
LCaps&) { | |
381 const AltEllipseEdgeEffect& rrectEffect = drawEffect.castEffect<AltE
llipseEdgeEffect>(); | |
382 | |
383 return rrectEffect.isStroked() ? 0x1 : 0x0; | |
384 } | |
385 | |
386 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_
OVERRIDE { | |
387 } | |
388 | |
389 private: | |
390 typedef GrGLEffect INHERITED; | |
391 }; | |
392 | |
393 private: | |
394 AltEllipseEdgeEffect(bool stroke) : GrEffect() { | |
395 this->addVertexAttrib(kVec2f_GrSLType); | |
396 this->addVertexAttrib(kVec4f_GrSLType); | |
397 fStroke = stroke; | |
398 } | |
399 | |
400 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { | |
401 const AltEllipseEdgeEffect& aeee = CastEffect<AltEllipseEdgeEffect>(othe
r); | |
402 return aeee.fStroke == fStroke; | |
403 } | |
404 | |
405 bool fStroke; | |
406 | |
407 GR_DECLARE_EFFECT_TEST; | |
408 | |
409 typedef GrEffect INHERITED; | |
410 }; | |
411 | |
412 GR_DEFINE_EFFECT_TEST(AltEllipseEdgeEffect); | |
413 | |
414 GrEffectRef* AltEllipseEdgeEffect::TestCreate(SkMWCRandom* random, | |
415 GrContext* context, | |
416 const GrDrawTargetCaps&, | |
417 GrTexture* textures[]) { | |
418 return AltEllipseEdgeEffect::Create(random->nextBool()); | |
419 } | |
420 | |
421 /////////////////////////////////////////////////////////////////////////////// | |
422 | |
423 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, bo
ol useAA, | 284 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, bo
ol useAA, |
424 const GrRect& oval, const SkStrokeRec& stroke) | 285 const GrRect& oval, const SkStrokeRec& stroke) |
425 { | 286 { |
426 if (!useAA) { | 287 if (!useAA) { |
427 return false; | 288 return false; |
428 } | 289 } |
429 | 290 |
430 const SkMatrix& vm = context->getMatrix(); | 291 const SkMatrix& vm = context->getMatrix(); |
431 | 292 |
432 // we can draw circles | 293 // we can draw circles |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
504 SkScalar halfWidth = 0; | 365 SkScalar halfWidth = 0; |
505 if (style != SkStrokeRec::kFill_Style) { | 366 if (style != SkStrokeRec::kFill_Style) { |
506 if (SkScalarNearlyZero(strokeWidth)) { | 367 if (SkScalarNearlyZero(strokeWidth)) { |
507 halfWidth = SK_ScalarHalf; | 368 halfWidth = SK_ScalarHalf; |
508 } else { | 369 } else { |
509 halfWidth = SkScalarHalf(strokeWidth); | 370 halfWidth = SkScalarHalf(strokeWidth); |
510 } | 371 } |
511 | 372 |
512 outerRadius += halfWidth; | 373 outerRadius += halfWidth; |
513 if (isStroked) { | 374 if (isStroked) { |
514 innerRadius = SkMaxScalar(0, radius - halfWidth); | 375 innerRadius = radius - halfWidth; |
| 376 isStroked = (innerRadius > 0); |
515 } | 377 } |
516 } | 378 } |
517 | 379 |
518 // The radii are outset for two reasons. First, it allows the shader to simp
ly perform | 380 // The radii are outset for two reasons. First, it allows the shader to simp
ly perform |
519 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is use
d to compute the | 381 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is use
d to compute the |
520 // verts of the bounding box that is rendered and the outset ensures the box
will cover all | 382 // verts of the bounding box that is rendered and the outset ensures the box
will cover all |
521 // pixels partially covered by the circle. | 383 // pixels partially covered by the circle. |
522 outerRadius += SK_ScalarHalf; | 384 outerRadius += SK_ScalarHalf; |
523 innerRadius -= SK_ScalarHalf; | 385 innerRadius -= SK_ScalarHalf; |
524 | 386 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 // do any matrix crunching before we reset the draw state for device coords | 444 // do any matrix crunching before we reset the draw state for device coords |
583 const SkMatrix& vm = drawState->getViewMatrix(); | 445 const SkMatrix& vm = drawState->getViewMatrix(); |
584 GrPoint center = GrPoint::Make(ellipse.centerX(), ellipse.centerY()); | 446 GrPoint center = GrPoint::Make(ellipse.centerX(), ellipse.centerY()); |
585 vm.mapPoints(¢er, 1); | 447 vm.mapPoints(¢er, 1); |
586 SkScalar ellipseXRadius = SkScalarHalf(ellipse.width()); | 448 SkScalar ellipseXRadius = SkScalarHalf(ellipse.width()); |
587 SkScalar ellipseYRadius = SkScalarHalf(ellipse.height()); | 449 SkScalar ellipseYRadius = SkScalarHalf(ellipse.height()); |
588 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*ellipseXRadius + | 450 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*ellipseXRadius + |
589 vm[SkMatrix::kMSkewY]*ellipseYRadius); | 451 vm[SkMatrix::kMSkewY]*ellipseYRadius); |
590 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*ellipseXRadius + | 452 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*ellipseXRadius + |
591 vm[SkMatrix::kMScaleY]*ellipseYRadius); | 453 vm[SkMatrix::kMScaleY]*ellipseYRadius); |
592 if (SkScalarDiv(xRadius, yRadius) > 2 || SkScalarDiv(yRadius, xRadius) > 2)
{ | |
593 return false; | |
594 } | |
595 | 454 |
596 // do (potentially) anisotropic mapping of stroke | 455 // do (potentially) anisotropic mapping of stroke |
597 SkVector scaledStroke; | 456 SkVector scaledStroke; |
598 SkScalar strokeWidth = stroke.getWidth(); | 457 SkScalar strokeWidth = stroke.getWidth(); |
599 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMat
rix::kMSkewY])); | 458 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMat
rix::kMSkewY])); |
600 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatr
ix::kMScaleY])); | 459 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatr
ix::kMScaleY])); |
601 | 460 |
| 461 SkStrokeRec::Style style = stroke.getStyle(); |
| 462 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl
ine_Style == style); |
| 463 |
| 464 SkScalar innerXRadius = 0.0f; |
| 465 SkScalar innerYRadius = 0.0f; |
| 466 if (SkStrokeRec::kFill_Style != style) { |
| 467 if (SkScalarNearlyZero(scaledStroke.length())) { |
| 468 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); |
| 469 } else { |
| 470 scaledStroke.scale(SK_ScalarHalf); |
| 471 } |
| 472 |
| 473 // we only handle thick strokes for near-circular ellipses |
| 474 if (scaledStroke.length() > SK_ScalarHalf && |
| 475 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)
) { |
| 476 return false; |
| 477 } |
| 478 |
| 479 // we don't handle it if curvature of the stroke is less than curvature
of the ellipse |
| 480 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY
)*xRadius || |
| 481 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX
)*yRadius) { |
| 482 return false; |
| 483 } |
| 484 |
| 485 // this is legit only if scale & translation (which should be the case a
t the moment) |
| 486 if (isStroked) { |
| 487 innerXRadius = xRadius - scaledStroke.fX; |
| 488 innerYRadius = yRadius - scaledStroke.fY; |
| 489 isStroked = (innerXRadius > 0 && innerYRadius > 0); |
| 490 } |
| 491 |
| 492 xRadius += scaledStroke.fX; |
| 493 yRadius += scaledStroke.fY; |
| 494 } |
| 495 |
602 GrDrawState::AutoDeviceCoordDraw adcd(drawState); | 496 GrDrawState::AutoDeviceCoordDraw adcd(drawState); |
603 if (!adcd.succeeded()) { | 497 if (!adcd.succeeded()) { |
604 return false; | 498 return false; |
605 } | 499 } |
606 | 500 |
607 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVe
rtexAttribs)); | 501 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVe
rtexAttribs)); |
608 GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize()); | 502 GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize()); |
609 | 503 |
610 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); | 504 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); |
611 if (!geo.succeeded()) { | 505 if (!geo.succeeded()) { |
612 GrPrintf("Failed to get space for vertices!\n"); | 506 GrPrintf("Failed to get space for vertices!\n"); |
613 return false; | 507 return false; |
614 } | 508 } |
615 | 509 |
616 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); | 510 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); |
617 | 511 |
618 SkStrokeRec::Style style = stroke.getStyle(); | |
619 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl
ine_Style == style); | |
620 enum { | 512 enum { |
621 // the edge effects share this stage with glyph rendering | 513 // the edge effects share this stage with glyph rendering |
622 // (kGlyphMaskStage in GrTextContext) && SW path rendering | 514 // (kGlyphMaskStage in GrTextContext) && SW path rendering |
623 // (kPathMaskStage in GrSWMaskHelper) | 515 // (kPathMaskStage in GrSWMaskHelper) |
624 kEdgeEffectStage = GrPaint::kTotalStages, | 516 kEdgeEffectStage = GrPaint::kTotalStages, |
625 }; | 517 }; |
| 518 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked); |
626 | 519 |
627 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked); | |
628 static const int kEllipseCenterAttrIndex = 1; | 520 static const int kEllipseCenterAttrIndex = 1; |
629 static const int kEllipseEdgeAttrIndex = 2; | 521 static const int kEllipseEdgeAttrIndex = 2; |
630 drawState->setEffect(kEdgeEffectStage, effect, | 522 drawState->setEffect(kEdgeEffectStage, effect, |
631 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref(
); | 523 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref(
); |
632 | 524 |
633 SkScalar innerXRadius = 0.0f; | 525 // Compute the reciprocals of the radii here to save time in the shader |
634 SkScalar innerRatio = 1.0f; | 526 SkScalar xRadRecip = SkScalarInvert(xRadius); |
635 | 527 SkScalar yRadRecip = SkScalarInvert(yRadius); |
636 if (SkStrokeRec::kFill_Style != style) { | 528 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius); |
637 if (SkScalarNearlyZero(scaledStroke.length())) { | 529 SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius); |
638 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); | |
639 } else { | |
640 scaledStroke.scale(0.5f); | |
641 } | |
642 | |
643 // this is legit only if scale & translation (which should be the case a
t the moment) | |
644 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style
== style) { | |
645 SkScalar innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY); | |
646 if (innerYRadius > SK_ScalarNearlyZero) { | |
647 innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX); | |
648 innerRatio = innerXRadius/innerYRadius; | |
649 } | |
650 } | |
651 xRadius += scaledStroke.fX; | |
652 yRadius += scaledStroke.fY; | |
653 } | |
654 | |
655 SkScalar outerRatio = SkScalarDiv(xRadius, yRadius); | |
656 | 530 |
657 // We've extended the outer x radius out half a pixel to antialias. | 531 // We've extended the outer x radius out half a pixel to antialias. |
658 // This will also expand the rect so all the pixels will be captured. | 532 // This will also expand the rect so all the pixels will be captured. |
| 533 // TODO: Consider if we should use sqrt(2)/2 instead |
659 xRadius += SK_ScalarHalf; | 534 xRadius += SK_ScalarHalf; |
660 yRadius += SK_ScalarHalf; | 535 yRadius += SK_ScalarHalf; |
661 innerXRadius -= SK_ScalarHalf; | |
662 | 536 |
663 SkRect bounds = SkRect::MakeLTRB( | 537 SkRect bounds = SkRect::MakeLTRB( |
664 center.fX - xRadius, | 538 center.fX - xRadius, |
665 center.fY - yRadius, | 539 center.fY - yRadius, |
666 center.fX + xRadius, | 540 center.fX + xRadius, |
667 center.fY + yRadius | 541 center.fY + yRadius |
668 ); | 542 ); |
669 | 543 |
670 // The offsets are created by scaling the y radius by the appropriate ratio.
This way we end up | |
671 // with a circle equation which can be checked quickly in the shader. We nee
d one offset for | |
672 // outer and one for inner because they have different scale factors -- othe
rwise we end up with | |
673 // non-uniform strokes. | |
674 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); | 544 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); |
675 verts[0].fOuterXRadius = xRadius; | 545 verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius); |
676 verts[0].fInnerXRadius = innerXRadius; | 546 verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
677 verts[0].fOuterOffset = SkPoint::Make(-xRadius, -outerRatio*yRadius); | 547 verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
678 verts[0].fInnerOffset = SkPoint::Make(-xRadius, -innerRatio*yRadius); | |
679 | 548 |
680 verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); | 549 verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); |
681 verts[1].fOuterXRadius = xRadius; | 550 verts[1].fOffset = SkPoint::Make(xRadius, -yRadius); |
682 verts[1].fInnerXRadius = innerXRadius; | 551 verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
683 verts[1].fOuterOffset = SkPoint::Make(xRadius, -outerRatio*yRadius); | 552 verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
684 verts[1].fInnerOffset = SkPoint::Make(xRadius, -innerRatio*yRadius); | |
685 | 553 |
686 verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); | 554 verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); |
687 verts[2].fOuterXRadius = xRadius; | 555 verts[2].fOffset = SkPoint::Make(-xRadius, yRadius); |
688 verts[2].fInnerXRadius = innerXRadius; | 556 verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
689 verts[2].fOuterOffset = SkPoint::Make(-xRadius, outerRatio*yRadius); | 557 verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
690 verts[2].fInnerOffset = SkPoint::Make(-xRadius, innerRatio*yRadius); | |
691 | 558 |
692 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); | 559 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); |
693 verts[3].fOuterXRadius = xRadius; | 560 verts[3].fOffset = SkPoint::Make(xRadius, yRadius); |
694 verts[3].fInnerXRadius = innerXRadius; | 561 verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
695 verts[3].fOuterOffset = SkPoint::Make(xRadius, outerRatio*yRadius); | 562 verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
696 verts[3].fInnerOffset = SkPoint::Make(xRadius, innerRatio*yRadius); | |
697 | 563 |
698 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); | 564 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); |
699 | 565 |
700 return true; | 566 return true; |
701 } | 567 } |
702 | 568 |
703 /////////////////////////////////////////////////////////////////////////////// | 569 /////////////////////////////////////////////////////////////////////////////// |
704 | 570 |
705 static const uint16_t gRRectIndices[] = { | 571 static const uint16_t gRRectIndices[] = { |
706 // corners | 572 // corners |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
756 // do any matrix crunching before we reset the draw state for device coords | 622 // do any matrix crunching before we reset the draw state for device coords |
757 const SkRect& rrectBounds = rrect.getBounds(); | 623 const SkRect& rrectBounds = rrect.getBounds(); |
758 SkRect bounds; | 624 SkRect bounds; |
759 vm.mapRect(&bounds, rrectBounds); | 625 vm.mapRect(&bounds, rrectBounds); |
760 | 626 |
761 SkVector radii = rrect.getSimpleRadii(); | 627 SkVector radii = rrect.getSimpleRadii(); |
762 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*radii.fX + | 628 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*radii.fX + |
763 vm[SkMatrix::kMSkewY]*radii.fY); | 629 vm[SkMatrix::kMSkewY]*radii.fY); |
764 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX + | 630 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX + |
765 vm[SkMatrix::kMScaleY]*radii.fY); | 631 vm[SkMatrix::kMScaleY]*radii.fY); |
766 // tall or wide quarter-ellipse corners aren't handled | 632 |
767 if (SkScalarDiv(xRadius, yRadius) > 2 || SkScalarDiv(yRadius, xRadius) > 2)
{ | |
768 return false; | |
769 } | |
770 // if hairline stroke is greater than radius, we don't handle that right now | 633 // if hairline stroke is greater than radius, we don't handle that right now |
771 SkStrokeRec::Style style = stroke.getStyle(); | 634 SkStrokeRec::Style style = stroke.getStyle(); |
772 if (SkStrokeRec::kHairline_Style == style && | 635 if (SkStrokeRec::kHairline_Style == style && |
773 (SK_ScalarHalf >= xRadius || SK_ScalarHalf >= yRadius)) { | 636 (SK_ScalarHalf >= xRadius || SK_ScalarHalf >= yRadius)) { |
774 return false; | 637 return false; |
775 } | 638 } |
776 | 639 |
777 // do (potentially) anisotropic mapping of stroke | 640 // do (potentially) anisotropic mapping of stroke |
778 SkVector scaledStroke; | 641 SkVector scaledStroke; |
779 SkScalar strokeWidth = stroke.getWidth(); | 642 SkScalar strokeWidth = stroke.getWidth(); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
812 drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircle
VertexAttribs)); | 675 drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircle
VertexAttribs)); |
813 GrAssert(sizeof(CircleVertex) == drawState->getVertexSize()); | 676 GrAssert(sizeof(CircleVertex) == drawState->getVertexSize()); |
814 | 677 |
815 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); | 678 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); |
816 if (!geo.succeeded()) { | 679 if (!geo.succeeded()) { |
817 GrPrintf("Failed to get space for vertices!\n"); | 680 GrPrintf("Failed to get space for vertices!\n"); |
818 return false; | 681 return false; |
819 } | 682 } |
820 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); | 683 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); |
821 | 684 |
822 GrEffectRef* effect = CircleEdgeEffect::Create(isStroked); | |
823 static const int kCircleEdgeAttrIndex = 1; | |
824 drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->un
ref(); | |
825 | |
826 SkScalar innerRadius = 0.0f; | 685 SkScalar innerRadius = 0.0f; |
827 SkScalar outerRadius = xRadius; | 686 SkScalar outerRadius = xRadius; |
828 SkScalar halfWidth = 0; | 687 SkScalar halfWidth = 0; |
829 if (style != SkStrokeRec::kFill_Style) { | 688 if (style != SkStrokeRec::kFill_Style) { |
830 if (SkScalarNearlyZero(scaledStroke.fX)) { | 689 if (SkScalarNearlyZero(scaledStroke.fX)) { |
831 halfWidth = SK_ScalarHalf; | 690 halfWidth = SK_ScalarHalf; |
832 } else { | 691 } else { |
833 halfWidth = SkScalarHalf(scaledStroke.fX); | 692 halfWidth = SkScalarHalf(scaledStroke.fX); |
834 } | 693 } |
835 | 694 |
836 if (isStroked) { | 695 if (isStroked) { |
837 innerRadius = SkMaxScalar(0, xRadius - halfWidth); | 696 innerRadius = xRadius - halfWidth; |
| 697 isStroked = (innerRadius > 0); |
838 } | 698 } |
839 outerRadius += halfWidth; | 699 outerRadius += halfWidth; |
840 bounds.outset(halfWidth, halfWidth); | 700 bounds.outset(halfWidth, halfWidth); |
841 } | 701 } |
842 | 702 |
| 703 GrEffectRef* effect = CircleEdgeEffect::Create(isStroked); |
| 704 static const int kCircleEdgeAttrIndex = 1; |
| 705 drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->un
ref(); |
| 706 |
843 // The radii are outset for two reasons. First, it allows the shader to
simply perform | 707 // The radii are outset for two reasons. First, it allows the shader to
simply perform |
844 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is
used to compute the | 708 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is
used to compute the |
845 // verts of the bounding box that is rendered and the outset ensures the
box will cover all | 709 // verts of the bounding box that is rendered and the outset ensures the
box will cover all |
846 // pixels partially covered by the circle. | 710 // pixels partially covered by the circle. |
847 outerRadius += SK_ScalarHalf; | 711 outerRadius += SK_ScalarHalf; |
848 innerRadius -= SK_ScalarHalf; | 712 innerRadius -= SK_ScalarHalf; |
849 | 713 |
850 // Expand the rect so all the pixels will be captured. | 714 // Expand the rect so all the pixels will be captured. |
851 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); | 715 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); |
852 | 716 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
886 verts->fOuterRadius = outerRadius; | 750 verts->fOuterRadius = outerRadius; |
887 verts->fInnerRadius = innerRadius; | 751 verts->fInnerRadius = innerRadius; |
888 verts++; | 752 verts++; |
889 } | 753 } |
890 | 754 |
891 // drop out the middle quad if we're stroked | 755 // drop out the middle quad if we're stroked |
892 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO
UNT(gRRectIndices); | 756 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO
UNT(gRRectIndices); |
893 target->setIndexSourceToBuffer(indexBuffer); | 757 target->setIndexSourceToBuffer(indexBuffer); |
894 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou
nds); | 758 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou
nds); |
895 | 759 |
896 // otherwise we use the special ellipse renderer | 760 // otherwise we use the ellipse renderer |
897 } else { | 761 } else { |
| 762 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllip
seVertexAttribs)); |
| 763 GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize()); |
898 | 764 |
899 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllip
seVertexAttribs)); | 765 SkScalar innerXRadius = 0.0f; |
900 GrAssert(sizeof(RRectVertex) == drawState->getVertexSize()); | 766 SkScalar innerYRadius = 0.0f; |
| 767 if (SkStrokeRec::kFill_Style != style) { |
| 768 if (SkScalarNearlyZero(scaledStroke.length())) { |
| 769 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); |
| 770 } else { |
| 771 scaledStroke.scale(SK_ScalarHalf); |
| 772 } |
| 773 |
| 774 // we only handle thick strokes for near-circular ellipses |
| 775 if (scaledStroke.length() > SK_ScalarHalf && |
| 776 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRad
ius)) { |
| 777 return false; |
| 778 } |
| 779 |
| 780 // we don't handle it if curvature of the stroke is less than curvat
ure of the ellipse |
| 781 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStrok
e.fY)*xRadius || |
| 782 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStrok
e.fX)*yRadius) { |
| 783 return false; |
| 784 } |
| 785 |
| 786 // this is legit only if scale & translation (which should be the ca
se at the moment) |
| 787 if (isStroked) { |
| 788 innerXRadius = xRadius - scaledStroke.fX; |
| 789 innerYRadius = yRadius - scaledStroke.fY; |
| 790 isStroked = (innerXRadius > 0 && innerYRadius > 0); |
| 791 } |
| 792 |
| 793 xRadius += scaledStroke.fX; |
| 794 yRadius += scaledStroke.fY; |
| 795 bounds.outset(scaledStroke.fX, scaledStroke.fY); |
| 796 } |
901 | 797 |
902 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); | 798 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); |
903 if (!geo.succeeded()) { | 799 if (!geo.succeeded()) { |
904 GrPrintf("Failed to get space for vertices!\n"); | 800 GrPrintf("Failed to get space for vertices!\n"); |
905 return false; | 801 return false; |
906 } | 802 } |
907 RRectVertex* verts = reinterpret_cast<RRectVertex*>(geo.vertices()); | 803 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); |
908 | 804 |
909 GrEffectRef* effect = AltEllipseEdgeEffect::Create(isStroked); | 805 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked); |
910 static const int kEllipseOffsetAttrIndex = 1; | 806 static const int kEllipseOffsetAttrIndex = 1; |
911 static const int kEllipseRadiiAttrIndex = 2; | 807 static const int kEllipseRadiiAttrIndex = 2; |
912 drawState->setEffect(kEdgeEffectStage, effect, | 808 drawState->setEffect(kEdgeEffectStage, effect, |
913 kEllipseOffsetAttrIndex, kEllipseRadiiAttrIndex)->u
nref(); | 809 kEllipseOffsetAttrIndex, kEllipseRadiiAttrIndex)->u
nref(); |
914 | 810 |
915 SkScalar innerXRadius = 0.0f; | 811 // Compute the reciprocals of the radii here to save time in the shader |
916 SkScalar innerYRadius = 0.0f; | 812 SkScalar xRadRecip = SkScalarInvert(xRadius); |
917 | 813 SkScalar yRadRecip = SkScalarInvert(yRadius); |
918 if (SkStrokeRec::kFill_Style != style) { | 814 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius); |
919 if (SkScalarNearlyZero(scaledStroke.length())) { | 815 SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius); |
920 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); | |
921 } else { | |
922 scaledStroke.scale(0.5f); | |
923 } | |
924 | |
925 // this is legit only if scale & translation (which should be the ca
se at the moment) | |
926 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_St
yle == style) { | |
927 innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX); | |
928 innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY); | |
929 } | |
930 xRadius += scaledStroke.fX; | |
931 yRadius += scaledStroke.fY; | |
932 bounds.outset(scaledStroke.fX, scaledStroke.fY); | |
933 } | |
934 | 816 |
935 // Extend the radii out half a pixel to antialias. | 817 // Extend the radii out half a pixel to antialias. |
936 SkScalar xOuterRadius = xRadius + SK_ScalarHalf; | 818 SkScalar xOuterRadius = xRadius + SK_ScalarHalf; |
937 SkScalar yOuterRadius = yRadius + SK_ScalarHalf; | 819 SkScalar yOuterRadius = yRadius + SK_ScalarHalf; |
938 SkScalar xInnerRadius = SkMaxScalar(innerXRadius - SK_ScalarHalf, 0); | |
939 SkScalar yInnerRadius = SkMaxScalar(innerYRadius - SK_ScalarHalf, 0); | |
940 | 820 |
941 // Expand the rect so all the pixels will be captured. | 821 // Expand the rect so all the pixels will be captured. |
942 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); | 822 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); |
943 | 823 |
944 SkScalar yCoords[4] = { | 824 SkScalar yCoords[4] = { |
945 bounds.fTop, | 825 bounds.fTop, |
946 bounds.fTop + yOuterRadius, | 826 bounds.fTop + yOuterRadius, |
947 bounds.fBottom - yOuterRadius, | 827 bounds.fBottom - yOuterRadius, |
948 bounds.fBottom | 828 bounds.fBottom |
949 }; | 829 }; |
950 SkScalar yOuterOffsets[4] = { | 830 SkScalar yOuterOffsets[4] = { |
951 -yOuterRadius, | 831 -yOuterRadius, |
952 SK_ScalarNearlyZero, // we're using inversesqrt() in the shader, so
can't be exactly 0 | 832 SK_ScalarNearlyZero, // we're using inversesqrt() in the shader, so
can't be exactly 0 |
953 SK_ScalarNearlyZero, | 833 SK_ScalarNearlyZero, |
954 yOuterRadius | 834 yOuterRadius |
955 }; | 835 }; |
956 | 836 |
957 SkScalar recipOuterX = SK_Scalar1/xOuterRadius; | |
958 SkScalar recipOuterY = SK_Scalar1/yOuterRadius; | |
959 SkScalar recipInnerX = SK_Scalar1/xInnerRadius; | |
960 SkScalar recipInnerY = SK_Scalar1/yInnerRadius; | |
961 | |
962 for (int i = 0; i < 4; ++i) { | 837 for (int i = 0; i < 4; ++i) { |
963 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); | 838 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); |
964 verts->fOffset = SkPoint::Make(-xOuterRadius, yOuterOffsets[i]); | 839 verts->fOffset = SkPoint::Make(-xOuterRadius, yOuterOffsets[i]); |
965 verts->fOuterRadii = SkPoint::Make(recipOuterX, recipOuterY); | 840 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
966 verts->fInnerRadii = SkPoint::Make(recipInnerX, recipInnerY); | 841 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
967 verts++; | 842 verts++; |
968 | 843 |
969 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i])
; | 844 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i])
; |
970 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]
); | 845 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]
); |
971 verts->fOuterRadii = SkPoint::Make(recipOuterX, recipOuterY); | 846 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
972 verts->fInnerRadii = SkPoint::Make(recipInnerX, recipInnerY); | 847 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
973 verts++; | 848 verts++; |
974 | 849 |
975 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]
); | 850 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]
); |
976 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]
); | 851 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]
); |
977 verts->fOuterRadii = SkPoint::Make(recipOuterX, recipOuterY); | 852 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
978 verts->fInnerRadii = SkPoint::Make(recipInnerX, recipInnerY); | 853 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
979 verts++; | 854 verts++; |
980 | 855 |
981 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); | 856 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); |
982 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]); | 857 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]); |
983 verts->fOuterRadii = SkPoint::Make(recipOuterX, recipOuterY); | 858 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
984 verts->fInnerRadii = SkPoint::Make(recipInnerX, recipInnerY); | 859 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
985 verts++; | 860 verts++; |
986 } | 861 } |
987 | 862 |
988 // drop out the middle quad if we're stroked | 863 // drop out the middle quad if we're stroked |
989 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO
UNT(gRRectIndices); | 864 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO
UNT(gRRectIndices); |
990 target->setIndexSourceToBuffer(indexBuffer); | 865 target->setIndexSourceToBuffer(indexBuffer); |
991 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou
nds); | 866 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou
nds); |
992 } | 867 } |
993 | 868 |
994 return true; | 869 return true; |
995 } | 870 } |
OLD | NEW |