2023-08-15 16:20:26 +02:00
|
|
|
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2020-04-21 16:55:00 +02:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
Cleanup: fewer iostreams related includes from BLI/BKE headers
Including <iostream> or similar headers is quite expensive, since it
also pulls in things like <locale> and so on. In many BLI headers,
iostreams are only used to implement some sort of "debug print",
or an operator<< for ostream.
Change some of the commonly used places to instead include <iosfwd>,
which is the standard way of forward-declaring iostreams related
classes, and move the actual debug-print / operator<< implementations
into .cc files.
This is not done for templated classes though (it would be possible
to provide explicit operator<< instantiations somewhere in the
source file, but that would lead to hard-to-figure-out linker error
whenever someone would add a different template type). There, where
possible, I changed from full <iostream> include to only the needed
<ostream> part.
For Span<T>, I just removed print_as_lines since it's not used by
anything. It could be moved into a .cc file using a similar approach
as above if needed.
Doing full blender build changes include counts this way:
- <iostream> 1986 -> 978
- <sstream> 2880 -> 925
It does not affect the total build time much though, mostly because
towards the end of it there's just several CPU cores finishing
compiling OpenVDB related source files.
Pull Request: https://projects.blender.org/blender/blender/pulls/111046
2023-08-11 11:27:56 +02:00
|
|
|
#include <ostream>
|
2020-04-21 16:55:00 +02:00
|
|
|
|
|
|
|
#include "BLI_math_color.h"
|
|
|
|
|
2020-06-09 10:27:24 +02:00
|
|
|
namespace blender {
|
2020-04-21 16:55:00 +02:00
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
/**
|
|
|
|
* CPP based color structures.
|
|
|
|
*
|
|
|
|
* Strongly typed color storage structures with space and alpha association.
|
|
|
|
* Will increase readability and visibility of typical mistakes when
|
|
|
|
* working with colors.
|
|
|
|
*
|
|
|
|
* The storage structs can hold 4 channels (r, g, b and a).
|
|
|
|
*
|
|
|
|
* Usage:
|
|
|
|
*
|
|
|
|
* Convert a theme byte color to a linearrgb premultiplied.
|
2021-07-20 14:52:31 +02:00
|
|
|
* \code{.cc}
|
2021-05-25 17:16:35 +02:00
|
|
|
* ColorTheme4b theme_color;
|
|
|
|
* ColorSceneLinear4f<eAlpha::Premultiplied> linearrgb_color =
|
|
|
|
* BLI_color_convert_to_scene_linear(theme_color).premultiply_alpha();
|
2021-07-20 14:52:31 +02:00
|
|
|
* \endcode
|
2021-05-25 17:16:35 +02:00
|
|
|
*
|
|
|
|
* The API is structured to make most use of inlining. Most notable are space
|
|
|
|
* conversions done via `BLI_color_convert_to*` functions.
|
|
|
|
*
|
|
|
|
* - Conversions between spaces (theme <=> scene linear) should always be done by
|
|
|
|
* invoking the `BLI_color_convert_to*` methods.
|
|
|
|
* - Encoding colors (compressing to store colors inside a less precision storage)
|
|
|
|
* should be done by invoking the `encode` and `decode` methods.
|
|
|
|
* - Changing alpha association should be done by invoking `premultiply_alpha` or
|
|
|
|
* `unpremultiply_alpha` methods.
|
|
|
|
*
|
|
|
|
* # Encoding.
|
|
|
|
*
|
|
|
|
* Color encoding is used to store colors with less precision as in using `uint8_t` in
|
|
|
|
* stead of `float`. This encoding is supported for `eSpace::SceneLinear`.
|
|
|
|
* To make this clear to the developer the `eSpace::SceneLinearByteEncoded`
|
|
|
|
* space is added.
|
|
|
|
*
|
|
|
|
* # Precision
|
|
|
|
*
|
|
|
|
* Colors can be stored using `uint8_t` or `float` colors. The conversion
|
|
|
|
* between the two precisions are available as methods. (`to_4b` and
|
|
|
|
* `to_4f`).
|
|
|
|
*
|
|
|
|
* # Alpha conversion
|
|
|
|
*
|
|
|
|
* Alpha conversion is only supported in SceneLinear space.
|
|
|
|
*
|
|
|
|
* Extending this file:
|
|
|
|
* - This file can be extended with `ColorHex/Hsl/Hsv` for different representations
|
|
|
|
* of rgb based colors. `ColorHsl4f<eSpace::SceneLinear, eAlpha::Premultiplied>`
|
|
|
|
* - Add non RGB spaces/storages ColorXyz.
|
|
|
|
*/
|
|
|
|
|
2021-12-20 09:01:14 +01:00
|
|
|
/** Enumeration containing the different alpha modes. */
|
2021-05-25 17:16:35 +02:00
|
|
|
enum class eAlpha {
|
2021-12-20 09:01:14 +01:00
|
|
|
/** Color and alpha are unassociated. */
|
2021-05-25 17:16:35 +02:00
|
|
|
Straight,
|
2021-12-20 09:01:14 +01:00
|
|
|
/** Color and alpha are associated. */
|
2021-05-25 17:16:35 +02:00
|
|
|
Premultiplied,
|
|
|
|
};
|
|
|
|
std::ostream &operator<<(std::ostream &stream, const eAlpha &space);
|
2020-04-21 16:55:00 +02:00
|
|
|
|
2021-12-20 09:01:14 +01:00
|
|
|
/** Enumeration containing internal spaces. */
|
2021-05-25 17:16:35 +02:00
|
|
|
enum class eSpace {
|
2021-12-20 09:01:14 +01:00
|
|
|
/** Blender theme color space (sRGB). */
|
2021-05-25 17:16:35 +02:00
|
|
|
Theme,
|
2022-01-11 09:50:50 +01:00
|
|
|
/** Blender internal scene linear color space (maps to scene_linear role in OCIO). */
|
2021-05-25 17:16:35 +02:00
|
|
|
SceneLinear,
|
2021-12-20 09:01:14 +01:00
|
|
|
/** Blender internal scene linear color space compressed to be stored in 4 uint8_t. */
|
2021-05-25 17:16:35 +02:00
|
|
|
SceneLinearByteEncoded,
|
|
|
|
};
|
|
|
|
std::ostream &operator<<(std::ostream &stream, const eSpace &space);
|
2020-04-21 16:55:00 +02:00
|
|
|
|
2022-06-21 22:47:25 +02:00
|
|
|
/** Template class to store RGBA values with different precision, space, and alpha association. */
|
2021-05-25 17:16:35 +02:00
|
|
|
template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGBA {
|
|
|
|
public:
|
|
|
|
ChannelStorageType r, g, b, a;
|
|
|
|
constexpr ColorRGBA() = default;
|
|
|
|
|
|
|
|
constexpr ColorRGBA(const ChannelStorageType rgba[4])
|
|
|
|
: r(rgba[0]), g(rgba[1]), b(rgba[2]), a(rgba[3])
|
2020-06-30 17:55:21 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
constexpr ColorRGBA(const ChannelStorageType r,
|
|
|
|
const ChannelStorageType g,
|
|
|
|
const ChannelStorageType b,
|
|
|
|
const ChannelStorageType a)
|
|
|
|
: r(r), g(g), b(b), a(a)
|
2020-04-21 16:55:00 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
operator ChannelStorageType *()
|
2020-04-21 16:55:00 +02:00
|
|
|
{
|
|
|
|
return &r;
|
|
|
|
}
|
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
operator const ChannelStorageType *() const
|
2020-04-21 16:55:00 +02:00
|
|
|
{
|
|
|
|
return &r;
|
|
|
|
}
|
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
friend std::ostream &operator<<(std::ostream &stream,
|
|
|
|
const ColorRGBA<ChannelStorageType, Space, Alpha> &c)
|
2020-04-21 16:55:00 +02:00
|
|
|
{
|
2021-05-25 17:16:35 +02:00
|
|
|
|
|
|
|
stream << Space << Alpha << "(" << c.r << ", " << c.g << ", " << c.b << ", " << c.a << ")";
|
2020-04-21 16:55:00 +02:00
|
|
|
return stream;
|
|
|
|
}
|
2020-07-08 14:40:34 +02:00
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
friend bool operator==(const ColorRGBA<ChannelStorageType, Space, Alpha> &a,
|
|
|
|
const ColorRGBA<ChannelStorageType, Space, Alpha> &b)
|
2020-07-08 14:40:34 +02:00
|
|
|
{
|
|
|
|
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
|
|
|
|
}
|
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
friend bool operator!=(const ColorRGBA<ChannelStorageType, Space, Alpha> &a,
|
|
|
|
const ColorRGBA<ChannelStorageType, Space, Alpha> &b)
|
2020-07-08 14:40:34 +02:00
|
|
|
{
|
|
|
|
return !(a == b);
|
|
|
|
}
|
|
|
|
|
2020-07-20 12:16:20 +02:00
|
|
|
uint64_t hash() const
|
2020-07-08 14:40:34 +02:00
|
|
|
{
|
2020-08-07 18:24:59 +02:00
|
|
|
uint64_t x1 = *reinterpret_cast<const uint32_t *>(&r);
|
|
|
|
uint64_t x2 = *reinterpret_cast<const uint32_t *>(&g);
|
|
|
|
uint64_t x3 = *reinterpret_cast<const uint32_t *>(&b);
|
|
|
|
uint64_t x4 = *reinterpret_cast<const uint32_t *>(&a);
|
2020-07-08 14:40:34 +02:00
|
|
|
return (x1 * 1283591) ^ (x2 * 850177) ^ (x3 * 735391) ^ (x4 * 442319);
|
|
|
|
}
|
2020-04-21 16:55:00 +02:00
|
|
|
};
|
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
/* Forward declarations of concrete color classes. */
|
2021-12-20 09:01:14 +01:00
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
template<eAlpha Alpha> class ColorSceneLinear4f;
|
|
|
|
template<eAlpha Alpha> class ColorSceneLinearByteEncoded4b;
|
|
|
|
template<typename ChannelStorageType> class ColorTheme4;
|
2020-04-21 16:55:00 +02:00
|
|
|
|
2021-05-27 09:02:44 +02:00
|
|
|
/* Forward declaration of precision conversion methods. */
|
2021-12-20 09:01:14 +01:00
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
BLI_INLINE ColorTheme4<float> BLI_color_convert_to_theme4f(const ColorTheme4<uint8_t> &srgb4b);
|
|
|
|
BLI_INLINE ColorTheme4<uint8_t> BLI_color_convert_to_theme4b(const ColorTheme4<float> &srgb4f);
|
2020-04-21 16:55:00 +02:00
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
template<eAlpha Alpha>
|
|
|
|
class ColorSceneLinear4f final : public ColorRGBA<float, eSpace::SceneLinear, Alpha> {
|
|
|
|
public:
|
2022-12-23 12:01:59 +01:00
|
|
|
constexpr ColorSceneLinear4f<Alpha>() = default;
|
2020-04-21 16:55:00 +02:00
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
constexpr ColorSceneLinear4f<Alpha>(const float *rgba)
|
|
|
|
: ColorRGBA<float, eSpace::SceneLinear, Alpha>(rgba)
|
2020-04-21 16:55:00 +02:00
|
|
|
{
|
|
|
|
}
|
2021-05-25 17:00:14 +02:00
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
constexpr ColorSceneLinear4f<Alpha>(float r, float g, float b, float a)
|
|
|
|
: ColorRGBA<float, eSpace::SceneLinear, Alpha>(r, g, b, a)
|
2020-07-08 14:40:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
/**
|
2022-06-21 22:47:25 +02:00
|
|
|
* Convert to its byte encoded counterpart.
|
2021-06-24 07:56:58 +02:00
|
|
|
*/
|
2021-05-25 17:16:35 +02:00
|
|
|
ColorSceneLinearByteEncoded4b<Alpha> encode() const
|
2020-07-08 14:40:34 +02:00
|
|
|
{
|
2021-05-25 17:16:35 +02:00
|
|
|
ColorSceneLinearByteEncoded4b<Alpha> encoded;
|
|
|
|
linearrgb_to_srgb_uchar4(encoded, *this);
|
|
|
|
return encoded;
|
2020-07-08 14:40:34 +02:00
|
|
|
}
|
2020-07-10 12:53:50 +02:00
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
/**
|
|
|
|
* Convert color and alpha association to premultiplied alpha.
|
|
|
|
*
|
2022-06-21 22:47:25 +02:00
|
|
|
* Does nothing when color already has a premultiplied alpha.
|
2021-05-25 17:16:35 +02:00
|
|
|
*/
|
|
|
|
ColorSceneLinear4f<eAlpha::Premultiplied> premultiply_alpha() const
|
2021-05-25 17:00:14 +02:00
|
|
|
{
|
2021-05-25 17:16:35 +02:00
|
|
|
if constexpr (Alpha == eAlpha::Straight) {
|
|
|
|
ColorSceneLinear4f<eAlpha::Premultiplied> premultiplied;
|
|
|
|
straight_to_premul_v4_v4(premultiplied, *this);
|
|
|
|
return premultiplied;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return *this;
|
|
|
|
}
|
2021-05-25 17:00:14 +02:00
|
|
|
}
|
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
/**
|
|
|
|
* Convert color and alpha association to straight alpha.
|
|
|
|
*
|
2022-06-21 22:47:25 +02:00
|
|
|
* Does nothing when color has straight alpha.
|
2021-05-25 17:16:35 +02:00
|
|
|
*/
|
|
|
|
ColorSceneLinear4f<eAlpha::Straight> unpremultiply_alpha() const
|
2021-05-25 17:00:14 +02:00
|
|
|
{
|
2021-05-25 17:16:35 +02:00
|
|
|
if constexpr (Alpha == eAlpha::Premultiplied) {
|
|
|
|
ColorSceneLinear4f<eAlpha::Straight> straighten;
|
|
|
|
premul_to_straight_v4_v4(straighten, *this);
|
|
|
|
return straighten;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return *this;
|
|
|
|
}
|
2021-05-25 17:00:14 +02:00
|
|
|
}
|
2021-05-25 17:16:35 +02:00
|
|
|
};
|
2021-05-25 17:00:14 +02:00
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
template<eAlpha Alpha>
|
|
|
|
class ColorSceneLinearByteEncoded4b final
|
|
|
|
: public ColorRGBA<uint8_t, eSpace::SceneLinearByteEncoded, Alpha> {
|
|
|
|
public:
|
|
|
|
constexpr ColorSceneLinearByteEncoded4b() = default;
|
|
|
|
|
|
|
|
constexpr ColorSceneLinearByteEncoded4b(const uint8_t *rgba)
|
|
|
|
: ColorRGBA<uint8_t, eSpace::SceneLinearByteEncoded, Alpha>(rgba)
|
2021-05-25 17:00:14 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
constexpr ColorSceneLinearByteEncoded4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
|
|
|
: ColorRGBA<uint8_t, eSpace::SceneLinearByteEncoded, Alpha>(r, g, b, a)
|
2020-07-10 12:53:50 +02:00
|
|
|
{
|
2021-05-25 17:00:14 +02:00
|
|
|
}
|
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
/**
|
2022-06-21 22:47:25 +02:00
|
|
|
* Convert to a float color.
|
2021-05-25 17:16:35 +02:00
|
|
|
*/
|
|
|
|
ColorSceneLinear4f<Alpha> decode() const
|
|
|
|
{
|
|
|
|
ColorSceneLinear4f<Alpha> decoded;
|
|
|
|
srgb_to_linearrgb_uchar4(decoded, *this);
|
|
|
|
return decoded;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Theme color template class.
|
|
|
|
*
|
|
|
|
* Don't use directly, but use `ColorTheme4b/ColorTheme4b`.
|
|
|
|
*
|
|
|
|
* This has been implemented as a template to improve inlining. When implemented as concrete
|
|
|
|
* classes (ColorTheme4b/f) the functions would be hidden in a compile unit what wouldn't be
|
|
|
|
* inlined.
|
|
|
|
*/
|
|
|
|
template<typename ChannelStorageType>
|
|
|
|
class ColorTheme4 final : public ColorRGBA<ChannelStorageType, eSpace::Theme, eAlpha::Straight> {
|
|
|
|
public:
|
2023-01-17 13:43:38 +01:00
|
|
|
constexpr ColorTheme4() = default;
|
2021-05-25 17:16:35 +02:00
|
|
|
|
|
|
|
constexpr ColorTheme4(const ChannelStorageType *rgba)
|
|
|
|
: ColorRGBA<ChannelStorageType, eSpace::Theme, eAlpha::Straight>(rgba)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr ColorTheme4(ChannelStorageType r,
|
|
|
|
ChannelStorageType g,
|
|
|
|
ChannelStorageType b,
|
|
|
|
ChannelStorageType a)
|
|
|
|
: ColorRGBA<ChannelStorageType, eSpace::Theme, eAlpha::Straight>(r, g, b, a)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Change precision of color to float.
|
|
|
|
*/
|
|
|
|
ColorTheme4<float> to_4f() const
|
2021-05-25 17:00:14 +02:00
|
|
|
{
|
2021-05-25 17:16:35 +02:00
|
|
|
if constexpr ((std::is_same_v<ChannelStorageType, uint8_t>)) {
|
|
|
|
return BLI_color_convert_to_theme4f(*this);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Change precision of color to uint8_t.
|
|
|
|
*/
|
|
|
|
ColorTheme4<uint8_t> to_4b() const
|
|
|
|
{
|
|
|
|
if constexpr ((std::is_same_v<ChannelStorageType, float>)) {
|
|
|
|
return BLI_color_convert_to_theme4b(*this);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return *this;
|
|
|
|
}
|
2020-07-10 12:53:50 +02:00
|
|
|
}
|
2020-04-21 16:55:00 +02:00
|
|
|
};
|
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
using ColorTheme4b = ColorTheme4<uint8_t>;
|
|
|
|
using ColorTheme4f = ColorTheme4<float>;
|
|
|
|
|
|
|
|
BLI_INLINE ColorTheme4b BLI_color_convert_to_theme4b(const ColorTheme4f &theme4f)
|
|
|
|
{
|
|
|
|
ColorTheme4b theme4b;
|
|
|
|
rgba_float_to_uchar(theme4b, theme4f);
|
|
|
|
return theme4b;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE ColorTheme4f BLI_color_convert_to_theme4f(const ColorTheme4b &theme4b)
|
|
|
|
{
|
|
|
|
ColorTheme4f theme4f;
|
|
|
|
rgba_uchar_to_float(theme4f, theme4b);
|
|
|
|
return theme4f;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE ColorSceneLinear4f<eAlpha::Straight> BLI_color_convert_to_scene_linear(
|
|
|
|
const ColorTheme4f &theme4f)
|
|
|
|
{
|
|
|
|
ColorSceneLinear4f<eAlpha::Straight> scene_linear;
|
|
|
|
srgb_to_linearrgb_v4(scene_linear, theme4f);
|
|
|
|
return scene_linear;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE ColorSceneLinear4f<eAlpha::Straight> BLI_color_convert_to_scene_linear(
|
|
|
|
const ColorTheme4b &theme4b)
|
|
|
|
{
|
|
|
|
ColorSceneLinear4f<eAlpha::Straight> scene_linear;
|
|
|
|
srgb_to_linearrgb_uchar4(scene_linear, theme4b);
|
|
|
|
return scene_linear;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE ColorTheme4f
|
|
|
|
BLI_color_convert_to_theme4f(const ColorSceneLinear4f<eAlpha::Straight> &scene_linear)
|
|
|
|
{
|
|
|
|
ColorTheme4f theme4f;
|
|
|
|
linearrgb_to_srgb_v4(theme4f, scene_linear);
|
|
|
|
return theme4f;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE ColorTheme4b
|
|
|
|
BLI_color_convert_to_theme4b(const ColorSceneLinear4f<eAlpha::Straight> &scene_linear)
|
|
|
|
{
|
|
|
|
ColorTheme4b theme4b;
|
|
|
|
linearrgb_to_srgb_uchar4(theme4b, scene_linear);
|
|
|
|
return theme4b;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Internal roles. For convenience to shorten the type names and hide complexity. */
|
2021-12-20 09:01:14 +01:00
|
|
|
|
2021-05-25 17:16:35 +02:00
|
|
|
using ColorGeometry4f = ColorSceneLinear4f<eAlpha::Premultiplied>;
|
|
|
|
using ColorGeometry4b = ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>;
|
2022-04-21 07:03:45 +02:00
|
|
|
using ColorPaint4f = ColorSceneLinear4f<eAlpha::Straight>;
|
|
|
|
using ColorPaint4b = ColorSceneLinearByteEncoded4b<eAlpha::Straight>;
|
2021-05-25 17:16:35 +02:00
|
|
|
|
2020-06-09 10:27:24 +02:00
|
|
|
} // namespace blender
|