|
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 GrPaint() { this->reset(); } |
|
47 |
|
48 GrPaint(const GrPaint& paint) { *this = paint; } |
|
49 |
|
50 ~GrPaint() {} |
|
51 |
|
52 /** |
|
53 * Sets the blending coefficients to use to blend the final primitive color with the |
|
54 * destination color. Defaults to kOne for src and kZero for dst (i.e. src mode). |
|
55 */ |
|
56 void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) { |
|
57 fSrcBlendCoeff = srcCoeff; |
|
58 fDstBlendCoeff = dstCoeff; |
|
59 } |
|
60 GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlendCoeff; } |
|
61 GrBlendCoeff getDstBlendCoeff() const { return fDstBlendCoeff; } |
|
62 |
|
63 /** |
|
64 * The initial color of the drawn primitive. Defaults to solid white. |
|
65 */ |
|
66 void setColor(GrColor color) { fColor = color; } |
|
67 GrColor getColor() const { return fColor; } |
|
68 |
|
69 /** |
|
70 * Applies fractional coverage to the entire drawn primitive. Defaults to 0xff. |
|
71 */ |
|
72 void setCoverage(uint8_t coverage) { fCoverage = coverage; } |
|
73 uint8_t getCoverage() const { return fCoverage; } |
|
74 |
|
75 /** |
|
76 * Should primitives be anti-aliased or not. Defaults to false. |
|
77 */ |
|
78 void setAntiAlias(bool aa) { fAntiAlias = aa; } |
|
79 bool isAntiAlias() const { return fAntiAlias; } |
|
80 |
|
81 /** |
|
82 * Should dithering be applied. Defaults to false. |
|
83 */ |
|
84 void setDither(bool dither) { fDither = dither; } |
|
85 bool isDither() const { return fDither; } |
|
86 |
|
87 /** |
|
88 * Appends an additional color effect to the color computation. |
|
89 */ |
|
90 const GrEffectRef* addColorEffect(const GrEffectRef* effect, int attr0 = -1, int attr1 = -1) { |
|
91 SkASSERT(NULL != effect); |
|
92 if (!(*effect)->willUseInputColor()) { |
|
93 fColorStages.reset(); |
|
94 } |
|
95 SkNEW_APPEND_TO_TARRAY(&fColorStages, GrEffectStage, (effect, attr0, attr1)); |
|
96 return effect; |
|
97 } |
|
98 |
|
99 /** |
|
100 * Appends an additional coverage effect to the coverage computation. |
|
101 */ |
|
102 const GrEffectRef* addCoverageEffect(const GrEffectRef* effect, int attr0 = -1, int attr1 = -1) { |
|
103 SkASSERT(NULL != effect); |
|
104 if (!(*effect)->willUseInputColor()) { |
|
105 fCoverageStages.reset(); |
|
106 } |
|
107 SkNEW_APPEND_TO_TARRAY(&fCoverageStages, GrEffectStage, (effect, attr0, attr1)); |
|
108 return effect; |
|
109 } |
|
110 |
|
111 /** |
|
112 * Helpers for adding color or coverage effects that sample a texture. The matrix is applied |
|
113 * to the src space position to compute texture coordinates. |
|
114 */ |
|
115 void addColorTextureEffect(GrTexture* texture, const SkMatrix& matrix); |
|
116 void addCoverageTextureEffect(GrTexture* texture, const SkMatrix& matrix); |
|
117 |
|
118 void addColorTextureEffect(GrTexture* texture, |
|
119 const SkMatrix& matrix, |
|
120 const GrTextureParams& params); |
|
121 void addCoverageTextureEffect(GrTexture* texture, |
|
122 const SkMatrix& matrix, |
|
123 const GrTextureParams& params); |
|
124 |
|
125 int numColorStages() const { return fColorStages.count(); } |
|
126 int numCoverageStages() const { return fCoverageStages.count(); } |
|
127 int numTotalStages() const { return this->numColorStages() + this->numCoverageStages(); } |
|
128 |
|
129 const GrEffectStage& getColorStage(int s) const { return fColorStages[s]; } |
|
130 const GrEffectStage& getCoverageStage(int s) const { return fCoverageStages[s]; } |
|
131 |
|
132 GrPaint& operator=(const GrPaint& paint) { |
|
133 fSrcBlendCoeff = paint.fSrcBlendCoeff; |
|
134 fDstBlendCoeff = paint.fDstBlendCoeff; |
|
135 fAntiAlias = paint.fAntiAlias; |
|
136 fDither = paint.fDither; |
|
137 |
|
138 fColor = paint.fColor; |
|
139 fCoverage = paint.fCoverage; |
|
140 |
|
141 fColorStages = paint.fColorStages; |
|
142 fCoverageStages = paint.fCoverageStages; |
|
143 |
|
144 return *this; |
|
145 } |
|
146 |
|
147 /** |
|
148 * Resets the paint to the defaults. |
|
149 */ |
|
150 void reset() { |
|
151 this->resetBlend(); |
|
152 this->resetOptions(); |
|
153 this->resetColor(); |
|
154 this->resetCoverage(); |
|
155 this->resetStages(); |
|
156 } |
|
157 |
|
158 /** |
|
159 * Determines whether the drawing with this paint is opaque with respect to both color blending |
|
160 * and fractional coverage. It does not consider whether AA has been enabled on the paint or |
|
161 * not. Depending upon whether multisampling or coverage-based AA is in use, AA may make the |
|
162 * result only apply to the interior of primitives. |
|
163 * |
|
164 */ |
|
165 bool isOpaque() const; |
|
166 |
|
167 /** |
|
168 * Returns true if isOpaque would return true and the paint represents a solid constant color |
|
169 * draw. If the result is true, constantColor will be updated to contain the constant color. |
|
170 */ |
|
171 bool isOpaqueAndConstantColor(GrColor* constantColor) const; |
|
172 |
|
173 private: |
|
174 |
|
175 /** |
|
176 * Helper for isOpaque and isOpaqueAndConstantColor. |
|
177 */ |
|
178 bool getOpaqueAndKnownColor(GrColor* solidColor, uint32_t* solidColorKnownComponents) const; |
|
179 |
|
180 /** |
|
181 * Called when the source coord system from which geometry is rendered changes. It ensures that |
|
182 * the local coordinates seen by effects remains unchanged. oldToNew gives the transformation |
|
183 * from the previous coord system to the new coord system. |
|
184 */ |
|
185 void localCoordChange(const SkMatrix& oldToNew) { |
|
186 for (int i = 0; i < fColorStages.count(); ++i) { |
|
187 fColorStages[i].localCoordChange(oldToNew); |
|
188 } |
|
189 for (int i = 0; i < fCoverageStages.count(); ++i) { |
|
190 fCoverageStages[i].localCoordChange(oldToNew); |
|
191 } |
|
192 } |
|
193 |
|
194 bool localCoordChangeInverse(const SkMatrix& newToOld) { |
|
195 SkMatrix oldToNew; |
|
196 bool computed = false; |
|
197 for (int i = 0; i < fColorStages.count(); ++i) { |
|
198 if (!computed && !newToOld.invert(&oldToNew)) { |
|
199 return false; |
|
200 } else { |
|
201 computed = true; |
|
202 } |
|
203 fColorStages[i].localCoordChange(oldToNew); |
|
204 } |
|
205 for (int i = 0; i < fCoverageStages.count(); ++i) { |
|
206 if (!computed && !newToOld.invert(&oldToNew)) { |
|
207 return false; |
|
208 } else { |
|
209 computed = true; |
|
210 } |
|
211 fCoverageStages[i].localCoordChange(oldToNew); |
|
212 } |
|
213 return true; |
|
214 } |
|
215 |
|
216 friend class GrContext; // To access above two functions |
|
217 |
|
218 SkSTArray<4, GrEffectStage> fColorStages; |
|
219 SkSTArray<2, GrEffectStage> fCoverageStages; |
|
220 |
|
221 GrBlendCoeff fSrcBlendCoeff; |
|
222 GrBlendCoeff fDstBlendCoeff; |
|
223 bool fAntiAlias; |
|
224 bool fDither; |
|
225 |
|
226 GrColor fColor; |
|
227 uint8_t fCoverage; |
|
228 |
|
229 void resetBlend() { |
|
230 fSrcBlendCoeff = kOne_GrBlendCoeff; |
|
231 fDstBlendCoeff = kZero_GrBlendCoeff; |
|
232 } |
|
233 |
|
234 void resetOptions() { |
|
235 fAntiAlias = false; |
|
236 fDither = false; |
|
237 } |
|
238 |
|
239 void resetColor() { |
|
240 fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff); |
|
241 } |
|
242 |
|
243 void resetCoverage() { |
|
244 fCoverage = 0xff; |
|
245 } |
|
246 |
|
247 void resetStages() { |
|
248 fColorStages.reset(); |
|
249 fCoverageStages.reset(); |
|
250 } |
|
251 }; |
|
252 |
|
253 #endif |