blob: e61c1ccb922b4dd98c51f3a99409c209076756ae [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SkColorMatrix.h"
2
3#define kRScale 0
4#define kGScale 6
5#define kBScale 12
6#define kAScale 18
7
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +00008void SkColorMatrix::setIdentity() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00009 memset(fMat, 0, sizeof(fMat));
10 fMat[kRScale] = fMat[kGScale] = fMat[kBScale] = fMat[kAScale] = SK_Scalar1;
11}
12
13void SkColorMatrix::setScale(SkScalar rScale, SkScalar gScale, SkScalar bScale,
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +000014 SkScalar aScale) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000015 memset(fMat, 0, sizeof(fMat));
16 fMat[kRScale] = rScale;
17 fMat[kGScale] = gScale;
18 fMat[kBScale] = bScale;
19 fMat[kAScale] = aScale;
20}
21
22///////////////////////////////////////////////////////////////////////////////
23
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +000024void SkColorMatrix::setRotate(Axis axis, SkScalar degrees) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000025 SkScalar S, C;
26
27 S = SkScalarSinCos(SkDegreesToRadians(degrees), &C);
28
29 this->setSinCos(axis, S, C);
30}
31
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +000032void SkColorMatrix::setSinCos(Axis axis, SkScalar sine, SkScalar cosine) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000033 SkASSERT((unsigned)axis < 3);
34
35 static const uint8_t gRotateIndex[] = {
36 6, 7, 11, 12,
reed@android.com1d15d372009-11-10 17:58:47 +000037 0, 10, 2, 12,
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 0, 1, 5, 6,
39 };
40 const uint8_t* index = gRotateIndex + axis * 4;
41
42 this->setIdentity();
43 fMat[index[0]] = cosine;
44 fMat[index[1]] = sine;
45 fMat[index[2]] = -sine;
46 fMat[index[3]] = cosine;
47}
48
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +000049void SkColorMatrix::preRotate(Axis axis, SkScalar degrees) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000050 SkColorMatrix tmp;
51 tmp.setRotate(axis, degrees);
52 this->preConcat(tmp);
53}
54
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +000055void SkColorMatrix::postRotate(Axis axis, SkScalar degrees) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 SkColorMatrix tmp;
57 tmp.setRotate(axis, degrees);
58 this->postConcat(tmp);
59}
60
61///////////////////////////////////////////////////////////////////////////////
62
63void SkColorMatrix::setConcat(const SkColorMatrix& matA,
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +000064 const SkColorMatrix& matB) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000065 SkScalar tmp[20];
66 SkScalar* result = fMat;
67
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +000068 if (&matA == this || &matB == this) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000069 result = tmp;
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +000070 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000071
72 const SkScalar* a = matA.fMat;
73 const SkScalar* b = matB.fMat;
74
75 int index = 0;
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +000076 for (int j = 0; j < 20; j += 5) {
77 for (int i = 0; i < 4; i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000078 result[index++] = SkScalarMul(a[j + 0], b[i + 0]) +
79 SkScalarMul(a[j + 1], b[i + 5]) +
80 SkScalarMul(a[j + 2], b[i + 10]) +
81 SkScalarMul(a[j + 3], b[i + 15]);
82 }
83 result[index++] = SkScalarMul(a[j + 0], b[4]) +
84 SkScalarMul(a[j + 1], b[9]) +
85 SkScalarMul(a[j + 2], b[14]) +
86 SkScalarMul(a[j + 3], b[19]) +
87 a[j + 4];
88 }
89
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +000090 if (fMat != result) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000091 memcpy(fMat, result, sizeof(fMat));
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +000092 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000093}
94
95///////////////////////////////////////////////////////////////////////////////
96
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +000097static void setrow(SkScalar row[], SkScalar r, SkScalar g, SkScalar b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000098 row[0] = r;
99 row[1] = g;
100 row[2] = b;
101}
102
103static const SkScalar kHueR = SkFloatToScalar(0.213f);
104static const SkScalar kHueG = SkFloatToScalar(0.715f);
105static const SkScalar kHueB = SkFloatToScalar(0.072f);
106
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +0000107void SkColorMatrix::setSaturation(SkScalar sat) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108 memset(fMat, 0, sizeof(fMat));
109
110 const SkScalar R = SkScalarMul(kHueR, SK_Scalar1 - sat);
111 const SkScalar G = SkScalarMul(kHueG, SK_Scalar1 - sat);
112 const SkScalar B = SkScalarMul(kHueB, SK_Scalar1 - sat);
113
114 setrow(fMat + 0, R + sat, G, B);
115 setrow(fMat + 5, R, G + sat, B);
116 setrow(fMat + 10, R, G, B + sat);
117 fMat[18] = SK_Scalar1;
118}
119
120static const SkScalar kR2Y = SkFloatToScalar(0.299f);
121static const SkScalar kG2Y = SkFloatToScalar(0.587f);
122static const SkScalar kB2Y = SkFloatToScalar(0.114f);
123
124static const SkScalar kR2U = SkFloatToScalar(-0.16874f);
125static const SkScalar kG2U = SkFloatToScalar(-0.33126f);
126static const SkScalar kB2U = SkFloatToScalar(0.5f);
127
128static const SkScalar kR2V = SkFloatToScalar(0.5f);
129static const SkScalar kG2V = SkFloatToScalar(-0.41869f);
130static const SkScalar kB2V = SkFloatToScalar(-0.08131f);
131
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +0000132void SkColorMatrix::setRGB2YUV() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133 memset(fMat, 0, sizeof(fMat));
134
135 setrow(fMat + 0, kR2Y, kG2Y, kB2Y);
136 setrow(fMat + 5, kR2U, kG2U, kB2U);
137 setrow(fMat + 10, kR2V, kG2V, kB2V);
138 fMat[18] = SK_Scalar1;
139}
140
141static const SkScalar kV2R = SkFloatToScalar(1.402f);
142static const SkScalar kU2G = SkFloatToScalar(-0.34414f);
143static const SkScalar kV2G = SkFloatToScalar(-0.71414f);
144static const SkScalar kU2B = SkFloatToScalar(1.772f);
145
mike@reedtribe.org68ac0df2011-05-04 00:20:09 +0000146void SkColorMatrix::setYUV2RGB() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147 memset(fMat, 0, sizeof(fMat));
148
149 setrow(fMat + 0, SK_Scalar1, 0, kV2R);
150 setrow(fMat + 5, SK_Scalar1, kU2G, kV2G);
151 setrow(fMat + 10, SK_Scalar1, kU2B, 0);
152 fMat[18] = SK_Scalar1;
153}
154