blob: 9f9403e9e7272d080656c7048aaf74211840e2d9 [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
13#include "GrTexture.h"
14#include "GrColor.h"
15#include "GrSamplerState.h"
16
Scroggo97c88c22011-05-11 14:05:25 +000017#include "SkXfermode.h"
18
bsalomon@google.com27847de2011-02-22 20:59:41 +000019/**
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000020 * The paint describes how color and coverage are computed at each pixel by GrContext draw
21 * functions and the how color is blended with the destination pixel.
22 *
23 * The paint allows installation of custom color and coverage stages. New types of stages are
24 * created by subclassing GrCustomStage.
25 *
26 * The primitive color computation starts with the color specified by setColor(). This color is the
27 * input to the first color stage. Each color stage feeds its output to the next color stage. The
28 * final color stage's output color is input to the color filter specified by
29 * setXfermodeColorFilter which it turn feeds into the color matrix. The output of the color matrix
30 * is the final source color, S.
31 *
32 * Fractional pixel coverage follows a similar flow. The coverage is initially the value specified
33 * by setCoverage(). This is input to the first coverage stage. Coverage stages are chained
34 * together in the same manner as color stages. The output of the last stage is modulated by any
35 * fractional coverage produced by anti-aliasing. This last step produces the final coverage, C.
36 *
37 * setBlendFunc() specifies blending coefficients for S (described above) and D, the initial value
38 * of the destination pixel, labeled Bs and Bd respectively. The final value of the destination
39 * pixel is then D' = (1-C)*D + C*(Bd*D + Bs*S).
40 *
41 * Note that the coverage is applied after the blend. This is why they are computed as distinct
42 * values.
43 *
44 * TODO: Encapsulate setXfermodeColorFilter and color matrix in stages and remove from GrPaint.
bsalomon@google.com27847de2011-02-22 20:59:41 +000045 */
46class GrPaint {
47public:
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +000048 enum {
bsalomon@google.com88becf42012-10-05 14:54:42 +000049 kMaxColorStages = 2,
50 kMaxCoverageStages = 1,
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +000051 };
bsalomon@google.com27847de2011-02-22 20:59:41 +000052
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000053 GrPaint() { this->reset(); }
bsalomon@google.com27847de2011-02-22 20:59:41 +000054
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000055 GrPaint(const GrPaint& paint) { *this = paint; }
bsalomon@google.com27847de2011-02-22 20:59:41 +000056
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000057 ~GrPaint() {}
Scroggo97c88c22011-05-11 14:05:25 +000058
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000059 /**
60 * Sets the blending coefficients to use to blend the final primitive color with the
61 * destination color. Defaults to kOne for src and kZero for dst (i.e. src mode).
62 */
63 void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
64 fSrcBlendCoeff = srcCoeff;
65 fDstBlendCoeff = dstCoeff;
66 }
67 GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlendCoeff; }
68 GrBlendCoeff getDstBlendCoeff() const { return fDstBlendCoeff; }
69
70 /**
71 * The initial color of the drawn primitive. Defaults to solid white.
72 */
73 void setColor(GrColor color) { fColor = color; }
74 GrColor getColor() const { return fColor; }
75
76 /**
77 * Applies fractional coverage to the entire drawn primitive. Defaults to 0xff.
78 */
79 void setCoverage(uint8_t coverage) { fCoverage = coverage; }
80 uint8_t getCoverage() const { return fCoverage; }
81
82 /**
83 * Should primitives be anti-aliased or not. Defaults to false.
84 */
85 void setAntiAlias(bool aa) { fAntiAlias = aa; }
86 bool isAntiAlias() const { return fAntiAlias; }
87
88 /**
89 * Should dithering be applied. Defaults to false.
90 */
91 void setDither(bool dither) { fDither = dither; }
92 bool isDither() const { return fDither; }
93
94 /**
95 * Enables a SkXfermode::Mode-based color filter applied to the primitive color. The constant
96 * color passed to this function is considered the "src" color and the primitive's color is
97 * considered the "dst" color. Defaults to kDst_Mode which equates to simply passing through
98 * the primitive color unmodified.
99 */
100 void setXfermodeColorFilter(SkXfermode::Mode mode, GrColor color) {
101 fColorFilterColor = color;
102 fColorFilterXfermode = mode;
103 }
104 SkXfermode::Mode getColorFilterMode() const { return fColorFilterXfermode; }
105 GrColor getColorFilterColor() const { return fColorFilterColor; }
106
107 /**
108 * Turns off application of a color matrix. By default the color matrix is disabled.
109 */
110 void disableColorMatrix() { fColorMatrixEnabled = false; }
111
112 /**
113 * Specifies and enables a 4 x 5 color matrix.
114 */
115 void setColorMatrix(const float matrix[20]) {
116 fColorMatrixEnabled = true;
117 memcpy(fColorMatrix, matrix, sizeof(fColorMatrix));
118 }
119
120 bool isColorMatrixEnabled() const { return fColorMatrixEnabled; }
121 const float* getColorMatrix() const { return fColorMatrix; }
122
123 /**
124 * Disables both the matrix and SkXfermode::Mode color filters.
125 */
126 void resetColorFilter() {
127 fColorFilterXfermode = SkXfermode::kDst_Mode;
128 fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
129 fColorMatrixEnabled = false;
130 }
131
132 /**
133 * Specifies a stage of the color pipeline. Usually the texture matrices of color stages apply
134 * to the primitive's positions. Some GrContext calls take explicit coords as an array or a
135 * rect. In this case these are the pre-matrix coords to colorSampler(0).
136 */
bsalomon@google.com88becf42012-10-05 14:54:42 +0000137 GrSamplerState* colorSampler(int i) {
138 GrAssert((unsigned)i < kMaxColorStages);
139 return fColorSamplers + i;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000140 }
141
bsalomon@google.com88becf42012-10-05 14:54:42 +0000142 const GrSamplerState& getColorSampler(int i) const {
143 GrAssert((unsigned)i < kMaxColorStages);
144 return fColorSamplers[i];
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000145 }
146
bsalomon@google.com88becf42012-10-05 14:54:42 +0000147 bool isColorStageEnabled(int i) const {
148 GrAssert((unsigned)i < kMaxColorStages);
149 return (NULL != fColorSamplers[i].getCustomStage());
tomhudson@google.comf13f5882012-06-25 17:27:28 +0000150 }
151
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000152 /**
153 * Specifies a stage of the coverage pipeline. Coverage stages' texture matrices are always
154 * applied to the primitive's position, never to explicit texture coords.
155 */
bsalomon@google.com88becf42012-10-05 14:54:42 +0000156 GrSamplerState* coverageSampler(int i) {
157 GrAssert((unsigned)i < kMaxCoverageStages);
158 return fCoverageSamplers + i;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000159 }
160
bsalomon@google.com88becf42012-10-05 14:54:42 +0000161 const GrSamplerState& getCoverageSampler(int i) const {
162 GrAssert((unsigned)i < kMaxCoverageStages);
163 return fCoverageSamplers[i];
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000164 }
165
bsalomon@google.com88becf42012-10-05 14:54:42 +0000166 bool isCoverageStageEnabled(int i) const {
167 GrAssert((unsigned)i < kMaxCoverageStages);
168 return (NULL != fCoverageSamplers[i].getCustomStage());
tomhudson@google.comf13f5882012-06-25 17:27:28 +0000169 }
170
bsalomon@google.com88becf42012-10-05 14:54:42 +0000171 bool hasCoverageStage() const {
172 for (int i = 0; i < kMaxCoverageStages; ++i) {
173 if (this->isCoverageStageEnabled(i)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000174 return true;
175 }
176 }
177 return false;
178 }
179
bsalomon@google.com88becf42012-10-05 14:54:42 +0000180 bool hasColorStage() const {
181 for (int i = 0; i < kMaxColorStages; ++i) {
182 if (this->isColorStageEnabled(i)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000183 return true;
184 }
185 }
186 return false;
187 }
188
bsalomon@google.com88becf42012-10-05 14:54:42 +0000189 bool hasStage() const { return this->hasColorStage() || this->hasCoverageStage(); }
bsalomon@google.come3d32162012-07-20 13:37:06 +0000190
191 /**
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000192 * Preconcats the matrix of all samplers in the mask with the inverse of a matrix. If the
193 * matrix inverse cannot be computed (and there is at least one enabled stage) then false is
194 * returned.
bsalomon@google.come3d32162012-07-20 13:37:06 +0000195 */
196 bool preConcatSamplerMatricesWithInverse(const GrMatrix& matrix) {
197 GrMatrix inv;
198 bool computed = false;
bsalomon@google.com88becf42012-10-05 14:54:42 +0000199 for (int i = 0; i < kMaxColorStages; ++i) {
200 if (this->isColorStageEnabled(i)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000201 if (!computed && !matrix.invert(&inv)) {
202 return false;
203 } else {
204 computed = true;
205 }
bsalomon@google.com88becf42012-10-05 14:54:42 +0000206 fColorSamplers[i].preConcatMatrix(inv);
bsalomon@google.come3d32162012-07-20 13:37:06 +0000207 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000208 }
bsalomon@google.com88becf42012-10-05 14:54:42 +0000209 for (int i = 0; i < kMaxCoverageStages; ++i) {
210 if (this->isCoverageStageEnabled(i)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000211 if (!computed && !matrix.invert(&inv)) {
212 return false;
213 } else {
214 computed = true;
215 }
bsalomon@google.com88becf42012-10-05 14:54:42 +0000216 fCoverageSamplers[i].preConcatMatrix(inv);
bsalomon@google.come3d32162012-07-20 13:37:06 +0000217 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000218 }
bsalomon@google.come3d32162012-07-20 13:37:06 +0000219 return true;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000220 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000221
bsalomon@google.com27c9b6d2011-09-12 14:30:27 +0000222 GrPaint& operator=(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000223 fSrcBlendCoeff = paint.fSrcBlendCoeff;
224 fDstBlendCoeff = paint.fDstBlendCoeff;
225 fAntiAlias = paint.fAntiAlias;
226 fDither = paint.fDither;
227
228 fColor = paint.fColor;
bsalomon@google.comdd1be602012-01-18 20:34:00 +0000229 fCoverage = paint.fCoverage;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000230
Scroggo97c88c22011-05-11 14:05:25 +0000231 fColorFilterColor = paint.fColorFilterColor;
232 fColorFilterXfermode = paint.fColorFilterXfermode;
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +0000233 fColorMatrixEnabled = paint.fColorMatrixEnabled;
bsalomon@google.comdddf6f62012-03-16 17:50:37 +0000234 if (fColorMatrixEnabled) {
235 memcpy(fColorMatrix, paint.fColorMatrix, sizeof(fColorMatrix));
236 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000237
bsalomon@google.com88becf42012-10-05 14:54:42 +0000238 for (int i = 0; i < kMaxColorStages; ++i) {
239 if (paint.isColorStageEnabled(i)) {
240 fColorSamplers[i] = paint.fColorSamplers[i];
bsalomon@google.comdddf6f62012-03-16 17:50:37 +0000241 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000242 }
bsalomon@google.com88becf42012-10-05 14:54:42 +0000243 for (int i = 0; i < kMaxCoverageStages; ++i) {
244 if (paint.isCoverageStageEnabled(i)) {
245 fCoverageSamplers[i] = paint.fCoverageSamplers[i];
bsalomon@google.comdddf6f62012-03-16 17:50:37 +0000246 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000247 }
bsalomon@google.com27c9b6d2011-09-12 14:30:27 +0000248 return *this;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000249 }
250
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000251 /**
252 * Resets the paint to the defaults.
253 */
bsalomon@google.com27847de2011-02-22 20:59:41 +0000254 void reset() {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000255 this->resetBlend();
256 this->resetOptions();
257 this->resetColor();
bsalomon@google.comdd1be602012-01-18 20:34:00 +0000258 this->resetCoverage();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000259 this->resetTextures();
260 this->resetColorFilter();
261 this->resetMasks();
Scroggo97c88c22011-05-11 14:05:25 +0000262 }
263
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000264 // internal use
265 // GrPaint's textures and masks map to the first N stages
266 // of GrDrawTarget in that order (textures followed by masks)
267 enum {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000268 kFirstColorStage = 0,
269 kFirstCoverageStage = kMaxColorStages,
270 kTotalStages = kFirstColorStage + kMaxColorStages + kMaxCoverageStages,
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000271 };
272
bsalomon@google.com27847de2011-02-22 20:59:41 +0000273private:
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000274
bsalomon@google.com88becf42012-10-05 14:54:42 +0000275 GrSamplerState fColorSamplers[kMaxColorStages];
276 GrSamplerState fCoverageSamplers[kMaxCoverageStages];
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000277
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000278 GrBlendCoeff fSrcBlendCoeff;
279 GrBlendCoeff fDstBlendCoeff;
280 bool fAntiAlias;
281 bool fDither;
282 bool fColorMatrixEnabled;
283
284 GrColor fColor;
285 uint8_t fCoverage;
286
287 GrColor fColorFilterColor;
288 SkXfermode::Mode fColorFilterXfermode;
289 float fColorMatrix[20];
290
bsalomon@google.com27847de2011-02-22 20:59:41 +0000291 void resetBlend() {
bsalomon@google.com47059542012-06-06 20:51:20 +0000292 fSrcBlendCoeff = kOne_GrBlendCoeff;
293 fDstBlendCoeff = kZero_GrBlendCoeff;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000294 }
295
296 void resetOptions() {
297 fAntiAlias = false;
298 fDither = false;
299 }
300
301 void resetColor() {
302 fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
303 }
304
bsalomon@google.comdd1be602012-01-18 20:34:00 +0000305 void resetCoverage() {
306 fCoverage = 0xff;
307 }
308
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000309 void resetTextures() {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000310 for (int i = 0; i < kMaxColorStages; ++i) {
311 fColorSamplers[i].reset();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000312 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000313 }
314
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000315 void resetMasks() {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000316 for (int i = 0; i < kMaxCoverageStages; ++i) {
317 fCoverageSamplers[i].reset();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000318 }
319 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000320};
321
322#endif