blob: 8c38f9bebf919071af1c7a079deef5adbca983d2 [file] [log] [blame]
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrDistanceFieldTextureEffect.h"
#include "gl/GrGLEffect.h"
#include "gl/GrGLSL.h"
#include "gl/GrGLTexture.h"
#include "gl/GrGLVertexEffect.h"
#include "GrTBackendEffectFactory.h"
#include "GrTexture.h"
// The distance field is constructed as unsigned char values, so that the zero value is at 128.
// Hence our zero threshold is 128/255.
#define THRESHOLD "0.50196078431"
class GrGLDistanceFieldTextureEffect : public GrGLVertexEffect {
public:
GrGLDistanceFieldTextureEffect(const GrBackendEffectFactory& factory, const GrDrawEffect& drawEffect)
: INHERITED (factory) {}
virtual void emitCode(GrGLFullShaderBuilder* builder,
const GrDrawEffect& drawEffect,
EffectKey key,
const char* outputColor,
const char* inputColor,
const TransformedCoordsArray&,
const TextureSamplerArray& samplers) SK_OVERRIDE {
SkASSERT(1 == drawEffect.castEffect<GrDistanceFieldTextureEffect>().numVertexAttribs());
SkString fsCoordName;
const char* vsVaryingName;
const char* fsVaryingNamePtr;
builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsVaryingName, &fsVaryingNamePtr);
fsCoordName = fsVaryingNamePtr;
const char* attrName =
builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0])->c_str();
builder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, attrName);
builder->fsCodeAppend("\tvec4 texColor = ");
builder->fsAppendTextureLookup(samplers[0],
fsCoordName.c_str(),
kVec2f_GrSLType);
builder->fsCodeAppend(";\n");
builder->fsCodeAppend("\tfloat distance = texColor.r;\n");
// this gives us a smooth step across approximately one fragment
// (assuming a radius of the diagonal of the fragment, hence a factor of sqrt(2)/2)
builder->fsCodeAppend("\tfloat afwidth = 0.7071*length(vec2(dFdx(distance), dFdy(distance)));\n");
builder->fsCodeAppend("\tfloat val = smoothstep("THRESHOLD"-afwidth, "THRESHOLD"+afwidth, distance);\n");
builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
(GrGLSLExpr4(inputColor) * GrGLSLExpr1("val")).c_str());
}
virtual void setData(const GrGLUniformManager& uman,
const GrDrawEffect& drawEffect) SK_OVERRIDE {}
private:
typedef GrGLVertexEffect INHERITED;
};
///////////////////////////////////////////////////////////////////////////////
GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrTexture* texture,
const GrTextureParams& params)
: fTextureAccess(texture, params) {
this->addTextureAccess(&fTextureAccess);
this->addVertexAttrib(kVec2f_GrSLType);
}
bool GrDistanceFieldTextureEffect::onIsEqual(const GrEffect& other) const {
const GrDistanceFieldTextureEffect& cte = CastEffect<GrDistanceFieldTextureEffect>(other);
return fTextureAccess == cte.fTextureAccess;
}
void GrDistanceFieldTextureEffect::getConstantColorComponents(GrColor* color,
uint32_t* validFlags) const {
if ((*validFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(*color) &&
GrPixelConfigIsOpaque(this->texture(0)->config())) {
*validFlags = kA_GrColorComponentFlag;
} else {
*validFlags = 0;
}
}
const GrBackendEffectFactory& GrDistanceFieldTextureEffect::getFactory() const {
return GrTBackendEffectFactory<GrDistanceFieldTextureEffect>::getInstance();
}
///////////////////////////////////////////////////////////////////////////////
GR_DEFINE_EFFECT_TEST(GrDistanceFieldTextureEffect);
GrEffectRef* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random,
GrContext*,
const GrDrawTargetCaps&,
GrTexture* textures[]) {
int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
GrEffectUnitTest::kAlphaTextureIdx;
static const SkShader::TileMode kTileModes[] = {
SkShader::kClamp_TileMode,
SkShader::kRepeat_TileMode,
SkShader::kMirror_TileMode,
};
SkShader::TileMode tileModes[] = {
kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
};
GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
GrTextureParams::kNone_FilterMode);
return GrDistanceFieldTextureEffect::Create(textures[texIdx], params);
}