OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkDither.h" | 8 #include "SkDither.h" |
9 #include "SkPerlinNoiseShader.h" | 9 #include "SkPerlinNoiseShader.h" |
10 #include "SkColorFilter.h" | 10 #include "SkColorFilter.h" |
11 #include "SkReadBuffer.h" | 11 #include "SkReadBuffer.h" |
12 #include "SkWriteBuffer.h" | 12 #include "SkWriteBuffer.h" |
13 #include "SkShader.h" | 13 #include "SkShader.h" |
14 #include "SkUnPreMultiply.h" | 14 #include "SkUnPreMultiply.h" |
15 #include "SkString.h" | 15 #include "SkString.h" |
16 | 16 |
17 #if SK_SUPPORT_GPU | 17 #if SK_SUPPORT_GPU |
18 #include "GrContext.h" | 18 #include "GrContext.h" |
19 #include "GrCoordTransform.h" | 19 #include "GrCoordTransform.h" |
20 #include "gl/GrGLEffect.h" | 20 #include "gl/GrGLEffect.h" |
21 #include "GrTBackendEffectFactory.h" | 21 #include "GrTBackendEffectFactory.h" |
22 #include "SkGr.h" | 22 #include "SkGr.h" |
23 #endif | 23 #endif |
24 | 24 |
25 static const int kBlockSize = 256; | 25 const int SkPerlinNoiseShader::kBlockSize; |
26 static const int kBlockMask = kBlockSize - 1; | 26 const int SkPerlinNoiseShader::kBlockMask; |
27 static const int kPerlinNoise = 4096; | 27 static const int kPerlinNoise = 4096; |
28 static const int kRandMaximum = SK_MaxS32; // 2**31 - 1 | 28 static const int kRandMaximum = SK_MaxS32; // 2**31 - 1 |
29 | 29 |
30 namespace { | 30 namespace { |
31 | 31 |
32 // noiseValue is the color component's value (or color) | 32 // noiseValue is the color component's value (or color) |
33 // limitValue is the maximum perlin noise array index value allowed | 33 // limitValue is the maximum perlin noise array index value allowed |
34 // newValue is the current noise dimension (either width or height) | 34 // newValue is the current noise dimension (either width or height) |
35 inline int checkNoise(int noiseValue, int limitValue, int newValue) { | 35 inline int checkNoise(int noiseValue, int limitValue, int newValue) { |
36 // If the noise value would bring us out of bounds of the current noise arra y while we are | 36 // If the noise value would bring us out of bounds of the current noise arra y while we are |
(...skipping 15 matching lines...) Expand all Loading... | |
52 return SkScalarMul(SkScalarSquare(t), SK_Scalar3 - 2 * t); | 52 return SkScalarMul(SkScalarSquare(t), SK_Scalar3 - 2 * t); |
53 } | 53 } |
54 | 54 |
55 bool perlin_noise_type_is_valid(SkPerlinNoiseShader::Type type) { | 55 bool perlin_noise_type_is_valid(SkPerlinNoiseShader::Type type) { |
56 return (SkPerlinNoiseShader::kFractalNoise_Type == type) || | 56 return (SkPerlinNoiseShader::kFractalNoise_Type == type) || |
57 (SkPerlinNoiseShader::kTurbulence_Type == type); | 57 (SkPerlinNoiseShader::kTurbulence_Type == type); |
58 } | 58 } |
59 | 59 |
60 } // end namespace | 60 } // end namespace |
61 | 61 |
62 struct SkPerlinNoiseShader::StitchData { | 62 inline int random(int* seed) { |
63 StitchData() | 63 static const int gRandAmplitude = 16807; // 7**5; primitive root of m |
64 : fWidth(0) | 64 static const int gRandQ = 127773; // m / a |
65 , fWrapX(0) | 65 static const int gRandR = 2836; // m % a |
66 , fHeight(0) | |
67 , fWrapY(0) | |
68 {} | |
69 | 66 |
70 bool operator==(const StitchData& other) const { | 67 int result = gRandAmplitude * (*seed % gRandQ) - gRandR * (*seed / gRandQ); |
71 return fWidth == other.fWidth && | 68 if (result <= 0) { |
72 fWrapX == other.fWrapX && | 69 result += kRandMaximum; |
73 fHeight == other.fHeight && | 70 } |
74 fWrapY == other.fWrapY; | 71 *seed = result; |
72 return result; | |
73 } | |
74 | |
75 // Only called once. Could be part of the constructor. | |
76 void SkPerlinNoiseShader::init() | |
77 { | |
78 static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSi ze)); | |
79 | |
80 // The seed value clamp to the range [1, kRandMaximum - 1]. | |
81 if (fSeed <= 0) { | |
82 fSeed = -(fSeed % (kRandMaximum - 1)) + 1; | |
83 } | |
84 if (fSeed > kRandMaximum - 1) { | |
85 fSeed = kRandMaximum - 1; | |
86 } | |
87 for (int channel = 0; channel < 4; ++channel) { | |
88 for (int i = 0; i < kBlockSize; ++i) { | |
89 fLatticeSelector[i] = i; | |
90 fNoise[channel][i][0] = (random(&fSeed) % (2 * kBlockSize)); | |
91 fNoise[channel][i][1] = (random(&fSeed) % (2 * kBlockSize)); | |
92 } | |
93 } | |
94 for (int i = kBlockSize - 1; i > 0; --i) { | |
95 int k = fLatticeSelector[i]; | |
96 int j = random(&fSeed) % kBlockSize; | |
97 SkASSERT(j >= 0); | |
98 SkASSERT(j < kBlockSize); | |
99 fLatticeSelector[i] = fLatticeSelector[j]; | |
100 fLatticeSelector[j] = k; | |
75 } | 101 } |
76 | 102 |
77 int fWidth; // How much to subtract to wrap for stitching. | 103 // Perform the permutations now |
78 int fWrapX; // Minimum value to wrap. | |
79 int fHeight; | |
80 int fWrapY; | |
81 }; | |
82 | |
83 struct SkPerlinNoiseShader::PaintingData { | |
84 PaintingData(const SkISize& tileSize) | |
85 : fSeed(0) | |
86 , fTileSize(tileSize) | |
87 , fPermutationsBitmap(NULL) | |
88 , fNoiseBitmap(NULL) | |
89 {} | |
90 | |
91 ~PaintingData() | |
92 { | 104 { |
93 SkDELETE(fPermutationsBitmap); | 105 // Copy noise data |
94 SkDELETE(fNoiseBitmap); | 106 uint16_t noise[4][kBlockSize][2]; |
95 } | 107 for (int i = 0; i < kBlockSize; ++i) { |
96 | 108 for (int channel = 0; channel < 4; ++channel) { |
97 int fSeed; | 109 for (int j = 0; j < 2; ++j) { |
98 uint8_t fLatticeSelector[kBlockSize]; | 110 noise[channel][i][j] = fNoise[channel][i][j]; |
99 uint16_t fNoise[4][kBlockSize][2]; | |
100 SkPoint fGradient[4][kBlockSize]; | |
101 SkISize fTileSize; | |
102 SkVector fBaseFrequency; | |
103 StitchData fStitchDataInit; | |
104 | |
105 private: | |
106 | |
107 SkBitmap* fPermutationsBitmap; | |
108 SkBitmap* fNoiseBitmap; | |
109 | |
110 public: | |
111 | |
112 inline int random() { | |
113 static const int gRandAmplitude = 16807; // 7**5; primitive root of m | |
114 static const int gRandQ = 127773; // m / a | |
115 static const int gRandR = 2836; // m % a | |
116 | |
117 int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRand Q); | |
118 if (result <= 0) | |
119 result += kRandMaximum; | |
120 fSeed = result; | |
121 return result; | |
122 } | |
123 | |
124 void init(SkScalar seed) | |
125 { | |
126 static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlo ckSize)); | |
127 | |
128 // According to the SVG spec, we must truncate (not round) the seed valu e. | |
129 fSeed = SkScalarTruncToInt(seed); | |
130 // The seed value clamp to the range [1, kRandMaximum - 1]. | |
131 if (fSeed <= 0) { | |
132 fSeed = -(fSeed % (kRandMaximum - 1)) + 1; | |
133 } | |
134 if (fSeed > kRandMaximum - 1) { | |
135 fSeed = kRandMaximum - 1; | |
136 } | |
137 for (int channel = 0; channel < 4; ++channel) { | |
138 for (int i = 0; i < kBlockSize; ++i) { | |
139 fLatticeSelector[i] = i; | |
140 fNoise[channel][i][0] = (random() % (2 * kBlockSize)); | |
141 fNoise[channel][i][1] = (random() % (2 * kBlockSize)); | |
142 } | |
143 } | |
144 for (int i = kBlockSize - 1; i > 0; --i) { | |
145 int k = fLatticeSelector[i]; | |
146 int j = random() % kBlockSize; | |
147 SkASSERT(j >= 0); | |
148 SkASSERT(j < kBlockSize); | |
149 fLatticeSelector[i] = fLatticeSelector[j]; | |
150 fLatticeSelector[j] = k; | |
151 } | |
152 | |
153 // Perform the permutations now | |
154 { | |
155 // Copy noise data | |
156 uint16_t noise[4][kBlockSize][2]; | |
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 noise[channel][i][j] = fNoise[channel][i][j]; | |
161 } | |
162 } | |
163 } | |
164 // Do permutations on noise data | |
165 for (int i = 0; i < kBlockSize; ++i) { | |
166 for (int channel = 0; channel < 4; ++channel) { | |
167 for (int j = 0; j < 2; ++j) { | |
168 fNoise[channel][i][j] = noise[channel][fLatticeSelector[ i]][j]; | |
169 } | |
170 } | 111 } |
171 } | 112 } |
172 } | 113 } |
114 // Do permutations on noise data | |
115 for (int i = 0; i < kBlockSize; ++i) { | |
116 for (int channel = 0; channel < 4; ++channel) { | |
117 for (int j = 0; j < 2; ++j) { | |
118 fNoise[channel][i][j] = noise[channel][fLatticeSelector[ i]][j]; | |
119 } | |
120 } | |
121 } | |
122 } | |
173 | 123 |
174 // Half of the largest possible value for 16 bit unsigned int | 124 // Half of the largest possible value for 16 bit unsigned int |
175 static const SkScalar gHalfMax16bits = 32767.5f; | 125 static const SkScalar gHalfMax16bits = 32767.5f; |
176 | 126 |
177 // Compute gradients from permutated noise data | 127 // Compute gradients from permutated noise data |
178 for (int channel = 0; channel < 4; ++channel) { | 128 for (int channel = 0; channel < 4; ++channel) { |
179 for (int i = 0; i < kBlockSize; ++i) { | 129 for (int i = 0; i < kBlockSize; ++i) { |
180 fGradient[channel][i] = SkPoint::Make( | 130 fGradient[channel][i] = SkPoint::Make( |
181 SkScalarMul(SkIntToScalar(fNoise[channel][i][0] - kBlockSize ), | 131 SkScalarMul(SkIntToScalar(fNoise[channel][i][0] - kBlockSize ), |
182 gInvBlockSizef), | 132 gInvBlockSizef), |
183 SkScalarMul(SkIntToScalar(fNoise[channel][i][1] - kBlockSize ), | 133 SkScalarMul(SkIntToScalar(fNoise[channel][i][1] - kBlockSize ), |
184 gInvBlockSizef)); | 134 gInvBlockSizef)); |
185 fGradient[channel][i].normalize(); | 135 fGradient[channel][i].normalize(); |
186 // Put the normalized gradient back into the noise data | 136 // Put the normalized gradient back into the noise data |
187 fNoise[channel][i][0] = SkScalarRoundToInt(SkScalarMul( | 137 fNoise[channel][i][0] = SkScalarRoundToInt(SkScalarMul( |
188 fGradient[channel][i].fX + SK_Scalar1, gHalfMax16bits)); | 138 fGradient[channel][i].fX + SK_Scalar1, gHalfMax16bits)); |
189 fNoise[channel][i][1] = SkScalarRoundToInt(SkScalarMul( | 139 fNoise[channel][i][1] = SkScalarRoundToInt(SkScalarMul( |
190 fGradient[channel][i].fY + SK_Scalar1, gHalfMax16bits)); | 140 fGradient[channel][i].fY + SK_Scalar1, gHalfMax16bits)); |
191 } | |
192 } | 141 } |
193 | |
194 // Invalidate bitmaps | |
195 SkDELETE(fPermutationsBitmap); | |
196 fPermutationsBitmap = NULL; | |
197 SkDELETE(fNoiseBitmap); | |
198 fNoiseBitmap = NULL; | |
199 } | 142 } |
200 | 143 |
201 void stitch() { | 144 if (fTileSize.isEmpty()) { |
scroggo
2014/03/04 22:26:34
stitch() is now part of init.
| |
202 SkScalar tileWidth = SkIntToScalar(fTileSize.width()); | 145 return; |
203 SkScalar tileHeight = SkIntToScalar(fTileSize.height()); | |
204 SkASSERT(tileWidth > 0 && tileHeight > 0); | |
205 // When stitching tiled turbulence, the frequencies must be adjusted | |
206 // so that the tile borders will be continuous. | |
207 if (fBaseFrequency.fX) { | |
208 SkScalar lowFrequencx = | |
209 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth ; | |
210 SkScalar highFrequencx = | |
211 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth; | |
212 // BaseFrequency should be non-negative according to the standard. | |
213 if (SkScalarDiv(fBaseFrequency.fX, lowFrequencx) < | |
214 SkScalarDiv(highFrequencx, fBaseFrequency.fX)) { | |
215 fBaseFrequency.fX = lowFrequencx; | |
216 } else { | |
217 fBaseFrequency.fX = highFrequencx; | |
218 } | |
219 } | |
220 if (fBaseFrequency.fY) { | |
221 SkScalar lowFrequency = | |
222 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeig ht; | |
223 SkScalar highFrequency = | |
224 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeigh t; | |
225 if (SkScalarDiv(fBaseFrequency.fY, lowFrequency) < | |
226 SkScalarDiv(highFrequency, fBaseFrequency.fY)) { | |
227 fBaseFrequency.fY = lowFrequency; | |
228 } else { | |
229 fBaseFrequency.fY = highFrequency; | |
230 } | |
231 } | |
232 // Set up TurbulenceInitial stitch values. | |
233 fStitchDataInit.fWidth = | |
234 SkScalarRoundToInt(tileWidth * fBaseFrequency.fX); | |
235 fStitchDataInit.fWrapX = kPerlinNoise + fStitchDataInit.fWidth; | |
236 fStitchDataInit.fHeight = | |
237 SkScalarRoundToInt(tileHeight * fBaseFrequency.fY); | |
238 fStitchDataInit.fWrapY = kPerlinNoise + fStitchDataInit.fHeight; | |
239 } | 146 } |
240 | 147 |
241 SkBitmap* getPermutationsBitmap() | 148 SkScalar tileWidth = SkIntToScalar(fTileSize.width()); |
242 { | 149 SkScalar tileHeight = SkIntToScalar(fTileSize.height()); |
243 if (!fPermutationsBitmap) { | 150 SkASSERT(tileWidth > 0 && tileHeight > 0); |
244 fPermutationsBitmap = SkNEW(SkBitmap); | 151 // When stitching tiled turbulence, the frequencies must be adjusted |
245 fPermutationsBitmap->allocPixels(SkImageInfo::MakeA8(kBlockSize, 1)) ; | 152 // so that the tile borders will be continuous. |
246 uint8_t* bitmapPixels = fPermutationsBitmap->getAddr8(0, 0); | 153 if (fBaseFrequency.fX) { |
247 memcpy(bitmapPixels, fLatticeSelector, sizeof(uint8_t) * kBlockSize) ; | 154 SkScalar lowFrequencx = |
155 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth ; | |
156 SkScalar highFrequencx = | |
157 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth; | |
158 // BaseFrequency should be non-negative according to the standard. | |
159 if (SkScalarDiv(fBaseFrequency.fX, lowFrequencx) < | |
160 SkScalarDiv(highFrequencx, fBaseFrequency.fX)) { | |
161 fBaseFrequency.fX = lowFrequencx; | |
162 } else { | |
163 fBaseFrequency.fX = highFrequencx; | |
248 } | 164 } |
249 return fPermutationsBitmap; | |
250 } | 165 } |
166 if (fBaseFrequency.fY) { | |
167 SkScalar lowFrequency = | |
168 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeig ht; | |
169 SkScalar highFrequency = | |
170 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeigh t; | |
171 if (SkScalarDiv(fBaseFrequency.fY, lowFrequency) < | |
172 SkScalarDiv(highFrequency, fBaseFrequency.fY)) { | |
173 fBaseFrequency.fY = lowFrequency; | |
174 } else { | |
175 fBaseFrequency.fY = highFrequency; | |
176 } | |
177 } | |
178 // Set up TurbulenceInitial stitch values. | |
179 fStitchDataInit.fWidth = | |
180 SkScalarRoundToInt(tileWidth * fBaseFrequency.fX); | |
181 fStitchDataInit.fWrapX = kPerlinNoise + fStitchDataInit.fWidth; | |
182 fStitchDataInit.fHeight = | |
183 SkScalarRoundToInt(tileHeight * fBaseFrequency.fY); | |
184 fStitchDataInit.fWrapY = kPerlinNoise + fStitchDataInit.fHeight; | |
185 } | |
251 | 186 |
252 SkBitmap* getNoiseBitmap() | 187 const SkBitmap& SkPerlinNoiseShader::getPermutationsBitmap() const { |
253 { | 188 if (kUnknown_SkColorType == fPermutationsBitmap.colorType()) { |
254 if (!fNoiseBitmap) { | 189 // initialize the cache. |
255 fNoiseBitmap = SkNEW(SkBitmap); | 190 fPermutationsBitmap.allocPixels(SkImageInfo::MakeA8(kBlockSize, 1)); |
256 fNoiseBitmap->allocPixels(SkImageInfo::MakeN32Premul(kBlockSize, 4)) ; | 191 uint8_t* bitmapPixels = fPermutationsBitmap.getAddr8(0, 0); |
257 uint32_t* bitmapPixels = fNoiseBitmap->getAddr32(0, 0); | 192 memcpy(bitmapPixels, fLatticeSelector, sizeof(uint8_t) * kBlockSize); |
258 memcpy(bitmapPixels, fNoise[0][0], sizeof(uint16_t) * kBlockSize * 4 * 2); | |
259 } | |
260 return fNoiseBitmap; | |
261 } | 193 } |
262 }; | 194 return fPermutationsBitmap; |
195 } | |
196 | |
197 const SkBitmap& SkPerlinNoiseShader::getNoiseBitmap() const { | |
198 if (kUnknown_SkColorType == fNoiseBitmap.colorType()) { | |
199 // initialize the cache. | |
200 fNoiseBitmap.allocPixels(SkImageInfo::MakeN32Premul(kBlockSize, 4)); | |
201 uint32_t* bitmapPixels = fNoiseBitmap.getAddr32(0, 0); | |
202 memcpy(bitmapPixels, fNoise[0][0], sizeof(uint16_t) * kBlockSize * 4 * 2 ); | |
203 } | |
204 return fNoiseBitmap; | |
205 } | |
263 | 206 |
264 SkShader* SkPerlinNoiseShader::CreateFractalNoise(SkScalar baseFrequencyX, SkSca lar baseFrequencyY, | 207 SkShader* SkPerlinNoiseShader::CreateFractalNoise(SkScalar baseFrequencyX, SkSca lar baseFrequencyY, |
265 int numOctaves, SkScalar seed, | 208 int numOctaves, SkScalar seed, |
266 const SkISize* tileSize) { | 209 const SkISize* tileSize) { |
267 return SkNEW_ARGS(SkPerlinNoiseShader, (kFractalNoise_Type, baseFrequencyX, baseFrequencyY, | 210 return SkNEW_ARGS(SkPerlinNoiseShader, (kFractalNoise_Type, baseFrequencyX, baseFrequencyY, |
268 numOctaves, seed, tileSize)); | 211 numOctaves, seed, tileSize)); |
269 } | 212 } |
270 | 213 |
271 SkShader* SkPerlinNoiseShader::CreateTubulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, | 214 SkShader* SkPerlinNoiseShader::CreateTubulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, |
272 int numOctaves, SkScalar seed, | 215 int numOctaves, SkScalar seed, |
273 const SkISize* tileSize) { | 216 const SkISize* tileSize) { |
274 return SkNEW_ARGS(SkPerlinNoiseShader, (kTurbulence_Type, baseFrequencyX, ba seFrequencyY, | 217 return SkNEW_ARGS(SkPerlinNoiseShader, (kTurbulence_Type, baseFrequencyX, ba seFrequencyY, |
275 numOctaves, seed, tileSize)); | 218 numOctaves, seed, tileSize)); |
276 } | 219 } |
277 | 220 |
278 SkPerlinNoiseShader::SkPerlinNoiseShader(SkPerlinNoiseShader::Type type, | 221 SkPerlinNoiseShader::SkPerlinNoiseShader(SkPerlinNoiseShader::Type type, |
279 SkScalar baseFrequencyX, | 222 SkScalar baseFrequencyX, |
280 SkScalar baseFrequencyY, | 223 SkScalar baseFrequencyY, |
281 int numOctaves, | 224 int numOctaves, |
282 SkScalar seed, | 225 SkScalar seed, |
283 const SkISize* tileSize) | 226 const SkISize* tileSize) |
284 : fType(type) | 227 : fType(type) |
285 , fBaseFrequencyX(baseFrequencyX) | 228 , fBaseFrequency(SkPoint::Make(baseFrequencyX, baseFrequencyY)) |
286 , fBaseFrequencyY(baseFrequencyY) | |
287 , fNumOctaves(numOctaves > 255 ? 255 : numOctaves/*[0,255] octaves allowed*/) | 229 , fNumOctaves(numOctaves > 255 ? 255 : numOctaves/*[0,255] octaves allowed*/) |
288 , fSeed(seed) | 230 // According to the SVG spec, we must truncate (not round) the seed value. |
289 , fStitchTiles((tileSize != NULL) && !tileSize->isEmpty()) | 231 , fSeed(SkScalarTruncToInt(seed)) |
290 , fPaintingData(NULL) | 232 , fTileSize(NULL == tileSize ? SkISize::Make(0, 0) : *tileSize) |
233 , fStitchTiles(!fTileSize.isEmpty()) | |
291 { | 234 { |
292 SkASSERT(numOctaves >= 0 && numOctaves < 256); | 235 SkASSERT(numOctaves >= 0 && numOctaves < 256); |
293 setTileSize(fStitchTiles ? *tileSize : SkISize::Make(0,0)); | |
294 fMatrix.reset(); | 236 fMatrix.reset(); |
237 this->init(); | |
295 } | 238 } |
296 | 239 |
297 SkPerlinNoiseShader::SkPerlinNoiseShader(SkReadBuffer& buffer) : | 240 SkPerlinNoiseShader::SkPerlinNoiseShader(SkReadBuffer& buffer) |
298 INHERITED(buffer), fPaintingData(NULL) { | 241 : INHERITED(buffer) |
242 { | |
299 fType = (SkPerlinNoiseShader::Type) buffer.readInt(); | 243 fType = (SkPerlinNoiseShader::Type) buffer.readInt(); |
300 fBaseFrequencyX = buffer.readScalar(); | 244 buffer.readPoint(&fBaseFrequency); |
301 fBaseFrequencyY = buffer.readScalar(); | |
302 fNumOctaves = buffer.readInt(); | 245 fNumOctaves = buffer.readInt(); |
303 fSeed = buffer.readScalar(); | 246 fSeed = buffer.readInt(); |
Stephen White
2014/03/05 14:32:58
Hmmm. Isn't this going to require an SkPicture ver
sugoi
2014/03/05 16:50:33
Hmmm... In this const shader world, is there no wa
scroggo
2014/03/05 18:24:05
What do you mean by "later on during processing?"
scroggo
2014/03/05 18:24:05
Yes, this would require a picture version bump. In
| |
304 fStitchTiles = buffer.readBool(); | 247 fStitchTiles = buffer.readBool(); |
305 fTileSize.fWidth = buffer.readInt(); | 248 fTileSize.fWidth = buffer.readInt(); |
306 fTileSize.fHeight = buffer.readInt(); | 249 fTileSize.fHeight = buffer.readInt(); |
307 setTileSize(fTileSize); | |
308 fMatrix.reset(); | 250 fMatrix.reset(); |
251 this->init(); | |
309 buffer.validate(perlin_noise_type_is_valid(fType) && | 252 buffer.validate(perlin_noise_type_is_valid(fType) && |
310 (fNumOctaves >= 0) && (fNumOctaves <= 255)); | 253 (fNumOctaves >= 0) && (fNumOctaves <= 255) && |
311 } | 254 (fStitchTiles != fTileSize.isEmpty())); |
312 | |
313 SkPerlinNoiseShader::~SkPerlinNoiseShader() { | |
314 // Safety, should have been done in endContext() | |
315 SkDELETE(fPaintingData); | |
316 } | 255 } |
317 | 256 |
318 void SkPerlinNoiseShader::flatten(SkWriteBuffer& buffer) const { | 257 void SkPerlinNoiseShader::flatten(SkWriteBuffer& buffer) const { |
319 this->INHERITED::flatten(buffer); | 258 this->INHERITED::flatten(buffer); |
320 buffer.writeInt((int) fType); | 259 buffer.writeInt((int) fType); |
321 buffer.writeScalar(fBaseFrequencyX); | 260 buffer.writePoint(fBaseFrequency); |
322 buffer.writeScalar(fBaseFrequencyY); | |
323 buffer.writeInt(fNumOctaves); | 261 buffer.writeInt(fNumOctaves); |
324 buffer.writeScalar(fSeed); | 262 buffer.writeInt(fSeed); |
325 buffer.writeBool(fStitchTiles); | 263 buffer.writeBool(fStitchTiles); |
326 buffer.writeInt(fTileSize.fWidth); | 264 buffer.writeInt(fTileSize.fWidth); |
327 buffer.writeInt(fTileSize.fHeight); | 265 buffer.writeInt(fTileSize.fHeight); |
328 } | 266 } |
329 | 267 |
330 void SkPerlinNoiseShader::initPaint(PaintingData& paintingData) | 268 SkScalar SkPerlinNoiseShader::noise2D(int channel, const StitchData& stitchData, |
331 { | 269 const SkPoint& noiseVector) const { |
332 paintingData.init(fSeed); | |
333 | |
334 // Set frequencies to original values | |
335 paintingData.fBaseFrequency.set(fBaseFrequencyX, fBaseFrequencyY); | |
336 // Adjust frequecies based on size if stitching is enabled | |
337 if (fStitchTiles) { | |
338 paintingData.stitch(); | |
339 } | |
340 } | |
341 | |
342 void SkPerlinNoiseShader::setTileSize(const SkISize& tileSize) { | |
343 fTileSize = tileSize; | |
344 | |
345 if (NULL == fPaintingData) { | |
346 fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize)); | |
347 initPaint(*fPaintingData); | |
348 } else { | |
349 // Set Size | |
350 fPaintingData->fTileSize = fTileSize; | |
351 // Set frequencies to original values | |
352 fPaintingData->fBaseFrequency.set(fBaseFrequencyX, fBaseFrequencyY); | |
353 // Adjust frequecies based on size if stitching is enabled | |
354 if (fStitchTiles) { | |
355 fPaintingData->stitch(); | |
356 } | |
357 } | |
358 } | |
359 | |
360 SkScalar SkPerlinNoiseShader::noise2D(int channel, const PaintingData& paintingD ata, | |
361 const StitchData& stitchData, const SkPoint & noiseVector) | |
362 { | |
363 struct Noise { | 270 struct Noise { |
364 int noisePositionIntegerValue; | 271 int noisePositionIntegerValue; |
365 SkScalar noisePositionFractionValue; | 272 SkScalar noisePositionFractionValue; |
366 Noise(SkScalar component) | 273 Noise(SkScalar component) |
367 { | 274 { |
368 SkScalar position = component + kPerlinNoise; | 275 SkScalar position = component + kPerlinNoise; |
369 noisePositionIntegerValue = SkScalarFloorToInt(position); | 276 noisePositionIntegerValue = SkScalarFloorToInt(position); |
370 noisePositionFractionValue = position - SkIntToScalar(noisePositionI ntegerValue); | 277 noisePositionFractionValue = position - SkIntToScalar(noisePositionI ntegerValue); |
371 } | 278 } |
372 }; | 279 }; |
373 Noise noiseX(noiseVector.x()); | 280 Noise noiseX(noiseVector.x()); |
374 Noise noiseY(noiseVector.y()); | 281 Noise noiseY(noiseVector.y()); |
375 SkScalar u, v; | 282 SkScalar u, v; |
376 // If stitching, adjust lattice points accordingly. | 283 // If stitching, adjust lattice points accordingly. |
377 if (fStitchTiles) { | 284 if (fStitchTiles) { |
378 noiseX.noisePositionIntegerValue = | 285 noiseX.noisePositionIntegerValue = |
379 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stit chData.fWidth); | 286 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stit chData.fWidth); |
380 noiseY.noisePositionIntegerValue = | 287 noiseY.noisePositionIntegerValue = |
381 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stit chData.fHeight); | 288 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stit chData.fHeight); |
382 } | 289 } |
383 noiseX.noisePositionIntegerValue &= kBlockMask; | 290 noiseX.noisePositionIntegerValue &= kBlockMask; |
384 noiseY.noisePositionIntegerValue &= kBlockMask; | 291 noiseY.noisePositionIntegerValue &= kBlockMask; |
385 int latticeIndex = | 292 int latticeIndex = fLatticeSelector[noiseX.noisePositionIntegerValue] + |
386 paintingData.fLatticeSelector[noiseX.noisePositionIntegerValue] + | 293 noiseY.noisePositionIntegerValue; |
387 noiseY.noisePositionIntegerValue; | 294 int nextLatticeIndex = fLatticeSelector[(noiseX.noisePositionIntegerValue + 1) & kBlockMask] + |
388 int nextLatticeIndex = | 295 noiseY.noisePositionIntegerValue; |
389 paintingData.fLatticeSelector[(noiseX.noisePositionIntegerValue + 1) & k BlockMask] + | |
390 noiseY.noisePositionIntegerValue; | |
391 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue); | 296 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue); |
392 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue); | 297 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue); |
393 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html# feTurbulenceElement | 298 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html# feTurbulenceElement |
394 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue, | 299 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue, |
395 noiseY.noisePositionFractionValue); // Offset (0,0) | 300 noiseY.noisePositionFractionValue); // Offset (0,0) |
396 u = paintingData.fGradient[channel][latticeIndex & kBlockMask].dot(fractionV alue); | 301 u = fGradient[channel][latticeIndex & kBlockMask].dot(fractionValue); |
397 fractionValue.fX -= SK_Scalar1; // Offset (-1,0) | 302 fractionValue.fX -= SK_Scalar1; // Offset (-1,0) |
398 v = paintingData.fGradient[channel][nextLatticeIndex & kBlockMask].dot(fract ionValue); | 303 v = fGradient[channel][nextLatticeIndex & kBlockMask].dot(fractionValue); |
399 SkScalar a = SkScalarInterp(u, v, sx); | 304 SkScalar a = SkScalarInterp(u, v, sx); |
400 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1) | 305 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1) |
401 v = paintingData.fGradient[channel][(nextLatticeIndex + 1) & kBlockMask].dot (fractionValue); | 306 v = fGradient[channel][(nextLatticeIndex + 1) & kBlockMask].dot(fractionValu e); |
402 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1) | 307 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1) |
403 u = paintingData.fGradient[channel][(latticeIndex + 1) & kBlockMask].dot(fra ctionValue); | 308 u = fGradient[channel][(latticeIndex + 1) & kBlockMask].dot(fractionValue); |
404 SkScalar b = SkScalarInterp(u, v, sx); | 309 SkScalar b = SkScalarInterp(u, v, sx); |
405 return SkScalarInterp(a, b, sy); | 310 return SkScalarInterp(a, b, sy); |
406 } | 311 } |
407 | 312 |
408 SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint( | 313 SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint(int channel, Stit chData& stitchData, |
409 int channel, const PaintingData& paintingData, StitchData& stitchData, const SkPoint& point) | 314 const SkPoint& po int) const { |
410 { | |
411 if (fStitchTiles) { | 315 if (fStitchTiles) { |
412 // Set up TurbulenceInitial stitch values. | 316 // Set up TurbulenceInitial stitch values. |
413 stitchData = paintingData.fStitchDataInit; | 317 stitchData = fStitchDataInit; |
414 } | 318 } |
415 SkScalar turbulenceFunctionResult = 0; | 319 SkScalar turbulenceFunctionResult = 0; |
416 SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), paintingData.fBaseF requency.fX), | 320 SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), fBaseFrequency.fX), |
417 SkScalarMul(point.y(), paintingData.fBaseF requency.fY))); | 321 SkScalarMul(point.y(), fBaseFrequency.fY)) ); |
418 SkScalar ratio = SK_Scalar1; | 322 SkScalar ratio = SK_Scalar1; |
419 for (int octave = 0; octave < fNumOctaves; ++octave) { | 323 for (int octave = 0; octave < fNumOctaves; ++octave) { |
420 SkScalar noise = noise2D(channel, paintingData, stitchData, noiseVector) ; | 324 SkScalar noise = noise2D(channel, stitchData, noiseVector); |
421 turbulenceFunctionResult += SkScalarDiv( | 325 turbulenceFunctionResult += SkScalarDiv( |
422 (fType == kFractalNoise_Type) ? noise : SkScalarAbs(noise), ratio); | 326 (fType == kFractalNoise_Type) ? noise : SkScalarAbs(noise), ratio); |
423 noiseVector.fX *= 2; | 327 noiseVector.fX *= 2; |
424 noiseVector.fY *= 2; | 328 noiseVector.fY *= 2; |
425 ratio *= 2; | 329 ratio *= 2; |
426 if (fStitchTiles) { | 330 if (fStitchTiles) { |
427 // Update stitch values | 331 // Update stitch values |
428 stitchData.fWidth *= 2; | 332 stitchData.fWidth *= 2; |
429 stitchData.fWrapX = stitchData.fWidth + kPerlinNoise; | 333 stitchData.fWrapX = stitchData.fWidth + kPerlinNoise; |
430 stitchData.fHeight *= 2; | 334 stitchData.fHeight *= 2; |
(...skipping 10 matching lines...) Expand all Loading... | |
441 | 345 |
442 if (channel == 3) { // Scale alpha by paint value | 346 if (channel == 3) { // Scale alpha by paint value |
443 turbulenceFunctionResult = SkScalarMul(turbulenceFunctionResult, | 347 turbulenceFunctionResult = SkScalarMul(turbulenceFunctionResult, |
444 SkScalarDiv(SkIntToScalar(getPaintAlpha()), SkIntToScalar(255))); | 348 SkScalarDiv(SkIntToScalar(getPaintAlpha()), SkIntToScalar(255))); |
445 } | 349 } |
446 | 350 |
447 // Clamp result | 351 // Clamp result |
448 return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1); | 352 return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1); |
449 } | 353 } |
450 | 354 |
451 SkPMColor SkPerlinNoiseShader::shade(const SkPoint& point, StitchData& stitchDat a) { | 355 SkPMColor SkPerlinNoiseShader::shade(const SkPoint& point, StitchData& stitchDat a) const { |
452 SkMatrix matrix = fMatrix; | 356 SkMatrix matrix = fMatrix; |
453 matrix.postConcat(getLocalMatrix()); | 357 matrix.postConcat(getLocalMatrix()); |
454 SkMatrix invMatrix; | 358 SkMatrix invMatrix; |
455 if (!matrix.invert(&invMatrix)) { | 359 if (!matrix.invert(&invMatrix)) { |
456 invMatrix.reset(); | 360 invMatrix.reset(); |
457 } else { | 361 } else { |
458 invMatrix.postConcat(invMatrix); // Square the matrix | 362 invMatrix.postConcat(invMatrix); // Square the matrix |
459 } | 363 } |
460 // This (1,1) translation is due to WebKit's 1 based coordinates for the noi se | 364 // This (1,1) translation is due to WebKit's 1 based coordinates for the noi se |
461 // (as opposed to 0 based, usually). The same adjustment is in the setData() function. | 365 // (as opposed to 0 based, usually). The same adjustment is in the setData() function. |
462 matrix.postTranslate(SK_Scalar1, SK_Scalar1); | 366 matrix.postTranslate(SK_Scalar1, SK_Scalar1); |
463 SkPoint newPoint; | 367 SkPoint newPoint; |
464 matrix.mapPoints(&newPoint, &point, 1); | 368 matrix.mapPoints(&newPoint, &point, 1); |
465 invMatrix.mapPoints(&newPoint, &newPoint, 1); | 369 invMatrix.mapPoints(&newPoint, &newPoint, 1); |
466 newPoint.fX = SkScalarRoundToScalar(newPoint.fX); | 370 newPoint.fX = SkScalarRoundToScalar(newPoint.fX); |
467 newPoint.fY = SkScalarRoundToScalar(newPoint.fY); | 371 newPoint.fY = SkScalarRoundToScalar(newPoint.fY); |
468 | 372 |
469 U8CPU rgba[4]; | 373 U8CPU rgba[4]; |
470 for (int channel = 3; channel >= 0; --channel) { | 374 for (int channel = 3; channel >= 0; --channel) { |
471 rgba[channel] = SkScalarFloorToInt(255 * | 375 rgba[channel] = SkScalarFloorToInt(255 * |
472 calculateTurbulenceValueForPoint(channel, *fPaintingData, stitchData , newPoint)); | 376 calculateTurbulenceValueForPoint(channel, stitchData, newPoint)); |
473 } | 377 } |
474 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]); | 378 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]); |
475 } | 379 } |
476 | 380 |
477 bool SkPerlinNoiseShader::setContext(const SkBitmap& device, const SkPaint& pain t, | 381 bool SkPerlinNoiseShader::setContext(const SkBitmap& device, const SkPaint& pain t, |
478 const SkMatrix& matrix) { | 382 const SkMatrix& matrix) { |
479 fMatrix = matrix; | 383 fMatrix = matrix; |
480 return INHERITED::setContext(device, paint, matrix); | 384 return INHERITED::setContext(device, paint, matrix); |
481 } | 385 } |
482 | 386 |
(...skipping 831 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1314 return cf->asNewEffect(context); | 1218 return cf->asNewEffect(context); |
1315 } | 1219 } |
1316 | 1220 |
1317 // Either we don't stitch tiles, either we have a valid tile size | 1221 // Either we don't stitch tiles, either we have a valid tile size |
1318 SkASSERT(!fStitchTiles || !fTileSize.isEmpty()); | 1222 SkASSERT(!fStitchTiles || !fTileSize.isEmpty()); |
1319 | 1223 |
1320 #ifdef SK_USE_SIMPLEX_NOISE | 1224 #ifdef SK_USE_SIMPLEX_NOISE |
1321 // Simplex noise is currently disabled but can be enabled by defining SK_USE _SIMPLEX_NOISE | 1225 // Simplex noise is currently disabled but can be enabled by defining SK_USE _SIMPLEX_NOISE |
1322 sk_ignore_unused_variable(context); | 1226 sk_ignore_unused_variable(context); |
1323 GrEffectRef* effect = | 1227 GrEffectRef* effect = |
1324 GrSimplexNoiseEffect::Create(fType, fPaintingData->fBaseFrequency, | 1228 GrSimplexNoiseEffect::Create(fType, fBaseFrequency, |
1325 fNumOctaves, fStitchTiles, fSeed, | 1229 fNumOctaves, fStitchTiles, fSeed, |
1326 this->getLocalMatrix(), paint.getAlpha()); | 1230 this->getLocalMatrix(), paint.getAlpha()); |
1327 #else | 1231 #else |
1328 GrTexture* permutationsTexture = GrLockAndRefCachedBitmapTexture( | 1232 GrTexture* permutationsTexture = GrLockAndRefCachedBitmapTexture( |
1329 context, *fPaintingData->getPermutationsBitmap(), NULL); | 1233 context, this->getPermutationsBitmap(), NULL); |
1330 GrTexture* noiseTexture = GrLockAndRefCachedBitmapTexture( | 1234 GrTexture* noiseTexture = GrLockAndRefCachedBitmapTexture( |
1331 context, *fPaintingData->getNoiseBitmap(), NULL); | 1235 context, this->getNoiseBitmap(), NULL); |
1332 | 1236 |
1333 GrEffectRef* effect = (NULL != permutationsTexture) && (NULL != noiseTexture ) ? | 1237 GrEffectRef* effect = (NULL != permutationsTexture) && (NULL != noiseTexture ) ? |
1334 GrPerlinNoiseEffect::Create(fType, fPaintingData->fBaseFrequency, | 1238 GrPerlinNoiseEffect::Create(fType, fBaseFrequency, |
1335 fNumOctaves, fStitchTiles, | 1239 fNumOctaves, fStitchTiles, |
1336 fPaintingData->fStitchDataInit, | 1240 fStitchDataInit, |
1337 permutationsTexture, noiseTexture, | 1241 permutationsTexture, noiseTexture, |
1338 this->getLocalMatrix(), paint.getAlpha()) : | 1242 this->getLocalMatrix(), paint.getAlpha()) : |
1339 NULL; | 1243 NULL; |
1340 | 1244 |
1341 // Unlock immediately, this is not great, but we don't have a way of | 1245 // Unlock immediately, this is not great, but we don't have a way of |
1342 // knowing when else to unlock it currently. TODO: Remove this when | 1246 // knowing when else to unlock it currently. TODO: Remove this when |
1343 // unref becomes the unlock replacement for all types of textures. | 1247 // unref becomes the unlock replacement for all types of textures. |
1344 if (NULL != permutationsTexture) { | 1248 if (NULL != permutationsTexture) { |
1345 GrUnlockAndUnrefCachedBitmapTexture(permutationsTexture); | 1249 GrUnlockAndUnrefCachedBitmapTexture(permutationsTexture); |
1346 } | 1250 } |
(...skipping 24 matching lines...) Expand all Loading... | |
1371 str->append("\"fractal noise\""); | 1275 str->append("\"fractal noise\""); |
1372 break; | 1276 break; |
1373 case kTurbulence_Type: | 1277 case kTurbulence_Type: |
1374 str->append("\"turbulence\""); | 1278 str->append("\"turbulence\""); |
1375 break; | 1279 break; |
1376 default: | 1280 default: |
1377 str->append("\"unknown\""); | 1281 str->append("\"unknown\""); |
1378 break; | 1282 break; |
1379 } | 1283 } |
1380 str->append(" base frequency: ("); | 1284 str->append(" base frequency: ("); |
1381 str->appendScalar(fBaseFrequencyX); | 1285 str->appendScalar(fBaseFrequency.fX); |
1382 str->append(", "); | 1286 str->append(", "); |
1383 str->appendScalar(fBaseFrequencyY); | 1287 str->appendScalar(fBaseFrequency.fY); |
1384 str->append(") number of octaves: "); | 1288 str->append(") number of octaves: "); |
1385 str->appendS32(fNumOctaves); | 1289 str->appendS32(fNumOctaves); |
1386 str->append(" seed: "); | 1290 str->append(" seed: "); |
1387 str->appendScalar(fSeed); | 1291 str->appendS32(fSeed); |
1388 str->append(" stitch tiles: "); | 1292 str->append(" stitch tiles: "); |
1389 str->append(fStitchTiles ? "true " : "false "); | 1293 str->append(fStitchTiles ? "true " : "false "); |
1390 | 1294 |
1391 this->INHERITED::toString(str); | 1295 this->INHERITED::toString(str); |
1392 | 1296 |
1393 str->append(")"); | 1297 str->append(")"); |
1394 } | 1298 } |
1395 #endif | 1299 #endif |
OLD | NEW |