blob: bbfb8cf5830bf9748213551b28cb67b366d734be [file] [log] [blame]
ethannicholas417011c2015-11-09 06:35:12 -08001/*
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 "SkPerlinNoiseShader2.h"
10#include "SkColorFilter.h"
11#include "SkReadBuffer.h"
12#include "SkWriteBuffer.h"
13#include "SkShader.h"
14#include "SkUnPreMultiply.h"
15#include "SkString.h"
16
17#if SK_SUPPORT_GPU
18#include "GrContext.h"
19#include "GrCoordTransform.h"
20#include "GrInvariantOutput.h"
21#include "SkGr.h"
22#include "effects/GrConstColorProcessor.h"
23#include "gl/GrGLFragmentProcessor.h"
24#include "gl/builders/GrGLProgramBuilder.h"
25#include "glsl/GrGLSLProgramDataManager.h"
26#endif
27
28static const int kBlockSize = 256;
29static const int kBlockMask = kBlockSize - 1;
30static const int kPerlinNoise = 4096;
31static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
32
33static uint8_t improved_noise_permutations[] = {
34 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
35 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
36 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
37 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
38 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
39 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
40 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
41 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
42 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
43 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
44 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
45 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
46 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
47 141, 128, 195, 78, 66, 215, 61, 156, 180,
48 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
49 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
50 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
51 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
52 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
53 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
54 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
55 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
56 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
57 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
58 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
59 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
60 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
61 141, 128, 195, 78, 66, 215, 61, 156, 180
62};
63
64namespace {
65
66// noiseValue is the color component's value (or color)
67// limitValue is the maximum perlin noise array index value allowed
68// newValue is the current noise dimension (either width or height)
69inline int checkNoise(int noiseValue, int limitValue, int newValue) {
70 // If the noise value would bring us out of bounds of the current noise array while we are
71 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
72 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
73 if (noiseValue >= limitValue) {
74 noiseValue -= newValue;
75 }
76 return noiseValue;
77}
78
79inline SkScalar smoothCurve(SkScalar t) {
80 static const SkScalar SK_Scalar3 = 3.0f;
81
82 // returns t * t * (3 - 2 * t)
83 return SkScalarMul(SkScalarSquare(t), SK_Scalar3 - 2 * t);
84}
85
86} // end namespace
87
88struct SkPerlinNoiseShader2::StitchData {
89 StitchData()
90 : fWidth(0)
91 , fWrapX(0)
92 , fHeight(0)
93 , fWrapY(0)
94 {}
95
96 bool operator==(const StitchData& other) const {
97 return fWidth == other.fWidth &&
98 fWrapX == other.fWrapX &&
99 fHeight == other.fHeight &&
100 fWrapY == other.fWrapY;
101 }
102
103 int fWidth; // How much to subtract to wrap for stitching.
104 int fWrapX; // Minimum value to wrap.
105 int fHeight;
106 int fWrapY;
107};
108
109struct SkPerlinNoiseShader2::PaintingData {
110 PaintingData(const SkISize& tileSize, SkScalar seed,
111 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
112 const SkMatrix& matrix)
113 {
114 SkVector vec[2] = {
115 { SkScalarInvert(baseFrequencyX), SkScalarInvert(baseFrequencyY) },
116 { SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight) },
117 };
118 matrix.mapVectors(vec, 2);
119
120 fBaseFrequency.set(SkScalarInvert(vec[0].fX), SkScalarInvert(vec[0].fY));
121 fTileSize.set(SkScalarRoundToInt(vec[1].fX), SkScalarRoundToInt(vec[1].fY));
122 this->init(seed);
123 if (!fTileSize.isEmpty()) {
124 this->stitch();
125 }
126
127#if SK_SUPPORT_GPU
128 fPermutationsBitmap.setInfo(SkImageInfo::MakeA8(kBlockSize, 1));
129 fPermutationsBitmap.setPixels(fLatticeSelector);
130
131 fNoiseBitmap.setInfo(SkImageInfo::MakeN32Premul(kBlockSize, 4));
132 fNoiseBitmap.setPixels(fNoise[0][0]);
133
134 fImprovedPermutationsBitmap.setInfo(SkImageInfo::MakeA8(256, 1));
135 fImprovedPermutationsBitmap.setPixels(improved_noise_permutations);
136
137 fGradientBitmap.setInfo(SkImageInfo::MakeN32Premul(16, 1));
138 static uint8_t gradients[] = { 2, 2, 1, 0,
139 0, 2, 1, 0,
140 2, 0, 1, 0,
141 0, 0, 1, 0,
142 2, 1, 2, 0,
143 0, 1, 2, 0,
144 2, 1, 0, 0,
145 0, 1, 0, 0,
146 1, 2, 2, 0,
147 1, 0, 2, 0,
148 1, 2, 0, 0,
149 1, 0, 0, 0,
150 2, 2, 1, 0,
151 1, 0, 2, 0,
152 0, 2, 1, 0,
153 1, 0, 0, 0 };
154 fGradientBitmap.setPixels(gradients);
155#endif
156 }
157
158 int fSeed;
159 uint8_t fLatticeSelector[kBlockSize];
160 uint16_t fNoise[4][kBlockSize][2];
161 SkPoint fGradient[4][kBlockSize];
162 SkISize fTileSize;
163 SkVector fBaseFrequency;
164 StitchData fStitchDataInit;
165
166private:
167
168#if SK_SUPPORT_GPU
169 SkBitmap fPermutationsBitmap;
170 SkBitmap fNoiseBitmap;
171 SkBitmap fImprovedPermutationsBitmap;
172 SkBitmap fGradientBitmap;
173#endif
174
175 inline int random() {
176 static const int gRandAmplitude = 16807; // 7**5; primitive root of m
177 static const int gRandQ = 127773; // m / a
178 static const int gRandR = 2836; // m % a
179
180 int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
181 if (result <= 0)
182 result += kRandMaximum;
183 fSeed = result;
184 return result;
185 }
186
187 // Only called once. Could be part of the constructor.
188 void init(SkScalar seed)
189 {
190 static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
191
192 // According to the SVG spec, we must truncate (not round) the seed value.
193 fSeed = SkScalarTruncToInt(seed);
194 // The seed value clamp to the range [1, kRandMaximum - 1].
195 if (fSeed <= 0) {
196 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
197 }
198 if (fSeed > kRandMaximum - 1) {
199 fSeed = kRandMaximum - 1;
200 }
201 for (int channel = 0; channel < 4; ++channel) {
202 for (int i = 0; i < kBlockSize; ++i) {
203 fLatticeSelector[i] = i;
204 fNoise[channel][i][0] = (random() % (2 * kBlockSize));
205 fNoise[channel][i][1] = (random() % (2 * kBlockSize));
206 }
207 }
208 for (int i = kBlockSize - 1; i > 0; --i) {
209 int k = fLatticeSelector[i];
210 int j = random() % kBlockSize;
211 SkASSERT(j >= 0);
212 SkASSERT(j < kBlockSize);
213 fLatticeSelector[i] = fLatticeSelector[j];
214 fLatticeSelector[j] = k;
215 }
216
217 // Perform the permutations now
218 {
219 // Copy noise data
220 uint16_t noise[4][kBlockSize][2];
221 for (int i = 0; i < kBlockSize; ++i) {
222 for (int channel = 0; channel < 4; ++channel) {
223 for (int j = 0; j < 2; ++j) {
224 noise[channel][i][j] = fNoise[channel][i][j];
225 }
226 }
227 }
228 // Do permutations on noise data
229 for (int i = 0; i < kBlockSize; ++i) {
230 for (int channel = 0; channel < 4; ++channel) {
231 for (int j = 0; j < 2; ++j) {
232 fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
233 }
234 }
235 }
236 }
237
238 // Half of the largest possible value for 16 bit unsigned int
239 static const SkScalar gHalfMax16bits = 32767.5f;
240
241 // Compute gradients from permutated noise data
242 for (int channel = 0; channel < 4; ++channel) {
243 for (int i = 0; i < kBlockSize; ++i) {
244 fGradient[channel][i] = SkPoint::Make(
245 SkScalarMul(SkIntToScalar(fNoise[channel][i][0] - kBlockSize),
246 gInvBlockSizef),
247 SkScalarMul(SkIntToScalar(fNoise[channel][i][1] - kBlockSize),
248 gInvBlockSizef));
249 fGradient[channel][i].normalize();
250 // Put the normalized gradient back into the noise data
251 fNoise[channel][i][0] = SkScalarRoundToInt(SkScalarMul(
252 fGradient[channel][i].fX + SK_Scalar1, gHalfMax16bits));
253 fNoise[channel][i][1] = SkScalarRoundToInt(SkScalarMul(
254 fGradient[channel][i].fY + SK_Scalar1, gHalfMax16bits));
255 }
256 }
257 }
258
259 // Only called once. Could be part of the constructor.
260 void stitch() {
261 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
262 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
263 SkASSERT(tileWidth > 0 && tileHeight > 0);
264 // When stitching tiled turbulence, the frequencies must be adjusted
265 // so that the tile borders will be continuous.
266 if (fBaseFrequency.fX) {
267 SkScalar lowFrequencx =
268 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
269 SkScalar highFrequencx =
270 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
271 // BaseFrequency should be non-negative according to the standard.
272 if (fBaseFrequency.fX / lowFrequencx < highFrequencx / fBaseFrequency.fX) {
273 fBaseFrequency.fX = lowFrequencx;
274 } else {
275 fBaseFrequency.fX = highFrequencx;
276 }
277 }
278 if (fBaseFrequency.fY) {
279 SkScalar lowFrequency =
280 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
281 SkScalar highFrequency =
282 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
283 if (fBaseFrequency.fY / lowFrequency < highFrequency / fBaseFrequency.fY) {
284 fBaseFrequency.fY = lowFrequency;
285 } else {
286 fBaseFrequency.fY = highFrequency;
287 }
288 }
289 // Set up TurbulenceInitial stitch values.
290 fStitchDataInit.fWidth =
291 SkScalarRoundToInt(tileWidth * fBaseFrequency.fX);
292 fStitchDataInit.fWrapX = kPerlinNoise + fStitchDataInit.fWidth;
293 fStitchDataInit.fHeight =
294 SkScalarRoundToInt(tileHeight * fBaseFrequency.fY);
295 fStitchDataInit.fWrapY = kPerlinNoise + fStitchDataInit.fHeight;
296 }
297
298public:
299
300#if SK_SUPPORT_GPU
301 const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
302
303 const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
304
305 const SkBitmap& getImprovedPermutationsBitmap() const { return fImprovedPermutationsBitmap; }
306
307 const SkBitmap& getGradientBitmap() const { return fGradientBitmap; }
308#endif
309};
310
311SkShader* SkPerlinNoiseShader2::CreateFractalNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY,
312 int numOctaves, SkScalar seed,
313 const SkISize* tileSize) {
314 return new SkPerlinNoiseShader2(kFractalNoise_Type, baseFrequencyX, baseFrequencyY, numOctaves,
315 seed, tileSize);
316}
317
318SkShader* SkPerlinNoiseShader2::CreateTurbulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY,
319 int numOctaves, SkScalar seed,
320 const SkISize* tileSize) {
321 return new SkPerlinNoiseShader2(kTurbulence_Type, baseFrequencyX, baseFrequencyY, numOctaves,
322 seed, tileSize);
323}
324
325SkShader* SkPerlinNoiseShader2::CreateImprovedNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY,
326 int numOctaves, SkScalar z) {
327 return new SkPerlinNoiseShader2(kImprovedNoise_Type, baseFrequencyX, baseFrequencyY, numOctaves,
328 z, NULL);
329}
330
331SkPerlinNoiseShader2::SkPerlinNoiseShader2(SkPerlinNoiseShader2::Type type,
332 SkScalar baseFrequencyX,
333 SkScalar baseFrequencyY,
334 int numOctaves,
335 SkScalar seed,
336 const SkISize* tileSize)
337 : fType(type)
338 , fBaseFrequencyX(baseFrequencyX)
339 , fBaseFrequencyY(baseFrequencyY)
340 , fNumOctaves(numOctaves > 255 ? 255 : numOctaves/*[0,255] octaves allowed*/)
341 , fSeed(seed)
342 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
343 , fStitchTiles(!fTileSize.isEmpty())
344{
345 SkASSERT(numOctaves >= 0 && numOctaves < 256);
346}
347
348SkPerlinNoiseShader2::~SkPerlinNoiseShader2() {
349}
350
351SkFlattenable* SkPerlinNoiseShader2::CreateProc(SkReadBuffer& buffer) {
352 Type type = (Type)buffer.readInt();
353 SkScalar freqX = buffer.readScalar();
354 SkScalar freqY = buffer.readScalar();
355 int octaves = buffer.readInt();
356 SkScalar seed = buffer.readScalar();
357 SkISize tileSize;
358 tileSize.fWidth = buffer.readInt();
359 tileSize.fHeight = buffer.readInt();
360
361 switch (type) {
362 case kFractalNoise_Type:
363 return SkPerlinNoiseShader2::CreateFractalNoise(freqX, freqY, octaves, seed, &tileSize);
364 case kTurbulence_Type:
365 return SkPerlinNoiseShader2::CreateTubulence(freqX, freqY, octaves, seed, &tileSize);
366 case kImprovedNoise_Type:
367 return SkPerlinNoiseShader2::CreateImprovedNoise(freqX, freqY, octaves, seed);
368 default:
369 return nullptr;
370 }
371}
372
373void SkPerlinNoiseShader2::flatten(SkWriteBuffer& buffer) const {
374 buffer.writeInt((int) fType);
375 buffer.writeScalar(fBaseFrequencyX);
376 buffer.writeScalar(fBaseFrequencyY);
377 buffer.writeInt(fNumOctaves);
378 buffer.writeScalar(fSeed);
379 buffer.writeInt(fTileSize.fWidth);
380 buffer.writeInt(fTileSize.fHeight);
381}
382
383SkScalar SkPerlinNoiseShader2::PerlinNoiseShaderContext::noise2D(
384 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
385 struct Noise {
386 int noisePositionIntegerValue;
387 int nextNoisePositionIntegerValue;
388 SkScalar noisePositionFractionValue;
389 Noise(SkScalar component)
390 {
391 SkScalar position = component + kPerlinNoise;
392 noisePositionIntegerValue = SkScalarFloorToInt(position);
393 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
394 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
395 }
396 };
397 Noise noiseX(noiseVector.x());
398 Noise noiseY(noiseVector.y());
399 SkScalar u, v;
400 const SkPerlinNoiseShader2& perlinNoiseShader = static_cast<const SkPerlinNoiseShader2&>(fShader);
401 // If stitching, adjust lattice points accordingly.
402 if (perlinNoiseShader.fStitchTiles) {
403 noiseX.noisePositionIntegerValue =
404 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
405 noiseY.noisePositionIntegerValue =
406 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
407 noiseX.nextNoisePositionIntegerValue =
408 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
409 noiseY.nextNoisePositionIntegerValue =
410 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
411 }
412 noiseX.noisePositionIntegerValue &= kBlockMask;
413 noiseY.noisePositionIntegerValue &= kBlockMask;
414 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
415 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
416 int i =
417 fPaintingData->fLatticeSelector[noiseX.noisePositionIntegerValue];
418 int j =
419 fPaintingData->fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
420 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
421 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
422 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
423 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
424 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
425 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
426 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
427 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
428 noiseY.noisePositionFractionValue); // Offset (0,0)
429 u = fPaintingData->fGradient[channel][b00].dot(fractionValue);
430 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
431 v = fPaintingData->fGradient[channel][b10].dot(fractionValue);
432 SkScalar a = SkScalarInterp(u, v, sx);
433 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
434 v = fPaintingData->fGradient[channel][b11].dot(fractionValue);
435 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
436 u = fPaintingData->fGradient[channel][b01].dot(fractionValue);
437 SkScalar b = SkScalarInterp(u, v, sx);
438 return SkScalarInterp(a, b, sy);
439}
440
441SkScalar SkPerlinNoiseShader2::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
442 int channel, StitchData& stitchData, const SkPoint& point) const {
443 const SkPerlinNoiseShader2& perlinNoiseShader = static_cast<const SkPerlinNoiseShader2&>(fShader);
444 if (perlinNoiseShader.fStitchTiles) {
445 // Set up TurbulenceInitial stitch values.
446 stitchData = fPaintingData->fStitchDataInit;
447 }
448 SkScalar turbulenceFunctionResult = 0;
449 SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), fPaintingData->fBaseFrequency.fX),
450 SkScalarMul(point.y(), fPaintingData->fBaseFrequency.fY)));
451 SkScalar ratio = SK_Scalar1;
452 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
453 SkScalar noise = noise2D(channel, stitchData, noiseVector);
454 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
455 noise : SkScalarAbs(noise);
456 turbulenceFunctionResult += numer / ratio;
457 noiseVector.fX *= 2;
458 noiseVector.fY *= 2;
459 ratio *= 2;
460 if (perlinNoiseShader.fStitchTiles) {
461 // Update stitch values
462 stitchData.fWidth *= 2;
463 stitchData.fWrapX = stitchData.fWidth + kPerlinNoise;
464 stitchData.fHeight *= 2;
465 stitchData.fWrapY = stitchData.fHeight + kPerlinNoise;
466 }
467 }
468
469 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
470 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
471 if (perlinNoiseShader.fType == kFractalNoise_Type) {
472 turbulenceFunctionResult =
473 SkScalarMul(turbulenceFunctionResult, SK_ScalarHalf) + SK_ScalarHalf;
474 }
475
476 if (channel == 3) { // Scale alpha by paint value
477 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
478 }
479
480 // Clamp result
481 return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1);
482}
483
484////////////////////////////////////////////////////////////////////////////////////////////////////
485// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
486static SkScalar fade(SkScalar t) {
487 return t * t * t * (t * (t * 6 - 15) + 10);
488}
489
490static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
491 return a + t * (b - a);
492}
493
494static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
495 int h = hash & 15;
496 SkScalar u = h < 8 ? x : y;
497 SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
498 return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
499}
500
501SkScalar SkPerlinNoiseShader2::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
502 int channel, const SkPoint& point) const {
503 const SkPerlinNoiseShader2& perlinNoiseShader = static_cast<const SkPerlinNoiseShader2&>(fShader);
504 SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
505 SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
506 // z offset between different channels, chosen arbitrarily
507 static const SkScalar CHANNEL_DELTA = 1000.0f;
508 SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
509 SkScalar result = 0;
510 SkScalar ratio = SK_Scalar1;
511 for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
512 int X = SkScalarFloorToInt(x) & 255;
513 int Y = SkScalarFloorToInt(y) & 255;
514 int Z = SkScalarFloorToInt(z) & 255;
515 SkScalar px = x - SkScalarFloorToScalar(x);
516 SkScalar py = y - SkScalarFloorToScalar(y);
517 SkScalar pz = z - SkScalarFloorToScalar(z);
518 SkScalar u = fade(px);
519 SkScalar v = fade(py);
520 SkScalar w = fade(pz);
521 uint8_t* permutations = improved_noise_permutations;
522 int A = permutations[X] + Y;
523 int AA = permutations[A] + Z;
524 int AB = permutations[A + 1] + Z;
525 int B = permutations[X + 1] + Y;
526 int BA = permutations[B] + Z;
527 int BB = permutations[B + 1] + Z;
528 result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
529 grad(permutations[BA ], px - 1, py , pz )),
530 lerp(u, grad(permutations[AB ], px , py - 1, pz ),
531 grad(permutations[BB ], px - 1, py - 1, pz ))),
532 lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
533 grad(permutations[BA + 1], px - 1, py , pz - 1)),
534 lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
535 grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
536 ratio;
537 x *= 2;
538 y *= 2;
539 ratio *= 2;
540 }
541 result = SkScalarClampMax((result + 1.0f) / 2.0f, 1.0f);
542 return result;
543}
544////////////////////////////////////////////////////////////////////////////////////////////////////
545
546SkPMColor SkPerlinNoiseShader2::PerlinNoiseShaderContext::shade(
547 const SkPoint& point, StitchData& stitchData) const {
548 const SkPerlinNoiseShader2& perlinNoiseShader = static_cast<const SkPerlinNoiseShader2&>(fShader);
549 SkPoint newPoint;
550 fMatrix.mapPoints(&newPoint, &point, 1);
551 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
552 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
553
554 U8CPU rgba[4];
555 for (int channel = 3; channel >= 0; --channel) {
556 SkScalar value;
557 if (perlinNoiseShader.fType == kImprovedNoise_Type) {
558 value = calculateImprovedNoiseValueForPoint(channel, newPoint);
559 }
560 else {
561 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
562 }
563 rgba[channel] = SkScalarFloorToInt(255 * value);
564 }
565 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
566}
567
568SkShader::Context* SkPerlinNoiseShader2::onCreateContext(const ContextRec& rec,
569 void* storage) const {
570 return new (storage) PerlinNoiseShaderContext(*this, rec);
571}
572
573size_t SkPerlinNoiseShader2::contextSize() const {
574 return sizeof(PerlinNoiseShaderContext);
575}
576
577SkPerlinNoiseShader2::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
578 const SkPerlinNoiseShader2& shader, const ContextRec& rec)
579 : INHERITED(shader, rec)
580{
581 SkMatrix newMatrix = *rec.fMatrix;
582 newMatrix.preConcat(shader.getLocalMatrix());
583 if (rec.fLocalMatrix) {
584 newMatrix.preConcat(*rec.fLocalMatrix);
585 }
586 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
587 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
588 fMatrix.setTranslate(-newMatrix.getTranslateX() + SK_Scalar1, -newMatrix.getTranslateY() + SK_Scalar1);
589 fPaintingData = new PaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
590 shader.fBaseFrequencyY, newMatrix);
591}
592
593SkPerlinNoiseShader2::PerlinNoiseShaderContext::~PerlinNoiseShaderContext() { delete fPaintingData; }
594
595void SkPerlinNoiseShader2::PerlinNoiseShaderContext::shadeSpan(
596 int x, int y, SkPMColor result[], int count) {
597 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
598 StitchData stitchData;
599 for (int i = 0; i < count; ++i) {
600 result[i] = shade(point, stitchData);
601 point.fX += SK_Scalar1;
602 }
603}
604
605void SkPerlinNoiseShader2::PerlinNoiseShaderContext::shadeSpan16(
606 int x, int y, uint16_t result[], int count) {
607 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
608 StitchData stitchData;
609 DITHER_565_SCAN(y);
610 for (int i = 0; i < count; ++i) {
611 unsigned dither = DITHER_VALUE(x);
612 result[i] = SkDitherRGB32To565(shade(point, stitchData), dither);
613 DITHER_INC_X(x);
614 point.fX += SK_Scalar1;
615 }
616}
617
618/////////////////////////////////////////////////////////////////////
619
620#if SK_SUPPORT_GPU
621
622class GrGLPerlinNoise2 : public GrGLFragmentProcessor {
623public:
624 GrGLPerlinNoise2(const GrProcessor&);
625 virtual ~GrGLPerlinNoise2() {}
626
627 virtual void emitCode(EmitArgs&) override;
628
629 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
630
631protected:
632 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
633
634private:
635
636 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
637 SkPerlinNoiseShader2::Type fType;
638 bool fStitchTiles;
639 int fNumOctaves;
640 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
641
642private:
643 typedef GrGLFragmentProcessor INHERITED;
644};
645
646/////////////////////////////////////////////////////////////////////
647
648class GrPerlinNoise2Effect : public GrFragmentProcessor {
649public:
650 static GrFragmentProcessor* Create(SkPerlinNoiseShader2::Type type,
651 int numOctaves, bool stitchTiles,
652 SkPerlinNoiseShader2::PaintingData* paintingData,
653 GrTexture* permutationsTexture, GrTexture* noiseTexture,
654 const SkMatrix& matrix) {
655 return new GrPerlinNoise2Effect(type, numOctaves, stitchTiles, paintingData,
656 permutationsTexture, noiseTexture, matrix);
657 }
658
659 virtual ~GrPerlinNoise2Effect() { delete fPaintingData; }
660
661 const char* name() const override { return "PerlinNoise"; }
662
663 const SkPerlinNoiseShader2::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
664
665 SkPerlinNoiseShader2::Type type() const { return fType; }
666 bool stitchTiles() const { return fStitchTiles; }
667 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
668 int numOctaves() const { return fNumOctaves; }
669 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
670
671private:
672 GrGLFragmentProcessor* onCreateGLInstance() const override {
673 return new GrGLPerlinNoise2(*this);
674 }
675
676 virtual void onGetGLProcessorKey(const GrGLSLCaps& caps,
677 GrProcessorKeyBuilder* b) const override {
678 GrGLPerlinNoise2::GenKey(*this, caps, b);
679 }
680
681 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
682 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
683 return fType == s.fType &&
684 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
685 fNumOctaves == s.fNumOctaves &&
686 fStitchTiles == s.fStitchTiles &&
687 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
688 }
689
690 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
691 inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput);
692 }
693
694 GrPerlinNoise2Effect(SkPerlinNoiseShader2::Type type,
695 int numOctaves, bool stitchTiles,
696 SkPerlinNoiseShader2::PaintingData* paintingData,
697 GrTexture* permutationsTexture, GrTexture* noiseTexture,
698 const SkMatrix& matrix)
699 : fType(type)
700 , fNumOctaves(numOctaves)
701 , fStitchTiles(stitchTiles)
702 , fPermutationsAccess(permutationsTexture)
703 , fNoiseAccess(noiseTexture)
704 , fPaintingData(paintingData) {
705 this->initClassID<GrPerlinNoise2Effect>();
706 this->addTextureAccess(&fPermutationsAccess);
707 this->addTextureAccess(&fNoiseAccess);
708 fCoordTransform.reset(kLocal_GrCoordSet, matrix);
709 this->addCoordTransform(&fCoordTransform);
710 }
711
712 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
713
714 SkPerlinNoiseShader2::Type fType;
715 GrCoordTransform fCoordTransform;
716 int fNumOctaves;
717 bool fStitchTiles;
718 GrTextureAccess fPermutationsAccess;
719 GrTextureAccess fNoiseAccess;
720 SkPerlinNoiseShader2::PaintingData *fPaintingData;
721
722private:
723 typedef GrFragmentProcessor INHERITED;
724};
725
726/////////////////////////////////////////////////////////////////////
727GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
728
729const GrFragmentProcessor* GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
730 int numOctaves = d->fRandom->nextRangeU(2, 10);
731 bool stitchTiles = d->fRandom->nextBool();
732 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
733 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
734 d->fRandom->nextRangeU(4, 4096));
735 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
736 0.99f);
737 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
738 0.99f);
739
740 SkAutoTUnref<SkShader> shader(d->fRandom->nextBool() ?
741 SkPerlinNoiseShader2::CreateFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
742 stitchTiles ? &tileSize : nullptr) :
743 SkPerlinNoiseShader2::CreateTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
744 stitchTiles ? &tileSize : nullptr));
745
746 GrPaint grPaint;
747 return shader->asFragmentProcessor(d->fContext,
748 GrTest::TestMatrix(d->fRandom), nullptr,
749 kNone_SkFilterQuality);
750}
751
752GrGLPerlinNoise2::GrGLPerlinNoise2(const GrProcessor& processor)
753 : fType(processor.cast<GrPerlinNoise2Effect>().type())
754 , fStitchTiles(processor.cast<GrPerlinNoise2Effect>().stitchTiles())
755 , fNumOctaves(processor.cast<GrPerlinNoise2Effect>().numOctaves()) {
756}
757
758void GrGLPerlinNoise2::emitCode(EmitArgs& args) {
759 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
760 SkString vCoords = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
761
762 fBaseFrequencyUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
763 kVec2f_GrSLType, kDefault_GrSLPrecision,
764 "baseFrequency");
765 const char* baseFrequencyUni = args.fBuilder->getUniformCStr(fBaseFrequencyUni);
766
767 const char* stitchDataUni = nullptr;
768 if (fStitchTiles) {
769 fStitchDataUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
770 kVec2f_GrSLType, kDefault_GrSLPrecision,
771 "stitchData");
772 stitchDataUni = args.fBuilder->getUniformCStr(fStitchDataUni);
773 }
774
775 // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
776 const char* chanCoordR = "0.125";
777 const char* chanCoordG = "0.375";
778 const char* chanCoordB = "0.625";
779 const char* chanCoordA = "0.875";
780 const char* chanCoord = "chanCoord";
781 const char* stitchData = "stitchData";
782 const char* ratio = "ratio";
783 const char* noiseVec = "noiseVec";
784 const char* noiseSmooth = "noiseSmooth";
785 const char* floorVal = "floorVal";
786 const char* fractVal = "fractVal";
787 const char* uv = "uv";
788 const char* ab = "ab";
789 const char* latticeIdx = "latticeIdx";
790 const char* bcoords = "bcoords";
791 const char* lattice = "lattice";
792 const char* inc8bit = "0.00390625"; // 1.0 / 256.0
793 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
794 // [-1,1] vector and perform a dot product between that vector and the provided vector.
795 const char* dotLattice = "dot(((%s.ga + %s.rb * vec2(%s)) * vec2(2.0) - vec2(1.0)), %s);";
796
797 // Add noise function
798 static const GrGLSLShaderVar gPerlinNoiseArgs[] = {
799 GrGLSLShaderVar(chanCoord, kFloat_GrSLType),
800 GrGLSLShaderVar(noiseVec, kVec2f_GrSLType)
801 };
802
803 static const GrGLSLShaderVar gPerlinNoiseStitchArgs[] = {
804 GrGLSLShaderVar(chanCoord, kFloat_GrSLType),
805 GrGLSLShaderVar(noiseVec, kVec2f_GrSLType),
806 GrGLSLShaderVar(stitchData, kVec2f_GrSLType)
807 };
808
809 SkString noiseCode;
810
811 noiseCode.appendf("\tvec4 %s;\n", floorVal);
812 noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
813 noiseCode.appendf("\t%s.zw = %s.xy + vec2(1.0);\n", floorVal, floorVal);
814 noiseCode.appendf("\tvec2 %s = fract(%s);\n", fractVal, noiseVec);
815
816 // smooth curve : t * t * (3 - 2 * t)
817 noiseCode.appendf("\n\tvec2 %s = %s * %s * (vec2(3.0) - vec2(2.0) * %s);",
818 noiseSmooth, fractVal, fractVal, fractVal);
819
820 // Adjust frequencies if we're stitching tiles
821 if (fStitchTiles) {
822 noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
823 floorVal, stitchData, floorVal, stitchData);
824 noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
825 floorVal, stitchData, floorVal, stitchData);
826 noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
827 floorVal, stitchData, floorVal, stitchData);
828 noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
829 floorVal, stitchData, floorVal, stitchData);
830 }
831
832 // Get texture coordinates and normalize
833 noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / vec4(256.0));\n",
834 floorVal, floorVal);
835
836 // Get permutation for x
837 {
838 SkString xCoords("");
839 xCoords.appendf("vec2(%s.x, 0.5)", floorVal);
840
841 noiseCode.appendf("\n\tvec2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
842 fsBuilder->appendTextureLookup(&noiseCode, args.fSamplers[0], xCoords.c_str(),
843 kVec2f_GrSLType);
844 noiseCode.append(".r;");
845 }
846
847 // Get permutation for x + 1
848 {
849 SkString xCoords("");
850 xCoords.appendf("vec2(%s.z, 0.5)", floorVal);
851
852 noiseCode.appendf("\n\t%s.y = ", latticeIdx);
853 fsBuilder->appendTextureLookup(&noiseCode, args.fSamplers[0], xCoords.c_str(),
854 kVec2f_GrSLType);
855 noiseCode.append(".r;");
856 }
857
858#if defined(SK_BUILD_FOR_ANDROID)
859 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
860 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
861 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
862 // (or 0.484368 here). The following rounding operation prevents these precision issues from
863 // affecting the result of the noise by making sure that we only have multiples of 1/255.
864 // (Note that 1/255 is about 0.003921569, which is the value used here).
865 noiseCode.appendf("\n\t%s = floor(%s * vec2(255.0) + vec2(0.5)) * vec2(0.003921569);",
866 latticeIdx, latticeIdx);
867#endif
868
869 // Get (x,y) coordinates with the permutated x
870 noiseCode.appendf("\n\tvec4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
871
872 noiseCode.appendf("\n\n\tvec2 %s;", uv);
873 // Compute u, at offset (0,0)
874 {
875 SkString latticeCoords("");
876 latticeCoords.appendf("vec2(%s.x, %s)", bcoords, chanCoord);
877 noiseCode.appendf("\n\tvec4 %s = ", lattice);
878 fsBuilder->appendTextureLookup(&noiseCode, args.fSamplers[1], latticeCoords.c_str(),
879 kVec2f_GrSLType);
880 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
881 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
882 }
883
884 noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
885 // Compute v, at offset (-1,0)
886 {
887 SkString latticeCoords("");
888 latticeCoords.appendf("vec2(%s.y, %s)", bcoords, chanCoord);
889 noiseCode.append("\n\tlattice = ");
890 fsBuilder->appendTextureLookup(&noiseCode, args.fSamplers[1], latticeCoords.c_str(),
891 kVec2f_GrSLType);
892 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
893 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
894 }
895
896 // Compute 'a' as a linear interpolation of 'u' and 'v'
897 noiseCode.appendf("\n\tvec2 %s;", ab);
898 noiseCode.appendf("\n\t%s.x = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth);
899
900 noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
901 // Compute v, at offset (-1,-1)
902 {
903 SkString latticeCoords("");
904 latticeCoords.appendf("vec2(%s.w, %s)", bcoords, chanCoord);
905 noiseCode.append("\n\tlattice = ");
906 fsBuilder->appendTextureLookup(&noiseCode, args.fSamplers[1], latticeCoords.c_str(),
907 kVec2f_GrSLType);
908 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
909 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
910 }
911
912 noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
913 // Compute u, at offset (0,-1)
914 {
915 SkString latticeCoords("");
916 latticeCoords.appendf("vec2(%s.z, %s)", bcoords, chanCoord);
917 noiseCode.append("\n\tlattice = ");
918 fsBuilder->appendTextureLookup(&noiseCode, args.fSamplers[1], latticeCoords.c_str(),
919 kVec2f_GrSLType);
920 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
921 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
922 }
923
924 // Compute 'b' as a linear interpolation of 'u' and 'v'
925 noiseCode.appendf("\n\t%s.y = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth);
926 // Compute the noise as a linear interpolation of 'a' and 'b'
927 noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
928
929 SkString noiseFuncName;
930 if (fStitchTiles) {
931 fsBuilder->emitFunction(kFloat_GrSLType,
932 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
933 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
934 } else {
935 fsBuilder->emitFunction(kFloat_GrSLType,
936 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
937 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
938 }
939
940 // There are rounding errors if the floor operation is not performed here
941 fsBuilder->codeAppendf("\n\t\tvec2 %s = floor(%s.xy) * %s;",
942 noiseVec, vCoords.c_str(), baseFrequencyUni);
943
944 // Clear the color accumulator
945 fsBuilder->codeAppendf("\n\t\t%s = vec4(0.0);", args.fOutputColor);
946
947 if (fStitchTiles) {
948 // Set up TurbulenceInitial stitch values.
949 fsBuilder->codeAppendf("\n\t\tvec2 %s = %s;", stitchData, stitchDataUni);
950 }
951
952 fsBuilder->codeAppendf("\n\t\tfloat %s = 1.0;", ratio);
953
954 // Loop over all octaves
955 fsBuilder->codeAppendf("\n\t\tfor (int octave = 0; octave < %d; ++octave) {", fNumOctaves);
956
957 fsBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor);
958 if (fType != SkPerlinNoiseShader2::kFractalNoise_Type) {
959 fsBuilder->codeAppend("abs(");
960 }
961 if (fStitchTiles) {
962 fsBuilder->codeAppendf(
963 "vec4(\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s),"
964 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
965 noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
966 noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
967 noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
968 noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
969 } else {
970 fsBuilder->codeAppendf(
971 "vec4(\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s),"
972 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
973 noiseFuncName.c_str(), chanCoordR, noiseVec,
974 noiseFuncName.c_str(), chanCoordG, noiseVec,
975 noiseFuncName.c_str(), chanCoordB, noiseVec,
976 noiseFuncName.c_str(), chanCoordA, noiseVec);
977 }
978 if (fType != SkPerlinNoiseShader2::kFractalNoise_Type) {
979 fsBuilder->codeAppendf(")"); // end of "abs("
980 }
981 fsBuilder->codeAppendf(" * %s;", ratio);
982
983 fsBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", noiseVec);
984 fsBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
985
986 if (fStitchTiles) {
987 fsBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", stitchData);
988 }
989 fsBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
990
991 if (fType == SkPerlinNoiseShader2::kFractalNoise_Type) {
992 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
993 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
994 fsBuilder->codeAppendf("\n\t\t%s = %s * vec4(0.5) + vec4(0.5);",
995 args.fOutputColor,args.fOutputColor);
996 }
997
998 // Clamp values
999 fsBuilder->codeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);
1000
1001 // Pre-multiply the result
1002 fsBuilder->codeAppendf("\n\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n",
1003 args.fOutputColor, args.fOutputColor,
1004 args.fOutputColor, args.fOutputColor);
1005}
1006
1007void GrGLPerlinNoise2::GenKey(const GrProcessor& processor, const GrGLSLCaps&,
1008 GrProcessorKeyBuilder* b) {
1009 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
1010
1011 uint32_t key = turbulence.numOctaves();
1012
1013 key = key << 3; // Make room for next 3 bits
1014
1015 switch (turbulence.type()) {
1016 case SkPerlinNoiseShader2::kFractalNoise_Type:
1017 key |= 0x1;
1018 break;
1019 case SkPerlinNoiseShader2::kTurbulence_Type:
1020 key |= 0x2;
1021 break;
1022 default:
1023 // leave key at 0
1024 break;
1025 }
1026
1027 if (turbulence.stitchTiles()) {
1028 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1029 }
1030
1031 b->add32(key);
1032}
1033
1034void GrGLPerlinNoise2::onSetData(const GrGLSLProgramDataManager& pdman,
1035 const GrProcessor& processor) {
1036 INHERITED::onSetData(pdman, processor);
1037
1038 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
1039
1040 const SkVector& baseFrequency = turbulence.baseFrequency();
1041 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1042
1043 if (turbulence.stitchTiles()) {
1044 const SkPerlinNoiseShader2::StitchData& stitchData = turbulence.stitchData();
1045 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
1046 SkIntToScalar(stitchData.fHeight));
1047 }
1048}
1049
1050/////////////////////////////////////////////////////////////////////
1051
1052class GrGLImprovedPerlinNoise : public GrGLFragmentProcessor {
1053public:
1054 GrGLImprovedPerlinNoise(const GrProcessor&);
1055 virtual ~GrGLImprovedPerlinNoise() {}
1056
1057 virtual void emitCode(EmitArgs&) override;
1058
1059 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
1060
1061protected:
1062 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
1063
1064private:
1065
1066 SkScalar fZ;
1067 GrGLSLProgramDataManager::UniformHandle fZUni;
1068 GrGLSLProgramDataManager::UniformHandle fOctavesUni;
1069 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1070
1071private:
1072 typedef GrGLFragmentProcessor INHERITED;
1073};
1074
1075/////////////////////////////////////////////////////////////////////
1076
1077class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1078public:
egdaniel478c04e2015-11-09 07:40:49 -08001079 static GrFragmentProcessor* Create(int octaves, SkScalar z,
ethannicholas417011c2015-11-09 06:35:12 -08001080 SkPerlinNoiseShader2::PaintingData* paintingData,
1081 GrTexture* permutationsTexture, GrTexture* gradientTexture,
1082 const SkMatrix& matrix) {
1083 return new GrImprovedPerlinNoiseEffect(octaves, z, paintingData, permutationsTexture,
1084 gradientTexture, matrix);
1085 }
1086
1087 virtual ~GrImprovedPerlinNoiseEffect() { delete fPaintingData; }
1088
1089 const char* name() const override { return "ImprovedPerlinNoise"; }
1090
1091 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1092 SkScalar z() const { return fZ; }
1093 int octaves() const { return fOctaves; }
1094 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
1095
1096private:
1097 GrGLFragmentProcessor* onCreateGLInstance() const override {
1098 return new GrGLImprovedPerlinNoise(*this);
1099 }
1100
1101 virtual void onGetGLProcessorKey(const GrGLSLCaps& caps,
1102 GrProcessorKeyBuilder* b) const override {
1103 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1104 }
1105
1106 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1107 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1108 return fZ == fZ &&
1109 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1110 }
1111
1112 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
1113 inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput);
1114 }
1115
1116 GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
1117 SkPerlinNoiseShader2::PaintingData* paintingData,
1118 GrTexture* permutationsTexture, GrTexture* gradientTexture,
1119 const SkMatrix& matrix)
1120 : fOctaves(octaves)
1121 , fZ(z)
1122 , fPermutationsAccess(permutationsTexture)
1123 , fGradientAccess(gradientTexture)
1124 , fPaintingData(paintingData) {
1125 this->initClassID<GrImprovedPerlinNoiseEffect>();
1126 this->addTextureAccess(&fPermutationsAccess);
1127 this->addTextureAccess(&fGradientAccess);
1128 fCoordTransform.reset(kLocal_GrCoordSet, matrix);
1129 this->addCoordTransform(&fCoordTransform);
1130 }
1131
1132 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
1133
1134 GrCoordTransform fCoordTransform;
1135 int fOctaves;
1136 SkScalar fZ;
1137 GrTextureAccess fPermutationsAccess;
1138 GrTextureAccess fGradientAccess;
1139 SkPerlinNoiseShader2::PaintingData *fPaintingData;
1140
1141private:
1142 typedef GrFragmentProcessor INHERITED;
1143};
1144
1145/////////////////////////////////////////////////////////////////////
1146GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1147
1148const GrFragmentProcessor* GrImprovedPerlinNoiseEffect::TestCreate(GrProcessorTestData* d) {
1149 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1150 0.99f);
1151 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1152 0.99f);
1153 int numOctaves = d->fRandom->nextRangeU(2, 10);
1154 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1155
1156 SkAutoTUnref<SkShader> shader(SkPerlinNoiseShader2::CreateImprovedNoise(baseFrequencyX,
1157 baseFrequencyY,
1158 numOctaves,
1159 z));
1160
1161 GrPaint grPaint;
1162 return shader->asFragmentProcessor(d->fContext,
1163 GrTest::TestMatrix(d->fRandom), nullptr,
1164 kNone_SkFilterQuality);
1165}
1166
1167GrGLImprovedPerlinNoise::GrGLImprovedPerlinNoise(const GrProcessor& processor)
1168 : fZ(processor.cast<GrImprovedPerlinNoiseEffect>().z()) {
1169}
1170
1171void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
1172 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
1173 SkString vCoords = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
1174
1175 fBaseFrequencyUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1176 kVec2f_GrSLType, kDefault_GrSLPrecision,
1177 "baseFrequency");
1178 const char* baseFrequencyUni = args.fBuilder->getUniformCStr(fBaseFrequencyUni);
1179
1180 fOctavesUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1181 kFloat_GrSLType, kDefault_GrSLPrecision,
1182 "octaves");
1183 const char* octavesUni = args.fBuilder->getUniformCStr(fOctavesUni);
1184
1185 fZUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1186 kFloat_GrSLType, kDefault_GrSLPrecision,
1187 "z");
1188 const char* zUni = args.fBuilder->getUniformCStr(fZUni);
1189
1190 // fade function
1191 static const GrGLSLShaderVar fadeArgs[] = {
1192 GrGLSLShaderVar("t", kVec3f_GrSLType)
1193 };
1194 SkString fadeFuncName;
1195 fsBuilder->emitFunction(kVec3f_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
1196 fadeArgs,
1197 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1198 &fadeFuncName);
1199
1200 // perm function
1201 static const GrGLSLShaderVar permArgs[] = {
1202 GrGLSLShaderVar("x", kFloat_GrSLType)
1203 };
1204 SkString permFuncName;
1205 SkString permCode("return ");
1206 // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not
1207 // sure why. Using fract() (here and the next texture lookup) as a workaround.
1208 fsBuilder->appendTextureLookup(&permCode, args.fSamplers[0], "vec2(fract(x / 256.0), 0.0)",
1209 kVec2f_GrSLType);
1210 permCode.append(".r * 255.0;");
1211 fsBuilder->emitFunction(kFloat_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
1212 permCode.c_str(), &permFuncName);
1213
1214 // grad function
1215 static const GrGLSLShaderVar gradArgs[] = {
1216 GrGLSLShaderVar("x", kFloat_GrSLType),
1217 GrGLSLShaderVar("p", kVec3f_GrSLType)
1218 };
1219 SkString gradFuncName;
1220 SkString gradCode("return dot(");
1221 fsBuilder->appendTextureLookup(&gradCode, args.fSamplers[1], "vec2(fract(x / 16.0), 0.0)",
1222 kVec2f_GrSLType);
1223 gradCode.append(".rgb * 255.0 - vec3(1.0), p);");
1224 fsBuilder->emitFunction(kFloat_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
1225 gradCode.c_str(), &gradFuncName);
1226
1227 // lerp function
1228 static const GrGLSLShaderVar lerpArgs[] = {
1229 GrGLSLShaderVar("a", kFloat_GrSLType),
1230 GrGLSLShaderVar("b", kFloat_GrSLType),
1231 GrGLSLShaderVar("w", kFloat_GrSLType)
1232 };
1233 SkString lerpFuncName;
1234 fsBuilder->emitFunction(kFloat_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
1235 "return a + w * (b - a);", &lerpFuncName);
1236
1237 // noise function
1238 static const GrGLSLShaderVar noiseArgs[] = {
1239 GrGLSLShaderVar("p", kVec3f_GrSLType),
1240 };
1241 SkString noiseFuncName;
1242 SkString noiseCode;
1243 noiseCode.append("vec3 P = mod(floor(p), 256.0);");
1244 noiseCode.append("p -= floor(p);");
1245 noiseCode.appendf("vec3 f = %s(p);", fadeFuncName.c_str());
1246 noiseCode.appendf("float A = %s(P.x) + P.y;", permFuncName.c_str());
1247 noiseCode.appendf("float AA = %s(A) + P.z;", permFuncName.c_str());
1248 noiseCode.appendf("float AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1249 noiseCode.appendf("float B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1250 noiseCode.appendf("float BA = %s(B) + P.z;", permFuncName.c_str());
1251 noiseCode.appendf("float BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1252 noiseCode.appendf("float result = %s(", lerpFuncName.c_str());
1253 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1254 gradFuncName.c_str(), permFuncName.c_str());
1255 noiseCode.appendf("%s(%s(BA), p + vec3(-1.0, 0.0, 0.0)), f.x),", gradFuncName.c_str(),
1256 permFuncName.c_str());
1257 noiseCode.appendf("%s(%s(%s(AB), p + vec3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
1258 gradFuncName.c_str(), permFuncName.c_str());
1259 noiseCode.appendf("%s(%s(BB), p + vec3(-1.0, -1.0, 0.0)), f.x), f.y),",
1260 gradFuncName.c_str(), permFuncName.c_str());
1261 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + vec3(0.0, 0.0, -1.0)),",
1262 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1263 permFuncName.c_str());
1264 noiseCode.appendf("%s(%s(BA + 1.0), p + vec3(-1.0, 0.0, -1.0)), f.x),",
1265 gradFuncName.c_str(), permFuncName.c_str());
1266 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + vec3(0.0, -1.0, -1.0)),",
1267 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
1268 noiseCode.appendf("%s(%s(BB + 1.0), p + vec3(-1.0, -1.0, -1.0)), f.x), f.y), f.z);",
1269 gradFuncName.c_str(), permFuncName.c_str());
1270 noiseCode.append("return result;");
1271 fsBuilder->emitFunction(kFloat_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
1272 noiseCode.c_str(), &noiseFuncName);
1273
1274 // noiseOctaves function
1275 static const GrGLSLShaderVar noiseOctavesArgs[] = {
1276 GrGLSLShaderVar("p", kVec3f_GrSLType),
1277 GrGLSLShaderVar("octaves", kFloat_GrSLType),
1278 };
1279 SkString noiseOctavesFuncName;
1280 SkString noiseOctavesCode;
1281 noiseOctavesCode.append("float result = 0.0;");
1282 noiseOctavesCode.append("float ratio = 1.0;");
1283 noiseOctavesCode.append("for (float i = 0.0; i < octaves; i++) {");
1284 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1285 noiseOctavesCode.append("p *= 2.0;");
1286 noiseOctavesCode.append("ratio *= 2.0;");
1287 noiseOctavesCode.append("}");
1288 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
1289 fsBuilder->emitFunction(kFloat_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
1290 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1291
1292 fsBuilder->codeAppendf("vec2 coords = %s * %s;", vCoords.c_str(), baseFrequencyUni);
1293 fsBuilder->codeAppendf("float r = %s(vec3(coords, %s), %s);", noiseOctavesFuncName.c_str(),
1294 zUni, octavesUni);
egdaniel478c04e2015-11-09 07:40:49 -08001295 fsBuilder->codeAppendf("float g = %s(vec3(coords, %s + 0000.0), %s);",
ethannicholas417011c2015-11-09 06:35:12 -08001296 noiseOctavesFuncName.c_str(), zUni, octavesUni);
egdaniel478c04e2015-11-09 07:40:49 -08001297 fsBuilder->codeAppendf("float b = %s(vec3(coords, %s + 0000.0), %s);",
ethannicholas417011c2015-11-09 06:35:12 -08001298 noiseOctavesFuncName.c_str(), zUni, octavesUni);
egdaniel478c04e2015-11-09 07:40:49 -08001299 fsBuilder->codeAppendf("float a = %s(vec3(coords, %s + 0000.0), %s);",
ethannicholas417011c2015-11-09 06:35:12 -08001300 noiseOctavesFuncName.c_str(), zUni, octavesUni);
1301 fsBuilder->codeAppendf("%s = vec4(r, g, b, a);", args.fOutputColor);
1302
1303 // Clamp values
1304 fsBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);
1305
1306 // Pre-multiply the result
1307 fsBuilder->codeAppendf("\n\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n",
1308 args.fOutputColor, args.fOutputColor,
1309 args.fOutputColor, args.fOutputColor);
1310}
1311
1312void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrGLSLCaps&,
1313 GrProcessorKeyBuilder* b) {
1314}
1315
1316void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1317 const GrProcessor& processor) {
1318 INHERITED::onSetData(pdman, processor);
1319
1320 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1321
1322 const SkVector& baseFrequency = noise.baseFrequency();
1323 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1324
egdaniel478c04e2015-11-09 07:40:49 -08001325 pdman.set1f(fOctavesUni, SkIntToScalar(noise.octaves()));
ethannicholas417011c2015-11-09 06:35:12 -08001326
1327 pdman.set1f(fZUni, noise.z());
1328}
1329
1330/////////////////////////////////////////////////////////////////////
1331const GrFragmentProcessor* SkPerlinNoiseShader2::asFragmentProcessor(
1332 GrContext* context,
1333 const SkMatrix& viewM,
1334 const SkMatrix* externalLocalMatrix,
1335 SkFilterQuality) const {
1336 SkASSERT(context);
1337
1338 SkMatrix localMatrix = this->getLocalMatrix();
1339 if (externalLocalMatrix) {
1340 localMatrix.preConcat(*externalLocalMatrix);
1341 }
1342
1343 SkMatrix matrix = viewM;
1344 matrix.preConcat(localMatrix);
1345
1346 // Either we don't stitch tiles, either we have a valid tile size
1347 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1348
1349 SkPerlinNoiseShader2::PaintingData* paintingData =
1350 new PaintingData(fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY, matrix);
1351
1352 SkMatrix m = viewM;
1353 m.setTranslateX(-localMatrix.getTranslateX() + SK_Scalar1);
1354 m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1);
1355
1356 if (fType == kImprovedNoise_Type) {
1357 GrTextureParams textureParams(SkShader::TileMode::kRepeat_TileMode,
1358 GrTextureParams::FilterMode::kNone_FilterMode);
1359 SkAutoTUnref<GrTexture> permutationsTexture(
1360 GrRefCachedBitmapTexture(context, paintingData->getImprovedPermutationsBitmap(),
1361 textureParams));
1362 SkAutoTUnref<GrTexture> gradientTexture(
1363 GrRefCachedBitmapTexture(context, paintingData->getGradientBitmap(),
1364 textureParams));
1365 return GrImprovedPerlinNoiseEffect::Create(fNumOctaves, fSeed, paintingData,
1366 permutationsTexture, gradientTexture, m);
1367 }
1368
1369 if (0 == fNumOctaves) {
1370 if (kFractalNoise_Type == fType) {
1371 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
1372 SkAutoTUnref<const GrFragmentProcessor> inner(
1373 GrConstColorProcessor::Create(0x80404040,
1374 GrConstColorProcessor::kModulateRGBA_InputMode));
1375 return GrFragmentProcessor::MulOutputByInputAlpha(inner);
1376 }
1377 // Emit zero.
1378 return GrConstColorProcessor::Create(0x0, GrConstColorProcessor::kIgnore_InputMode);
1379 }
1380
1381 SkAutoTUnref<GrTexture> permutationsTexture(
1382 GrRefCachedBitmapTexture(context, paintingData->getPermutationsBitmap(),
1383 GrTextureParams::ClampNoFilter()));
1384 SkAutoTUnref<GrTexture> noiseTexture(
1385 GrRefCachedBitmapTexture(context, paintingData->getNoiseBitmap(),
1386 GrTextureParams::ClampNoFilter()));
1387
1388 if ((permutationsTexture) && (noiseTexture)) {
1389 SkAutoTUnref<GrFragmentProcessor> inner(
1390 GrPerlinNoise2Effect::Create(fType,
1391 fNumOctaves,
1392 fStitchTiles,
1393 paintingData,
1394 permutationsTexture, noiseTexture,
1395 m));
1396 return GrFragmentProcessor::MulOutputByInputAlpha(inner);
1397 }
1398 delete paintingData;
1399 return nullptr;
1400}
1401
1402#endif
1403
1404#ifndef SK_IGNORE_TO_STRING
1405void SkPerlinNoiseShader2::toString(SkString* str) const {
1406 str->append("SkPerlinNoiseShader2: (");
1407
1408 str->append("type: ");
1409 switch (fType) {
1410 case kFractalNoise_Type:
1411 str->append("\"fractal noise\"");
1412 break;
1413 case kTurbulence_Type:
1414 str->append("\"turbulence\"");
1415 break;
1416 default:
1417 str->append("\"unknown\"");
1418 break;
1419 }
1420 str->append(" base frequency: (");
1421 str->appendScalar(fBaseFrequencyX);
1422 str->append(", ");
1423 str->appendScalar(fBaseFrequencyY);
1424 str->append(") number of octaves: ");
1425 str->appendS32(fNumOctaves);
1426 str->append(" seed: ");
1427 str->appendScalar(fSeed);
1428 str->append(" stitch tiles: ");
1429 str->append(fStitchTiles ? "true " : "false ");
1430
1431 this->INHERITED::toString(str);
1432
1433 str->append(")");
1434}
1435#endif