1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef API_BASE_UTIL_COLOR_H
17 #define API_BASE_UTIL_COLOR_H
18
19 #include <cstdint>
20
21 #include <base/math/vector.h>
22 #include <base/namespace.h>
23
24 BASE_BEGIN_NAMESPACE()
25 constexpr const uint8_t COLOR_SHIFT_0 = 0;
26 constexpr const uint8_t COLOR_SHIFT_8 = 8;
27 constexpr const uint8_t COLOR_SHIFT_16 = 16;
28 constexpr const uint8_t COLOR_SHIFT_24 = 24;
29
30 constexpr const bool MAKE_COLOR_AS_LINEAR = true;
31
32 /** Color values are in linear space (non premultiplied value)
33 * Linear color space (non-srgb values)
34 * Prefer using 32-bit color (uint32_t) in sRGB format
35 */
36 using Color = Math::Vec4;
37
SRGBToLinearConv(const float srgb)38 inline float SRGBToLinearConv(const float srgb)
39 {
40 float col = srgb;
41 if (srgb <= 0.04045f) {
42 col *= (1.f / 12.92f);
43 } else {
44 col = Math::pow((col + 0.055f) * (1.f / 1.055f), 2.4f);
45 }
46 return col;
47 }
48
LinearToSRGBConv(const float linear)49 inline float LinearToSRGBConv(const float linear)
50 {
51 float srgb = linear;
52 if (srgb <= 0.0031308f) {
53 srgb *= 12.92f;
54 } else {
55 srgb = 1.0550000667572021484375f * Math::pow(srgb, 1.f / 2.4f) - 0.05500000715255737305f;
56 }
57 return srgb;
58 }
59
60 /** Input color in linear ARGB format (uint32_t)
61 * Output color in linear (Vec4)
62 */
MakeColorFromLinear(const uint32_t color)63 constexpr Color MakeColorFromLinear(const uint32_t color)
64 {
65 uint8_t b = (color >> COLOR_SHIFT_0) & UINT8_MAX;
66 uint8_t g = (color >> COLOR_SHIFT_8) & UINT8_MAX;
67 uint8_t r = (color >> COLOR_SHIFT_16) & UINT8_MAX;
68 uint8_t a = (color >> COLOR_SHIFT_24) & UINT8_MAX;
69
70 return { r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f };
71 }
72
73 /** Input color in sRGB ARGB format (uint32_t)
74 * Output color in linear (Vec4)
75 */
MakeColorFromSRGB(const uint32_t color)76 inline Color MakeColorFromSRGB(const uint32_t color)
77 {
78 uint8_t b = (color >> COLOR_SHIFT_0) & UINT8_MAX;
79 uint8_t g = (color >> COLOR_SHIFT_8) & UINT8_MAX;
80 uint8_t r = (color >> COLOR_SHIFT_16) & UINT8_MAX;
81 uint8_t a = (color >> COLOR_SHIFT_24) & UINT8_MAX;
82
83 return { SRGBToLinearConv(r / 255.0f), SRGBToLinearConv(g / 255.0f), SRGBToLinearConv(b / 255.0f), a / 255.0f };
84 }
85
86 /** Input color in linear (Vec4)
87 * Output color in linear (uint32_t)
88 */
FromColorToLinear(Color color)89 constexpr uint32_t FromColorToLinear(Color color)
90 {
91 color *= 255.f;
92 uint32_t b = (static_cast<uint32_t>(color.z) & UINT8_MAX) << COLOR_SHIFT_0;
93 uint32_t g = (static_cast<uint32_t>(color.y) & UINT8_MAX) << COLOR_SHIFT_8;
94 uint32_t r = (static_cast<uint32_t>(color.x) & UINT8_MAX) << COLOR_SHIFT_16;
95 uint32_t a = (static_cast<uint32_t>(color.w) & UINT8_MAX) << COLOR_SHIFT_24;
96
97 return a | r | g | b;
98 }
99
100 /** Input color in linear (Vec4)
101 * Output color in sRGB (uint32_t)
102 */
FromColorToSRGB(Color color)103 inline uint32_t FromColorToSRGB(Color color)
104 {
105 // rounding should be handled in some smart way to get actual min and max values too
106 uint32_t b = (static_cast<uint32_t>(LinearToSRGBConv(color.z) * 255.f) & UINT8_MAX) << COLOR_SHIFT_0;
107 uint32_t g = (static_cast<uint32_t>(LinearToSRGBConv(color.y) * 255.f) & UINT8_MAX) << COLOR_SHIFT_8;
108 uint32_t r = (static_cast<uint32_t>(LinearToSRGBConv(color.x) * 255.f) & UINT8_MAX) << COLOR_SHIFT_16;
109 uint32_t a = (static_cast<uint32_t>(color.w * 255.f) & UINT8_MAX) << COLOR_SHIFT_24;
110
111 return a | r | g | b;
112 }
113
114 /** Input color in linear (Vec4)
115 * Output color in linear (uint32_t)
116 */
FromColorRGBAToLinear(Color color)117 constexpr uint32_t FromColorRGBAToLinear(Color color)
118 {
119 color *= 255.f;
120 uint32_t r = (static_cast<uint32_t>(color.x) & UINT8_MAX) << COLOR_SHIFT_0;
121 uint32_t b = (static_cast<uint32_t>(color.z) & UINT8_MAX) << COLOR_SHIFT_16;
122 uint32_t g = (static_cast<uint32_t>(color.y) & UINT8_MAX) << COLOR_SHIFT_8;
123 uint32_t a = (static_cast<uint32_t>(color.w) & UINT8_MAX) << COLOR_SHIFT_24;
124
125 return a | b | g | r;
126 }
127
128 /** Input color in linear (Vec4)
129 * Output color in sRGB (uint32_t)
130 */
FromColorRGBAToSRGB(Color color)131 inline uint32_t FromColorRGBAToSRGB(Color color)
132 {
133 uint32_t r = (static_cast<uint32_t>(LinearToSRGBConv(color.x) * 255.0f) & UINT8_MAX) << COLOR_SHIFT_0;
134 uint32_t b = (static_cast<uint32_t>(LinearToSRGBConv(color.z) * 255.0f) & UINT8_MAX) << COLOR_SHIFT_16;
135 uint32_t g = (static_cast<uint32_t>(LinearToSRGBConv(color.y) * 255.0f) & UINT8_MAX) << COLOR_SHIFT_8;
136 uint32_t a = (static_cast<uint32_t>(color.w * 255.0f) & UINT8_MAX) << COLOR_SHIFT_24;
137
138 return a | b | g | r;
139 }
140
FromColorRGBA(const Color color)141 inline uint32_t FromColorRGBA(const Color color)
142 {
143 if (MAKE_COLOR_AS_LINEAR) {
144 return FromColorRGBAToLinear(color);
145 } else {
146 return FromColorRGBAToSRGB(color);
147 }
148 }
149
150 static const Color BLACK_COLOR = MakeColorFromLinear(0xFF000000);
151 static const Color WHITE_COLOR = MakeColorFromLinear(0xFFFFFFFF);
152 BASE_END_NAMESPACE()
153
154 #endif // API_BASE_UTIL_COLOR_H
155