1
2/*
3 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10
11#ifndef GrSamplerState_DEFINED
12#define GrSamplerState_DEFINED
13
14#include "GrTypes.h"
15#include "GrMatrix.h"
16
17#define MAX_KERNEL_WIDTH 25
18
19class GrSamplerState {
20public:
21    enum Filter {
22        /**
23         * Read the closest src texel to the sample position
24         */
25        kNearest_Filter,
26        /**
27         * Blend between closest 4 src texels to sample position (tent filter)
28         */
29        kBilinear_Filter,
30        /**
31         * Average of 4 bilinear filterings spaced +/- 1 texel from sample
32         * position in x and y. Intended for averaging 16 texels in a downsample
33         * pass. (rasterizing such that texture samples fall exactly halfway
34         * between texels in x and y spaced 4 texels apart.) Only supported
35         * on shader backends.
36         */
37        k4x4Downsample_Filter,
38        /**
39         * Apply a separable convolution kernel.
40         */
41        kConvolution_Filter,
42        /**
43         * Apply a dilate filter (max over a 1D radius).
44         */
45        kDilate_Filter,
46        /**
47         * Apply an erode filter (min over a 1D radius).
48         */
49        kErode_Filter,
50
51        kDefault_Filter = kNearest_Filter
52    };
53
54    /**
55     * The intepretation of the texture matrix depends on the sample mode. The
56     * texture matrix is applied both when the texture coordinates are explicit
57     * and  when vertex positions are used as texture  coordinates. In the latter
58     * case the texture matrix is applied to the pre-view-matrix position
59     * values.
60     *
61     * kNormal_SampleMode
62     *  The post-matrix texture coordinates are in normalize space with (0,0) at
63     *  the top-left and (1,1) at the bottom right.
64     * kRadial_SampleMode
65     *  The matrix specifies the radial gradient parameters.
66     *  (0,0) in the post-matrix space is center of the radial gradient.
67     * kRadial2_SampleMode
68     *   Matrix transforms to space where first circle is centered at the
69     *   origin. The second circle will be centered (x, 0) where x may be
70     *   0 and is provided by setRadial2Params. The post-matrix space is
71     *   normalized such that 1 is the second radius - first radius.
72     * kSweepSampleMode
73     *  The angle from the origin of texture coordinates in post-matrix space
74     *  determines the gradient value.
75     */
76    enum SampleMode {
77        kNormal_SampleMode,     //!< sample color directly
78        kRadial_SampleMode,     //!< treat as radial gradient
79        kRadial2_SampleMode,    //!< treat as 2-point radial gradient
80        kSweep_SampleMode,      //!< treat as sweep gradient
81
82        kDefault_SampleMode = kNormal_SampleMode
83    };
84
85    /**
86     * Describes how a texture is sampled when coordinates are outside the
87     * texture border
88     */
89    enum WrapMode {
90        kClamp_WrapMode,
91        kRepeat_WrapMode,
92        kMirror_WrapMode,
93
94        kDefault_WrapMode = kClamp_WrapMode
95    };
96
97    /**
98     * For the filters which perform more than one texture sample (convolution,
99     * erode, dilate), this determines the direction in which the texture
100     * coordinates will be incremented.
101     */
102    enum FilterDirection {
103        kX_FilterDirection,
104        kY_FilterDirection,
105
106        kDefault_FilterDirection = kX_FilterDirection,
107    };
108    /**
109     * Default sampler state is set to clamp, use normal sampling mode, be
110     * unfiltered, and use identity matrix.
111     */
112    GrSamplerState()
113    : fRadial2CenterX1()
114    , fRadial2Radius0()
115    , fRadial2PosRoot() {
116        this->reset();
117    }
118
119    WrapMode getWrapX() const { return fWrapX; }
120    WrapMode getWrapY() const { return fWrapY; }
121    FilterDirection getFilterDirection() const { return fFilterDirection; }
122    SampleMode getSampleMode() const { return fSampleMode; }
123    const GrMatrix& getMatrix() const { return fMatrix; }
124    const GrRect& getTextureDomain() const { return fTextureDomain; }
125    bool hasTextureDomain() const {return SkIntToScalar(0) != fTextureDomain.right();}
126    Filter getFilter() const { return fFilter; }
127    int getKernelWidth() const { return fKernelWidth; }
128    const float* getKernel() const { return fKernel; }
129    bool swapsRAndB() const { return fSwapRAndB; }
130
131    bool isGradient() const {
132        return  kRadial_SampleMode == fSampleMode ||
133                kRadial2_SampleMode == fSampleMode ||
134                kSweep_SampleMode == fSampleMode;
135    }
136
137    void setWrapX(WrapMode mode) { fWrapX = mode; }
138    void setWrapY(WrapMode mode) { fWrapY = mode; }
139    void setSampleMode(SampleMode mode) { fSampleMode = mode; }
140    void setFilterDirection(FilterDirection mode) { fFilterDirection = mode; }
141
142    /**
143     * Access the sampler's matrix. See SampleMode for explanation of
144     * relationship between the matrix and sample mode.
145     */
146    GrMatrix* matrix() { return &fMatrix; }
147
148    /**
149     * Sets the sampler's texture coordinate domain to a
150     * custom rectangle, rather than the default (0,1).
151     * This option is currently only supported with kClamp_WrapMode
152     */
153    void setTextureDomain(const GrRect& textureDomain) { fTextureDomain = textureDomain; }
154
155    /**
156     * Swaps the R and B components when reading from the texture. Has no effect
157     * if the texture is alpha only.
158     */
159    void setRAndBSwap(bool swap) { fSwapRAndB = swap; }
160
161    /**
162     *  Multiplies the current sampler matrix  a matrix
163     *
164     *  After this call M' = M*m where M is the old matrix, m is the parameter
165     *  to this function, and M' is the new matrix. (We consider points to
166     *  be column vectors so tex cood vector t is transformed by matrix X as
167     *  t' = X*t.)
168     *
169     *  @param matrix   the matrix used to modify the matrix.
170     */
171    void preConcatMatrix(const GrMatrix& matrix) { fMatrix.preConcat(matrix); }
172
173    /**
174     * Sets filtering type.
175     * @param filter    type of filtering to apply
176     */
177    void setFilter(Filter filter) { fFilter = filter; }
178
179    void reset(WrapMode wrapXAndY,
180               Filter filter,
181               FilterDirection direction,
182               const GrMatrix& matrix) {
183        fWrapX = wrapXAndY;
184        fWrapY = wrapXAndY;
185        fSampleMode = kDefault_SampleMode;
186        fFilter = filter;
187        fFilterDirection = direction;
188        fMatrix = matrix;
189        fTextureDomain.setEmpty();
190        fSwapRAndB = false;
191    }
192    void reset(WrapMode wrapXAndY, Filter filter, const GrMatrix& matrix) {
193        this->reset(wrapXAndY, filter, kDefault_FilterDirection, matrix);
194    }
195    void reset(WrapMode wrapXAndY,
196               Filter filter) {
197        this->reset(wrapXAndY, filter, kDefault_FilterDirection, GrMatrix::I());
198    }
199    void reset(const GrMatrix& matrix) {
200        this->reset(kDefault_WrapMode, kDefault_Filter, kDefault_FilterDirection, matrix);
201    }
202    void reset() {
203        this->reset(kDefault_WrapMode, kDefault_Filter, kDefault_FilterDirection, GrMatrix::I());
204    }
205
206    GrScalar getRadial2CenterX1() const { return fRadial2CenterX1; }
207    GrScalar getRadial2Radius0() const { return fRadial2Radius0; }
208    bool     isRadial2PosRoot() const { return SkToBool(fRadial2PosRoot); }
209    // do the radial gradient params lead to a linear (rather than quadratic)
210    // equation.
211    bool radial2IsDegenerate() const { return GR_Scalar1 == fRadial2CenterX1; }
212
213    /**
214     * Sets the parameters for kRadial2_SampleMode. The texture
215     * matrix must be set so that the first point is at (0,0) and the second
216     * point lies on the x-axis. The second radius minus the first is 1 unit.
217     * The additional parameters to define the gradient are specified by this
218     * function.
219     */
220    void setRadial2Params(GrScalar centerX1, GrScalar radius0, bool posRoot) {
221        fRadial2CenterX1 = centerX1;
222        fRadial2Radius0 = radius0;
223        fRadial2PosRoot = posRoot;
224    }
225
226    void setConvolutionParams(int kernelWidth, const float* kernel) {
227        GrAssert(kernelWidth >= 0 && kernelWidth <= MAX_KERNEL_WIDTH);
228        fKernelWidth = kernelWidth;
229        if (NULL != kernel) {
230            memcpy(fKernel, kernel, kernelWidth * sizeof(float));
231        }
232    }
233
234    void setMorphologyRadius(int radius) {
235        GrAssert(radius >= 0 && radius <= MAX_KERNEL_WIDTH);
236        fKernelWidth = radius;
237    }
238
239private:
240    WrapMode            fWrapX : 8;
241    WrapMode            fWrapY : 8;
242    FilterDirection     fFilterDirection : 8;
243    SampleMode          fSampleMode : 8;
244    Filter              fFilter : 8;
245    GrMatrix            fMatrix;
246    bool                fSwapRAndB;
247    GrRect              fTextureDomain;
248
249    // these are undefined unless fSampleMode == kRadial2_SampleMode
250    GrScalar            fRadial2CenterX1;
251    GrScalar            fRadial2Radius0;
252    SkBool8             fRadial2PosRoot;
253
254    // These are undefined unless fFilter == kConvolution_Filter
255    uint8_t             fKernelWidth;
256    float               fKernel[MAX_KERNEL_WIDTH];
257};
258
259#endif
260
261