Index: src/effects/SkPerlinNoiseShader.cpp |
diff --git a/src/effects/SkPerlinNoiseShader.cpp b/src/effects/SkPerlinNoiseShader.cpp |
index 84026b6046434c972faff51ad59b0a53b465b6bb..7f0127ea5a4c5c382390a0259ad0070644211028 100644 |
--- a/src/effects/SkPerlinNoiseShader.cpp |
+++ b/src/effects/SkPerlinNoiseShader.cpp |
@@ -79,10 +79,19 @@ struct SkPerlinNoiseShader::StitchData { |
struct SkPerlinNoiseShader::PaintingData { |
PaintingData(const SkISize& tileSize, SkScalar seed, |
- SkScalar baseFrequencyX, SkScalar baseFrequencyY) |
- : fTileSize(tileSize) |
- , fBaseFrequency(SkPoint::Make(baseFrequencyX, baseFrequencyY)) |
+ SkScalar baseFrequencyX, SkScalar baseFrequencyY, |
+ const SkMatrix& matrix) |
{ |
+ SkVector wavelength = SkVector::Make(SkScalarInvert(baseFrequencyX), |
+ SkScalarInvert(baseFrequencyY)); |
+ matrix.mapVectors(&wavelength, 1); |
+ fBaseFrequency.fX = SkScalarInvert(wavelength.fX); |
+ fBaseFrequency.fY = SkScalarInvert(wavelength.fY); |
+ SkVector sizeVec = SkVector::Make(SkIntToScalar(tileSize.fWidth), |
+ SkIntToScalar(tileSize.fHeight)); |
+ matrix.mapVectors(&sizeVec, 1); |
+ fTileSize.fWidth = SkScalarRoundToInt(sizeVec.fX); |
+ fTileSize.fHeight = SkScalarRoundToInt(sizeVec.fY); |
this->init(seed); |
if (!fTileSize.isEmpty()) { |
this->stitch(); |
@@ -275,7 +284,6 @@ SkPerlinNoiseShader::SkPerlinNoiseShader(SkPerlinNoiseShader::Type type, |
, fStitchTiles(!fTileSize.isEmpty()) |
{ |
SkASSERT(numOctaves >= 0 && numOctaves < 256); |
- fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY)); |
} |
SkPerlinNoiseShader::SkPerlinNoiseShader(SkReadBuffer& buffer) |
@@ -289,15 +297,12 @@ SkPerlinNoiseShader::SkPerlinNoiseShader(SkReadBuffer& buffer) |
fStitchTiles = buffer.readBool(); |
fTileSize.fWidth = buffer.readInt(); |
fTileSize.fHeight = buffer.readInt(); |
- fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY)); |
buffer.validate(perlin_noise_type_is_valid(fType) && |
(fNumOctaves >= 0) && (fNumOctaves <= 255) && |
(fStitchTiles != fTileSize.isEmpty())); |
} |
SkPerlinNoiseShader::~SkPerlinNoiseShader() { |
- // Safety, should have been done in endContext() |
- SkDELETE(fPaintingData); |
} |
void SkPerlinNoiseShader::flatten(SkWriteBuffer& buffer) const { |
@@ -313,8 +318,7 @@ void SkPerlinNoiseShader::flatten(SkWriteBuffer& buffer) const { |
} |
SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::noise2D( |
- int channel, const PaintingData& paintingData, |
- const StitchData& stitchData, const SkPoint& noiseVector) const { |
+ int channel, const StitchData& stitchData, const SkPoint& noiseVector) const { |
struct Noise { |
int noisePositionIntegerValue; |
int nextNoisePositionIntegerValue; |
@@ -347,9 +351,9 @@ SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::noise2D( |
noiseX.nextNoisePositionIntegerValue &= kBlockMask; |
noiseY.nextNoisePositionIntegerValue &= kBlockMask; |
int i = |
- paintingData.fLatticeSelector[noiseX.noisePositionIntegerValue]; |
+ fPaintingData->fLatticeSelector[noiseX.noisePositionIntegerValue]; |
int j = |
- paintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue]; |
+ fPaintingData->fLatticeSelector[noiseX.nextNoisePositionIntegerValue]; |
int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask; |
int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask; |
int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask; |
@@ -359,32 +363,31 @@ SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::noise2D( |
// This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement |
SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue, |
noiseY.noisePositionFractionValue); // Offset (0,0) |
- u = paintingData.fGradient[channel][b00].dot(fractionValue); |
+ u = fPaintingData->fGradient[channel][b00].dot(fractionValue); |
fractionValue.fX -= SK_Scalar1; // Offset (-1,0) |
- v = paintingData.fGradient[channel][b10].dot(fractionValue); |
+ v = fPaintingData->fGradient[channel][b10].dot(fractionValue); |
SkScalar a = SkScalarInterp(u, v, sx); |
fractionValue.fY -= SK_Scalar1; // Offset (-1,-1) |
- v = paintingData.fGradient[channel][b11].dot(fractionValue); |
+ v = fPaintingData->fGradient[channel][b11].dot(fractionValue); |
fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1) |
- u = paintingData.fGradient[channel][b01].dot(fractionValue); |
+ u = fPaintingData->fGradient[channel][b01].dot(fractionValue); |
SkScalar b = SkScalarInterp(u, v, sx); |
return SkScalarInterp(a, b, sy); |
} |
SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint( |
- int channel, const PaintingData& paintingData, |
- StitchData& stitchData, const SkPoint& point) const { |
+ int channel, StitchData& stitchData, const SkPoint& point) const { |
const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader); |
if (perlinNoiseShader.fStitchTiles) { |
// Set up TurbulenceInitial stitch values. |
- stitchData = paintingData.fStitchDataInit; |
+ stitchData = fPaintingData->fStitchDataInit; |
} |
SkScalar turbulenceFunctionResult = 0; |
- SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), paintingData.fBaseFrequency.fX), |
- SkScalarMul(point.y(), paintingData.fBaseFrequency.fY))); |
+ SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), fPaintingData->fBaseFrequency.fX), |
+ SkScalarMul(point.y(), fPaintingData->fBaseFrequency.fY))); |
SkScalar ratio = SK_Scalar1; |
for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) { |
- SkScalar noise = noise2D(channel, paintingData, stitchData, noiseVector); |
+ SkScalar noise = noise2D(channel, stitchData, noiseVector); |
turbulenceFunctionResult += SkScalarDiv( |
(perlinNoiseShader.fType == kFractalNoise_Type) ? noise : SkScalarAbs(noise), ratio); |
noiseVector.fX *= 2; |
@@ -417,7 +420,6 @@ SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::calculateTurbulenceValue |
SkPMColor SkPerlinNoiseShader::PerlinNoiseShaderContext::shade( |
const SkPoint& point, StitchData& stitchData) const { |
- const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader); |
SkPoint newPoint; |
fMatrix.mapPoints(&newPoint, &point, 1); |
newPoint.fX = SkScalarRoundToScalar(newPoint.fX); |
@@ -426,8 +428,7 @@ SkPMColor SkPerlinNoiseShader::PerlinNoiseShaderContext::shade( |
U8CPU rgba[4]; |
for (int channel = 3; channel >= 0; --channel) { |
rgba[channel] = SkScalarFloorToInt(255 * |
- calculateTurbulenceValueForPoint(channel, *perlinNoiseShader.fPaintingData, |
- stitchData, newPoint)); |
+ calculateTurbulenceValueForPoint(channel, stitchData, newPoint)); |
} |
return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]); |
} |
@@ -450,16 +451,14 @@ SkPerlinNoiseShader::PerlinNoiseShaderContext::PerlinNoiseShaderContext( |
if (rec.fLocalMatrix) { |
newMatrix.preConcat(*rec.fLocalMatrix); |
} |
- SkMatrix invMatrix; |
- if (!newMatrix.invert(&invMatrix)) { |
- invMatrix.reset(); |
- } |
// This (1,1) translation is due to WebKit's 1 based coordinates for the noise |
// (as opposed to 0 based, usually). The same adjustment is in the setData() function. |
- newMatrix.postTranslate(SK_Scalar1, SK_Scalar1); |
- newMatrix.postConcat(invMatrix); |
- newMatrix.postConcat(invMatrix); |
- fMatrix = newMatrix; |
+ fMatrix.setTranslate(-newMatrix.getTranslateX() + SK_Scalar1, -newMatrix.getTranslateY() + SK_Scalar1); |
+ fPaintingData = SkNEW_ARGS(PaintingData, (shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX, shader.fBaseFrequencyY, newMatrix)); |
+} |
+ |
+SkPerlinNoiseShader::PerlinNoiseShaderContext::~PerlinNoiseShaderContext() { |
+ SkDELETE(fPaintingData); |
} |
void SkPerlinNoiseShader::PerlinNoiseShaderContext::shadeSpan( |
@@ -517,7 +516,6 @@ private: |
int fNumOctaves; |
GrGLUniformManager::UniformHandle fBaseFrequencyUni; |
GrGLUniformManager::UniformHandle fAlphaUni; |
- GrGLUniformManager::UniformHandle fInvMatrixUni; |
private: |
typedef GrGLEffect INHERITED; |
@@ -527,27 +525,29 @@ private: |
class GrPerlinNoiseEffect : public GrEffect { |
public: |
- static GrEffectRef* Create(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency, |
+ static GrEffectRef* Create(SkPerlinNoiseShader::Type type, |
int numOctaves, bool stitchTiles, |
- const SkPerlinNoiseShader::StitchData& stitchData, |
+ SkPerlinNoiseShader::PaintingData* paintingData, |
GrTexture* permutationsTexture, GrTexture* noiseTexture, |
const SkMatrix& matrix, uint8_t alpha) { |
- AutoEffectUnref effect(SkNEW_ARGS(GrPerlinNoiseEffect, (type, baseFrequency, numOctaves, |
- stitchTiles, stitchData, permutationsTexture, noiseTexture, matrix, alpha))); |
+ AutoEffectUnref effect(SkNEW_ARGS(GrPerlinNoiseEffect, (type, numOctaves, |
+ stitchTiles, paintingData, permutationsTexture, noiseTexture, matrix, alpha))); |
return CreateEffectRef(effect); |
} |
- virtual ~GrPerlinNoiseEffect() { } |
+ virtual ~GrPerlinNoiseEffect() { |
+ SkDELETE(fPaintingData); |
+ } |
static const char* Name() { return "PerlinNoise"; } |
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { |
return GrTBackendEffectFactory<GrPerlinNoiseEffect>::getInstance(); |
} |
- const SkPerlinNoiseShader::StitchData& stitchData() const { return fStitchData; } |
+ const SkPerlinNoiseShader::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; } |
SkPerlinNoiseShader::Type type() const { return fType; } |
bool stitchTiles() const { return fStitchTiles; } |
- const SkVector& baseFrequency() const { return fBaseFrequency; } |
+ const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; } |
int numOctaves() const { return fNumOctaves; } |
const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); } |
uint8_t alpha() const { return fAlpha; } |
@@ -558,34 +558,31 @@ private: |
virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE { |
const GrPerlinNoiseEffect& s = CastEffect<GrPerlinNoiseEffect>(sBase); |
return fType == s.fType && |
- fBaseFrequency == s.fBaseFrequency && |
+ fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency && |
fNumOctaves == s.fNumOctaves && |
fStitchTiles == s.fStitchTiles && |
fCoordTransform.getMatrix() == s.fCoordTransform.getMatrix() && |
fAlpha == s.fAlpha && |
fPermutationsAccess.getTexture() == s.fPermutationsAccess.getTexture() && |
fNoiseAccess.getTexture() == s.fNoiseAccess.getTexture() && |
- fStitchData == s.fStitchData; |
+ fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit; |
} |
- GrPerlinNoiseEffect(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency, |
+ GrPerlinNoiseEffect(SkPerlinNoiseShader::Type type, |
int numOctaves, bool stitchTiles, |
- const SkPerlinNoiseShader::StitchData& stitchData, |
+ SkPerlinNoiseShader::PaintingData* paintingData, |
GrTexture* permutationsTexture, GrTexture* noiseTexture, |
const SkMatrix& matrix, uint8_t alpha) |
: fType(type) |
- , fBaseFrequency(baseFrequency) |
, fNumOctaves(numOctaves) |
, fStitchTiles(stitchTiles) |
, fAlpha(alpha) |
, fPermutationsAccess(permutationsTexture) |
, fNoiseAccess(noiseTexture) |
- , fStitchData(stitchData) { |
+ , fPaintingData(paintingData) { |
this->addTextureAccess(&fPermutationsAccess); |
this->addTextureAccess(&fNoiseAccess); |
- SkMatrix m = matrix; |
- m.postTranslate(SK_Scalar1, SK_Scalar1); |
- fCoordTransform.reset(kLocal_GrCoordSet, m); |
+ fCoordTransform.reset(kLocal_GrCoordSet, matrix); |
this->addCoordTransform(&fCoordTransform); |
this->setWillNotUseInputColor(); |
} |
@@ -594,13 +591,12 @@ private: |
SkPerlinNoiseShader::Type fType; |
GrCoordTransform fCoordTransform; |
- SkVector fBaseFrequency; |
int fNumOctaves; |
bool fStitchTiles; |
uint8_t fAlpha; |
GrTextureAccess fPermutationsAccess; |
GrTextureAccess fNoiseAccess; |
- SkPerlinNoiseShader::StitchData fStitchData; |
+ SkPerlinNoiseShader::PaintingData *fPaintingData; |
void getConstantColorComponents(GrColor*, uint32_t* validFlags) const SK_OVERRIDE { |
*validFlags = 0; // This is noise. Nothing is constant. |
@@ -660,9 +656,6 @@ void GrGLPerlinNoise::emitCode(GrGLShaderBuilder* builder, |
SkString vCoords = builder->ensureFSCoords2D(coords, 0); |
- fInvMatrixUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
- kMat33f_GrSLType, "invMatrix"); |
- const char* invMatrixUni = builder->getUniformCStr(fInvMatrixUni); |
fBaseFrequencyUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
kVec2f_GrSLType, "baseFrequency"); |
const char* baseFrequencyUni = builder->getUniformCStr(fBaseFrequencyUni); |
@@ -841,8 +834,8 @@ void GrGLPerlinNoise::emitCode(GrGLShaderBuilder* builder, |
} |
// There are rounding errors if the floor operation is not performed here |
- builder->fsCodeAppendf("\n\t\tvec2 %s = floor((%s * vec3(%s, 1.0)).xy) * %s;", |
- noiseVec, invMatrixUni, vCoords.c_str(), baseFrequencyUni); |
+ builder->fsCodeAppendf("\n\t\tvec2 %s = floor(%s.xy) * %s;", |
+ noiseVec, vCoords.c_str(), baseFrequencyUni); |
// Clear the color accumulator |
builder->fsCodeAppendf("\n\t\t%s = vec4(0.0);", outputColor); |
@@ -942,16 +935,6 @@ void GrGLPerlinNoise::setData(const GrGLUniformManager& uman, const GrDrawEffect |
uman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY); |
uman.set1f(fAlphaUni, SkScalarDiv(SkIntToScalar(turbulence.alpha()), SkIntToScalar(255))); |
- SkMatrix m = turbulence.matrix(); |
- m.postTranslate(-SK_Scalar1, -SK_Scalar1); |
- SkMatrix invM; |
- if (!m.invert(&invM)) { |
- invM.reset(); |
- } else { |
- invM.postConcat(invM); // Square the matrix |
- } |
- uman.setSkMatrix(fInvMatrixUni, invM); |
- |
if (turbulence.stitchTiles()) { |
const SkPerlinNoiseShader::StitchData& stitchData = turbulence.stitchData(); |
uman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth), |
@@ -967,12 +950,15 @@ bool SkPerlinNoiseShader::asNewEffect(GrContext* context, const SkPaint& paint, |
SkASSERT(NULL != context); |
*grColor = SkColor2GrColorJustAlpha(paint.getColor()); |
- |
+ |
SkMatrix localMatrix = this->getLocalMatrix(); |
if (externalLocalMatrix) { |
localMatrix.preConcat(*externalLocalMatrix); |
} |
+ SkMatrix matrix = context->getMatrix(); |
+ matrix.preConcat(localMatrix); |
+ |
if (0 == fNumOctaves) { |
SkColor clearColor = 0; |
if (kFractalNoise_Type == fType) { |
@@ -987,18 +973,26 @@ bool SkPerlinNoiseShader::asNewEffect(GrContext* context, const SkPaint& paint, |
// Either we don't stitch tiles, either we have a valid tile size |
SkASSERT(!fStitchTiles || !fTileSize.isEmpty()); |
+ SkPerlinNoiseShader::PaintingData* paintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY, matrix)); |
GrTexture* permutationsTexture = GrLockAndRefCachedBitmapTexture( |
- context, fPaintingData->getPermutationsBitmap(), NULL); |
+ context, paintingData->getPermutationsBitmap(), NULL); |
GrTexture* noiseTexture = GrLockAndRefCachedBitmapTexture( |
- context, fPaintingData->getNoiseBitmap(), NULL); |
- |
- *grEffect = (NULL != permutationsTexture) && (NULL != noiseTexture) ? |
- GrPerlinNoiseEffect::Create(fType, fPaintingData->fBaseFrequency, |
- fNumOctaves, fStitchTiles, |
- fPaintingData->fStitchDataInit, |
- permutationsTexture, noiseTexture, |
- localMatrix, paint.getAlpha()) : |
- NULL; |
+ context, paintingData->getNoiseBitmap(), NULL); |
+ |
+ SkMatrix m = context->getMatrix(); |
+ m.setTranslateX(-localMatrix.getTranslateX() + SK_Scalar1); |
+ m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1); |
+ if ((NULL != permutationsTexture) && (NULL != noiseTexture)) { |
+ *grEffect = GrPerlinNoiseEffect::Create(fType, |
+ fNumOctaves, |
+ fStitchTiles, |
+ paintingData, |
+ permutationsTexture, noiseTexture, |
+ m, paint.getAlpha()); |
+ } else { |
+ SkDELETE(paintingData); |
+ *grEffect = NULL; |
+ } |
// Unlock immediately, this is not great, but we don't have a way of |
// knowing when else to unlock it currently. TODO: Remove this when |