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"
20605dd0fbce9dbb2a0d3313e13e161f2bd54870d7egdaniel#include "GrInvariantOutput.h"
21eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "SkGr.h"
22b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "gl/GrGLProcessor.h"
2330ba436f04e61d4505fb854d5fc56079636e0788joshualitt#include "gl/builders/GrGLProgramBuilder.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
53e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com} // end namespace
54e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
55e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comstruct SkPerlinNoiseShader::StitchData {
56e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    StitchData()
57e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com      : fWidth(0)
58e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com      , fWrapX(0)
59e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com      , fHeight(0)
60e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com      , fWrapY(0)
61e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {}
62e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
63e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    bool operator==(const StitchData& other) const {
64e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        return fWidth == other.fWidth &&
65e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com               fWrapX == other.fWrapX &&
66e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com               fHeight == other.fHeight &&
67e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com               fWrapY == other.fWrapY;
68e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
69e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
70e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    int fWidth; // How much to subtract to wrap for stitching.
71e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    int fWrapX; // Minimum value to wrap.
72e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    int fHeight;
73e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    int fWrapY;
74e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com};
75e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
76e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comstruct SkPerlinNoiseShader::PaintingData {
77fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    PaintingData(const SkISize& tileSize, SkScalar seed,
78ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco                 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
79ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco                 const SkMatrix& matrix)
80e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
8111fa2247b747eb75e2f158dc7571d458ed6c0115reed        SkVector vec[2] = {
8211fa2247b747eb75e2f158dc7571d458ed6c0115reed            { SkScalarInvert(baseFrequencyX),   SkScalarInvert(baseFrequencyY)  },
8311fa2247b747eb75e2f158dc7571d458ed6c0115reed            { SkIntToScalar(tileSize.fWidth),   SkIntToScalar(tileSize.fHeight) },
8411fa2247b747eb75e2f158dc7571d458ed6c0115reed        };
8511fa2247b747eb75e2f158dc7571d458ed6c0115reed        matrix.mapVectors(vec, 2);
8611fa2247b747eb75e2f158dc7571d458ed6c0115reed
8711fa2247b747eb75e2f158dc7571d458ed6c0115reed        fBaseFrequency.set(SkScalarInvert(vec[0].fX), SkScalarInvert(vec[0].fY));
8811fa2247b747eb75e2f158dc7571d458ed6c0115reed        fTileSize.set(SkScalarRoundToInt(vec[1].fX), SkScalarRoundToInt(vec[1].fY));
89fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org        this->init(seed);
90fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org        if (!fTileSize.isEmpty()) {
91fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org            this->stitch();
92fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org        }
93fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org
94f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco#if SK_SUPPORT_GPU
95a3264e53ee3f3c5d6a2c813df7e44b5b96d207f2commit-bot@chromium.org        fPermutationsBitmap.setInfo(SkImageInfo::MakeA8(kBlockSize, 1));
96fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org        fPermutationsBitmap.setPixels(fLatticeSelector);
97fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org
98a3264e53ee3f3c5d6a2c813df7e44b5b96d207f2commit-bot@chromium.org        fNoiseBitmap.setInfo(SkImageInfo::MakeN32Premul(kBlockSize, 4));
99fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org        fNoiseBitmap.setPixels(fNoise[0][0]);
100fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org#endif
101e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
102e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
103e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    int         fSeed;
104e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    uint8_t     fLatticeSelector[kBlockSize];
105e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    uint16_t    fNoise[4][kBlockSize][2];
106e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkPoint     fGradient[4][kBlockSize];
107e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkISize     fTileSize;
108e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkVector    fBaseFrequency;
109e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    StitchData  fStitchDataInit;
110e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
111e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comprivate:
112e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
113f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco#if SK_SUPPORT_GPU
114fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    SkBitmap   fPermutationsBitmap;
115fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    SkBitmap   fNoiseBitmap;
116fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org#endif
117e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
118e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    inline int random()  {
119e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        static const int gRandAmplitude = 16807; // 7**5; primitive root of m
120e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        static const int gRandQ = 127773; // m / a
121e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        static const int gRandR = 2836; // m % a
122e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
123e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
124e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        if (result <= 0)
125e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            result += kRandMaximum;
126e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        fSeed = result;
127e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        return result;
128e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
129e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
130fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    // Only called once. Could be part of the constructor.
131e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    void init(SkScalar seed)
132e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
133e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
134e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
135857e320300372dab938c0dbffadc3c2c8a893b92senorblanco@chromium.org        // According to the SVG spec, we must truncate (not round) the seed value.
136857e320300372dab938c0dbffadc3c2c8a893b92senorblanco@chromium.org        fSeed = SkScalarTruncToInt(seed);
137e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // The seed value clamp to the range [1, kRandMaximum - 1].
138e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        if (fSeed <= 0) {
139e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
140e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
141e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        if (fSeed > kRandMaximum - 1) {
142e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            fSeed = kRandMaximum - 1;
143e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
144e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        for (int channel = 0; channel < 4; ++channel) {
145e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            for (int i = 0; i < kBlockSize; ++i) {
146e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fLatticeSelector[i] = i;
147e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fNoise[channel][i][0] = (random() % (2 * kBlockSize));
148e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fNoise[channel][i][1] = (random() % (2 * kBlockSize));
149e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            }
150e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
151e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        for (int i = kBlockSize - 1; i > 0; --i) {
152e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            int k = fLatticeSelector[i];
153e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            int j = random() % kBlockSize;
154e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            SkASSERT(j >= 0);
155e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            SkASSERT(j < kBlockSize);
156e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            fLatticeSelector[i] = fLatticeSelector[j];
157e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            fLatticeSelector[j] = k;
158e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
159e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
160e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // Perform the permutations now
161e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        {
162e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            // Copy noise data
163e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            uint16_t noise[4][kBlockSize][2];
164e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            for (int i = 0; i < kBlockSize; ++i) {
165e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                for (int channel = 0; channel < 4; ++channel) {
166e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                    for (int j = 0; j < 2; ++j) {
167e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                        noise[channel][i][j] = fNoise[channel][i][j];
168e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                    }
169e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                }
170e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            }
171e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            // Do permutations on noise data
172e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            for (int i = 0; i < kBlockSize; ++i) {
173e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                for (int channel = 0; channel < 4; ++channel) {
174e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                    for (int j = 0; j < 2; ++j) {
175e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                        fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
176e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                    }
177e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                }
178e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            }
179e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
180e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
181e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // Half of the largest possible value for 16 bit unsigned int
1824b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org        static const SkScalar gHalfMax16bits = 32767.5f;
183e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
184e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // Compute gradients from permutated noise data
185e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        for (int channel = 0; channel < 4; ++channel) {
186e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            for (int i = 0; i < kBlockSize; ++i) {
187e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fGradient[channel][i] = SkPoint::Make(
188e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                    SkScalarMul(SkIntToScalar(fNoise[channel][i][0] - kBlockSize),
189e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                gInvBlockSizef),
190cff0243b0ff1de25b3d99e2bf15a30c0e0a31261skia.committer@gmail.com                    SkScalarMul(SkIntToScalar(fNoise[channel][i][1] - kBlockSize),
191e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                gInvBlockSizef));
192e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fGradient[channel][i].normalize();
193e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                // Put the normalized gradient back into the noise data
194e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fNoise[channel][i][0] = SkScalarRoundToInt(SkScalarMul(
195d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com                    fGradient[channel][i].fX + SK_Scalar1, gHalfMax16bits));
196e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fNoise[channel][i][1] = SkScalarRoundToInt(SkScalarMul(
197d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com                    fGradient[channel][i].fY + SK_Scalar1, gHalfMax16bits));
198e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            }
199e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
200e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
201e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
202fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    // Only called once. Could be part of the constructor.
203e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    void stitch() {
204e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkScalar tileWidth  = SkIntToScalar(fTileSize.width());
205e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkScalar tileHeight = SkIntToScalar(fTileSize.height());
206e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkASSERT(tileWidth > 0 && tileHeight > 0);
207e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // When stitching tiled turbulence, the frequencies must be adjusted
208e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // so that the tile borders will be continuous.
209e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        if (fBaseFrequency.fX) {
2108015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com            SkScalar lowFrequencx =
2118015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com                SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
2128015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com            SkScalar highFrequencx =
2138015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com                SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
214e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            // BaseFrequency should be non-negative according to the standard.
21580ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            if (fBaseFrequency.fX / lowFrequencx < highFrequencx / fBaseFrequency.fX) {
216e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fBaseFrequency.fX = lowFrequencx;
217e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            } else {
218e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fBaseFrequency.fX = highFrequencx;
219e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            }
220e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
221e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        if (fBaseFrequency.fY) {
2228015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com            SkScalar lowFrequency =
2238015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com                SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
2248015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com            SkScalar highFrequency =
2258015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com                SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
22680ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            if (fBaseFrequency.fY / lowFrequency < highFrequency / fBaseFrequency.fY) {
227e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fBaseFrequency.fY = lowFrequency;
228e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            } else {
229e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                fBaseFrequency.fY = highFrequency;
230e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            }
231e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
232e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // Set up TurbulenceInitial stitch values.
233e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        fStitchDataInit.fWidth  =
2348015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com            SkScalarRoundToInt(tileWidth * fBaseFrequency.fX);
235e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        fStitchDataInit.fWrapX  = kPerlinNoise + fStitchDataInit.fWidth;
236e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        fStitchDataInit.fHeight =
2378015cdd8fa5694e52b70e728bcdc6b35d739b819reed@google.com            SkScalarRoundToInt(tileHeight * fBaseFrequency.fY);
238e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        fStitchDataInit.fWrapY  = kPerlinNoise + fStitchDataInit.fHeight;
239e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
240e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
241fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.orgpublic:
242e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
243f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco#if SK_SUPPORT_GPU
244fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
245fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org
246fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org    const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
247fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org#endif
248e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com};
249e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
250e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comSkShader* SkPerlinNoiseShader::CreateFractalNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY,
251e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                                  int numOctaves, SkScalar seed,
252e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                                  const SkISize* tileSize) {
253e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return SkNEW_ARGS(SkPerlinNoiseShader, (kFractalNoise_Type, baseFrequencyX, baseFrequencyY,
254e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                            numOctaves, seed, tileSize));
255e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
256e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
2579fbbcca1c958e6df2cff24d3ccdb7ebd89b8486bcommit-bot@chromium.orgSkShader* SkPerlinNoiseShader::CreateTurbulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY,
258e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                              int numOctaves, SkScalar seed,
259e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                              const SkISize* tileSize) {
260e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return SkNEW_ARGS(SkPerlinNoiseShader, (kTurbulence_Type, baseFrequencyX, baseFrequencyY,
261e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                            numOctaves, seed, tileSize));
262e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
263e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
264e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comSkPerlinNoiseShader::SkPerlinNoiseShader(SkPerlinNoiseShader::Type type,
265e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                         SkScalar baseFrequencyX,
266e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                         SkScalar baseFrequencyY,
267e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                         int numOctaves,
268e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                         SkScalar seed,
269e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                         const SkISize* tileSize)
270e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com  : fType(type)
271e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com  , fBaseFrequencyX(baseFrequencyX)
272e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com  , fBaseFrequencyY(baseFrequencyY)
273ce33d60187718e7bb01944ee130c9f5d9fb335eccommit-bot@chromium.org  , fNumOctaves(numOctaves > 255 ? 255 : numOctaves/*[0,255] octaves allowed*/)
274e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com  , fSeed(seed)
275fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org  , fTileSize(NULL == tileSize ? SkISize::Make(0, 0) : *tileSize)
276fd5c9a6e04ba31a82670d281b03b9c4a3f9b6e3ccommit-bot@chromium.org  , fStitchTiles(!fTileSize.isEmpty())
277e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com{
278e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkASSERT(numOctaves >= 0 && numOctaves < 256);
279e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
280e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
281e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comSkPerlinNoiseShader::~SkPerlinNoiseShader() {
282e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
283e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
2849fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkPerlinNoiseShader::CreateProc(SkReadBuffer& buffer) {
2859fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    Type type = (Type)buffer.readInt();
2869fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkScalar freqX = buffer.readScalar();
2879fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkScalar freqY = buffer.readScalar();
2889fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    int octaves = buffer.readInt();
2899fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkScalar seed = buffer.readScalar();
2909fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkISize tileSize;
2919fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    tileSize.fWidth = buffer.readInt();
2929fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    tileSize.fHeight = buffer.readInt();
2939fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
2949fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    switch (type) {
2959fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        case kFractalNoise_Type:
2969fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed            return SkPerlinNoiseShader::CreateFractalNoise(freqX, freqY, octaves, seed, &tileSize);
2979fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        case kTurbulence_Type:
2989fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed            return SkPerlinNoiseShader::CreateTubulence(freqX, freqY, octaves, seed, &tileSize);
2999fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        default:
3009fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed            return NULL;
3019fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
3029fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
3039fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
3048b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkPerlinNoiseShader::flatten(SkWriteBuffer& buffer) const {
305e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeInt((int) fType);
306e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeScalar(fBaseFrequencyX);
307e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeScalar(fBaseFrequencyY);
308e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeInt(fNumOctaves);
309e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeScalar(fSeed);
310e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeInt(fTileSize.fWidth);
311e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    buffer.writeInt(fTileSize.fHeight);
312e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
313e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
31487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::noise2D(
315ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
316e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    struct Noise {
317e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        int noisePositionIntegerValue;
318ce6a354e121915c2925e545e7df2929492d69d50senorblanco        int nextNoisePositionIntegerValue;
319e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkScalar noisePositionFractionValue;
320e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        Noise(SkScalar component)
321e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        {
322e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            SkScalar position = component + kPerlinNoise;
323e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            noisePositionIntegerValue = SkScalarFloorToInt(position);
324e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
325ce6a354e121915c2925e545e7df2929492d69d50senorblanco            nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
326e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
327e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    };
328e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    Noise noiseX(noiseVector.x());
329e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    Noise noiseY(noiseVector.y());
330e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar u, v;
33187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader);
332e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // If stitching, adjust lattice points accordingly.
33387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    if (perlinNoiseShader.fStitchTiles) {
334e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        noiseX.noisePositionIntegerValue =
335e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
336e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        noiseY.noisePositionIntegerValue =
337e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
338ce6a354e121915c2925e545e7df2929492d69d50senorblanco        noiseX.nextNoisePositionIntegerValue =
339ce6a354e121915c2925e545e7df2929492d69d50senorblanco            checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
340ce6a354e121915c2925e545e7df2929492d69d50senorblanco        noiseY.nextNoisePositionIntegerValue =
341ce6a354e121915c2925e545e7df2929492d69d50senorblanco            checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
342e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
343e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    noiseX.noisePositionIntegerValue &= kBlockMask;
344e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    noiseY.noisePositionIntegerValue &= kBlockMask;
345ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseX.nextNoisePositionIntegerValue &= kBlockMask;
346ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseY.nextNoisePositionIntegerValue &= kBlockMask;
347ce6a354e121915c2925e545e7df2929492d69d50senorblanco    int i =
348ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        fPaintingData->fLatticeSelector[noiseX.noisePositionIntegerValue];
349ce6a354e121915c2925e545e7df2929492d69d50senorblanco    int j =
350ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        fPaintingData->fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
351ce6a354e121915c2925e545e7df2929492d69d50senorblanco    int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
352ce6a354e121915c2925e545e7df2929492d69d50senorblanco    int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
353ce6a354e121915c2925e545e7df2929492d69d50senorblanco    int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
354ce6a354e121915c2925e545e7df2929492d69d50senorblanco    int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
355e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
356e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
357e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
358e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
359e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                          noiseY.noisePositionFractionValue); // Offset (0,0)
360ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    u = fPaintingData->fGradient[channel][b00].dot(fractionValue);
361e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
362ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    v = fPaintingData->fGradient[channel][b10].dot(fractionValue);
363e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar a = SkScalarInterp(u, v, sx);
364e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
365ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    v = fPaintingData->fGradient[channel][b11].dot(fractionValue);
366e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
367ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    u = fPaintingData->fGradient[channel][b01].dot(fractionValue);
368e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar b = SkScalarInterp(u, v, sx);
369e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return SkScalarInterp(a, b, sy);
370e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
371e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
37287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
373ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        int channel, StitchData& stitchData, const SkPoint& point) const {
37487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader);
37587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    if (perlinNoiseShader.fStitchTiles) {
376e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // Set up TurbulenceInitial stitch values.
377ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        stitchData = fPaintingData->fStitchDataInit;
378e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
379e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar turbulenceFunctionResult = 0;
380ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), fPaintingData->fBaseFrequency.fX),
381ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco                                      SkScalarMul(point.y(), fPaintingData->fBaseFrequency.fY)));
382e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar ratio = SK_Scalar1;
38387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
384ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        SkScalar noise = noise2D(channel, stitchData, noiseVector);
38580ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed        SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
38680ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed                            noise : SkScalarAbs(noise);
38780ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed        turbulenceFunctionResult += numer / ratio;
388e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        noiseVector.fX *= 2;
389e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        noiseVector.fY *= 2;
390e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        ratio *= 2;
39187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        if (perlinNoiseShader.fStitchTiles) {
392e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            // Update stitch values
393e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            stitchData.fWidth  *= 2;
394e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            stitchData.fWrapX   = stitchData.fWidth + kPerlinNoise;
395e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            stitchData.fHeight *= 2;
396e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            stitchData.fWrapY   = stitchData.fHeight + kPerlinNoise;
397e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        }
398e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
399e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
400e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
401e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // by fractalNoise and (turbulenceFunctionResult) by turbulence.
40287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    if (perlinNoiseShader.fType == kFractalNoise_Type) {
403e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        turbulenceFunctionResult =
404e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            SkScalarMul(turbulenceFunctionResult, SK_ScalarHalf) + SK_ScalarHalf;
405e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
406e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
407e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    if (channel == 3) { // Scale alpha by paint value
40880ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed        turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
409e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
410e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
411e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Clamp result
412e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1);
413e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
414e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
41587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkPMColor SkPerlinNoiseShader::PerlinNoiseShaderContext::shade(
41687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        const SkPoint& point, StitchData& stitchData) const {
417e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkPoint newPoint;
418a8d95f899bf3fe404d3cd5c357531ff852c15b29senorblanco@chromium.org    fMatrix.mapPoints(&newPoint, &point, 1);
419e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
420e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
421e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
422e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    U8CPU rgba[4];
423e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    for (int channel = 3; channel >= 0; --channel) {
424e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        rgba[channel] = SkScalarFloorToInt(255 *
425ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco            calculateTurbulenceValueForPoint(channel, stitchData, newPoint));
426e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
427e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
428e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
429e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
430ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.orgSkShader::Context* SkPerlinNoiseShader::onCreateContext(const ContextRec& rec,
431ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org                                                        void* storage) const {
432e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    return SkNEW_PLACEMENT_ARGS(storage, PerlinNoiseShaderContext, (*this, rec));
43387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
43487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
43587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgsize_t SkPerlinNoiseShader::contextSize() const {
43687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    return sizeof(PerlinNoiseShaderContext);
43787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
43887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
43987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkPerlinNoiseShader::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
440e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org        const SkPerlinNoiseShader& shader, const ContextRec& rec)
441e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    : INHERITED(shader, rec)
44287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org{
443e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    SkMatrix newMatrix = *rec.fMatrix;
444b67b8e6052bf5567eb3f9726dda99a6b260dfb05reed@google.com    newMatrix.preConcat(shader.getLocalMatrix());
445b67b8e6052bf5567eb3f9726dda99a6b260dfb05reed@google.com    if (rec.fLocalMatrix) {
446b67b8e6052bf5567eb3f9726dda99a6b260dfb05reed@google.com        newMatrix.preConcat(*rec.fLocalMatrix);
447b67b8e6052bf5567eb3f9726dda99a6b260dfb05reed@google.com    }
448a8d95f899bf3fe404d3cd5c357531ff852c15b29senorblanco@chromium.org    // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
449a8d95f899bf3fe404d3cd5c357531ff852c15b29senorblanco@chromium.org    // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
450ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    fMatrix.setTranslate(-newMatrix.getTranslateX() + SK_Scalar1, -newMatrix.getTranslateY() + SK_Scalar1);
451ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    fPaintingData = SkNEW_ARGS(PaintingData, (shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX, shader.fBaseFrequencyY, newMatrix));
452ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco}
453ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco
454ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblancoSkPerlinNoiseShader::PerlinNoiseShaderContext::~PerlinNoiseShaderContext() {
455ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    SkDELETE(fPaintingData);
456e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
457e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
45887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkPerlinNoiseShader::PerlinNoiseShaderContext::shadeSpan(
45987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        int x, int y, SkPMColor result[], int count) {
460e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
461e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    StitchData stitchData;
462e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    for (int i = 0; i < count; ++i) {
463e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        result[i] = shade(point, stitchData);
464e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        point.fX += SK_Scalar1;
465e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
466e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
467e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
46887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkPerlinNoiseShader::PerlinNoiseShaderContext::shadeSpan16(
46987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        int x, int y, uint16_t result[], int count) {
470e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
471e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    StitchData stitchData;
472e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    DITHER_565_SCAN(y);
473e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    for (int i = 0; i < count; ++i) {
474e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        unsigned dither = DITHER_VALUE(x);
475e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        result[i] = SkDitherRGB32To565(shade(point, stitchData), dither);
476e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        DITHER_INC_X(x);
477e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        point.fX += SK_Scalar1;
478e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
479e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
480e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
481e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com/////////////////////////////////////////////////////////////////////
482e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
483344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org#if SK_SUPPORT_GPU
484e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
485b0a8a377f832c59cee939ad721e1f87d378b7142joshualittclass GrGLPerlinNoise : public GrGLFragmentProcessor {
4864775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.compublic:
487eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    GrGLPerlinNoise(const GrProcessor&);
4884775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com    virtual ~GrGLPerlinNoise() {}
489e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
4901598899975ecc85b003a59740b588d1ddbcedb09joshualitt    virtual void emitCode(GrGLFPBuilder*,
491b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                          const GrFragmentProcessor&,
492e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                          const char* outputColor,
493e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                          const char* inputColor,
49477af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                          const TransformedCoordsArray&,
49536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                          const TextureSamplerArray&) override;
496e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
49736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
4984775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com
499cfc18867d982119d9dc2888bf09f1093012daaddjvanverth    static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
5004775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com
501f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblancoprivate:
502e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
5037510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    GrGLProgramDataManager::UniformHandle fStitchDataUni;
5047510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    SkPerlinNoiseShader::Type             fType;
5057510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    bool                                  fStitchTiles;
5067510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    int                                   fNumOctaves;
5077510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    GrGLProgramDataManager::UniformHandle fBaseFrequencyUni;
5087510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    GrGLProgramDataManager::UniformHandle fAlphaUni;
509e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
510e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comprivate:
511b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    typedef GrGLFragmentProcessor INHERITED;
512e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com};
513e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
514e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com/////////////////////////////////////////////////////////////////////
515e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
516b0a8a377f832c59cee939ad721e1f87d378b7142joshualittclass GrPerlinNoiseEffect : public GrFragmentProcessor {
517e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.compublic:
518b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    static GrFragmentProcessor* Create(SkPerlinNoiseShader::Type type,
519b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       int numOctaves, bool stitchTiles,
520b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       SkPerlinNoiseShader::PaintingData* paintingData,
521b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       GrTexture* permutationsTexture, GrTexture* noiseTexture,
522b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       const SkMatrix& matrix, uint8_t alpha) {
52355fad7af61c21d502acb9891d631e8aa29e3628cbsalomon        return SkNEW_ARGS(GrPerlinNoiseEffect, (type, numOctaves, stitchTiles, paintingData,
52455fad7af61c21d502acb9891d631e8aa29e3628cbsalomon                                                permutationsTexture, noiseTexture, matrix, alpha));
525e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
526e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
527ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    virtual ~GrPerlinNoiseEffect() {
528ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        SkDELETE(fPaintingData);
529ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    }
530e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
53136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "PerlinNoise"; }
532eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
533cfc18867d982119d9dc2888bf09f1093012daaddjvanverth    virtual void getGLProcessorKey(const GrGLSLCaps& caps,
53436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                                   GrProcessorKeyBuilder* b) const override {
535eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        GrGLPerlinNoise::GenKey(*this, caps, b);
536eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
537eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
53836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    GrGLFragmentProcessor* createGLInstance() const override {
539eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        return SkNEW_ARGS(GrGLPerlinNoise, (*this));
540e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
541eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
542ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    const SkPerlinNoiseShader::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
543e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
544f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    SkPerlinNoiseShader::Type type() const { return fType; }
545f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    bool stitchTiles() const { return fStitchTiles; }
546ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
547f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    int numOctaves() const { return fNumOctaves; }
548f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
549f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    uint8_t alpha() const { return fAlpha; }
550f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco
551e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comprivate:
55236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onIsEqual(const GrFragmentProcessor& sBase) const override {
55349586bec7383d4ccb81f85f8e2dc4162e2d4f6a8joshualitt        const GrPerlinNoiseEffect& s = sBase.cast<GrPerlinNoiseEffect>();
554f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco        return fType == s.fType &&
555ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco               fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
556f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco               fNumOctaves == s.fNumOctaves &&
557f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco               fStitchTiles == s.fStitchTiles &&
558f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco               fAlpha == s.fAlpha &&
559ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco               fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
560e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
561e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
56236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
563605dd0fbce9dbb2a0d3313e13e161f2bd54870d7egdaniel        inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput);
5641a8ecdfb73a15de600d5779b75d7c4b61863c50begdaniel    }
5651a8ecdfb73a15de600d5779b75d7c4b61863c50begdaniel
566ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    GrPerlinNoiseEffect(SkPerlinNoiseShader::Type type,
567e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                        int numOctaves, bool stitchTiles,
568ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco                        SkPerlinNoiseShader::PaintingData* paintingData,
569e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                        GrTexture* permutationsTexture, GrTexture* noiseTexture,
570e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                        const SkMatrix& matrix, uint8_t alpha)
571f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco      : fType(type)
572f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco      , fNumOctaves(numOctaves)
573f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco      , fStitchTiles(stitchTiles)
574f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco      , fAlpha(alpha)
5754775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com      , fPermutationsAccess(permutationsTexture)
576e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com      , fNoiseAccess(noiseTexture)
577ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco      , fPaintingData(paintingData) {
578eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        this->initClassID<GrPerlinNoiseEffect>();
579e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        this->addTextureAccess(&fPermutationsAccess);
580e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        this->addTextureAccess(&fNoiseAccess);
581ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        fCoordTransform.reset(kLocal_GrCoordSet, matrix);
582f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco        this->addCoordTransform(&fCoordTransform);
583e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
584e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
585b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
586e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
587f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    SkPerlinNoiseShader::Type       fType;
588f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    GrCoordTransform                fCoordTransform;
589f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    int                             fNumOctaves;
590f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    bool                            fStitchTiles;
591f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco    uint8_t                         fAlpha;
592e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    GrTextureAccess                 fPermutationsAccess;
593e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    GrTextureAccess                 fNoiseAccess;
594ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    SkPerlinNoiseShader::PaintingData *fPaintingData;
595e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
5964775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.comprivate:
597b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    typedef GrFragmentProcessor INHERITED;
598e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com};
599e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
600e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com/////////////////////////////////////////////////////////////////////
601b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoiseEffect);
602e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
603b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrFragmentProcessor* GrPerlinNoiseEffect::TestCreate(SkRandom* random,
604b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                     GrContext* context,
605b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                     const GrDrawTargetCaps&,
606b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                     GrTexture**) {
607423ac13f351b22308d3b1d039ab4859540be0b9dsugoi@google.com    int      numOctaves = random->nextRangeU(2, 10);
608e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    bool     stitchTiles = random->nextBool();
609e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkScalar seed = SkIntToScalar(random->nextU());
610e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkISize  tileSize = SkISize::Make(random->nextRangeU(4, 4096), random->nextRangeU(4, 4096));
6114b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    SkScalar baseFrequencyX = random->nextRangeScalar(0.01f,
6124b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org                                                      0.99f);
6134b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    SkScalar baseFrequencyY = random->nextRangeScalar(0.01f,
6144b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org                                                      0.99f);
615e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
616e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkShader* shader = random->nextBool() ?
617e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkPerlinNoiseShader::CreateFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
618e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                                stitchTiles ? &tileSize : NULL) :
6199fbbcca1c958e6df2cff24d3ccdb7ebd89b8486bcommit-bot@chromium.org        SkPerlinNoiseShader::CreateTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
620e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                                             stitchTiles ? &tileSize : NULL);
621e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
622e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkPaint paint;
62383d081ae1d731b5039e99823620f5e287542ee39bsalomon    GrColor paintColor;
624b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GrFragmentProcessor* effect;
6255531d51ce7426bdae7563547326fcf0bf926a083joshualitt    SkAssertResult(shader->asFragmentProcessor(context, paint,
6264eaf9cef5a76098f78efac30beb966ac833d32c2joshualitt                                               GrTest::TestMatrix(random), NULL,
6275531d51ce7426bdae7563547326fcf0bf926a083joshualitt                                               &paintColor, &effect));
628e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
629e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkDELETE(shader);
630e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
631e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    return effect;
632e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
6334775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com
634eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualittGrGLPerlinNoise::GrGLPerlinNoise(const GrProcessor& processor)
635eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt  : fType(processor.cast<GrPerlinNoiseEffect>().type())
636b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt  , fStitchTiles(processor.cast<GrPerlinNoiseEffect>().stitchTiles())
637b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt  , fNumOctaves(processor.cast<GrPerlinNoiseEffect>().numOctaves()) {
6384775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com}
6394775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com
6401598899975ecc85b003a59740b588d1ddbcedb09joshualittvoid GrGLPerlinNoise::emitCode(GrGLFPBuilder* builder,
641b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                               const GrFragmentProcessor&,
642e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                               const char* outputColor,
643e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                               const char* inputColor,
64477af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                               const TransformedCoordsArray& coords,
645e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                               const TextureSamplerArray& samplers) {
646e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    sk_ignore_unused_variable(inputColor);
647e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
64829bee0fe657fabf7c396502b69c9167fba13eaaaegdaniel    GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
64930ba436f04e61d4505fb854d5fc56079636e0788joshualitt    SkString vCoords = fsBuilder->ensureFSCoords2D(coords, 0);
650e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
65130ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fBaseFrequencyUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
652422f56f6e51c2f6a6ab425573b4d790f0157f883bsalomon                                            kVec2f_GrSLType, kDefault_GrSLPrecision,
653422f56f6e51c2f6a6ab425573b4d790f0157f883bsalomon                                            "baseFrequency");
654e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* baseFrequencyUni = builder->getUniformCStr(fBaseFrequencyUni);
65530ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fAlphaUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
656422f56f6e51c2f6a6ab425573b4d790f0157f883bsalomon                                    kFloat_GrSLType, kDefault_GrSLPrecision,
657422f56f6e51c2f6a6ab425573b4d790f0157f883bsalomon                                    "alpha");
658e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* alphaUni = builder->getUniformCStr(fAlphaUni);
659e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
660e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* stitchDataUni = NULL;
661e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    if (fStitchTiles) {
66230ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fStitchDataUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
663422f56f6e51c2f6a6ab425573b4d790f0157f883bsalomon                                             kVec2f_GrSLType, kDefault_GrSLPrecision,
664422f56f6e51c2f6a6ab425573b4d790f0157f883bsalomon                                             "stitchData");
665e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        stitchDataUni = builder->getUniformCStr(fStitchDataUni);
666e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
667e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
668d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
669d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    const char* chanCoordR  = "0.125";
670d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    const char* chanCoordG  = "0.375";
671d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    const char* chanCoordB  = "0.625";
672d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    const char* chanCoordA  = "0.875";
673d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    const char* chanCoord   = "chanCoord";
674e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* stitchData  = "stitchData";
675e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* ratio       = "ratio";
676e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* noiseVec    = "noiseVec";
677e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* noiseSmooth = "noiseSmooth";
678ce6a354e121915c2925e545e7df2929492d69d50senorblanco    const char* floorVal    = "floorVal";
679e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* fractVal    = "fractVal";
680e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* uv          = "uv";
681e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* ab          = "ab";
682e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* latticeIdx  = "latticeIdx";
683ce6a354e121915c2925e545e7df2929492d69d50senorblanco    const char* bcoords     = "bcoords";
684e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* lattice     = "lattice";
685e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* inc8bit     = "0.00390625";  // 1.0 / 256.0
686e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
687e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // [-1,1] vector and perform a dot product between that vector and the provided vector.
688e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const char* dotLattice  = "dot(((%s.ga + %s.rb * vec2(%s)) * vec2(2.0) - vec2(1.0)), %s);";
689e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
690d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    // Add noise function
691d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    static const GrGLShaderVar gPerlinNoiseArgs[] =  {
692d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        GrGLShaderVar(chanCoord, kFloat_GrSLType),
6939839320ae17ab1c2182dc144db5ba94caa1bde56commit-bot@chromium.org        GrGLShaderVar(noiseVec, kVec2f_GrSLType)
694d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    };
695e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
696d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    static const GrGLShaderVar gPerlinNoiseStitchArgs[] =  {
697d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        GrGLShaderVar(chanCoord, kFloat_GrSLType),
6989839320ae17ab1c2182dc144db5ba94caa1bde56commit-bot@chromium.org        GrGLShaderVar(noiseVec, kVec2f_GrSLType),
6999839320ae17ab1c2182dc144db5ba94caa1bde56commit-bot@chromium.org        GrGLShaderVar(stitchData, kVec2f_GrSLType)
700d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    };
701e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
702d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    SkString noiseCode;
703e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
704ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\tvec4 %s;\n", floorVal);
705ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
706ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\t%s.zw = %s.xy + vec2(1.0);\n", floorVal, floorVal);
707ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\tvec2 %s = fract(%s);\n", fractVal, noiseVec);
708e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
709e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // smooth curve : t * t * (3 - 2 * t)
710ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\n\tvec2 %s = %s * %s * (vec2(3.0) - vec2(2.0) * %s);",
711ce6a354e121915c2925e545e7df2929492d69d50senorblanco        noiseSmooth, fractVal, fractVal, fractVal);
712e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
713e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Adjust frequencies if we're stitching tiles
714e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    if (fStitchTiles) {
7159839320ae17ab1c2182dc144db5ba94caa1bde56commit-bot@chromium.org        noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
716ce6a354e121915c2925e545e7df2929492d69d50senorblanco            floorVal, stitchData, floorVal, stitchData);
7179839320ae17ab1c2182dc144db5ba94caa1bde56commit-bot@chromium.org        noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
718ce6a354e121915c2925e545e7df2929492d69d50senorblanco            floorVal, stitchData, floorVal, stitchData);
719ce6a354e121915c2925e545e7df2929492d69d50senorblanco        noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
720ce6a354e121915c2925e545e7df2929492d69d50senorblanco            floorVal, stitchData, floorVal, stitchData);
721ce6a354e121915c2925e545e7df2929492d69d50senorblanco        noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
722ce6a354e121915c2925e545e7df2929492d69d50senorblanco            floorVal, stitchData, floorVal, stitchData);
723e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
724e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
725e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Get texture coordinates and normalize
726ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / vec4(256.0));\n",
727ce6a354e121915c2925e545e7df2929492d69d50senorblanco        floorVal, floorVal);
728e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
729e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Get permutation for x
730e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
731e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkString xCoords("");
732ce6a354e121915c2925e545e7df2929492d69d50senorblanco        xCoords.appendf("vec2(%s.x, 0.5)", floorVal);
733e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
734d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf("\n\tvec2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
73530ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->appendTextureLookup(&noiseCode, samplers[0], xCoords.c_str(), kVec2f_GrSLType);
736d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.append(".r;");
737e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
738e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
739e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Get permutation for x + 1
740e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
741e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkString xCoords("");
742ce6a354e121915c2925e545e7df2929492d69d50senorblanco        xCoords.appendf("vec2(%s.z, 0.5)", floorVal);
743e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
744d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf("\n\t%s.y = ", latticeIdx);
74530ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->appendTextureLookup(&noiseCode, samplers[0], xCoords.c_str(), kVec2f_GrSLType);
746d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.append(".r;");
747e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
748e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
749344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org#if defined(SK_BUILD_FOR_ANDROID)
750344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
751344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
752344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
753344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    // (or 0.484368 here). The following rounding operation prevents these precision issues from
754344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    // affecting the result of the noise by making sure that we only have multiples of 1/255.
755344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    // (Note that 1/255 is about 0.003921569, which is the value used here).
756344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org    noiseCode.appendf("\n\t%s = floor(%s * vec2(255.0) + vec2(0.5)) * vec2(0.003921569);",
757344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org                      latticeIdx, latticeIdx);
758344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org#endif
759344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org
760e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Get (x,y) coordinates with the permutated x
761ce6a354e121915c2925e545e7df2929492d69d50senorblanco    noiseCode.appendf("\n\tvec4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
762e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
763d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\n\tvec2 %s;", uv);
764e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute u, at offset (0,0)
765e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
766e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkString latticeCoords("");
767ce6a354e121915c2925e545e7df2929492d69d50senorblanco        latticeCoords.appendf("vec2(%s.x, %s)", bcoords, chanCoord);
768d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf("\n\tvec4 %s = ", lattice);
76930ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
770d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            kVec2f_GrSLType);
771d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
772d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
773e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
774e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
775d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
776e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute v, at offset (-1,0)
777e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
778e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkString latticeCoords("");
779ce6a354e121915c2925e545e7df2929492d69d50senorblanco        latticeCoords.appendf("vec2(%s.y, %s)", bcoords, chanCoord);
780344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org        noiseCode.append("\n\tlattice = ");
78130ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
782d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            kVec2f_GrSLType);
783d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
784d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
785e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
786e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
787e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute 'a' as a linear interpolation of 'u' and 'v'
788d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\tvec2 %s;", ab);
789d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\t%s.x = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth);
790e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
791d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
792e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute v, at offset (-1,-1)
793e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
794e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkString latticeCoords("");
795ce6a354e121915c2925e545e7df2929492d69d50senorblanco        latticeCoords.appendf("vec2(%s.w, %s)", bcoords, chanCoord);
796344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org        noiseCode.append("\n\tlattice = ");
79730ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
798d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            kVec2f_GrSLType);
799d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
800d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
801e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
802e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
803d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
804e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute u, at offset (0,-1)
805e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    {
806e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        SkString latticeCoords("");
807ce6a354e121915c2925e545e7df2929492d69d50senorblanco        latticeCoords.appendf("vec2(%s.z, %s)", bcoords, chanCoord);
808344cf45a40c7de3c4664f8a048d4017af88adfeecommit-bot@chromium.org        noiseCode.append("\n\tlattice = ");
80930ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
810d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            kVec2f_GrSLType);
811d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
812d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
813e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
814e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
815e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute 'b' as a linear interpolation of 'u' and 'v'
816d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\t%s.y = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth);
817e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Compute the noise as a linear interpolation of 'a' and 'b'
818d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
819d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com
820d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    SkString noiseFuncName;
821d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    if (fStitchTiles) {
82230ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->emitFunction(kFloat_GrSLType,
82374a3a2135ca82ab9324b7e499caa3280348a4fdacommit-bot@chromium.org                                "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
82474a3a2135ca82ab9324b7e499caa3280348a4fdacommit-bot@chromium.org                                gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
825d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    } else {
82630ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->emitFunction(kFloat_GrSLType,
82774a3a2135ca82ab9324b7e499caa3280348a4fdacommit-bot@chromium.org                                "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
82874a3a2135ca82ab9324b7e499caa3280348a4fdacommit-bot@chromium.org                                gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
829d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    }
830e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
831d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    // There are rounding errors if the floor operation is not performed here
83230ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\tvec2 %s = floor(%s.xy) * %s;",
833ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco                           noiseVec, vCoords.c_str(), baseFrequencyUni);
834e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
835d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    // Clear the color accumulator
83630ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t%s = vec4(0.0);", outputColor);
837e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
838e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    if (fStitchTiles) {
839d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com        // Set up TurbulenceInitial stitch values.
84030ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("\n\t\tvec2 %s = %s;", stitchData, stitchDataUni);
841e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
842e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
84330ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\tfloat %s = 1.0;", ratio);
844d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com
845d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    // Loop over all octaves
84630ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\tfor (int octave = 0; octave < %d; ++octave) {", fNumOctaves);
847d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com
84830ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t\t%s += ", outputColor);
849d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    if (fType != SkPerlinNoiseShader::kFractalNoise_Type) {
85030ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend("abs(");
851d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    }
852d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    if (fStitchTiles) {
85330ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf(
854d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            "vec4(\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s),"
855d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com                 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
856d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
857d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
858d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
859d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
860d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    } else {
86130ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf(
862d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            "vec4(\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s),"
863d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com                 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
864d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordR, noiseVec,
865d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordG, noiseVec,
866d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordB, noiseVec,
867d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com            noiseFuncName.c_str(), chanCoordA, noiseVec);
868d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    }
869d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    if (fType != SkPerlinNoiseShader::kFractalNoise_Type) {
87030ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf(")"); // end of "abs("
871d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    }
87230ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf(" * %s;", ratio);
873d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com
87430ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", noiseVec);
87530ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
876d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com
877d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    if (fStitchTiles) {
87830ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", stitchData);
879d537af50fcd013aa69fddc24afb1b997408ec762sugoi@google.com    }
88030ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
881e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
882e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    if (fType == SkPerlinNoiseShader::kFractalNoise_Type) {
883e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
884e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        // by fractalNoise and (turbulenceFunctionResult) by turbulence.
88530ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("\n\t\t%s = %s * vec4(0.5) + vec4(0.5);", outputColor, outputColor);
886e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
887e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
88830ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t%s.a *= %s;", outputColor, alphaUni);
889e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
890e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Clamp values
89130ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", outputColor, outputColor);
892e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
893e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Pre-multiply the result
89430ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\n\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n",
895e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com                  outputColor, outputColor, outputColor, outputColor);
896e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
897e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
898cfc18867d982119d9dc2888bf09f1093012daaddjvanverthvoid GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrGLSLCaps&,
899b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                             GrProcessorKeyBuilder* b) {
900b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrPerlinNoiseEffect& turbulence = processor.cast<GrPerlinNoiseEffect>();
901e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
90263e99f7a03b2ac90ae7a00232674fd39c0bdcc68bsalomon    uint32_t key = turbulence.numOctaves();
903e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
904e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    key = key << 3; // Make room for next 3 bits
905e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
906e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    switch (turbulence.type()) {
907e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        case SkPerlinNoiseShader::kFractalNoise_Type:
908e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            key |= 0x1;
909e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            break;
910e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        case SkPerlinNoiseShader::kTurbulence_Type:
911e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            key |= 0x2;
912e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            break;
913e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        default:
914e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            // leave key at 0
915e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            break;
916e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
917e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
918e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    if (turbulence.stitchTiles()) {
919e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        key |= 0x4; // Flip the 3rd bit if tile stitching is on
920e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
921e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
92263e99f7a03b2ac90ae7a00232674fd39c0bdcc68bsalomon    b->add32(key);
923e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
924e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
925b0a8a377f832c59cee939ad721e1f87d378b7142joshualittvoid GrGLPerlinNoise::setData(const GrGLProgramDataManager& pdman, const GrProcessor& processor) {
926b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    INHERITED::setData(pdman, processor);
927f3b50276a4ad71c9e8ba13d752a5db0c073cae2csenorblanco
928b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrPerlinNoiseEffect& turbulence = processor.cast<GrPerlinNoiseEffect>();
929e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
930e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    const SkVector& baseFrequency = turbulence.baseFrequency();
9317510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
93280ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed    pdman.set1f(fAlphaUni, SkIntToScalar(turbulence.alpha()) / 255);
933e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
9344775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com    if (turbulence.stitchTiles()) {
9354775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com        const SkPerlinNoiseShader::StitchData& stitchData = turbulence.stitchData();
9367510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen        pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
9379839320ae17ab1c2182dc144db5ba94caa1bde56commit-bot@chromium.org                                   SkIntToScalar(stitchData.fHeight));
9384775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com    }
9394775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com}
9404775cba7b37e24e8480bd2d96e297fd0828fb5c3sugoi@google.com
941e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com/////////////////////////////////////////////////////////////////////
942e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
943b0a8a377f832c59cee939ad721e1f87d378b7142joshualittbool SkPerlinNoiseShader::asFragmentProcessor(GrContext* context, const SkPaint& paint,
9445531d51ce7426bdae7563547326fcf0bf926a083joshualitt                                              const SkMatrix& viewM,
945b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                              const SkMatrix* externalLocalMatrix,
946b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                              GrColor* paintColor, GrFragmentProcessor** fp) const {
94749f085dddff10473b6ebf832a974288300224e60bsalomon    SkASSERT(context);
9483f3b3d003527861dc0bd89733857576408906431mtklein
94983d081ae1d731b5039e99823620f5e287542ee39bsalomon    *paintColor = SkColor2GrColorJustAlpha(paint.getColor());
950ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco
95196fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org    SkMatrix localMatrix = this->getLocalMatrix();
95296fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org    if (externalLocalMatrix) {
95396fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        localMatrix.preConcat(*externalLocalMatrix);
95496fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org    }
95596fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org
9565531d51ce7426bdae7563547326fcf0bf926a083joshualitt    SkMatrix matrix = viewM;
957ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    matrix.preConcat(localMatrix);
958ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco
959c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org    if (0 == fNumOctaves) {
960c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org        if (kFractalNoise_Type == fType) {
961ea8b55db889b19786008b7c613d238e7202485e5bsalomon            uint32_t alpha = paint.getAlpha() >> 1;
962ea8b55db889b19786008b7c613d238e7202485e5bsalomon            uint32_t rgb = alpha >> 1;
963ea8b55db889b19786008b7c613d238e7202485e5bsalomon            *paintColor = GrColorPackRGBA(rgb, rgb, rgb, alpha);
964ea8b55db889b19786008b7c613d238e7202485e5bsalomon        } else {
965ea8b55db889b19786008b7c613d238e7202485e5bsalomon            *paintColor = 0;
966cff10b21a9934afc540d121b493b204335829589reed        }
9679de5b514d38c5b36066bcdc14fba2f7e5196d372dandov        return true;
968c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org    }
969c2a0ea6418988d4bcc0719f99b1a110cecd08679commit-bot@chromium.org
970e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    // Either we don't stitch tiles, either we have a valid tile size
971e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
972e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
973b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    SkPerlinNoiseShader::PaintingData* paintingData =
974b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt            SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY, matrix));
975bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon    SkAutoTUnref<GrTexture> permutationsTexture(
976bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon        GrRefCachedBitmapTexture(context, paintingData->getPermutationsBitmap(), NULL));
977bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon    SkAutoTUnref<GrTexture> noiseTexture(
978bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon        GrRefCachedBitmapTexture(context, paintingData->getNoiseBitmap(), NULL));
979ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco
9805531d51ce7426bdae7563547326fcf0bf926a083joshualitt    SkMatrix m = viewM;
981ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    m.setTranslateX(-localMatrix.getTranslateX() + SK_Scalar1);
982ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1);
98349f085dddff10473b6ebf832a974288300224e60bsalomon    if ((permutationsTexture) && (noiseTexture)) {
984b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        *fp = GrPerlinNoiseEffect::Create(fType,
985b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          fNumOctaves,
986b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          fStitchTiles,
987b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          paintingData,
988b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          permutationsTexture, noiseTexture,
989b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          m, paint.getAlpha());
990ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    } else {
991ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco        SkDELETE(paintingData);
992b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        *fp = NULL;
993ca6a7c29452e13cf63bb4e225972065cbfe6e265senorblanco    }
9949de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    return true;
995e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
996e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
997e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#else
998e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
9995531d51ce7426bdae7563547326fcf0bf926a083joshualittbool SkPerlinNoiseShader::asFragmentProcessor(GrContext*, const SkPaint&, const SkMatrix&,
10005531d51ce7426bdae7563547326fcf0bf926a083joshualitt                                              const SkMatrix*, GrColor*,
1001b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                              GrFragmentProcessor**) const {
1002e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    SkDEBUGFAIL("Should not call in GPU-less build");
10039de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    return false;
1004e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
1005e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
1006e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#endif
1007e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
10080f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
1009e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.comvoid SkPerlinNoiseShader::toString(SkString* str) const {
1010e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append("SkPerlinNoiseShader: (");
1011e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
1012e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append("type: ");
1013e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    switch (fType) {
1014e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        case kFractalNoise_Type:
1015e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            str->append("\"fractal noise\"");
1016e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            break;
1017e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        case kTurbulence_Type:
1018e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            str->append("\"turbulence\"");
1019e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            break;
1020e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        default:
1021e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            str->append("\"unknown\"");
1022e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com            break;
1023e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    }
1024e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(" base frequency: (");
1025e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->appendScalar(fBaseFrequencyX);
1026e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(", ");
1027e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->appendScalar(fBaseFrequencyY);
1028e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(") number of octaves: ");
1029e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->appendS32(fNumOctaves);
1030e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(" seed: ");
1031e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->appendScalar(fSeed);
1032e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(" stitch tiles: ");
1033e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(fStitchTiles ? "true " : "false ");
1034e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
1035e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    this->INHERITED::toString(str);
1036e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
1037e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com    str->append(")");
1038e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com}
1039e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com#endif
1040