| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 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 | #include "SkDither.h" | 
 | 9 | #include "SkPerlinNoiseShader.h" | 
 | 10 | #include "SkFlattenableBuffers.h" | 
 | 11 | #include "SkShader.h" | 
 | 12 | #include "SkUnPreMultiply.h" | 
 | 13 | #include "SkString.h" | 
 | 14 |  | 
 | 15 | #if SK_SUPPORT_GPU | 
 | 16 | #include "GrContext.h" | 
 | 17 | #include "gl/GrGLEffect.h" | 
 | 18 | #include "gl/GrGLEffectMatrix.h" | 
 | 19 | #include "GrTBackendEffectFactory.h" | 
 | 20 | #include "SkGr.h" | 
 | 21 | #endif | 
 | 22 |  | 
 | 23 | static const int kBlockSize = 256; | 
 | 24 | static const int kBlockMask = kBlockSize - 1; | 
 | 25 | static const int kPerlinNoise = 4096; | 
 | 26 | static const int kRandMaximum = SK_MaxS32; // 2**31 - 1 | 
 | 27 |  | 
 | 28 | namespace { | 
 | 29 |  | 
 | 30 | // noiseValue is the color component's value (or color) | 
 | 31 | // limitValue is the maximum perlin noise array index value allowed | 
 | 32 | // newValue is the current noise dimension (either width or height) | 
 | 33 | inline int checkNoise(int noiseValue, int limitValue, int newValue) { | 
 | 34 |     // If the noise value would bring us out of bounds of the current noise array while we are | 
 | 35 |     // stiching noise tiles together, wrap the noise around the current dimension of the noise to | 
 | 36 |     // stay within the array bounds in a continuous fashion (so that tiling lines are not visible) | 
 | 37 |     if (noiseValue >= limitValue) { | 
 | 38 |         noiseValue -= newValue; | 
 | 39 |     } | 
 | 40 |     if (noiseValue >= limitValue - 1) { | 
 | 41 |         noiseValue -= newValue - 1; | 
 | 42 |     } | 
 | 43 |     return noiseValue; | 
 | 44 | } | 
 | 45 |  | 
 | 46 | inline SkScalar smoothCurve(SkScalar t) { | 
 | 47 |     static const SkScalar SK_Scalar3 = SkFloatToScalar(3.0f); | 
 | 48 |  | 
 | 49 |     // returns t * t * (3 - 2 * t) | 
 | 50 |     return SkScalarMul(SkScalarSquare(t), SK_Scalar3 - 2 * t); | 
 | 51 | } | 
 | 52 |  | 
 | 53 | } // end namespace | 
 | 54 |  | 
 | 55 | struct SkPerlinNoiseShader::StitchData { | 
 | 56 |     StitchData() | 
 | 57 |       : fWidth(0) | 
 | 58 |       , fWrapX(0) | 
 | 59 |       , fHeight(0) | 
 | 60 |       , fWrapY(0) | 
 | 61 |     {} | 
 | 62 |  | 
 | 63 |     bool operator==(const StitchData& other) const { | 
 | 64 |         return fWidth == other.fWidth && | 
 | 65 |                fWrapX == other.fWrapX && | 
 | 66 |                fHeight == other.fHeight && | 
 | 67 |                fWrapY == other.fWrapY; | 
 | 68 |     } | 
 | 69 |  | 
 | 70 |     int fWidth; // How much to subtract to wrap for stitching. | 
 | 71 |     int fWrapX; // Minimum value to wrap. | 
 | 72 |     int fHeight; | 
 | 73 |     int fWrapY; | 
 | 74 | }; | 
 | 75 |  | 
 | 76 | struct SkPerlinNoiseShader::PaintingData { | 
 | 77 |     PaintingData(const SkISize& tileSize) | 
 | 78 |       : fSeed(0) | 
 | 79 |       , fTileSize(tileSize) | 
 | 80 |       , fPermutationsBitmap(NULL) | 
 | 81 |       , fNoiseBitmap(NULL) | 
 | 82 |     {} | 
 | 83 |  | 
 | 84 |     ~PaintingData() | 
 | 85 |     { | 
 | 86 |         SkDELETE(fPermutationsBitmap); | 
 | 87 |         SkDELETE(fNoiseBitmap); | 
 | 88 |     } | 
 | 89 |  | 
 | 90 |     int         fSeed; | 
 | 91 |     uint8_t     fLatticeSelector[kBlockSize]; | 
 | 92 |     uint16_t    fNoise[4][kBlockSize][2]; | 
 | 93 |     SkPoint     fGradient[4][kBlockSize]; | 
 | 94 |     SkISize     fTileSize; | 
 | 95 |     SkVector    fBaseFrequency; | 
 | 96 |     StitchData  fStitchDataInit; | 
 | 97 |  | 
 | 98 | private: | 
 | 99 |  | 
 | 100 |     SkBitmap*    fPermutationsBitmap; | 
 | 101 |     SkBitmap*    fNoiseBitmap; | 
 | 102 |  | 
 | 103 | public: | 
 | 104 |  | 
 | 105 |     inline int random()  { | 
 | 106 |         static const int gRandAmplitude = 16807; // 7**5; primitive root of m | 
 | 107 |         static const int gRandQ = 127773; // m / a | 
 | 108 |         static const int gRandR = 2836; // m % a | 
 | 109 |  | 
 | 110 |         int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ); | 
 | 111 |         if (result <= 0) | 
 | 112 |             result += kRandMaximum; | 
 | 113 |         fSeed = result; | 
 | 114 |         return result; | 
 | 115 |     } | 
 | 116 |  | 
 | 117 |     void init(SkScalar seed) | 
 | 118 |     { | 
 | 119 |         static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize)); | 
 | 120 |  | 
 | 121 |         // The seed value clamp to the range [1, kRandMaximum - 1]. | 
 | 122 |         fSeed = SkScalarRoundToInt(seed); | 
 | 123 |         if (fSeed <= 0) { | 
 | 124 |             fSeed = -(fSeed % (kRandMaximum - 1)) + 1; | 
 | 125 |         } | 
 | 126 |         if (fSeed > kRandMaximum - 1) { | 
 | 127 |             fSeed = kRandMaximum - 1; | 
 | 128 |         } | 
 | 129 |         for (int channel = 0; channel < 4; ++channel) { | 
 | 130 |             for (int i = 0; i < kBlockSize; ++i) { | 
 | 131 |                 fLatticeSelector[i] = i; | 
 | 132 |                 fNoise[channel][i][0] = (random() % (2 * kBlockSize)); | 
 | 133 |                 fNoise[channel][i][1] = (random() % (2 * kBlockSize)); | 
 | 134 |             } | 
 | 135 |         } | 
 | 136 |         for (int i = kBlockSize - 1; i > 0; --i) { | 
 | 137 |             int k = fLatticeSelector[i]; | 
 | 138 |             int j = random() % kBlockSize; | 
 | 139 |             SkASSERT(j >= 0); | 
 | 140 |             SkASSERT(j < kBlockSize); | 
 | 141 |             fLatticeSelector[i] = fLatticeSelector[j]; | 
 | 142 |             fLatticeSelector[j] = k; | 
 | 143 |         } | 
 | 144 |  | 
 | 145 |         // Perform the permutations now | 
 | 146 |         { | 
 | 147 |             // Copy noise data | 
 | 148 |             uint16_t noise[4][kBlockSize][2]; | 
 | 149 |             for (int i = 0; i < kBlockSize; ++i) { | 
 | 150 |                 for (int channel = 0; channel < 4; ++channel) { | 
 | 151 |                     for (int j = 0; j < 2; ++j) { | 
 | 152 |                         noise[channel][i][j] = fNoise[channel][i][j]; | 
 | 153 |                     } | 
 | 154 |                 } | 
 | 155 |             } | 
 | 156 |             // Do permutations on noise data | 
 | 157 |             for (int i = 0; i < kBlockSize; ++i) { | 
 | 158 |                 for (int channel = 0; channel < 4; ++channel) { | 
 | 159 |                     for (int j = 0; j < 2; ++j) { | 
 | 160 |                         fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j]; | 
 | 161 |                     } | 
 | 162 |                 } | 
 | 163 |             } | 
 | 164 |         } | 
 | 165 |  | 
 | 166 |         // Half of the largest possible value for 16 bit unsigned int | 
 | 167 |         static const SkScalar halfMax16bits = SkFloatToScalar(32767.5f); | 
 | 168 |  | 
 | 169 |         // Compute gradients from permutated noise data | 
 | 170 |         for (int channel = 0; channel < 4; ++channel) { | 
 | 171 |             for (int i = 0; i < kBlockSize; ++i) { | 
 | 172 |                 fGradient[channel][i] = SkPoint::Make( | 
 | 173 |                     SkScalarMul(SkIntToScalar(fNoise[channel][i][0] - kBlockSize), | 
 | 174 |                                 gInvBlockSizef), | 
| skia.committer@gmail.com | cff0243 | 2013-04-06 07:01:10 +0000 | [diff] [blame] | 175 |                     SkScalarMul(SkIntToScalar(fNoise[channel][i][1] - kBlockSize), | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 176 |                                 gInvBlockSizef)); | 
 | 177 |                 fGradient[channel][i].normalize(); | 
 | 178 |                 // Put the normalized gradient back into the noise data | 
 | 179 |                 fNoise[channel][i][0] = SkScalarRoundToInt(SkScalarMul( | 
 | 180 |                     fGradient[channel][i].fX + SK_Scalar1, halfMax16bits)); | 
 | 181 |                 fNoise[channel][i][1] = SkScalarRoundToInt(SkScalarMul( | 
 | 182 |                     fGradient[channel][i].fY + SK_Scalar1, halfMax16bits)); | 
 | 183 |             } | 
 | 184 |         } | 
 | 185 |  | 
 | 186 |         // Invalidate bitmaps | 
 | 187 |         SkDELETE(fPermutationsBitmap); | 
 | 188 |         fPermutationsBitmap = NULL; | 
 | 189 |         SkDELETE(fNoiseBitmap); | 
 | 190 |         fNoiseBitmap = NULL; | 
 | 191 |     } | 
 | 192 |  | 
 | 193 |     void stitch() { | 
 | 194 |         SkScalar tileWidth  = SkIntToScalar(fTileSize.width()); | 
 | 195 |         SkScalar tileHeight = SkIntToScalar(fTileSize.height()); | 
 | 196 |         SkASSERT(tileWidth > 0 && tileHeight > 0); | 
 | 197 |         // When stitching tiled turbulence, the frequencies must be adjusted | 
 | 198 |         // so that the tile borders will be continuous. | 
 | 199 |         if (fBaseFrequency.fX) { | 
 | 200 |             SkScalar lowFrequencx = SkScalarDiv( | 
 | 201 |                 SkScalarMulFloor(tileWidth, fBaseFrequency.fX), tileWidth); | 
 | 202 |             SkScalar highFrequencx = SkScalarDiv( | 
 | 203 |                 SkScalarMulCeil(tileWidth, fBaseFrequency.fX), tileWidth); | 
 | 204 |             // BaseFrequency should be non-negative according to the standard. | 
| skia.committer@gmail.com | cff0243 | 2013-04-06 07:01:10 +0000 | [diff] [blame] | 205 |             if (SkScalarDiv(fBaseFrequency.fX, lowFrequencx) < | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 206 |                 SkScalarDiv(highFrequencx, fBaseFrequency.fX)) { | 
 | 207 |                 fBaseFrequency.fX = lowFrequencx; | 
 | 208 |             } else { | 
 | 209 |                 fBaseFrequency.fX = highFrequencx; | 
 | 210 |             } | 
 | 211 |         } | 
 | 212 |         if (fBaseFrequency.fY) { | 
 | 213 |             SkScalar lowFrequency = SkScalarDiv( | 
 | 214 |                 SkScalarMulFloor(tileHeight, fBaseFrequency.fY), tileHeight); | 
 | 215 |             SkScalar highFrequency = SkScalarDiv( | 
 | 216 |                 SkScalarMulCeil(tileHeight, fBaseFrequency.fY), tileHeight); | 
| skia.committer@gmail.com | cff0243 | 2013-04-06 07:01:10 +0000 | [diff] [blame] | 217 |             if (SkScalarDiv(fBaseFrequency.fY, lowFrequency) < | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 218 |                 SkScalarDiv(highFrequency, fBaseFrequency.fY)) { | 
 | 219 |                 fBaseFrequency.fY = lowFrequency; | 
 | 220 |             } else { | 
 | 221 |                 fBaseFrequency.fY = highFrequency; | 
 | 222 |             } | 
 | 223 |         } | 
 | 224 |         // Set up TurbulenceInitial stitch values. | 
 | 225 |         fStitchDataInit.fWidth  = | 
 | 226 |             SkScalarMulRound(tileWidth, fBaseFrequency.fX); | 
 | 227 |         fStitchDataInit.fWrapX  = kPerlinNoise + fStitchDataInit.fWidth; | 
 | 228 |         fStitchDataInit.fHeight = | 
 | 229 |             SkScalarMulRound(tileHeight, fBaseFrequency.fY); | 
 | 230 |         fStitchDataInit.fWrapY  = kPerlinNoise + fStitchDataInit.fHeight; | 
 | 231 |     } | 
 | 232 |  | 
 | 233 |     SkBitmap* getPermutationsBitmap() | 
 | 234 |     { | 
 | 235 |         if (!fPermutationsBitmap) { | 
 | 236 |             fPermutationsBitmap = SkNEW(SkBitmap); | 
 | 237 |             fPermutationsBitmap->setConfig(SkBitmap::kA8_Config, kBlockSize, 1); | 
 | 238 |             fPermutationsBitmap->allocPixels(); | 
 | 239 |             uint8_t* bitmapPixels = fPermutationsBitmap->getAddr8(0, 0); | 
 | 240 |             memcpy(bitmapPixels, fLatticeSelector, sizeof(uint8_t) * kBlockSize); | 
 | 241 |         } | 
 | 242 |         return fPermutationsBitmap; | 
 | 243 |     } | 
 | 244 |  | 
 | 245 |     SkBitmap* getNoiseBitmap() | 
 | 246 |     { | 
 | 247 |         if (!fNoiseBitmap) { | 
 | 248 |             fNoiseBitmap = SkNEW(SkBitmap); | 
 | 249 |             fNoiseBitmap->setConfig(SkBitmap::kARGB_8888_Config, kBlockSize, 4); | 
 | 250 |             fNoiseBitmap->allocPixels(); | 
 | 251 |             uint32_t* bitmapPixels = fNoiseBitmap->getAddr32(0, 0); | 
 | 252 |             memcpy(bitmapPixels, fNoise[0][0], sizeof(uint16_t) * kBlockSize * 4 * 2); | 
 | 253 |         } | 
 | 254 |         return fNoiseBitmap; | 
 | 255 |     } | 
 | 256 | }; | 
 | 257 |  | 
 | 258 | SkShader* SkPerlinNoiseShader::CreateFractalNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY, | 
 | 259 |                                                   int numOctaves, SkScalar seed, | 
 | 260 |                                                   const SkISize* tileSize) { | 
 | 261 |     return SkNEW_ARGS(SkPerlinNoiseShader, (kFractalNoise_Type, baseFrequencyX, baseFrequencyY, | 
 | 262 |                                             numOctaves, seed, tileSize)); | 
 | 263 | } | 
 | 264 |  | 
 | 265 | SkShader* SkPerlinNoiseShader::CreateTubulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, | 
 | 266 |                                               int numOctaves, SkScalar seed, | 
 | 267 |                                               const SkISize* tileSize) { | 
 | 268 |     return SkNEW_ARGS(SkPerlinNoiseShader, (kTurbulence_Type, baseFrequencyX, baseFrequencyY, | 
 | 269 |                                             numOctaves, seed, tileSize)); | 
 | 270 | } | 
 | 271 |  | 
 | 272 | SkPerlinNoiseShader::SkPerlinNoiseShader(SkPerlinNoiseShader::Type type, | 
 | 273 |                                          SkScalar baseFrequencyX, | 
 | 274 |                                          SkScalar baseFrequencyY, | 
 | 275 |                                          int numOctaves, | 
 | 276 |                                          SkScalar seed, | 
 | 277 |                                          const SkISize* tileSize) | 
 | 278 |   : fType(type) | 
 | 279 |   , fBaseFrequencyX(baseFrequencyX) | 
 | 280 |   , fBaseFrequencyY(baseFrequencyY) | 
 | 281 |   , fNumOctaves(numOctaves & 0xFF /*[0,255] octaves allowed*/) | 
 | 282 |   , fSeed(seed) | 
 | 283 |   , fStitchTiles((tileSize != NULL) && !tileSize->isEmpty()) | 
 | 284 |   , fPaintingData(NULL) | 
 | 285 | { | 
 | 286 |     SkASSERT(numOctaves >= 0 && numOctaves < 256); | 
 | 287 |     setTileSize(fStitchTiles ? *tileSize : SkISize::Make(0,0)); | 
 | 288 |     fMatrix.reset(); | 
 | 289 | } | 
 | 290 |  | 
 | 291 | SkPerlinNoiseShader::SkPerlinNoiseShader(SkFlattenableReadBuffer& buffer) : | 
 | 292 |         INHERITED(buffer), fPaintingData(NULL) { | 
 | 293 |     fType           = (SkPerlinNoiseShader::Type) buffer.readInt(); | 
 | 294 |     fBaseFrequencyX = buffer.readScalar(); | 
 | 295 |     fBaseFrequencyY = buffer.readScalar(); | 
 | 296 |     fNumOctaves     = buffer.readInt(); | 
 | 297 |     fSeed           = buffer.readScalar(); | 
 | 298 |     fStitchTiles    = buffer.readBool(); | 
 | 299 |     fTileSize.fWidth  = buffer.readInt(); | 
 | 300 |     fTileSize.fHeight = buffer.readInt(); | 
 | 301 |     setTileSize(fTileSize); | 
 | 302 |     fMatrix.reset(); | 
 | 303 | } | 
 | 304 |  | 
 | 305 | SkPerlinNoiseShader::~SkPerlinNoiseShader() { | 
 | 306 |     // Safety, should have been done in endContext() | 
 | 307 |     SkDELETE(fPaintingData); | 
 | 308 | } | 
 | 309 |  | 
 | 310 | void SkPerlinNoiseShader::flatten(SkFlattenableWriteBuffer& buffer) const { | 
 | 311 |     this->INHERITED::flatten(buffer); | 
 | 312 |     buffer.writeInt((int) fType); | 
 | 313 |     buffer.writeScalar(fBaseFrequencyX); | 
 | 314 |     buffer.writeScalar(fBaseFrequencyY); | 
 | 315 |     buffer.writeInt(fNumOctaves); | 
 | 316 |     buffer.writeScalar(fSeed); | 
 | 317 |     buffer.writeBool(fStitchTiles); | 
 | 318 |     buffer.writeInt(fTileSize.fWidth); | 
 | 319 |     buffer.writeInt(fTileSize.fHeight); | 
 | 320 | } | 
 | 321 |  | 
 | 322 | void SkPerlinNoiseShader::initPaint(PaintingData& paintingData) | 
 | 323 | { | 
 | 324 |     paintingData.init(fSeed); | 
 | 325 |  | 
 | 326 |     // Set frequencies to original values | 
 | 327 |     paintingData.fBaseFrequency.set(fBaseFrequencyX, fBaseFrequencyY); | 
 | 328 |     // Adjust frequecies based on size if stitching is enabled | 
 | 329 |     if (fStitchTiles) { | 
 | 330 |         paintingData.stitch(); | 
 | 331 |     } | 
 | 332 | } | 
 | 333 |  | 
 | 334 | void SkPerlinNoiseShader::setTileSize(const SkISize& tileSize) { | 
 | 335 |     fTileSize = tileSize; | 
 | 336 |  | 
 | 337 |     if (NULL == fPaintingData) { | 
 | 338 |         fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize)); | 
 | 339 |         initPaint(*fPaintingData); | 
 | 340 |     } else { | 
 | 341 |         // Set Size | 
 | 342 |         fPaintingData->fTileSize = fTileSize; | 
 | 343 |         // Set frequencies to original values | 
 | 344 |         fPaintingData->fBaseFrequency.set(fBaseFrequencyX, fBaseFrequencyY); | 
 | 345 |         // Adjust frequecies based on size if stitching is enabled | 
 | 346 |         if (fStitchTiles) { | 
 | 347 |             fPaintingData->stitch(); | 
 | 348 |         } | 
 | 349 |     } | 
 | 350 | } | 
 | 351 |  | 
 | 352 | SkScalar SkPerlinNoiseShader::noise2D(int channel, const PaintingData& paintingData, | 
 | 353 |                                      const StitchData& stitchData, const SkPoint& noiseVector) | 
 | 354 | { | 
 | 355 |     struct Noise { | 
 | 356 |         int noisePositionIntegerValue; | 
 | 357 |         SkScalar noisePositionFractionValue; | 
 | 358 |         Noise(SkScalar component) | 
 | 359 |         { | 
 | 360 |             SkScalar position = component + kPerlinNoise; | 
 | 361 |             noisePositionIntegerValue = SkScalarFloorToInt(position); | 
 | 362 |             noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue); | 
 | 363 |         } | 
 | 364 |     }; | 
 | 365 |     Noise noiseX(noiseVector.x()); | 
 | 366 |     Noise noiseY(noiseVector.y()); | 
 | 367 |     SkScalar u, v; | 
 | 368 |     // If stitching, adjust lattice points accordingly. | 
 | 369 |     if (fStitchTiles) { | 
 | 370 |         noiseX.noisePositionIntegerValue = | 
 | 371 |             checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth); | 
 | 372 |         noiseY.noisePositionIntegerValue = | 
 | 373 |             checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight); | 
 | 374 |     } | 
 | 375 |     noiseX.noisePositionIntegerValue &= kBlockMask; | 
 | 376 |     noiseY.noisePositionIntegerValue &= kBlockMask; | 
 | 377 |     int latticeIndex = | 
