blob: 843a9348e5f387c262086f7195d817b15c983f5f [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
28 * setXfermodeColorFilter which it turn feeds into the color matrix. The output of the color matrix
29 * is the final source color, S.
30 *
31 * Fractional pixel coverage follows a similar flow. The coverage is initially the value specified
32 * by setCoverage(). This is input to the first coverage stage. Coverage stages are chained
33 * together in the same manner as color stages. The output of the last stage is modulated by any
34 * fractional coverage produced by anti-aliasing. This last step produces the final coverage, C.
35 *
36 * setBlendFunc() specifies blending coefficients for S (described above) and D, the initial value
37 * of the destination pixel, labeled Bs and Bd respectively. The final value of the destination
38 * pixel is then D' = (1-C)*D + C*(Bd*D + Bs*S).
39 *
40 * Note that the coverage is applied after the blend. This is why they are computed as distinct
41 * values.
42 *
43 * TODO: Encapsulate setXfermodeColorFilter and color matrix in stages and remove from GrPaint.
bsalomon@google.com27847de2011-02-22 20:59:41 +000044 */
45class GrPaint {
46public:
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +000047 enum {
bsalomon@google.com88becf42012-10-05 14:54:42 +000048 kMaxColorStages = 2,
49 kMaxCoverageStages = 1,
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +000050 };
bsalomon@google.com27847de2011-02-22 20:59:41 +000051
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000052 GrPaint() { this->reset(); }
bsalomon@google.com27847de2011-02-22 20:59:41 +000053
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000054 GrPaint(const GrPaint& paint) { *this = paint; }
bsalomon@google.com27847de2011-02-22 20:59:41 +000055
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000056 ~GrPaint() {}
Scroggo97c88c22011-05-11 14:05:25 +000057
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000058 /**
59 * Sets the blending coefficients to use to blend the final primitive color with the
60 * destination color. Defaults to kOne for src and kZero for dst (i.e. src mode).
61 */
62 void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
63 fSrcBlendCoeff = srcCoeff;
64 fDstBlendCoeff = dstCoeff;
65 }
66 GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlendCoeff; }
67 GrBlendCoeff getDstBlendCoeff() const { return fDstBlendCoeff; }
68
69 /**
70 * The initial color of the drawn primitive. Defaults to solid white.
71 */
72 void setColor(GrColor color) { fColor = color; }
73 GrColor getColor() const { return fColor; }
74
75 /**
76 * Applies fractional coverage to the entire drawn primitive. Defaults to 0xff.
77 */
78 void setCoverage(uint8_t coverage) { fCoverage = coverage; }
79 uint8_t getCoverage() const { return fCoverage; }
80
81 /**
82 * Should primitives be anti-aliased or not. Defaults to false.
83 */
84 void setAntiAlias(bool aa) { fAntiAlias = aa; }
85 bool isAntiAlias() const { return fAntiAlias; }
86
87 /**
88 * Should dithering be applied. Defaults to false.
89 */
90 void setDither(bool dither) { fDither = dither; }
91 bool isDither() const { return fDither; }
92
93 /**
94 * Enables a SkXfermode::Mode-based color filter applied to the primitive color. The constant
95 * color passed to this function is considered the "src" color and the primitive's color is
96 * considered the "dst" color. Defaults to kDst_Mode which equates to simply passing through
97 * the primitive color unmodified.
98 */
99 void setXfermodeColorFilter(SkXfermode::Mode mode, GrColor color) {
100 fColorFilterColor = color;
101 fColorFilterXfermode = mode;
102 }
103 SkXfermode::Mode getColorFilterMode() const { return fColorFilterXfermode; }
104 GrColor getColorFilterColor() const { return fColorFilterColor; }
105
106 /**
107 * Turns off application of a color matrix. By default the color matrix is disabled.
108 */
109 void disableColorMatrix() { fColorMatrixEnabled = false; }
110
111 /**
112 * Specifies and enables a 4 x 5 color matrix.
113 */
114 void setColorMatrix(const float matrix[20]) {
115 fColorMatrixEnabled = true;
116 memcpy(fColorMatrix, matrix, sizeof(fColorMatrix));
117 }
118
119 bool isColorMatrixEnabled() const { return fColorMatrixEnabled; }
120 const float* getColorMatrix() const { return fColorMatrix; }
121
122 /**
123 * Disables both the matrix and SkXfermode::Mode color filters.
124 */
125 void resetColorFilter() {
126 fColorFilterXfermode = SkXfermode::kDst_Mode;
127 fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
128 fColorMatrixEnabled = false;
129 }
130
131 /**
132 * Specifies a stage of the color pipeline. Usually the texture matrices of color stages apply
133 * to the primitive's positions. Some GrContext calls take explicit coords as an array or a
134 * rect. In this case these are the pre-matrix coords to colorSampler(0).
135 */
bsalomon@google.com88becf42012-10-05 14:54:42 +0000136 GrSamplerState* colorSampler(int i) {
137 GrAssert((unsigned)i < kMaxColorStages);
138 return fColorSamplers + i;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000139 }
140
bsalomon@google.com88becf42012-10-05 14:54:42 +0000141 const GrSamplerState& getColorSampler(int i) const {
142 GrAssert((unsigned)i < kMaxColorStages);
143 return fColorSamplers[i];
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000144 }
145
bsalomon@google.com88becf42012-10-05 14:54:42 +0000146 bool isColorStageEnabled(int i) const {
147 GrAssert((unsigned)i < kMaxColorStages);
148 return (NULL != fColorSamplers[i].getCustomStage());
tomhudson@google.comf13f5882012-06-25 17:27:28 +0000149 }
150
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000151 /**
152 * Specifies a stage of the coverage pipeline. Coverage stages' texture matrices are always
153 * applied to the primitive's position, never to explicit texture coords.
154 */
bsalomon@google.com88becf42012-10-05 14:54:42 +0000155 GrSamplerState* coverageSampler(int i) {
156 GrAssert((unsigned)i < kMaxCoverageStages);
157 return fCoverageSamplers + i;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000158 }
159
bsalomon@google.com88becf42012-10-05 14:54:42 +0000160 const GrSamplerState& getCoverageSampler(int i) const {
161 GrAssert((unsigned)i < kMaxCoverageStages);
162 return fCoverageSamplers[i];
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000163 }
164
bsalomon@google.com88becf42012-10-05 14:54:42 +0000165 bool isCoverageStageEnabled(int i) const {
166 GrAssert((unsigned)i < kMaxCoverageStages);
167 return (NULL != fCoverageSamplers[i].getCustomStage());
tomhudson@google.comf13f5882012-06-25 17:27:28 +0000168 }
169
bsalomon@google.com88becf42012-10-05 14:54:42 +0000170 bool hasCoverageStage() const {
171 for (int i = 0; i < kMaxCoverageStages; ++i) {
172 if (this->isCoverageStageEnabled(i)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000173 return true;
174 }
175 }
176 return false;
177 }
178
bsalomon@google.com88becf42012-10-05 14:54:42 +0000179 bool hasColorStage() const {
180 for (int i = 0; i < kMaxColorStages; ++i) {
181 if (this->isColorStageEnabled(i)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000182 return true;
183 }
184 }
185 return false;
186 }
187
bsalomon@google.com88becf42012-10-05 14:54:42 +0000188 bool hasStage() const { return this->hasColorStage() || this->hasCoverageStage(); }
bsalomon@google.come3d32162012-07-20 13:37:06 +0000189
190 /**
bsalomon@google.com288d9542012-10-17 12:53:54 +0000191 * Called when the source coord system is changing. preConcatInverse is the inverse of the
192 * transformation from the old coord system to the new coord system. Returns false if the matrix
193 * cannot be inverted.
bsalomon@google.come3d32162012-07-20 13:37:06 +0000194 */
bsalomon@google.com288d9542012-10-17 12:53:54 +0000195 bool sourceCoordChangeByInverse(const GrMatrix& preConcatInverse) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000196 GrMatrix inv;
197 bool computed = false;
bsalomon@google.com88becf42012-10-05 14:54:42 +0000198 for (int i = 0; i < kMaxColorStages; ++i) {
199 if (this->isColorStageEnabled(i)) {
bsalomon@google.com288d9542012-10-17 12:53:54 +0000200 if (!computed && !preConcatInverse.invert(&inv)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000201 return false;
202 } else {
203 computed = true;
204 }
bsalomon@google.com288d9542012-10-17 12:53:54 +0000205 fColorSamplers[i].preConcatCoordChange(inv);
bsalomon@google.come3d32162012-07-20 13:37:06 +0000206 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000207 }
bsalomon@google.com88becf42012-10-05 14:54:42 +0000208 for (int i = 0; i < kMaxCoverageStages; ++i) {
209 if (this->isCoverageStageEnabled(i)) {
bsalomon@google.com288d9542012-10-17 12:53:54 +0000210 if (!computed && !preConcatInverse.invert(&inv)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000211 return false;
212 } else {
213 computed = true;
214 }
bsalomon@google.com288d9542012-10-17 12:53:54 +0000215 fCoverageSamplers[i].preConcatCoordChange(inv);
bsalomon@google.come3d32162012-07-20 13:37:06 +0000216 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000217 }
bsalomon@google.come3d32162012-07-20 13:37:06 +0000218 return true;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000219 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000220
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000221 /**
bsalomon@google.com288d9542012-10-17 12:53:54 +0000222 * Called when the source coord system is changing. preConcat gives the transformation from the
223 * old coord system to the new coord system.
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000224 */
bsalomon@google.com288d9542012-10-17 12:53:54 +0000225 void sourceCoordChange(const GrMatrix& preConcat) {
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000226 for (int i = 0; i < kMaxColorStages; ++i) {
227 if (this->isColorStageEnabled(i)) {
bsalomon@google.com288d9542012-10-17 12:53:54 +0000228 fColorSamplers[i].preConcatCoordChange(preConcat);
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000229 }
230 }
231 for (int i = 0; i < kMaxCoverageStages; ++i) {
232 if (this->isCoverageStageEnabled(i)) {
bsalomon@google.com288d9542012-10-17 12:53:54 +0000233 fCoverageSamplers[i].preConcatCoordChange(preConcat);
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000234 }
235 }
236 }
237
bsalomon@google.com27c9b6d2011-09-12 14:30:27 +0000238 GrPaint& operator=(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000239 fSrcBlendCoeff = paint.fSrcBlendCoeff;
240 fDstBlendCoeff = paint.fDstBlendCoeff;
241 fAntiAlias = paint.fAntiAlias;
242 fDither = paint.fDither;
243
244 fColor = paint.fColor;
bsalomon@google.comdd1be602012-01-18 20:34:00 +0000245 fCoverage = paint.fCoverage;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000246
Scroggo97c88c22011-05-11 14:05:25 +0000247 fColorFilterColor = paint.fColorFilterColor;
248 fColorFilterXfermode = paint.fColorFilterXfermode;
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +0000249 fColorMatrixEnabled = paint.fColorMatrixEnabled;
bsalomon@google.comdddf6f62012-03-16 17:50:37 +0000250 if (fColorMatrixEnabled) {
251 memcpy(fColorMatrix, paint.fColorMatrix, sizeof(fColorMatrix));
252 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000253
bsalomon@google.com88becf42012-10-05 14:54:42 +0000254 for (int i = 0; i < kMaxColorStages; ++i) {
255 if (paint.isColorStageEnabled(i)) {
256 fColorSamplers[i] = paint.fColorSamplers[i];
bsalomon@google.comdddf6f62012-03-16 17:50:37 +0000257 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000258 }
bsalomon@google.com88becf42012-10-05 14:54:42 +0000259 for (int i = 0; i < kMaxCoverageStages; ++i) {
260 if (paint.isCoverageStageEnabled(i)) {
261 fCoverageSamplers[i] = paint.fCoverageSamplers[i];
bsalomon@google.comdddf6f62012-03-16 17:50:37 +0000262 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000263 }
bsalomon@google.com27c9b6d2011-09-12 14:30:27 +0000264 return *this;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000265 }
266
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000267 /**
268 * Resets the paint to the defaults.
269 */
bsalomon@google.com27847de2011-02-22 20:59:41 +0000270 void reset() {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000271 this->resetBlend();
272 this->resetOptions();
273 this->resetColor();
bsalomon@google.comdd1be602012-01-18 20:34:00 +0000274 this->resetCoverage();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000275 this->resetTextures();
276 this->resetColorFilter();
277 this->resetMasks();
Scroggo97c88c22011-05-11 14:05:25 +0000278 }
279
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000280 // internal use
281 // GrPaint's textures and masks map to the first N stages
282 // of GrDrawTarget in that order (textures followed by masks)
283 enum {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000284 kFirstColorStage = 0,
285 kFirstCoverageStage = kMaxColorStages,
286 kTotalStages = kFirstColorStage + kMaxColorStages + kMaxCoverageStages,
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000287 };
288
bsalomon@google.com27847de2011-02-22 20:59:41 +0000289private:
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000290
bsalomon@google.com88becf42012-10-05 14:54:42 +0000291 GrSamplerState fColorSamplers[kMaxColorStages];
292 GrSamplerState fCoverageSamplers[kMaxCoverageStages];
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000293
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000294 GrBlendCoeff fSrcBlendCoeff;
295 GrBlendCoeff fDstBlendCoeff;
296 bool fAntiAlias;
297 bool fDither;
298 bool fColorMatrixEnabled;
299
300 GrColor fColor;
301 uint8_t fCoverage;
302
303 GrColor fColorFilterColor;
304 SkXfermode::Mode fColorFilterXfermode;
305 float fColorMatrix[20];
306
bsalomon@google.com27847de2011-02-22 20:59:41 +0000307 void resetBlend() {
bsalomon@google.com47059542012-06-06 20:51:20 +0000308 fSrcBlendCoeff = kOne_GrBlendCoeff;
309 fDstBlendCoeff = kZero_GrBlendCoeff;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000310 }
311
312 void resetOptions() {
313 fAntiAlias = false;
314 fDither = false;
315 }
316
317 void resetColor() {
318 fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
319 }
320
bsalomon@google.comdd1be602012-01-18 20:34:00 +0000321 void resetCoverage() {
322 fCoverage = 0xff;
323 }
324
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000325 void resetTextures() {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000326 for (int i = 0; i < kMaxColorStages; ++i) {
327 fColorSamplers[i].reset();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000328 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000329 }
330
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000331 void resetMasks() {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000332 for (int i = 0; i < kMaxCoverageStages; ++i) {
333 fCoverageSamplers[i].reset();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000334 }
335 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000336};
337
338#endif