/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrPaint_DEFINED
#define GrPaint_DEFINED
#include "GrTexture.h"
#include "GrColor.h"
#include "GrSamplerState.h"
#include "SkXfermode.h"
/**
* The paint describes how pixels are colored when the context draws to
* them. TODO: Make this a "real" class with getters and setters, default
* values, and documentation.
*/
class GrPaint {
public:
enum {
kMaxTextures = 1,
kMaxMasks = 1,
};
// All the paint fields are public except textures/samplers
GrBlendCoeff fSrcBlendCoeff;
GrBlendCoeff fDstBlendCoeff;
bool fAntiAlias;
bool fDither;
bool fColorMatrixEnabled;
GrColor fColor;
uint8_t fCoverage;
GrColor fColorFilterColor;
SkXfermode::Mode fColorFilterXfermode;
float fColorMatrix[20];
void setTexture(int i, GrTexture* texture) {
GrAssert((unsigned)i < kMaxTextures);
GrSafeRef(texture);
GrSafeUnref(fTextures[i]);
fTextures[i] = texture;
}
GrTexture* getTexture(int i) const {
GrAssert((unsigned)i < kMaxTextures);
return fTextures[i];
}
GrSamplerState* textureSampler(int i) {
GrAssert((unsigned)i < kMaxTextures);
return fTextureSamplers + i;
}
const GrSamplerState& getTextureSampler(int i) const {
GrAssert((unsigned)i < kMaxTextures);
return fTextureSamplers[i];
}
// The mask can be alpha-only or per channel. It is applied
// after the colorfilter
void setMask(int i, GrTexture* mask) {
GrAssert((unsigned)i < kMaxMasks);
GrSafeRef(mask);
GrSafeUnref(fMaskTextures[i]);
fMaskTextures[i] = mask;
}
GrTexture* getMask(int i) const {
GrAssert((unsigned)i < kMaxMasks);
return fMaskTextures[i];
}
// mask's sampler matrix is always applied to the positions
// (i.e. no explicit texture coordinates)
GrSamplerState* maskSampler(int i) {
GrAssert((unsigned)i < kMaxMasks);
return fMaskSamplers + i;
}
const GrSamplerState& getMaskSampler(int i) const {
GrAssert((unsigned)i < kMaxMasks);
return fMaskSamplers[i];
}
// pre-concats sampler matrices for non-NULL textures and masks
void preConcatActiveSamplerMatrices(const GrMatrix& matrix) {
for (int i = 0; i < kMaxTextures; ++i) {
fTextureSamplers[i].preConcatMatrix(matrix);
}
for (int i = 0; i < kMaxMasks; ++i) {
fMaskSamplers[i].preConcatMatrix(matrix);
}
}
// uninitialized
GrPaint() {
for (int i = 0; i < kMaxTextures; ++i) {
fTextures[i] = NULL;
}
for (int i = 0; i < kMaxMasks; ++i) {
fMaskTextures[i] = NULL;
}
}
GrPaint(const GrPaint& paint) {
for (int i = 0; i < kMaxTextures; ++i) {
fTextures[i] = NULL;
}
for (int i = 0; i < kMaxMasks; ++i) {
fMaskTextures[i] = NULL;
}
*this = paint;
}
GrPaint& operator=(const GrPaint& paint) {
fSrcBlendCoeff = paint.fSrcBlendCoeff;
fDstBlendCoeff = paint.fDstBlendCoeff;
fAntiAlias = paint.fAntiAlias;
fDither = paint.fDither;
fColor = paint.fColor;
fCoverage = paint.fCoverage;
fColorFilterColor = paint.fColorFilterColor;
fColorFilterXfermode = paint.fColorFilterXfermode;
memcpy(fColorMatrix, paint.fColorMatrix, sizeof(fColorMatrix));
fColorMatrixEnabled = paint.fColorMatrixEnabled;
for (int i = 0; i < kMaxTextures; ++i) {
GrSafeUnref(fTextures[i]);
fTextureSamplers[i] = paint.fTextureSamplers[i];
fTextures[i] = paint.fTextures[i];
GrSafeRef(fTextures[i]);
}
for (int i = 0; i < kMaxMasks; ++i) {
GrSafeUnref(fMaskTextures[i]);
fMaskSamplers[i] = paint.fMaskSamplers[i];
fMaskTextures[i] = paint.fMaskTextures[i];
GrSafeRef(fMaskTextures[i]);
}
return *this;
}
~GrPaint() {
for (int i = 0; i < kMaxTextures; ++i) {
GrSafeUnref(fTextures[i]);
}
for (int i = 0; i < kMaxMasks; ++i) {
GrSafeUnref(fMaskTextures[i]);
}
}
// sets paint to src-over, solid white, no texture, no mask
void reset() {
this->resetBlend();
this->resetOptions();
this->resetColor();
this->resetCoverage();
this->resetTextures();
this->resetColorFilter();
this->resetMasks();
}
void resetColorFilter() {
fColorFilterXfermode = SkXfermode::kDst_Mode;
fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
memset(fColorMatrix, 0, sizeof(fColorMatrix));
fColorMatrixEnabled = false;
}
bool hasTexture() const {
return 0 != this->getActiveTextureStageMask();
}
bool hasMask() const {
return 0 != this->getActiveMaskStageMask();
}
bool hasTextureOrMask() const {
return this->hasTexture() || this->hasMask();
}
// helpers for GrContext, GrTextContext
int getActiveTextureStageMask() const {
int mask = 0;
for (int i = 0; i < kMaxTextures; ++i) {
if (NULL != fTextures[i]) {
mask |= 1 << (i + kFirstTextureStage);
}
}
return mask;
}
int getActiveMaskStageMask() const {
int mask = 0;
for (int i = 0; i < kMaxMasks; ++i) {
if (NULL != fMaskTextures[i]) {
mask |= 1 << (i + kFirstMaskStage);
}
}
return mask;
}
int getActiveStageMask() const {
return this->getActiveTextureStageMask() |
this->getActiveMaskStageMask();
}
// internal use
// GrPaint's textures and masks map to the first N stages
// of GrDrawTarget in that order (textures followed by masks)
enum {
kFirstTextureStage = 0,
kFirstMaskStage = kMaxTextures,
kTotalStages = kMaxTextures + kMaxMasks,
};
private:
GrSamplerState fTextureSamplers[kMaxTextures];
GrSamplerState fMaskSamplers[kMaxMasks];
GrTexture* fTextures[kMaxTextures];
GrTexture* fMaskTextures[kMaxMasks];
void resetBlend() {
fSrcBlendCoeff = kOne_BlendCoeff;
fDstBlendCoeff = kZero_BlendCoeff;
}
void resetOptions() {
fAntiAlias = false;
fDither = false;
}
void resetColor() {
fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
}
void resetCoverage() {
fCoverage = 0xff;
}
void resetTextures() {
for (int i = 0; i < kMaxTextures; ++i) {
this->setTexture(i, NULL);
fTextureSamplers[i].reset();
}
}
void resetMasks() {
for (int i = 0; i < kMaxMasks; ++i) {
this->setMask(i, NULL);
fMaskSamplers[i].reset();
}
}
};
#endif