1e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com/*
2e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com * Copyright 2013 Google Inc.
3e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com *
4e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com * Use of this source code is governed by a BSD-style license that can be
5e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com * found in the LICENSE file.
6e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com */
7e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
8e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#include "SkDither.h"
9e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#include "SkPerlinNoiseShader.h"
10c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org#include "SkColorFilter.h"
118b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
128b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
13e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#include "SkShader.h"
14e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#include "SkUnPreMultiply.h"
15e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#include "SkString.h"
16e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
17e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#if SK_SUPPORT_GPU
18e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#include "GrContext.h"
1977af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com#include "GrCoordTransform.h"
20b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "gl/GrGLProcessor.h"
2130ba436f04e61d4505fb854d5fc56079636e0788joshualitt#include "gl/builders/GrGLProgramBuilder.h"
22b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "GrTBackendProcessorFactory.h"
23e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#include "SkGr.h"
24e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#endif
25e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
26e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comstatic const int kBlockSize = 256;
27e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comstatic const int kBlockMask = kBlockSize - 1;
28e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comstatic const int kPerlinNoise = 4096;
29e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comstatic const int kRandMaximum = SK_MaxS32; // 2**31 - 1
30e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
31e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comnamespace {
32e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
33e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com// noiseValue is the color component's value (or color)
34e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com// limitValue is the maximum perlin noise array index value allowed
35e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com// newValue is the current noise dimension (either width or height)
36e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.cominline int checkNoise(int noiseValue, int limitValue, int newValue) {
37e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // If the noise value would bring us out of bounds of the current noise array while we are
38e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // stiching noise tiles together, wrap the noise around the current dimension of the noise to
39e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
40e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    if (noiseValue >= limitValue) {
41e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        noiseValue -= newValue;
42e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
43e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return noiseValue;
44e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
45e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
46e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.cominline SkScalar smoothCurve(SkScalar t) {
474b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    static const SkScalar SK_Scalar3 = 3.0f;
48e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
49e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // returns t * t * (3 - 2 * t)
50e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return SkScalarMul(SkScalarSquare(t), SK_Scalar3 - 2 * t);
51e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
52e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
53ce33d60187718e7bb01944ee130c9f5d9fb335eccommit-bot@chromium.orgbool perlin_noise_type_is_valid(SkPerlinNoiseShader::Type type) {
54ce33d60187718e7bb01944ee130c9f5d9fb335eccommit-bot@chromium.org    return (SkPerlinNoiseShader::kFractalNoise_Type == type) ||
55ce33d60187718e7bb01944ee130c9f5d9fb335eccommit-bot@chromium.org           (SkPerlinNoiseShader::kTurbulence_Type == type);
56ce33d60187718e7bb01944ee130c9f5d9fb335eccommit-bot@chromium.org}
57ce33d60187718e7bb01944ee130c9f5d9fb335eccommit-bot@chromium.org
58e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com} // end namespace
59e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
60e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comstruct SkPerlinNoiseShader::StitchData {
61e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    StitchData()
62e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com      : fWidth(0)
63e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com      , fWrapX(0)
64e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com      , fHeight(0)
65e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com      , fWrapY(0)
66e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {}
67e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
68e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    bool operator==(const StitchData& other) const {
69e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        return fWidth == other.fWidth &&
70e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com               fWrapX == other.fWrapX &&
71e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com               fHeight == other.fHeight &&
72e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com               fWrapY == other.fWrapY;
73e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
74e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
75e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    int fWidth; // How much to subtract to wrap for stitching.
76e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    int fWrapX; // Minimum value to wrap.
77e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    int fHeight;
78e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    int fWrapY;
79e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com};
80e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
81e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comstruct SkPerlinNoiseShader::PaintingData {
82fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    PaintingData(const SkISize& tileSize, SkScalar seed,
83ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco                 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
84ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco                 const SkMatrix& matrix)
85e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
86ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        SkVector wavelength = SkVector::Make(SkScalarInvert(baseFrequencyX),
87ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco                                             SkScalarInvert(baseFrequencyY));
88ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        matrix.mapVectors(&wavelength, 1);
89ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        fBaseFrequency.fX = SkScalarInvert(wavelength.fX);
90ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        fBaseFrequency.fY = SkScalarInvert(wavelength.fY);
91ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        SkVector sizeVec = SkVector::Make(SkIntToScalar(tileSize.fWidth),
92ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco                                          SkIntToScalar(tileSize.fHeight));
93ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        matrix.mapVectors(&sizeVec, 1);
94ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        fTileSize.fWidth = SkScalarRoundToInt(sizeVec.fX);
95ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        fTileSize.fHeight = SkScalarRoundToInt(sizeVec.fY);
96fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org        this->init(seed);
97fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org        if (!fTileSize.isEmpty()) {
98fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org            this->stitch();
99fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org        }
100fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org
101f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco#if SK_SUPPORT_GPU
102a3264e53ee3f3c5d6a2c813df7e44b5b96d207f2commit-bot@chromium.org        fPermutationsBitmap.setInfo(SkImageInfo::MakeA8(kBlockSize, 1));
103fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org        fPermutationsBitmap.setPixels(fLatticeSelector);
104fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org
105a3264e53ee3f3c5d6a2c813df7e44b5b96d207f2commit-bot@chromium.org        fNoiseBitmap.setInfo(SkImageInfo::MakeN32Premul(kBlockSize, 4));
106fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org        fNoiseBitmap.setPixels(fNoise[0][0]);
107fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org#endif
108e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
109e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
110e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    int         fSeed;
111e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    uint8_t     fLatticeSelector[kBlockSize];
112e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    uint16_t    fNoise[4][kBlockSize][2];
113e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkPoint     fGradient[4][kBlockSize];
114e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkISize     fTileSize;
115e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkVector    fBaseFrequency;
116e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    StitchData  fStitchDataInit;
117e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
118e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comprivate:
119e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
120f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco#if SK_SUPPORT_GPU
121fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    SkBitmap   fPermutationsBitmap;
122fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    SkBitmap   fNoiseBitmap;
123fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org#endif
124e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
125e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    inline int random()  {
126e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        static const int gRandAmplitude = 16807; // 7**5; primitive root of m
127e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        static const int gRandQ = 127773; // m / a
128e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        static const int gRandR = 2836; // m % a
129e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
130e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
131e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        if (result <= 0)
132e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            result += kRandMaximum;
133e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        fSeed = result;
134e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        return result;
135e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
136e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
137fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    // Only called once. Could be part of the constructor.
138e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    void init(SkScalar seed)
139e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
140e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
141e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
142857e320300372dab938c0dbffadc3c2c8a893b92senorblanco@chromium.org        // According to the SVG spec, we must truncate (not round) the seed value.
143857e320300372dab938c0dbffadc3c2c8a893b92senorblanco@chromium.org        fSeed = SkScalarTruncToInt(seed);
144e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // The seed value clamp to the range [1, kRandMaximum - 1].
145e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        if (fSeed <= 0) {
146e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
147e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
148e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        if (fSeed > kRandMaximum - 1) {
149e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            fSeed = kRandMaximum - 1;
150e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
151e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        for (int channel = 0; channel < 4; ++channel) {
152e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            for (int i = 0; i < kBlockSize; ++i) {
153e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fLatticeSelector[i] = i;
154e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fNoise[channel][i][0] = (random() % (2 * kBlockSize));
155e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fNoise[channel][i][1] = (random() % (2 * kBlockSize));
156e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            }
157e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
158e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        for (int i = kBlockSize - 1; i > 0; --i) {
159e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            int k = fLatticeSelector[i];
160e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            int j = random() % kBlockSize;
161e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            SkASSERT(j >= 0);
162e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            SkASSERT(j < kBlockSize);
163e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            fLatticeSelector[i] = fLatticeSelector[j];
164e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            fLatticeSelector[j] = k;
165e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
166e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
167e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // Perform the permutations now
168e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        {
169e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            // Copy noise data
170e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            uint16_t noise[4][kBlockSize][2];
171e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            for (int i = 0; i < kBlockSize; ++i) {
172e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                for (int channel = 0; channel < 4; ++channel) {
173e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                    for (int j = 0; j < 2; ++j) {
174e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                        noise[channel][i][j] = fNoise[channel][i][j];
175e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                    }
176e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                }
177e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            }
178e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            // Do permutations on noise data
179e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            for (int i = 0; i < kBlockSize; ++i) {
180e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                for (int channel = 0; channel < 4; ++channel) {
181e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                    for (int j = 0; j < 2; ++j) {
182e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                        fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
183e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                    }
184e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                }
185e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            }
186e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
187e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
188e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // Half of the largest possible value for 16 bit unsigned int
1894b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org        static const SkScalar gHalfMax16bits = 32767.5f;
190e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
191e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // Compute gradients from permutated noise data
192e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        for (int channel = 0; channel < 4; ++channel) {
193e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            for (int i = 0; i < kBlockSize; ++i) {
194e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fGradient[channel][i] = SkPoint::Make(
195e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                    SkScalarMul(SkIntToScalar(fNoise[channel][i][0] - kBlockSize),
196e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                gInvBlockSizef),
197cff0243b0ff1de25b3d99e2bf15a30c0e0a31261skia.committer@gmail.com                    SkScalarMul(SkIntToScalar(fNoise[channel][i][1] - kBlockSize),
198e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                gInvBlockSizef));
199e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fGradient[channel][i].normalize();
200e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                // Put the normalized gradient back into the noise data
201e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fNoise[channel][i][0] = SkScalarRoundToInt(SkScalarMul(
202d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com                    fGradient[channel][i].fX + SK_Scalar1, gHalfMax16bits));
203e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fNoise[channel][i][1] = SkScalarRoundToInt(SkScalarMul(
204d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com                    fGradient[channel][i].fY + SK_Scalar1, gHalfMax16bits));
205e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            }
206e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
207e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
208e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
209fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    // Only called once. Could be part of the constructor.
210e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    void stitch() {
211e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkScalar tileWidth  = SkIntToScalar(fTileSize.width());
212e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkScalar tileHeight = SkIntToScalar(fTileSize.height());
213e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkASSERT(tileWidth > 0 && tileHeight > 0);
214e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // When stitching tiled turbulence, the frequencies must be adjusted
215e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // so that the tile borders will be continuous.
216e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        if (fBaseFrequency.fX) {
2178015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com            SkScalar lowFrequencx =
2188015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com                SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
2198015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com            SkScalar highFrequencx =
2208015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com                SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
221e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            // BaseFrequency should be non-negative according to the standard.
222cff0243b0ff1de25b3d99e2bf15a30c0e0a31261skia.committer@gmail.com            if (SkScalarDiv(fBaseFrequency.fX, lowFrequencx) <
223e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                SkScalarDiv(highFrequencx, fBaseFrequency.fX)) {
224e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fBaseFrequency.fX = lowFrequencx;
225e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            } else {
226e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fBaseFrequency.fX = highFrequencx;
227e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            }
228e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
229e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        if (fBaseFrequency.fY) {
2308015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com            SkScalar lowFrequency =
2318015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com                SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
2328015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com            SkScalar highFrequency =
2338015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com                SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
234cff0243b0ff1de25b3d99e2bf15a30c0e0a31261skia.committer@gmail.com            if (SkScalarDiv(fBaseFrequency.fY, lowFrequency) <
235e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                SkScalarDiv(highFrequency, fBaseFrequency.fY)) {
236e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fBaseFrequency.fY = lowFrequency;
237e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            } else {
238e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fBaseFrequency.fY = highFrequency;
239e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            }
240e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
241e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // Set up TurbulenceInitial stitch values.
242e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        fStitchDataInit.fWidth  =
2438015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com            SkScalarRoundToInt(tileWidth * fBaseFrequency.fX);
244e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        fStitchDataInit.fWrapX  = kPerlinNoise + fStitchDataInit.fWidth;
245e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        fStitchDataInit.fHeight =
2468015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com            SkScalarRoundToInt(tileHeight * fBaseFrequency.fY);
247e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        fStitchDataInit.fWrapY  = kPerlinNoise + fStitchDataInit.fHeight;
248e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
249e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
250fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.orgpublic:
251e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
252f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco#if SK_SUPPORT_GPU
253fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
254fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org
255fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
256fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org#endif
257e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com};
258e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
259e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comSkShader* SkPerlinNoiseShader::CreateFractalNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY,
260e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                                  int numOctaves, SkScalar seed,
261e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                                  const SkISize* tileSize) {
262e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return SkNEW_ARGS(SkPerlinNoiseShader, (kFractalNoise_Type, baseFrequencyX, baseFrequencyY,
263e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                            numOctaves, seed, tileSize));
264e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
265e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
2669fbbcca1c958e6df2cff24d3ccdb7ebd89b8486bcommit-bot@chromium.orgSkShader* SkPerlinNoiseShader::CreateTurbulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY,
267e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                              int numOctaves, SkScalar seed,
268e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                              const SkISize* tileSize) {
269e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return SkNEW_ARGS(SkPerlinNoiseShader, (kTurbulence_Type, baseFrequencyX, baseFrequencyY,
270e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                            numOctaves, seed, tileSize));
271e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
272e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
273e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comSkPerlinNoiseShader::SkPerlinNoiseShader(SkPerlinNoiseShader::Type type,
274e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                         SkScalar baseFrequencyX,
275e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                         SkScalar baseFrequencyY,
276e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                         int numOctaves,
277e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                         SkScalar seed,
278e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                         const SkISize* tileSize)
279e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com  : fType(type)
280e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com  , fBaseFrequencyX(baseFrequencyX)
281e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com  , fBaseFrequencyY(baseFrequencyY)
282ce33d60187718e7bb01944ee130c9f5d9fb335eccommit-bot@chromium.org  , fNumOctaves(numOctaves > 255 ? 255 : numOctaves/*[0,255] octaves allowed*/)
283e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com  , fSeed(seed)
284fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org  , fTileSize(NULL == tileSize ? SkISize::Make(0, 0) : *tileSize)
285fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org  , fStitchTiles(!fTileSize.isEmpty())
286e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com{
287e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkASSERT(numOctaves >= 0 && numOctaves < 256);
288e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
289e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
2909fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
2919fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkPerlinNoiseShader::SkPerlinNoiseShader(SkReadBuffer& buffer) : INHERITED(buffer) {
292e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fType           = (SkPerlinNoiseShader::Type) buffer.readInt();
293e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fBaseFrequencyX = buffer.readScalar();
294e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fBaseFrequencyY = buffer.readScalar();
295e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fNumOctaves     = buffer.readInt();
296e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fSeed           = buffer.readScalar();
297e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fStitchTiles    = buffer.readBool();
298e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fTileSize.fWidth  = buffer.readInt();
299e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fTileSize.fHeight = buffer.readInt();
300ce33d60187718e7bb01944ee130c9f5d9fb335eccommit-bot@chromium.org    buffer.validate(perlin_noise_type_is_valid(fType) &&
301fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org                    (fNumOctaves >= 0) && (fNumOctaves <= 255) &&
302fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org                    (fStitchTiles != fTileSize.isEmpty()));
303e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
3049fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#endif
305e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
306e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comSkPerlinNoiseShader::~SkPerlinNoiseShader() {
307e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
308e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
3099fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkPerlinNoiseShader::CreateProc(SkReadBuffer& buffer) {
3109fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    Type type = (Type)buffer.readInt();
3119fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkScalar freqX = buffer.readScalar();
3129fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkScalar freqY = buffer.readScalar();
3139fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    int octaves = buffer.readInt();
3149fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkScalar seed = buffer.readScalar();
3159fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkISize tileSize;
3169fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    tileSize.fWidth = buffer.readInt();
3179fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    tileSize.fHeight = buffer.readInt();
3189fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
3199fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    switch (type) {
3209fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        case kFractalNoise_Type:
3219fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed            return SkPerlinNoiseShader::CreateFractalNoise(freqX, freqY, octaves, seed, &tileSize);
3229fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        case kTurbulence_Type:
3239fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed            return SkPerlinNoiseShader::CreateTubulence(freqX, freqY, octaves, seed, &tileSize);
3249fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        default:
3259fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed            return NULL;
3269fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
3279fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
3289fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
3298b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkPerlinNoiseShader::flatten(SkWriteBuffer& buffer) const {
330e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeInt((int) fType);
331e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeScalar(fBaseFrequencyX);
332e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeScalar(fBaseFrequencyY);
333e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeInt(fNumOctaves);
334e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeScalar(fSeed);
335e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeInt(fTileSize.fWidth);
336e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeInt(fTileSize.fHeight);
337e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
338e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
33987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::noise2D(
340ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
341e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    struct Noise {
342e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        int noisePositionIntegerValue;
343ce6a354e121915c2925e545e7df2929492d69d50senorblanco        int nextNoisePositionIntegerValue;
344e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkScalar noisePositionFractionValue;
345e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        Noise(SkScalar component)
346e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        {
347e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            SkScalar position = component + kPerlinNoise;
348e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            noisePositionIntegerValue = SkScalarFloorToInt(position);
349e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
350ce6a354e121915c2925e545e7df2929492d69d50senorblanco            nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
351e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
352e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    };
353e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    Noise noiseX(noiseVector.x());
354e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    Noise noiseY(noiseVector.y());
355e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar u, v;
35687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader);
357e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // If stitching, adjust lattice points accordingly.
35887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    if (perlinNoiseShader.fStitchTiles) {
359e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        noiseX.noisePositionIntegerValue =
360e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
361e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        noiseY.noisePositionIntegerValue =
362e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
363ce6a354e121915c2925e545e7df2929492d69d50senorblanco        noiseX.nextNoisePositionIntegerValue =
364ce6a354e121915c2925e545e7df2929492d69d50senorblanco            checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
365ce6a354e121915c2925e545e7df2929492d69d50senorblanco        noiseY.nextNoisePositionIntegerValue =
366ce6a354e121915c2925e545e7df2929492d69d50senorblanco            checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
367e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
368e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    noiseX.noisePositionIntegerValue &= kBlockMask;
369e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    noiseY.noisePositionIntegerValue &= kBlockMask;
370ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseX.nextNoisePositionIntegerValue &= kBlockMask;
371ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseY.nextNoisePositionIntegerValue &= kBlockMask;
372ce6a354e121915c2925e545e7df2929492d69d50senorblanco    int i =
373ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        fPaintingData->fLatticeSelector[noiseX.noisePositionIntegerValue];
374ce6a354e121915c2925e545e7df2929492d69d50senorblanco    int j =
375ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        fPaintingData->fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
376ce6a354e121915c2925e545e7df2929492d69d50senorblanco    int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
377ce6a354e121915c2925e545e7df2929492d69d50senorblanco    int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
378ce6a354e121915c2925e545e7df2929492d69d50senorblanco    int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
379ce6a354e121915c2925e545e7df2929492d69d50senorblanco    int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
380e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
381e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
382e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
383e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
384e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                          noiseY.noisePositionFractionValue); // Offset (0,0)
385ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    u = fPaintingData->fGradient[channel][b00].dot(fractionValue);
386e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
387ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    v = fPaintingData->fGradient[channel][b10].dot(fractionValue);
388e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar a = SkScalarInterp(u, v, sx);
389e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
390ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    v = fPaintingData->fGradient[channel][b11].dot(fractionValue);
391e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
392ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    u = fPaintingData->fGradient[channel][b01].dot(fractionValue);
393e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar b = SkScalarInterp(u, v, sx);
394e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return SkScalarInterp(a, b, sy);
395e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
396e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
39787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
398ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        int channel, StitchData& stitchData, const SkPoint& point) const {
39987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader);
40087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    if (perlinNoiseShader.fStitchTiles) {
401e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // Set up TurbulenceInitial stitch values.
402ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        stitchData = fPaintingData->fStitchDataInit;
403e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
404e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar turbulenceFunctionResult = 0;
405ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), fPaintingData->fBaseFrequency.fX),
406ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco                                      SkScalarMul(point.y(), fPaintingData->fBaseFrequency.fY)));
407e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar ratio = SK_Scalar1;
40887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
409ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        SkScalar noise = noise2D(channel, stitchData, noiseVector);
410e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        turbulenceFunctionResult += SkScalarDiv(
41187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            (perlinNoiseShader.fType == kFractalNoise_Type) ? noise : SkScalarAbs(noise), ratio);
412e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        noiseVector.fX *= 2;
413e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        noiseVector.fY *= 2;
414e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        ratio *= 2;
41587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        if (perlinNoiseShader.fStitchTiles) {
416e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            // Update stitch values
417e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            stitchData.fWidth  *= 2;
418e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            stitchData.fWrapX   = stitchData.fWidth + kPerlinNoise;
419e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            stitchData.fHeight *= 2;
420e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            stitchData.fWrapY   = stitchData.fHeight + kPerlinNoise;
421e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
422e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
423e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
424e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
425e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // by fractalNoise and (turbulenceFunctionResult) by turbulence.
42687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    if (perlinNoiseShader.fType == kFractalNoise_Type) {
427e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        turbulenceFunctionResult =
428e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            SkScalarMul(turbulenceFunctionResult, SK_ScalarHalf) + SK_ScalarHalf;
429e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
430e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
431e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    if (channel == 3) { // Scale alpha by paint value
432e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        turbulenceFunctionResult = SkScalarMul(turbulenceFunctionResult,
433e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            SkScalarDiv(SkIntToScalar(getPaintAlpha()), SkIntToScalar(255)));
434e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
435e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
436e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Clamp result
437e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1);
438e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
439e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
44087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkPMColor SkPerlinNoiseShader::PerlinNoiseShaderContext::shade(
44187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        const SkPoint& point, StitchData& stitchData) const {
442e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkPoint newPoint;
443a8d95f899bf3fe404d3cd5c357531ff852c15b29senorblanco@chromium.org    fMatrix.mapPoints(&newPoint, &point, 1);
444e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
445e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
446e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
447e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    U8CPU rgba[4];
448e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    for (int channel = 3; channel >= 0; --channel) {
449e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        rgba[channel] = SkScalarFloorToInt(255 *
450ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco            calculateTurbulenceValueForPoint(channel, stitchData, newPoint));
451e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
452e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
453e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
454e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
455ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.orgSkShader::Context* SkPerlinNoiseShader::onCreateContext(const ContextRec& rec,
456ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org                                                        void* storage) const {
457e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    return SkNEW_PLACEMENT_ARGS(storage, PerlinNoiseShaderContext, (*this, rec));
45887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
45987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
46087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgsize_t SkPerlinNoiseShader::contextSize() const {
46187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    return sizeof(PerlinNoiseShaderContext);
46287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
46387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
46487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkPerlinNoiseShader::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
465e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org        const SkPerlinNoiseShader& shader, const ContextRec& rec)
466e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    : INHERITED(shader, rec)
46787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org{
468e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    SkMatrix newMatrix = *rec.fMatrix;
469b67b8e6052bf5567eb3f9726dda99a6b260dfb05reed@google.com    newMatrix.preConcat(shader.getLocalMatrix());
470b67b8e6052bf5567eb3f9726dda99a6b260dfb05reed@google.com    if (rec.fLocalMatrix) {
471b67b8e6052bf5567eb3f9726dda99a6b260dfb05reed@google.com        newMatrix.preConcat(*rec.fLocalMatrix);
472b67b8e6052bf5567eb3f9726dda99a6b260dfb05reed@google.com    }
473a8d95f899bf3fe404d3cd5c357531ff852c15b29senorblanco@chromium.org    // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
474a8d95f899bf3fe404d3cd5c357531ff852c15b29senorblanco@chromium.org    // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
475ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    fMatrix.setTranslate(-newMatrix.getTranslateX() + SK_Scalar1, -newMatrix.getTranslateY() + SK_Scalar1);
476ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    fPaintingData = SkNEW_ARGS(PaintingData, (shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX, shader.fBaseFrequencyY, newMatrix));
477ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco}
478ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco
479ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblancoSkPerlinNoiseShader::PerlinNoiseShaderContext::~PerlinNoiseShaderContext() {
480ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    SkDELETE(fPaintingData);
481e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
482e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
48387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkPerlinNoiseShader::PerlinNoiseShaderContext::shadeSpan(
48487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        int x, int y, SkPMColor result[], int count) {
485e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
486e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    StitchData stitchData;
487e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    for (int i = 0; i < count; ++i) {
488e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        result[i] = shade(point, stitchData);
489e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        point.fX += SK_Scalar1;
490e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
491e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
492e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
49387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkPerlinNoiseShader::PerlinNoiseShaderContext::shadeSpan16(
49487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        int x, int y, uint16_t result[], int count) {
495e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
496e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    StitchData stitchData;
497e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    DITHER_565_SCAN(y);
498e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    for (int i = 0; i < count; ++i) {
499e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        unsigned dither = DITHER_VALUE(x);
500e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        result[i] = SkDitherRGB32To565(shade(point, stitchData), dither);
501e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        DITHER_INC_X(x);
502e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        point.fX += SK_Scalar1;
503e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
504e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
505e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
506e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com/////////////////////////////////////////////////////////////////////
507e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
508344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org#if SK_SUPPORT_GPU
509e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
510b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "GrTBackendProcessorFactory.h"
511e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
512b0a8a377f832c59cee939ad721e1f87d378b7142joshualittclass GrGLPerlinNoise : public GrGLFragmentProcessor {
5134775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.compublic:
514b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GrGLPerlinNoise(const GrBackendProcessorFactory&,
515b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                    const GrProcessor&);
5164775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com    virtual ~GrGLPerlinNoise() {}
517e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
51830ba436f04e61d4505fb854d5fc56079636e0788joshualitt    virtual void emitCode(GrGLProgramBuilder*,
519b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                          const GrFragmentProcessor&,
520b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                          const GrProcessorKey&,
521e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                          const char* outputColor,
522e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                          const char* inputColor,
52377af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                          const TransformedCoordsArray&,
524e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                          const TextureSamplerArray&) SK_OVERRIDE;
525e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
526b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
5274775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com
528b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b);
5294775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com
530f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblancoprivate:
531e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
5327510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    GrGLProgramDataManager::UniformHandle fStitchDataUni;
5337510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    SkPerlinNoiseShader::Type             fType;
5347510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    bool                                  fStitchTiles;
5357510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    int                                   fNumOctaves;
5367510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    GrGLProgramDataManager::UniformHandle fBaseFrequencyUni;
5377510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    GrGLProgramDataManager::UniformHandle fAlphaUni;
538e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
539e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comprivate:
540b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    typedef GrGLFragmentProcessor INHERITED;
541e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com};
542e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
543e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com/////////////////////////////////////////////////////////////////////
544e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
545b0a8a377f832c59cee939ad721e1f87d378b7142joshualittclass GrPerlinNoiseEffect : public GrFragmentProcessor {
546e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.compublic:
547b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    static GrFragmentProcessor* Create(SkPerlinNoiseShader::Type type,
548b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       int numOctaves, bool stitchTiles,
549b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       SkPerlinNoiseShader::PaintingData* paintingData,
550b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       GrTexture* permutationsTexture, GrTexture* noiseTexture,
551b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       const SkMatrix& matrix, uint8_t alpha) {
55255fad7af61c21d502acb9891d631e8aa29e3628cbsalomon        return SkNEW_ARGS(GrPerlinNoiseEffect, (type, numOctaves, stitchTiles, paintingData,
55355fad7af61c21d502acb9891d631e8aa29e3628cbsalomon                                                permutationsTexture, noiseTexture, matrix, alpha));
554e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
555e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
556ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    virtual ~GrPerlinNoiseEffect() {
557ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        SkDELETE(fPaintingData);
558ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    }
559e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
560e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    static const char* Name() { return "PerlinNoise"; }
561b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE {
562b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        return GrTBackendFragmentProcessorFactory<GrPerlinNoiseEffect>::getInstance();
563e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
564ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    const SkPerlinNoiseShader::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
565e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
566f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    SkPerlinNoiseShader::Type type() const { return fType; }
567f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    bool stitchTiles() const { return fStitchTiles; }
568ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
569f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    int numOctaves() const { return fNumOctaves; }
570f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
571f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    uint8_t alpha() const { return fAlpha; }
572f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco
573b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    typedef GrGLPerlinNoise GLProcessor;
574e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
575e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comprivate:
576b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    virtual bool onIsEqual(const GrProcessor& sBase) const SK_OVERRIDE {
57749586bec7383d4ccb81f85f8e2dc4162e2d4f6a8joshualitt        const GrPerlinNoiseEffect& s = sBase.cast<GrPerlinNoiseEffect>();
578f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco        return fType == s.fType &&
579ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco               fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
580f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco               fNumOctaves == s.fNumOctaves &&
581f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco               fStitchTiles == s.fStitchTiles &&
582f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco               fCoordTransform.getMatrix() == s.fCoordTransform.getMatrix() &&
583f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco               fAlpha == s.fAlpha &&
5844775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com               fPermutationsAccess.getTexture() == s.fPermutationsAccess.getTexture() &&
585e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com               fNoiseAccess.getTexture() == s.fNoiseAccess.getTexture() &&
586ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco               fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
587e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
588e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
589ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    GrPerlinNoiseEffect(SkPerlinNoiseShader::Type type,
590e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                        int numOctaves, bool stitchTiles,
591ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco                        SkPerlinNoiseShader::PaintingData* paintingData,
592e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                        GrTexture* permutationsTexture, GrTexture* noiseTexture,
593e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                        const SkMatrix& matrix, uint8_t alpha)
594f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco      : fType(type)
595f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco      , fNumOctaves(numOctaves)
596f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco      , fStitchTiles(stitchTiles)
597f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco      , fAlpha(alpha)
5984775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com      , fPermutationsAccess(permutationsTexture)
599e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com      , fNoiseAccess(noiseTexture)
600ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco      , fPaintingData(paintingData) {
601e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        this->addTextureAccess(&fPermutationsAccess);
602e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        this->addTextureAccess(&fNoiseAccess);
603ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        fCoordTransform.reset(kLocal_GrCoordSet, matrix);
604f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco        this->addCoordTransform(&fCoordTransform);
605f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco        this->setWillNotUseInputColor();
606e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
607e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
608b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
609e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
610f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    SkPerlinNoiseShader::Type       fType;
611f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    GrCoordTransform                fCoordTransform;
612f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    int                             fNumOctaves;
613f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    bool                            fStitchTiles;
614f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    uint8_t                         fAlpha;
615e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    GrTextureAccess                 fPermutationsAccess;
616e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    GrTextureAccess                 fNoiseAccess;
617ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    SkPerlinNoiseShader::PaintingData *fPaintingData;
618e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
619f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    void getConstantColorComponents(GrColor*, uint32_t* validFlags) const SK_OVERRIDE {
620f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco        *validFlags = 0; // This is noise. Nothing is constant.
6214775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com    }
6224775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com
6234775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.comprivate:
624b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    typedef GrFragmentProcessor INHERITED;
625e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com};
626e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
627e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com/////////////////////////////////////////////////////////////////////
628b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoiseEffect);
629e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
630b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrFragmentProcessor* GrPerlinNoiseEffect::TestCreate(SkRandom* random,
631b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                     GrContext* context,
632b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                     const GrDrawTargetCaps&,
633b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                     GrTexture**) {
634423ac13f351b22308d3b1d039ab4859540be0b9dsugoi@google.com    int      numOctaves = random->nextRangeU(2, 10);
635e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    bool     stitchTiles = random->nextBool();
636e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar seed = SkIntToScalar(random->nextU());
637e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkISize  tileSize = SkISize::Make(random->nextRangeU(4, 4096), random->nextRangeU(4, 4096));
6384b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    SkScalar baseFrequencyX = random->nextRangeScalar(0.01f,
6394b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org                                                      0.99f);
6404b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    SkScalar baseFrequencyY = random->nextRangeScalar(0.01f,
6414b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org                                                      0.99f);
642e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
643e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkShader* shader = random->nextBool() ?
644e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkPerlinNoiseShader::CreateFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
645e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                                stitchTiles ? &tileSize : NULL) :
6469fbbcca1c958e6df2cff24d3ccdb7ebd89b8486bcommit-bot@chromium.org        SkPerlinNoiseShader::CreateTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
647e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                             stitchTiles ? &tileSize : NULL);
648e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
649e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkPaint paint;
65083d081ae1d731b5039e99823620f5e287542ee39bsalomon    GrColor paintColor;
651b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GrFragmentProcessor* effect;
652b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    SkAssertResult(shader->asFragmentProcessor(context, paint, NULL, &paintColor, &effect));
653e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
654e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkDELETE(shader);
655e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
656e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return effect;
657e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
6584775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com
659b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrGLPerlinNoise::GrGLPerlinNoise(const GrBackendProcessorFactory& factory,
660b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                 const GrProcessor& processor)
661f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco  : INHERITED (factory)
662b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt  , fType(processor.cast<GrPerlinNoiseEffect>().type())
663b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt  , fStitchTiles(processor.cast<GrPerlinNoiseEffect>().stitchTiles())
664b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt  , fNumOctaves(processor.cast<GrPerlinNoiseEffect>().numOctaves()) {
6654775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com}
6664775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com
66730ba436f04e61d4505fb854d5fc56079636e0788joshualittvoid GrGLPerlinNoise::emitCode(GrGLProgramBuilder* builder,
668b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                               const GrFragmentProcessor&,
669b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                               const GrProcessorKey& key,
670e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                               const char* outputColor,
671e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                               const char* inputColor,
67277af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                               const TransformedCoordsArray& coords,
673e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                               const TextureSamplerArray& samplers) {
674e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    sk_ignore_unused_variable(inputColor);
675e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
67630ba436f04e61d4505fb854d5fc56079636e0788joshualitt    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
67730ba436f04e61d4505fb854d5fc56079636e0788joshualitt    SkString vCoords = fsBuilder->ensureFSCoords2D(coords, 0);
678e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
67930ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fBaseFrequencyUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
680e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                            kVec2f_GrSLType, "baseFrequency");
681e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* baseFrequencyUni = builder->getUniformCStr(fBaseFrequencyUni);
68230ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fAlphaUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
683e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                    kFloat_GrSLType, "alpha");
684e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* alphaUni = builder->getUniformCStr(fAlphaUni);
685e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
686e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* stitchDataUni = NULL;
687e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    if (fStitchTiles) {
68830ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fStitchDataUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
6899839320ae17ab1c2182dc144db5ba94caa1bde56commit-bot@chromium.org                                             kVec2f_GrSLType, "stitchData");
690e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        stitchDataUni = builder->getUniformCStr(fStitchDataUni);
691e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
692e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
693d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
694d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    const char* chanCoordR  = "0.125";
695d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    const char* chanCoordG  = "0.375";
696d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    const char* chanCoordB  = "0.625";
697d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    const char* chanCoordA  = "0.875";
698d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    const char* chanCoord   = "chanCoord";
699e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* stitchData  = "stitchData";
700e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* ratio       = "ratio";
701e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* noiseVec    = "noiseVec";
702e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* noiseSmooth = "noiseSmooth";
703ce6a354e121915c2925e545e7df2929492d69d50senorblanco    const char* floorVal    = "floorVal";
704e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* fractVal    = "fractVal";
705e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* uv          = "uv";
706e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* ab          = "ab";
707e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* latticeIdx  = "latticeIdx";
708ce6a354e121915c2925e545e7df2929492d69d50senorblanco    const char* bcoords     = "bcoords";
709e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* lattice     = "lattice";
710e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* inc8bit     = "0.00390625";  // 1.0 / 256.0
711e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
712e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // [-1,1] vector and perform a dot product between that vector and the provided vector.
713e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* dotLattice  = "dot(((%s.ga + %s.rb * vec2(%s)) * vec2(2.0) - vec2(1.0)), %s);";
714e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
715d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    // Add noise function
716d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    static const GrGLShaderVar gPerlinNoiseArgs[] =  {
717d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        GrGLShaderVar(chanCoord, kFloat_GrSLType),
7189839320ae17ab1c2182dc144db5ba94caa1bde56commit-bot@chromium.org        GrGLShaderVar(noiseVec, kVec2f_GrSLType)
719d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    };
720e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
721d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    static const GrGLShaderVar gPerlinNoiseStitchArgs[] =  {
722d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        GrGLShaderVar(chanCoord, kFloat_GrSLType),
7239839320ae17ab1c2182dc144db5ba94caa1bde56commit-bot@chromium.org        GrGLShaderVar(noiseVec, kVec2f_GrSLType),
7249839320ae17ab1c2182dc144db5ba94caa1bde56commit-bot@chromium.org        GrGLShaderVar(stitchData, kVec2f_GrSLType)
725d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    };
726e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
727d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    SkString noiseCode;
728e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
729ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\tvec4 %s;\n", floorVal);
730ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
731ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\t%s.zw = %s.xy + vec2(1.0);\n", floorVal, floorVal);
732ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\tvec2 %s = fract(%s);\n", fractVal, noiseVec);
733e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
734e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // smooth curve : t * t * (3 - 2 * t)
735ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\n\tvec2 %s = %s * %s * (vec2(3.0) - vec2(2.0) * %s);",
736ce6a354e121915c2925e545e7df2929492d69d50senorblanco        noiseSmooth, fractVal, fractVal, fractVal);
737e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
738e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Adjust frequencies if we're stitching tiles
739e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    if (fStitchTiles) {
7409839320ae17ab1c2182dc144db5ba94caa1bde56commit-bot@chromium.org        noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
741ce6a354e121915c2925e545e7df2929492d69d50senorblanco            floorVal, stitchData, floorVal, stitchData);
7429839320ae17ab1c2182dc144db5ba94caa1bde56commit-bot@chromium.org        noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
743ce6a354e121915c2925e545e7df2929492d69d50senorblanco            floorVal, stitchData, floorVal, stitchData);
744ce6a354e121915c2925e545e7df2929492d69d50senorblanco        noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
745ce6a354e121915c2925e545e7df2929492d69d50senorblanco            floorVal, stitchData, floorVal, stitchData);
746ce6a354e121915c2925e545e7df2929492d69d50senorblanco        noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
747ce6a354e121915c2925e545e7df2929492d69d50senorblanco            floorVal, stitchData, floorVal, stitchData);
748e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
749e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
750e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Get texture coordinates and normalize
751ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / vec4(256.0));\n",
752ce6a354e121915c2925e545e7df2929492d69d50senorblanco        floorVal, floorVal);
753e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
754e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Get permutation for x
755e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
756e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkString xCoords("");
757ce6a354e121915c2925e545e7df2929492d69d50senorblanco        xCoords.appendf("vec2(%s.x, 0.5)", floorVal);
758e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
759d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf("\n\tvec2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
76030ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->appendTextureLookup(&noiseCode, samplers[0], xCoords.c_str(), kVec2f_GrSLType);
761d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.append(".r;");
762e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
763e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
764e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Get permutation for x + 1
765e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
766e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkString xCoords("");
767ce6a354e121915c2925e545e7df2929492d69d50senorblanco        xCoords.appendf("vec2(%s.z, 0.5)", floorVal);
768e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
769d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf("\n\t%s.y = ", latticeIdx);
77030ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->appendTextureLookup(&noiseCode, samplers[0], xCoords.c_str(), kVec2f_GrSLType);
771d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.append(".r;");
772e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
773e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
774344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org#if defined(SK_BUILD_FOR_ANDROID)
775344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
776344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
777344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
778344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    // (or 0.484368 here). The following rounding operation prevents these precision issues from
779344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    // affecting the result of the noise by making sure that we only have multiples of 1/255.
780344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    // (Note that 1/255 is about 0.003921569, which is the value used here).
781344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    noiseCode.appendf("\n\t%s = floor(%s * vec2(255.0) + vec2(0.5)) * vec2(0.003921569);",
782344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org                      latticeIdx, latticeIdx);
783344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org#endif
784344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org
785e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Get (x,y) coordinates with the permutated x
786ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\n\tvec4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
787e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
788d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\n\tvec2 %s;", uv);
789e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute u, at offset (0,0)
790e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
791e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkString latticeCoords("");
792ce6a354e121915c2925e545e7df2929492d69d50senorblanco        latticeCoords.appendf("vec2(%s.x, %s)", bcoords, chanCoord);
793d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf("\n\tvec4 %s = ", lattice);
79430ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
795d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            kVec2f_GrSLType);
796d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
797d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
798e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
799e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
800d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
801e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute v, at offset (-1,0)
802e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
803e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkString latticeCoords("");
804ce6a354e121915c2925e545e7df2929492d69d50senorblanco        latticeCoords.appendf("vec2(%s.y, %s)", bcoords, chanCoord);
805344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org        noiseCode.append("\n\tlattice = ");
80630ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
807d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            kVec2f_GrSLType);
808d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
809d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
810e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
811e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
812e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute 'a' as a linear interpolation of 'u' and 'v'
813d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\tvec2 %s;", ab);
814d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\t%s.x = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth);
815e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
816d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
817e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute v, at offset (-1,-1)
818e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
819e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkString latticeCoords("");
820ce6a354e121915c2925e545e7df2929492d69d50senorblanco        latticeCoords.appendf("vec2(%s.w, %s)", bcoords, chanCoord);
821344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org        noiseCode.append("\n\tlattice = ");
82230ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
823d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            kVec2f_GrSLType);
824d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
825d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
826e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
827e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
828d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
829e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute u, at offset (0,-1)
830e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
831e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkString latticeCoords("");
832ce6a354e121915c2925e545e7df2929492d69d50senorblanco        latticeCoords.appendf("vec2(%s.z, %s)", bcoords, chanCoord);
833344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org        noiseCode.append("\n\tlattice = ");
83430ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
835d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            kVec2f_GrSLType);
836d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
837d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
838e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
839e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
840e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute 'b' as a linear interpolation of 'u' and 'v'
841d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\t%s.y = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth);
842e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute the noise as a linear interpolation of 'a' and 'b'
843d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
844d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com
845d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    SkString noiseFuncName;
846d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    if (fStitchTiles) {
84730ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->emitFunction(kFloat_GrSLType,
84874a3a2135ca82ab9324b7e499caa3280348a4fdacommit-bot@chromium.org                                "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
84974a3a2135ca82ab9324b7e499caa3280348a4fdacommit-bot@chromium.org                                gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
850d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    } else {
85130ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->emitFunction(kFloat_GrSLType,
85274a3a2135ca82ab9324b7e499caa3280348a4fdacommit-bot@chromium.org                                "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
85374a3a2135ca82ab9324b7e499caa3280348a4fdacommit-bot@chromium.org                                gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
854d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    }
855e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
856d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    // There are rounding errors if the floor operation is not performed here
85730ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\tvec2 %s = floor(%s.xy) * %s;",
858ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco                           noiseVec, vCoords.c_str(), baseFrequencyUni);
859e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
860d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    // Clear the color accumulator
86130ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t%s = vec4(0.0);", outputColor);
862e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
863e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    if (fStitchTiles) {
864d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        // Set up TurbulenceInitial stitch values.
86530ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("\n\t\tvec2 %s = %s;", stitchData, stitchDataUni);
866e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
867e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
86830ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\tfloat %s = 1.0;", ratio);
869d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com
870d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    // Loop over all octaves
87130ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\tfor (int octave = 0; octave < %d; ++octave) {", fNumOctaves);
872d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com
87330ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t\t%s += ", outputColor);
874d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    if (fType != SkPerlinNoiseShader::kFractalNoise_Type) {
87530ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend("abs(");
876d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    }
877d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    if (fStitchTiles) {
87830ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf(
879d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            "vec4(\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s),"
880d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com                 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
881d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
882d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
883d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
884d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
885d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    } else {
88630ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf(
887d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            "vec4(\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s),"
888d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com                 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
889d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordR, noiseVec,
890d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordG, noiseVec,
891d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordB, noiseVec,
892d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordA, noiseVec);
893d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    }
894d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    if (fType != SkPerlinNoiseShader::kFractalNoise_Type) {
89530ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf(")"); // end of "abs("
896d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    }
89730ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf(" * %s;", ratio);
898d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com
89930ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", noiseVec);
90030ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
901d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com
902d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    if (fStitchTiles) {
90330ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", stitchData);
904d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    }
90530ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
906e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
907e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    if (fType == SkPerlinNoiseShader::kFractalNoise_Type) {
908e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
909e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // by fractalNoise and (turbulenceFunctionResult) by turbulence.
91030ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("\n\t\t%s = %s * vec4(0.5) + vec4(0.5);", outputColor, outputColor);
911e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
912e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
91330ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t%s.a *= %s;", outputColor, alphaUni);
914e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
915e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Clamp values
91630ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", outputColor, outputColor);
917e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
918e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Pre-multiply the result
91930ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n",
920e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                  outputColor, outputColor, outputColor, outputColor);
921e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
922e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
923b0a8a377f832c59cee939ad721e1f87d378b7142joshualittvoid GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrGLCaps&,
924b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                             GrProcessorKeyBuilder* b) {
925b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrPerlinNoiseEffect& turbulence = processor.cast<GrPerlinNoiseEffect>();
926e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
92763e99f7a03b2ac90ae7a00232674fd39c0bdcc68bsalomon    uint32_t key = turbulence.numOctaves();
928e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
929e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    key = key << 3; // Make room for next 3 bits
930e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
931e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    switch (turbulence.type()) {
932e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        case SkPerlinNoiseShader::kFractalNoise_Type:
933e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            key |= 0x1;
934e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            break;
935e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        case SkPerlinNoiseShader::kTurbulence_Type:
936e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            key |= 0x2;
937e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            break;
938e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        default:
939e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            // leave key at 0
940e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            break;
941e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
942e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
943e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    if (turbulence.stitchTiles()) {
944e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        key |= 0x4; // Flip the 3rd bit if tile stitching is on
945e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
946e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
94763e99f7a03b2ac90ae7a00232674fd39c0bdcc68bsalomon    b->add32(key);
948e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
949e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
950b0a8a377f832c59cee939ad721e1f87d378b7142joshualittvoid GrGLPerlinNoise::setData(const GrGLProgramDataManager& pdman, const GrProcessor& processor) {
951b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    INHERITED::setData(pdman, processor);
952f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco
953b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrPerlinNoiseEffect& turbulence = processor.cast<GrPerlinNoiseEffect>();
954e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
955e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const SkVector& baseFrequency = turbulence.baseFrequency();
9567510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
9577510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    pdman.set1f(fAlphaUni, SkScalarDiv(SkIntToScalar(turbulence.alpha()), SkIntToScalar(255)));
958e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
9594775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com    if (turbulence.stitchTiles()) {
9604775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com        const SkPerlinNoiseShader::StitchData& stitchData = turbulence.stitchData();
9617510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen        pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
9629839320ae17ab1c2182dc144db5ba94caa1bde56commit-bot@chromium.org                                   SkIntToScalar(stitchData.fHeight));
9634775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com    }
9644775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com}
9654775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com
966e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com/////////////////////////////////////////////////////////////////////
967e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
968b0a8a377f832c59cee939ad721e1f87d378b7142joshualittbool SkPerlinNoiseShader::asFragmentProcessor(GrContext* context, const SkPaint& paint,
969b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                              const SkMatrix* externalLocalMatrix,
970b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                              GrColor* paintColor, GrFragmentProcessor** fp) const {
97149f085dddff10473b6ebf832a974288300224e60bsalomon    SkASSERT(context);
9729de5b514d38c5b36066bcdc14fba2f7e5196d372dandov
97383d081ae1d731b5039e99823620f5e287542ee39bsalomon    *paintColor = SkColor2GrColorJustAlpha(paint.getColor());
974ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco
97596fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org    SkMatrix localMatrix = this->getLocalMatrix();
97696fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org    if (externalLocalMatrix) {
97796fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        localMatrix.preConcat(*externalLocalMatrix);
97896fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org    }
97996fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org
980ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    SkMatrix matrix = context->getMatrix();
981ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    matrix.preConcat(localMatrix);
982ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco
983c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org    if (0 == fNumOctaves) {
984c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org        SkColor clearColor = 0;
985c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org        if (kFractalNoise_Type == fType) {
986c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org            clearColor = SkColorSetARGB(paint.getAlpha() / 2, 127, 127, 127);
987c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org        }
988c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org        SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(
989c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org                                                clearColor, SkXfermode::kSrc_Mode));
990b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        *fp = cf->asFragmentProcessor(context);
9919de5b514d38c5b36066bcdc14fba2f7e5196d372dandov        return true;
992c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org    }
993c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org
994e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Either we don't stitch tiles, either we have a valid tile size
995e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
996e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
997b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    SkPerlinNoiseShader::PaintingData* paintingData =
998b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt            SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY, matrix));
999e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    GrTexture* permutationsTexture = GrLockAndRefCachedBitmapTexture(
1000ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        context, paintingData->getPermutationsBitmap(), NULL);
1001e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    GrTexture* noiseTexture = GrLockAndRefCachedBitmapTexture(
1002ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        context, paintingData->getNoiseBitmap(), NULL);
1003ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco
1004ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    SkMatrix m = context->getMatrix();
1005ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    m.setTranslateX(-localMatrix.getTranslateX() + SK_Scalar1);
1006ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1);
100749f085dddff10473b6ebf832a974288300224e60bsalomon    if ((permutationsTexture) && (noiseTexture)) {
1008b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        *fp = GrPerlinNoiseEffect::Create(fType,
1009b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          fNumOctaves,
1010b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          fStitchTiles,
1011b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          paintingData,
1012b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          permutationsTexture, noiseTexture,
1013b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          m, paint.getAlpha());
1014ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    } else {
1015ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        SkDELETE(paintingData);
1016b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        *fp = NULL;
1017ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    }
1018e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
1019e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Unlock immediately, this is not great, but we don't have a way of
1020e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // knowing when else to unlock it currently. TODO: Remove this when
1021e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // unref becomes the unlock replacement for all types of textures.
102249f085dddff10473b6ebf832a974288300224e60bsalomon    if (permutationsTexture) {
1023e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        GrUnlockAndUnrefCachedBitmapTexture(permutationsTexture);
1024e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
102549f085dddff10473b6ebf832a974288300224e60bsalomon    if (noiseTexture) {
1026e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        GrUnlockAndUnrefCachedBitmapTexture(noiseTexture);
1027e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
1028e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
10299de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    return true;
1030e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
1031e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
1032e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#else
1033e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
1034b0a8a377f832c59cee939ad721e1f87d378b7142joshualittbool SkPerlinNoiseShader::asFragmentProcessor(GrContext*, const SkPaint&, const SkMatrix*, GrColor*,
1035b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                              GrFragmentProcessor**) const {
1036e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkDEBUGFAIL("Should not call in GPU-less build");
10379de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    return false;
1038e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
1039e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
1040e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#endif
1041e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
10420f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
1043e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comvoid SkPerlinNoiseShader::toString(SkString* str) const {
1044e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append("SkPerlinNoiseShader: (");
1045e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
1046e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append("type: ");
1047e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    switch (fType) {
1048e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        case kFractalNoise_Type:
1049e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            str->append("\"fractal noise\"");
1050e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            break;
1051e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        case kTurbulence_Type:
1052e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            str->append("\"turbulence\"");
1053e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            break;
1054e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        default:
1055e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            str->append("\"unknown\"");
1056e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            break;
1057e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
1058e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(" base frequency: (");
1059e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->appendScalar(fBaseFrequencyX);
1060e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(", ");
1061e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->appendScalar(fBaseFrequencyY);
1062e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(") number of octaves: ");
1063e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->appendS32(fNumOctaves);
1064e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(" seed: ");
1065e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->appendScalar(fSeed);
1066e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(" stitch tiles: ");
1067e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(fStitchTiles ? "true " : "false ");
1068e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
1069e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    this->INHERITED::toString(str);
1070e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
1071e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(")");
1072e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
1073e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#endif
1074