1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #ifndef skgpu_Swizzle_DEFINED
9 #define skgpu_Swizzle_DEFINED
10
11 #include "include/core/SkString.h"
12 #include "include/private/SkColorData.h"
13
14 class SkRasterPipeline;
15
16 namespace skgpu {
17
18 /** Represents a rgba swizzle. It can be converted either into a string or a eight bit int. */
19 class Swizzle {
20 public:
Swizzle()21 constexpr Swizzle() : Swizzle("rgba") {}
22 explicit constexpr Swizzle(const char c[4]);
23
24 constexpr Swizzle(const Swizzle&);
25 constexpr Swizzle& operator=(const Swizzle& that);
26
27 static constexpr Swizzle Concat(const Swizzle& a, const Swizzle& b);
28
29 constexpr bool operator==(const Swizzle& that) const { return fKey == that.fKey; }
30 constexpr bool operator!=(const Swizzle& that) const { return !(*this == that); }
31
32 /** Compact representation of the swizzle suitable for a key. */
asKey()33 constexpr uint16_t asKey() const { return fKey; }
34
35 /** 4 char null terminated string consisting only of chars 'r', 'g', 'b', 'a', '0', and '1'. */
36 SkString asString() const;
37
38 constexpr char operator[](int i) const {
39 SkASSERT(i >= 0 && i < 4);
40 int idx = (fKey >> (4U * i)) & 0xfU;
41 return IToC(idx);
42 }
43
44 /** Applies this swizzle to the input color and returns the swizzled color. */
45 constexpr std::array<float, 4> applyTo(std::array<float, 4> color) const;
46
47 /** Convenience version for SkRGBA colors. */
48 template <SkAlphaType AlphaType>
applyTo(SkRGBA4f<AlphaType> color)49 constexpr SkRGBA4f<AlphaType> applyTo(SkRGBA4f<AlphaType> color) const {
50 std::array<float, 4> result = this->applyTo(color.array());
51 return {result[0], result[1], result[2], result[3]};
52 }
53
54 void apply(SkRasterPipeline*) const;
55
RGBA()56 static constexpr Swizzle RGBA() { return Swizzle("rgba"); }
BGRA()57 static constexpr Swizzle BGRA() { return Swizzle("bgra"); }
RRRA()58 static constexpr Swizzle RRRA() { return Swizzle("rrra"); }
RGB1()59 static constexpr Swizzle RGB1() { return Swizzle("rgb1"); }
60
61 private:
Swizzle(uint16_t key)62 explicit constexpr Swizzle(uint16_t key) : fKey(key) {}
63
64 static constexpr float ComponentIndexToFloat(std::array<float, 4>, int idx);
65 static constexpr int CToI(char c);
66 static constexpr char IToC(int idx);
67
68 uint16_t fKey;
69 };
70
Swizzle(const char c[4])71 constexpr Swizzle::Swizzle(const char c[4])
72 : fKey((CToI(c[0]) << 0) | (CToI(c[1]) << 4) | (CToI(c[2]) << 8) | (CToI(c[3]) << 12)) {}
73
Swizzle(const Swizzle & that)74 constexpr Swizzle::Swizzle(const Swizzle& that)
75 : fKey(that.fKey) {}
76
77 constexpr Swizzle& Swizzle::operator=(const Swizzle& that) {
78 fKey = that.fKey;
79 return *this;
80 }
81
applyTo(std::array<float,4> color)82 constexpr std::array<float, 4> Swizzle::applyTo(std::array<float, 4> color) const {
83 uint32_t key = fKey;
84 // Index of the input color that should be mapped to output r.
85 int idx = (key & 15);
86 float outR = ComponentIndexToFloat(color, idx);
87 key >>= 4;
88 idx = (key & 15);
89 float outG = ComponentIndexToFloat(color, idx);
90 key >>= 4;
91 idx = (key & 15);
92 float outB = ComponentIndexToFloat(color, idx);
93 key >>= 4;
94 idx = (key & 15);
95 float outA = ComponentIndexToFloat(color, idx);
96 return { outR, outG, outB, outA };
97 }
98
ComponentIndexToFloat(std::array<float,4> color,int idx)99 constexpr float Swizzle::ComponentIndexToFloat(std::array<float, 4> color, int idx) {
100 if (idx <= 3) {
101 return color[idx];
102 }
103 if (idx == CToI('1')) {
104 return 1.0f;
105 }
106 if (idx == CToI('0')) {
107 return 0.0f;
108 }
109 SkUNREACHABLE;
110 }
111
CToI(char c)112 constexpr int Swizzle::CToI(char c) {
113 switch (c) {
114 // r...a must map to 0...3 because other methods use them as indices into fSwiz.
115 case 'r': return 0;
116 case 'g': return 1;
117 case 'b': return 2;
118 case 'a': return 3;
119 case '0': return 4;
120 case '1': return 5;
121 default: SkUNREACHABLE;
122 }
123 }
124
IToC(int idx)125 constexpr char Swizzle::IToC(int idx) {
126 switch (idx) {
127 case CToI('r'): return 'r';
128 case CToI('g'): return 'g';
129 case CToI('b'): return 'b';
130 case CToI('a'): return 'a';
131 case CToI('0'): return '0';
132 case CToI('1'): return '1';
133 default: SkUNREACHABLE;
134 }
135 }
136
Concat(const Swizzle & a,const Swizzle & b)137 constexpr Swizzle Swizzle::Concat(const Swizzle& a, const Swizzle& b) {
138 uint16_t key = 0;
139 for (int i = 0; i < 4; ++i) {
140 int idx = (b.fKey >> (4U * i)) & 0xfU;
141 if (idx != CToI('0') && idx != CToI('1')) {
142 SkASSERT(idx >= 0 && idx < 4);
143 // Get the index value stored in a at location idx.
144 idx = ((a.fKey >> (4U * idx)) & 0xfU);
145 }
146 key |= (idx << (4U * i));
147 }
148 return Swizzle(key);
149 }
150
151 } // namespace skgpu
152 #endif
153