| skia.committer@gmail.com | cff0243 | 2013-04-06 07:01:10 +0000 | [diff] [blame] | 378 |         paintingData.fLatticeSelector[noiseX.noisePositionIntegerValue] + | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 379 |         noiseY.noisePositionIntegerValue; | 
 | 380 |     int nextLatticeIndex = | 
| skia.committer@gmail.com | cff0243 | 2013-04-06 07:01:10 +0000 | [diff] [blame] | 381 |         paintingData.fLatticeSelector[(noiseX.noisePositionIntegerValue + 1) & kBlockMask] + | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 382 |         noiseY.noisePositionIntegerValue; | 
 | 383 |     SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue); | 
 | 384 |     SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue); | 
 | 385 |     // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement | 
 | 386 |     SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue, | 
 | 387 |                                           noiseY.noisePositionFractionValue); // Offset (0,0) | 
 | 388 |     u = paintingData.fGradient[channel][latticeIndex & kBlockMask].dot(fractionValue); | 
 | 389 |     fractionValue.fX -= SK_Scalar1; // Offset (-1,0) | 
 | 390 |     v = paintingData.fGradient[channel][nextLatticeIndex & kBlockMask].dot(fractionValue); | 
 | 391 |     SkScalar a = SkScalarInterp(u, v, sx); | 
 | 392 |     fractionValue.fY -= SK_Scalar1; // Offset (-1,-1) | 
 | 393 |     v = paintingData.fGradient[channel][(nextLatticeIndex + 1) & kBlockMask].dot(fractionValue); | 
 | 394 |     fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1) | 
 | 395 |     u = paintingData.fGradient[channel][(latticeIndex + 1) & kBlockMask].dot(fractionValue); | 
 | 396 |     SkScalar b = SkScalarInterp(u, v, sx); | 
 | 397 |     return SkScalarInterp(a, b, sy); | 
 | 398 | } | 
 | 399 |  | 
 | 400 | SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint( | 
 | 401 |     int channel, const PaintingData& paintingData, StitchData& stitchData, const SkPoint& point) | 
 | 402 | { | 
 | 403 |     if (fStitchTiles) { | 
 | 404 |         // Set up TurbulenceInitial stitch values. | 
 | 405 |         stitchData = paintingData.fStitchDataInit; | 
 | 406 |     } | 
 | 407 |     SkScalar turbulenceFunctionResult = 0; | 
 | 408 |     SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), paintingData.fBaseFrequency.fX), | 
 | 409 |                                       SkScalarMul(point.y(), paintingData.fBaseFrequency.fY))); | 
 | 410 |     SkScalar ratio = SK_Scalar1; | 
 | 411 |     for (int octave = 0; octave < fNumOctaves; ++octave) { | 
 | 412 |         SkScalar noise = noise2D(channel, paintingData, stitchData, noiseVector); | 
 | 413 |         turbulenceFunctionResult += SkScalarDiv( | 
 | 414 |             (fType == kFractalNoise_Type) ? noise : SkScalarAbs(noise), ratio); | 
 | 415 |         noiseVector.fX *= 2; | 
 | 416 |         noiseVector.fY *= 2; | 
 | 417 |         ratio *= 2; | 
 | 418 |         if (fStitchTiles) { | 
 | 419 |             // Update stitch values | 
 | 420 |             stitchData.fWidth  *= 2; | 
 | 421 |             stitchData.fWrapX   = stitchData.fWidth + kPerlinNoise; | 
 | 422 |             stitchData.fHeight *= 2; | 
 | 423 |             stitchData.fWrapY   = stitchData.fHeight + kPerlinNoise; | 
 | 424 |         } | 
 | 425 |     } | 
 | 426 |  | 
 | 427 |     // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2 | 
 | 428 |     // by fractalNoise and (turbulenceFunctionResult) by turbulence. | 
 | 429 |     if (fType == kFractalNoise_Type) { | 
 | 430 |         turbulenceFunctionResult = | 
 | 431 |             SkScalarMul(turbulenceFunctionResult, SK_ScalarHalf) + SK_ScalarHalf; | 
 | 432 |     } | 
 | 433 |  | 
 | 434 |     if (channel == 3) { // Scale alpha by paint value | 
 | 435 |         turbulenceFunctionResult = SkScalarMul(turbulenceFunctionResult, | 
 | 436 |             SkScalarDiv(SkIntToScalar(getPaintAlpha()), SkIntToScalar(255))); | 
 | 437 |     } | 
 | 438 |  | 
 | 439 |     // Clamp result | 
 | 440 |     return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1); | 
 | 441 | } | 
 | 442 |  | 
 | 443 | SkPMColor SkPerlinNoiseShader::shade(const SkPoint& point, StitchData& stitchData) { | 
 | 444 |     SkMatrix matrix = fMatrix; | 
 | 445 |     SkMatrix invMatrix; | 
 | 446 |     if (!matrix.invert(&invMatrix)) { | 
 | 447 |         invMatrix.reset(); | 
 | 448 |     } else { | 
 | 449 |         invMatrix.postConcat(invMatrix); // Square the matrix | 
 | 450 |     } | 
 | 451 |     // This (1,1) translation is due to WebKit's 1 based coordinates for the noise | 
 | 452 |     // (as opposed to 0 based, usually). The same adjustment is in the setData() function. | 
 | 453 |     matrix.postTranslate(SK_Scalar1, SK_Scalar1); | 
 | 454 |     SkPoint newPoint; | 
 | 455 |     matrix.mapPoints(&newPoint, &point, 1); | 
 | 456 |     invMatrix.mapPoints(&newPoint, &newPoint, 1); | 
 | 457 |     newPoint.fX = SkScalarRoundToScalar(newPoint.fX); | 
 | 458 |     newPoint.fY = SkScalarRoundToScalar(newPoint.fY); | 
 | 459 |  | 
 | 460 |     U8CPU rgba[4]; | 
 | 461 |     for (int channel = 3; channel >= 0; --channel) { | 
 | 462 |         rgba[channel] = SkScalarFloorToInt(255 * | 
 | 463 |             calculateTurbulenceValueForPoint(channel, *fPaintingData, stitchData, newPoint)); | 
 | 464 |     } | 
 | 465 |     return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]); | 
 | 466 | } | 
 | 467 |  | 
 | 468 | bool SkPerlinNoiseShader::setContext(const SkBitmap& device, const SkPaint& paint, | 
 | 469 |                                      const SkMatrix& matrix) { | 
 | 470 |     fMatrix = matrix; | 
 | 471 |     return INHERITED::setContext(device, paint, matrix); | 
 | 472 | } | 
 | 473 |  | 
 | 474 | void SkPerlinNoiseShader::shadeSpan(int x, int y, SkPMColor result[], int count) { | 
 | 475 |     SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y)); | 
 | 476 |     StitchData stitchData; | 
 | 477 |     for (int i = 0; i < count; ++i) { | 
 | 478 |         result[i] = shade(point, stitchData); | 
 | 479 |         point.fX += SK_Scalar1; | 
 | 480 |     } | 
 | 481 | } | 
 | 482 |  | 
 | 483 | void SkPerlinNoiseShader::shadeSpan16(int x, int y, uint16_t result[], int count) { | 
 | 484 |     SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y)); | 
 | 485 |     StitchData stitchData; | 
 | 486 |     DITHER_565_SCAN(y); | 
 | 487 |     for (int i = 0; i < count; ++i) { | 
 | 488 |         unsigned dither = DITHER_VALUE(x); | 
 | 489 |         result[i] = SkDitherRGB32To565(shade(point, stitchData), dither); | 
 | 490 |         DITHER_INC_X(x); | 
 | 491 |         point.fX += SK_Scalar1; | 
 | 492 |     } | 
 | 493 | } | 
 | 494 |  | 
 | 495 | ///////////////////////////////////////////////////////////////////// | 
 | 496 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 497 | #if SK_SUPPORT_GPU && !defined(SK_BUILD_FOR_ANDROID) | 
 | 498 | // CPU noise is faster on Android, so the GPU implementation is only for desktop | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 499 |  | 
 | 500 | #include "GrTBackendEffectFactory.h" | 
 | 501 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 502 | class GrGLNoise : public GrGLEffect { | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 503 | public: | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 504 |     GrGLNoise(const GrBackendEffectFactory& factory, | 
 | 505 |               const GrDrawEffect& drawEffect); | 
 | 506 |     virtual ~GrGLNoise() {} | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 507 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 508 |     static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); | 
 | 509 |  | 
 | 510 |     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; | 
 | 511 |  | 
 | 512 | protected: | 
 | 513 |     SkPerlinNoiseShader::Type           fType; | 
 | 514 |     bool                                fStitchTiles; | 
 | 515 |     int                                 fNumOctaves; | 
 | 516 |     GrGLUniformManager::UniformHandle   fBaseFrequencyUni; | 
 | 517 |     GrGLUniformManager::UniformHandle   fAlphaUni; | 
 | 518 |     GrGLUniformManager::UniformHandle   fInvMatrixUni; | 
 | 519 |     GrGLEffectMatrix                    fEffectMatrix; | 
 | 520 |  | 
 | 521 | private: | 
 | 522 |     typedef GrGLEffect INHERITED; | 
 | 523 | }; | 
 | 524 |  | 
 | 525 | class GrGLPerlinNoise : public GrGLNoise { | 
 | 526 | public: | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 527 |     GrGLPerlinNoise(const GrBackendEffectFactory& factory, | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 528 |                     const GrDrawEffect& drawEffect) | 
 | 529 |       : GrGLNoise(factory, drawEffect) {} | 
 | 530 |     virtual ~GrGLPerlinNoise() {} | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 531 |  | 
 | 532 |     virtual void emitCode(GrGLShaderBuilder*, | 
 | 533 |                           const GrDrawEffect&, | 
 | 534 |                           EffectKey, | 
 | 535 |                           const char* outputColor, | 
 | 536 |                           const char* inputColor, | 
 | 537 |                           const TextureSamplerArray&) SK_OVERRIDE; | 
 | 538 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 539 |     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 540 |  | 
 | 541 | private: | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 542 |     GrGLUniformManager::UniformHandle fStitchDataUni; | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 543 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 544 |     typedef GrGLNoise INHERITED; | 
 | 545 | }; | 
 | 546 |  | 
 | 547 | class GrGLSimplexNoise : public GrGLNoise { | 
 | 548 |     // Note : This is for reference only. GrGLPerlinNoise is used for processing. | 
 | 549 | public: | 
 | 550 |     GrGLSimplexNoise(const GrBackendEffectFactory& factory, | 
 | 551 |                      const GrDrawEffect& drawEffect) | 
 | 552 |       : GrGLNoise(factory, drawEffect) {} | 
 | 553 |  | 
 | 554 |     virtual ~GrGLSimplexNoise() {} | 
 | 555 |  | 
 | 556 |     virtual void emitCode(GrGLShaderBuilder*, | 
 | 557 |                           const GrDrawEffect&, | 
 | 558 |                           EffectKey, | 
 | 559 |                           const char* outputColor, | 
 | 560 |                           const char* inputColor, | 
 | 561 |                           const TextureSamplerArray&) SK_OVERRIDE; | 
 | 562 |  | 
 | 563 |     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; | 
 | 564 |  | 
 | 565 | private: | 
 | 566 |     GrGLUniformManager::UniformHandle fSeedUni; | 
 | 567 |  | 
 | 568 |     typedef GrGLNoise INHERITED; | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 569 | }; | 
 | 570 |  | 
 | 571 | ///////////////////////////////////////////////////////////////////// | 
 | 572 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 573 | class GrNoiseEffect : public GrEffect { | 
 | 574 | public: | 
 | 575 |     virtual ~GrNoiseEffect() { } | 
 | 576 |  | 
 | 577 |     SkPerlinNoiseShader::Type type() const { return fType; } | 
 | 578 |     bool stitchTiles() const { return fStitchTiles; } | 
 | 579 |     const SkVector& baseFrequency() const { return fBaseFrequency; } | 
 | 580 |     int numOctaves() const { return fNumOctaves; } | 
 | 581 |     const SkMatrix& matrix() const { return fMatrix; } | 
 | 582 |     uint8_t alpha() const { return fAlpha; } | 
 | 583 |     GrGLEffectMatrix::CoordsType coordsType() const { return GrEffect::kLocal_CoordsType; } | 
 | 584 |  | 
 | 585 |     void getConstantColorComponents(GrColor*, uint32_t* validFlags) const SK_OVERRIDE { | 
 | 586 |         *validFlags = 0; // This is noise. Nothing is constant. | 
 | 587 |     } | 
 | 588 |  | 
 | 589 | protected: | 
 | 590 |     virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE { | 
 | 591 |         const GrNoiseEffect& s = CastEffect<GrNoiseEffect>(sBase); | 
 | 592 |         return fType == s.fType && | 
 | 593 |                fBaseFrequency == s.fBaseFrequency && | 
 | 594 |                fNumOctaves == s.fNumOctaves && | 
 | 595 |                fStitchTiles == s.fStitchTiles && | 
 | 596 |                fMatrix == s.fMatrix && | 
 | 597 |                fAlpha == s.fAlpha; | 
 | 598 |     } | 
 | 599 |  | 
 | 600 |     GrNoiseEffect(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency, int numOctaves, | 
 | 601 |                   bool stitchTiles, const SkMatrix& matrix, uint8_t alpha) | 
 | 602 |       : fType(type) | 
 | 603 |       , fBaseFrequency(baseFrequency) | 
 | 604 |       , fNumOctaves(numOctaves) | 
 | 605 |       , fStitchTiles(stitchTiles) | 
 | 606 |       , fMatrix(matrix) | 
 | 607 |       , fAlpha(alpha) { | 
 | 608 |     } | 
 | 609 |  | 
 | 610 |     SkPerlinNoiseShader::Type       fType; | 
 | 611 |     SkVector                        fBaseFrequency; | 
 | 612 |     int                             fNumOctaves; | 
 | 613 |     bool                            fStitchTiles; | 
 | 614 |     SkMatrix                        fMatrix; | 
 | 615 |     uint8_t                         fAlpha; | 
 | 616 |  | 
 | 617 | private: | 
 | 618 |     typedef GrEffect INHERITED; | 
 | 619 | }; | 
 | 620 |  | 
 | 621 | class GrPerlinNoiseEffect : public GrNoiseEffect { | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 622 | public: | 
 | 623 |     static GrEffectRef* Create(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency, | 
 | 624 |                                int numOctaves, bool stitchTiles, | 
 | 625 |                                const SkPerlinNoiseShader::StitchData& stitchData, | 
 | 626 |                                GrTexture* permutationsTexture, GrTexture* noiseTexture, | 
 | 627 |                                const SkMatrix& matrix, uint8_t alpha) { | 
 | 628 |         AutoEffectUnref effect(SkNEW_ARGS(GrPerlinNoiseEffect, (type, baseFrequency, numOctaves, | 
 | 629 |             stitchTiles, stitchData, permutationsTexture, noiseTexture, matrix, alpha))); | 
 | 630 |         return CreateEffectRef(effect); | 
 | 631 |     } | 
 | 632 |  | 
 | 633 |     virtual ~GrPerlinNoiseEffect() { } | 
 | 634 |  | 
 | 635 |     static const char* Name() { return "PerlinNoise"; } | 
 | 636 |     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { | 
 | 637 |         return GrTBackendEffectFactory<GrPerlinNoiseEffect>::getInstance(); | 
 | 638 |     } | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 639 |     const SkPerlinNoiseShader::StitchData& stitchData() const { return fStitchData; } | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 640 |  | 
 | 641 |     typedef GrGLPerlinNoise GLEffect; | 
 | 642 |  | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 643 | private: | 
 | 644 |     virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE { | 
 | 645 |         const GrPerlinNoiseEffect& s = CastEffect<GrPerlinNoiseEffect>(sBase); | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 646 |         return INHERITED::onIsEqual(sBase) && | 
 | 647 |                fPermutationsAccess.getTexture() == s.fPermutationsAccess.getTexture() && | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 648 |                fNoiseAccess.getTexture() == s.fNoiseAccess.getTexture() && | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 649 |                fStitchData == s.fStitchData; | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 650 |     } | 
 | 651 |  | 
 | 652 |     GrPerlinNoiseEffect(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency, | 
 | 653 |                         int numOctaves, bool stitchTiles, | 
 | 654 |                         const SkPerlinNoiseShader::StitchData& stitchData, | 
 | 655 |                         GrTexture* permutationsTexture, GrTexture* noiseTexture, | 
 | 656 |                         const SkMatrix& matrix, uint8_t alpha) | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 657 |       : GrNoiseEffect(type, baseFrequency, numOctaves, stitchTiles, matrix, alpha) | 
 | 658 |       , fPermutationsAccess(permutationsTexture) | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 659 |       , fNoiseAccess(noiseTexture) | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 660 |       , fStitchData(stitchData) { | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 661 |         this->addTextureAccess(&fPermutationsAccess); | 
 | 662 |         this->addTextureAccess(&fNoiseAccess); | 
 | 663 |     } | 
 | 664 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 665 |     GR_DECLARE_EFFECT_TEST; | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 666 |  | 
 | 667 |     GrTextureAccess                 fPermutationsAccess; | 
 | 668 |     GrTextureAccess                 fNoiseAccess; | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 669 |     SkPerlinNoiseShader::StitchData fStitchData; | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 670 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 671 |     typedef GrNoiseEffect INHERITED; | 
 | 672 | }; | 
 | 673 |  | 
 | 674 | class GrSimplexNoiseEffect : public GrNoiseEffect { | 
 | 675 |     // Note : This is for reference only. GrPerlinNoiseEffect is used for processing. | 
 | 676 | public: | 
 | 677 |     static GrEffectRef* Create(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency, | 
 | 678 |                                int numOctaves, bool stitchTiles, const SkScalar seed, | 
 | 679 |                                const SkMatrix& matrix, uint8_t alpha) { | 
 | 680 |         AutoEffectUnref effect(SkNEW_ARGS(GrSimplexNoiseEffect, (type, baseFrequency, numOctaves, | 
 | 681 |             stitchTiles, seed, matrix, alpha))); | 
 | 682 |         return CreateEffectRef(effect); | 
 | 683 |     } | 
 | 684 |  | 
 | 685 |     virtual ~GrSimplexNoiseEffect() { } | 
 | 686 |  | 
 | 687 |     static const char* Name() { return "SimplexNoise"; } | 
 | 688 |     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { | 
 | 689 |         return GrTBackendEffectFactory<GrSimplexNoiseEffect>::getInstance(); | 
 | 690 |     } | 
 | 691 |     const SkScalar& seed() const { return fSeed; } | 
 | 692 |  | 
 | 693 |     typedef GrGLSimplexNoise GLEffect; | 
 | 694 |  | 
 | 695 | private: | 
 | 696 |     virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE { | 
 | 697 |         const GrSimplexNoiseEffect& s = CastEffect<GrSimplexNoiseEffect>(sBase); | 
 | 698 |         return INHERITED::onIsEqual(sBase) && fSeed == s.fSeed; | 
 | 699 |     } | 
 | 700 |  | 
 | 701 |     GrSimplexNoiseEffect(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency, | 
 | 702 |                          int numOctaves, bool stitchTiles, const SkScalar seed, | 
 | 703 |                          const SkMatrix& matrix, uint8_t alpha) | 
 | 704 |       : GrNoiseEffect(type, baseFrequency, numOctaves, stitchTiles, matrix, alpha) | 
 | 705 |       , fSeed(seed) { | 
 | 706 |     } | 
 | 707 |  | 
 | 708 |     SkScalar fSeed; | 
 | 709 |  | 
 | 710 |     typedef GrNoiseEffect INHERITED; | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 711 | }; | 
 | 712 |  | 
 | 713 | ///////////////////////////////////////////////////////////////////// | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 714 | GR_DEFINE_EFFECT_TEST(GrPerlinNoiseEffect); | 
 | 715 |  | 
 | 716 | GrEffectRef* GrPerlinNoiseEffect::TestCreate(SkMWCRandom* random, | 
 | 717 |                                              GrContext* context, | 
 | 718 |                                              const GrDrawTargetCaps&, | 
 | 719 |                                              GrTexture**) { | 
 | 720 |     int      numOctaves = random->nextRangeU(2, 10); | 
 | 721 |     bool     stitchTiles = random->nextBool(); | 
 | 722 |     SkScalar seed = SkIntToScalar(random->nextU()); | 
 | 723 |     SkISize  tileSize = SkISize::Make(random->nextRangeU(4, 4096), random->nextRangeU(4, 4096)); | 
 | 724 |     SkScalar baseFrequencyX = random->nextRangeScalar(SkFloatToScalar(0.01f), | 
 | 725 |                                                       SkFloatToScalar(0.99f)); | 
 | 726 |     SkScalar baseFrequencyY = random->nextRangeScalar(SkFloatToScalar(0.01f), | 
 | 727 |                                                       SkFloatToScalar(0.99f)); | 
 | 728 |  | 
 | 729 |     SkShader* shader = random->nextBool() ? | 
 | 730 |         SkPerlinNoiseShader::CreateFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed, | 
 | 731 |                                                 stitchTiles ? &tileSize : NULL) : | 
 | 732 |         SkPerlinNoiseShader::CreateTubulence(baseFrequencyX, baseFrequencyY, numOctaves, seed, | 
 | 733 |                                              stitchTiles ? &tileSize : NULL); | 
 | 734 |  | 
 | 735 |     SkPaint paint; | 
 | 736 |     GrEffectRef* effect = shader->asNewEffect(context, paint); | 
 | 737 |  | 
 | 738 |     SkDELETE(shader); | 
 | 739 |  | 
 | 740 |     return effect; | 
 | 741 | } | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 742 |  | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 743 | ///////////////////////////////////////////////////////////////////// | 
 | 744 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 745 | void GrGLSimplexNoise::emitCode(GrGLShaderBuilder* builder, | 
 | 746 |                                 const GrDrawEffect&, | 
 | 747 |                                 EffectKey key, | 
 | 748 |                                 const char* outputColor, | 
 | 749 |                                 const char* inputColor, | 
 | 750 |                                 const TextureSamplerArray&) { | 
 | 751 |     sk_ignore_unused_variable(inputColor); | 
 | 752 |  | 
 | 753 |     const char* vCoords; | 
 | 754 |     fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &vCoords); | 
 | 755 |  | 
 | 756 |     fSeedUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 757 |                                    kFloat_GrSLType, "seed"); | 
 | 758 |     const char* seedUni = builder->getUniformCStr(fSeedUni); | 
 | 759 |     fInvMatrixUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 760 |                                         kMat33f_GrSLType, "invMatrix"); | 
 | 761 |     const char* invMatrixUni = builder->getUniformCStr(fInvMatrixUni); | 
 | 762 |     fBaseFrequencyUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 763 |                                             kVec2f_GrSLType, "baseFrequency"); | 
 | 764 |     const char* baseFrequencyUni = builder->getUniformCStr(fBaseFrequencyUni); | 
 | 765 |     fAlphaUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 766 |                                     kFloat_GrSLType, "alpha"); | 
 | 767 |     const char* alphaUni = builder->getUniformCStr(fAlphaUni); | 
 | 768 |  | 
 | 769 |     // Add vec3 modulo 289 function | 
 | 770 |     static const GrGLShaderVar vec3_Args[] =  { | 
 | 771 |         GrGLShaderVar("x", kVec3f_GrSLType) | 
 | 772 |     }; | 
 | 773 |  | 
 | 774 |     SkString mod289_3_funcName; | 
 | 775 |     builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType, | 
 | 776 |                           "mod289", SK_ARRAY_COUNT(vec3_Args), vec3_Args, | 
 | 777 |                           "const vec2 C = vec2(1.0 / 289.0, 289.0);\n" | 
 | 778 |                           "return x - floor(x * C.xxx) * C.yyy;", &mod289_3_funcName); | 
 | 779 |  | 
 | 780 |     // Add vec4 modulo 289 function | 
 | 781 |     static const GrGLShaderVar vec4_Args[] =  { | 
 | 782 |         GrGLShaderVar("x", kVec4f_GrSLType) | 
 | 783 |     }; | 
 | 784 |  | 
 | 785 |     SkString mod289_4_funcName; | 
 | 786 |     builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, kVec4f_GrSLType, | 
 | 787 |                           "mod289", SK_ARRAY_COUNT(vec4_Args), vec4_Args, | 
 | 788 |                           "const vec2 C = vec2(1.0 / 289.0, 289.0);\n" | 
 | 789 |                           "return x - floor(x * C.xxxx) * C.yyyy;", &mod289_4_funcName); | 
 | 790 |  | 
 | 791 |     // Add vec4 permute function | 
 | 792 |     SkString permute_code; | 
 | 793 |     permute_code.appendf("const vec2 C = vec2(34.0, 1.0);\n" | 
 | 794 |                          "return %s(((x * C.xxxx) + C.yyyy) * x);", mod289_4_funcName.c_str()); | 
 | 795 |     SkString permute_funcName; | 
 | 796 |     builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, kVec4f_GrSLType, | 
 | 797 |                           "permute", SK_ARRAY_COUNT(vec4_Args), vec4_Args, | 
 | 798 |                           permute_code.c_str(), &permute_funcName); | 
 | 799 |  | 
 | 800 |     // Add vec4 taylorInvSqrt function | 
 | 801 |     SkString taylorInvSqrt_funcName; | 
 | 802 |     builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, kVec4f_GrSLType, | 
 | 803 |                           "taylorInvSqrt", SK_ARRAY_COUNT(vec4_Args), vec4_Args, | 
 | 804 |                           "const vec2 C = vec2(-0.85373472095314, 1.79284291400159);\n" | 
 | 805 |                           "return x * C.xxxx + C.yyyy;", &taylorInvSqrt_funcName); | 
 | 806 |  | 
 | 807 |     // Add vec3 noise function | 
 | 808 |     static const GrGLShaderVar noise_vec3_Args[] =  { | 
 | 809 |         GrGLShaderVar("v", kVec3f_GrSLType) | 
 | 810 |     }; | 
 | 811 |  | 
 | 812 |     SkString noise_code; | 
 | 813 |     noise_code.append( | 
 | 814 |         "const vec2 C = vec2(1.0/6.0, 1.0/3.0);\n" | 
 | 815 |         "const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);\n" | 
 | 816 |  | 
 | 817 |         // First corner | 
 | 818 |         "vec3 i = floor(v + dot(v, C.yyy));\n" | 
 | 819 |         "vec3 x0 = v - i + dot(i, C.xxx);\n" | 
 | 820 |  | 
 | 821 |         // Other corners | 
 | 822 |         "vec3 g = step(x0.yzx, x0.xyz);\n" | 
 | 823 |         "vec3 l = 1.0 - g;\n" | 
 | 824 |         "vec3 i1 = min(g.xyz, l.zxy);\n" | 
 | 825 |         "vec3 i2 = max(g.xyz, l.zxy);\n" | 
 | 826 |  | 
 | 827 |         "vec3 x1 = x0 - i1 + C.xxx;\n" | 
 | 828 |         "vec3 x2 = x0 - i2 + C.yyy;\n" // 2.0*C.x = 1/3 = C.y | 
 | 829 |         "vec3 x3 = x0 - D.yyy;\n" // -1.0+3.0*C.x = -0.5 = -D.y | 
 | 830 |     ); | 
 | 831 |  | 
 | 832 |     noise_code.appendf( | 
 | 833 |         // Permutations | 
 | 834 |         "i = %s(i);\n" | 
 | 835 |         "vec4 p = %s(%s(%s(\n" | 
 | 836 |         "         i.z + vec4(0.0, i1.z, i2.z, 1.0)) +\n" | 
 | 837 |         "         i.y + vec4(0.0, i1.y, i2.y, 1.0)) +\n" | 
 | 838 |         "         i.x + vec4(0.0, i1.x, i2.x, 1.0));\n", | 
 | 839 |         mod289_3_funcName.c_str(), permute_funcName.c_str(), permute_funcName.c_str(), | 
 | 840 |         permute_funcName.c_str()); | 
 | 841 |  | 
 | 842 |     noise_code.append( | 
 | 843 |         // Gradients: 7x7 points over a square, mapped onto an octahedron. | 
 | 844 |         // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) | 
 | 845 |         "float n_ = 0.142857142857;\n" // 1.0/7.0 | 
 | 846 |         "vec3  ns = n_ * D.wyz - D.xzx;\n" | 
 | 847 |  | 
 | 848 |         "vec4 j = p - 49.0 * floor(p * ns.z * ns.z);\n" // mod(p,7*7) | 
 | 849 |  | 
 | 850 |         "vec4 x_ = floor(j * ns.z);\n" | 
 | 851 |         "vec4 y_ = floor(j - 7.0 * x_);" // mod(j,N) | 
 | 852 |  | 
 | 853 |         "vec4 x = x_ *ns.x + ns.yyyy;\n" | 
 | 854 |         "vec4 y = y_ *ns.x + ns.yyyy;\n" | 
 | 855 |         "vec4 h = 1.0 - abs(x) - abs(y);\n" | 
 | 856 |  | 
 | 857 |         "vec4 b0 = vec4(x.xy, y.xy);\n" | 
 | 858 |         "vec4 b1 = vec4(x.zw, y.zw);\n" | 
 | 859 |     ); | 
 | 860 |  | 
 | 861 |     noise_code.append( | 
 | 862 |         "vec4 s0 = floor(b0) * 2.0 + 1.0;\n" | 
 | 863 |         "vec4 s1 = floor(b1) * 2.0 + 1.0;\n" | 
 | 864 |         "vec4 sh = -step(h, vec4(0.0));\n" | 
 | 865 |  | 
 | 866 |         "vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;\n" | 
 | 867 |         "vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;\n" | 
 | 868 |  | 
 | 869 |         "vec3 p0 = vec3(a0.xy, h.x);\n" | 
 | 870 |         "vec3 p1 = vec3(a0.zw, h.y);\n" | 
 | 871 |         "vec3 p2 = vec3(a1.xy, h.z);\n" | 
 | 872 |         "vec3 p3 = vec3(a1.zw, h.w);\n" | 
 | 873 |     ); | 
 | 874 |  | 
 | 875 |     noise_code.appendf( | 
 | 876 |         // Normalise gradients | 
 | 877 |         "vec4 norm = %s(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));\n" | 
 | 878 |         "p0 *= norm.x;\n" | 
 | 879 |         "p1 *= norm.y;\n" | 
 | 880 |         "p2 *= norm.z;\n" | 
 | 881 |         "p3 *= norm.w;\n" | 
 | 882 |  | 
 | 883 |         // Mix final noise value | 
 | 884 |         "vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);\n" | 
 | 885 |         "m = m * m;\n" | 
 | 886 |         "return 42.0 * dot(m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));", | 
 | 887 |         taylorInvSqrt_funcName.c_str()); | 
 | 888 |  | 
 | 889 |     SkString noise_funcName; | 
 | 890 |     builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, kFloat_GrSLType, | 
 | 891 |                           "snoise", SK_ARRAY_COUNT(noise_vec3_Args), noise_vec3_Args, | 
 | 892 |                           noise_code.c_str(), &noise_funcName); | 
 | 893 |  | 
 | 894 |     const char* noiseVecIni = "noiseVecIni"; | 
 | 895 |     const char* factors     = "factors"; | 
 | 896 |     const char* sum         = "sum"; | 
 | 897 |     const char* xOffsets    = "xOffsets"; | 
 | 898 |     const char* yOffsets    = "yOffsets"; | 
 | 899 |     const char* channel     = "channel"; | 
 | 900 |  | 
 | 901 |     // Fill with some prime numbers | 
 | 902 |     builder->fsCodeAppendf("\t\tconst vec4 %s = vec4(13.0, 53.0, 101.0, 151.0);\n", xOffsets); | 
 | 903 |     builder->fsCodeAppendf("\t\tconst vec4 %s = vec4(109.0, 167.0, 23.0, 67.0);\n", yOffsets); | 
 | 904 |  | 
 | 905 |     // There are rounding errors if the floor operation is not performed here | 
 | 906 |     builder->fsCodeAppendf( | 
 | 907 |         "\t\tvec3 %s = vec3(floor((%s*vec3(%s, 1.0)).xy) * vec2(0.66) * %s, 0.0);\n", | 
 | 908 |         noiseVecIni, invMatrixUni, vCoords, baseFrequencyUni); | 
 | 909 |  | 
 | 910 |     // Perturb the texcoords with three components of noise | 
 | 911 |     builder->fsCodeAppendf("\t\t%s += 0.1 * vec3(%s(%s + vec3(  0.0,   0.0, %s))," | 
 | 912 |                                                 "%s(%s + vec3( 43.0,  17.0, %s))," | 
 | 913 |                                                 "%s(%s + vec3(-17.0, -43.0, %s)));\n", | 
 | 914 |                            noiseVecIni, noise_funcName.c_str(), noiseVecIni, seedUni, | 
 | 915 |                                         noise_funcName.c_str(), noiseVecIni, seedUni, | 
 | 916 |                                         noise_funcName.c_str(), noiseVecIni, seedUni); | 
 | 917 |  | 
 | 918 |     builder->fsCodeAppendf("\t\t%s = vec4(0.0);\n", outputColor); | 
 | 919 |  | 
 | 920 |     builder->fsCodeAppendf("\t\tvec3 %s = vec3(1.0);\n", factors); | 
 | 921 |     builder->fsCodeAppendf("\t\tfloat %s = 0.0;\n", sum); | 
 | 922 |  | 
 | 923 |     // Loop over all octaves | 
 | 924 |     builder->fsCodeAppendf("\t\tfor (int octave = 0; octave < %d; ++octave) {\n", fNumOctaves); | 
 | 925 |  | 
 | 926 |     // Loop over the 4 channels | 
 | 927 |     builder->fsCodeAppendf("\t\t\tfor (int %s = 3; %s >= 0; --%s) {\n", channel, channel, channel); | 
 | 928 |  | 
 | 929 |     builder->fsCodeAppendf( | 
 | 930 |         "\t\t\t\t%s[channel] += %s.x * %s(%s * %s.yyy - vec3(%s[%s], %s[%s], %s * %s.z));\n", | 
 | 931 |         outputColor, factors, noise_funcName.c_str(), noiseVecIni, factors, xOffsets, channel, | 
 | 932 |         yOffsets, channel, seedUni, factors); | 
 | 933 |  | 
 | 934 |     builder->fsCodeAppend("\t\t\t}\n"); // end of the for loop on channels | 
 | 935 |  | 
 | 936 |     builder->fsCodeAppendf("\t\t\t%s += %s.x;\n", sum, factors); | 
 | 937 |     builder->fsCodeAppendf("\t\t\t%s *= vec3(0.5, 2.0, 0.75);\n", factors); | 
 | 938 |  | 
 | 939 |     builder->fsCodeAppend("\t\t}\n"); // end of the for loop on octaves | 
 | 940 |  | 
 | 941 |     if (fType == SkPerlinNoiseShader::kFractalNoise_Type) { | 
 | 942 |         // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2 | 
 | 943 |         // by fractalNoise and (turbulenceFunctionResult) by turbulence. | 
 | 944 |         builder->fsCodeAppendf("\t\t%s = %s * vec4(0.5 / %s) + vec4(0.5);\n", | 
 | 945 |                                outputColor, outputColor, sum); | 
 | 946 |     } else { | 
 | 947 |         builder->fsCodeAppendf("\t\t%s = abs(%s / vec4(%s));\n", | 
 | 948 |                                outputColor, outputColor, sum); | 
 | 949 |     } | 
 | 950 |  | 
 | 951 |     builder->fsCodeAppendf("\t\t%s.a *= %s;\n", outputColor, alphaUni); | 
 | 952 |  | 
 | 953 |     // Clamp values | 
 | 954 |     builder->fsCodeAppendf("\t\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor); | 
 | 955 |  | 
 | 956 |     // Pre-multiply the result | 
 | 957 |     builder->fsCodeAppendf("\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n", | 
 | 958 |                            outputColor, outputColor, outputColor, outputColor); | 
 | 959 | } | 
 | 960 |  | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 961 | void GrGLPerlinNoise::emitCode(GrGLShaderBuilder* builder, | 
 | 962 |                                const GrDrawEffect&, | 
 | 963 |                                EffectKey key, | 
 | 964 |                                const char* outputColor, | 
 | 965 |                                const char* inputColor, | 
 | 966 |                                const TextureSamplerArray& samplers) { | 
 | 967 |     sk_ignore_unused_variable(inputColor); | 
 | 968 |  | 
 | 969 |     const char* vCoords; | 
 | 970 |     fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &vCoords); | 
 | 971 |  | 
 | 972 |     fInvMatrixUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 973 |                                         kMat33f_GrSLType, "invMatrix"); | 
 | 974 |     const char* invMatrixUni = builder->getUniformCStr(fInvMatrixUni); | 
 | 975 |     fBaseFrequencyUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 976 |                                             kVec2f_GrSLType, "baseFrequency"); | 
 | 977 |     const char* baseFrequencyUni = builder->getUniformCStr(fBaseFrequencyUni); | 
 | 978 |     fAlphaUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 979 |                                     kFloat_GrSLType, "alpha"); | 
 | 980 |     const char* alphaUni = builder->getUniformCStr(fAlphaUni); | 
 | 981 |  | 
 | 982 |     const char* stitchDataUni = NULL; | 
 | 983 |     if (fStitchTiles) { | 
 | 984 |         fStitchDataUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 985 |                                              kVec4f_GrSLType, "stitchData"); | 
 | 986 |         stitchDataUni = builder->getUniformCStr(fStitchDataUni); | 
 | 987 |     } | 
 | 988 |  | 
 | 989 |     const char* chanCoords  = "chanCoords"; | 
 | 990 |     const char* stitchData  = "stitchData"; | 
 | 991 |     const char* ratio       = "ratio"; | 
 | 992 |     const char* noise       = "noise"; | 
 | 993 |     const char* noiseXY     = "noiseXY"; | 
 | 994 |     const char* noiseVec    = "noiseVec"; | 
 | 995 |     const char* noiseVecIni = "noiseVecIni"; | 
 | 996 |     const char* noiseSmooth = "noiseSmooth"; | 
 | 997 |     const char* fractVal    = "fractVal"; | 
 | 998 |     const char* uv          = "uv"; | 
 | 999 |     const char* ab          = "ab"; | 
 | 1000 |     const char* latticeIdx  = "latticeIdx"; | 
 | 1001 |     const char* lattice     = "lattice"; | 
 | 1002 |     const char* perlinNoise = "4096.0"; | 
 | 1003 |     const char* inc8bit     = "0.00390625";  // 1.0 / 256.0 | 
 | 1004 |     // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a | 
 | 1005 |     // [-1,1] vector and perform a dot product between that vector and the provided vector. | 
 | 1006 |     const char* dotLattice  = "dot(((%s.ga + %s.rb * vec2(%s)) * vec2(2.0) - vec2(1.0)), %s);"; | 
 | 1007 |  | 
 | 1008 |     // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8 | 
 | 1009 |     builder->fsCodeAppendf("\t\tconst vec4 %s = vec4(0.125, 0.375, 0.625, 0.875);", chanCoords); | 
 | 1010 |  | 
 | 1011 |     // There are rounding errors if the floor operation is not performed here | 
 | 1012 |     builder->fsCodeAppendf("\t\tvec2 %s = floor((%s*vec3(%s, 1.0)).xy) * %s;", | 
 | 1013 |                            noiseVecIni, invMatrixUni, vCoords, baseFrequencyUni); | 
 | 1014 |  | 
 | 1015 |     // Loop over the 4 channels | 
 | 1016 |     builder->fsCodeAppend("\t\tfor (int channel = 3; channel >= 0; --channel) {"); | 
 | 1017 |  | 
 | 1018 |     if (fStitchTiles) { | 
 | 1019 |         // Set up TurbulenceInitial stitch values. | 
 | 1020 |         builder->fsCodeAppendf("\t\tvec4 %s = %s;", stitchData, stitchDataUni); | 
 | 1021 |     } | 
