1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2013 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkPerlinNoiseShaderImpl_DEFINED 8*c8dee2aaSAndroid Build Coastguard Worker #define SkPerlinNoiseShaderImpl_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker 10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkAlphaType.h" 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorType.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFlattenable.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h" 16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h" 17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h" 18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h" 19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h" 20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMath.h" 21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkOnce.h" 22*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkShaderBase.h" 23*c8dee2aaSAndroid Build Coastguard Worker 24*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm> 25*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint> 26*c8dee2aaSAndroid Build Coastguard Worker #include <cstring> 27*c8dee2aaSAndroid Build Coastguard Worker #include <memory> 28*c8dee2aaSAndroid Build Coastguard Worker 29*c8dee2aaSAndroid Build Coastguard Worker class SkReadBuffer; 30*c8dee2aaSAndroid Build Coastguard Worker enum class SkPerlinNoiseShaderType; 31*c8dee2aaSAndroid Build Coastguard Worker struct SkStageRec; 32*c8dee2aaSAndroid Build Coastguard Worker class SkWriteBuffer; 33*c8dee2aaSAndroid Build Coastguard Worker 34*c8dee2aaSAndroid Build Coastguard Worker class SkPerlinNoiseShader : public SkShaderBase { 35*c8dee2aaSAndroid Build Coastguard Worker private: 36*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kBlockSize = 256; 37*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kBlockMask = kBlockSize - 1; 38*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kPerlinNoise = 4096; 39*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kRandMaximum = SK_MaxS32; // 2**31 - 1 40*c8dee2aaSAndroid Build Coastguard Worker 41*c8dee2aaSAndroid Build Coastguard Worker public: 42*c8dee2aaSAndroid Build Coastguard Worker struct StitchData { 43*c8dee2aaSAndroid Build Coastguard Worker StitchData() = default; 44*c8dee2aaSAndroid Build Coastguard Worker StitchDataStitchData45*c8dee2aaSAndroid Build Coastguard Worker StitchData(SkScalar w, SkScalar h) 46*c8dee2aaSAndroid Build Coastguard Worker : fWidth(std::min(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise)) 47*c8dee2aaSAndroid Build Coastguard Worker , fWrapX(kPerlinNoise + fWidth) 48*c8dee2aaSAndroid Build Coastguard Worker , fHeight(std::min(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise)) 49*c8dee2aaSAndroid Build Coastguard Worker , fWrapY(kPerlinNoise + fHeight) {} 50*c8dee2aaSAndroid Build Coastguard Worker 51*c8dee2aaSAndroid Build Coastguard Worker bool operator==(const StitchData& other) const { 52*c8dee2aaSAndroid Build Coastguard Worker return fWidth == other.fWidth && fWrapX == other.fWrapX && fHeight == other.fHeight && 53*c8dee2aaSAndroid Build Coastguard Worker fWrapY == other.fWrapY; 54*c8dee2aaSAndroid Build Coastguard Worker } 55*c8dee2aaSAndroid Build Coastguard Worker 56*c8dee2aaSAndroid Build Coastguard Worker int fWidth = 0; // How much to subtract to wrap for stitching. 57*c8dee2aaSAndroid Build Coastguard Worker int fWrapX = 0; // Minimum value to wrap. 58*c8dee2aaSAndroid Build Coastguard Worker int fHeight = 0; 59*c8dee2aaSAndroid Build Coastguard Worker int fWrapY = 0; 60*c8dee2aaSAndroid Build Coastguard Worker }; 61*c8dee2aaSAndroid Build Coastguard Worker 62*c8dee2aaSAndroid Build Coastguard Worker struct PaintingData { PaintingDataPaintingData63*c8dee2aaSAndroid Build Coastguard Worker PaintingData(const SkISize& tileSize, 64*c8dee2aaSAndroid Build Coastguard Worker SkScalar seed, 65*c8dee2aaSAndroid Build Coastguard Worker SkScalar baseFrequencyX, 66*c8dee2aaSAndroid Build Coastguard Worker SkScalar baseFrequencyY) { 67*c8dee2aaSAndroid Build Coastguard Worker fBaseFrequency.set(baseFrequencyX, baseFrequencyY); 68*c8dee2aaSAndroid Build Coastguard Worker fTileSize.set(SkScalarRoundToInt(tileSize.fWidth), 69*c8dee2aaSAndroid Build Coastguard Worker SkScalarRoundToInt(tileSize.fHeight)); 70*c8dee2aaSAndroid Build Coastguard Worker this->init(seed); 71*c8dee2aaSAndroid Build Coastguard Worker if (!fTileSize.isEmpty()) { 72*c8dee2aaSAndroid Build Coastguard Worker this->stitch(); 73*c8dee2aaSAndroid Build Coastguard Worker } 74*c8dee2aaSAndroid Build Coastguard Worker } 75*c8dee2aaSAndroid Build Coastguard Worker generateBitmapsPaintingData76*c8dee2aaSAndroid Build Coastguard Worker void generateBitmaps() { 77*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1); 78*c8dee2aaSAndroid Build Coastguard Worker fPermutationsBitmap.installPixels(info, fLatticeSelector, info.minRowBytes()); 79*c8dee2aaSAndroid Build Coastguard Worker fPermutationsBitmap.setImmutable(); 80*c8dee2aaSAndroid Build Coastguard Worker 81*c8dee2aaSAndroid Build Coastguard Worker info = SkImageInfo::Make(kBlockSize, 4, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 82*c8dee2aaSAndroid Build Coastguard Worker fNoiseBitmap.installPixels(info, fNoise[0][0], info.minRowBytes()); 83*c8dee2aaSAndroid Build Coastguard Worker fNoiseBitmap.setImmutable(); 84*c8dee2aaSAndroid Build Coastguard Worker } 85*c8dee2aaSAndroid Build Coastguard Worker PaintingDataPaintingData86*c8dee2aaSAndroid Build Coastguard Worker PaintingData(const PaintingData& that) 87*c8dee2aaSAndroid Build Coastguard Worker : fSeed(that.fSeed) 88*c8dee2aaSAndroid Build Coastguard Worker , fTileSize(that.fTileSize) 89*c8dee2aaSAndroid Build Coastguard Worker , fBaseFrequency(that.fBaseFrequency) 90*c8dee2aaSAndroid Build Coastguard Worker , fStitchDataInit(that.fStitchDataInit) 91*c8dee2aaSAndroid Build Coastguard Worker , fPermutationsBitmap(that.fPermutationsBitmap) 92*c8dee2aaSAndroid Build Coastguard Worker , fNoiseBitmap(that.fNoiseBitmap) { 93*c8dee2aaSAndroid Build Coastguard Worker memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector)); 94*c8dee2aaSAndroid Build Coastguard Worker memcpy(fNoise, that.fNoise, sizeof(fNoise)); 95*c8dee2aaSAndroid Build Coastguard Worker } 96*c8dee2aaSAndroid Build Coastguard Worker 97*c8dee2aaSAndroid Build Coastguard Worker int fSeed; 98*c8dee2aaSAndroid Build Coastguard Worker uint8_t fLatticeSelector[kBlockSize]; 99*c8dee2aaSAndroid Build Coastguard Worker uint16_t fNoise[4][kBlockSize][2]; 100*c8dee2aaSAndroid Build Coastguard Worker SkISize fTileSize; 101*c8dee2aaSAndroid Build Coastguard Worker SkVector fBaseFrequency; 102*c8dee2aaSAndroid Build Coastguard Worker StitchData fStitchDataInit; 103*c8dee2aaSAndroid Build Coastguard Worker 104*c8dee2aaSAndroid Build Coastguard Worker private: 105*c8dee2aaSAndroid Build Coastguard Worker SkBitmap fPermutationsBitmap; 106*c8dee2aaSAndroid Build Coastguard Worker SkBitmap fNoiseBitmap; 107*c8dee2aaSAndroid Build Coastguard Worker randomPaintingData108*c8dee2aaSAndroid Build Coastguard Worker int random() { 109*c8dee2aaSAndroid Build Coastguard Worker // See https://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement 110*c8dee2aaSAndroid Build Coastguard Worker // m = kRandMaximum, 2**31 - 1 (2147483647) 111*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kRandAmplitude = 16807; // 7**5; primitive root of m 112*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kRandQ = 127773; // m / a 113*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kRandR = 2836; // m % a 114*c8dee2aaSAndroid Build Coastguard Worker 115*c8dee2aaSAndroid Build Coastguard Worker int result = kRandAmplitude * (fSeed % kRandQ) - kRandR * (fSeed / kRandQ); 116*c8dee2aaSAndroid Build Coastguard Worker if (result <= 0) { 117*c8dee2aaSAndroid Build Coastguard Worker result += kRandMaximum; 118*c8dee2aaSAndroid Build Coastguard Worker } 119*c8dee2aaSAndroid Build Coastguard Worker fSeed = result; 120*c8dee2aaSAndroid Build Coastguard Worker return result; 121*c8dee2aaSAndroid Build Coastguard Worker } 122*c8dee2aaSAndroid Build Coastguard Worker 123*c8dee2aaSAndroid Build Coastguard Worker // Only called once. Could be part of the constructor. initPaintingData124*c8dee2aaSAndroid Build Coastguard Worker void init(SkScalar seed) { 125*c8dee2aaSAndroid Build Coastguard Worker // According to the SVG spec, we must truncate (not round) the seed value. 126*c8dee2aaSAndroid Build Coastguard Worker fSeed = SkScalarTruncToInt(seed); 127*c8dee2aaSAndroid Build Coastguard Worker // The seed value clamp to the range [1, kRandMaximum - 1]. 128*c8dee2aaSAndroid Build Coastguard Worker if (fSeed <= 0) { 129*c8dee2aaSAndroid Build Coastguard Worker fSeed = -(fSeed % (kRandMaximum - 1)) + 1; 130*c8dee2aaSAndroid Build Coastguard Worker } 131*c8dee2aaSAndroid Build Coastguard Worker if (fSeed > kRandMaximum - 1) { 132*c8dee2aaSAndroid Build Coastguard Worker fSeed = kRandMaximum - 1; 133*c8dee2aaSAndroid Build Coastguard Worker } 134*c8dee2aaSAndroid Build Coastguard Worker for (int channel = 0; channel < 4; ++channel) { 135*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < kBlockSize; ++i) { 136*c8dee2aaSAndroid Build Coastguard Worker fLatticeSelector[i] = i; 137*c8dee2aaSAndroid Build Coastguard Worker fNoise[channel][i][0] = (random() % (2 * kBlockSize)); 138*c8dee2aaSAndroid Build Coastguard Worker fNoise[channel][i][1] = (random() % (2 * kBlockSize)); 139*c8dee2aaSAndroid Build Coastguard Worker } 140*c8dee2aaSAndroid Build Coastguard Worker } 141*c8dee2aaSAndroid Build Coastguard Worker for (int i = kBlockSize - 1; i > 0; --i) { 142*c8dee2aaSAndroid Build Coastguard Worker int k = fLatticeSelector[i]; 143*c8dee2aaSAndroid Build Coastguard Worker int j = random() % kBlockSize; 144*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(j >= 0); 145*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(j < kBlockSize); 146*c8dee2aaSAndroid Build Coastguard Worker fLatticeSelector[i] = fLatticeSelector[j]; 147*c8dee2aaSAndroid Build Coastguard Worker fLatticeSelector[j] = k; 148*c8dee2aaSAndroid Build Coastguard Worker } 149*c8dee2aaSAndroid Build Coastguard Worker 150*c8dee2aaSAndroid Build Coastguard Worker // Perform the permutations now 151*c8dee2aaSAndroid Build Coastguard Worker { 152*c8dee2aaSAndroid Build Coastguard Worker // Copy noise data 153*c8dee2aaSAndroid Build Coastguard Worker uint16_t noise[4][kBlockSize][2]; 154*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < kBlockSize; ++i) { 155*c8dee2aaSAndroid Build Coastguard Worker for (int channel = 0; channel < 4; ++channel) { 156*c8dee2aaSAndroid Build Coastguard Worker for (int j = 0; j < 2; ++j) { 157*c8dee2aaSAndroid Build Coastguard Worker noise[channel][i][j] = fNoise[channel][i][j]; 158*c8dee2aaSAndroid Build Coastguard Worker } 159*c8dee2aaSAndroid Build Coastguard Worker } 160*c8dee2aaSAndroid Build Coastguard Worker } 161*c8dee2aaSAndroid Build Coastguard Worker // Do permutations on noise data 162*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < kBlockSize; ++i) { 163*c8dee2aaSAndroid Build Coastguard Worker for (int channel = 0; channel < 4; ++channel) { 164*c8dee2aaSAndroid Build Coastguard Worker for (int j = 0; j < 2; ++j) { 165*c8dee2aaSAndroid Build Coastguard Worker fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j]; 166*c8dee2aaSAndroid Build Coastguard Worker } 167*c8dee2aaSAndroid Build Coastguard Worker } 168*c8dee2aaSAndroid Build Coastguard Worker } 169*c8dee2aaSAndroid Build Coastguard Worker } 170*c8dee2aaSAndroid Build Coastguard Worker 171*c8dee2aaSAndroid Build Coastguard Worker // Half of the largest possible value for 16 bit unsigned int 172*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kHalfMax16bits = 32767.5f; 173*c8dee2aaSAndroid Build Coastguard Worker 174*c8dee2aaSAndroid Build Coastguard Worker // Compute gradients from permuted noise data 175*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kInvBlockSizef = 1.0 / SkIntToScalar(kBlockSize); 176*c8dee2aaSAndroid Build Coastguard Worker for (int channel = 0; channel < 4; ++channel) { 177*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < kBlockSize; ++i) { 178*c8dee2aaSAndroid Build Coastguard Worker SkPoint gradient = 179*c8dee2aaSAndroid Build Coastguard Worker SkPoint::Make((fNoise[channel][i][0] - kBlockSize) * kInvBlockSizef, 180*c8dee2aaSAndroid Build Coastguard Worker (fNoise[channel][i][1] - kBlockSize) * kInvBlockSizef); 181*c8dee2aaSAndroid Build Coastguard Worker gradient.normalize(); 182*c8dee2aaSAndroid Build Coastguard Worker // Put the normalized gradient back into the noise data 183*c8dee2aaSAndroid Build Coastguard Worker fNoise[channel][i][0] = SkScalarRoundToInt((gradient.fX + 1) * kHalfMax16bits); 184*c8dee2aaSAndroid Build Coastguard Worker fNoise[channel][i][1] = SkScalarRoundToInt((gradient.fY + 1) * kHalfMax16bits); 185*c8dee2aaSAndroid Build Coastguard Worker } 186*c8dee2aaSAndroid Build Coastguard Worker } 187*c8dee2aaSAndroid Build Coastguard Worker } 188*c8dee2aaSAndroid Build Coastguard Worker 189*c8dee2aaSAndroid Build Coastguard Worker // Only called once. Could be part of the constructor. stitchPaintingData190*c8dee2aaSAndroid Build Coastguard Worker void stitch() { 191*c8dee2aaSAndroid Build Coastguard Worker SkScalar tileWidth = SkIntToScalar(fTileSize.width()); 192*c8dee2aaSAndroid Build Coastguard Worker SkScalar tileHeight = SkIntToScalar(fTileSize.height()); 193*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(tileWidth > 0 && tileHeight > 0); 194*c8dee2aaSAndroid Build Coastguard Worker // When stitching tiled turbulence, the frequencies must be adjusted 195*c8dee2aaSAndroid Build Coastguard Worker // so that the tile borders will be continuous. 196*c8dee2aaSAndroid Build Coastguard Worker if (fBaseFrequency.fX) { 197*c8dee2aaSAndroid Build Coastguard Worker SkScalar lowFrequencx = 198*c8dee2aaSAndroid Build Coastguard Worker SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth; 199*c8dee2aaSAndroid Build Coastguard Worker SkScalar highFrequencx = 200*c8dee2aaSAndroid Build Coastguard Worker SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth; 201*c8dee2aaSAndroid Build Coastguard Worker // BaseFrequency should be non-negative according to the standard. 202*c8dee2aaSAndroid Build Coastguard Worker // lowFrequencx can be 0 if fBaseFrequency.fX is very small. 203*c8dee2aaSAndroid Build Coastguard Worker if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) < 204*c8dee2aaSAndroid Build Coastguard Worker highFrequencx / fBaseFrequency.fX) { 205*c8dee2aaSAndroid Build Coastguard Worker fBaseFrequency.fX = lowFrequencx; 206*c8dee2aaSAndroid Build Coastguard Worker } else { 207*c8dee2aaSAndroid Build Coastguard Worker fBaseFrequency.fX = highFrequencx; 208*c8dee2aaSAndroid Build Coastguard Worker } 209*c8dee2aaSAndroid Build Coastguard Worker } 210*c8dee2aaSAndroid Build Coastguard Worker if (fBaseFrequency.fY) { 211*c8dee2aaSAndroid Build Coastguard Worker SkScalar lowFrequency = 212*c8dee2aaSAndroid Build Coastguard Worker SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight; 213*c8dee2aaSAndroid Build Coastguard Worker SkScalar highFrequency = 214*c8dee2aaSAndroid Build Coastguard Worker SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight; 215*c8dee2aaSAndroid Build Coastguard Worker // lowFrequency can be 0 if fBaseFrequency.fY is very small. 216*c8dee2aaSAndroid Build Coastguard Worker if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) < 217*c8dee2aaSAndroid Build Coastguard Worker highFrequency / fBaseFrequency.fY) { 218*c8dee2aaSAndroid Build Coastguard Worker fBaseFrequency.fY = lowFrequency; 219*c8dee2aaSAndroid Build Coastguard Worker } else { 220*c8dee2aaSAndroid Build Coastguard Worker fBaseFrequency.fY = highFrequency; 221*c8dee2aaSAndroid Build Coastguard Worker } 222*c8dee2aaSAndroid Build Coastguard Worker } 223*c8dee2aaSAndroid Build Coastguard Worker fStitchDataInit = 224*c8dee2aaSAndroid Build Coastguard Worker StitchData(tileWidth * fBaseFrequency.fX, tileHeight * fBaseFrequency.fY); 225*c8dee2aaSAndroid Build Coastguard Worker } 226*c8dee2aaSAndroid Build Coastguard Worker 227*c8dee2aaSAndroid Build Coastguard Worker public: getPermutationsBitmapPaintingData228*c8dee2aaSAndroid Build Coastguard Worker const SkBitmap& getPermutationsBitmap() const { 229*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fPermutationsBitmap.drawsNothing()); 230*c8dee2aaSAndroid Build Coastguard Worker return fPermutationsBitmap; 231*c8dee2aaSAndroid Build Coastguard Worker } getNoiseBitmapPaintingData232*c8dee2aaSAndroid Build Coastguard Worker const SkBitmap& getNoiseBitmap() const { 233*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fNoiseBitmap.drawsNothing()); 234*c8dee2aaSAndroid Build Coastguard Worker return fNoiseBitmap; 235*c8dee2aaSAndroid Build Coastguard Worker } 236*c8dee2aaSAndroid Build Coastguard Worker }; // struct PaintingData 237*c8dee2aaSAndroid Build Coastguard Worker 238*c8dee2aaSAndroid Build Coastguard Worker static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves 239*c8dee2aaSAndroid Build Coastguard Worker 240*c8dee2aaSAndroid Build Coastguard Worker SkPerlinNoiseShader(SkPerlinNoiseShaderType type, 241*c8dee2aaSAndroid Build Coastguard Worker SkScalar baseFrequencyX, 242*c8dee2aaSAndroid Build Coastguard Worker SkScalar baseFrequencyY, 243*c8dee2aaSAndroid Build Coastguard Worker int numOctaves, 244*c8dee2aaSAndroid Build Coastguard Worker SkScalar seed, 245*c8dee2aaSAndroid Build Coastguard Worker const SkISize* tileSize); 246*c8dee2aaSAndroid Build Coastguard Worker type()247*c8dee2aaSAndroid Build Coastguard Worker ShaderType type() const override { return ShaderType::kPerlinNoise; } 248*c8dee2aaSAndroid Build Coastguard Worker noiseType()249*c8dee2aaSAndroid Build Coastguard Worker SkPerlinNoiseShaderType noiseType() const { return fType; } numOctaves()250*c8dee2aaSAndroid Build Coastguard Worker int numOctaves() const { return fNumOctaves; } stitchTiles()251*c8dee2aaSAndroid Build Coastguard Worker bool stitchTiles() const { return fStitchTiles; } tileSize()252*c8dee2aaSAndroid Build Coastguard Worker SkISize tileSize() const { return fTileSize; } 253*c8dee2aaSAndroid Build Coastguard Worker getPaintingData()254*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<PaintingData> getPaintingData() const { 255*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<PaintingData>(fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY); 256*c8dee2aaSAndroid Build Coastguard Worker } 257*c8dee2aaSAndroid Build Coastguard Worker 258*c8dee2aaSAndroid Build Coastguard Worker bool appendStages(const SkStageRec& rec, const SkShaders::MatrixRec& mRec) const override; 259*c8dee2aaSAndroid Build Coastguard Worker 260*c8dee2aaSAndroid Build Coastguard Worker protected: 261*c8dee2aaSAndroid Build Coastguard Worker void flatten(SkWriteBuffer&) const override; 262*c8dee2aaSAndroid Build Coastguard Worker 263*c8dee2aaSAndroid Build Coastguard Worker private: 264*c8dee2aaSAndroid Build Coastguard Worker SK_FLATTENABLE_HOOKS(SkPerlinNoiseShader) 265*c8dee2aaSAndroid Build Coastguard Worker 266*c8dee2aaSAndroid Build Coastguard Worker const SkPerlinNoiseShaderType fType; 267*c8dee2aaSAndroid Build Coastguard Worker const SkScalar fBaseFrequencyX; 268*c8dee2aaSAndroid Build Coastguard Worker const SkScalar fBaseFrequencyY; 269*c8dee2aaSAndroid Build Coastguard Worker const int fNumOctaves; 270*c8dee2aaSAndroid Build Coastguard Worker const SkScalar fSeed; 271*c8dee2aaSAndroid Build Coastguard Worker const SkISize fTileSize; 272*c8dee2aaSAndroid Build Coastguard Worker const bool fStitchTiles; 273*c8dee2aaSAndroid Build Coastguard Worker 274*c8dee2aaSAndroid Build Coastguard Worker mutable SkOnce fInitPaintingDataOnce; 275*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<PaintingData> fPaintingData; 276*c8dee2aaSAndroid Build Coastguard Worker 277*c8dee2aaSAndroid Build Coastguard Worker friend void SkRegisterPerlinNoiseShaderFlattenable(); 278*c8dee2aaSAndroid Build Coastguard Worker }; 279*c8dee2aaSAndroid Build Coastguard Worker 280*c8dee2aaSAndroid Build Coastguard Worker #endif 281