diff options
Diffstat (limited to 'source/blender/blenkernel/BKE_attribute_math.hh')
-rw-r--r-- | source/blender/blenkernel/BKE_attribute_math.hh | 225 |
1 files changed, 196 insertions, 29 deletions
diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh index 01c2ef988f2..abd8b33b260 100644 --- a/source/blender/blenkernel/BKE_attribute_math.hh +++ b/source/blender/blenkernel/BKE_attribute_math.hh @@ -46,6 +46,58 @@ inline void convert_to_static_type(const eCustomDataType data_type, const Func & } /* -------------------------------------------------------------------- */ +/** \name Mix two values of the same type. + * + * This is just basic linear interpolation. + * \{ */ + +template<typename T> T mix2(float factor, const T &a, const T &b); + +template<> inline bool mix2(const float factor, const bool &a, const bool &b) +{ + return ((1.0f - factor) * a + factor * b) >= 0.5f; +} + +template<> inline int8_t mix2(const float factor, const int8_t &a, const int8_t &b) +{ + return static_cast<int8_t>(std::round((1.0f - factor) * a + factor * b)); +} + +template<> inline int mix2(const float factor, const int &a, const int &b) +{ + return static_cast<int>(std::round((1.0f - factor) * a + factor * b)); +} + +template<> inline float mix2(const float factor, const float &a, const float &b) +{ + return (1.0f - factor) * a + factor * b; +} + +template<> inline float2 mix2(const float factor, const float2 &a, const float2 &b) +{ + return math::interpolate(a, b, factor); +} + +template<> inline float3 mix2(const float factor, const float3 &a, const float3 &b) +{ + return math::interpolate(a, b, factor); +} + +template<> +inline ColorGeometry4f mix2(const float factor, const ColorGeometry4f &a, const ColorGeometry4f &b) +{ + return math::interpolate(a, b, factor); +} + +template<> +inline ColorGeometry4b mix2(const float factor, const ColorGeometry4b &a, const ColorGeometry4b &b) +{ + return math::interpolate(a, b, factor); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Mix three values of the same type. * * This is typically used to interpolate values within a triangle. @@ -117,53 +169,85 @@ inline ColorGeometry4b mix3(const float3 &weights, /** \} */ /* -------------------------------------------------------------------- */ -/** \name Mix two values of the same type. +/** \name Mix four values of the same type. * - * This is just basic linear interpolation. * \{ */ -template<typename T> T mix2(float factor, const T &a, const T &b); +template<typename T> +T mix4(const float4 &weights, const T &v0, const T &v1, const T &v2, const T &v3); -template<> inline bool mix2(const float factor, const bool &a, const bool &b) +template<> +inline int8_t mix4( + const float4 &weights, const int8_t &v0, const int8_t &v1, const int8_t &v2, const int8_t &v3) { - return ((1.0f - factor) * a + factor * b) >= 0.5f; + return static_cast<int8_t>( + std::round(weights.x * v0 + weights.y * v1 + weights.z * v2 + weights.w * v3)); } -template<> inline int8_t mix2(const float factor, const int8_t &a, const int8_t &b) +template<> +inline bool mix4( + const float4 &weights, const bool &v0, const bool &v1, const bool &v2, const bool &v3) { - return static_cast<int8_t>(std::round((1.0f - factor) * a + factor * b)); + return (weights.x * v0 + weights.y * v1 + weights.z * v2 + weights.w * v3) >= 0.5f; } -template<> inline int mix2(const float factor, const int &a, const int &b) +template<> +inline int mix4(const float4 &weights, const int &v0, const int &v1, const int &v2, const int &v3) { - return static_cast<int>(std::round((1.0f - factor) * a + factor * b)); + return static_cast<int>( + std::round(weights.x * v0 + weights.y * v1 + weights.z * v2 + weights.w * v3)); } -template<> inline float mix2(const float factor, const float &a, const float &b) +template<> +inline float mix4( + const float4 &weights, const float &v0, const float &v1, const float &v2, const float &v3) { - return (1.0f - factor) * a + factor * b; + return weights.x * v0 + weights.y * v1 + weights.z * v2 + weights.w * v3; } -template<> inline float2 mix2(const float factor, const float2 &a, const float2 &b) +template<> +inline float2 mix4( + const float4 &weights, const float2 &v0, const float2 &v1, const float2 &v2, const float2 &v3) { - return math::interpolate(a, b, factor); + return weights.x * v0 + weights.y * v1 + weights.z * v2 + weights.w * v3; } -template<> inline float3 mix2(const float factor, const float3 &a, const float3 &b) +template<> +inline float3 mix4( + const float4 &weights, const float3 &v0, const float3 &v1, const float3 &v2, const float3 &v3) { - return math::interpolate(a, b, factor); + return weights.x * v0 + weights.y * v1 + weights.z * v2 + weights.w * v3; } template<> -inline ColorGeometry4f mix2(const float factor, const ColorGeometry4f &a, const ColorGeometry4f &b) +inline ColorGeometry4f mix4(const float4 &weights, + const ColorGeometry4f &v0, + const ColorGeometry4f &v1, + const ColorGeometry4f &v2, + const ColorGeometry4f &v3) { - return math::interpolate(a, b, factor); + ColorGeometry4f result; + interp_v4_v4v4v4v4(result, v0, v1, v2, v3, weights); + return result; } template<> -inline ColorGeometry4b mix2(const float factor, const ColorGeometry4b &a, const ColorGeometry4b &b) +inline ColorGeometry4b mix4(const float4 &weights, + const ColorGeometry4b &v0, + const ColorGeometry4b &v1, + const ColorGeometry4b &v2, + const ColorGeometry4b &v3) { - return math::interpolate(a, b, factor); + const float4 v0_f{&v0.r}; + const float4 v1_f{&v1.r}; + const float4 v2_f{&v2.r}; + const float4 v3_f{&v3.r}; + float4 mixed; + interp_v4_v4v4v4v4(mixed, v0_f, v1_f, v2_f, v3_f, weights); + return ColorGeometry4b{static_cast<uint8_t>(mixed[0]), + static_cast<uint8_t>(mixed[1]), + static_cast<uint8_t>(mixed[2]), + static_cast<uint8_t>(mixed[3])}; } /** \} */ @@ -188,10 +272,28 @@ template<typename T> class SimpleMixer { * \param default_value: Output value for an element that has not been affected by a #mix_in. */ SimpleMixer(MutableSpan<T> buffer, T default_value = {}) + : SimpleMixer(buffer, buffer.index_range(), default_value) + { + } + + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + SimpleMixer(MutableSpan<T> buffer, const IndexMask mask, T default_value = {}) : buffer_(buffer), default_value_(default_value), total_weights_(buffer.size(), 0.0f) { BLI_STATIC_ASSERT(std::is_trivial_v<T>, ""); - memset(buffer_.data(), 0, sizeof(T) * buffer_.size()); + mask.foreach_index([&](const int64_t i) { buffer_[i] = default_value_; }); + } + + /** + * Set a #value into the element with the given #index. + */ + void set(const int64_t index, const T &value, const float weight = 1.0f) + { + BLI_assert(weight >= 0.0f); + buffer_[index] = value * weight; + total_weights_[index] = weight; } /** @@ -209,7 +311,12 @@ template<typename T> class SimpleMixer { */ void finalize() { - for (const int64_t i : buffer_.index_range()) { + this->finalize(IndexMask(buffer_.size())); + } + + void finalize(const IndexMask mask) + { + mask.foreach_index([&](const int64_t i) { const float weight = total_weights_[i]; if (weight > 0.0f) { buffer_[i] *= 1.0f / weight; @@ -217,7 +324,7 @@ template<typename T> class SimpleMixer { else { buffer_[i] = default_value_; } - } + }); } }; @@ -237,9 +344,25 @@ class BooleanPropagationMixer { /** * \param buffer: Span where the interpolated values should be stored. */ - BooleanPropagationMixer(MutableSpan<bool> buffer) : buffer_(buffer) + BooleanPropagationMixer(MutableSpan<bool> buffer) + : BooleanPropagationMixer(buffer, buffer.index_range()) { - buffer_.fill(false); + } + + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + BooleanPropagationMixer(MutableSpan<bool> buffer, const IndexMask mask) : buffer_(buffer) + { + mask.foreach_index([&](const int64_t i) { buffer_[i] = false; }); + } + + /** + * Set a #value into the element with the given #index. + */ + void set(const int64_t index, const bool value, [[maybe_unused]] const float weight = 1.0f) + { + buffer_[index] = value; } /** @@ -256,6 +379,10 @@ class BooleanPropagationMixer { void finalize() { } + + void finalize(const IndexMask /*mask*/) + { + } }; /** @@ -277,8 +404,27 @@ class SimpleMixerWithAccumulationType { public: SimpleMixerWithAccumulationType(MutableSpan<T> buffer, T default_value = {}) + : SimpleMixerWithAccumulationType(buffer, buffer.index_range(), default_value) + { + } + + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + SimpleMixerWithAccumulationType(MutableSpan<T> buffer, + const IndexMask mask, + T default_value = {}) : buffer_(buffer), default_value_(default_value), accumulation_buffer_(buffer.size()) { + mask.foreach_index([&](const int64_t index) { buffer_[index] = default_value_; }); + } + + void set(const int64_t index, const T &value, const float weight = 1.0f) + { + const AccumulationT converted_value = static_cast<AccumulationT>(value); + Item &item = accumulation_buffer_[index]; + item.value = converted_value * weight; + item.weight = weight; } void mix_in(const int64_t index, const T &value, const float weight = 1.0f) @@ -291,7 +437,12 @@ class SimpleMixerWithAccumulationType { void finalize() { - for (const int64_t i : buffer_.index_range()) { + this->finalize(buffer_.index_range()); + } + + void finalize(const IndexMask mask) + { + mask.foreach_index([&](const int64_t i) { const Item &item = accumulation_buffer_[i]; if (item.weight > 0.0f) { const float weight_inv = 1.0f / item.weight; @@ -301,7 +452,7 @@ class SimpleMixerWithAccumulationType { else { buffer_[i] = default_value_; } - } + }); } }; @@ -314,8 +465,16 @@ class ColorGeometry4fMixer { public: ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer, ColorGeometry4f default_color = ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer, + IndexMask mask, + ColorGeometry4f default_color = ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); + void set(int64_t index, const ColorGeometry4f &color, float weight = 1.0f); void mix_in(int64_t index, const ColorGeometry4f &color, float weight = 1.0f); void finalize(); + void finalize(IndexMask mask); }; class ColorGeometry4bMixer { @@ -328,8 +487,16 @@ class ColorGeometry4bMixer { public: ColorGeometry4bMixer(MutableSpan<ColorGeometry4b> buffer, ColorGeometry4b default_color = ColorGeometry4b(0, 0, 0, 255)); + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + ColorGeometry4bMixer(MutableSpan<ColorGeometry4b> buffer, + IndexMask mask, + ColorGeometry4b default_color = ColorGeometry4b(0, 0, 0, 255)); + void set(int64_t index, const ColorGeometry4b &color, float weight = 1.0f); void mix_in(int64_t index, const ColorGeometry4b &color, float weight = 1.0f); void finalize(); + void finalize(IndexMask mask); }; template<typename T> struct DefaultMixerStruct { @@ -381,12 +548,12 @@ template<> struct DefaultMixerStruct<int8_t> { using type = SimpleMixerWithAccumulationType<int8_t, float, float_to_int8_t>; }; -template<typename T> struct DefaultPropatationMixerStruct { +template<typename T> struct DefaultPropagationMixerStruct { /* Use void by default. This can be checked for in `if constexpr` statements. */ using type = typename DefaultMixerStruct<T>::type; }; -template<> struct DefaultPropatationMixerStruct<bool> { +template<> struct DefaultPropagationMixerStruct<bool> { using type = BooleanPropagationMixer; }; @@ -396,7 +563,7 @@ template<> struct DefaultPropatationMixerStruct<bool> { * (the default mixing for booleans). */ template<typename T> -using DefaultPropatationMixer = typename DefaultPropatationMixerStruct<T>::type; +using DefaultPropagationMixer = typename DefaultPropagationMixerStruct<T>::type; /* Utility to get a good default mixer for a given type. This is `void` when there is no default * mixer for the given type. */ |