| skia.committer@gmail.com | cff0243 | 2013-04-06 07:01:10 +0000 | [diff] [blame] | 1022 |  | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 1023 |     builder->fsCodeAppendf("\t\t%s[channel] = 0.0;", outputColor); | 
 | 1024 |  | 
 | 1025 |     builder->fsCodeAppendf("\t\tfloat %s = 1.0;", ratio); | 
 | 1026 |     builder->fsCodeAppendf("\t\tvec2 %s = %s;", noiseVec, noiseVecIni); | 
 | 1027 |  | 
 | 1028 |     // Loop over all octaves | 
 | 1029 |     builder->fsCodeAppendf("\t\tfor (int octave = 0; octave < %d; ++octave) {", fNumOctaves); | 
 | 1030 |  | 
 | 1031 |     builder->fsCodeAppendf("\t\tvec4 %s = vec4(floor(%s) + vec2(%s), fract(%s));", | 
 | 1032 |                   noiseXY, noiseVec, perlinNoise, noiseVec); | 
 | 1033 |  | 
 | 1034 |     // smooth curve : t * t * (3 - 2 * t) | 
 | 1035 |     builder->fsCodeAppendf("\t\tvec2 %s = %s.zw * %s.zw * (vec2(3.0) - vec2(2.0) * %s.zw);", | 
 | 1036 |                   noiseSmooth, noiseXY, noiseXY, noiseXY); | 
 | 1037 |  | 
 | 1038 |     // Adjust frequencies if we're stitching tiles | 
 | 1039 |     if (fStitchTiles) { | 
 | 1040 |         builder->fsCodeAppendf("\t\tif(%s.x >= %s.y) { %s.x -= %s.x; }", | 
 | 1041 |                       noiseXY, stitchData, noiseXY, stitchData); | 
 | 1042 |         builder->fsCodeAppendf("\t\tif(%s.x >= (%s.y - 1.0)) { %s.x -= (%s.x - 1.0); }", | 
 | 1043 |                       noiseXY, stitchData, noiseXY, stitchData); | 
 | 1044 |         builder->fsCodeAppendf("\t\tif(%s.y >= %s.w) { %s.y -= %s.z; }", | 
 | 1045 |                       noiseXY, stitchData, noiseXY, stitchData); | 
 | 1046 |         builder->fsCodeAppendf("\t\tif(%s.y >= (%s.w - 1.0)) { %s.y -= (%s.z - 1.0); }", | 
 | 1047 |                       noiseXY, stitchData, noiseXY, stitchData); | 
 | 1048 |     } | 
 | 1049 |  | 
 | 1050 |     // Get texture coordinates and normalize | 
 | 1051 |     builder->fsCodeAppendf("\t\t%s.xy = fract(floor(mod(%s.xy, 256.0)) / vec2(256.0));", | 
 | 1052 |                   noiseXY, noiseXY); | 
 | 1053 |  | 
 | 1054 |     // Get permutation for x | 
 | 1055 |     { | 
 | 1056 |         SkString xCoords(""); | 
 | 1057 |         xCoords.appendf("vec2(%s.x, 0.5)", noiseXY); | 
 | 1058 |  | 
 | 1059 |         builder->fsCodeAppendf("\t\tvec2 %s;\t\t%s.x = ", latticeIdx, latticeIdx); | 
 | 1060 |         builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 1061 |                                      samplers[0], xCoords.c_str(), kVec2f_GrSLType); | 
 | 1062 |         builder->fsCodeAppend(".r;\n"); | 
 | 1063 |     } | 
 | 1064 |  | 
 | 1065 |     // Get permutation for x + 1 | 
 | 1066 |     { | 
 | 1067 |         SkString xCoords(""); | 
 | 1068 |         xCoords.appendf("vec2(fract(%s.x + %s), 0.5)", noiseXY, inc8bit); | 
 | 1069 |  | 
 | 1070 |         builder->fsCodeAppendf("\t\t%s.y = ", latticeIdx); | 
 | 1071 |         builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 1072 |                                      samplers[0], xCoords.c_str(), kVec2f_GrSLType); | 
 | 1073 |         builder->fsCodeAppend(".r;\n"); | 
 | 1074 |     } | 
 | 1075 |  | 
 | 1076 |     // Get (x,y) coordinates with the permutated x | 
 | 1077 |     builder->fsCodeAppendf("\t\t%s = fract(%s + %s.yy);", latticeIdx, latticeIdx, noiseXY); | 
 | 1078 |  | 
 | 1079 |     builder->fsCodeAppendf("\t\tvec2 %s = %s.zw;", fractVal, noiseXY); | 
 | 1080 |  | 
 | 1081 |     builder->fsCodeAppendf("\t\tvec2 %s;", uv); | 
 | 1082 |     // Compute u, at offset (0,0) | 
 | 1083 |     { | 
 | 1084 |         SkString latticeCoords(""); | 
 | 1085 |         latticeCoords.appendf("vec2(%s.x, %s[channel])", latticeIdx, chanCoords); | 
 | 1086 |         builder->fsCodeAppendf("vec4 %s = ", lattice); | 
 | 1087 |         builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 1088 |                                      samplers[1], latticeCoords.c_str(), kVec2f_GrSLType); | 
 | 1089 |         builder->fsCodeAppendf(".bgra;\n\t\t%s.x = ", uv); | 
 | 1090 |         builder->fsCodeAppendf(dotLattice, lattice, lattice, inc8bit, fractVal); | 
 | 1091 |     } | 
 | 1092 |  | 
 | 1093 |     builder->fsCodeAppendf("\t\t%s.x -= 1.0;", fractVal); | 
 | 1094 |     // Compute v, at offset (-1,0) | 
 | 1095 |     { | 
 | 1096 |         SkString latticeCoords(""); | 
 | 1097 |         latticeCoords.appendf("vec2(%s.y, %s[channel])", latticeIdx, chanCoords); | 
 | 1098 |         builder->fsCodeAppend("lattice = "); | 
 | 1099 |         builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 1100 |                                      samplers[1], latticeCoords.c_str(), kVec2f_GrSLType); | 
 | 1101 |         builder->fsCodeAppendf(".bgra;\n\t\t%s.y = ", uv); | 
 | 1102 |         builder->fsCodeAppendf(dotLattice, lattice, lattice, inc8bit, fractVal); | 
 | 1103 |     } | 
 | 1104 |  | 
 | 1105 |     // Compute 'a' as a linear interpolation of 'u' and 'v' | 
 | 1106 |     builder->fsCodeAppendf("\t\tvec2 %s;", ab); | 
 | 1107 |     builder->fsCodeAppendf("\t\t%s.x = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth); | 
 | 1108 |  | 
 | 1109 |     builder->fsCodeAppendf("\t\t%s.y -= 1.0;", fractVal); | 
 | 1110 |     // Compute v, at offset (-1,-1) | 
 | 1111 |     { | 
 | 1112 |         SkString latticeCoords(""); | 
 | 1113 |         latticeCoords.appendf("vec2(fract(%s.y + %s), %s[channel])", | 
 | 1114 |             latticeIdx, inc8bit, chanCoords); | 
 | 1115 |         builder->fsCodeAppend("lattice = "); | 
 | 1116 |         builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 1117 |                                      samplers[1], latticeCoords.c_str(), kVec2f_GrSLType); | 
 | 1118 |         builder->fsCodeAppendf(".bgra;\n\t\t%s.y = ", uv); | 
 | 1119 |         builder->fsCodeAppendf(dotLattice, lattice, lattice, inc8bit, fractVal); | 
 | 1120 |     } | 
 | 1121 |  | 
 | 1122 |     builder->fsCodeAppendf("\t\t%s.x += 1.0;", fractVal); | 
 | 1123 |     // Compute u, at offset (0,-1) | 
 | 1124 |     { | 
 | 1125 |         SkString latticeCoords(""); | 
 | 1126 |         latticeCoords.appendf("vec2(fract(%s.x + %s), %s[channel])", | 
 | 1127 |             latticeIdx, inc8bit, chanCoords); | 
 | 1128 |         builder->fsCodeAppend("lattice = "); | 
 | 1129 |         builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, | 
 | 1130 |                                      samplers[1], latticeCoords.c_str(), kVec2f_GrSLType); | 
 | 1131 |         builder->fsCodeAppendf(".bgra;\n\t\t%s.x = ", uv); | 
 | 1132 |         builder->fsCodeAppendf(dotLattice, lattice, lattice, inc8bit, fractVal); | 
 | 1133 |     } | 
 | 1134 |  | 
 | 1135 |     // Compute 'b' as a linear interpolation of 'u' and 'v' | 
 | 1136 |     builder->fsCodeAppendf("\t\t%s.y = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth); | 
 | 1137 |     // Compute the noise as a linear interpolation of 'a' and 'b' | 
 | 1138 |     builder->fsCodeAppendf("\t\tfloat %s = mix(%s.x, %s.y, %s.y);", noise, ab, ab, noiseSmooth); | 
 | 1139 |  | 
 | 1140 |     builder->fsCodeAppendf("\t\t%s[channel] += ", outputColor); | 
 | 1141 |     builder->fsCodeAppendf((fType == SkPerlinNoiseShader::kFractalNoise_Type) ? | 
 | 1142 |                   "%s / %s;" : "abs(%s) / %s;", noise, ratio); | 
 | 1143 |  | 
 | 1144 |     builder->fsCodeAppendf("\t\t%s *= vec2(2.0);", noiseVec); | 
 | 1145 |     builder->fsCodeAppendf("\t\t%s *= 2.0;", ratio); | 
 | 1146 |  | 
 | 1147 |     if (fStitchTiles) { | 
 | 1148 |         builder->fsCodeAppendf("\t\t%s.xz *= vec2(2.0);", stitchData); | 
 | 1149 |         builder->fsCodeAppendf("\t\t%s.yw = %s.xz + vec2(%s);", stitchData, stitchData, perlinNoise); | 
 | 1150 |     } | 
 | 1151 |     builder->fsCodeAppend("\t\t}"); // end of the for loop on octaves | 
 | 1152 |  | 
 | 1153 |     builder->fsCodeAppend("\t\t}"); // end of the for loop on channels | 
 | 1154 |  | 
 | 1155 |     if (fType == SkPerlinNoiseShader::kFractalNoise_Type) { | 
 | 1156 |         // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2 | 
 | 1157 |         // by fractalNoise and (turbulenceFunctionResult) by turbulence. | 
 | 1158 |         builder->fsCodeAppendf("\t\t%s = %s * vec4(0.5) + vec4(0.5);", outputColor, outputColor); | 
 | 1159 |     } | 
 | 1160 |  | 
 | 1161 |     builder->fsCodeAppendf("\t\t%s.a *= %s;", outputColor, alphaUni); | 
 | 1162 |  | 
 | 1163 |     // Clamp values | 
 | 1164 |     builder->fsCodeAppendf("\t\t%s = clamp(%s, 0.0, 1.0);", outputColor, outputColor); | 
 | 1165 |  | 
 | 1166 |     // Pre-multiply the result | 
 | 1167 |     builder->fsCodeAppendf("\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n", | 
 | 1168 |                   outputColor, outputColor, outputColor, outputColor); | 
 | 1169 | } | 
 | 1170 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 1171 | GrGLNoise::GrGLNoise(const GrBackendEffectFactory& factory, const GrDrawEffect& drawEffect) | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 1172 |   : INHERITED (factory) | 
 | 1173 |   , fType(drawEffect.castEffect<GrPerlinNoiseEffect>().type()) | 
 | 1174 |   , fStitchTiles(drawEffect.castEffect<GrPerlinNoiseEffect>().stitchTiles()) | 
 | 1175 |   , fNumOctaves(drawEffect.castEffect<GrPerlinNoiseEffect>().numOctaves()) | 
 | 1176 |   , fEffectMatrix(drawEffect.castEffect<GrPerlinNoiseEffect>().coordsType()) { | 
 | 1177 | } | 
 | 1178 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 1179 | GrGLEffect::EffectKey GrGLNoise::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 1180 |     const GrPerlinNoiseEffect& turbulence = drawEffect.castEffect<GrPerlinNoiseEffect>(); | 
 | 1181 |  | 
 | 1182 |     EffectKey key = turbulence.numOctaves(); | 
 | 1183 |  | 
 | 1184 |     key = key << 3; // Make room for next 3 bits | 
 | 1185 |  | 
 | 1186 |     switch (turbulence.type()) { | 
 | 1187 |         case SkPerlinNoiseShader::kFractalNoise_Type: | 
 | 1188 |             key |= 0x1; | 
 | 1189 |             break; | 
 | 1190 |         case SkPerlinNoiseShader::kTurbulence_Type: | 
 | 1191 |             key |= 0x2; | 
 | 1192 |             break; | 
 | 1193 |         default: | 
 | 1194 |             // leave key at 0 | 
 | 1195 |             break; | 
 | 1196 |     } | 
 | 1197 |  | 
 | 1198 |     if (turbulence.stitchTiles()) { | 
 | 1199 |         key |= 0x4; // Flip the 3rd bit if tile stitching is on | 
 | 1200 |     } | 
 | 1201 |  | 
 | 1202 |     key = key << GrGLEffectMatrix::kKeyBits; | 
 | 1203 |  | 
 | 1204 |     SkMatrix m = turbulence.matrix(); | 
 | 1205 |     m.postTranslate(SK_Scalar1, SK_Scalar1); | 
 | 1206 |     return key | GrGLEffectMatrix::GenKey(m, drawEffect, | 
 | 1207 |                  drawEffect.castEffect<GrPerlinNoiseEffect>().coordsType(), NULL); | 
 | 1208 | } | 
 | 1209 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 1210 | void GrGLNoise::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 1211 |     const GrPerlinNoiseEffect& turbulence = drawEffect.castEffect<GrPerlinNoiseEffect>(); | 
 | 1212 |  | 
 | 1213 |     const SkVector& baseFrequency = turbulence.baseFrequency(); | 
 | 1214 |     uman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY); | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 1215 |     uman.set1f(fAlphaUni, SkScalarDiv(SkIntToScalar(turbulence.alpha()), SkIntToScalar(255))); | 
 | 1216 |  | 
 | 1217 |     SkMatrix m = turbulence.matrix(); | 
 | 1218 |     SkMatrix invM; | 
 | 1219 |     if (!m.invert(&invM)) { | 
 | 1220 |         invM.reset(); | 
 | 1221 |     } else { | 
 | 1222 |         invM.postConcat(invM); // Square the matrix | 
 | 1223 |     } | 
 | 1224 |     uman.setSkMatrix(fInvMatrixUni, invM); | 
 | 1225 |  | 
 | 1226 |     // This (1,1) translation is due to WebKit's 1 based coordinates for the noise | 
 | 1227 |     // (as opposed to 0 based, usually). The same adjustment is in the shadeSpan() functions. | 
 | 1228 |     m.postTranslate(SK_Scalar1, SK_Scalar1); | 
 | 1229 |     fEffectMatrix.setData(uman, m, drawEffect, NULL); | 
 | 1230 | } | 
 | 1231 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 1232 | void GrGLPerlinNoise::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { | 
 | 1233 |     INHERITED::setData(uman, drawEffect); | 
 | 1234 |  | 
 | 1235 |     const GrPerlinNoiseEffect& turbulence = drawEffect.castEffect<GrPerlinNoiseEffect>(); | 
 | 1236 |     if (turbulence.stitchTiles()) { | 
 | 1237 |         const SkPerlinNoiseShader::StitchData& stitchData = turbulence.stitchData(); | 
 | 1238 |         uman.set4f(fStitchDataUni, SkIntToScalar(stitchData.fWidth), | 
 | 1239 |                                    SkIntToScalar(stitchData.fWrapX), | 
 | 1240 |                                    SkIntToScalar(stitchData.fHeight), | 
 | 1241 |                                    SkIntToScalar(stitchData.fWrapY)); | 
 | 1242 |     } | 
 | 1243 | } | 
 | 1244 |  | 
 | 1245 | void GrGLSimplexNoise::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { | 
 | 1246 |     INHERITED::setData(uman, drawEffect); | 
 | 1247 |  | 
 | 1248 |     const GrSimplexNoiseEffect& turbulence = drawEffect.castEffect<GrSimplexNoiseEffect>(); | 
 | 1249 |     uman.set1f(fSeedUni, turbulence.seed()); | 
 | 1250 | } | 
 | 1251 |  | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 1252 | ///////////////////////////////////////////////////////////////////// | 
 | 1253 |  | 
 | 1254 | GrEffectRef* SkPerlinNoiseShader::asNewEffect(GrContext* context, const SkPaint& paint) const { | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 1255 |     SkASSERT(NULL != context); | 
 | 1256 |  | 
 | 1257 |     // Either we don't stitch tiles, either we have a valid tile size | 
 | 1258 |     SkASSERT(!fStitchTiles || !fTileSize.isEmpty()); | 
 | 1259 |  | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 1260 | #ifdef SK_USE_SIMPLEX_NOISE | 
 | 1261 |     // Simplex noise is currently disabled but can be enabled by defining SK_USE_SIMPLEX_NOISE | 
 | 1262 |     sk_ignore_unused_variable(context); | 
 | 1263 |     GrEffectRef* effect = | 
 | 1264 |         GrSimplexNoiseEffect::Create(fType, fPaintingData->fBaseFrequency, | 
 | 1265 |                                      fNumOctaves, fStitchTiles, fSeed, | 
 | 1266 |                                      this->getLocalMatrix(), paint.getAlpha()); | 
 | 1267 | #else | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 1268 |     GrTexture* permutationsTexture = GrLockAndRefCachedBitmapTexture( | 
 | 1269 |         context, *fPaintingData->getPermutationsBitmap(), NULL); | 
 | 1270 |     GrTexture* noiseTexture = GrLockAndRefCachedBitmapTexture( | 
 | 1271 |         context, *fPaintingData->getNoiseBitmap(), NULL); | 
 | 1272 |  | 
 | 1273 |     GrEffectRef* effect = (NULL != permutationsTexture) && (NULL != noiseTexture) ? | 
