diff --git a/source/blender/blenkernel/BKE_object_types.hh b/source/blender/blenkernel/BKE_object_types.hh index c4d465a4ade..fb39bd853d2 100644 --- a/source/blender/blenkernel/BKE_object_types.hh +++ b/source/blender/blenkernel/BKE_object_types.hh @@ -56,9 +56,6 @@ struct ObjectRuntime { */ char is_data_eval_owned = false; - /** Start time of the mode transfer overlay animation. */ - double overlay_mode_transfer_start_time = 0.0f; - /** * The bounding box of the object's evaluated geometry in the active dependency graph. The bounds * are copied back to the original object for the RNA API and for display in the interface. diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 7b8b8e72c16..24b9453917e 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -146,6 +146,7 @@ set(SRC engines/overlay/overlay_armature.cc engines/overlay/overlay_engine.cc engines/overlay/overlay_instance.cc + engines/overlay/overlay_mode_transfer.cc engines/overlay/overlay_shader.cc engines/overlay/overlay_shape.cc diff --git a/source/blender/draw/engines/overlay/overlay_mode_transfer.cc b/source/blender/draw/engines/overlay/overlay_mode_transfer.cc new file mode 100644 index 00000000000..bd7638de6c7 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_mode_transfer.cc @@ -0,0 +1,34 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "ED_object.hh" + +#include "overlay_mode_transfer.hh" + +namespace blender::draw::overlay { + +void ModeTransfer::begin_sync(Resources &res, const State &state) +{ + object_factors_ = ed::object::mode_transfer_overlay_current_state(); + + enabled_ = state.is_space_v3d() && !res.is_selection() && !object_factors_.is_empty(); + + if (!enabled_) { + /* Not used. But release the data. */ + ps_.init(); + return; + } + + UI_GetThemeColor3fv(TH_VERTEX_SELECT, flash_color_); + srgb_to_linearrgb_v4(flash_color_, flash_color_); + + ps_.init(); + ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_DEPTH, + state.clipping_plane_count); + ps_.shader_set(res.shaders->uniform_color.get()); + ps_.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf); + ps_.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf); +} + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_mode_transfer.hh b/source/blender/draw/engines/overlay/overlay_mode_transfer.hh index 9a700784498..6b2a9c97ed4 100644 --- a/source/blender/draw/engines/overlay/overlay_mode_transfer.hh +++ b/source/blender/draw/engines/overlay/overlay_mode_transfer.hh @@ -8,7 +8,7 @@ #pragma once -#include "BLI_time.h" +#include "BLI_map.hh" #include "BKE_paint.hh" @@ -27,38 +27,12 @@ class ModeTransfer : Overlay { private: PassSimple ps_ = {"ModeTransfer"}; + Map object_factors_; + float4 flash_color_; - double current_time_ = 0.0; - - /* True if any object used was synced using this overlay. */ - bool any_animated_ = false; - public: - void begin_sync(Resources &res, const State &state) final - { - enabled_ = state.is_space_v3d() && !res.is_selection(); - - if (!enabled_) { - /* Not used. But release the data. */ - ps_.init(); - return; - } - - UI_GetThemeColor3fv(TH_VERTEX_SELECT, flash_color_); - srgb_to_linearrgb_v4(flash_color_, flash_color_); - - current_time_ = BLI_time_now_seconds(); - - ps_.init(); - ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_DEPTH, - state.clipping_plane_count); - ps_.shader_set(res.shaders->uniform_color.get()); - ps_.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf); - ps_.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf); - - any_animated_ = false; - } + void begin_sync(Resources &res, const State &state) final; void object_sync(Manager &manager, const ObjectRef &ob_ref, @@ -69,6 +43,11 @@ class ModeTransfer : Overlay { return; } + const std::optional alpha_opt = object_factors_.lookup_try_as(ob_ref.object->id.name); + if (!alpha_opt) { + return; + } + const bool renderable = DRW_object_is_renderable(ob_ref.object); const bool draw_surface = (ob_ref.object->dt >= OB_WIRE) && (renderable || (ob_ref.object->dt == OB_WIRE)); @@ -76,11 +55,8 @@ class ModeTransfer : Overlay { return; } - const float time = current_time_ - ob_ref.object->runtime->overlay_mode_transfer_start_time; - const float alpha = alpha_from_time_get(time); - if (alpha == 0.0f) { - return; - } + constexpr float flash_alpha = 0.25f; + const float alpha = *alpha_opt * flash_alpha; ps_.push_constant("ucolor", float4(flash_color_.xyz() * alpha, alpha)); @@ -99,8 +75,6 @@ class ModeTransfer : Overlay { ps_.draw(geom, manager.unique_handle(ob_ref)); } } - - any_animated_ = true; } void draw(Framebuffer &framebuffer, Manager &manager, View &view) final @@ -112,25 +86,8 @@ class ModeTransfer : Overlay { GPU_framebuffer_bind(framebuffer); manager.submit(ps_, view); - if (any_animated_) { - /* Request redraws until the object fades out. */ - DRW_viewport_request_redraw(); - } - } - - private: - static constexpr float flash_length = 0.55f; - static constexpr float flash_alpha = 0.25f; - - static float alpha_from_time_get(const float anim_time) - { - if (anim_time > flash_length) { - return 0.0f; - } - if (anim_time < 0.0f) { - return 0.0f; - } - return (1.0f - (anim_time / flash_length)) * flash_alpha; + /* Request redraws until the object fades out (enabled_ will be reset to false). */ + DRW_viewport_request_redraw(); } }; diff --git a/source/blender/editors/include/ED_object.hh b/source/blender/editors/include/ED_object.hh index dbd9700cacf..23eae04cd28 100644 --- a/source/blender/editors/include/ED_object.hh +++ b/source/blender/editors/include/ED_object.hh @@ -11,6 +11,7 @@ #include #include "BLI_compiler_attrs.h" +#include "BLI_map.hh" #include "BLI_math_matrix_types.hh" #include "BLI_string_ref.hh" #include "BLI_vector.hh" @@ -457,6 +458,13 @@ Object *object_in_mode_from_index(const Scene *scene, eObjectMode mode, int index); +/** + * Retrieve the alpha factors of the currently active mode transfer overlay animations. The key is + * the object ID name to prevent possible storage of stale pointers and because the #session_uid + * isn't available on evaluated objects. + */ +Map mode_transfer_overlay_current_state(); + /* `object_modifier.cc` */ enum { diff --git a/source/blender/editors/object/object_modes.cc b/source/blender/editors/object/object_modes.cc index 89a7d236c6b..fa8ad39744a 100644 --- a/source/blender/editors/object/object_modes.cc +++ b/source/blender/editors/object/object_modes.cc @@ -408,11 +408,50 @@ static void object_transfer_mode_reposition_view_pivot(ARegion *region, ups->last_stroke_valid = true; } +constexpr float mode_transfer_flash_length = 0.55f; + +static auto &mode_transfer_overlay_start_times() +{ + static Map map; + return map; +} + +static float alpha_from_time_get(const float anim_time) +{ + if (anim_time < 0.0f) { + return 0.0f; + } + return (1.0f - (anim_time / mode_transfer_flash_length)); +} + +Map mode_transfer_overlay_current_state() +{ + const double now = BLI_time_now_seconds(); + + /* Protect against possible concurrent access from multiple renderers or viewports. */ + static Mutex mutex; + std::scoped_lock lock(mutex); + + /* Remove finished animations form the global map. */ + Map &start_times = mode_transfer_overlay_start_times(); + start_times.remove_if( + [&](const auto &item) { return (now - item.value) > mode_transfer_flash_length; }); + + Map factors; + for (const auto &item : start_times.items()) { + const float alpha = alpha_from_time_get(now - item.value); + if (alpha > 0.0f) { + factors.add_new(item.key, alpha); + } + } + return factors; +} + static void object_overlay_mode_transfer_animation_start(bContext *C, Object *ob_dst) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Object *ob_dst_eval = DEG_get_evaluated(depsgraph, ob_dst); - ob_dst_eval->runtime->overlay_mode_transfer_start_time = BLI_time_now_seconds(); + mode_transfer_overlay_start_times().add_as(ob_dst_eval->id.name, BLI_time_now_seconds()); } static bool object_transfer_mode_to_base(bContext *C,