Home | History | Annotate | Download | only in effects
      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
    251