Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/BKE_attribute_math.hh
| Show First 20 Lines • Show All 225 Lines • ▼ Show 20 Lines | for (const int64_t i : buffer_.index_range()) { | ||||
| else { | else { | ||||
| buffer_[i] = default_value_; | buffer_[i] = default_value_; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| }; | }; | ||||
| /** | /** | ||||
| * Mixes together booleans with "or" while fitting the same interface as the other | |||||
| * mixers in order to be simpler to use. This mixing method has a few benefits: | |||||
| * - An "average" for selections is relatively meaningless. | |||||
| * - Predictable selection propagation is very super important. | |||||
| * - It's generally easier to remove an element from a selection that is slightly too large than | |||||
| * the opposite. | |||||
| */ | |||||
| class BooleanPropagationMixer { | |||||
| private: | |||||
| MutableSpan<bool> buffer_; | |||||
| public: | |||||
| /** | |||||
| * \param buffer: Span where the interpolated values should be stored. | |||||
| */ | |||||
| BooleanPropagationMixer(MutableSpan<bool> buffer) : buffer_(buffer) | |||||
| { | |||||
| buffer_.fill(false); | |||||
| } | |||||
| /** | |||||
| * Mix a #value into the element with the given #index. | |||||
| */ | |||||
| void mix_in(const int64_t index, const bool value, [[maybe_unused]] const float weight = 1.0f) | |||||
| { | |||||
| buffer_[index] |= value; | |||||
| } | |||||
| /** | |||||
| * Does not do anything, since the mixing is trivial. | |||||
| */ | |||||
| void finalize() | |||||
| { | |||||
| } | |||||
| }; | |||||
| /** | |||||
| * This mixer accumulates values in a type that is different from the one that is mixed. | * This mixer accumulates values in a type that is different from the one that is mixed. | ||||
| * Some types cannot encode the floating point weights in their values (e.g. int and bool). | * Some types cannot encode the floating point weights in their values (e.g. int and bool). | ||||
| */ | */ | ||||
| template<typename T, typename AccumulationT, T (*ConvertToT)(const AccumulationT &value)> | template<typename T, typename AccumulationT, T (*ConvertToT)(const AccumulationT &value)> | ||||
| class SimpleMixerWithAccumulationType { | class SimpleMixerWithAccumulationType { | ||||
| private: | private: | ||||
| struct Item { | struct Item { | ||||
| /* Store both values together, because they are accessed together. */ | /* Store both values together, because they are accessed together. */ | ||||
| ▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
| public: | public: | ||||
| ColorGeometryMixer(MutableSpan<ColorGeometry4f> buffer, | ColorGeometryMixer(MutableSpan<ColorGeometry4f> buffer, | ||||
| ColorGeometry4f default_color = ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); | ColorGeometry4f default_color = ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); | ||||
| void mix_in(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(); | ||||
| }; | }; | ||||
| template<typename T> struct DefaultMixerStruct { | template<typename T> struct DefaultMixerStruct { | ||||
| /* Use void by default. This can be check for in `if constexpr` statements. */ | /* Use void by default. This can be checked for in `if constexpr` statements. */ | ||||
| using type = void; | using type = void; | ||||
| }; | }; | ||||
| template<> struct DefaultMixerStruct<float> { | template<> struct DefaultMixerStruct<float> { | ||||
| using type = SimpleMixer<float>; | using type = SimpleMixer<float>; | ||||
| }; | }; | ||||
| template<> struct DefaultMixerStruct<float2> { | template<> struct DefaultMixerStruct<float2> { | ||||
| using type = SimpleMixer<float2>; | using type = SimpleMixer<float2>; | ||||
| }; | }; | ||||
| Show All 19 Lines | template<> struct DefaultMixerStruct<bool> { | ||||
| { | { | ||||
| return value >= 0.5f; | return value >= 0.5f; | ||||
| } | } | ||||
| /* Store interpolated booleans in a float temporary. | /* Store interpolated booleans in a float temporary. | ||||
| * Otherwise information provided by weights is easily rounded away. */ | * Otherwise information provided by weights is easily rounded away. */ | ||||
| using type = SimpleMixerWithAccumulationType<bool, float, float_to_bool>; | using type = SimpleMixerWithAccumulationType<bool, float, float_to_bool>; | ||||
| }; | }; | ||||
| template<typename T> struct DefaultPropatationMixerStruct { | |||||
JacquesLucke: Typo (`propatation`) | |||||
| /* Use void by default. This can be checked for in `if constexpr` statements. */ | |||||
| using type = typename DefaultMixerStruct<T>::type; | |||||
| }; | |||||
| template<> struct DefaultPropatationMixerStruct<bool> { | |||||
| using type = BooleanPropagationMixer; | |||||
| }; | |||||
| /** | |||||
| * This mixer is meant for propagating attributes when creating new geometry. A key difference | |||||
| * with the default mixer is that booleans are mixed with "or" instead of "at least half" | |||||
| * (the default mixing for booleans). | |||||
| */ | |||||
| template<typename T> | |||||
| using DefaultPropatationMixer = typename DefaultPropatationMixerStruct<T>::type; | |||||
| /* Utility to get a good default mixer for a given type. This is `void` when there is no default | /* Utility to get a good default mixer for a given type. This is `void` when there is no default | ||||
| * mixer for the given type. */ | * mixer for the given type. */ | ||||
| template<typename T> using DefaultMixer = typename DefaultMixerStruct<T>::type; | template<typename T> using DefaultMixer = typename DefaultMixerStruct<T>::type; | ||||
| /** \} */ | /** \} */ | ||||
| } // namespace blender::attribute_math | } // namespace blender::attribute_math | ||||
Typo (propatation)