1/*
2 * Copyright 2012 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 GrTextureDomainEffect_DEFINED
9#define GrTextureDomainEffect_DEFINED
10
11#include "GrSingleTextureEffect.h"
12#include "gl/GrGLEffect.h"
13
14class GrGLShaderBuilder;
15struct SkRect;
16
17/**
18 * Limits a texture's lookup coordinates to a domain. Samples outside the domain are either clamped
19 * the edge of the domain or result in a vec4 of zeros (decal mode). The domain is clipped to
20 * normalized texture coords ([0,1]x[0,1] square). Bilinear filtering can cause texels outside the
21 * domain to affect the read value unless the caller considers this when calculating the domain.
22 */
23class GrTextureDomain {
24public:
25    enum Mode {
26        kIgnore_Mode,  // Ignore the texture domain rectangle.
27        kClamp_Mode,   // Clamp texture coords to the domain rectangle.
28        kDecal_Mode,   // Treat the area outside the domain rectangle as fully transparent.
29
30        kLastMode = kDecal_Mode
31    };
32    static const int kModeCount = kLastMode + 1;
33
34    static const GrTextureDomain& IgnoredDomain() {
35        static const SkRect gDummyRect = {0, 0, 0, 0};
36        static const GrTextureDomain gDomain(gDummyRect, kIgnore_Mode);
37        return gDomain;
38    }
39
40    /**
41     * @param index     Pass a value >= 0 if using multiple texture domains in the same effect.
42     *                  It is used to keep inserted variables from causing name collisions.
43     */
44    GrTextureDomain(const SkRect& domain, Mode, int index = -1);
45
46    const SkRect& domain() const { return fDomain; }
47    Mode mode() const { return fMode; }
48
49    /* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled
50       texels neighboring the domain may be read. */
51    static const SkRect MakeTexelDomain(const GrTexture* texture, const SkIRect& texelRect) {
52        SkScalar wInv = SK_Scalar1 / texture->width();
53        SkScalar hInv = SK_Scalar1 / texture->height();
54        SkRect result = {
55            texelRect.fLeft * wInv,
56            texelRect.fTop * hInv,
57            texelRect.fRight * wInv,
58            texelRect.fBottom * hInv
59        };
60        return result;
61    }
62
63    bool operator== (const GrTextureDomain& that) const {
64        return fMode == that.fMode && fDomain == that.fDomain;
65    }
66
67    /**
68     * A GrGLEffect subclass that corresponds to a GrEffect subclass that uses GrTextureDomain
69     * should include this helper. It generates the texture domain GLSL, produces the part of the
70     * effect key that reflects the texture domain code, and performs the uniform uploads necessary
71     * for texture domains.
72     */
73    class GLDomain {
74    public:
75        GLDomain() {
76            fPrevDomain[0] = SK_FloatNaN;
77            SkDEBUGCODE(fMode = (Mode) -1;)
78        }
79
80        /**
81         * Call this from GrGLEffect::emitCode() to sample the texture W.R.T. the domain and mode.
82         *
83         * @param outcolor  name of vec4 variable to hold the sampled color.
84         * @param inCoords  name of vec2 variable containing the coords to be used with the domain.
85         *                  It is assumed that this is a variable and not an expression.
86         * @param inModulateColor   if non-NULL the sampled color will be modulated with this
87         *                          expression before being written to outColor.
88         */
89        void sampleTexture(GrGLShaderBuilder* builder,
90                           const GrTextureDomain& textureDomain,
91                           const char* outColor,
92                           const SkString& inCoords,
93                           const GrGLEffect::TextureSampler sampler,
94                           const char* inModulateColor = NULL);
95
96        /**
97         * Call this from GrGLEffect::setData() to upload uniforms necessary for the texture domain.
98         * The rectangle is automatically adjusted to account for the texture's origin.
99         */
100        void setData(const GrGLUniformManager& uman, const GrTextureDomain& textureDomain,
101                     GrSurfaceOrigin textureOrigin);
102
103        enum {
104            kDomainKeyBits = 2, // See DomainKey().
105        };
106
107        /**
108         * GrGLEffect::GenKey() must call this and include the returned value in it's computed key.
109         * The returned will be limited to the lower kDomainKeyBits bits.
110         */
111        static GrGLEffect::EffectKey DomainKey(const GrTextureDomain& domain) {
112            GR_STATIC_ASSERT(kModeCount <= 4);
113            return domain.mode();
114        }
115
116    private:
117        SkDEBUGCODE(Mode                  fMode;)
118        GrGLUniformManager::UniformHandle fDomainUni;
119        SkString                          fDomainName;
120        GrGLfloat                         fPrevDomain[4];
121    };
122
123protected:
124    Mode    fMode;
125    SkRect  fDomain;
126    int     fIndex;
127
128    typedef GrSingleTextureEffect INHERITED;
129};
130
131class GrGLTextureDomainEffect;
132
133/**
134 * A basic texture effect that uses GrTextureDomain.
135 */
136class GrTextureDomainEffect : public GrSingleTextureEffect {
137
138public:
139    static GrEffectRef* Create(GrTexture*,
140                               const SkMatrix&,
141                               const SkRect& domain,
142                               GrTextureDomain::Mode,
143                               GrTextureParams::FilterMode filterMode,
144                               GrCoordSet = kLocal_GrCoordSet);
145
146    virtual ~GrTextureDomainEffect();
147
148    static const char* Name() { return "TextureDomain"; }
149
150    typedef GrGLTextureDomainEffect GLEffect;
151
152    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
153    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
154
155    const GrTextureDomain& textureDomain() const { return fTextureDomain; }
156
157protected:
158    GrTextureDomain fTextureDomain;
159
160private:
161    GrTextureDomainEffect(GrTexture*,
162                          const SkMatrix&,
163                          const SkRect& domain,
164                          GrTextureDomain::Mode,
165                          GrTextureParams::FilterMode,
166                          GrCoordSet);
167
168    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
169
170    GR_DECLARE_EFFECT_TEST;
171
172    typedef GrSingleTextureEffect INHERITED;
173};
174
175#endif
176