Blenlib: Explicit Colors.

Colors are often thought of as being 4 values that make up that can make any color.
But that is of course too limited. In C we didn’t spend time to annotate what we meant
when using colors.

Recently `BLI_color.hh` was made to facilitate color structures in CPP. CPP has possibilities to
enforce annotating structures during compilation and can adds conversions between them using
function overloading and explicit constructors.

The storage structs can hold 4 channels (r, g, b and a).

Usage:

Convert a theme byte color to a linearrgb premultiplied.
```
ColorTheme4b theme_color;
ColorSceneLinear4f<eAlpha::Premultiplied> linearrgb_color =
    BLI_color_convert_to_scene_linear(theme_color).premultiply_alpha();
```

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 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.

Reviewed By: JacquesLucke, brecht

Differential Revision: https://developer.blender.org/D10978
This commit is contained in:
Jeroen Bakker 2021-05-25 17:00:14 +02:00 committed by Jeroen Bakker
parent b046bc536b
commit fd94e03344
Notes: blender-bot 2023-02-14 10:37:49 +01:00
Referenced by commit 00955cd31e, Revert "Blenlib: Explicit Colors."
26 changed files with 603 additions and 160 deletions

View File

@ -52,7 +52,7 @@ inline void convert_to_static_type(const CustomDataType data_type, const Func &f
func(bool());
break;
case CD_PROP_COLOR:
func(Color4f());
func(ColorGeometry4f());
break;
default:
BLI_assert_unreachable();
@ -78,8 +78,8 @@ inline void convert_to_static_type(const fn::CPPType &cpp_type, const Func &func
else if (cpp_type.is<bool>()) {
func(bool());
}
else if (cpp_type.is<Color4f>()) {
func(Color4f());
else if (cpp_type.is<ColorGeometry4f>()) {
func(ColorGeometry4f());
}
else {
BLI_assert_unreachable();
@ -123,9 +123,12 @@ inline float3 mix3(const float3 &weights, const float3 &v0, const float3 &v1, co
}
template<>
inline Color4f mix3(const float3 &weights, const Color4f &v0, const Color4f &v1, const Color4f &v2)
inline ColorGeometry4f mix3(const float3 &weights,
const ColorGeometry4f &v0,
const ColorGeometry4f &v1,
const ColorGeometry4f &v2)
{
Color4f result;
ColorGeometry4f result;
interp_v4_v4v4v4(result, v0, v1, v2, weights);
return result;
}
@ -165,9 +168,10 @@ template<> inline float3 mix2(const float factor, const float3 &a, const float3
return float3::interpolate(a, b, factor);
}
template<> inline Color4f mix2(const float factor, const Color4f &a, const Color4f &b)
template<>
inline ColorGeometry4f mix2(const float factor, const ColorGeometry4f &a, const ColorGeometry4f &b)
{
Color4f result;
ColorGeometry4f result;
interp_v4_v4v4(result, a, b, factor);
return result;
}
@ -274,15 +278,16 @@ class SimpleMixerWithAccumulationType {
}
};
class Color4fMixer {
class ColorGeometryMixer {
private:
MutableSpan<Color4f> buffer_;
Color4f default_color_;
MutableSpan<ColorGeometry4f> buffer_;
ColorGeometry4f default_color_;
Array<float> total_weights_;
public:
Color4fMixer(MutableSpan<Color4f> buffer, Color4f default_color = {0, 0, 0, 1});
void mix_in(const int64_t index, const Color4f &color, const float weight = 1.0f);
ColorGeometryMixer(MutableSpan<ColorGeometry4f> buffer,
ColorGeometry4f default_color = ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
void mix_in(const int64_t index, const ColorGeometry4f &color, const float weight = 1.0f);
void finalize();
};
@ -299,10 +304,10 @@ template<> struct DefaultMixerStruct<float2> {
template<> struct DefaultMixerStruct<float3> {
using type = SimpleMixer<float3>;
};
template<> struct DefaultMixerStruct<Color4f> {
/* Use a special mixer for colors. Color4f can't be added/multiplied, because this is not
template<> struct DefaultMixerStruct<ColorGeometry4f> {
/* Use a special mixer for colors. ColorGeometry4f can't be added/multiplied, because this is not
* something one should usually do with colors. */
using type = Color4fMixer;
using type = ColorGeometryMixer;
};
template<> struct DefaultMixerStruct<int> {
static int double_to_int(const double &value)

View File

@ -61,7 +61,7 @@ const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType ty
case CD_PROP_INT32:
return &CPPType::get<int>();
case CD_PROP_COLOR:
return &CPPType::get<Color4f>();
return &CPPType::get<ColorGeometry4f>();
case CD_PROP_BOOL:
return &CPPType::get<bool>();
default:
@ -84,7 +84,7 @@ CustomDataType cpp_type_to_custom_data_type(const blender::fn::CPPType &type)
if (type.is<int>()) {
return CD_PROP_INT32;
}
if (type.is<Color4f>()) {
if (type.is<ColorGeometry4f>()) {
return CD_PROP_COLOR;
}
if (type.is<bool>()) {
@ -355,7 +355,7 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
case CD_PROP_INT32:
return this->layer_to_read_attribute<int>(layer, domain_size);
case CD_PROP_COLOR:
return this->layer_to_read_attribute<Color4f>(layer, domain_size);
return this->layer_to_read_attribute<ColorGeometry4f>(layer, domain_size);
case CD_PROP_BOOL:
return this->layer_to_read_attribute<bool>(layer, domain_size);
default:
@ -389,7 +389,7 @@ WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write(
case CD_PROP_INT32:
return this->layer_to_write_attribute<int>(layer, domain_size);
case CD_PROP_COLOR:
return this->layer_to_write_attribute<Color4f>(layer, domain_size);
return this->layer_to_write_attribute<ColorGeometry4f>(layer, domain_size);
case CD_PROP_BOOL:
return this->layer_to_write_attribute<bool>(layer, domain_size);
default:

View File

@ -18,18 +18,21 @@
namespace blender::attribute_math {
Color4fMixer::Color4fMixer(MutableSpan<Color4f> output_buffer, Color4f default_color)
ColorGeometryMixer::ColorGeometryMixer(MutableSpan<ColorGeometry4f> output_buffer,
ColorGeometry4f default_color)
: buffer_(output_buffer),
default_color_(default_color),
total_weights_(output_buffer.size(), 0.0f)
{
buffer_.fill(Color4f(0, 0, 0, 0));
buffer_.fill(ColorGeometry4f(0.0f, 0.0f, 0.0f, 0.0f));
}
void Color4fMixer::mix_in(const int64_t index, const Color4f &color, const float weight)
void ColorGeometryMixer::mix_in(const int64_t index,
const ColorGeometry4f &color,
const float weight)
{
BLI_assert(weight >= 0.0f);
Color4f &output_color = buffer_[index];
ColorGeometry4f &output_color = buffer_[index];
output_color.r += color.r * weight;
output_color.g += color.g * weight;
output_color.b += color.b * weight;
@ -37,11 +40,11 @@ void Color4fMixer::mix_in(const int64_t index, const Color4f &color, const float
total_weights_[index] += weight;
}
void Color4fMixer::finalize()
void ColorGeometryMixer::finalize()
{
for (const int64_t i : buffer_.index_range()) {
const float weight = total_weights_[i];
Color4f &output_color = buffer_[i];
ColorGeometry4f &output_color = buffer_[i];
if (weight > 0.0f) {
const float weight_inv = 1.0f / weight;
output_color.r *= weight_inv;

View File

@ -773,18 +773,20 @@ static void set_loop_uv(MLoopUV &uv, float2 co)
copy_v2_v2(uv.uv, co);
}
static Color4f get_loop_color(const MLoopCol &col)
static ColorGeometry4f get_loop_color(const MLoopCol &col)
{
Color4f srgb_color;
rgba_uchar_to_float(srgb_color, &col.r);
Color4f linear_color;
srgb_to_linearrgb_v4(linear_color, srgb_color);
ColorGeometry4b encoded_color = ColorGeometry4b(col.r, col.g, col.b, col.a);
ColorGeometry4f linear_color = encoded_color.decode();
return linear_color;
}
static void set_loop_color(MLoopCol &col, Color4f linear_color)
static void set_loop_color(MLoopCol &col, ColorGeometry4f linear_color)
{
linearrgb_to_srgb_uchar4(&col.r, linear_color);
ColorGeometry4b encoded_color = linear_color.encode();
col.r = encoded_color.r;
col.g = encoded_color.g;
col.b = encoded_color.b;
col.a = encoded_color.a;
}
static float get_crease(const MEdge &edge)
@ -1121,8 +1123,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
CD_PROP_COLOR,
CD_MLOOPCOL,
corner_access,
make_derived_read_attribute<MLoopCol, Color4f, get_loop_color>,
make_derived_write_attribute<MLoopCol, Color4f, get_loop_color, set_loop_color>);
make_derived_read_attribute<MLoopCol, ColorGeometry4f, get_loop_color>,
make_derived_write_attribute<MLoopCol, ColorGeometry4f, get_loop_color, set_loop_color>);
static VertexGroupsAttributeProvider vertex_groups;
static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);

View File

@ -22,41 +22,122 @@
namespace blender {
struct Color4f {
float r, g, b, a;
/**
* 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.
* ```
* ColorTheme4b theme_color;
* ColorSceneLinear4f<eAlpha::Premultiplied> linearrgb_color =
* BLI_color_convert_to_scene_linear(theme_color).premultiply_alpha();
* ```
*
* 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.
*/
Color4f() = default;
/* Enumeration containing the different alpha modes. */
enum class eAlpha {
/* Color and alpha are unassociated. */
Straight,
/* Color and alpha are associated. */
Premultiplied,
};
std::ostream &operator<<(std::ostream &stream, const eAlpha &space);
Color4f(const float *rgba) : r(rgba[0]), g(rgba[1]), b(rgba[2]), a(rgba[3])
/* Enumeration containing internal spaces. */
enum class eSpace {
/* Blender theme color space (sRGB). */
Theme,
/* Blender internal scene linear color space (maps to SceneReference role in OCIO). */
SceneLinear,
/* Blender internal scene linear color space compressed to be stored in 4 uint8_t. */
SceneLinearByteEncoded,
};
std::ostream &operator<<(std::ostream &stream, const eSpace &space);
/* Template class to store RGBA values with different precision, space and alpha association. */
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])
{
}
Color4f(float r, float g, float b, float a) : r(r), g(g), b(b), a(a)
constexpr ColorRGBA(const ChannelStorageType r,
const ChannelStorageType g,
const ChannelStorageType b,
const ChannelStorageType a)
: r(r), g(g), b(b), a(a)
{
}
operator float *()
operator ChannelStorageType *()
{
return &r;
}
operator const float *() const
operator const ChannelStorageType *() const
{
return &r;
}
friend std::ostream &operator<<(std::ostream &stream, Color4f c)
friend std::ostream &operator<<(std::ostream &stream,
const ColorRGBA<ChannelStorageType, Space, Alpha> &c)
{
stream << "(" << c.r << ", " << c.g << ", " << c.b << ", " << c.a << ")";
stream << Space << Alpha << "(" << c.r << ", " << c.g << ", " << c.b << ", " << c.a << ")";
return stream;
}
friend bool operator==(const Color4f &a, const Color4f &b)
friend bool operator==(const ColorRGBA<ChannelStorageType, Space, Alpha> &a,
const ColorRGBA<ChannelStorageType, Space, Alpha> &b)
{
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
}
friend bool operator!=(const Color4f &a, const Color4f &b)
friend bool operator!=(const ColorRGBA<ChannelStorageType, Space, Alpha> &a,
const ColorRGBA<ChannelStorageType, Space, Alpha> &b)
{
return !(a == b);
}
@ -71,58 +152,209 @@ struct Color4f {
}
};
struct Color4b {
uint8_t r, g, b, a;
/* Forward declarations of concrete color classes. */
template<eAlpha Alpha> class ColorSceneLinear4f;
template<eAlpha Alpha> class ColorSceneLinearByteEncoded4b;
template<typename ChannelStorageType> class ColorTheme4;
Color4b() = default;
/* Forward declation of precision conversion methods. */
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);
Color4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : r(r), g(g), b(b), a(a)
template<eAlpha Alpha>
class ColorSceneLinear4f final : public ColorRGBA<float, eSpace::SceneLinear, Alpha> {
public:
constexpr ColorSceneLinear4f<Alpha>() : ColorRGBA<float, eSpace::SceneLinear, Alpha>()
{
}
Color4b(Color4f other)
constexpr ColorSceneLinear4f<Alpha>(const float *rgba)
: ColorRGBA<float, eSpace::SceneLinear, Alpha>(rgba)
{
rgba_float_to_uchar(*this, other);
}
operator Color4f() const
constexpr ColorSceneLinear4f<Alpha>(float r, float g, float b, float a)
: ColorRGBA<float, eSpace::SceneLinear, Alpha>(r, g, b, a)
{
Color4f result;
rgba_uchar_to_float(result, *this);
return result;
}
operator uint8_t *()
/**
* Convert to its byte encoded counter space.
**/
ColorSceneLinearByteEncoded4b<Alpha> encode() const
{
return &r;
ColorSceneLinearByteEncoded4b<Alpha> encoded;
linearrgb_to_srgb_uchar4(encoded, *this);
return encoded;
}
operator const uint8_t *() const
/**
* Convert color and alpha association to premultiplied alpha.
*
* Does nothing when color has already a premultiplied alpha.
*/
ColorSceneLinear4f<eAlpha::Premultiplied> premultiply_alpha() const
{
return &r;
if constexpr (Alpha == eAlpha::Straight) {
ColorSceneLinear4f<eAlpha::Premultiplied> premultiplied;
straight_to_premul_v4_v4(premultiplied, *this);
return premultiplied;
}
else {
return *this;
}
}
friend std::ostream &operator<<(std::ostream &stream, Color4b c)
/**
* Convert color and alpha association to straight alpha.
*
* Does nothing when color has straighten alpha.
*/
ColorSceneLinear4f<eAlpha::Straight> unpremultiply_alpha() const
{
stream << "(" << c.r << ", " << c.g << ", " << c.b << ", " << c.a << ")";
return stream;
}
friend bool operator==(const Color4b &a, const Color4b &b)
{
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
}
friend bool operator!=(const Color4b &a, const Color4b &b)
{
return !(a == b);
}
uint64_t hash() const
{
return static_cast<uint64_t>(r * 1283591) ^ static_cast<uint64_t>(g * 850177) ^
static_cast<uint64_t>(b * 735391) ^ static_cast<uint64_t>(a * 442319);
if constexpr (Alpha == eAlpha::Premultiplied) {
ColorSceneLinear4f<eAlpha::Straight> straighten;
premul_to_straight_v4_v4(straighten, *this);
return straighten;
}
else {
return *this;
}
}
};
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)
{
}
constexpr ColorSceneLinearByteEncoded4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
: ColorRGBA<uint8_t, eSpace::SceneLinearByteEncoded, Alpha>(r, g, b, a)
{
}
/**
* Convert to back to float color.
*/
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:
constexpr ColorTheme4() : ColorRGBA<ChannelStorageType, eSpace::Theme, eAlpha::Straight>(){};
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
{
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;
}
}
};
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. */
using ColorGeometry4f = ColorSceneLinear4f<eAlpha::Premultiplied>;
using ColorGeometry4b = ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>;
} // namespace blender

View File

@ -39,6 +39,7 @@ set(SRC
intern/BLI_args.c
intern/BLI_array.c
intern/BLI_assert.c
intern/BLI_color.cc
intern/BLI_dial_2d.c
intern/BLI_dynstr.c
intern/BLI_filelist.c
@ -389,6 +390,7 @@ if(WITH_GTESTS)
tests/BLI_array_store_test.cc
tests/BLI_array_test.cc
tests/BLI_array_utils_test.cc
tests/BLI_color_test.cc
tests/BLI_delaunay_2d_test.cc
tests/BLI_disjoint_set_test.cc
tests/BLI_edgehash_test.cc

View File

@ -0,0 +1,55 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BLI_color.hh"
namespace blender {
std::ostream &operator<<(std::ostream &stream, const eAlpha &space)
{
switch (space) {
case eAlpha::Straight: {
stream << "Straight";
break;
}
case eAlpha::Premultiplied: {
stream << "Premultiplied";
break;
}
}
return stream;
}
std::ostream &operator<<(std::ostream &stream, const eSpace &space)
{
switch (space) {
case eSpace::Theme: {
stream << "Theme";
break;
}
case eSpace::SceneLinear: {
stream << "SceneLinear";
break;
}
case eSpace::SceneLinearByteEncoded: {
stream << "SceneLinearByteEncoded";
break;
}
}
return stream;
}
} // namespace blender

View File

@ -0,0 +1,133 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "BLI_color.hh"
namespace blender::tests {
/**
* \name Conversions
* \{ */
TEST(color, ThemeByteToFloat)
{
ColorTheme4b theme_byte(192, 128, 64, 128);
ColorTheme4f theme_float = theme_byte.to_4f();
EXPECT_NEAR(0.75f, theme_float.r, 0.01f);
EXPECT_NEAR(0.5f, theme_float.g, 0.01f);
EXPECT_NEAR(0.25f, theme_float.b, 0.01f);
EXPECT_NEAR(0.5f, theme_float.a, 0.01f);
}
TEST(color, SrgbStraightFloatToByte)
{
ColorTheme4f theme_float(0.75f, 0.5f, 0.25f, 0.5f);
ColorTheme4b theme_byte = theme_float.to_4b();
EXPECT_EQ(191, theme_byte.r);
EXPECT_EQ(128, theme_byte.g);
EXPECT_EQ(64, theme_byte.b);
EXPECT_EQ(128, theme_byte.a);
}
TEST(color, SrgbStraightToSceneLinearPremultiplied)
{
BLI_init_srgb_conversion();
ColorTheme4b theme(192, 128, 64, 128);
ColorSceneLinear4f<eAlpha::Premultiplied> linear =
BLI_color_convert_to_scene_linear(theme).premultiply_alpha();
EXPECT_NEAR(0.26f, linear.r, 0.01f);
EXPECT_NEAR(0.11f, linear.g, 0.01f);
EXPECT_NEAR(0.02f, linear.b, 0.01f);
EXPECT_NEAR(0.5f, linear.a, 0.01f);
}
TEST(color, SceneLinearStraightToPremultiplied)
{
ColorSceneLinear4f<eAlpha::Straight> straight(0.75f, 0.5f, 0.25f, 0.5f);
ColorSceneLinear4f<eAlpha::Premultiplied> premultiplied = straight.premultiply_alpha();
EXPECT_NEAR(0.37f, premultiplied.r, 0.01f);
EXPECT_NEAR(0.25f, premultiplied.g, 0.01f);
EXPECT_NEAR(0.12f, premultiplied.b, 0.01f);
EXPECT_NEAR(0.5f, premultiplied.a, 0.01f);
}
TEST(color, SceneLinearPremultipliedToStraight)
{
ColorSceneLinear4f<eAlpha::Premultiplied> premultiplied(0.75f, 0.5f, 0.25f, 0.5f);
ColorSceneLinear4f<eAlpha::Straight> straight = premultiplied.unpremultiply_alpha();
EXPECT_NEAR(1.5f, straight.r, 0.01f);
EXPECT_NEAR(1.0f, straight.g, 0.01f);
EXPECT_NEAR(0.5f, straight.b, 0.01f);
EXPECT_NEAR(0.5f, straight.a, 0.01f);
}
TEST(color, SceneLinearStraightSrgbFloat)
{
BLI_init_srgb_conversion();
ColorSceneLinear4f<eAlpha::Straight> linear(0.75f, 0.5f, 0.25f, 0.5f);
ColorTheme4f theme = BLI_color_convert_to_theme4f(linear);
EXPECT_NEAR(0.88f, theme.r, 0.01);
EXPECT_NEAR(0.73f, theme.g, 0.01);
EXPECT_NEAR(0.53f, theme.b, 0.01);
EXPECT_NEAR(0.5f, theme.a, 0.01);
}
TEST(color, SceneLinearPremultipliedToSrgbFloat)
{
BLI_init_srgb_conversion();
ColorSceneLinear4f<eAlpha::Premultiplied> linear(0.75f, 0.5f, 0.25f, 0.5f);
ColorTheme4f theme = BLI_color_convert_to_theme4f(linear.unpremultiply_alpha());
EXPECT_NEAR(1.19f, theme.r, 0.01);
EXPECT_NEAR(1.0f, theme.g, 0.01);
EXPECT_NEAR(0.74f, theme.b, 0.01);
EXPECT_NEAR(0.5f, theme.a, 0.01);
}
TEST(color, SceneLinearStraightSrgbByte)
{
BLI_init_srgb_conversion();
ColorSceneLinear4f<eAlpha::Straight> linear(0.75f, 0.5f, 0.25f, 0.5f);
ColorTheme4b theme = BLI_color_convert_to_theme4b(linear);
EXPECT_EQ(225, theme.r);
EXPECT_EQ(188, theme.g);
EXPECT_EQ(137, theme.b);
EXPECT_EQ(128, theme.a);
}
TEST(color, SceneLinearPremultipliedToSrgbByte)
{
BLI_init_srgb_conversion();
ColorSceneLinear4f<eAlpha::Premultiplied> linear(0.75f, 0.5f, 0.25f, 0.5f);
ColorTheme4b theme = BLI_color_convert_to_theme4b(linear.unpremultiply_alpha());
EXPECT_EQ(255, theme.r);
EXPECT_EQ(255, theme.g);
EXPECT_EQ(188, theme.b);
EXPECT_EQ(128, theme.a);
}
TEST(color, SceneLinearByteEncoding)
{
ColorSceneLinear4f<eAlpha::Premultiplied> linear(0.75f, 0.5f, 0.25f, 0.5f);
ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied> encoded = linear.encode();
EXPECT_EQ(225, encoded.r);
EXPECT_EQ(188, encoded.g);
EXPECT_EQ(137, encoded.b);
EXPECT_EQ(128, encoded.a);
}
TEST(color, SceneLinearByteDecoding)
{
ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied> encoded(225, 188, 137, 128);
ColorSceneLinear4f<eAlpha::Premultiplied> decoded = encoded.decode();
EXPECT_NEAR(0.75f, decoded.r, 0.01f);
EXPECT_NEAR(0.5f, decoded.g, 0.01f);
EXPECT_NEAR(0.25f, decoded.b, 0.01f);
EXPECT_NEAR(0.5f, decoded.a, 0.01f);
}
/* \} */
} // namespace blender::tests

View File

@ -266,7 +266,6 @@ struct GPUBatch *DRW_particles_batch_cache_get_edit_inner_points(struct Object *
struct GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(struct Object *object,
struct ParticleSystem *psys,
struct PTCacheEdit *edit);
#ifdef __cplusplus
}
#endif

View File

@ -50,7 +50,7 @@ class CellValue {
std::optional<bool> value_bool;
std::optional<float2> value_float2;
std::optional<float3> value_float3;
std::optional<Color4f> value_color;
std::optional<ColorGeometry4f> value_color;
std::optional<ObjectCellValue> value_object;
std::optional<CollectionCellValue> value_collection;
};

View File

@ -116,7 +116,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
column_id.name,
domain_size,
[varray](int index, CellValue &r_cell_value) {
Color4f value;
ColorGeometry4f value;
varray->get(index, &value);
r_cell_value.value_color = value;
},

View File

@ -170,7 +170,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
this->draw_float_vector(params, Span(&value.x, 3));
}
else if (cell_value.value_color.has_value()) {
const Color4f value = *cell_value.value_color;
const ColorGeometry4f value = *cell_value.value_color;
this->draw_float_vector(params, Span(&value.r, 4));
}
else if (cell_value.value_object.has_value()) {

View File

@ -34,8 +34,8 @@ MAKE_CPP_TYPE(int32, int32_t)
MAKE_CPP_TYPE(uint32, uint32_t)
MAKE_CPP_TYPE(uint8, uint8_t)
MAKE_CPP_TYPE(Color4f, blender::Color4f)
MAKE_CPP_TYPE(Color4b, blender::Color4b)
MAKE_CPP_TYPE(ColorGeometry4f, blender::ColorGeometry4f)
MAKE_CPP_TYPE(ColorGeometry4b, blender::ColorGeometry4b)
MAKE_CPP_TYPE(string, std::string)

View File

@ -101,9 +101,12 @@ template<> inline float3 clamp_value(const float3 val, const float3 min, const f
return tmp;
}
template<> inline Color4f clamp_value(const Color4f val, const Color4f min, const Color4f max)
template<>
inline ColorGeometry4f clamp_value(const ColorGeometry4f val,
const ColorGeometry4f min,
const ColorGeometry4f max)
{
Color4f tmp;
ColorGeometry4f tmp;
tmp.r = std::min(std::max(val.r, min.r), max.r);
tmp.g = std::min(std::max(val.g, min.g), max.g);
tmp.b = std::min(std::max(val.b, min.b), max.b);
@ -214,8 +217,8 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
break;
}
case CD_PROP_COLOR: {
Color4f min = params.get_input<Color4f>("Min_003");
Color4f max = params.get_input<Color4f>("Max_003");
ColorGeometry4f min = params.get_input<ColorGeometry4f>("Min_003");
ColorGeometry4f max = params.get_input<ColorGeometry4f>("Max_003");
if (operation == NODE_CLAMP_RANGE) {
if (min.r > max.r) {
std::swap(min.r, max.r);
@ -230,8 +233,9 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
std::swap(min.a, max.a);
}
}
MutableSpan<Color4f> results = attribute_result.as_span<Color4f>();
clamp_attribute<Color4f>(attribute_input->typed<Color4f>(), results, min, max);
MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>();
clamp_attribute<ColorGeometry4f>(
attribute_input->typed<ColorGeometry4f>(), results, min, max);
break;
}
default: {

View File

@ -83,8 +83,8 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
* currently. */
const AttributeDomain result_domain = get_result_domain(component, input_name, result_name);
OutputAttribute_Typed<Color4f> attribute_result =
component.attribute_try_get_for_output_only<Color4f>(result_name, result_domain);
OutputAttribute_Typed<ColorGeometry4f> attribute_result =
component.attribute_try_get_for_output_only<ColorGeometry4f>(result_name, result_domain);
if (!attribute_result) {
return;
}
@ -92,7 +92,7 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>(
input_name, result_domain, 0.0f);
MutableSpan<Color4f> results = attribute_result.as_span();
MutableSpan<ColorGeometry4f> results = attribute_result.as_span();
ColorBand *color_ramp = &node_storage->color_ramp;
parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {

View File

@ -131,16 +131,16 @@ static void do_equal_operation_float3(const VArray<float3> &input_a,
}
}
static void do_equal_operation_color4f(const VArray<Color4f> &input_a,
const VArray<Color4f> &input_b,
static void do_equal_operation_color4f(const VArray<ColorGeometry4f> &input_a,
const VArray<ColorGeometry4f> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
const float threshold_squared = pow2f(threshold);
const int size = input_a.size();
for (const int i : IndexRange(size)) {
const Color4f a = input_a[i];
const Color4f b = input_b[i];
const ColorGeometry4f a = input_a[i];
const ColorGeometry4f b = input_b[i];
span_result[i] = len_squared_v4v4(a, b) < threshold_squared;
}
}
@ -185,16 +185,16 @@ static void do_not_equal_operation_float3(const VArray<float3> &input_a,
}
}
static void do_not_equal_operation_color4f(const VArray<Color4f> &input_a,
const VArray<Color4f> &input_b,
static void do_not_equal_operation_color4f(const VArray<ColorGeometry4f> &input_a,
const VArray<ColorGeometry4f> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
const float threshold_squared = pow2f(threshold);
const int size = input_a.size();
for (const int i : IndexRange(size)) {
const Color4f a = input_a[i];
const Color4f b = input_b[i];
const ColorGeometry4f a = input_a[i];
const ColorGeometry4f b = input_b[i];
span_result[i] = len_squared_v4v4(a, b) >= threshold_squared;
}
}
@ -287,8 +287,10 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
do_equal_operation_color4f(
attribute_a->typed<Color4f>(), attribute_b->typed<Color4f>(), threshold, result_span);
do_equal_operation_color4f(attribute_a->typed<ColorGeometry4f>(),
attribute_b->typed<ColorGeometry4f>(),
threshold,
result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
do_equal_operation_bool(
@ -305,8 +307,10 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
do_not_equal_operation_color4f(
attribute_a->typed<Color4f>(), attribute_b->typed<Color4f>(), threshold, result_span);
do_not_equal_operation_color4f(attribute_a->typed<ColorGeometry4f>(),
attribute_b->typed<ColorGeometry4f>(),
threshold,
result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
do_not_equal_operation_bool(

View File

@ -165,9 +165,10 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
}
case CD_PROP_COLOR: {
const CurveMapping *cumap = (CurveMapping *)node_storage.curve_rgb;
GVArray_Typed<Color4f> attribute_in = component.attribute_get_for_read<Color4f>(
input_name, result_domain, Color4f(0.0f, 0.0f, 0.0f, 1.0f));
MutableSpan<Color4f> results = attribute_result.as_span<Color4f>();
GVArray_Typed<ColorGeometry4f> attribute_in =
component.attribute_get_for_read<ColorGeometry4f>(
input_name, result_domain, ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>();
parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
for (const int i : range) {
BKE_curvemapping_evaluateRGBF(cumap, results[i], attribute_in[i]);

View File

@ -110,7 +110,7 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
break;
}
case CD_PROP_COLOR: {
const Color4f value = params.get_input<Color4f>("Value_002");
const ColorGeometry4f value = params.get_input<ColorGeometry4f>("Value_002");
attribute->fill(&value);
break;
}

View File

@ -120,16 +120,16 @@ static void do_mix_operation_float3(const int blend_mode,
static void do_mix_operation_color4f(const int blend_mode,
const VArray<float> &factors,
const VArray<Color4f> &inputs_a,
const VArray<Color4f> &inputs_b,
VMutableArray<Color4f> &results)
const VArray<ColorGeometry4f> &inputs_a,
const VArray<ColorGeometry4f> &inputs_b,
VMutableArray<ColorGeometry4f> &results)
{
const int size = results.size();
parallel_for(IndexRange(size), 512, [&](IndexRange range) {
for (const int i : range) {
const float factor = factors[i];
Color4f a = inputs_a[i];
const Color4f b = inputs_b[i];
ColorGeometry4f a = inputs_a[i];
const ColorGeometry4f b = inputs_b[i];
ramp_blend(blend_mode, a, factor, b);
results.set(i, a);
}
@ -160,9 +160,9 @@ static void do_mix_operation(const CustomDataType result_type,
else if (result_type == CD_PROP_COLOR) {
do_mix_operation_color4f(blend_mode,
attribute_factor,
attribute_a.typed<Color4f>(),
attribute_b.typed<Color4f>(),
attribute_result.typed<Color4f>());
attribute_a.typed<ColorGeometry4f>(),
attribute_b.typed<ColorGeometry4f>(),
attribute_result.typed<ColorGeometry4f>());
}
}

View File

@ -79,8 +79,9 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
const AttributeDomain result_domain = get_result_domain(
component, result_attribute_name, mapping_name);
OutputAttribute_Typed<Color4f> attribute_out =
component.attribute_try_get_for_output_only<Color4f>(result_attribute_name, result_domain);
OutputAttribute_Typed<ColorGeometry4f> attribute_out =
component.attribute_try_get_for_output_only<ColorGeometry4f>(result_attribute_name,
result_domain);
if (!attribute_out) {
return;
}
@ -88,7 +89,7 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
GVArray_Typed<float3> mapping_attribute = component.attribute_get_for_read<float3>(
mapping_name, result_domain, {0, 0, 0});
MutableSpan<Color4f> colors = attribute_out.as_span();
MutableSpan<ColorGeometry4f> colors = attribute_out.as_span();
parallel_for(IndexRange(mapping_attribute.size()), 128, [&](IndexRange range) {
for (const int i : range) {
TexResult texture_result = {0};

View File

@ -134,7 +134,7 @@ static void geo_node_switch_exec(GeoNodeExecParams params)
break;
}
case SOCK_RGBA: {
output_input<Color4f>(params, input, "_004", "Output_004");
output_input<ColorGeometry4f>(params, input, "_004", "Output_004");
break;
}
case SOCK_STRING: {

View File

@ -104,9 +104,10 @@ GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name,
return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
}
if (found_socket->type == SOCK_RGBA) {
const Color4f value = this->get_input<Color4f>(found_socket->identifier);
const ColorGeometry4f value = this->get_input<ColorGeometry4f>(found_socket->identifier);
BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
conversions.convert_to_uninitialized(CPPType::get<Color4f>(), *cpp_type, &value, buffer);
conversions.convert_to_uninitialized(
CPPType::get<ColorGeometry4f>(), *cpp_type, &value, buffer);
return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
}
BLI_assert(false);

View File

@ -637,9 +637,9 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
static bNodeSocketType *make_socket_type_rgba()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE);
socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<blender::Color4f>(); };
socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<blender::ColorGeometry4f>(); };
socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(blender::Color4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value;
*(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value;
};
return socktype;
}

View File

@ -66,9 +66,9 @@ static bool float_to_bool(const float &a)
{
return a > 0.0f;
}
static Color4f float_to_color(const float &a)
static ColorGeometry4f float_to_color(const float &a)
{
return Color4f(a, a, a, 1.0f);
return ColorGeometry4f(a, a, a, 1.0f);
}
static float3 float2_to_float3(const float2 &a)
@ -87,9 +87,9 @@ static bool float2_to_bool(const float2 &a)
{
return !is_zero_v2(a);
}
static Color4f float2_to_color(const float2 &a)
static ColorGeometry4f float2_to_color(const float2 &a)
{
return Color4f(a.x, a.y, 0.0f, 1.0f);
return ColorGeometry4f(a.x, a.y, 0.0f, 1.0f);
}
static bool float3_to_bool(const float3 &a)
@ -108,9 +108,9 @@ static float2 float3_to_float2(const float3 &a)
{
return float2(a);
}
static Color4f float3_to_color(const float3 &a)
static ColorGeometry4f float3_to_color(const float3 &a)
{
return Color4f(a.x, a.y, a.z, 1.0f);
return ColorGeometry4f(a.x, a.y, a.z, 1.0f);
}
static bool int_to_bool(const int32_t &a)
@ -129,9 +129,9 @@ static float3 int_to_float3(const int32_t &a)
{
return float3((float)a);
}
static Color4f int_to_color(const int32_t &a)
static ColorGeometry4f int_to_color(const int32_t &a)
{
return Color4f((float)a, (float)a, (float)a, 1.0f);
return ColorGeometry4f((float)a, (float)a, (float)a, 1.0f);
}
static float bool_to_float(const bool &a)
@ -150,28 +150,28 @@ static float3 bool_to_float3(const bool &a)
{
return (a) ? float3(1.0f) : float3(0.0f);
}
static Color4f bool_to_color(const bool &a)
static ColorGeometry4f bool_to_color(const bool &a)
{
return (a) ? Color4f(1.0f, 1.0f, 1.0f, 1.0f) : Color4f(0.0f, 0.0f, 0.0f, 1.0f);
return (a) ? ColorGeometry4f(1.0f, 1.0f, 1.0f, 1.0f) : ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f);
}
static bool color_to_bool(const Color4f &a)
static bool color_to_bool(const ColorGeometry4f &a)
{
return rgb_to_grayscale(a) > 0.0f;
}
static float color_to_float(const Color4f &a)
static float color_to_float(const ColorGeometry4f &a)
{
return rgb_to_grayscale(a);
}
static int32_t color_to_int(const Color4f &a)
static int32_t color_to_int(const ColorGeometry4f &a)
{
return (int)rgb_to_grayscale(a);
}
static float2 color_to_float2(const Color4f &a)
static float2 color_to_float2(const ColorGeometry4f &a)
{
return float2(a.r, a.g);
}
static float3 color_to_float3(const Color4f &a)
static float3 color_to_float3(const ColorGeometry4f &a)
{
return float3(a.r, a.g, a.b);
}
@ -184,37 +184,37 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<float, float3, float_to_float3>(conversions);
add_implicit_conversion<float, int32_t, float_to_int>(conversions);
add_implicit_conversion<float, bool, float_to_bool>(conversions);
add_implicit_conversion<float, Color4f, float_to_color>(conversions);
add_implicit_conversion<float, ColorGeometry4f, float_to_color>(conversions);
add_implicit_conversion<float2, float3, float2_to_float3>(conversions);
add_implicit_conversion<float2, float, float2_to_float>(conversions);
add_implicit_conversion<float2, int32_t, float2_to_int>(conversions);
add_implicit_conversion<float2, bool, float2_to_bool>(conversions);
add_implicit_conversion<float2, Color4f, float2_to_color>(conversions);
add_implicit_conversion<float2, ColorGeometry4f, float2_to_color>(conversions);
add_implicit_conversion<float3, bool, float3_to_bool>(conversions);
add_implicit_conversion<float3, float, float3_to_float>(conversions);
add_implicit_conversion<float3, int32_t, float3_to_int>(conversions);
add_implicit_conversion<float3, float2, float3_to_float2>(conversions);
add_implicit_conversion<float3, Color4f, float3_to_color>(conversions);
add_implicit_conversion<float3, ColorGeometry4f, float3_to_color>(conversions);
add_implicit_conversion<int32_t, bool, int_to_bool>(conversions);
add_implicit_conversion<int32_t, float, int_to_float>(conversions);
add_implicit_conversion<int32_t, float2, int_to_float2>(conversions);
add_implicit_conversion<int32_t, float3, int_to_float3>(conversions);
add_implicit_conversion<int32_t, Color4f, int_to_color>(conversions);
add_implicit_conversion<int32_t, ColorGeometry4f, int_to_color>(conversions);
add_implicit_conversion<bool, float, bool_to_float>(conversions);
add_implicit_conversion<bool, int32_t, bool_to_int>(conversions);
add_implicit_conversion<bool, float2, bool_to_float2>(conversions);
add_implicit_conversion<bool, float3, bool_to_float3>(conversions);
add_implicit_conversion<bool, Color4f, bool_to_color>(conversions);
add_implicit_conversion<bool, ColorGeometry4f, bool_to_color>(conversions);
add_implicit_conversion<Color4f, bool, color_to_bool>(conversions);
add_implicit_conversion<Color4f, float, color_to_float>(conversions);
add_implicit_conversion<Color4f, int32_t, color_to_int>(conversions);
add_implicit_conversion<Color4f, float2, color_to_float2>(conversions);
add_implicit_conversion<Color4f, float3, color_to_float3>(conversions);
add_implicit_conversion<ColorGeometry4f, bool, color_to_bool>(conversions);
add_implicit_conversion<ColorGeometry4f, float, color_to_float>(conversions);
add_implicit_conversion<ColorGeometry4f, int32_t, color_to_int>(conversions);
add_implicit_conversion<ColorGeometry4f, float2, color_to_float2>(conversions);
add_implicit_conversion<ColorGeometry4f, float3, color_to_float3>(conversions);
return conversions;
}

View File

@ -70,7 +70,7 @@ class SeparateRGBFunction : public blender::fn::MultiFunction {
static blender::fn::MFSignature create_signature()
{
blender::fn::MFSignatureBuilder signature{"Separate RGB"};
signature.single_input<blender::Color4f>("Color");
signature.single_input<blender::ColorGeometry4f>("Color");
signature.single_output<float>("R");
signature.single_output<float>("G");
signature.single_output<float>("B");
@ -81,14 +81,14 @@ class SeparateRGBFunction : public blender::fn::MultiFunction {
blender::fn::MFParams params,
blender::fn::MFContext UNUSED(context)) const override
{
const blender::VArray<blender::Color4f> &colors =
params.readonly_single_input<blender::Color4f>(0, "Color");
const blender::VArray<blender::ColorGeometry4f> &colors =
params.readonly_single_input<blender::ColorGeometry4f>(0, "Color");
blender::MutableSpan<float> rs = params.uninitialized_single_output<float>(1, "R");
blender::MutableSpan<float> gs = params.uninitialized_single_output<float>(2, "G");
blender::MutableSpan<float> bs = params.uninitialized_single_output<float>(3, "B");
for (int64_t i : mask) {
blender::Color4f color = colors[i];
blender::ColorGeometry4f color = colors[i];
rs[i] = color.r;
gs[i] = color.g;
bs[i] = color.b;
@ -155,8 +155,9 @@ static int gpu_shader_combrgb(GPUMaterial *mat,
static void sh_node_combrgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
{
static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, blender::Color4f> fn{
"Combine RGB", [](float r, float g, float b) { return blender::Color4f(r, g, b, 1.0f); }};
static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, blender::ColorGeometry4f> fn{
"Combine RGB",
[](float r, float g, float b) { return blender::ColorGeometry4f(r, g, b, 1.0f); }};
builder.set_matching_fn(fn);
}

View File

@ -140,7 +140,7 @@ class ColorBandFunction : public blender::fn::MultiFunction {
{
blender::fn::MFSignatureBuilder signature{"Color Band"};
signature.single_input<float>("Value");
signature.single_output<blender::Color4f>("Color");
signature.single_output<blender::ColorGeometry4f>("Color");
signature.single_output<float>("Alpha");
return signature.build();
}
@ -150,12 +150,12 @@ class ColorBandFunction : public blender::fn::MultiFunction {
blender::fn::MFContext UNUSED(context)) const override
{
const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
blender::MutableSpan<blender::Color4f> colors =
params.uninitialized_single_output<blender::Color4f>(1, "Color");
blender::MutableSpan<blender::ColorGeometry4f> colors =
params.uninitialized_single_output<blender::ColorGeometry4f>(1, "Color");
blender::MutableSpan<float> alphas = params.uninitialized_single_output<float>(2, "Alpha");
for (int64_t i : mask) {
blender::Color4f color;
blender::ColorGeometry4f color;
BKE_colorband_evaluate(&color_band_, values[i], color);
colors[i] = color;
alphas[i] = color.a;