• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2011 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 #ifndef GrPaint_DEFINED
11 #define GrPaint_DEFINED
12 
13 #include "GrColor.h"
14 #include "GrEffectStage.h"
15 
16 #include "SkXfermode.h"
17 
18 /**
19  * The paint describes how color and coverage are computed at each pixel by GrContext draw
20  * functions and the how color is blended with the destination pixel.
21  *
22  * The paint allows installation of custom color and coverage stages. New types of stages are
23  * created by subclassing GrEffect.
24  *
25  * The primitive color computation starts with the color specified by setColor(). This color is the
26  * input to the first color stage. Each color stage feeds its output to the next color stage. The
27  * final color stage's output color is input to the color filter specified by
28  * setXfermodeColorFilter which produces the final source color, S.
29  *
30  * Fractional pixel coverage follows a similar flow. The coverage is initially the value specified
31  * by setCoverage(). This is input to the first coverage stage. Coverage stages are chained
32  * together in the same manner as color stages. The output of the last stage is modulated by any
33  * fractional coverage produced by anti-aliasing. This last step produces the final coverage, C.
34  *
35  * setBlendFunc() specifies blending coefficients for S (described above) and D, the initial value
36  * of the destination pixel, labeled Bs and Bd respectively. The final value of the destination
37  * pixel is then D' = (1-C)*D + C*(Bd*D + Bs*S).
38  *
39  * Note that the coverage is applied after the blend. This is why they are computed as distinct
40  * values.
41  *
42  * TODO: Encapsulate setXfermodeColorFilter in a GrEffect and remove from GrPaint.
43  */
44 class GrPaint {
45 public:
46     enum {
47         kMaxColorStages     = 2,
48         kMaxCoverageStages  = 1,
49     };
50 
GrPaint()51     GrPaint() { this->reset(); }
52 
GrPaint(const GrPaint & paint)53     GrPaint(const GrPaint& paint) { *this = paint; }
54 
~GrPaint()55     ~GrPaint() {}
56 
57     /**
58      * Sets the blending coefficients to use to blend the final primitive color with the
59      * destination color. Defaults to kOne for src and kZero for dst (i.e. src mode).
60      */
setBlendFunc(GrBlendCoeff srcCoeff,GrBlendCoeff dstCoeff)61     void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
62         fSrcBlendCoeff = srcCoeff;
63         fDstBlendCoeff = dstCoeff;
64     }
getSrcBlendCoeff()65     GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlendCoeff; }
getDstBlendCoeff()66     GrBlendCoeff getDstBlendCoeff() const { return fDstBlendCoeff; }
67 
68     /**
69      * The initial color of the drawn primitive. Defaults to solid white.
70      */
setColor(GrColor color)71     void setColor(GrColor color) { fColor = color; }
getColor()72     GrColor getColor() const { return fColor; }
73 
74     /**
75      * Applies fractional coverage to the entire drawn primitive. Defaults to 0xff.
76      */
setCoverage(uint8_t coverage)77     void setCoverage(uint8_t coverage) { fCoverage = coverage; }
getCoverage()78     uint8_t getCoverage() const { return fCoverage; }
79 
80     /**
81      * Should primitives be anti-aliased or not. Defaults to false.
82      */
setAntiAlias(bool aa)83     void setAntiAlias(bool aa) { fAntiAlias = aa; }
isAntiAlias()84     bool isAntiAlias() const { return fAntiAlias; }
85 
86     /**
87      * Should dithering be applied. Defaults to false.
88      */
setDither(bool dither)89     void setDither(bool dither) { fDither = dither; }
isDither()90     bool isDither() const { return fDither; }
91 
92     /**
93      * Enables a SkXfermode::Mode-based color filter applied to the primitive color. The constant
94      * color passed to this function is considered the "src" color and the primitive's color is
95      * considered the "dst" color. Defaults to kDst_Mode which equates to simply passing through
96      * the primitive color unmodified.
97      */
setXfermodeColorFilter(SkXfermode::Mode mode,GrColor color)98     void setXfermodeColorFilter(SkXfermode::Mode mode, GrColor color) {
99         fColorFilterColor = color;
100         fColorFilterXfermode = mode;
101     }
getColorFilterMode()102     SkXfermode::Mode getColorFilterMode() const { return fColorFilterXfermode; }
getColorFilterColor()103     GrColor getColorFilterColor() const { return fColorFilterColor; }
104 
105     /**
106      * Disables the SkXfermode::Mode color filter.
107      */
resetColorFilter()108     void resetColorFilter() {
109         fColorFilterXfermode = SkXfermode::kDst_Mode;
110         fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
111     }
112 
113     /**
114      * Specifies a stage of the color pipeline. Usually the texture matrices of color stages apply
115      * to the primitive's positions. Some GrContext calls take explicit coords as an array or a
116      * rect. In this case these are the pre-matrix coords to colorStage(0).
117      */
colorStage(int i)118     GrEffectStage* colorStage(int i) {
119         GrAssert((unsigned)i < kMaxColorStages);
120         return fColorStages + i;
121     }
122 
getColorStage(int i)123     const GrEffectStage& getColorStage(int i) const {
124         GrAssert((unsigned)i < kMaxColorStages);
125         return fColorStages[i];
126     }
127 
isColorStageEnabled(int i)128     bool isColorStageEnabled(int i) const {
129         GrAssert((unsigned)i < kMaxColorStages);
130         return (NULL != fColorStages[i].getEffect());
131     }
132 
133     /**
134      * Specifies a stage of the coverage pipeline. Coverage stages' texture matrices are always
135      * applied to the primitive's position, never to explicit texture coords.
136      */
coverageStage(int i)137     GrEffectStage* coverageStage(int i) {
138         GrAssert((unsigned)i < kMaxCoverageStages);
139         return fCoverageStages + i;
140     }
141 
getCoverageStage(int i)142     const GrEffectStage& getCoverageStage(int i) const {
143         GrAssert((unsigned)i < kMaxCoverageStages);
144         return fCoverageStages[i];
145     }
146 
isCoverageStageEnabled(int i)147     bool isCoverageStageEnabled(int i) const {
148         GrAssert((unsigned)i < kMaxCoverageStages);
149         return (NULL != fCoverageStages[i].getEffect());
150     }
151 
hasCoverageStage()152     bool hasCoverageStage() const {
153         for (int i = 0; i < kMaxCoverageStages; ++i) {
154             if (this->isCoverageStageEnabled(i)) {
155                 return true;
156             }
157         }
158         return false;
159     }
160 
hasColorStage()161     bool hasColorStage() const {
162         for (int i = 0; i < kMaxColorStages; ++i) {
163             if (this->isColorStageEnabled(i)) {
164                 return true;
165             }
166         }
167         return false;
168     }
169 
hasStage()170     bool hasStage() const { return this->hasColorStage() || this->hasCoverageStage(); }
171 
172     /**
173      * Called when the source coord system is changing. preConcatInverse is the inverse of the
174      * transformation from the old coord system to the new coord system. Returns false if the matrix
175      * cannot be inverted.
176      */
sourceCoordChangeByInverse(const SkMatrix & preConcatInverse)177     bool sourceCoordChangeByInverse(const SkMatrix& preConcatInverse) {
178         SkMatrix inv;
179         bool computed = false;
180         for (int i = 0; i < kMaxColorStages; ++i) {
181             if (this->isColorStageEnabled(i)) {
182                 if (!computed && !preConcatInverse.invert(&inv)) {
183                     return false;
184                 } else {
185                     computed = true;
186                 }
187                 fColorStages[i].preConcatCoordChange(inv);
188             }
189         }
190         for (int i = 0; i < kMaxCoverageStages; ++i) {
191             if (this->isCoverageStageEnabled(i)) {
192                 if (!computed && !preConcatInverse.invert(&inv)) {
193                     return false;
194                 } else {
195                     computed = true;
196                 }
197                 fCoverageStages[i].preConcatCoordChange(inv);
198             }
199         }
200         return true;
201     }
202 
203     /**
204      * Called when the source coord system is changing. preConcat gives the transformation from the
205      * old coord system to the new coord system.
206      */
sourceCoordChange(const SkMatrix & preConcat)207     void sourceCoordChange(const SkMatrix& preConcat) {
208         for (int i = 0; i < kMaxColorStages; ++i) {
209             if (this->isColorStageEnabled(i)) {
210                 fColorStages[i].preConcatCoordChange(preConcat);
211             }
212         }
213         for (int i = 0; i < kMaxCoverageStages; ++i) {
214             if (this->isCoverageStageEnabled(i)) {
215                 fCoverageStages[i].preConcatCoordChange(preConcat);
216             }
217         }
218     }
219 
220     GrPaint& operator=(const GrPaint& paint) {
221         fSrcBlendCoeff = paint.fSrcBlendCoeff;
222         fDstBlendCoeff = paint.fDstBlendCoeff;
223         fAntiAlias = paint.fAntiAlias;
224         fDither = paint.fDither;
225 
226         fColor = paint.fColor;
227         fCoverage = paint.fCoverage;
228 
229         fColorFilterColor = paint.fColorFilterColor;
230         fColorFilterXfermode = paint.fColorFilterXfermode;
231 
232         for (int i = 0; i < kMaxColorStages; ++i) {
233             if (paint.isColorStageEnabled(i)) {
234                 fColorStages[i] = paint.fColorStages[i];
235             }
236         }
237         for (int i = 0; i < kMaxCoverageStages; ++i) {
238             if (paint.isCoverageStageEnabled(i)) {
239                 fCoverageStages[i] = paint.fCoverageStages[i];
240             }
241         }
242         return *this;
243     }
244 
245     /**
246      * Resets the paint to the defaults.
247      */
reset()248     void reset() {
249         this->resetBlend();
250         this->resetOptions();
251         this->resetColor();
252         this->resetCoverage();
253         this->resetStages();
254         this->resetColorFilter();
255     }
256 
257     // internal use
258     // GrPaint's textures and masks map to the first N stages
259     // of GrDrawTarget in that order (textures followed by masks)
260     enum {
261         kFirstColorStage = 0,
262         kFirstCoverageStage = kMaxColorStages,
263         kTotalStages = kFirstColorStage + kMaxColorStages + kMaxCoverageStages,
264     };
265 
266 private:
267 
268     GrEffectStage               fColorStages[kMaxColorStages];
269     GrEffectStage               fCoverageStages[kMaxCoverageStages];
270 
271     GrBlendCoeff                fSrcBlendCoeff;
272     GrBlendCoeff                fDstBlendCoeff;
273     bool                        fAntiAlias;
274     bool                        fDither;
275 
276     GrColor                     fColor;
277     uint8_t                     fCoverage;
278 
279     GrColor                     fColorFilterColor;
280     SkXfermode::Mode            fColorFilterXfermode;
281 
resetBlend()282     void resetBlend() {
283         fSrcBlendCoeff = kOne_GrBlendCoeff;
284         fDstBlendCoeff = kZero_GrBlendCoeff;
285     }
286 
resetOptions()287     void resetOptions() {
288         fAntiAlias = false;
289         fDither = false;
290     }
291 
resetColor()292     void resetColor() {
293         fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
294     }
295 
resetCoverage()296     void resetCoverage() {
297         fCoverage = 0xff;
298     }
299 
resetStages()300     void resetStages() {
301         for (int i = 0; i < kMaxColorStages; ++i) {
302             fColorStages[i].reset();
303         }
304         for (int i = 0; i < kMaxCoverageStages; ++i) {
305             fCoverageStages[i].reset();
306         }
307     }
308 };
309 
310 #endif
311