| skia.committer@gmail.com | cff0243 | 2013-04-06 07:01:10 +0000 | [diff] [blame] | 1274 |         GrPerlinNoiseEffect::Create(fType, fPaintingData->fBaseFrequency, | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 1275 |                                     fNumOctaves, fStitchTiles, | 
 | 1276 |                                     fPaintingData->fStitchDataInit, | 
| skia.committer@gmail.com | cff0243 | 2013-04-06 07:01:10 +0000 | [diff] [blame] | 1277 |                                     permutationsTexture, noiseTexture, | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 1278 |                                     this->getLocalMatrix(), paint.getAlpha()) : | 
 | 1279 |         NULL; | 
 | 1280 |  | 
 | 1281 |     // Unlock immediately, this is not great, but we don't have a way of | 
 | 1282 |     // knowing when else to unlock it currently. TODO: Remove this when | 
 | 1283 |     // unref becomes the unlock replacement for all types of textures. | 
 | 1284 |     if (NULL != permutationsTexture) { | 
 | 1285 |         GrUnlockAndUnrefCachedBitmapTexture(permutationsTexture); | 
 | 1286 |     } | 
 | 1287 |     if (NULL != noiseTexture) { | 
 | 1288 |         GrUnlockAndUnrefCachedBitmapTexture(noiseTexture); | 
 | 1289 |     } | 
