diff options
-rw-r--r-- | core/object/callable_method_pointer.h | 24 | ||||
-rw-r--r-- | core/templates/list.h | 39 | ||||
-rw-r--r-- | editor/surface_upgrade_tool.cpp | 10 | ||||
-rw-r--r-- | modules/gdscript/gdscript.cpp | 149 | ||||
-rw-r--r-- | modules/gdscript/gdscript.h | 19 | ||||
-rw-r--r-- | modules/gdscript/gdscript_lambda_callable.cpp | 4 | ||||
-rw-r--r-- | modules/gdscript/gdscript_lambda_callable.h | 4 | ||||
-rw-r--r-- | scene/animation/animation_mixer.cpp | 70 | ||||
-rw-r--r-- | scene/animation/animation_mixer.h | 13 | ||||
-rw-r--r-- | scene/main/viewport.cpp | 4 |
10 files changed, 204 insertions, 132 deletions
diff --git a/core/object/callable_method_pointer.h b/core/object/callable_method_pointer.h index db78b982e4..f8e8c4d7e9 100644 --- a/core/object/callable_method_pointer.h +++ b/core/object/callable_method_pointer.h @@ -81,35 +81,27 @@ template <class T, class... P> class CallableCustomMethodPointer : public CallableCustomMethodPointerBase { struct Data { T *instance; -#ifdef DEBUG_ENABLED uint64_t object_id; -#endif void (T::*method)(P...); } data; public: virtual ObjectID get_object() const { -#ifdef DEBUG_ENABLED if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) { return ObjectID(); } -#endif return data.instance->get_instance_id(); } virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { -#ifdef DEBUG_ENABLED ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method."); -#endif call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error); } CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) { memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes. data.instance = p_instance; -#ifdef DEBUG_ENABLED data.object_id = p_instance->get_instance_id(); -#endif data.method = p_method; _setup((uint32_t *)&data, sizeof(Data)); } @@ -135,36 +127,28 @@ template <class T, class R, class... P> class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase { struct Data { T *instance; -#ifdef DEBUG_ENABLED uint64_t object_id; -#endif R(T::*method) (P...); } data; public: virtual ObjectID get_object() const { -#ifdef DEBUG_ENABLED if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) { return ObjectID(); } -#endif return data.instance->get_instance_id(); } virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { -#ifdef DEBUG_ENABLED ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method."); -#endif call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error); } CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) { memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes. data.instance = p_instance; -#ifdef DEBUG_ENABLED data.object_id = p_instance->get_instance_id(); -#endif data.method = p_method; _setup((uint32_t *)&data, sizeof(Data)); } @@ -190,36 +174,28 @@ template <class T, class R, class... P> class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase { struct Data { T *instance; -#ifdef DEBUG_ENABLED uint64_t object_id; -#endif R(T::*method) (P...) const; } data; public: virtual ObjectID get_object() const override { -#ifdef DEBUG_ENABLED if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) { return ObjectID(); } -#endif return data.instance->get_instance_id(); } virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override { -#ifdef DEBUG_ENABLED ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method."); -#endif call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error); } CallableCustomMethodPointerRetC(T *p_instance, R (T::*p_method)(P...) const) { memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes. data.instance = p_instance; -#ifdef DEBUG_ENABLED data.object_id = p_instance->get_instance_id(); -#endif data.method = p_method; _setup((uint32_t *)&data, sizeof(Data)); } diff --git a/core/templates/list.h b/core/templates/list.h index 6393b942ff..354e826a43 100644 --- a/core/templates/list.h +++ b/core/templates/list.h @@ -132,6 +132,8 @@ public: data->erase(this); } + void transfer_to_back(List<T, A> *p_dst_list); + _FORCE_INLINE_ Element() {} }; @@ -762,4 +764,41 @@ public: } }; +template <class T, class A> +void List<T, A>::Element::transfer_to_back(List<T, A> *p_dst_list) { + // Detach from current. + + if (data->first == this) { + data->first = data->first->next_ptr; + } + if (data->last == this) { + data->last = data->last->prev_ptr; + } + if (prev_ptr) { + prev_ptr->next_ptr = next_ptr; + } + if (next_ptr) { + next_ptr->prev_ptr = prev_ptr; + } + data->size_cache--; + + // Attach to the back of the new one. + + if (!p_dst_list->_data) { + p_dst_list->_data = memnew_allocator(_Data, A); + p_dst_list->_data->first = this; + p_dst_list->_data->last = nullptr; + p_dst_list->_data->size_cache = 0; + prev_ptr = nullptr; + } else { + p_dst_list->_data->last->next_ptr = this; + prev_ptr = p_dst_list->_data->last; + } + p_dst_list->_data->last = this; + next_ptr = nullptr; + + data = p_dst_list->_data; + p_dst_list->_data->size_cache++; +} + #endif // LIST_H diff --git a/editor/surface_upgrade_tool.cpp b/editor/surface_upgrade_tool.cpp index 0c0f8555b5..78ebe43c96 100644 --- a/editor/surface_upgrade_tool.cpp +++ b/editor/surface_upgrade_tool.cpp @@ -76,6 +76,7 @@ void SurfaceUpgradeTool::_try_show_popup() { } else { singleton->_show_popup(); } + RS::get_singleton()->set_warn_on_surface_upgrade(false); } void SurfaceUpgradeTool::_show_popup() { @@ -122,11 +123,13 @@ void SurfaceUpgradeTool::finish_upgrade() { // Update all meshes here. Vector<String> resave_paths = EditorSettings::get_singleton()->get_project_metadata("surface_upgrade_tool", "resave_paths", Vector<String>()); - EditorProgress ep("surface_upgrade_resave", TTR("Upgrading All Meshes in Project"), resave_paths.size()); + Vector<String> reimport_paths = EditorSettings::get_singleton()->get_project_metadata("surface_upgrade_tool", "reimport_paths", Vector<String>()); + EditorProgress ep("surface_upgrade_resave", TTR("Upgrading All Meshes in Project"), resave_paths.size() + reimport_paths.size()); + int step = 0; for (const String &file_path : resave_paths) { Ref<Resource> res = ResourceLoader::load(file_path); - ep.step(TTR("Attempting to re-save ") + file_path); + ep.step(TTR("Attempting to re-save ") + file_path, step++); if (res.is_valid()) { // Ignore things that fail to load. ResourceSaver::save(res); @@ -135,7 +138,6 @@ void SurfaceUpgradeTool::finish_upgrade() { EditorSettings::get_singleton()->set_project_metadata("surface_upgrade_tool", "resave_paths", Vector<String>()); // Remove the imported scenes/meshes from .import so they will be reimported automatically after this. - Vector<String> reimport_paths = EditorSettings::get_singleton()->get_project_metadata("surface_upgrade_tool", "reimport_paths", Vector<String>()); for (const String &file_path : reimport_paths) { Ref<ConfigFile> config; config.instantiate(); @@ -150,6 +152,8 @@ void SurfaceUpgradeTool::finish_upgrade() { continue; } + ep.step(TTR("Attempting to remove ") + remap_path, step++); + String path = OS::get_singleton()->get_resource_dir() + remap_path.replace_first("res://", "/"); print_verbose("Moving to trash: " + path); err = OS::get_singleton()->move_to_trash(path); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index b098a0d3d5..05c2558417 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1391,108 +1391,51 @@ String GDScript::debug_get_script_name(const Ref<Script> &p_script) { } #endif -thread_local GDScript::UpdatableFuncPtr GDScript::func_ptrs_to_update_thread_local; -GDScript::UpdatableFuncPtr *GDScript::func_ptrs_to_update_main_thread = &func_ptrs_to_update_thread_local; +GDScript::UpdatableFuncPtr GDScript::func_ptrs_to_update_main_thread; +thread_local GDScript::UpdatableFuncPtr *GDScript::func_ptrs_to_update_thread_local = nullptr; -List<GDScript::UpdatableFuncPtrElement>::Element *GDScript::_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr) { - MutexLock lock(func_ptrs_to_update_mutex); - - List<UpdatableFuncPtrElement>::Element *result = func_ptrs_to_update_elems.push_back(UpdatableFuncPtrElement()); +GDScript::UpdatableFuncPtrElement GDScript::_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr) { + UpdatableFuncPtrElement result = {}; { - MutexLock lock2(func_ptrs_to_update_thread_local.mutex); - result->get().element = func_ptrs_to_update_thread_local.ptrs.push_back(p_func_ptr_ptr); - result->get().mutex = &func_ptrs_to_update_thread_local.mutex; + MutexLock lock(func_ptrs_to_update_thread_local->mutex); + result.element = func_ptrs_to_update_thread_local->ptrs.push_back(p_func_ptr_ptr); + result.func_ptr = func_ptrs_to_update_thread_local; - if (likely(func_ptrs_to_update_thread_local.initialized)) { + if (likely(func_ptrs_to_update_thread_local->initialized)) { return result; } - func_ptrs_to_update_thread_local.initialized = true; + func_ptrs_to_update_thread_local->initialized = true; } - func_ptrs_to_update.push_back(&func_ptrs_to_update_thread_local); + MutexLock lock(func_ptrs_to_update_mutex); + func_ptrs_to_update.push_back(func_ptrs_to_update_thread_local); + func_ptrs_to_update_thread_local->rc++; return result; } -void GDScript::_remove_func_ptr_to_update(List<UpdatableFuncPtrElement>::Element *p_func_ptr_element) { - // None of these checks should ever fail, unless there's a bug. - // They can be removed once we are sure they never catch anything. - // Left here now due to extra safety needs late in the release cycle. - ERR_FAIL_NULL(p_func_ptr_element); - MutexLock lock(func_ptrs_to_update_thread_local.mutex); - ERR_FAIL_NULL(p_func_ptr_element->get().element); - ERR_FAIL_NULL(p_func_ptr_element->get().mutex); - MutexLock lock2(*p_func_ptr_element->get().mutex); - p_func_ptr_element->get().element->erase(); - p_func_ptr_element->erase(); +void GDScript::_remove_func_ptr_to_update(const UpdatableFuncPtrElement &p_func_ptr_element) { + ERR_FAIL_NULL(p_func_ptr_element.element); + ERR_FAIL_NULL(p_func_ptr_element.func_ptr); + MutexLock lock(p_func_ptr_element.func_ptr->mutex); + p_func_ptr_element.element->erase(); } void GDScript::_fixup_thread_function_bookkeeping() { // Transfer the ownership of these update items to the main thread, // because the current one is dying, leaving theirs orphan, dangling. - HashSet<GDScript *> scripts; - DEV_ASSERT(!Thread::is_main_thread()); - MutexLock lock(func_ptrs_to_update_main_thread->mutex); - { - MutexLock lock2(func_ptrs_to_update_thread_local.mutex); - - while (!func_ptrs_to_update_thread_local.ptrs.is_empty()) { - // Transfer the thread-to-script records from the dying thread to the main one. - - List<GDScriptFunction **>::Element *E = func_ptrs_to_update_thread_local.ptrs.front(); - List<GDScriptFunction **>::Element *new_E = func_ptrs_to_update_main_thread->ptrs.push_front(E->get()); - - GDScript *script = (*E->get())->get_script(); - if (!scripts.has(script)) { - scripts.insert(script); - - // Replace dying thread by the main thread in the script-to-thread records. - - MutexLock lock3(script->func_ptrs_to_update_mutex); - DEV_ASSERT(script->func_ptrs_to_update.find(&func_ptrs_to_update_thread_local)); - { - for (List<UpdatableFuncPtrElement>::Element *F = script->func_ptrs_to_update_elems.front(); F; F = F->next()) { - bool is_dying_thread_entry = F->get().mutex == &func_ptrs_to_update_thread_local.mutex; - if (is_dying_thread_entry) { - // This may lead to multiple main-thread entries, but that's not a problem - // and allows to reuse the element, which is needed, since it's tracked by pointer. - F->get().element = new_E; - F->get().mutex = &func_ptrs_to_update_main_thread->mutex; - } - } - } - } + MutexLock lock(func_ptrs_to_update_main_thread.mutex); + MutexLock lock2(func_ptrs_to_update_thread_local->mutex); - E->erase(); - } - } - func_ptrs_to_update_main_thread->initialized = true; - - { - // Remove orphan thread-to-script entries from every script. - // FIXME: This involves iterating through every script whenever a thread dies. - // While it's OK that thread creation/destruction are heavy operations, - // additional bookkeeping can be used to outperform this brute-force approach. - - GDScriptLanguage *gd_lang = GDScriptLanguage::get_singleton(); - - MutexLock lock2(gd_lang->mutex); - - for (SelfList<GDScript> *s = gd_lang->script_list.first(); s; s = s->next()) { - GDScript *script = s->self(); - for (List<UpdatableFuncPtr *>::Element *E = script->func_ptrs_to_update.front(); E; E = E->next()) { - bool is_dying_thread_entry = &E->get()->mutex == &func_ptrs_to_update_thread_local.mutex; - if (is_dying_thread_entry) { - E->erase(); - break; - } - } - } + while (!func_ptrs_to_update_thread_local->ptrs.is_empty()) { + List<GDScriptFunction **>::Element *E = func_ptrs_to_update_thread_local->ptrs.front(); + E->transfer_to_back(&func_ptrs_to_update_main_thread.ptrs); + func_ptrs_to_update_thread_local->transferred = true; } } @@ -1516,12 +1459,29 @@ void GDScript::clear(ClearData *p_clear_data) { { MutexLock outer_lock(func_ptrs_to_update_mutex); for (UpdatableFuncPtr *updatable : func_ptrs_to_update) { - MutexLock inner_lock(updatable->mutex); - for (GDScriptFunction **func_ptr_ptr : updatable->ptrs) { - *func_ptr_ptr = nullptr; + bool destroy = false; + { + MutexLock inner_lock(updatable->mutex); + if (updatable->transferred) { + func_ptrs_to_update_main_thread.mutex.lock(); + } + for (GDScriptFunction **func_ptr_ptr : updatable->ptrs) { + *func_ptr_ptr = nullptr; + } + DEV_ASSERT(updatable->rc != 0); + updatable->rc--; + if (updatable->rc == 0) { + destroy = true; + } + if (updatable->transferred) { + func_ptrs_to_update_main_thread.mutex.unlock(); + } + } + if (destroy) { + DEV_ASSERT(updatable != &func_ptrs_to_update_main_thread); + memdelete(updatable); } } - func_ptrs_to_update_elems.clear(); } RBSet<GDScript *> must_clear_dependencies = get_must_clear_dependencies(); @@ -2141,8 +2101,25 @@ void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) { named_globals.erase(p_name); } +void GDScriptLanguage::thread_enter() { + GDScript::func_ptrs_to_update_thread_local = memnew(GDScript::UpdatableFuncPtr); +} + void GDScriptLanguage::thread_exit() { GDScript::_fixup_thread_function_bookkeeping(); + + bool destroy = false; + { + MutexLock lock(GDScript::func_ptrs_to_update_thread_local->mutex); + DEV_ASSERT(GDScript::func_ptrs_to_update_thread_local->rc != 0); + GDScript::func_ptrs_to_update_thread_local->rc--; + if (GDScript::func_ptrs_to_update_thread_local->rc == 0) { + destroy = true; + } + } + if (destroy) { + memdelete(GDScript::func_ptrs_to_update_thread_local); + } } void GDScriptLanguage::init() { @@ -2177,6 +2154,8 @@ void GDScriptLanguage::init() { _add_global(E.name, E.ptr); } + GDScript::func_ptrs_to_update_thread_local = &GDScript::func_ptrs_to_update_main_thread; + #ifdef TESTS_ENABLED GDScriptTests::GDScriptTestRunner::handle_cmdline(); #endif @@ -2226,6 +2205,8 @@ void GDScriptLanguage::finish() { } script_list.clear(); function_list.clear(); + + DEV_ASSERT(GDScript::func_ptrs_to_update_main_thread.rc == 1); } void GDScriptLanguage::profiling_start() { diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 8d62334d69..aba4d7e721 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -121,21 +121,23 @@ class GDScript : public Script { struct UpdatableFuncPtr { List<GDScriptFunction **> ptrs; Mutex mutex; - bool initialized = false; + bool initialized : 1; + bool transferred : 1; + uint32_t rc = 1; + UpdatableFuncPtr() : + initialized(false), transferred(false) {} }; struct UpdatableFuncPtrElement { List<GDScriptFunction **>::Element *element = nullptr; - Mutex *mutex = nullptr; + UpdatableFuncPtr *func_ptr = nullptr; }; - static thread_local UpdatableFuncPtr func_ptrs_to_update_thread_local; - static thread_local LocalVector<List<UpdatableFuncPtr *>::Element> func_ptrs_to_update_entries_thread_local; - static UpdatableFuncPtr *func_ptrs_to_update_main_thread; + static UpdatableFuncPtr func_ptrs_to_update_main_thread; + static thread_local UpdatableFuncPtr *func_ptrs_to_update_thread_local; List<UpdatableFuncPtr *> func_ptrs_to_update; - List<UpdatableFuncPtrElement> func_ptrs_to_update_elems; Mutex func_ptrs_to_update_mutex; - List<UpdatableFuncPtrElement>::Element *_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr); - static void _remove_func_ptr_to_update(List<UpdatableFuncPtrElement>::Element *p_func_ptr_element); + UpdatableFuncPtrElement _add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr); + static void _remove_func_ptr_to_update(const UpdatableFuncPtrElement &p_func_ptr_element); static void _fixup_thread_function_bookkeeping(); @@ -561,6 +563,7 @@ public: /* MULTITHREAD FUNCTIONS */ + virtual void thread_enter() override; virtual void thread_exit() override; /* DEBUGGER FUNCTIONS */ diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp index 339d1ac08e..547f5607d3 100644 --- a/modules/gdscript/gdscript_lambda_callable.cpp +++ b/modules/gdscript/gdscript_lambda_callable.cpp @@ -296,7 +296,5 @@ GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Object *p_self, GDScriptF } GDScriptLambdaSelfCallable::~GDScriptLambdaSelfCallable() { - if (updatable_func_ptr_element) { - GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element); - } + GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element); } diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h index 405d7c1823..ee7d547544 100644 --- a/modules/gdscript/gdscript_lambda_callable.h +++ b/modules/gdscript/gdscript_lambda_callable.h @@ -45,7 +45,7 @@ class GDScriptLambdaCallable : public CallableCustom { GDScriptFunction *function = nullptr; Ref<GDScript> script; uint32_t h; - List<GDScript::UpdatableFuncPtrElement>::Element *updatable_func_ptr_element = nullptr; + GDScript::UpdatableFuncPtrElement updatable_func_ptr_element; Vector<Variant> captures; @@ -72,7 +72,7 @@ class GDScriptLambdaSelfCallable : public CallableCustom { Ref<RefCounted> reference; // For objects that are RefCounted, keep a reference. Object *object = nullptr; // For non RefCounted objects, use a direct pointer. uint32_t h; - List<GDScript::UpdatableFuncPtrElement>::Element *updatable_func_ptr_element = nullptr; + GDScript::UpdatableFuncPtrElement updatable_func_ptr_element; Vector<Variant> captures; diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index e23fc56a23..522fc2db32 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -2138,3 +2138,73 @@ AnimationMixer::AnimationMixer() { AnimationMixer::~AnimationMixer() { } + +void AnimatedValuesBackup::set_data(const HashMap<NodePath, AnimationMixer::TrackCache *> p_data) { + clear_data(); + + for (const KeyValue<NodePath, AnimationMixer::TrackCache *> &E : p_data) { + data.insert(E.key, get_cache_copy(E.value)); + } +} + +HashMap<NodePath, AnimationMixer::TrackCache *> AnimatedValuesBackup::get_data() const { + HashMap<NodePath, AnimationMixer::TrackCache *> ret; + for (const KeyValue<NodePath, AnimationMixer::TrackCache *> &E : data) { + ret.insert(E.key, get_cache_copy(E.value)); + } + return ret; +} + +void AnimatedValuesBackup::clear_data() { + for (KeyValue<NodePath, AnimationMixer::TrackCache *> &K : data) { + memdelete(K.value); + } + data.clear(); +} + +AnimationMixer::TrackCache *AnimatedValuesBackup::get_cache_copy(AnimationMixer::TrackCache *p_cache) const { + switch (p_cache->type) { + case Animation::TYPE_VALUE: { + AnimationMixer::TrackCacheValue *src = static_cast<AnimationMixer::TrackCacheValue *>(p_cache); + AnimationMixer::TrackCacheValue *tc = memnew(AnimationMixer::TrackCacheValue); + memcpy((void *)tc, (void *)src, sizeof(AnimationMixer::TrackCacheValue)); + return tc; + } + + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: { + AnimationMixer::TrackCacheTransform *src = static_cast<AnimationMixer::TrackCacheTransform *>(p_cache); + AnimationMixer::TrackCacheTransform *tc = memnew(AnimationMixer::TrackCacheTransform); + memcpy((void *)tc, (void *)src, sizeof(AnimationMixer::TrackCacheTransform)); + return tc; + } + + case Animation::TYPE_BLEND_SHAPE: { + AnimationMixer::TrackCacheBlendShape *src = static_cast<AnimationMixer::TrackCacheBlendShape *>(p_cache); + AnimationMixer::TrackCacheBlendShape *tc = memnew(AnimationMixer::TrackCacheBlendShape); + memcpy((void *)tc, (void *)src, sizeof(AnimationMixer::TrackCacheBlendShape)); + return tc; + } + + case Animation::TYPE_BEZIER: { + AnimationMixer::TrackCacheBezier *src = static_cast<AnimationMixer::TrackCacheBezier *>(p_cache); + AnimationMixer::TrackCacheBezier *tc = memnew(AnimationMixer::TrackCacheBezier); + memcpy((void *)tc, (void *)src, sizeof(AnimationMixer::TrackCacheBezier)); + return tc; + } + + case Animation::TYPE_AUDIO: { + AnimationMixer::TrackCacheAudio *src = static_cast<AnimationMixer::TrackCacheAudio *>(p_cache); + AnimationMixer::TrackCacheAudio *tc = memnew(AnimationMixer::TrackCacheAudio); + memcpy((void *)tc, (void *)src, sizeof(AnimationMixer::TrackCacheAudio)); + return tc; + } + + case Animation::TYPE_METHOD: + case Animation::TYPE_ANIMATION: { + // Nothing to do here. + } break; + } + return nullptr; +} diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h index 247462b8ad..9dc48e7b1c 100644 --- a/scene/animation/animation_mixer.h +++ b/scene/animation/animation_mixer.h @@ -388,14 +388,13 @@ class AnimatedValuesBackup : public RefCounted { HashMap<NodePath, AnimationMixer::TrackCache *> data; public: - void set_data(const HashMap<NodePath, AnimationMixer::TrackCache *> p_data) { data = p_data; }; - HashMap<NodePath, AnimationMixer::TrackCache *> get_data() const { return data; }; + void set_data(const HashMap<NodePath, AnimationMixer::TrackCache *> p_data); + HashMap<NodePath, AnimationMixer::TrackCache *> get_data() const; + void clear_data(); - ~AnimatedValuesBackup() { - for (KeyValue<NodePath, AnimationMixer::TrackCache *> &K : data) { - memdelete(K.value); - } - } + AnimationMixer::TrackCache *get_cache_copy(AnimationMixer::TrackCache *p_cache) const; + + ~AnimatedValuesBackup() { clear_data(); } }; VARIANT_ENUM_CAST(AnimationMixer::AnimationCallbackModeProcess); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 43bdb1395b..e9ea09a3b1 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -3207,7 +3207,9 @@ void Viewport::_update_mouse_over(Vector2 p_pos) { } // Send Mouse Enter Self notification. - gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_ENTER_SELF); + if (gui.mouse_over) { + gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_ENTER_SELF); + } notify_embedded_viewports = true; } |