• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 /** Color values are in linear space (non premultiplied value)
31  * Linear color space (non-srgb values)
32  * Default initialized to ones (opaque white).
33  */
34 class Color {
35 public:
36     union {
37         struct {
38             float x;
39             float y;
40             float z;
41             float w;
42         };
43         struct {
44             float r;
45             float g;
46             float b;
47             float a;
48         };
49 
50         float data[4] { 0.0f };
51     };
52 
Color()53     constexpr Color() noexcept : x(1.f), y(1.f), z(1.f), w(1.f) {}
54 
Color(float val)55     constexpr explicit Color(float val) noexcept : x(val), y(val), z(val), w(val) {}
56 
57     /** Will set the alpha channel to 1.0
58      */
Color(float x,float y,float z)59     constexpr Color(float x, float y, float z) noexcept : x(x), y(y), z(z), w(1.0f) {}
60 
Color(float x,float y,float z,float w)61     constexpr Color(float x, float y, float z, float w) noexcept : x(x), y(y), z(z), w(w) {}
62 
63     /** Constructs Color from ARGB format (uint32_t)
64      */
Color(const uint32_t color)65     constexpr explicit Color(const uint32_t color) noexcept
66         : x(((color >> COLOR_SHIFT_16) & UINT8_MAX) / 255.0f), y(((color >> COLOR_SHIFT_8) & UINT8_MAX) / 255.0f),
67           z(((color >> COLOR_SHIFT_0) & UINT8_MAX) / 255.0f), w(((color >> COLOR_SHIFT_24) & UINT8_MAX) / 255.0f)
68     {}
69 
Color(const BASE_NS::Math::Vec4 & other)70     constexpr explicit Color(const BASE_NS::Math::Vec4& other) noexcept : x(other.x), y(other.y), z(other.z), w(other.w)
71     {}
72 
73     constexpr void operator=(const BASE_NS::Math::Vec4& other) noexcept
74     {
75         x = other.x;
76         y = other.y;
77         z = other.z;
78         w = other.w;
79     }
80 
81     constexpr Color operator+(const Color& other) const noexcept
82     {
83         Color result;
84         result.x = x + other.x;
85         result.y = y + other.y;
86         result.z = z + other.z;
87         result.w = w + other.w;
88 
89         return result;
90     }
91 
92     constexpr Color operator-(const Color& other) const noexcept
93     {
94         Color result;
95         result.x = x - other.x;
96         result.y = y - other.y;
97         result.z = z - other.z;
98         result.w = w - other.w;
99 
100         return result;
101     }
102 
103     constexpr Color operator*(const Color& other) const noexcept
104     {
105         Color result;
106         result.x = x * other.x;
107         result.y = y * other.y;
108         result.z = z * other.z;
109         result.w = w * other.w;
110 
111         return result;
112     }
113 
114     constexpr Color operator/(const Color& other) const noexcept
115     {
116         Color result;
117         result.x = other.x != 0.f ? x / other.x : 0.f;
118         result.y = other.y != 0.f ? y / other.y : 0.f;
119         result.z = other.z != 0.f ? z / other.z : 0.f;
120         result.w = other.w != 0.f ? w / other.w : 0.f;
121 
122         return result;
123     }
124 
125     constexpr Color operator*(const float scalar) const noexcept
126     {
127         Color result;
128         result.x = x * scalar;
129         result.y = y * scalar;
130         result.z = z * scalar;
131         result.w = w * scalar;
132 
133         return result;
134     }
135 
136     constexpr Color operator/(const float scalar) const noexcept
137     {
138         if (scalar != 0.f) {
139             Color result;
140             result.x = x / scalar;
141             result.y = y / scalar;
142             result.z = z / scalar;
143             result.w = w / scalar;
144 
145             return result;
146         }
147 
148         return *this;
149     }
150 
151     constexpr Color& operator*=(const float scalar) noexcept
152     {
153         x *= scalar;
154         y *= scalar;
155         z *= scalar;
156         w *= scalar;
157 
158         return *this;
159     }
160 
161     constexpr Color& operator/=(const float scalar) noexcept
162     {
163         if (scalar != 0.f) {
164             x /= scalar;
165             y /= scalar;
166             z /= scalar;
167             w /= scalar;
168         }
169 
170         return *this;
171     }
172 
173     constexpr bool operator==(const Color& other) const noexcept
174     {
175         return x == other.x && y == other.y && z == other.z && w == other.w;
176     }
177 
178     constexpr bool operator!=(const Color& other) const noexcept
179     {
180         return x != other.x || y != other.y || z != other.z || w != other.w;
181     }
182 
183     constexpr float& operator[](const uint32_t index) noexcept
184     {
185         switch (index) {
186             case 0: // 0: index
187                 return x;
188             case 1: // 1: index
189                 return y;
190             case 2: // 2: index
191                 return z;
192             case 3: // 3: index
193                 return w;
194             default: // do nothing
195                 break;
196         }
197 
198         return x; // dummy
199     }
200 
201     constexpr const float& operator[](const uint32_t index) const noexcept
202     {
203         switch (index) {
204             case 0: // 0: index
205                 return x;
206             case 1: // 1: index
207                 return y;
208             case 2: // 2: index
209                 return z;
210             case 3: // 3: index
211                 return w;
212             default: // do nothing
213                 break;
214         }
215 
216         return x; // dummy
217     }
218 
219     /** Returns Color's members as Math::Vec4
220      */
Vec4()221     constexpr operator Math::Vec4() const noexcept
222     {
223         return Math::Vec4(x, y, z, w);
224     }
225 
GetLerp(const Color & other,float weight)226     constexpr Color GetLerp(const Color& other, float weight) const noexcept
227     {
228         Color result = *this;
229         result.x = Math::lerp(result.x, other.x, weight);
230         result.y = Math::lerp(result.y, other.y, weight);
231         result.z = Math::lerp(result.z, other.z, weight);
232         result.w = Math::lerp(result.w, other.w, weight);
233 
234         return result;
235     }
236 
GetRgba32()237     inline uint32_t GetRgba32() const noexcept
238     {
239         uint32_t c = (uint8_t)Math::round(x * 255.0f);
240         c <<= COLOR_SHIFT_8;
241         c |= (uint8_t)Math::round(y * 255.0f);
242         c <<= COLOR_SHIFT_8;
243         c |= (uint8_t)Math::round(z * 255.0f);
244         c <<= COLOR_SHIFT_8;
245         c |= (uint8_t)Math::round(w * 255.0f);
246 
247         return c;
248     }
249 
GetRgba64()250     inline uint64_t GetRgba64() const noexcept
251     {
252         uint64_t c = (uint16_t)Math::round(x * 65535.0f);
253         c <<= COLOR_SHIFT_16;
254         c |= (uint16_t)Math::round(y * 65535.0f);
255         c <<= COLOR_SHIFT_16;
256         c |= (uint16_t)Math::round(z * 65535.0f);
257         c <<= COLOR_SHIFT_16;
258         c |= (uint16_t)Math::round(w * 65535.0f);
259 
260         return c;
261     }
262 
GetArgb32()263     inline uint32_t GetArgb32() const noexcept
264     {
265         uint32_t c = (uint8_t)Math::round(w * 255.0f);
266         c <<= COLOR_SHIFT_8;
267         c |= (uint8_t)Math::round(x * 255.0f);
268         c <<= COLOR_SHIFT_8;
269         c |= (uint8_t)Math::round(y * 255.0f);
270         c <<= COLOR_SHIFT_8;
271         c |= (uint8_t)Math::round(z * 255.0f);
272 
273         return c;
274     }
275 
GetArgb64()276     inline uint64_t GetArgb64() const noexcept
277     {
278         uint64_t c = (uint16_t)Math::round(w * 65535.0f);
279         c <<= COLOR_SHIFT_16;
280         c |= (uint16_t)Math::round(x * 65535.0f);
281         c <<= COLOR_SHIFT_16;
282         c |= (uint16_t)Math::round(y * 65535.0f);
283         c <<= COLOR_SHIFT_16;
284         c |= (uint16_t)Math::round(z * 65535.0f);
285 
286         return c;
287     }
288 
GetLuminanceLinear()289     constexpr float GetLuminanceLinear() const noexcept
290     {
291         return x * 0.299f + y * 0.587f + z * 0.114f;
292     }
293 
GetLuminanceSrgb()294     constexpr float GetLuminanceSrgb() const noexcept
295     {
296         return x * 0.2126f + y * 0.7152f + z * 0.0722f;
297     }
298 
GetGamma()299     inline Color GetGamma() const
300     {
301         Color result = *this;
302         result.x = Math::pow(result.x, 1.f / 2.2f);
303         result.y = Math::pow(result.y, 1.f / 2.2f);
304         result.z = Math::pow(result.z, 1.f / 2.2f);
305 
306         return result;
307     }
308 
GetGrayscaleSrgb()309     constexpr Color GetGrayscaleSrgb() const noexcept
310     {
311         float luminance = GetLuminanceSrgb();
312         return Color(luminance, luminance, luminance, w);
313     }
314 
GetGrayscaleLinear()315     constexpr Color GetGrayscaleLinear() const noexcept
316     {
317         float luminance = GetLuminanceLinear();
318         return Color(luminance, luminance, luminance, w);
319     }
320 };
321 
322 /** Color conversion types
323  */
324 enum ColorConversionType {
325     /** No conversion and should be used as default */
326     COLOR_CONVERSION_TYPE_NONE = 0,
327     /** sRGB to linear conversion */
328     COLOR_CONVERSION_TYPE_SRGB_TO_LINEAR = 1,
329     /** Linear to sRGB conversion */
330     COLOR_CONVERSION_TYPE_LINEAR_TO_SRGB = 2,
331 };
332 
333 /** Color space flag bits
334  * Defaults are linear
335  */
336 enum ColorSpaceFlagBits {
337     /** Add hint to treat typical sRGB data as linear with input data and with final output (swapchain)
338      * This value should be retrieved from the engine and use with all (or some of) the plugins
339      * NOTE: mainly affects the input formats where data is written into (and typically results as non-srgb formats),
340      * and swapchain formats.
341      */
342     COLOR_SPACE_SRGB_AS_LINEAR_BIT = 0x00000001,
343 };
344 /** Container for color space flag bits */
345 using ColorSpaceFlags = uint32_t;
346 
SRGBToLinearConv(const float srgb)347 inline float SRGBToLinearConv(const float srgb)
348 {
349     float col = srgb;
350     if (srgb <= 0.04045f) {
351         col *= (1.f / 12.92f);
352     } else {
353         col = Math::pow((col + 0.055f) * (1.f / 1.055f), 2.4f);
354     }
355     return col;
356 }
357 
LinearToSRGBConv(const float linear)358 inline float LinearToSRGBConv(const float linear)
359 {
360     float srgb = linear;
361     if (srgb <= 0.0031308f) {
362         srgb *= 12.92f;
363     } else {
364         srgb = 1.0550000667572021484375f * Math::pow(srgb, 1.f / 2.4f) - 0.05500000715255737305f;
365     }
366     return srgb;
367 }
368 
369 /** Input color in linear ARGB format (uint32_t)
370  * Output color in linear (Vec4)
371  */
MakeColorFromLinear(const uint32_t color)372 constexpr Color MakeColorFromLinear(const uint32_t color)
373 {
374     return Color(color);
375 }
376 
377 /** Input color in sRGB ARGB format (uint32_t)
378  * Output color in linear (Vec4)
379  */
MakeColorFromSRGB(const uint32_t color)380 inline Color MakeColorFromSRGB(const uint32_t color)
381 {
382     uint8_t b = (color >> COLOR_SHIFT_0) & UINT8_MAX;
383     uint8_t g = (color >> COLOR_SHIFT_8) & UINT8_MAX;
384     uint8_t r = (color >> COLOR_SHIFT_16) & UINT8_MAX;
385     uint8_t a = (color >> COLOR_SHIFT_24) & UINT8_MAX;
386 
387     return { SRGBToLinearConv(r / 255.0f), SRGBToLinearConv(g / 255.0f), SRGBToLinearConv(b / 255.0f), a / 255.0f };
388 }
389 
390 /** Input color in linear (Vec4)
391  * Output color in linear (uint32_t)
392  */
FromColorToLinear(Color color)393 constexpr uint32_t FromColorToLinear(Color color)
394 {
395     color *= 255.f;
396     uint32_t b = ((uint32_t)color.z & UINT8_MAX) << COLOR_SHIFT_0;
397     uint32_t g = ((uint32_t)color.y & UINT8_MAX) << COLOR_SHIFT_8;
398     uint32_t r = ((uint32_t)color.x & UINT8_MAX) << COLOR_SHIFT_16;
399     uint32_t a = ((uint32_t)color.w & UINT8_MAX) << COLOR_SHIFT_24;
400 
401     return a | r | g | b;
402 }
403 
404 /** Input color in linear (Vec4)
405  * Output color in sRGB (uint32_t)
406  */
FromColorToSRGB(Color color)407 inline uint32_t FromColorToSRGB(Color color)
408 {
409     // rounding should be handled in some smart way to get actual min and max values too
410     uint32_t b = ((uint32_t)(LinearToSRGBConv(color.z) * 255.f) & UINT8_MAX) << COLOR_SHIFT_0;
411     uint32_t g = ((uint32_t)(LinearToSRGBConv(color.y) * 255.f) & UINT8_MAX) << COLOR_SHIFT_8;
412     uint32_t r = ((uint32_t)(LinearToSRGBConv(color.x) * 255.f) & UINT8_MAX) << COLOR_SHIFT_16;
413     uint32_t a = ((uint32_t)(color.w * 255.f) & UINT8_MAX) << COLOR_SHIFT_24;
414 
415     return a | r | g | b;
416 }
417 
418 /** Input color in linear (Vec4)
419  * Output color in linear (uint32_t)
420  */
FromColorRGBAToLinear(Color color)421 constexpr uint32_t FromColorRGBAToLinear(Color color)
422 {
423     color *= 255.f;
424     uint32_t r = ((uint32_t)color.x & UINT8_MAX) << COLOR_SHIFT_0;
425     uint32_t g = ((uint32_t)color.y & UINT8_MAX) << COLOR_SHIFT_8;
426     uint32_t b = ((uint32_t)color.z & UINT8_MAX) << COLOR_SHIFT_16;
427     uint32_t a = ((uint32_t)color.w & UINT8_MAX) << COLOR_SHIFT_24;
428 
429     return a | b | g | r;
430 }
431 
432 /** Input color in linear (Vec4)
433  * Output color in sRGB (uint32_t)
434  */
FromColorRGBAToSRGB(Color color)435 inline uint32_t FromColorRGBAToSRGB(Color color)
436 {
437     uint32_t r = ((uint32_t)(LinearToSRGBConv(color.x) * 255.0f) & UINT8_MAX) << COLOR_SHIFT_0;
438     uint32_t g = ((uint32_t)(LinearToSRGBConv(color.y) * 255.0f) & UINT8_MAX) << COLOR_SHIFT_8;
439     uint32_t b = ((uint32_t)(LinearToSRGBConv(color.z) * 255.0f) & UINT8_MAX) << COLOR_SHIFT_16;
440     uint32_t a = ((uint32_t)(color.w * 255.0f) & UINT8_MAX) << COLOR_SHIFT_24;
441 
442     return a | b | g | r;
443 }
444 
FromColorRGBA(const Color color,const ColorSpaceFlags flags)445 inline uint32_t FromColorRGBA(const Color color, const ColorSpaceFlags flags)
446 {
447     if (flags == 0U) {
448         return FromColorRGBAToLinear(color);
449     } else {
450         return FromColorRGBAToSRGB(color);
451     }
452 }
453 
PackPremultiplyColorUnorm(Color color)454 inline constexpr uint32_t PackPremultiplyColorUnorm(Color color)
455 {
456     // premultiply colors by alpha and scale the components from 0..1 to 0..255 and pack them in a 32 bit value RGBA
457     // where R is the lowest byte and A the highest.
458     return (((uint32_t(BASE_NS::Math::clamp01(color.w) * 255.0f) & UINT8_MAX) << COLOR_SHIFT_24) |
459             ((uint32_t(BASE_NS::Math::clamp01(color.w * color.z) * 255.0f) & UINT8_MAX) << COLOR_SHIFT_16) |
460             ((uint32_t(BASE_NS::Math::clamp01(color.w * color.y) * 255.0f) & UINT8_MAX) << COLOR_SHIFT_8) |
461             ((uint32_t(BASE_NS::Math::clamp01(color.w * color.x) * 255.0f) & UINT8_MAX)));
462 }
463 
464 static const Color BLACK_COLOR = MakeColorFromLinear(0xFF000000);
465 static const Color WHITE_COLOR = MakeColorFromLinear(0xFFFFFFFF);
466 BASE_END_NAMESPACE()
467 
468 #endif // API_BASE_UTIL_COLOR_H
469