summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/object/callable_method_pointer.h24
-rw-r--r--core/templates/list.h39
-rw-r--r--editor/surface_upgrade_tool.cpp10
-rw-r--r--modules/gdscript/gdscript.cpp149
-rw-r--r--modules/gdscript/gdscript.h19
-rw-r--r--modules/gdscript/gdscript_lambda_callable.cpp4
-rw-r--r--modules/gdscript/gdscript_lambda_callable.h4
-rw-r--r--scene/animation/animation_mixer.cpp70
-rw-r--r--scene/animation/animation_mixer.h13
-rw-r--r--scene/main/viewport.cpp4
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;
}