| sugoi@google.com | 4775cba | 2013-04-17 13:46:56 +0000 | [diff] [blame^] | 1290 | #endif | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 1291 |  | 
 | 1292 |     return effect; | 
| sugoi@google.com | e3b4c50 | 2013-04-05 13:47:09 +0000 | [diff] [blame] | 1293 | } | 
 | 1294 |  | 
 | 1295 | #else | 
 | 1296 |  | 
 | 1297 | GrEffectRef* SkPerlinNoiseShader::asNewEffect(GrContext*, const SkPaint&) const { | 
 | 1298 |     SkDEBUGFAIL("Should not call in GPU-less build"); | 
 | 1299 |     return NULL; | 
 | 1300 | } | 
 | 1301 |  | 
 | 1302 | #endif | 
 | 1303 |  | 
 | 1304 | #ifdef SK_DEVELOPER | 
 | 1305 | void SkPerlinNoiseShader::toString(SkString* str) const { | 
 | 1306 |     str->append("SkPerlinNoiseShader: ("); | 
 | 1307 |  | 
 | 1308 |     str->append("type: "); | 
 | 1309 |     switch (fType) { | 
 | 1310 |         case kFractalNoise_Type: | 
 | 1311 |             str->append("\"fractal noise\""); | 
 | 1312 |             break; | 
 | 1313 |         case kTurbulence_Type: | 
 | 1314 |             str->append("\"turbulence\""); | 
 | 1315 |             break; | 
 | 1316 |         default: | 
 | 1317 |             str->append("\"unknown\""); | 
 | 1318 |             break; | 
 | 1319 |     } | 
 | 1320 |     str->append(" base frequency: ("); | 
 | 1321 |     str->appendScalar(fBaseFrequencyX); | 
 | 1322 |     str->append(", "); | 
 | 1323 |     str->appendScalar(fBaseFrequencyY); | 
 | 1324 |     str->append(") number of octaves: "); | 
 | 1325 |     str->appendS32(fNumOctaves); | 
 | 1326 |     str->append(" seed: "); | 
 | 1327 |     str->appendScalar(fSeed); | 
 | 1328 |     str->append(" stitch tiles: "); | 
 | 1329 |     str->append(fStitchTiles ? "true " : "false "); | 
 | 1330 |  | 
 | 1331 |     this->INHERITED::toString(str); | 
 | 1332 |  | 
 | 1333 |     str->append(")"); | 
 | 1334 | } | 
 | 1335 | #endif |