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