blob: efafd7f1ab740579e3e16d26987cbee2d440c788 [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"
bsalomon@google.com08283af2012-10-26 13:01:20 +000014#include "GrEffectStage.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000015
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
bsalomon@google.coma469c282012-10-24 18:28:34 +000023 * created by subclassing GrEffect.
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000024 *
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.coma469c282012-10-24 18:28:34 +000042 * TODO: Encapsulate setXfermodeColorFilter in a GrEffect 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
bsalomon@google.com08283af2012-10-26 13:01:20 +0000116 * rect. In this case these are the pre-matrix coords to colorStage(0).
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000117 */
bsalomon@google.com08283af2012-10-26 13:01:20 +0000118 GrEffectStage* colorStage(int i) {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000119 GrAssert((unsigned)i < kMaxColorStages);
bsalomon@google.com08283af2012-10-26 13:01:20 +0000120 return fColorStages + i;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000121 }
122
bsalomon@google.com08283af2012-10-26 13:01:20 +0000123 const GrEffectStage& getColorStage(int i) const {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000124 GrAssert((unsigned)i < kMaxColorStages);
bsalomon@google.com08283af2012-10-26 13:01:20 +0000125 return fColorStages[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);
bsalomon@google.com08283af2012-10-26 13:01:20 +0000130 return (NULL != fColorStages[i].getEffect());
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.com08283af2012-10-26 13:01:20 +0000137 GrEffectStage* coverageStage(int i) {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000138 GrAssert((unsigned)i < kMaxCoverageStages);
bsalomon@google.com08283af2012-10-26 13:01:20 +0000139 return fCoverageStages + i;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000140 }
141
bsalomon@google.com08283af2012-10-26 13:01:20 +0000142 const GrEffectStage& getCoverageStage(int i) const {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000143 GrAssert((unsigned)i < kMaxCoverageStages);
bsalomon@google.com08283af2012-10-26 13:01:20 +0000144 return fCoverageStages[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);
bsalomon@google.com08283af2012-10-26 13:01:20 +0000149 return (NULL != fCoverageStages[i].getEffect());
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.com08283af2012-10-26 13:01:20 +0000187 fColorStages[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.com08283af2012-10-26 13:01:20 +0000197 fCoverageStages[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.com08283af2012-10-26 13:01:20 +0000210 fColorStages[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.com08283af2012-10-26 13:01:20 +0000215 fCoverageStages[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)) {
bsalomon@google.com08283af2012-10-26 13:01:20 +0000234 fColorStages[i] = paint.fColorStages[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)) {
bsalomon@google.com08283af2012-10-26 13:01:20 +0000239 fCoverageStages[i] = paint.fCoverageStages[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.com08283af2012-10-26 13:01:20 +0000253 this->resetStages();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000254 this->resetColorFilter();
Scroggo97c88c22011-05-11 14:05:25 +0000255 }
256
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000257 // 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 {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000261 kFirstColorStage = 0,
262 kFirstCoverageStage = kMaxColorStages,
263 kTotalStages = kFirstColorStage + kMaxColorStages + kMaxCoverageStages,
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000264 };
265
bsalomon@google.com27847de2011-02-22 20:59:41 +0000266private:
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000267
bsalomon@google.com08283af2012-10-26 13:01:20 +0000268 GrEffectStage fColorStages[kMaxColorStages];
269 GrEffectStage fCoverageStages[kMaxCoverageStages];
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000270
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000271 GrBlendCoeff fSrcBlendCoeff;
272 GrBlendCoeff fDstBlendCoeff;
273 bool fAntiAlias;
274 bool fDither;
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000275
276 GrColor fColor;
277 uint8_t fCoverage;
278
279 GrColor fColorFilterColor;
280 SkXfermode::Mode fColorFilterXfermode;
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000281
bsalomon@google.com27847de2011-02-22 20:59:41 +0000282 void resetBlend() {
bsalomon@google.com47059542012-06-06 20:51:20 +0000283 fSrcBlendCoeff = kOne_GrBlendCoeff;
284 fDstBlendCoeff = kZero_GrBlendCoeff;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000285 }
286
287 void resetOptions() {
288 fAntiAlias = false;
289 fDither = false;
290 }
291
292 void resetColor() {
293 fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
294 }
295
bsalomon@google.comdd1be602012-01-18 20:34:00 +0000296 void resetCoverage() {
297 fCoverage = 0xff;
298 }
299
bsalomon@google.com08283af2012-10-26 13:01:20 +0000300 void resetStages() {
bsalomon@google.com88becf42012-10-05 14:54:42 +0000301 for (int i = 0; i < kMaxColorStages; ++i) {
bsalomon@google.com08283af2012-10-26 13:01:20 +0000302 fColorStages[i].reset();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000303 }
bsalomon@google.com88becf42012-10-05 14:54:42 +0000304 for (int i = 0; i < kMaxCoverageStages; ++i) {
bsalomon@google.com08283af2012-10-26 13:01:20 +0000305 fCoverageStages[i].reset();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000306 }
307 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000308};
309
310#endif