michael@0: /* michael@0: * Copyright 2012 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef GrTextureDomainEffect_DEFINED michael@0: #define GrTextureDomainEffect_DEFINED michael@0: michael@0: #include "GrSingleTextureEffect.h" michael@0: #include "gl/GrGLEffect.h" michael@0: michael@0: class GrGLShaderBuilder; michael@0: struct SkRect; michael@0: michael@0: /** michael@0: * Limits a texture's lookup coordinates to a domain. Samples outside the domain are either clamped michael@0: * the edge of the domain or result in a vec4 of zeros (decal mode). The domain is clipped to michael@0: * normalized texture coords ([0,1]x[0,1] square). Bilinear filtering can cause texels outside the michael@0: * domain to affect the read value unless the caller considers this when calculating the domain. michael@0: */ michael@0: class GrTextureDomain { michael@0: public: michael@0: enum Mode { michael@0: kIgnore_Mode, // Ignore the texture domain rectangle. michael@0: kClamp_Mode, // Clamp texture coords to the domain rectangle. michael@0: kDecal_Mode, // Treat the area outside the domain rectangle as fully transparent. michael@0: michael@0: kLastMode = kDecal_Mode michael@0: }; michael@0: static const int kModeCount = kLastMode + 1; michael@0: michael@0: static const GrTextureDomain& IgnoredDomain() { michael@0: static const SkRect gDummyRect = {0, 0, 0, 0}; michael@0: static const GrTextureDomain gDomain(gDummyRect, kIgnore_Mode); michael@0: return gDomain; michael@0: } michael@0: michael@0: /** michael@0: * @param index Pass a value >= 0 if using multiple texture domains in the same effect. michael@0: * It is used to keep inserted variables from causing name collisions. michael@0: */ michael@0: GrTextureDomain(const SkRect& domain, Mode, int index = -1); michael@0: michael@0: const SkRect& domain() const { return fDomain; } michael@0: Mode mode() const { return fMode; } michael@0: michael@0: /* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled michael@0: texels neighboring the domain may be read. */ michael@0: static const SkRect MakeTexelDomain(const GrTexture* texture, const SkIRect& texelRect) { michael@0: SkScalar wInv = SK_Scalar1 / texture->width(); michael@0: SkScalar hInv = SK_Scalar1 / texture->height(); michael@0: SkRect result = { michael@0: texelRect.fLeft * wInv, michael@0: texelRect.fTop * hInv, michael@0: texelRect.fRight * wInv, michael@0: texelRect.fBottom * hInv michael@0: }; michael@0: return result; michael@0: } michael@0: michael@0: bool operator== (const GrTextureDomain& that) const { michael@0: return fMode == that.fMode && fDomain == that.fDomain; michael@0: } michael@0: michael@0: /** michael@0: * A GrGLEffect subclass that corresponds to a GrEffect subclass that uses GrTextureDomain michael@0: * should include this helper. It generates the texture domain GLSL, produces the part of the michael@0: * effect key that reflects the texture domain code, and performs the uniform uploads necessary michael@0: * for texture domains. michael@0: */ michael@0: class GLDomain { michael@0: public: michael@0: GLDomain() { michael@0: fPrevDomain[0] = SK_FloatNaN; michael@0: SkDEBUGCODE(fMode = (Mode) -1;) michael@0: } michael@0: michael@0: /** michael@0: * Call this from GrGLEffect::emitCode() to sample the texture W.R.T. the domain and mode. michael@0: * michael@0: * @param outcolor name of vec4 variable to hold the sampled color. michael@0: * @param inCoords name of vec2 variable containing the coords to be used with the domain. michael@0: * It is assumed that this is a variable and not an expression. michael@0: * @param inModulateColor if non-NULL the sampled color will be modulated with this michael@0: * expression before being written to outColor. michael@0: */ michael@0: void sampleTexture(GrGLShaderBuilder* builder, michael@0: const GrTextureDomain& textureDomain, michael@0: const char* outColor, michael@0: const SkString& inCoords, michael@0: const GrGLEffect::TextureSampler sampler, michael@0: const char* inModulateColor = NULL); michael@0: michael@0: /** michael@0: * Call this from GrGLEffect::setData() to upload uniforms necessary for the texture domain. michael@0: * The rectangle is automatically adjusted to account for the texture's origin. michael@0: */ michael@0: void setData(const GrGLUniformManager& uman, const GrTextureDomain& textureDomain, michael@0: GrSurfaceOrigin textureOrigin); michael@0: michael@0: enum { michael@0: kDomainKeyBits = 2, // See DomainKey(). michael@0: }; michael@0: michael@0: /** michael@0: * GrGLEffect::GenKey() must call this and include the returned value in it's computed key. michael@0: * The returned will be limited to the lower kDomainKeyBits bits. michael@0: */ michael@0: static GrGLEffect::EffectKey DomainKey(const GrTextureDomain& domain) { michael@0: GR_STATIC_ASSERT(kModeCount <= 4); michael@0: return domain.mode(); michael@0: } michael@0: michael@0: private: michael@0: SkDEBUGCODE(Mode fMode;) michael@0: GrGLUniformManager::UniformHandle fDomainUni; michael@0: SkString fDomainName; michael@0: GrGLfloat fPrevDomain[4]; michael@0: }; michael@0: michael@0: protected: michael@0: Mode fMode; michael@0: SkRect fDomain; michael@0: int fIndex; michael@0: michael@0: typedef GrSingleTextureEffect INHERITED; michael@0: }; michael@0: michael@0: class GrGLTextureDomainEffect; michael@0: michael@0: /** michael@0: * A basic texture effect that uses GrTextureDomain. michael@0: */ michael@0: class GrTextureDomainEffect : public GrSingleTextureEffect { michael@0: michael@0: public: michael@0: static GrEffectRef* Create(GrTexture*, michael@0: const SkMatrix&, michael@0: const SkRect& domain, michael@0: GrTextureDomain::Mode, michael@0: GrTextureParams::FilterMode filterMode, michael@0: GrCoordSet = kLocal_GrCoordSet); michael@0: michael@0: virtual ~GrTextureDomainEffect(); michael@0: michael@0: static const char* Name() { return "TextureDomain"; } michael@0: michael@0: typedef GrGLTextureDomainEffect GLEffect; michael@0: michael@0: virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; michael@0: virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; michael@0: michael@0: const GrTextureDomain& textureDomain() const { return fTextureDomain; } michael@0: michael@0: protected: michael@0: GrTextureDomain fTextureDomain; michael@0: michael@0: private: michael@0: GrTextureDomainEffect(GrTexture*, michael@0: const SkMatrix&, michael@0: const SkRect& domain, michael@0: GrTextureDomain::Mode, michael@0: GrTextureParams::FilterMode, michael@0: GrCoordSet); michael@0: michael@0: virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; michael@0: michael@0: GR_DECLARE_EFFECT_TEST; michael@0: michael@0: typedef GrSingleTextureEffect INHERITED; michael@0: }; michael@0: michael@0: #endif