diff options
101 files changed, 1704 insertions, 401 deletions
diff --git a/core/io/image_loader.h b/core/io/image_loader.h index 7a58d46f93..15ee5e9ae1 100644 --- a/core/io/image_loader.h +++ b/core/io/image_loader.h @@ -88,6 +88,7 @@ public: }; class ResourceFormatLoaderImage : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderImage, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index 513252055f..e449ff216b 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -100,6 +100,7 @@ public: }; class ResourceFormatLoaderBinary : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderBinary, ResourceFormatLoader) public: virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; @@ -152,7 +153,7 @@ public: }; class ResourceFormatSaverBinary : public ResourceFormatSaver { - + GDCLASS(ResourceFormatSaverBinary, ResourceFormatSaver) public: static ResourceFormatSaverBinary *singleton; virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); diff --git a/core/io/resource_import.h b/core/io/resource_import.h index 53718bd789..ec66a422a3 100644 --- a/core/io/resource_import.h +++ b/core/io/resource_import.h @@ -37,6 +37,8 @@ class ResourceImporter; class ResourceFormatImporter : public ResourceFormatLoader { + GDCLASS(ResourceFormatImporter, ResourceFormatLoader) + struct PathAndType { String path; String type; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 71b01aa94a..41f3b2935c 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -39,7 +39,7 @@ #include "core/translation.h" #include "core/variant_parser.h" -ResourceFormatLoader *ResourceLoader::loader[MAX_LOADERS]; +Ref<ResourceFormatLoader> ResourceLoader::loader[ResourceLoader::MAX_LOADERS]; int ResourceLoader::loader_count = 0; @@ -73,6 +73,25 @@ bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_ return false; } +bool ResourceFormatLoader::handles_type(const String &p_type) const { + + if (get_script_instance() && get_script_instance()->has_method("handles_type")) { + // I guess custom loaders for custom resources should use "Resource" + return get_script_instance()->call("handles_type", p_type); + } + + return false; +} + +String ResourceFormatLoader::get_resource_type(const String &p_path) const { + + if (get_script_instance() && get_script_instance()->has_method("get_resource_type")) { + return get_script_instance()->call("get_resource_type", p_path); + } + + return ""; +} + void ResourceFormatLoader::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const { if (p_type == "" || handles_type(p_type)) @@ -129,9 +148,37 @@ bool ResourceFormatLoader::exists(const String &p_path) const { return FileAccess::exists(p_path); //by default just check file } +void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions) const { + + if (get_script_instance() && get_script_instance()->has_method("get_recognized_extensions")) { + PoolStringArray exts = get_script_instance()->call("get_recognized_extensions"); + + { + PoolStringArray::Read r = exts.read(); + for (int i = 0; i < exts.size(); ++i) { + p_extensions->push_back(r[i]); + } + } + } +} + RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error) { - String path = p_path; + if (get_script_instance() && get_script_instance()->has_method("load")) { + Variant res = get_script_instance()->call("load", p_path, p_original_path); + + if (res.get_type() == Variant::INT) { + + if (r_error) + *r_error = (Error)res.operator int64_t(); + + } else { + + if (r_error) + *r_error = OK; + return res; + } + } //or this must be implemented Ref<ResourceInteractiveLoader> ril = load_interactive(p_path, p_original_path, r_error); @@ -160,7 +207,47 @@ RES ResourceFormatLoader::load(const String &p_path, const String &p_original_pa void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { - //do nothing by default + if (get_script_instance() && get_script_instance()->has_method("get_dependencies")) { + PoolStringArray deps = get_script_instance()->call("get_dependencies", p_path, p_add_types); + + { + PoolStringArray::Read r = deps.read(); + for (int i = 0; i < deps.size(); ++i) { + p_dependencies->push_back(r[i]); + } + } + } +} + +Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Map<String, String> &p_map) { + + if (get_script_instance() && get_script_instance()->has_method("rename_dependencies")) { + + Dictionary deps_dict; + for (Map<String, String>::Element *E = p_map.front(); E; E = E->next()) { + deps_dict[E->key()] = E->value(); + } + + int64_t res = get_script_instance()->call("rename_dependencies", deps_dict); + return (Error)res; + } + + return OK; +} + +void ResourceFormatLoader::_bind_methods() { + + { + MethodInfo info = MethodInfo(Variant::NIL, "load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path")); + info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + ClassDB::add_virtual_method(get_class_static(), info); + } + + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::POOL_STRING_ARRAY, "get_recognized_extensions")); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles_type", PropertyInfo(Variant::STRING, "typename"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_resource_type", PropertyInfo(Variant::STRING, "path"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo("get_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "add_types"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "rename_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "renames"))); } /////////////////////////////////// @@ -348,9 +435,11 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ return Ref<ResourceInteractiveLoader>(); } -void ResourceLoader::add_resource_format_loader(ResourceFormatLoader *p_format_loader, bool p_at_front) { +void ResourceLoader::add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front) { + ERR_FAIL_COND(p_format_loader.is_null()); ERR_FAIL_COND(loader_count >= MAX_LOADERS); + if (p_at_front) { for (int i = loader_count; i > 0; i--) { loader[i] = loader[i - 1]; @@ -362,6 +451,27 @@ void ResourceLoader::add_resource_format_loader(ResourceFormatLoader *p_format_l } } +void ResourceLoader::remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader) { + + ERR_FAIL_COND(p_format_loader.is_null()); + + // Find loader + int i = 0; + for (; i < loader_count; ++i) { + if (loader[i] == p_format_loader) + break; + } + + ERR_FAIL_COND(i >= loader_count); // Not found + + // Shift next loaders up + for (; i < loader_count - 1; ++i) { + loader[i] = loader[i + 1]; + } + loader[loader_count - 1].unref(); + --loader_count; +} + int ResourceLoader::get_import_order(const String &p_path) { String path = _path_remap(p_path); @@ -645,6 +755,84 @@ void ResourceLoader::set_load_callback(ResourceLoadedCallback p_callback) { ResourceLoadedCallback ResourceLoader::_loaded_callback = NULL; +Ref<ResourceFormatLoader> ResourceLoader::_find_custom_resource_format_loader(String path) { + for (int i = 0; i < loader_count; ++i) { + if (loader[i]->get_script_instance() && loader[i]->get_script_instance()->get_script()->get_path() == path) { + return loader[i]; + } + } + return Ref<ResourceFormatLoader>(); +} + +bool ResourceLoader::add_custom_resource_format_loader(String script_path) { + + if (_find_custom_resource_format_loader(script_path).is_valid()) + return false; + + Ref<Resource> res = ResourceLoader::load(script_path); + ERR_FAIL_COND_V(res.is_null(), false); + ERR_FAIL_COND_V(!res->is_class("Script"), false); + + Ref<Script> s = res; + StringName ibt = s->get_instance_base_type(); + bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatLoader"); + ERR_EXPLAIN("Script does not inherit a CustomResourceLoader: " + script_path); + ERR_FAIL_COND_V(!valid_type, false); + + Object *obj = ClassDB::instance(ibt); + + ERR_EXPLAIN("Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt)); + ERR_FAIL_COND_V(obj == NULL, false); + + ResourceFormatLoader *crl = NULL; + crl = Object::cast_to<ResourceFormatLoader>(obj); + crl->set_script(s.get_ref_ptr()); + ResourceLoader::add_resource_format_loader(crl); + + return true; +} + +void ResourceLoader::remove_custom_resource_format_loader(String script_path) { + + Ref<ResourceFormatLoader> loader = _find_custom_resource_format_loader(script_path); + if (loader.is_valid()) + remove_resource_format_loader(loader); +} + +void ResourceLoader::add_custom_loaders() { + // Custom loaders registration exploits global class names + + String custom_loader_base_class = ResourceFormatLoader::get_class_static(); + + List<StringName> global_classes; + ScriptServer::get_global_class_list(&global_classes); + + for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) { + + StringName class_name = E->get(); + StringName base_class = ScriptServer::get_global_class_base(class_name); + + if (base_class == custom_loader_base_class) { + String path = ScriptServer::get_global_class_path(class_name); + add_custom_resource_format_loader(path); + } + } +} + +void ResourceLoader::remove_custom_loaders() { + + Vector<Ref<ResourceFormatLoader> > custom_loaders; + for (int i = 0; i < loader_count; ++i) { + if (loader[i]->get_script_instance()) { + custom_loaders.push_back(loader[i]); + } + } + + for (int i = 0; i < custom_loaders.size(); ++i) { + remove_resource_format_loader(custom_loaders[i]); + } +} + ResourceLoadErrorNotify ResourceLoader::err_notify = NULL; void *ResourceLoader::err_notify_ud = NULL; diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index a46a00203f..c411b3c398 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -56,18 +56,24 @@ public: ResourceInteractiveLoader() {} }; -class ResourceFormatLoader { +class ResourceFormatLoader : public Reference { + + GDCLASS(ResourceFormatLoader, Reference) + +protected: + static void _bind_methods(); + public: virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual bool exists(const String &p_path) const; - virtual void get_recognized_extensions(List<String> *p_extensions) const = 0; + virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const; - virtual bool handles_type(const String &p_type) const = 0; - virtual String get_resource_type(const String &p_path) const = 0; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); - virtual Error rename_dependencies(const String &p_path, const Map<String, String> &p_map) { return OK; } + virtual Error rename_dependencies(const String &p_path, const Map<String, String> &p_map); virtual bool is_import_valid(const String &p_path) const { return true; } virtual int get_import_order(const String &p_path) const { return 0; } @@ -86,7 +92,7 @@ class ResourceLoader { MAX_LOADERS = 64 }; - static ResourceFormatLoader *loader[MAX_LOADERS]; + static Ref<ResourceFormatLoader> loader[MAX_LOADERS]; static int loader_count; static bool timestamp_on_load; @@ -109,13 +115,16 @@ class ResourceLoader { static ResourceLoadedCallback _loaded_callback; + static Ref<ResourceFormatLoader> _find_custom_resource_format_loader(String path); + public: static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL); static RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL); static bool exists(const String &p_path, const String &p_type_hint = ""); static void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions); - static void add_resource_format_loader(ResourceFormatLoader *p_format_loader, bool p_at_front = false); + static void add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front = false); + static void remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader); static String get_resource_type(const String &p_path); static void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); static Error rename_dependencies(const String &p_path, const Map<String, String> &p_map); @@ -156,6 +165,11 @@ public: static void set_load_callback(ResourceLoadedCallback p_callback); static ResourceLoaderImport import; + + static bool add_custom_resource_format_loader(String script_path); + static void remove_custom_resource_format_loader(String script_path); + static void add_custom_loaders(); + static void remove_custom_loaders(); }; #endif diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 097e81e308..af726d9e2d 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -29,18 +29,62 @@ /*************************************************************************/ #include "resource_saver.h" - #include "core/io/resource_loader.h" #include "core/os/file_access.h" #include "core/project_settings.h" #include "core/script_language.h" -ResourceFormatSaver *ResourceSaver::saver[MAX_SAVERS]; +Ref<ResourceFormatSaver> ResourceSaver::saver[MAX_SAVERS]; int ResourceSaver::saver_count = 0; bool ResourceSaver::timestamp_on_save = false; ResourceSavedCallback ResourceSaver::save_callback = 0; +Error ResourceFormatSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { + + if (get_script_instance() && get_script_instance()->has_method("save")) { + return (Error)get_script_instance()->call("save", p_path, p_resource, p_flags).operator int64_t(); + } + + return ERR_METHOD_NOT_FOUND; +} + +bool ResourceFormatSaver::recognize(const RES &p_resource) const { + + if (get_script_instance() && get_script_instance()->has_method("recognize")) { + return get_script_instance()->call("recognize", p_resource); + } + + return false; +} + +void ResourceFormatSaver::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { + + if (get_script_instance() && get_script_instance()->has_method("get_recognized_extensions")) { + PoolStringArray exts = get_script_instance()->call("get_recognized_extensions", p_resource); + + { + PoolStringArray::Read r = exts.read(); + for (int i = 0; i < exts.size(); ++i) { + p_extensions->push_back(r[i]); + } + } + } +} + +void ResourceFormatSaver::_bind_methods() { + + { + PropertyInfo arg0 = PropertyInfo(Variant::STRING, "path"); + PropertyInfo arg1 = PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"); + PropertyInfo arg2 = PropertyInfo(Variant::INT, "flags"); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "save", arg0, arg1, arg2)); + } + + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::POOL_STRING_ARRAY, "get_recognized_extensions", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "recognize", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); +} + Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { String extension = p_path.get_extension(); @@ -113,8 +157,9 @@ void ResourceSaver::get_recognized_extensions(const RES &p_resource, List<String } } -void ResourceSaver::add_resource_format_saver(ResourceFormatSaver *p_format_saver, bool p_at_front) { +void ResourceSaver::add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front) { + ERR_FAIL_COND(p_format_saver.is_null()); ERR_FAIL_COND(saver_count >= MAX_SAVERS); if (p_at_front) { @@ -127,3 +172,102 @@ void ResourceSaver::add_resource_format_saver(ResourceFormatSaver *p_format_save saver[saver_count++] = p_format_saver; } } + +void ResourceSaver::remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver) { + + ERR_FAIL_COND(p_format_saver.is_null()); + + // Find saver + int i = 0; + for (; i < saver_count; ++i) { + if (saver[i] == p_format_saver) + break; + } + + ERR_FAIL_COND(i >= saver_count); // Not found + + // Shift next savers up + for (; i < saver_count - 1; ++i) { + saver[i] = saver[i + 1]; + } + saver[saver_count - 1].unref(); + --saver_count; +} + +Ref<ResourceFormatSaver> ResourceSaver::_find_custom_resource_format_saver(String path) { + for (int i = 0; i < saver_count; ++i) { + if (saver[i]->get_script_instance() && saver[i]->get_script_instance()->get_script()->get_path() == path) { + return saver[i]; + } + } + return Ref<ResourceFormatSaver>(); +} + +bool ResourceSaver::add_custom_resource_format_saver(String script_path) { + + if (_find_custom_resource_format_saver(script_path).is_valid()) + return false; + + Ref<Resource> res = ResourceLoader::load(script_path); + ERR_FAIL_COND_V(res.is_null(), false); + ERR_FAIL_COND_V(!res->is_class("Script"), false); + + Ref<Script> s = res; + StringName ibt = s->get_instance_base_type(); + bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatSaver"); + ERR_EXPLAIN("Script does not inherit a CustomResourceSaver: " + script_path); + ERR_FAIL_COND_V(!valid_type, false); + + Object *obj = ClassDB::instance(ibt); + + ERR_EXPLAIN("Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt)); + ERR_FAIL_COND_V(obj == NULL, false); + + ResourceFormatSaver *crl = NULL; + crl = Object::cast_to<ResourceFormatSaver>(obj); + crl->set_script(s.get_ref_ptr()); + ResourceSaver::add_resource_format_saver(crl); + + return true; +} + +void ResourceSaver::remove_custom_resource_format_saver(String script_path) { + + Ref<ResourceFormatSaver> saver = _find_custom_resource_format_saver(script_path); + if (saver.is_valid()) + remove_resource_format_saver(saver); +} + +void ResourceSaver::add_custom_savers() { + // Custom resource savers exploits global class names + + String custom_saver_base_class = ResourceFormatSaver::get_class_static(); + + List<StringName> global_classes; + ScriptServer::get_global_class_list(&global_classes); + + for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) { + + StringName class_name = E->get(); + StringName base_class = ScriptServer::get_global_class_base(class_name); + + if (base_class == custom_saver_base_class) { + String path = ScriptServer::get_global_class_path(class_name); + add_custom_resource_format_saver(path); + } + } +} + +void ResourceSaver::remove_custom_savers() { + + Vector<Ref<ResourceFormatSaver> > custom_savers; + for (int i = 0; i < saver_count; ++i) { + if (saver[i]->get_script_instance()) { + custom_savers.push_back(saver[i]); + } + } + + for (int i = 0; i < custom_savers.size(); ++i) { + remove_resource_format_saver(custom_savers[i]); + } +} diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h index cdd43292a2..1a250e84ea 100644 --- a/core/io/resource_saver.h +++ b/core/io/resource_saver.h @@ -37,11 +37,16 @@ @author Juan Linietsky <reduzio@gmail.com> */ -class ResourceFormatSaver { +class ResourceFormatSaver : public Reference { + GDCLASS(ResourceFormatSaver, Reference) + +protected: + static void _bind_methods(); + public: - virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0) = 0; - virtual bool recognize(const RES &p_resource) const = 0; - virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const = 0; + virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); + virtual bool recognize(const RES &p_resource) const; + virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; virtual ~ResourceFormatSaver() {} }; @@ -54,11 +59,13 @@ class ResourceSaver { MAX_SAVERS = 64 }; - static ResourceFormatSaver *saver[MAX_SAVERS]; + static Ref<ResourceFormatSaver> saver[MAX_SAVERS]; static int saver_count; static bool timestamp_on_save; static ResourceSavedCallback save_callback; + static Ref<ResourceFormatSaver> _find_custom_resource_format_saver(String path); + public: enum SaverFlags { @@ -73,12 +80,18 @@ public: static Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); static void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions); - static void add_resource_format_saver(ResourceFormatSaver *p_format_saver, bool p_at_front = false); + static void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front = false); + static void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver); static void set_timestamp_on_save(bool p_timestamp) { timestamp_on_save = p_timestamp; } static bool get_timestamp_on_save() { return timestamp_on_save; } static void set_save_callback(ResourceSavedCallback p_callback); + + static bool add_custom_resource_format_saver(String script_path); + static void remove_custom_resource_format_saver(String script_path); + static void add_custom_savers(); + static void remove_custom_savers(); }; #endif diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h index 670a9fdd7e..9543307cb5 100644 --- a/core/io/translation_loader_po.h +++ b/core/io/translation_loader_po.h @@ -36,6 +36,7 @@ #include "core/translation.h" class TranslationLoaderPO : public ResourceFormatLoader { + GDCLASS(TranslationLoaderPO, ResourceFormatLoader) public: static RES load_translation(FileAccess *f, Error *r_error, const String &p_path = String()); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 6b776cb0b1..61fd3043a5 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -65,11 +65,11 @@ #include "core/translation.h" #include "core/undo_redo.h" -static ResourceFormatSaverBinary *resource_saver_binary = NULL; -static ResourceFormatLoaderBinary *resource_loader_binary = NULL; -static ResourceFormatImporter *resource_format_importer = NULL; +static Ref<ResourceFormatSaverBinary> resource_saver_binary; +static Ref<ResourceFormatLoaderBinary> resource_loader_binary; +static Ref<ResourceFormatImporter> resource_format_importer; -static ResourceFormatLoaderImage *resource_format_image = NULL; +static Ref<ResourceFormatLoaderImage> resource_format_image; static _ResourceLoader *_resource_loader = NULL; static _ResourceSaver *_resource_saver = NULL; @@ -77,7 +77,7 @@ static _OS *_os = NULL; static _Engine *_engine = NULL; static _ClassDB *_classdb = NULL; static _Marshalls *_marshalls = NULL; -static TranslationLoaderPO *resource_format_po = NULL; +static Ref<TranslationLoaderPO> resource_format_po; static _JSON *_json = NULL; static IP *ip = NULL; @@ -106,18 +106,18 @@ void register_core_types() { CoreStringNames::create(); - resource_format_po = memnew(TranslationLoaderPO); + resource_format_po.instance(); ResourceLoader::add_resource_format_loader(resource_format_po); - resource_saver_binary = memnew(ResourceFormatSaverBinary); + resource_saver_binary.instance(); ResourceSaver::add_resource_format_saver(resource_saver_binary); - resource_loader_binary = memnew(ResourceFormatLoaderBinary); + resource_loader_binary.instance(); ResourceLoader::add_resource_format_loader(resource_loader_binary); - resource_format_importer = memnew(ResourceFormatImporter); + resource_format_importer.instance(); ResourceLoader::add_resource_format_loader(resource_format_importer); - resource_format_image = memnew(ResourceFormatLoaderImage); + resource_format_image.instance(); ResourceLoader::add_resource_format_loader(resource_format_image); ClassDB::register_class<Object>(); @@ -165,6 +165,9 @@ void register_core_types() { ClassDB::register_virtual_class<ResourceInteractiveLoader>(); + ClassDB::register_class<ResourceFormatLoader>(); + ClassDB::register_class<ResourceFormatSaver>(); + ClassDB::register_class<_File>(); ClassDB::register_class<_Directory>(); ClassDB::register_class<_Thread>(); @@ -248,16 +251,28 @@ void unregister_core_types() { memdelete(_geometry); - if (resource_format_image) - memdelete(resource_format_image); - if (resource_saver_binary) - memdelete(resource_saver_binary); - if (resource_loader_binary) - memdelete(resource_loader_binary); - if (resource_format_importer) - memdelete(resource_format_importer); + if (resource_format_image.is_valid()) { + ResourceLoader::remove_resource_format_loader(resource_format_image); + resource_format_image.unref(); + } + + if (resource_saver_binary.is_valid()) { + ResourceSaver::remove_resource_format_saver(resource_saver_binary); + resource_saver_binary.unref(); + } + + if (resource_loader_binary.is_valid()) { + ResourceLoader::remove_resource_format_loader(resource_loader_binary); + resource_loader_binary.unref(); + } + + if (resource_format_importer.is_valid()) { + ResourceLoader::remove_resource_format_loader(resource_format_importer); + resource_format_importer.unref(); + } - memdelete(resource_format_po); + ResourceLoader::remove_resource_format_loader(resource_format_po); + resource_format_po.unref(); if (ip) memdelete(ip); diff --git a/core/vector.h b/core/vector.h index 38a1082407..2fb6f6c1c4 100644 --- a/core/vector.h +++ b/core/vector.h @@ -44,17 +44,11 @@ template <class T> class VectorWriteProxy { - friend class Vector<T>; - CowData<T> *_parent; - - _FORCE_INLINE_ VectorWriteProxy(CowData<T> *parent) : - _parent(parent){}; - public: _FORCE_INLINE_ T &operator[](int p_index) { - CRASH_BAD_INDEX(p_index, _parent->size()); + CRASH_BAD_INDEX(p_index, ((Vector<T> *)(this))->_cowdata.size()); - return _parent->ptrw()[p_index]; + return ((Vector<T> *)(this))->_cowdata.ptrw()[p_index]; } }; @@ -62,39 +56,41 @@ template <class T> class Vector { friend class VectorWriteProxy<T>; - CowData<T> *_cowdata; - public: VectorWriteProxy<T> write; +private: + CowData<T> _cowdata; + +public: bool push_back(const T &p_elem); - void remove(int p_index) { _cowdata->remove(p_index); } + void remove(int p_index) { _cowdata.remove(p_index); } void erase(const T &p_val) { int idx = find(p_val); if (idx >= 0) remove(idx); }; void invert(); - _FORCE_INLINE_ T *ptrw() { return _cowdata->ptrw(); } - _FORCE_INLINE_ const T *ptr() const { return _cowdata->ptr(); } + _FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); } + _FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); } _FORCE_INLINE_ void clear() { resize(0); } - _FORCE_INLINE_ bool empty() const { return _cowdata->empty(); } + _FORCE_INLINE_ bool empty() const { return _cowdata.empty(); } - _FORCE_INLINE_ T get(int p_index) { return _cowdata->get(p_index); } - _FORCE_INLINE_ const T get(int p_index) const { return _cowdata->get(p_index); } - _FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata->set(p_index, p_elem); } - _FORCE_INLINE_ int size() const { return _cowdata->size(); } - Error resize(int p_size) { return _cowdata->resize(p_size); } - _FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata->get(p_index); } - Error insert(int p_pos, const T &p_val) { return _cowdata->insert(p_pos, p_val); } + _FORCE_INLINE_ T get(int p_index) { return _cowdata.get(p_index); } + _FORCE_INLINE_ const T get(int p_index) const { return _cowdata.get(p_index); } + _FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); } + _FORCE_INLINE_ int size() const { return _cowdata.size(); } + Error resize(int p_size) { return _cowdata.resize(p_size); } + _FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata.get(p_index); } + Error insert(int p_pos, const T &p_val) { return _cowdata.insert(p_pos, p_val); } void append_array(const Vector<T> &p_other); template <class C> void sort_custom() { - int len = _cowdata->size(); + int len = _cowdata.size(); if (len == 0) return; @@ -110,7 +106,7 @@ public: void ordered_insert(const T &p_val) { int i; - for (i = 0; i < _cowdata->size(); i++) { + for (i = 0; i < _cowdata.size(); i++) { if (p_val < operator[](i)) { break; @@ -135,20 +131,14 @@ public: return ret; } - _FORCE_INLINE_ Vector() : - _cowdata(new CowData<T>()), - write(VectorWriteProxy<T>(_cowdata)) {} - _FORCE_INLINE_ Vector(const Vector &p_from) : - _cowdata(new CowData<T>()), - write(VectorWriteProxy<T>(_cowdata)) { _cowdata->_ref(p_from._cowdata); } + _FORCE_INLINE_ Vector() {} + _FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); } inline Vector &operator=(const Vector &p_from) { - _cowdata->_ref(p_from._cowdata); + _cowdata._ref(p_from._cowdata); return *this; } - _FORCE_INLINE_ ~Vector() { - delete _cowdata; - } + _FORCE_INLINE_ ~Vector() {} }; template <class T> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 92d5415ed6..1d2057eb4e 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -172,8 +172,8 @@ Path to an image used for boot splash. </member> <member name="application/config/custom_user_dir_name" type="String" setter="" getter=""> - This directory is used for storing persistent data (user:// filesystem). If a custom name is set, then system paths will be used to store this on Desktop (AppData on Windows, user ~/.config on Unixes, etc), else the Godot config folder is used. This name needs to be unique, and it's recommended to set it to something before publishing. - the "use_custom_user_dir" setting must be enabled for this to take effect. + This user directory is used for storing persistent data ([code]user://[/code] filesystem). By default (no custom name defined), [code]user://[/code] resolves to a project-specific folder in Godot's own configuration folder (see [method OS.get_user_data_dir]). If a custom directory name is defined, this name will be used instead and appended to the system-specific user data directory (same parent folder as the Godot configuration folder documented in [method OS.get_user_data_dir]). + The [member use_custom_user_dir] setting must be enabled for this to take effect. </member> <member name="application/config/icon" type="String" setter="" getter=""> Icon used for the project, set when project loads. Exporters will use this icon when possible to. @@ -181,11 +181,11 @@ <member name="application/config/name" type="String" setter="" getter=""> Name of the project. It is used from both project manager and by the exporters. Overriding this as name.locale allows setting it in multiple languages. </member> - <member name="application/config/use_custom_user_dir" type="bool" setter="" getter=""> - Allow the project to save to its own custom user dir (in AppData on windows or ~/.config on unixes). This setting only works for desktop exporters. A name must be set in the "custom_user_dir_name" setting for this to take effect. - </member> <member name="application/config/project_settings_override" type="String" setter="" getter=""> - Specifies a file to override project settings. For example: user://custom_settings.cfg. + Specifies a file to override project settings. For example: [code]user://custom_settings.cfg[/code]. + </member> + <member name="application/config/use_custom_user_dir" type="bool" setter="" getter=""> + Allow the project to save to its own custom user dir (see [member custom_user_dir_name]). This setting only works for desktop platforms. A name must be set in the [member custom_user_dir_name] setting for this to take effect. </member> <member name="application/run/disable_stderr" type="bool" setter="" getter=""> Disable printing to stderr on exported build. @@ -583,10 +583,10 @@ Log all output to a file. </member> <member name="logging/file_logging/log_path" type="String" setter="" getter=""> - Path to logs withint he project. Using an user:// based path is recommended. + Path to logs withint he project. Using an [code]user://[/code] based path is recommended. </member> <member name="logging/file_logging/max_log_files" type="int" setter="" getter=""> - Amount of log files (used for rotation)/ + Amount of log files (used for rotation). </member> <member name="memory/limits/message_queue/max_size_kb" type="int" setter="" getter=""> Godot uses a message queue to defer some function calls. If you run out of space on it (you will see an error), you can increase the size here. diff --git a/doc/classes/ResourceFormatDDS.xml b/doc/classes/ResourceFormatDDS.xml new file mode 100644 index 0000000000..e237dfc6a5 --- /dev/null +++ b/doc/classes/ResourceFormatDDS.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatDDS" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatImporter.xml b/doc/classes/ResourceFormatImporter.xml new file mode 100644 index 0000000000..fa5b44fa18 --- /dev/null +++ b/doc/classes/ResourceFormatImporter.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatImporter" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatLoader.xml b/doc/classes/ResourceFormatLoader.xml new file mode 100644 index 0000000000..f03f0bbf54 --- /dev/null +++ b/doc/classes/ResourceFormatLoader.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatLoader" inherits="Reference" category="Core" version="3.1"> + <brief_description> + Loads a specific resource type from a file. + </brief_description> + <description> + Godot loads resources in the editor or in exported games using ResourceFormatLoaders. They get queried when you call `load`, or when a resource with internal dependencies is loaded. Each file type may load as a different resource type, so multiple ResourceFormatLoader are registered in the engine. + Extending this class allows you to define your own. You should give it a global class name with `class_name` for it to be registered. You may as well implement a [ResourceFormatSaver]. + Note: you can also extend [EditorImportPlugin] if the resource type you need exists but Godot is unable to load its format. Choosing one way over another depends if the format is suitable or not for the final exported game. Example: it's better to import .PNG textures as .STEX first, so they can be loaded with better efficiency on the graphics card. + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="get_dependencies" qualifiers="virtual"> + <return type="void"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <argument index="1" name="add_types" type="String"> + </argument> + <description> + If implemented, gets the dependencies of a given resource. If add_types is true, paths should be appended "::TypeName", where `TypeName` is the class name of the dependency. Note that custom resource types defined by scripts aren't known by the [ClassDB], so you might just return "Resource" for them. + </description> + </method> + <method name="get_recognized_extensions" qualifiers="virtual"> + <return type="PoolStringArray"> + </return> + <description> + Gets the list of extensions for files this loader is able to read. + </description> + </method> + <method name="get_resource_type" qualifiers="virtual"> + <return type="String"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <description> + Gets the class name of the resource associated with the given path. If the loader cannot handle it, it should return "". Note that custom resource types defined by scripts aren't known by the [ClassDB], so you might just return "Resource" for them. + </description> + </method> + <method name="handles_type" qualifiers="virtual"> + <return type="bool"> + </return> + <argument index="0" name="typename" type="String"> + </argument> + <description> + Tells which resource class this loader can load. Note that custom resource types defined by scripts aren't known by the [ClassDB], so you might just return "Resource" for them. + </description> + </method> + <method name="load" qualifiers="virtual"> + <return type="Variant"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <argument index="1" name="original_path" type="String"> + </argument> + <description> + Loads a resource when the engine finds this loader to be compatible. original_path: If the loaded resource is the result of an import, original_path will target the source file. Returns a resource object if succeeded, or an ERR_* constant listed in [@GlobalScope] if it failed. + </description> + </method> + <method name="rename_dependencies" qualifiers="virtual"> + <return type="int"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <argument index="1" name="renames" type="String"> + </argument> + <description> + If implemented, renames dependencies within the given resource and saves it. renames is a dictionary { String => String } mapping old dependency paths to new paths. Returns OK on success, or an ERR_* constant listed in [@GlobalScope] in case of failure. + </description> + </method> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatLoaderBMFont.xml b/doc/classes/ResourceFormatLoaderBMFont.xml new file mode 100644 index 0000000000..1e999353f8 --- /dev/null +++ b/doc/classes/ResourceFormatLoaderBMFont.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatLoaderBMFont" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatLoaderBinary.xml b/doc/classes/ResourceFormatLoaderBinary.xml new file mode 100644 index 0000000000..3c768851e2 --- /dev/null +++ b/doc/classes/ResourceFormatLoaderBinary.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatLoaderBinary" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatLoaderDynamicFont.xml b/doc/classes/ResourceFormatLoaderDynamicFont.xml new file mode 100644 index 0000000000..4cd5c9b2a6 --- /dev/null +++ b/doc/classes/ResourceFormatLoaderDynamicFont.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatLoaderDynamicFont" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatLoaderGDScript.xml b/doc/classes/ResourceFormatLoaderGDScript.xml new file mode 100644 index 0000000000..b661e4746a --- /dev/null +++ b/doc/classes/ResourceFormatLoaderGDScript.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatLoaderGDScript" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatLoaderImage.xml b/doc/classes/ResourceFormatLoaderImage.xml new file mode 100644 index 0000000000..5f7e55af28 --- /dev/null +++ b/doc/classes/ResourceFormatLoaderImage.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatLoaderImage" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatLoaderNativeScript.xml b/doc/classes/ResourceFormatLoaderNativeScript.xml new file mode 100644 index 0000000000..496602e7dd --- /dev/null +++ b/doc/classes/ResourceFormatLoaderNativeScript.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatLoaderNativeScript" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatLoaderShader.xml b/doc/classes/ResourceFormatLoaderShader.xml new file mode 100644 index 0000000000..0948810532 --- /dev/null +++ b/doc/classes/ResourceFormatLoaderShader.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatLoaderShader" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatLoaderStreamTexture.xml b/doc/classes/ResourceFormatLoaderStreamTexture.xml new file mode 100644 index 0000000000..34843f9e1a --- /dev/null +++ b/doc/classes/ResourceFormatLoaderStreamTexture.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatLoaderStreamTexture" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatLoaderText.xml b/doc/classes/ResourceFormatLoaderText.xml new file mode 100644 index 0000000000..db3b28f233 --- /dev/null +++ b/doc/classes/ResourceFormatLoaderText.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatLoaderText" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatLoaderTextureLayered.xml b/doc/classes/ResourceFormatLoaderTextureLayered.xml new file mode 100644 index 0000000000..cd31f35e49 --- /dev/null +++ b/doc/classes/ResourceFormatLoaderTextureLayered.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatLoaderTextureLayered" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatLoaderTheora.xml b/doc/classes/ResourceFormatLoaderTheora.xml new file mode 100644 index 0000000000..dff7e2f3dc --- /dev/null +++ b/doc/classes/ResourceFormatLoaderTheora.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatLoaderTheora" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatLoaderWebm.xml b/doc/classes/ResourceFormatLoaderWebm.xml new file mode 100644 index 0000000000..f2b403161e --- /dev/null +++ b/doc/classes/ResourceFormatLoaderWebm.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatLoaderWebm" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatPKM.xml b/doc/classes/ResourceFormatPKM.xml new file mode 100644 index 0000000000..aa511823d3 --- /dev/null +++ b/doc/classes/ResourceFormatPKM.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatPKM" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatPVR.xml b/doc/classes/ResourceFormatPVR.xml new file mode 100644 index 0000000000..4f3b4f670f --- /dev/null +++ b/doc/classes/ResourceFormatPVR.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatPVR" inherits="ResourceFormatLoader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatSaver.xml b/doc/classes/ResourceFormatSaver.xml new file mode 100644 index 0000000000..d15d97fc84 --- /dev/null +++ b/doc/classes/ResourceFormatSaver.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatSaver" inherits="Reference" category="Core" version="3.1"> + <brief_description> + Saves a specific resource type to a file. + </brief_description> + <description> + The engine can save resources when you do it from the editor, or when you call `ResourceSaver.save(resource)`. This is accomplished with multiple `ResourceFormatSavers`, each handling its own format. + By default, Godot saves resources as `.tres`, `.res` or another built-in format, but you can choose to create your own format by extending this class. You should give it a global class name with `class_name` for it to be registered. You may as well implement a [ResourceFormatLoader]. + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="get_recognized_extensions" qualifiers="virtual"> + <return type="PoolStringArray"> + </return> + <argument index="0" name="resource" type="Resource"> + </argument> + <description> + Gets the list of extensions for files this saver is able to write. + </description> + </method> + <method name="recognize" qualifiers="virtual"> + <return type="bool"> + </return> + <argument index="0" name="resource" type="Resource"> + </argument> + <description> + Returns true if the given resource object can be saved by this saver. + </description> + </method> + <method name="save" qualifiers="virtual"> + <return type="int"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <argument index="1" name="resource" type="Resource"> + </argument> + <argument index="2" name="flags" type="int"> + </argument> + <description> + Saves the given resource object to a file. flags is a bitmask composed with FLAG_* constants defined in [ResourceSaver]. Returns OK on success, or an ERR_* constant listed in [@GlobalScope] if it failed. + </description> + </method> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatSaverBinary.xml b/doc/classes/ResourceFormatSaverBinary.xml new file mode 100644 index 0000000000..7afec9ba23 --- /dev/null +++ b/doc/classes/ResourceFormatSaverBinary.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatSaverBinary" inherits="ResourceFormatSaver" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatSaverGDScript.xml b/doc/classes/ResourceFormatSaverGDScript.xml new file mode 100644 index 0000000000..27964c7c9b --- /dev/null +++ b/doc/classes/ResourceFormatSaverGDScript.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatSaverGDScript" inherits="ResourceFormatSaver" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatSaverNativeScript.xml b/doc/classes/ResourceFormatSaverNativeScript.xml new file mode 100644 index 0000000000..9f8c0ccc78 --- /dev/null +++ b/doc/classes/ResourceFormatSaverNativeScript.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatSaverNativeScript" inherits="ResourceFormatSaver" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatSaverShader.xml b/doc/classes/ResourceFormatSaverShader.xml new file mode 100644 index 0000000000..cdc512dfea --- /dev/null +++ b/doc/classes/ResourceFormatSaverShader.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatSaverShader" inherits="ResourceFormatSaver" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceFormatSaverText.xml b/doc/classes/ResourceFormatSaverText.xml new file mode 100644 index 0000000000..6ae4ff4a2c --- /dev/null +++ b/doc/classes/ResourceFormatSaverText.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceFormatSaverText" inherits="ResourceFormatSaver" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ResourceSaverPNG.xml b/doc/classes/ResourceSaverPNG.xml new file mode 100644 index 0000000000..a161a4de5f --- /dev/null +++ b/doc/classes/ResourceSaverPNG.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ResourceSaverPNG" inherits="ResourceFormatSaver" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/drivers/dummy/texture_loader_dummy.h b/drivers/dummy/texture_loader_dummy.h index f0a355ec12..6809e76331 100644 --- a/drivers/dummy/texture_loader_dummy.h +++ b/drivers/dummy/texture_loader_dummy.h @@ -35,6 +35,7 @@ #include "scene/resources/texture.h" class ResourceFormatDummyTexture : public ResourceFormatLoader { + GDCLASS(ResourceFormatDummyTexture, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/drivers/gles2/shaders/lens_distorted.glsl b/drivers/gles2/shaders/lens_distorted.glsl index d541db9bf9..efa35adf7d 100644 --- a/drivers/gles2/shaders/lens_distorted.glsl +++ b/drivers/gles2/shaders/lens_distorted.glsl @@ -1,6 +1,14 @@ /* clang-format off */ [vertex] +#ifdef USE_GLES_OVER_GL +#define mediump +#define highp +#else +precision highp float; +precision highp int; +#endif + attribute highp vec2 vertex; // attrib:0 /* clang-format on */ @@ -20,6 +28,14 @@ void main() { /* clang-format off */ [fragment] +#ifdef USE_GLES_OVER_GL +#define mediump +#define highp +#else +precision mediump float; +precision highp int; +#endif + uniform sampler2D source; //texunit:0 /* clang-format on */ diff --git a/drivers/png/resource_saver_png.h b/drivers/png/resource_saver_png.h index 34950f6723..2d5fd0882c 100644 --- a/drivers/png/resource_saver_png.h +++ b/drivers/png/resource_saver_png.h @@ -35,6 +35,7 @@ #include "core/io/resource_saver.h" class ResourceSaverPNG : public ResourceFormatSaver { + GDCLASS(ResourceSaverPNG, ResourceFormatSaver) public: static Error save_image(const String &p_path, const Ref<Image> &p_img); diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp index 9f5d9c1abf..9a6e0f45fc 100644 --- a/drivers/register_driver_types.cpp +++ b/drivers/register_driver_types.cpp @@ -42,15 +42,15 @@ #include "platform/windows/export/export.h" #endif -static ImageLoaderPNG *image_loader_png = NULL; -static ResourceSaverPNG *resource_saver_png = NULL; +static ImageLoaderPNG *image_loader_png; +static Ref<ResourceSaverPNG> resource_saver_png; void register_core_driver_types() { image_loader_png = memnew(ImageLoaderPNG); ImageLoader::add_image_format_loader(image_loader_png); - resource_saver_png = memnew(ResourceSaverPNG); + resource_saver_png.instance(); ResourceSaver::add_resource_format_saver(resource_saver_png); } @@ -58,8 +58,11 @@ void unregister_core_driver_types() { if (image_loader_png) memdelete(image_loader_png); - if (resource_saver_png) - memdelete(resource_saver_png); + + if (resource_saver_png.is_valid()) { + ResourceSaver::remove_resource_format_saver(resource_saver_png); + resource_saver_png.unref(); + } } void register_driver_types() { diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 94eb1a3399..37e2079b64 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1401,6 +1401,14 @@ void EditorFileSystem::update_script_classes() { ScriptServer::save_global_classes(); EditorNode::get_editor_data().script_class_save_icon_paths(); + + // Rescan custom loaders and savers. + // Doing the following here because the `filesystem_changed` signal fires multiple times and isn't always followed by script classes update. + // So I thought it's better to do this when script classes really get updated + ResourceLoader::remove_custom_loaders(); + ResourceLoader::add_custom_loaders(); + ResourceSaver::remove_custom_savers(); + ResourceSaver::add_custom_savers(); } void EditorFileSystem::_queue_update_script_classes() { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index d100d7f618..1063447376 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2471,7 +2471,7 @@ void EditorNode::_editor_select(int p_which) { } } -void EditorNode::add_editor_plugin(EditorPlugin *p_editor) { +void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed) { if (p_editor->has_main_screen()) { @@ -2496,9 +2496,11 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor) { } singleton->editor_data.add_editor_plugin(p_editor); singleton->add_child(p_editor); + if (p_config_changed) + p_editor->enable_plugin(); } -void EditorNode::remove_editor_plugin(EditorPlugin *p_editor) { +void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_changed) { if (p_editor->has_main_screen()) { @@ -2521,6 +2523,8 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor) { } p_editor->make_visible(false); p_editor->clear(); + if (p_config_changed) + p_editor->disable_plugin(); singleton->editor_plugins_over->get_plugins_list().erase(p_editor); singleton->remove_child(p_editor); singleton->editor_data.remove_editor_plugin(p_editor); @@ -2546,7 +2550,7 @@ void EditorNode::_update_addon_config() { project_settings->queue_save(); } -void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled) { +void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled, bool p_config_changed) { ERR_FAIL_COND(p_enabled && plugin_addons.has(p_addon)); ERR_FAIL_COND(!p_enabled && !plugin_addons.has(p_addon)); @@ -2554,7 +2558,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled) if (!p_enabled) { EditorPlugin *addon = plugin_addons[p_addon]; - remove_editor_plugin(addon); + remove_editor_plugin(addon, p_config_changed); memdelete(addon); //bye plugin_addons.erase(p_addon); _update_addon_config(); @@ -2606,7 +2610,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled) ep->set_script(script.get_ref_ptr()); ep->set_dir_cache(p_addon); plugin_addons[p_addon] = ep; - add_editor_plugin(ep); + add_editor_plugin(ep, p_config_changed); _update_addon_config(); } diff --git a/editor/editor_node.h b/editor/editor_node.h index e5670e5e7c..f4c0375c2e 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -637,8 +637,8 @@ public: ProjectSettingsEditor *get_project_settings() { return project_settings; } - static void add_editor_plugin(EditorPlugin *p_editor); - static void remove_editor_plugin(EditorPlugin *p_editor); + static void add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed = false); + static void remove_editor_plugin(EditorPlugin *p_editor, bool p_config_changed = false); void new_inherited_scene() { _menu_option_confirm(FILE_NEW_INHERITED_SCENE, false); } @@ -651,7 +651,7 @@ public: void add_control_to_dock(DockSlot p_slot, Control *p_control); void remove_control_from_dock(Control *p_control); - void set_addon_plugin_enabled(const String &p_addon, bool p_enabled); + void set_addon_plugin_enabled(const String &p_addon, bool p_enabled, bool p_config_changed = false); bool is_addon_plugin_enabled(const String &p_addon) const; void edit_node(Node *p_node); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index cd024ff870..403db4b8ba 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -698,6 +698,34 @@ void EditorPlugin::remove_scene_import_plugin(const Ref<EditorSceneImporter> &p_ ResourceImporterScene::get_singleton()->remove_importer(p_importer); } +int find(const PoolStringArray &a, const String &v) { + PoolStringArray::Read r = a.read(); + for (int j = 0; j < a.size(); ++j) { + if (r[j] == v) { + return j; + } + } + return -1; +} + +void EditorPlugin::enable_plugin() { + // Called when the plugin gets enabled in project settings, after it's added to the tree. + // You can implement it to register autoloads. + + if (get_script_instance() && get_script_instance()->has_method("enable_plugin")) { + get_script_instance()->call("enable_plugin"); + } +} + +void EditorPlugin::disable_plugin() { + // Last function called when the plugin gets disabled in project settings. + // Implement it to cleanup things from the project, such as unregister autoloads. + + if (get_script_instance() && get_script_instance()->has_method("disable_plugin")) { + get_script_instance()->call("disable_plugin"); + } +} + void EditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) { if (get_script_instance() && get_script_instance()->has_method("set_window_layout")) { @@ -801,6 +829,8 @@ void EditorPlugin::_bind_methods() { ClassDB::add_virtual_method(get_class_static(), MethodInfo("set_window_layout", PropertyInfo(Variant::OBJECT, "layout", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo("get_window_layout", PropertyInfo(Variant::OBJECT, "layout", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "build")); + ClassDB::add_virtual_method(get_class_static(), MethodInfo("enable_plugin")); + ClassDB::add_virtual_method(get_class_static(), MethodInfo("disable_plugin")); ADD_SIGNAL(MethodInfo("scene_changed", PropertyInfo(Variant::OBJECT, "scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("scene_closed", PropertyInfo(Variant::STRING, "filepath"))); diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index e03aeb5d30..5f060a4e96 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -232,6 +232,9 @@ public: String get_dir_cache() { return _dir_cache; } Ref<ConfigFile> get_config(); + void enable_plugin(); + void disable_plugin(); + EditorPlugin(); virtual ~EditorPlugin(); }; diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index 30027c0c34..a4d543c567 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -152,7 +152,7 @@ void EditorPluginSettings::_plugin_activity_changed() { bool active = ti->get_range(3); String name = ti->get_metadata(0); - EditorNode::get_singleton()->set_addon_plugin_enabled(name, active); + EditorNode::get_singleton()->set_addon_plugin_enabled(name, active, true); bool is_active = EditorNode::get_singleton()->is_addon_plugin_enabled(name); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 039ba22a77..fbcab3cbb6 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -581,6 +581,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { /* Extra config */ + _initial_set("project_manager/sorting_order", 0); + hints["project_manager/sorting_order"] = PropertyInfo(Variant::INT, "project_manager/sorting_order", PROPERTY_HINT_ENUM, "Name,Last Modified"); + if (p_extra_config.is_valid()) { if (p_extra_config->has_section("init_projects") && p_extra_config->has_section_key("init_projects", "list")) { diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 36053d7534..eacf2ee1b4 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -351,18 +351,18 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("mono_color", "Editor", mono_color); - Color success_color = accent_color.linear_interpolate(Color(0.2, 1, 0.2), 0.6) * 1.2; - Color warning_color = accent_color.linear_interpolate(Color(1, 1, 0), 0.7) * 1.0; - Color error_color = accent_color.linear_interpolate(Color(1, 0, 0), 0.8) * 1.7; + Color success_color = Color(0.45, 0.95, 0.5); + Color warning_color = Color(1, 0.87, 0.4); + Color error_color = Color(1, 0.47, 0.42); Color property_color = font_color.linear_interpolate(Color(0.5, 0.5, 0.5), 0.5); if (!dark_theme) { - // yellow on white themes is a P.I.T.A. - warning_color = accent_color.linear_interpolate(Color(0.9, 0.7, 0), 0.9); - warning_color = warning_color.linear_interpolate(mono_color, 0.2); - success_color = success_color.linear_interpolate(mono_color, 0.2); - error_color = error_color.linear_interpolate(mono_color, 0.2); + // Darken some colors to be readable on a light background + success_color = success_color.linear_interpolate(mono_color, 0.35); + warning_color = warning_color.linear_interpolate(mono_color, 0.35); + error_color = error_color.linear_interpolate(mono_color, 0.25); } + theme->set_color("success_color", "Editor", success_color); theme->set_color("warning_color", "Editor", warning_color); theme->set_color("error_color", "Editor", error_color); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 0e2e957333..ac728e8d7c 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1165,10 +1165,12 @@ void ProjectManager::_load_recent_projects() { bool set_ordered_latest_modification; ProjectListFilter::FilterOption filter_order_option = project_order_filter->get_filter_option(); - if (filter_order_option == ProjectListFilter::FILTER_NAME) + if (filter_order_option == ProjectListFilter::FILTER_NAME) { set_ordered_latest_modification = false; - else + } else { set_ordered_latest_modification = true; + } + EditorSettings::get_singleton()->set("project_manager/sorting_order", (int)filter_order_option); List<ProjectItem> projects; List<ProjectItem> favorite_projects; @@ -1838,16 +1840,19 @@ ProjectManager::ProjectManager() { Label *sort_label = memnew(Label); sort_label->set_text(TTR("Sort:")); sort_filters->add_child(sort_label); - Vector<String> vec1; - vec1.push_back("Name"); - vec1.push_back("Last Modified"); + Vector<String> sort_filter_titles; + sort_filter_titles.push_back("Name"); + sort_filter_titles.push_back("Last Modified"); project_order_filter = memnew(ProjectListFilter); - project_order_filter->_setup_filters(vec1); + project_order_filter->_setup_filters(sort_filter_titles); project_order_filter->set_filter_size(150); sort_filters->add_child(project_order_filter); project_order_filter->connect("filter_changed", this, "_load_recent_projects"); project_order_filter->set_custom_minimum_size(Size2(180, 10) * EDSCALE); + int projects_sorting_order = (int)EditorSettings::get_singleton()->get("project_manager/sorting_order"); + project_order_filter->set_filter_option((ProjectListFilter::FilterOption)projects_sorting_order); + sort_filters->add_spacer(true); Label *search_label = memnew(Label); search_label->set_text(TTR("Search:")); @@ -2074,6 +2079,11 @@ ProjectListFilter::FilterOption ProjectListFilter::get_filter_option() { return _current_filter; } +void ProjectListFilter::set_filter_option(FilterOption option) { + filter_option->select((int)option); + _filter_option_selected(0); +} + void ProjectListFilter::_filter_option_selected(int p_idx) { FilterOption selected = (FilterOption)(filter_option->get_selected()); if (_current_filter != selected) { diff --git a/editor/project_manager.h b/editor/project_manager.h index 88fc081272..e0a0932cf8 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -152,6 +152,7 @@ public: void set_filter_size(int h_size); String get_search_term(); FilterOption get_filter_option(); + void set_filter_option(FilterOption); ProjectListFilter(); }; diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index df704706af..e0c95e3bbc 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -308,8 +308,10 @@ void ScriptCreateDialog::_built_in_pressed() { if (internal->is_pressed()) { is_built_in = true; + is_new_script_created = true; } else { is_built_in = false; + _path_changed(file_path->get_text()); } _update_dialog(); } diff --git a/main/input_default.cpp b/main/input_default.cpp index b1084900d6..67301a38f3 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -280,7 +280,7 @@ void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid() && !mb->is_doubleclick()) { + if (mb.is_valid()) { if (mb->is_pressed()) { mouse_button_mask |= (1 << (mb->get_button_index() - 1)); diff --git a/main/main.cpp b/main/main.cpp index 7383294167..f6902ffe23 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1230,6 +1230,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) { register_driver_types(); + // This loads global classes, so it must happen before custom loaders and savers are registered ScriptServer::init_languages(); MAIN_PRINT("Main: Load Translations"); @@ -1489,6 +1490,9 @@ bool Main::start() { } #endif + ResourceLoader::add_custom_loaders(); + ResourceSaver::add_custom_savers(); + if (!project_manager && !editor) { // game if (game_path != "" || script != "") { //autoload @@ -1961,11 +1965,13 @@ void Main::force_redraw() { * so that the engine closes cleanly without leaking memory or crashing. * The order matters as some of those steps are linked with each other. */ - void Main::cleanup() { ERR_FAIL_COND(!_start_success); + ResourceLoader::remove_custom_loaders(); + ResourceSaver::remove_custom_savers(); + message_queue->flush(); memdelete(message_queue); diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index f4b061f494..80fa2454ec 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -48,18 +48,76 @@ void CSGShape::set_use_collision(bool p_enable) { PhysicsServer::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid()); PhysicsServer::get_singleton()->body_set_space(root_collision_instance, get_world()->get_space()); PhysicsServer::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id()); + set_collision_layer(collision_layer); + set_collision_mask(collision_mask); _make_dirty(); //force update } else { PhysicsServer::get_singleton()->free(root_collision_instance); root_collision_instance = RID(); root_collision_shape.unref(); } + _change_notify(); } bool CSGShape::is_using_collision() const { return use_collision; } +void CSGShape::set_collision_layer(uint32_t p_layer) { + collision_layer = p_layer; + if (root_collision_instance.is_valid()) { + PhysicsServer::get_singleton()->body_set_collision_layer(root_collision_instance, p_layer); + } +} + +uint32_t CSGShape::get_collision_layer() const { + + return collision_layer; +} + +void CSGShape::set_collision_mask(uint32_t p_mask) { + + collision_mask = p_mask; + if (root_collision_instance.is_valid()) { + PhysicsServer::get_singleton()->body_set_collision_mask(root_collision_instance, p_mask); + } +} + +uint32_t CSGShape::get_collision_mask() const { + + return collision_mask; +} + +void CSGShape::set_collision_mask_bit(int p_bit, bool p_value) { + + uint32_t mask = get_collision_mask(); + if (p_value) + mask |= 1 << p_bit; + else + mask &= ~(1 << p_bit); + set_collision_mask(mask); +} + +bool CSGShape::get_collision_mask_bit(int p_bit) const { + + return get_collision_mask() & (1 << p_bit); +} + +void CSGShape::set_collision_layer_bit(int p_bit, bool p_value) { + + uint32_t mask = get_collision_layer(); + if (p_value) + mask |= 1 << p_bit; + else + mask &= ~(1 << p_bit); + set_collision_layer(mask); +} + +bool CSGShape::get_collision_layer_bit(int p_bit) const { + + return get_collision_layer() & (1 << p_bit); +} + bool CSGShape::is_root_shape() const { return !parent; @@ -459,6 +517,8 @@ void CSGShape::_notification(int p_what) { PhysicsServer::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid()); PhysicsServer::get_singleton()->body_set_space(root_collision_instance, get_world()->get_space()); PhysicsServer::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id()); + set_collision_layer(collision_layer); + set_collision_mask(collision_mask); } _make_dirty(); @@ -477,7 +537,7 @@ void CSGShape::_notification(int p_what) { parent->_make_dirty(); parent = NULL; - if (use_collision && is_root_shape()) { + if (use_collision && is_root_shape() && root_collision_instance.is_valid()) { PhysicsServer::get_singleton()->free(root_collision_instance); root_collision_instance = RID(); root_collision_shape.unref(); @@ -506,9 +566,12 @@ bool CSGShape::is_calculating_tangents() const { } void CSGShape::_validate_property(PropertyInfo &property) const { - if (is_inside_tree() && property.name.begins_with("use_collision") && !is_root_shape()) { + bool is_collision_prefixed = property.name.begins_with("collision_"); + if ((is_collision_prefixed || property.name.begins_with("use_collision")) && is_inside_tree() && !is_root_shape()) { //hide collision if not root property.usage = PROPERTY_USAGE_NOEDITOR; + } else if (is_collision_prefixed && !bool(get("use_collision"))) { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; } } @@ -520,34 +583,52 @@ void CSGShape::_bind_methods() { ClassDB::bind_method(D_METHOD("set_operation", "operation"), &CSGShape::set_operation); ClassDB::bind_method(D_METHOD("get_operation"), &CSGShape::get_operation); + ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGShape::set_snap); + ClassDB::bind_method(D_METHOD("get_snap"), &CSGShape::get_snap); + ClassDB::bind_method(D_METHOD("set_use_collision", "operation"), &CSGShape::set_use_collision); ClassDB::bind_method(D_METHOD("is_using_collision"), &CSGShape::is_using_collision); - ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGShape::set_snap); - ClassDB::bind_method(D_METHOD("get_snap"), &CSGShape::get_snap); + ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &CSGShape::set_collision_layer); + ClassDB::bind_method(D_METHOD("get_collision_layer"), &CSGShape::get_collision_layer); + + ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CSGShape::set_collision_mask); + ClassDB::bind_method(D_METHOD("get_collision_mask"), &CSGShape::get_collision_mask); + + ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CSGShape::set_collision_mask_bit); + ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CSGShape::get_collision_mask_bit); + + ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CSGShape::set_collision_layer_bit); + ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CSGShape::get_collision_layer_bit); ClassDB::bind_method(D_METHOD("set_calculate_tangents", "enabled"), &CSGShape::set_calculate_tangents); ClassDB::bind_method(D_METHOD("is_calculating_tangents"), &CSGShape::is_calculating_tangents); ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_collision"), "set_use_collision", "is_using_collision"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "snap", PROPERTY_HINT_RANGE, "0.0001,1,0.001"), "set_snap", "get_snap"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "calculate_tangents"), "set_calculate_tangents", "is_calculating_tangents"); + ADD_GROUP("Collision", "collision_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_collision"), "set_use_collision", "is_using_collision"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + BIND_ENUM_CONSTANT(OPERATION_UNION); BIND_ENUM_CONSTANT(OPERATION_INTERSECTION); BIND_ENUM_CONSTANT(OPERATION_SUBTRACTION); } CSGShape::CSGShape() { + operation = OPERATION_UNION; + parent = NULL; brush = NULL; - set_notify_local_transform(true); dirty = false; - parent = NULL; - use_collision = false; - operation = OPERATION_UNION; snap = 0.001; + use_collision = false; + collision_layer = 1; + collision_mask = 1; calculate_tangents = true; + set_notify_local_transform(true); } CSGShape::~CSGShape() { diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index 7326f3d36a..28d94bc2f2 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -61,6 +61,8 @@ private: float snap; bool use_collision; + uint32_t collision_layer; + uint32_t collision_mask; Ref<ConcavePolygonShape> root_collision_shape; RID root_collision_instance; @@ -126,6 +128,18 @@ public: void set_use_collision(bool p_enable); bool is_using_collision() const; + void set_collision_layer(uint32_t p_layer); + uint32_t get_collision_layer() const; + + void set_collision_mask(uint32_t p_mask); + uint32_t get_collision_mask() const; + + void set_collision_layer_bit(int p_bit, bool p_value); + bool get_collision_layer_bit(int p_bit) const; + + void set_collision_mask_bit(int p_bit, bool p_value); + bool get_collision_mask_bit(int p_bit) const; + void set_snap(float p_snap); float get_snap() const; diff --git a/modules/csg/doc_classes/CSGShape.xml b/modules/csg/doc_classes/CSGShape.xml index ac3c2342fc..56087cbb82 100644 --- a/modules/csg/doc_classes/CSGShape.xml +++ b/modules/csg/doc_classes/CSGShape.xml @@ -11,6 +11,24 @@ <demos> </demos> <methods> + <method name="get_collision_layer_bit" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="bit" type="int"> + </argument> + <description> + Returns an individual bit on the collision mask. + </description> + </method> + <method name="get_collision_mask_bit" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="bit" type="int"> + </argument> + <description> + Returns an individual bit on the collision mask. + </description> + </method> <method name="is_root_shape" qualifiers="const"> <return type="bool"> </return> @@ -18,11 +36,41 @@ Returns true if this is a root shape and is thus the object that is rendered. </description> </method> + <method name="set_collision_layer_bit"> + <return type="void"> + </return> + <argument index="0" name="bit" type="int"> + </argument> + <argument index="1" name="value" type="bool"> + </argument> + <description> + Sets individual bits on the layer mask. Use this if you only need to change one layer's value. + </description> + </method> + <method name="set_collision_mask_bit"> + <return type="void"> + </return> + <argument index="0" name="bit" type="int"> + </argument> + <argument index="1" name="value" type="bool"> + </argument> + <description> + Sets individual bits on the collision mask. Use this if you only need to change one layer's value. + </description> + </method> </methods> <members> <member name="calculate_tangents" type="bool" setter="set_calculate_tangents" getter="is_calculating_tangents"> Calculate tangents for the CSG shape which allows the use of normal maps. This is only applied on the root shape, this setting is ignored on any child. </member> + <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer"> + The physics layers this area is in. + Collidable objects can exist in any of 32 different layers. These layers work like a tagging system, and are not visual. A collidable can use these layers to select with which objects it can collide, using the collision_mask property. + A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. + </member> + <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask"> + The physics layers this CSG shape scans for collisions. + </member> <member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape.Operation"> The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent. </member> diff --git a/modules/dds/register_types.cpp b/modules/dds/register_types.cpp index d6351fb6fe..94f0ebfd5f 100644 --- a/modules/dds/register_types.cpp +++ b/modules/dds/register_types.cpp @@ -32,15 +32,16 @@ #include "texture_loader_dds.h" -static ResourceFormatDDS *resource_loader_dds = NULL; +static Ref<ResourceFormatDDS> resource_loader_dds; void register_dds_types() { - resource_loader_dds = memnew(ResourceFormatDDS); + resource_loader_dds.instance(); ResourceLoader::add_resource_format_loader(resource_loader_dds); } void unregister_dds_types() { - memdelete(resource_loader_dds); + ResourceLoader::remove_resource_format_loader(resource_loader_dds); + resource_loader_dds.unref(); } diff --git a/modules/dds/texture_loader_dds.h b/modules/dds/texture_loader_dds.h index 4e2593c744..abd747f63e 100644 --- a/modules/dds/texture_loader_dds.h +++ b/modules/dds/texture_loader_dds.h @@ -35,6 +35,7 @@ #include "scene/resources/texture.h" class ResourceFormatDDS : public ResourceFormatLoader { + GDCLASS(ResourceFormatDDS, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/modules/etc/register_types.cpp b/modules/etc/register_types.cpp index 1d1f0e1b77..301193874d 100644 --- a/modules/etc/register_types.cpp +++ b/modules/etc/register_types.cpp @@ -33,11 +33,11 @@ #include "image_etc.h" #include "texture_loader_pkm.h" -static ResourceFormatPKM *resource_loader_pkm = NULL; +static Ref<ResourceFormatPKM> resource_loader_pkm; void register_etc_types() { - resource_loader_pkm = memnew(ResourceFormatPKM); + resource_loader_pkm.instance(); ResourceLoader::add_resource_format_loader(resource_loader_pkm); _register_etc_compress_func(); @@ -45,5 +45,6 @@ void register_etc_types() { void unregister_etc_types() { - memdelete(resource_loader_pkm); + ResourceLoader::remove_resource_format_loader(resource_loader_pkm); + resource_loader_pkm.unref(); } diff --git a/modules/etc/texture_loader_pkm.h b/modules/etc/texture_loader_pkm.h index b5a95767c7..8308b84109 100644 --- a/modules/etc/texture_loader_pkm.h +++ b/modules/etc/texture_loader_pkm.h @@ -35,6 +35,7 @@ #include "scene/resources/texture.h" class ResourceFormatPKM : public ResourceFormatLoader { + GDCLASS(ResourceFormatPKM, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h index c5364a72ac..528344a814 100644 --- a/modules/gdnative/gdnative.h +++ b/modules/gdnative/gdnative.h @@ -161,6 +161,7 @@ public: }; class GDNativeLibraryResourceLoader : public ResourceFormatLoader { + GDCLASS(GDNativeLibraryResourceLoader, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path, Error *r_error); virtual void get_recognized_extensions(List<String> *p_extensions) const; @@ -169,6 +170,7 @@ public: }; class GDNativeLibraryResourceSaver : public ResourceFormatSaver { + GDCLASS(GDNativeLibraryResourceSaver, ResourceFormatSaver) public: virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags); virtual bool recognize(const RES &p_resource) const; diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index e6f3c06ee5..67fb54387d 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -380,6 +380,7 @@ public: }; class ResourceFormatLoaderNativeScript : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderNativeScript, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; @@ -388,6 +389,7 @@ public: }; class ResourceFormatSaverNativeScript : public ResourceFormatSaver { + GDCLASS(ResourceFormatSaverNativeScript, ResourceFormatSaver) virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); virtual bool recognize(const RES &p_resource) const; virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; diff --git a/modules/gdnative/nativescript/register_types.cpp b/modules/gdnative/nativescript/register_types.cpp index 4433c0a638..1e0c3d9fd8 100644 --- a/modules/gdnative/nativescript/register_types.cpp +++ b/modules/gdnative/nativescript/register_types.cpp @@ -39,8 +39,8 @@ NativeScriptLanguage *native_script_language; -ResourceFormatLoaderNativeScript *resource_loader_gdns = NULL; -ResourceFormatSaverNativeScript *resource_saver_gdns = NULL; +Ref<ResourceFormatLoaderNativeScript> resource_loader_gdns; +Ref<ResourceFormatSaverNativeScript> resource_saver_gdns; void register_nativescript_types() { native_script_language = memnew(NativeScriptLanguage); @@ -50,18 +50,20 @@ void register_nativescript_types() { native_script_language->set_language_index(ScriptServer::get_language_count()); ScriptServer::register_language(native_script_language); - resource_saver_gdns = memnew(ResourceFormatSaverNativeScript); + resource_saver_gdns.instance(); ResourceSaver::add_resource_format_saver(resource_saver_gdns); - resource_loader_gdns = memnew(ResourceFormatLoaderNativeScript); + resource_loader_gdns.instance(); ResourceLoader::add_resource_format_loader(resource_loader_gdns); } void unregister_nativescript_types() { - memdelete(resource_loader_gdns); + ResourceLoader::remove_resource_format_loader(resource_loader_gdns); + resource_loader_gdns.unref(); - memdelete(resource_saver_gdns); + ResourceSaver::remove_resource_format_saver(resource_saver_gdns); + resource_saver_gdns.unref(); if (native_script_language) { ScriptServer::unregister_language(native_script_language); diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp index 2b538c4a36..0cda8859dd 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.cpp +++ b/modules/gdnative/pluginscript/pluginscript_language.cpp @@ -417,8 +417,8 @@ void PluginScriptLanguage::unlock() { PluginScriptLanguage::PluginScriptLanguage(const godot_pluginscript_language_desc *desc) : _desc(*desc) { - _resource_loader = memnew(ResourceFormatLoaderPluginScript(this)); - _resource_saver = memnew(ResourceFormatSaverPluginScript(this)); + _resource_loader = Ref<ResourceFormatLoaderPluginScript>(memnew(ResourceFormatLoaderPluginScript(this))); + _resource_saver = Ref<ResourceFormatSaverPluginScript>(memnew(ResourceFormatSaverPluginScript(this))); // TODO: totally remove _lock attribute if NO_THREADS is set #ifdef NO_THREADS @@ -429,8 +429,6 @@ PluginScriptLanguage::PluginScriptLanguage(const godot_pluginscript_language_des } PluginScriptLanguage::~PluginScriptLanguage() { - memdelete(_resource_loader); - memdelete(_resource_saver); #ifndef NO_THREADS if (_lock) { memdelete(_lock); diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h index c4df6f3a33..f749e900f5 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.h +++ b/modules/gdnative/pluginscript/pluginscript_language.h @@ -48,8 +48,8 @@ class PluginScriptLanguage : public ScriptLanguage { friend class PluginScript; friend class PluginScriptInstance; - ResourceFormatLoaderPluginScript *_resource_loader; - ResourceFormatSaverPluginScript *_resource_saver; + Ref<ResourceFormatLoaderPluginScript> _resource_loader; + Ref<ResourceFormatSaverPluginScript> _resource_saver; const godot_pluginscript_language_desc _desc; godot_pluginscript_language_data *_data; @@ -59,8 +59,8 @@ class PluginScriptLanguage : public ScriptLanguage { public: virtual String get_name() const; - _FORCE_INLINE_ ResourceFormatLoaderPluginScript *get_resource_loader() { return _resource_loader; }; - _FORCE_INLINE_ ResourceFormatSaverPluginScript *get_resource_saver() { return _resource_saver; }; + _FORCE_INLINE_ Ref<ResourceFormatLoaderPluginScript> get_resource_loader() { return _resource_loader; } + _FORCE_INLINE_ Ref<ResourceFormatSaverPluginScript> get_resource_saver() { return _resource_saver; } /* LANGUAGE FUNCTIONS */ virtual void init(); diff --git a/modules/gdnative/pluginscript/pluginscript_loader.h b/modules/gdnative/pluginscript/pluginscript_loader.h index 5c17bb932e..ee9869be84 100644 --- a/modules/gdnative/pluginscript/pluginscript_loader.h +++ b/modules/gdnative/pluginscript/pluginscript_loader.h @@ -39,6 +39,9 @@ class PluginScriptLanguage; class ResourceFormatLoaderPluginScript : public ResourceFormatLoader { + + GDCLASS(ResourceFormatLoaderPluginScript, ResourceFormatLoader) + PluginScriptLanguage *_language; public: @@ -50,6 +53,9 @@ public: }; class ResourceFormatSaverPluginScript : public ResourceFormatSaver { + + GDCLASS(ResourceFormatSaverPluginScript, ResourceFormatSaver) + PluginScriptLanguage *_language; public: diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index 62e87c3651..51f0b9afcc 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -299,8 +299,8 @@ GDNativeCallRegistry *GDNativeCallRegistry::singleton; Vector<Ref<GDNative> > singleton_gdnatives; -GDNativeLibraryResourceLoader *resource_loader_gdnlib = NULL; -GDNativeLibraryResourceSaver *resource_saver_gdnlib = NULL; +Ref<GDNativeLibraryResourceLoader> resource_loader_gdnlib; +Ref<GDNativeLibraryResourceSaver> resource_saver_gdnlib; void register_gdnative_types() { @@ -312,8 +312,8 @@ void register_gdnative_types() { ClassDB::register_class<GDNativeLibrary>(); ClassDB::register_class<GDNative>(); - resource_loader_gdnlib = memnew(GDNativeLibraryResourceLoader); - resource_saver_gdnlib = memnew(GDNativeLibraryResourceSaver); + resource_loader_gdnlib.instance(); + resource_saver_gdnlib.instance(); ResourceLoader::add_resource_format_loader(resource_loader_gdnlib); ResourceSaver::add_resource_format_saver(resource_saver_gdnlib); @@ -391,8 +391,11 @@ void unregister_gdnative_types() { } #endif - memdelete(resource_loader_gdnlib); - memdelete(resource_saver_gdnlib); + ResourceLoader::remove_resource_format_loader(resource_loader_gdnlib); + ResourceSaver::remove_resource_format_saver(resource_saver_gdnlib); + + resource_loader_gdnlib.unref(); + resource_saver_gdnlib.unref(); // This is for printing out the sizes of the core types diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 752d660ffb..3e7cb076aa 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -500,6 +500,7 @@ public: }; class ResourceFormatLoaderGDScript : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderGDScript, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; @@ -508,6 +509,7 @@ public: }; class ResourceFormatSaverGDScript : public ResourceFormatSaver { + GDCLASS(ResourceFormatSaverGDScript, ResourceFormatSaver) public: virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 26dcbdcf89..9c4dc0c926 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -38,8 +38,8 @@ #include "gdscript_tokenizer.h" GDScriptLanguage *script_language_gd = NULL; -ResourceFormatLoaderGDScript *resource_loader_gd = NULL; -ResourceFormatSaverGDScript *resource_saver_gd = NULL; +Ref<ResourceFormatLoaderGDScript> resource_loader_gd; +Ref<ResourceFormatSaverGDScript> resource_saver_gd; #ifdef TOOLS_ENABLED @@ -87,9 +87,11 @@ void register_gdscript_types() { script_language_gd = memnew(GDScriptLanguage); ScriptServer::register_language(script_language_gd); - resource_loader_gd = memnew(ResourceFormatLoaderGDScript); + + resource_loader_gd.instance(); ResourceLoader::add_resource_format_loader(resource_loader_gd); - resource_saver_gd = memnew(ResourceFormatSaverGDScript); + + resource_saver_gd.instance(); ResourceSaver::add_resource_format_saver(resource_saver_gd); #ifdef TOOLS_ENABLED @@ -104,8 +106,14 @@ void unregister_gdscript_types() { if (script_language_gd) memdelete(script_language_gd); - if (resource_loader_gd) - memdelete(resource_loader_gd); - if (resource_saver_gd) - memdelete(resource_saver_gd); + + if (resource_loader_gd.is_valid()) { + ResourceLoader::remove_resource_format_loader(resource_loader_gd); + resource_loader_gd.unref(); + } + + if (resource_saver_gd.is_valid()) { + ResourceSaver::remove_resource_format_saver(resource_saver_gd); + resource_saver_gd.unref(); + } } diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 08466bae58..695889b2a8 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -398,6 +398,7 @@ public: }; class ResourceFormatLoaderCSharpScript : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderCSharpScript, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; @@ -406,6 +407,7 @@ public: }; class ResourceFormatSaverCSharpScript : public ResourceFormatSaver { + GDCLASS(ResourceFormatSaverCSharpScript, ResourceFormatSaver) public: virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp index f6cb143e8e..9ee7a0b5c4 100644 --- a/modules/mono/register_types.cpp +++ b/modules/mono/register_types.cpp @@ -35,8 +35,8 @@ #include "csharp_script.h" CSharpLanguage *script_language_cs = NULL; -ResourceFormatLoaderCSharpScript *resource_loader_cs = NULL; -ResourceFormatSaverCSharpScript *resource_saver_cs = NULL; +Ref<ResourceFormatLoaderCSharpScript> resource_loader_cs; +Ref<ResourceFormatSaverCSharpScript> resource_saver_cs; _GodotSharp *_godotsharp = NULL; @@ -52,9 +52,10 @@ void register_mono_types() { script_language_cs->set_language_index(ScriptServer::get_language_count()); ScriptServer::register_language(script_language_cs); - resource_loader_cs = memnew(ResourceFormatLoaderCSharpScript); + resource_loader_cs.instance(); ResourceLoader::add_resource_format_loader(resource_loader_cs); - resource_saver_cs = memnew(ResourceFormatSaverCSharpScript); + + resource_saver_cs.instance(); ResourceSaver::add_resource_format_saver(resource_saver_cs); } @@ -63,10 +64,16 @@ void unregister_mono_types() { if (script_language_cs) memdelete(script_language_cs); - if (resource_loader_cs) - memdelete(resource_loader_cs); - if (resource_saver_cs) - memdelete(resource_saver_cs); + + if (resource_loader_cs.is_valid()) { + ResourceLoader::remove_resource_format_loader(resource_loader_cs); + resource_loader_cs.unref(); + } + + if (resource_saver_cs.is_valid()) { + ResourceSaver::remove_resource_format_saver(resource_saver_cs); + resource_saver_cs.unref(); + } if (_godotsharp) memdelete(_godotsharp); diff --git a/modules/opus/audio_stream_opus.h b/modules/opus/audio_stream_opus.h index c004adeb77..c962936238 100644 --- a/modules/opus/audio_stream_opus.h +++ b/modules/opus/audio_stream_opus.h @@ -132,6 +132,7 @@ public: }; class ResourceFormatLoaderAudioStreamOpus : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderAudioStreamOpus, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/modules/opus/register_types.cpp b/modules/opus/register_types.cpp index f34555841e..3367fc1090 100644 --- a/modules/opus/register_types.cpp +++ b/modules/opus/register_types.cpp @@ -32,7 +32,7 @@ #include "audio_stream_opus.h" -static ResourceFormatLoaderAudioStreamOpus *opus_stream_loader = NULL; +static Ref<ResourceFormatLoaderAudioStreamOpus> opus_stream_loader; void register_opus_types() { // Sorry guys, do not enable this unless you can figure out a way diff --git a/modules/pvr/register_types.cpp b/modules/pvr/register_types.cpp index 0991828ef2..cf5bdabf3f 100644 --- a/modules/pvr/register_types.cpp +++ b/modules/pvr/register_types.cpp @@ -32,15 +32,16 @@ #include "texture_loader_pvr.h" -static ResourceFormatPVR *resource_loader_pvr = NULL; +static Ref<ResourceFormatPVR> resource_loader_pvr; void register_pvr_types() { - resource_loader_pvr = memnew(ResourceFormatPVR); + resource_loader_pvr.instance(); ResourceLoader::add_resource_format_loader(resource_loader_pvr); } void unregister_pvr_types() { - memdelete(resource_loader_pvr); + ResourceLoader::remove_resource_format_loader(resource_loader_pvr); + resource_loader_pvr.unref(); } diff --git a/modules/pvr/texture_loader_pvr.h b/modules/pvr/texture_loader_pvr.h index c859a4cdda..530b6948f0 100644 --- a/modules/pvr/texture_loader_pvr.h +++ b/modules/pvr/texture_loader_pvr.h @@ -35,6 +35,7 @@ #include "scene/resources/texture.h" class ResourceFormatPVR : public ResourceFormatLoader { + GDCLASS(ResourceFormatPVR, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path, Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/modules/theora/register_types.cpp b/modules/theora/register_types.cpp index 971fe39c44..3da721c6a0 100644 --- a/modules/theora/register_types.cpp +++ b/modules/theora/register_types.cpp @@ -32,11 +32,11 @@ #include "video_stream_theora.h" -static ResourceFormatLoaderTheora *resource_loader_theora = NULL; +static Ref<ResourceFormatLoaderTheora> resource_loader_theora; void register_theora_types() { - resource_loader_theora = memnew(ResourceFormatLoaderTheora); + resource_loader_theora.instance(); ResourceLoader::add_resource_format_loader(resource_loader_theora, true); ClassDB::register_class<VideoStreamTheora>(); @@ -44,7 +44,9 @@ void register_theora_types() { void unregister_theora_types() { - if (resource_loader_theora) { - memdelete(resource_loader_theora); + ResourceLoader::remove_resource_format_loader(resource_loader_theora); + + if (resource_loader_theora.is_valid()) { + resource_loader_theora.unref(); } } diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index 4be723f85b..c9629fbf9f 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -186,6 +186,7 @@ public: }; class ResourceFormatLoaderTheora : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderTheora, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/modules/vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h index 73c4b5f3f4..7683f38991 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.h +++ b/modules/vorbis/audio_stream_ogg_vorbis.h @@ -127,6 +127,7 @@ public: }; class ResourceFormatLoaderAudioStreamOGGVorbis : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderAudioStreamOGGVorbis, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/modules/vorbis/register_types.cpp b/modules/vorbis/register_types.cpp index 0ea1fbe8b2..8219e9e7ba 100644 --- a/modules/vorbis/register_types.cpp +++ b/modules/vorbis/register_types.cpp @@ -32,16 +32,17 @@ #include "audio_stream_ogg_vorbis.h" -static ResourceFormatLoaderAudioStreamOGGVorbis *vorbis_stream_loader = NULL; +static Ref<ResourceFormatLoaderAudioStreamOGGVorbis> vorbis_stream_loader; void register_vorbis_types() { - vorbis_stream_loader = memnew(ResourceFormatLoaderAudioStreamOGGVorbis); + vorbis_stream_loader.instance(); ResourceLoader::add_resource_format_loader(vorbis_stream_loader); ClassDB::register_class<AudioStreamOGGVorbis>(); } void unregister_vorbis_types() { - memdelete(vorbis_stream_loader); + ResourceLoader::remove_resource_format_loader(vorbis_stream_loader); + vorbis_stream_loader.unref(); } diff --git a/modules/webm/register_types.cpp b/modules/webm/register_types.cpp index 121b528d5b..dfa2dcf21c 100644 --- a/modules/webm/register_types.cpp +++ b/modules/webm/register_types.cpp @@ -32,11 +32,11 @@ #include "video_stream_webm.h" -static ResourceFormatLoaderWebm *resource_loader_webm = NULL; +static Ref<ResourceFormatLoaderWebm> resource_loader_webm; void register_webm_types() { - resource_loader_webm = memnew(ResourceFormatLoaderWebm); + resource_loader_webm.instance(); ResourceLoader::add_resource_format_loader(resource_loader_webm, true); ClassDB::register_class<VideoStreamWebm>(); @@ -44,7 +44,9 @@ void register_webm_types() { void unregister_webm_types() { - if (resource_loader_webm) { - memdelete(resource_loader_webm); + ResourceLoader::remove_resource_format_loader(resource_loader_webm); + + if (resource_loader_webm.is_valid()) { + resource_loader_webm.unref(); } } diff --git a/modules/webm/video_stream_webm.h b/modules/webm/video_stream_webm.h index 3739a73114..9501f513a0 100644 --- a/modules/webm/video_stream_webm.h +++ b/modules/webm/video_stream_webm.h @@ -127,6 +127,7 @@ public: }; class ResourceFormatLoaderWebm : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderWebm, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index a3b5b6dd58..7eda32b754 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -551,12 +551,15 @@ class EditorExportAndroid : public EditorExportPlatform { } static Vector<String> get_abis() { - // mips and armv6 are dead (especially for games), so not including them Vector<String> abis; + // We can still build armv7 in theory, but it doesn't make much + // sense for games, so disabling for now. + //abis.push_back("armeabi"); abis.push_back("armeabi-v7a"); abis.push_back("arm64-v8a"); abis.push_back("x86"); - abis.push_back("x86_64"); + // Don't expose x86_64 for now, we don't support it in detect.py + //abis.push_back("x86_64"); return abis; } diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 9250ca4903..1a40f6a979 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -295,6 +295,30 @@ EM_BOOL OS_JavaScript::mouse_button_callback(int p_event_type, const EmscriptenM default: return false; } + if (ev->is_pressed()) { + + uint64_t diff = p_event->timestamp - os->last_click_ms; + + if (ev->get_button_index() == os->last_click_button_index) { + + if (diff < 400 && Point2(os->last_click_pos).distance_to(ev->get_position()) < 5) { + + os->last_click_ms = 0; + os->last_click_pos = Point2(-100, -100); + os->last_click_button_index = -1; + ev->set_doubleclick(true); + } + + } else { + os->last_click_button_index = ev->get_button_index(); + } + + if (!ev->is_doubleclick()) { + os->last_click_ms += diff; + os->last_click_pos = ev->get_position(); + } + } + int mask = os->input->get_mouse_button_mask(); int button_flag = 1 << (ev->get_button_index() - 1); if (ev->is_pressed()) { @@ -452,7 +476,6 @@ EM_BOOL OS_JavaScript::wheel_callback(int p_event_type, const EmscriptenWheelEve InputDefault *input = get_singleton()->input; Ref<InputEventMouseButton> ev; ev.instance(); - ev->set_button_mask(input->get_mouse_button_mask()); ev->set_position(input->get_mouse_position()); ev->set_global_position(ev->get_position()); @@ -475,10 +498,14 @@ EM_BOOL OS_JavaScript::wheel_callback(int p_event_type, const EmscriptenWheelEve // Different browsers give wildly different delta values, and we can't // interpret deltaMode, so use default value for wheel events' factor. + int button_flag = 1 << (ev->get_button_index() - 1); + ev->set_pressed(true); + ev->set_button_mask(input->get_mouse_button_mask() | button_flag); input->parse_input_event(ev); ev->set_pressed(false); + ev->set_button_mask(input->get_mouse_button_mask() & ~button_flag); input->parse_input_event(ev); return true; @@ -1067,6 +1094,10 @@ OS_JavaScript::OS_JavaScript(int p_argc, char *p_argv[]) { } set_cmdline(p_argv[0], arguments); + last_click_button_index = -1; + last_click_ms = 0; + last_click_pos = Point2(-100, -100); + window_maximized = false; entering_fullscreen = false; just_exited_fullscreen = false; diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 79dac5940f..45c1a9d32d 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -52,6 +52,10 @@ class OS_JavaScript : public OS_Unix { CursorShape cursor_shape; Point2 touches[32]; + Point2i last_click_pos; + uint64_t last_click_ms; + int last_click_button_index; + MainLoop *main_loop; AudioDriverJavaScript audio_driver_javascript; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index f8dec3ec7a..dd82e982ed 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1075,6 +1075,8 @@ static int remapKey(unsigned int key) { inline void sendScrollEvent(int button, double factor, int modifierFlags) { + unsigned int mask = 1 << (button - 1); + Ref<InputEventMouseButton> sc; sc.instance(); @@ -1085,9 +1087,13 @@ inline void sendScrollEvent(int button, double factor, int modifierFlags) { Vector2 mouse_pos = Vector2(mouse_x, mouse_y); sc->set_position(mouse_pos); sc->set_global_position(mouse_pos); + button_mask |= mask; sc->set_button_mask(button_mask); OS_OSX::singleton->push_input(sc); + sc->set_pressed(false); + button_mask &= ~mask; + sc->set_button_mask(button_mask); OS_OSX::singleton->push_input(sc); } diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp index 60f20d6009..5d67e2113f 100644 --- a/platform/server/os_server.cpp +++ b/platform/server/os_server.cpp @@ -99,7 +99,7 @@ Error OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int _ensure_user_data_dir(); - resource_loader_dummy = memnew(ResourceFormatDummyTexture); + resource_loader_dummy.instance(); ResourceLoader::add_resource_format_loader(resource_loader_dummy); return OK; @@ -118,7 +118,8 @@ void OS_Server::finalize() { memdelete(power_manager); - memdelete(resource_loader_dummy); + ResourceLoader::remove_resource_format_loader(resource_loader_dummy); + resource_loader_dummy.unref(); args.clear(); } diff --git a/platform/server/os_server.h b/platform/server/os_server.h index 0367ec3db9..b5dc7900e6 100644 --- a/platform/server/os_server.h +++ b/platform/server/os_server.h @@ -77,7 +77,7 @@ class OS_Server : public OS_Unix { int video_driver_index; - ResourceFormatDummyTexture *resource_loader_dummy; + Ref<ResourceFormatDummyTexture> resource_loader_dummy; protected: virtual int get_video_driver_count() const; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 55d2bb2153..e1cbbcc66b 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -496,15 +496,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) mm->set_shift((wParam & MK_SHIFT) != 0); mm->set_alt(alt_mem); - int bmask = 0; - bmask |= (wParam & MK_LBUTTON) ? (1 << 0) : 0; - bmask |= (wParam & MK_RBUTTON) ? (1 << 1) : 0; - bmask |= (wParam & MK_MBUTTON) ? (1 << 2) : 0; - bmask |= (wParam & MK_XBUTTON1) ? (1 << 7) : 0; - bmask |= (wParam & MK_XBUTTON2) ? (1 << 8) : 0; - mm->set_button_mask(bmask); - - last_button_state = mm->get_button_mask(); + mm->set_button_mask(last_button_state); mm->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); mm->set_global_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); @@ -673,15 +665,12 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) mb->set_shift((wParam & MK_SHIFT) != 0); mb->set_alt(alt_mem); //mb->get_alt()=(wParam&MK_MENU)!=0; - int bmask = 0; - bmask |= (wParam & MK_LBUTTON) ? (1 << 0) : 0; - bmask |= (wParam & MK_RBUTTON) ? (1 << 1) : 0; - bmask |= (wParam & MK_MBUTTON) ? (1 << 2) : 0; - bmask |= (wParam & MK_XBUTTON1) ? (1 << 7) : 0; - bmask |= (wParam & MK_XBUTTON2) ? (1 << 8) : 0; - mb->set_button_mask(bmask); - - last_button_state = mb->get_button_mask(); + if (mb->is_pressed()) + last_button_state |= (1 << (mb->get_button_index() - 1)); + else + last_button_state &= ~(1 << (mb->get_button_index() - 1)); + mb->set_button_mask(last_button_state); + mb->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); if (mouse_mode == MOUSE_MODE_CAPTURED && !use_raw_input) { @@ -721,6 +710,8 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if (mb->is_pressed() && mb->get_button_index() > 3 && mb->get_button_index() < 8) { //send release for mouse wheel Ref<InputEventMouseButton> mbd = mb->duplicate(); + last_button_state &= ~(1 << (mbd->get_button_index() - 1)); + mbd->set_button_mask(last_button_state); mbd->set_pressed(false); input->parse_input_event(mbd); } diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 524c8448bc..9b6fb2f478 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -48,6 +48,11 @@ def can_build(): print("xrender not found.. x11 disabled.") return False + x11_error = os.system("pkg-config xi --modversion > /dev/null ") + if (x11_error): + print("xi not found.. Aborting.") + return False + return True def get_opts(): @@ -170,13 +175,9 @@ def configure(env): env.ParseConfig('pkg-config xinerama --cflags --libs') env.ParseConfig('pkg-config xrandr --cflags --libs') env.ParseConfig('pkg-config xrender --cflags --libs') + env.ParseConfig('pkg-config xi --cflags --libs') if (env['touch']): - x11_error = os.system("pkg-config xi --modversion > /dev/null ") - if (x11_error): - print("xi not found.. cannot build with touch. Aborting.") - sys.exit(255) - env.ParseConfig('pkg-config xi --cflags --libs') env.Append(CPPFLAGS=['-DTOUCH_ENABLED']) # FIXME: Check for existence of the libs before parsing their flags with pkg-config diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 0c02e47b5e..34ec8709c4 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -77,6 +77,13 @@ #include <X11/XKBlib.h> +// 2.2 is the first release with multitouch +#define XINPUT_CLIENT_VERSION_MAJOR 2 +#define XINPUT_CLIENT_VERSION_MINOR 2 + +static const double abs_resolution_mult = 10000.0; +static const double abs_resolution_range_mult = 10.0; + void OS_X11::initialize_core() { crash_handler.initialize(); @@ -96,6 +103,8 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a xmbstring = NULL; x11_window = 0; last_click_ms = 0; + last_click_button_index = -1; + last_click_pos = Point2(-100, -100); args = OS::get_singleton()->get_cmdline_args(); current_videomode = p_desired; main_loop = NULL; @@ -168,48 +177,12 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a } } -#ifdef TOUCH_ENABLED - if (!XQueryExtension(x11_display, "XInputExtension", &touch.opcode, &event_base, &error_base)) { - print_verbose("XInput extension not available, touch support disabled."); - } else { - // 2.2 is the first release with multitouch - int xi_major = 2; - int xi_minor = 2; - if (XIQueryVersion(x11_display, &xi_major, &xi_minor) != Success) { - print_verbose(vformat("XInput 2.2 not available (server supports %d.%d), touch support disabled.", xi_major, xi_minor)); - touch.opcode = 0; - } else { - int dev_count; - XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count); - - for (int i = 0; i < dev_count; i++) { - XIDeviceInfo *dev = &info[i]; - if (!dev->enabled) - continue; - if (!(dev->use == XIMasterPointer || dev->use == XIFloatingSlave)) - continue; - - bool direct_touch = false; - for (int j = 0; j < dev->num_classes; j++) { - if (dev->classes[j]->type == XITouchClass && ((XITouchClassInfo *)dev->classes[j])->mode == XIDirectTouch) { - direct_touch = true; - break; - } - } - if (direct_touch) { - touch.devices.push_back(dev->deviceid); - print_verbose("XInput: Using touch device: " + String(dev->name)); - } - } - - XIFreeDeviceInfo(info); - - if (!touch.devices.size()) { - print_verbose("XInput: No touch devices found."); - } - } + if (!refresh_device_info()) { + OS::get_singleton()->alert("Your system does not support XInput 2.\n" + "Please upgrade your distribution.", + "Unable to initialize XInput"); + return ERR_UNAVAILABLE; } -#endif xim = XOpenIM(x11_display, NULL, NULL, NULL); @@ -413,34 +386,42 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a XChangeWindowAttributes(x11_display, x11_window, CWEventMask, &new_attr); -#ifdef TOUCH_ENABLED - if (touch.devices.size()) { - - // Must be alive after this block - static unsigned char mask_data[XIMaskLen(XI_LASTEVENT)] = {}; + static unsigned char all_mask_data[XIMaskLen(XI_LASTEVENT)] = {}; + static unsigned char all_master_mask_data[XIMaskLen(XI_LASTEVENT)] = {}; - touch.event_mask.deviceid = XIAllDevices; - touch.event_mask.mask_len = sizeof(mask_data); - touch.event_mask.mask = mask_data; + xi.all_event_mask.deviceid = XIAllDevices; + xi.all_event_mask.mask_len = sizeof(all_mask_data); + xi.all_event_mask.mask = all_mask_data; - XISetMask(touch.event_mask.mask, XI_TouchBegin); - XISetMask(touch.event_mask.mask, XI_TouchUpdate); - XISetMask(touch.event_mask.mask, XI_TouchEnd); - XISetMask(touch.event_mask.mask, XI_TouchOwnership); + xi.all_master_event_mask.deviceid = XIAllMasterDevices; + xi.all_master_event_mask.mask_len = sizeof(all_master_mask_data); + xi.all_master_event_mask.mask = all_master_mask_data; - XISelectEvents(x11_display, x11_window, &touch.event_mask, 1); + XISetMask(xi.all_event_mask.mask, XI_HierarchyChanged); + XISetMask(xi.all_master_event_mask.mask, XI_DeviceChanged); + XISetMask(xi.all_master_event_mask.mask, XI_RawMotion); - // Disabled by now since grabbing also blocks mouse events - // (they are received as extended events instead of standard events) - /*XIClearMask(touch.event_mask.mask, XI_TouchOwnership); - - // Grab touch devices to avoid OS gesture interference - for (int i = 0; i < touch.devices.size(); ++i) { - XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask); - }*/ +#ifdef TOUCH_ENABLED + if (xi.touch_devices.size()) { + XISetMask(xi.all_event_mask.mask, XI_TouchBegin); + XISetMask(xi.all_event_mask.mask, XI_TouchUpdate); + XISetMask(xi.all_event_mask.mask, XI_TouchEnd); + XISetMask(xi.all_event_mask.mask, XI_TouchOwnership); } #endif + XISelectEvents(x11_display, x11_window, &xi.all_event_mask, 1); + XISelectEvents(x11_display, DefaultRootWindow(x11_display), &xi.all_master_event_mask, 1); + + // Disabled by now since grabbing also blocks mouse events + // (they are received as extended events instead of standard events) + /*XIClearMask(xi.touch_event_mask.mask, XI_TouchOwnership); + + // Grab touch devices to avoid OS gesture interference + for (int i = 0; i < xi.touch_devices.size(); ++i) { + XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask); + }*/ + /* set the titlebar name */ XStoreName(x11_display, x11_window, "Godot"); @@ -590,6 +571,101 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a return OK; } +bool OS_X11::refresh_device_info() { + int event_base, error_base; + + print_verbose("XInput: Refreshing devices."); + + if (!XQueryExtension(x11_display, "XInputExtension", &xi.opcode, &event_base, &error_base)) { + print_verbose("XInput extension not available. Please upgrade your distribution."); + return false; + } + + int xi_major_query = XINPUT_CLIENT_VERSION_MAJOR; + int xi_minor_query = XINPUT_CLIENT_VERSION_MINOR; + + if (XIQueryVersion(x11_display, &xi_major_query, &xi_minor_query) != Success) { + print_verbose(vformat("XInput 2 not available (server supports %d.%d).", xi_major_query, xi_minor_query)); + xi.opcode = 0; + return false; + } + + if (xi_major_query < XINPUT_CLIENT_VERSION_MAJOR || (xi_major_query == XINPUT_CLIENT_VERSION_MAJOR && xi_minor_query < XINPUT_CLIENT_VERSION_MINOR)) { + print_verbose(vformat("XInput %d.%d not available (server supports %d.%d). Touch input unavailable.", + XINPUT_CLIENT_VERSION_MAJOR, XINPUT_CLIENT_VERSION_MINOR, xi_major_query, xi_minor_query)); + } + + xi.absolute_devices.clear(); + xi.touch_devices.clear(); + + int dev_count; + XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count); + + for (int i = 0; i < dev_count; i++) { + XIDeviceInfo *dev = &info[i]; + if (!dev->enabled) + continue; + if (!(dev->use == XIMasterPointer || dev->use == XIFloatingSlave)) + continue; + + bool direct_touch = false; + bool absolute_mode = false; + int resolution_x = 0; + int resolution_y = 0; + int range_min_x = 0; + int range_min_y = 0; + int range_max_x = 0; + int range_max_y = 0; + for (int j = 0; j < dev->num_classes; j++) { +#ifdef TOUCH_ENABLED + if (dev->classes[j]->type == XITouchClass && ((XITouchClassInfo *)dev->classes[j])->mode == XIDirectTouch) { + direct_touch = true; + } +#endif + if (dev->classes[j]->type == XIValuatorClass) { + XIValuatorClassInfo *class_info = (XIValuatorClassInfo *)dev->classes[j]; + + if (class_info->number == 0 && class_info->mode == XIModeAbsolute) { + resolution_x = class_info->resolution; + range_min_x = class_info->min; + range_max_x = class_info->max; + absolute_mode = true; + } else if (class_info->number == 1 && class_info->mode == XIModeAbsolute) { + resolution_y = class_info->resolution; + range_min_y = class_info->min; + range_max_y = class_info->max; + absolute_mode = true; + } + } + } + if (direct_touch) { + xi.touch_devices.push_back(dev->deviceid); + print_verbose("XInput: Using touch device: " + String(dev->name)); + } + if (absolute_mode) { + // If no resolution was reported, use the min/max ranges. + if (resolution_x <= 0) { + resolution_x = (range_max_x - range_min_x) * abs_resolution_range_mult; + } + if (resolution_y <= 0) { + resolution_y = (range_max_y - range_min_y) * abs_resolution_range_mult; + } + + xi.absolute_devices[dev->deviceid] = Vector2(abs_resolution_mult / resolution_x, abs_resolution_mult / resolution_y); + print_verbose("XInput: Absolute pointing device: " + String(dev->name)); + } + } + + XIFreeDeviceInfo(info); +#ifdef TOUCH_ENABLED + if (!xi.touch_devices.size()) { + print_verbose("XInput: No touch devices found."); + } +#endif + + return true; +} + void OS_X11::xim_destroy_callback(::XIM im, ::XPointer client_data, ::XPointer call_data) { @@ -662,10 +738,10 @@ void OS_X11::finalize() { #ifdef JOYDEV_ENABLED memdelete(joypad); #endif -#ifdef TOUCH_ENABLED - touch.devices.clear(); - touch.state.clear(); -#endif + + xi.touch_devices.clear(); + xi.state.clear(); + memdelete(input); visual_server->finish(); @@ -725,21 +801,8 @@ void OS_X11::set_mouse_mode(MouseMode p_mode) { if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) { - while (true) { - //flush pending motion events - - if (XPending(x11_display) > 0) { - XEvent event; - XPeekEvent(x11_display, &event); - if (event.type == MotionNotify) { - XNextEvent(x11_display, &event); - } else { - break; - } - } else { - break; - } - } + //flush pending motion events + flush_mouse_motion(); if (XGrabPointer( x11_display, x11_window, True, @@ -780,6 +843,32 @@ void OS_X11::warp_mouse_position(const Point2 &p_to) { } } +void OS_X11::flush_mouse_motion() { + while (true) { + if (XPending(x11_display) > 0) { + XEvent event; + XPeekEvent(x11_display, &event); + + if (XGetEventData(x11_display, &event.xcookie) && event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) { + XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data; + + if (event_data->evtype == XI_RawMotion) { + XNextEvent(x11_display, &event); + } else { + break; + } + } else { + break; + } + } else { + break; + } + } + + xi.relative_motion.x = 0; + xi.relative_motion.y = 0; +} + OS::MouseMode OS_X11::get_mouse_mode() const { return mouse_mode; } @@ -1433,37 +1522,17 @@ void OS_X11::get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWith state->set_metakey((p_x11_state & Mod4Mask)); } -unsigned int OS_X11::get_mouse_button_state(unsigned int p_x11_state) { - - unsigned int state = 0; - - if (p_x11_state & Button1Mask) { - - state |= 1 << 0; - } - - if (p_x11_state & Button3Mask) { - - state |= 1 << 1; - } - - if (p_x11_state & Button2Mask) { +unsigned int OS_X11::get_mouse_button_state(unsigned int p_x11_button, int p_x11_type) { - state |= 1 << 2; - } + unsigned int mask = 1 << (p_x11_button - 1); - if (p_x11_state & Button4Mask) { - - state |= 1 << 3; - } - - if (p_x11_state & Button5Mask) { - - state |= 1 << 4; + if (p_x11_type == ButtonPress) { + last_button_state |= mask; + } else { + last_button_state &= ~mask; } - last_button_state = state; - return state; + return last_button_state; } void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) { @@ -1796,17 +1865,61 @@ void OS_X11::process_xevents() { continue; } -#ifdef TOUCH_ENABLED if (XGetEventData(x11_display, &event.xcookie)) { - if (event.xcookie.type == GenericEvent && event.xcookie.extension == touch.opcode) { + if (event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) { XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data; int index = event_data->detail; Vector2 pos = Vector2(event_data->event_x, event_data->event_y); switch (event_data->evtype) { + case XI_HierarchyChanged: + case XI_DeviceChanged: { + refresh_device_info(); + } break; + case XI_RawMotion: { + XIRawEvent *raw_event = (XIRawEvent *)event_data; + int device_id = raw_event->deviceid; + + // Determine the axis used (called valuators in XInput for some forsaken reason) + // Mask is a bitmask indicating which axes are involved. + // We are interested in the values of axes 0 and 1. + if (raw_event->valuators.mask_len <= 0 || !XIMaskIsSet(raw_event->valuators.mask, 0) || !XIMaskIsSet(raw_event->valuators.mask, 1)) { + break; + } + + double rel_x = raw_event->raw_values[0]; + double rel_y = raw_event->raw_values[1]; + + // https://bugs.freedesktop.org/show_bug.cgi?id=71609 + // http://lists.libsdl.org/pipermail/commits-libsdl.org/2015-June/000282.html + if (raw_event->time == xi.last_relative_time && rel_x == xi.relative_motion.x && rel_y == xi.relative_motion.y) { + break; // Flush duplicate to avoid overly fast motion + } + + xi.old_raw_pos.x = xi.raw_pos.x; + xi.old_raw_pos.y = xi.raw_pos.y; + xi.raw_pos.x = rel_x; + xi.raw_pos.y = rel_y; + + Map<int, Vector2>::Element *abs_info = xi.absolute_devices.find(device_id); + + if (abs_info) { + // Absolute mode device + Vector2 mult = abs_info->value(); + xi.relative_motion.x += (xi.raw_pos.x - xi.old_raw_pos.x) * mult.x; + xi.relative_motion.y += (xi.raw_pos.y - xi.old_raw_pos.y) * mult.y; + } else { + // Relative mode device + xi.relative_motion.x = xi.raw_pos.x; + xi.relative_motion.y = xi.raw_pos.y; + } + + xi.last_relative_time = raw_event->time; + } break; +#ifdef TOUCH_ENABLED case XI_TouchBegin: // Fall-through // Disabled hand-in-hand with the grabbing //XIAllowTouchEvents(x11_display, event_data->deviceid, event_data->detail, x11_window, XIAcceptTouch); @@ -1822,26 +1935,26 @@ void OS_X11::process_xevents() { st->set_pressed(is_begin); if (is_begin) { - if (touch.state.has(index)) // Defensive + if (xi.state.has(index)) // Defensive break; - touch.state[index] = pos; - if (touch.state.size() == 1) { + xi.state[index] = pos; + if (xi.state.size() == 1) { // X11 may send a motion event when a touch gesture begins, that would result // in a spurious mouse motion event being sent to Godot; remember it to be able to filter it out - touch.mouse_pos_to_filter = pos; + xi.mouse_pos_to_filter = pos; } input->parse_input_event(st); } else { - if (!touch.state.has(index)) // Defensive + if (!xi.state.has(index)) // Defensive break; - touch.state.erase(index); + xi.state.erase(index); input->parse_input_event(st); } } break; case XI_TouchUpdate: { - Map<int, Vector2>::Element *curr_pos_elem = touch.state.find(index); + Map<int, Vector2>::Element *curr_pos_elem = xi.state.find(index); if (!curr_pos_elem) { // Defensive break; } @@ -1858,11 +1971,11 @@ void OS_X11::process_xevents() { curr_pos_elem->value() = pos; } } break; +#endif } } } XFreeEventData(x11_display, &event.xcookie); -#endif switch (event.type) { case Expose: @@ -1908,8 +2021,8 @@ void OS_X11::process_xevents() { } #ifdef TOUCH_ENABLED // Grab touch devices to avoid OS gesture interference - /*for (int i = 0; i < touch.devices.size(); ++i) { - XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask); + /*for (int i = 0; i < xi.touch_devices.size(); ++i) { + XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask); }*/ #endif if (xic) { @@ -1930,12 +2043,12 @@ void OS_X11::process_xevents() { } #ifdef TOUCH_ENABLED // Ungrab touch devices so input works as usual while we are unfocused - /*for (int i = 0; i < touch.devices.size(); ++i) { - XIUngrabDevice(x11_display, touch.devices[i], CurrentTime); + /*for (int i = 0; i < xi.touch_devices.size(); ++i) { + XIUngrabDevice(x11_display, xi.touch_devices[i], CurrentTime); }*/ // Release every pointer to avoid sticky points - for (Map<int, Vector2>::Element *E = touch.state.front(); E; E = E->next()) { + for (Map<int, Vector2>::Element *E = xi.state.front(); E; E = E->next()) { Ref<InputEventScreenTouch> st; st.instance(); @@ -1943,7 +2056,7 @@ void OS_X11::process_xevents() { st->set_position(E->get()); input->parse_input_event(st); } - touch.state.clear(); + xi.state.clear(); #endif if (xic) { XUnsetICFocus(xic); @@ -1967,28 +2080,36 @@ void OS_X11::process_xevents() { mb.instance(); get_key_modifier_state(event.xbutton.state, mb); - mb->set_button_mask(get_mouse_button_state(event.xbutton.state)); - mb->set_position(Vector2(event.xbutton.x, event.xbutton.y)); - mb->set_global_position(mb->get_position()); mb->set_button_index(event.xbutton.button); if (mb->get_button_index() == 2) mb->set_button_index(3); else if (mb->get_button_index() == 3) mb->set_button_index(2); + mb->set_button_mask(get_mouse_button_state(mb->get_button_index(), event.xbutton.type)); + mb->set_position(Vector2(event.xbutton.x, event.xbutton.y)); + mb->set_global_position(mb->get_position()); mb->set_pressed((event.type == ButtonPress)); - if (event.type == ButtonPress && event.xbutton.button == 1) { + if (event.type == ButtonPress) { uint64_t diff = get_ticks_usec() / 1000 - last_click_ms; - if (diff < 400 && Point2(last_click_pos).distance_to(Point2(event.xbutton.x, event.xbutton.y)) < 5) { + if (mb->get_button_index() == last_click_button_index) { - last_click_ms = 0; - last_click_pos = Point2(-100, -100); - mb->set_doubleclick(true); + if (diff < 400 && Point2(last_click_pos).distance_to(Point2(event.xbutton.x, event.xbutton.y)) < 5) { - } else { + last_click_ms = 0; + last_click_pos = Point2(-100, -100); + last_click_button_index = -1; + mb->set_doubleclick(true); + } + + } else if (mb->get_button_index() < 4 || mb->get_button_index() > 7) { + last_click_button_index = mb->get_button_index(); + } + + if (!mb->is_doubleclick()) { last_click_ms += diff; last_click_pos = Point2(event.xbutton.x, event.xbutton.y); } @@ -2028,34 +2149,27 @@ void OS_X11::process_xevents() { // Motion is also simple. // A little hack is in order // to be able to send relative motion events. - Point2i pos(event.xmotion.x, event.xmotion.y); + Point2 pos(event.xmotion.x, event.xmotion.y); -#ifdef TOUCH_ENABLED // Avoidance of spurious mouse motion (see handling of touch) bool filter = false; // Adding some tolerance to match better Point2i to Vector2 - if (touch.state.size() && Vector2(pos).distance_squared_to(touch.mouse_pos_to_filter) < 2) { + if (xi.state.size() && Vector2(pos).distance_squared_to(xi.mouse_pos_to_filter) < 2) { filter = true; } // Invalidate to avoid filtering a possible legitimate similar event coming later - touch.mouse_pos_to_filter = Vector2(1e10, 1e10); + xi.mouse_pos_to_filter = Vector2(1e10, 1e10); if (filter) { break; } -#endif if (mouse_mode == MOUSE_MODE_CAPTURED) { - - if (pos == Point2i(current_videomode.width / 2, current_videomode.height / 2)) { - //this sucks, it's a hack, etc and is a little inaccurate, etc. - //but nothing I can do, X11 sucks. - - center = pos; + if (xi.relative_motion.x == 0 && xi.relative_motion.y == 0) { break; } Point2i new_center = pos; - pos = last_mouse_pos + (pos - center); + pos = last_mouse_pos + xi.relative_motion; center = new_center; do_mouse_warp = window_has_focus; // warp the cursor if we're focused in } @@ -2066,7 +2180,24 @@ void OS_X11::process_xevents() { last_mouse_pos_valid = true; } - Point2i rel = pos - last_mouse_pos; + // Hackish but relative mouse motion is already handled in the RawMotion event. + // RawMotion does not provide the absolute mouse position (whereas MotionNotify does). + // Therefore, RawMotion cannot be the authority on absolute mouse position. + // RawMotion provides more precision than MotionNotify, which doesn't sense subpixel motion. + // Therefore, MotionNotify cannot be the authority on relative mouse motion. + // This means we need to take a combined approach... + Point2 rel; + + // Only use raw input if in capture mode. Otherwise use the classic behavior. + if (mouse_mode == MOUSE_MODE_CAPTURED) { + rel = xi.relative_motion; + } else { + rel = pos - last_mouse_pos; + } + + // Reset to prevent lingering motion + xi.relative_motion.x = 0; + xi.relative_motion.y = 0; if (mouse_mode == MOUSE_MODE_CAPTURED) { pos = Point2i(current_videomode.width / 2, current_videomode.height / 2); @@ -2075,12 +2206,16 @@ void OS_X11::process_xevents() { Ref<InputEventMouseMotion> mm; mm.instance(); + // Make the absolute position integral so it doesn't look _too_ weird :) + Point2i posi(pos); + get_key_modifier_state(event.xmotion.state, mm); - mm->set_button_mask(get_mouse_button_state(event.xmotion.state)); - mm->set_position(pos); - mm->set_global_position(pos); - input->set_mouse_position(pos); + mm->set_button_mask(get_mouse_button_state()); + mm->set_position(posi); + mm->set_global_position(posi); + input->set_mouse_position(posi); mm->set_speed(input->get_last_mouse_speed()); + mm->set_relative(rel); last_mouse_pos = pos; diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index bb8411e213..4e73c5beec 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -48,11 +48,9 @@ #include <X11/Xcursor/Xcursor.h> #include <X11/Xlib.h> +#include <X11/extensions/XInput2.h> #include <X11/extensions/Xrandr.h> #include <X11/keysym.h> -#ifdef TOUCH_ENABLED -#include <X11/extensions/XInput2.h> -#endif // Hints for X11 fullscreen typedef struct { @@ -121,23 +119,32 @@ class OS_X11 : public OS_Unix { bool im_active; Vector2 im_position; - Point2i last_mouse_pos; + Point2 last_mouse_pos; bool last_mouse_pos_valid; Point2i last_click_pos; uint64_t last_click_ms; + int last_click_button_index; uint32_t last_button_state; -#ifdef TOUCH_ENABLED + struct { int opcode; - Vector<int> devices; - XIEventMask event_mask; + Vector<int> touch_devices; + Map<int, Vector2> absolute_devices; + XIEventMask all_event_mask; + XIEventMask all_master_event_mask; Map<int, Vector2> state; Vector2 mouse_pos_to_filter; - } touch; -#endif + Vector2 relative_motion; + Vector2 raw_pos; + Vector2 old_raw_pos; + ::Time last_relative_time; + } xi; + + bool refresh_device_info(); - unsigned int get_mouse_button_state(unsigned int p_x11_state); + unsigned int get_mouse_button_state(unsigned int p_x11_button, int p_x11_type); void get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state); + void flush_mouse_motion(); MouseMode mouse_mode; Point2i center; diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 1e9f4df4a3..a869f7cfcd 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "file_dialog.h" + #include "core/os/keyboard.h" #include "core/print_string.h" #include "scene/gui/label.h" @@ -596,7 +597,7 @@ void FileDialog::set_current_file(const String &p_file) { int lp = p_file.find_last("."); if (lp != -1) { file->select(0, lp); - if (file->is_inside_tree()) + if (file->is_inside_tree() && !get_tree()->is_node_being_edited(file)) file->grab_focus(); } } diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index f621522102..82d6e6480e 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -453,7 +453,6 @@ void PopupMenu::_notification(int p_what) { Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1); - item_ofs.x += items[i].h_ofs; if (!items[i].icon.is_null()) { icon_size = items[i].icon->get_size(); @@ -470,6 +469,7 @@ void PopupMenu::_notification(int p_what) { String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].xl_text; + item_ofs.x += items[i].h_ofs; if (items[i].separator) { int sep_h = separator->get_center_size().height + separator->get_minimum_size().height; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 5b1c2d8020..b220df6ce1 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1727,6 +1727,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.mouse_focus = _gui_find_control(pos); gui.mouse_focus_mask = 1 << (mb->get_button_index() - 1); + gui.last_mouse_focus = gui.mouse_focus; if (!gui.mouse_focus) { return; @@ -2114,14 +2115,14 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { set_input_as_handled(); return; } - } else if (gui.mouse_focus) { + } else if (touch_event->get_index() == 0 && gui.last_mouse_focus) { - if (gui.mouse_focus->can_process()) { + if (gui.last_mouse_focus->can_process()) { touch_event = touch_event->xformed_by(Transform2D()); //make a copy touch_event->set_position(gui.focus_inv_xform.xform(pos)); - _gui_call_input(gui.mouse_focus, touch_event); + _gui_call_input(gui.last_mouse_focus, touch_event); } set_input_as_handled(); return; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 278350b1c9..6b6ca3b7db 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -271,6 +271,7 @@ private: bool key_event_accepted; Control *mouse_focus; + Control *last_mouse_focus; Control *mouse_click_grabber; int mouse_focus_mask; Control *key_focus; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index d7750c91ef..ae6211a3df 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -210,18 +210,18 @@ #include "scene/resources/physics_material.h" #endif -static ResourceFormatSaverText *resource_saver_text = NULL; -static ResourceFormatLoaderText *resource_loader_text = NULL; +static Ref<ResourceFormatSaverText> resource_saver_text; +static Ref<ResourceFormatLoaderText> resource_loader_text; -static ResourceFormatLoaderDynamicFont *resource_loader_dynamic_font = NULL; +static Ref<ResourceFormatLoaderDynamicFont> resource_loader_dynamic_font; -static ResourceFormatLoaderStreamTexture *resource_loader_stream_texture = NULL; -static ResourceFormatLoaderTextureLayered *resource_loader_texture_layered = NULL; +static Ref<ResourceFormatLoaderStreamTexture> resource_loader_stream_texture; +static Ref<ResourceFormatLoaderTextureLayered> resource_loader_texture_layered; -static ResourceFormatLoaderBMFont *resource_loader_bmfont = NULL; +static Ref<ResourceFormatLoaderBMFont> resource_loader_bmfont; -static ResourceFormatSaverShader *resource_saver_shader = NULL; -static ResourceFormatLoaderShader *resource_loader_shader = NULL; +static Ref<ResourceFormatSaverShader> resource_saver_shader; +static Ref<ResourceFormatLoaderShader> resource_loader_shader; void register_scene_types() { @@ -231,28 +231,28 @@ void register_scene_types() { Node::init_node_hrcr(); - resource_loader_dynamic_font = memnew(ResourceFormatLoaderDynamicFont); + resource_loader_dynamic_font.instance(); ResourceLoader::add_resource_format_loader(resource_loader_dynamic_font); - resource_loader_stream_texture = memnew(ResourceFormatLoaderStreamTexture); + resource_loader_stream_texture.instance(); ResourceLoader::add_resource_format_loader(resource_loader_stream_texture); - resource_loader_texture_layered = memnew(ResourceFormatLoaderTextureLayered); + resource_loader_texture_layered.instance(); ResourceLoader::add_resource_format_loader(resource_loader_texture_layered); - resource_saver_text = memnew(ResourceFormatSaverText); + resource_saver_text.instance(); ResourceSaver::add_resource_format_saver(resource_saver_text, true); - resource_loader_text = memnew(ResourceFormatLoaderText); + resource_loader_text.instance(); ResourceLoader::add_resource_format_loader(resource_loader_text, true); - resource_saver_shader = memnew(ResourceFormatSaverShader); + resource_saver_shader.instance(); ResourceSaver::add_resource_format_saver(resource_saver_shader, true); - resource_loader_shader = memnew(ResourceFormatLoaderShader); + resource_loader_shader.instance(); ResourceLoader::add_resource_format_loader(resource_loader_shader, true); - resource_loader_bmfont = memnew(ResourceFormatLoaderBMFont); + resource_loader_bmfont.instance(); ResourceLoader::add_resource_format_loader(resource_loader_bmfont, true); OS::get_singleton()->yield(); //may take time to init @@ -735,27 +735,37 @@ void unregister_scene_types() { clear_default_theme(); - memdelete(resource_loader_dynamic_font); - memdelete(resource_loader_stream_texture); - memdelete(resource_loader_texture_layered); + ResourceLoader::remove_resource_format_loader(resource_loader_dynamic_font); + resource_loader_dynamic_font.unref(); + + ResourceLoader::remove_resource_format_loader(resource_loader_texture_layered); + resource_loader_texture_layered.unref(); + + ResourceLoader::remove_resource_format_loader(resource_loader_stream_texture); + resource_loader_stream_texture.unref(); DynamicFont::finish_dynamic_fonts(); - if (resource_saver_text) { - memdelete(resource_saver_text); + if (resource_saver_text.is_valid()) { + ResourceSaver::remove_resource_format_saver(resource_saver_text); + resource_saver_text.unref(); } - if (resource_loader_text) { - memdelete(resource_loader_text); + if (resource_loader_text.is_valid()) { + ResourceLoader::remove_resource_format_loader(resource_loader_text); + resource_loader_text.unref(); } - if (resource_saver_shader) { - memdelete(resource_saver_shader); + if (resource_saver_shader.is_valid()) { + ResourceSaver::remove_resource_format_saver(resource_saver_shader); + resource_saver_shader.unref(); } - if (resource_loader_shader) { - memdelete(resource_loader_shader); + if (resource_loader_shader.is_valid()) { + ResourceLoader::remove_resource_format_loader(resource_loader_shader); + resource_loader_shader.unref(); } - if (resource_loader_bmfont) { - memdelete(resource_loader_bmfont); + if (resource_loader_bmfont.is_valid()) { + ResourceLoader::remove_resource_format_loader(resource_loader_bmfont); + resource_loader_bmfont.unref(); } SpatialMaterial::finish_shaders(); diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h index 96437e8982..9c41c948bd 100644 --- a/scene/resources/dynamic_font.h +++ b/scene/resources/dynamic_font.h @@ -303,6 +303,7 @@ VARIANT_ENUM_CAST(DynamicFont::SpacingType); ///////////// class ResourceFormatLoaderDynamicFont : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderDynamicFont, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/scene/resources/dynamic_font_stb.h b/scene/resources/dynamic_font_stb.h index e1ef72ea4f..c83cc1b01f 100644 --- a/scene/resources/dynamic_font_stb.h +++ b/scene/resources/dynamic_font_stb.h @@ -180,6 +180,7 @@ public: ///////////// class ResourceFormatLoaderDynamicFont : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderDynamicFont, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/scene/resources/font.h b/scene/resources/font.h index 39e66a822d..3c5e650758 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -201,6 +201,7 @@ public: }; class ResourceFormatLoaderBMFont : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderBMFont, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/scene/resources/scene_format_text.h b/scene/resources/scene_format_text.h index 8d1af2bbb2..e5ee6ae760 100644 --- a/scene/resources/scene_format_text.h +++ b/scene/resources/scene_format_text.h @@ -128,7 +128,7 @@ public: }; class ResourceFormatLoaderText : public ResourceFormatLoader { - + GDCLASS(ResourceFormatLoaderText, ResourceFormatLoader) public: static ResourceFormatLoaderText *singleton; virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); @@ -170,6 +170,7 @@ public: }; class ResourceFormatSaverText : public ResourceFormatSaver { + GDCLASS(ResourceFormatSaverText, ResourceFormatSaver) public: static ResourceFormatSaverText *singleton; virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); diff --git a/scene/resources/shader.h b/scene/resources/shader.h index c2c205237f..6804832fb9 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -100,6 +100,7 @@ public: VARIANT_ENUM_CAST(Shader::Mode); class ResourceFormatLoaderShader : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderShader, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; @@ -108,6 +109,7 @@ public: }; class ResourceFormatSaverShader : public ResourceFormatSaver { + GDCLASS(ResourceFormatSaverShader, ResourceFormatSaver) public: virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; diff --git a/scene/resources/texture.h b/scene/resources/texture.h index e9b69e9cb1..845a075015 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -236,6 +236,7 @@ public: }; class ResourceFormatLoaderStreamTexture : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderStreamTexture, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; @@ -489,6 +490,7 @@ public: }; class ResourceFormatLoaderTextureLayered : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderTextureLayered, ResourceFormatLoader) public: enum Compression { COMPRESSION_LOSSLESS, |