blob: 06c16af57889aeac39965bf790643f84f23800f9 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * 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.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
bsalomon@google.com27847de2011-02-22 20:59:41 +000010#ifndef GrPaint_DEFINED
11#define GrPaint_DEFINED
12
bsalomon@google.com27847de2011-02-22 20:59:41 +000013#include "GrColor.h"
14#include "GrSamplerState.h"
15
Scroggo97c88c22011-05-11 14:05:25 +000016#include "SkXfermode.h"
17
bsalomon@google.com27847de2011-02-22 20:59:41 +000018/**
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000019 * 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 GrCustomStage.
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
bsalomon@google.com67e78c92012-10-17 13:36:14 +000028 * setXfermodeColorFilter which produces the final source color, S.
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000029 *
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 *
bsalomon@google.com67e78c92012-10-17 13:36:14 +000042 * TODO: Encapsulate setXfermodeColorFilter in a GrCustomStage and remove from GrPaint.
bsalomon@google.com27847de2011-02-22 20:59:41 +000043 */
44class GrPaint {
45public:
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +000046 enum {
bsalomon@google.com88becf42012-10-05 14:54:42 +000047 kMaxColorStages = 2,
48 kMaxCoverageStages = 1,
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +000049 };
bsalomon@google.com27847de2011-02-22 20:59:41 +000050
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000051 GrPaint() { this->reset(); }
bsalomon@google.com27847de2011-02-22 20:59:41 +000052
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000053 GrPaint(const GrPaint& paint) { *this = paint; }
bsalomon@google.com27847de2011-02-22 20:59:41 +000054
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000055 ~GrPaint() {}
Scroggo97c88c22011-05-11 14:05:25 +000056
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000057 /**
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 */
61 void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
62 fSrcBlendCoeff = srcCoeff;
63 fDstBlendCoeff = dstCoeff;
64 }
65 GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlendCoeff; }
66 GrBlendCoeff getDstBlendCoeff() const { return fDstBlendCoeff; }
67
68 /**
69 * The initial color of the drawn primitive. Defaults to solid white.
70 */
71 void setColor(GrColor color) { fColor = color; }
72 GrColor getColor() const { return fColor; }
73
74 /**
75 * Applies fractional coverage to the entire drawn primitive. Defaults to 0xff.
76 */
77 void setCoverage(uint8_t coverage) { fCoverage = coverage; }
78 uint8_t getCoverage() const { return fCoverage; }
79
80 /**
81 * Should primitives be anti-aliased or not. Defaults to false.
82 */
83 void setAntiAlias(bool aa) { fAntiAlias = aa; }
84 bool isAntiAlias() const { return fAntiAlias; }
85
86 /**
87 * Should dithering be applied. Defaults to false.
88 */
89 void setDither(bool dither) { fDither = dither; }
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 */
98 void setXfermodeColorFilter(SkXfermode::Mode mode, GrColor color) {
99 fColorFilterColor = color;
100 fColorFilterXfermode = mode;
101 }
102 SkXfermode::Mode getColorFilterMode() const { return fColorFilterXfermode; }
103 GrColor getColorFilterColor() const { return fColorFilterColor; }
104
105 /**
bsalomon@google.com67e78c92012-10-17 13:36:14 +0000106 * Disables the SkXfermode::Mode color filter.
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000107 */
108 void resetColorFilter() {
109 fColorFilterXfermode = SkXfermode::kDst_Mode;
110 fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000111 }
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 colorSampler(0).
117 */
bsalomon@google.com88becf42012-10-05 14:54:42 +0000118 GrSamplerState* colorSampler(int i) {
119 GrAssert((unsigned)i < kMaxColorStages);
120 return fColorSamplers + i;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000121 }
122
bsalomon@google.com88becf42012-10-05 14:54:42 +0000123 const GrSamplerState& getColorSampler(int i) const {
124 GrAssert((unsigned)i < kMaxColorStages);
125 return fColorSamplers[i];
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000126 }
127
bsalomon@google.com88becf42012-10-05 14:54:42 +0000128 bool isColorStageEnabled(int i) const {
129 GrAssert((unsigned)i < kMaxColorStages);
130 return (NULL != fColorSamplers[i].getCustomStage());
tomhudson@google.comf13f5882012-06-25 17:27:28 +0000131 }
132
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000133 /**
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 */
bsalomon@google.com88becf42012-10-05 14:54:42 +0000137 GrSamplerState* coverageSampler(int i) {
138 GrAssert((unsigned)i < kMaxCoverageStages);
139 return fCoverageSamplers + i;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000140 }
141
bsalomon@google.com88becf42012-10-05 14:54:42 +0000142 const GrSamplerState& getCoverageSampler(int i) const {
143 GrAssert((unsigned)i < kMaxCoverageStages);
144 return fCoverageSamplers[i];
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000145 }
146
bsalomon@google.com88becf42012-10-05 14:54:42 +0000147 bool isCoverageStageEnabled(int i) const {
148 GrAssert((unsigned)i < kMaxCoverageStages);
149 return (NULL != fCoverageSamplers[i].getCustomStage());
tomhudson@google.comf13f5882012-06-25 17:27:28 +0000150 }
151
bsalomon@google.com88becf42012-10-05 14:54:42 +0000152 bool hasCoverageStage() const {
153 for (int i = 0; i < kMaxCoverageStages; ++i) {
154 if (this->isCoverageStageEnabled(i)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000155 return true;
156 }
157 }
158 return false;
159 }
160
bsalomon@google.com88becf42012-10-05 14:54:42 +0000161 bool hasColorStage() const {
162 for (int i = 0; i < kMaxColorStages; ++i) {
163 if (this->isColorStageEnabled(i)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000164 return true;
165 }
166 }
167 return false;
168 }
169
bsalomon@google.com88becf42012-10-05 14:54:42 +0000170 bool hasStage() const { return this->hasColorStage() || this->hasCoverageStage(); }
bsalomon@google.come3d32162012-07-20 13:37:06 +0000171
172 /**
bsalomon@google.com288d9542012-10-17 12:53:54 +0000173 * 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.
bsalomon@google.come3d32162012-07-20 13:37:06 +0000176 */
bsalomon@google.com288d9542012-10-17 12:53:54 +0000177 bool sourceCoordChangeByInverse(const GrMatrix& preConcatInverse) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000178 GrMatrix inv;
179 bool computed = false;
bsalomon@google.com88becf42012-10-05 14:54:42 +0000180 for (int i = 0; i < kMaxColorStages; ++i) {
181 if (this->isColorStageEnabled(i)) {
bsalomon@google.com288d9542012-10-17 12:53:54 +0000182 if (!computed && !preConcatInverse.invert(&inv)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000183 return false;
184 } else {
185 computed = true;
186 }
bsalomon@google.com288d9542012-10-17 12:53:54 +0000187 fColorSamplers[i].preConcatCoordChange(inv);
bsalomon@google.come3d32162012-07-20 13:37:06 +0000188 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000189 }
bsalomon@google.com88becf42012-10-05 14:54:42 +0000190 for (int i = 0; i < kMaxCoverageStages; ++i) {
191 if (this->isCoverageStageEnabled(i)) {
bsalomon@google.com288d9542012-10-17 12:53:54 +0000192 if (!computed && !preConcatInverse.invert(&inv)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000193 return false;
194 } else {
195 computed = true;
196 }
bsalomon@google.com288d9542012-10-17 12:53:54 +0000197 fCoverageSamplers[i].preConcatCoordChange(inv);
bsalomon@google.come3d32162012-07-20 13:37:06 +0000198 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000199 }
bsalomon@google.come3d32162012-07-20 13:37:06 +0000200 return true;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000201 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000202
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000203 /**
bsalomon@google.com288d9542012-10-17 12:53:54 +0000204 * Called when the source coord system is changing. preConcat gives the transformation from the
205 * old coord system to the new coord system.
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000206 */
bsalomon@google.com288d9542012-10-17 12:53:54 +0000207 void sourceCoordChange(const GrMatrix& preConcat) {
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000208 for (int i = 0; i < kMaxColorStages; ++i) {
209 if (this->isColorStageEnabled(i)) {
bsalomon@google.com288d9542012-10-17 12:53:54 +0000210 fColorSamplers[i].preConcatCoordChange(preConcat);
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000211 }
212 }
213 for (int i = 0; i < kMaxCoverageStages; ++i) {
214 if (this->isCoverageStageEnabled(i)) {
bsalomon@google.com288d9542012-10-17 12:53:54 +0000215 fCoverageSamplers[i].preConcatCoordChange(preConcat);
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000216 }
217 }
218 }
219
bsalomon@google.com27c9b6d2011-09-12 14:30:27 +0000220 GrPaint& operator=(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000221 fSrcBlendCoeff = paint.fSrcBlendCoeff;
222 fDstBlendCoeff = paint.fDstBlendCoeff;
223 fAntiAlias = paint.fAntiAlias;
224 fDither = paint.fDither;
225
226 fColor = paint.fColor;
bsalomon@google.comdd1be602012-01-18 20:34:00 +0000227 fCoverage = paint.fCoverage;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000228
Scroggo97c88c22011-05-11 14:05:25 +0000229 fColorFilterColor = paint.fColorFilterColor;
230 fColorFilterXfermode = paint.fColorFilterXfermode;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000231
bsalomon@google.com88becf42012-10-05 14:54:42 +0000232 for (int i = 0; i < kMaxColorStages; ++i) {
233 if (paint.isColorStageEnabled(i)) {
234 fColorSamplers[i] = paint.fColorSamplers[i];
bsalomon@google.comdddf6f62012-03-16 17:50:37 +0000235 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000236 }
bsalomon@google.com88becf42012-10-05 14:54:42 +0000237 for (int i = 0; i < kMaxCoverageStages; ++i) {
238 if (paint.isCoverageStageEnabled(i)) {
239 fCoverageSamplers[i] = paint.fCoverageSamplers[i];
bsalomon@google.comdddf6f62012-03-16 17:50:37 +0000240 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000241 }
bsalomon@google.com27c9b6d2011-09-12 14:30:27 +0000242 return *this;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000243 }
244
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000245 /**
246 * Resets the paint to the defaults.
247 */
bsalomon@google.com27847de2011-02-22 20:59:41 +0000248 void reset() {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000249 this->resetBlend();
250 this->resetOptions();
251 this->resetColor();
bsalomon@google.comdd1be602012-01-18 20:34:00 +0000252 this->resetCoverage();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000253 this->resetTextures();
254 this->resetColorFilter();
255 this->resetMasks();
Scroggo97c88c22011-05-11 14:05:25 +0000256 }
257
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000258 // internal use
259 // GrPaint's textures and masks map to the first N stages
260 // of GrDrawTarget in that order (textures followed by masks)
261 enum {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000262 kFirstColorStage = 0,
263 kFirstCoverageStage = kMaxColorStages,
264 kTotalStages = kFirstColorStage + kMaxColorStages + kMaxCoverageStages,
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000265 };
266
bsalomon@google.com27847de2011-02-22 20:59:41 +0000267private:
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000268
bsalomon@google.com88becf42012-10-05 14:54:42 +0000269 GrSamplerState fColorSamplers[kMaxColorStages];
270 GrSamplerState fCoverageSamplers[kMaxCoverageStages];
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000271
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000272 GrBlendCoeff fSrcBlendCoeff;
273 GrBlendCoeff fDstBlendCoeff;
274 bool fAntiAlias;
275 bool fDither;
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000276
277 GrColor fColor;
278 uint8_t fCoverage;
279
280 GrColor fColorFilterColor;
281 SkXfermode::Mode fColorFilterXfermode;
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000282
bsalomon@google.com27847de2011-02-22 20:59:41 +0000283 void resetBlend() {
bsalomon@google.com47059542012-06-06 20:51:20 +0000284 fSrcBlendCoeff = kOne_GrBlendCoeff;
285 fDstBlendCoeff = kZero_GrBlendCoeff;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000286 }
287
288 void resetOptions() {
289 fAntiAlias = false;
290 fDither = false;
291 }
292
293 void resetColor() {
294 fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
295 }
296
bsalomon@google.comdd1be602012-01-18 20:34:00 +0000297 void resetCoverage() {
298 fCoverage = 0xff;
299 }
300
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000301 void resetTextures() {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000302 for (int i = 0; i < kMaxColorStages; ++i) {
303 fColorSamplers[i].reset();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000304 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000305 }
306
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000307 void resetMasks() {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000308 for (int i = 0; i < kMaxCoverageStages; ++i) {
309 fCoverageSamplers[i].reset();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000310 }
311 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000312};
313
314#endif