diff options
369 files changed, 9718 insertions, 5618 deletions
diff --git a/.travis.yml b/.travis.yml index 8aa21a4de4..371c965db4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -88,8 +88,8 @@ script: sh ./misc/travis/clang-format.sh; else if [ "$TRAVIS_OS_NAME" = "windows" ]; then - scons platform=$GODOT_TARGET progress=no verbose=yes CXX=$CXX openssl=builtin; + scons -j 2 platform=$GODOT_TARGET progress=no verbose=yes CXX=$CXX openssl=builtin; else - scons platform=$GODOT_TARGET progress=no verbose=yes bits=64 CXX=$CXX openssl=builtin; + scons -j 2 platform=$GODOT_TARGET progress=no verbose=yes bits=64 CXX=$CXX openssl=builtin; fi fi diff --git a/SConstruct b/SConstruct index f8b2d82b66..9783b3eaca 100644 --- a/SConstruct +++ b/SConstruct @@ -62,7 +62,7 @@ platform_arg = ARGUMENTS.get("platform", ARGUMENTS.get("p", False)) if (os.name == "posix"): pass elif (os.name == "nt"): - if (os.getenv("VCINSTALLDIR") == None or platform_arg == "android"): + if (os.getenv("VCINSTALLDIR") == None or platform_arg == "android" or platform_arg == "javascript"): custom_tools = ['mingw'] env_base = Environment(tools=custom_tools) @@ -288,7 +288,7 @@ if selected_platform in platform_list: if (env["warnings"] == 'yes'): print("WARNING: warnings=yes is deprecated; assuming warnings=all") - if (os.name == "nt" and os.getenv("VSINSTALLDIR")): # MSVC, needs to stand out of course + if (os.name == "nt" and os.getenv("VSINSTALLDIR") and (platform_arg == "windows" or platform_arg == "uwp")): # MSVC, needs to stand out of course disable_nonessential_warnings = ['/wd4267', '/wd4244', '/wd4305', '/wd4800'] # Truncations, narrowing conversions... if (env["warnings"] == 'extra'): env.Append(CCFLAGS=['/Wall']) # Implies /W4 diff --git a/core/SCsub b/core/SCsub index 02abaa2bb6..4c541d7269 100644 --- a/core/SCsub +++ b/core/SCsub @@ -14,9 +14,9 @@ for x in env.global_defaults: gd_inc += '#include "platform/' + x + '/globals/global_defaults.h"\n' gd_call += "\tregister_" + x + "_global_defaults();\n" -gd_cpp = '#include "global_config.h"\n' +gd_cpp = '#include "project_settings.h"\n' gd_cpp += gd_inc -gd_cpp += "void GlobalConfig::register_global_defaults() {\n" + gd_call + "\n}\n" +gd_cpp += "void ProjectSettings::register_global_defaults() {\n" + gd_call + "\n}\n" f = open("global_defaults.gen.cpp", "wb") f.write(gd_cpp) @@ -48,7 +48,7 @@ if ("SCRIPT_AES256_ENCRYPTION_KEY" in os.environ): print("Invalid AES256 encryption key, not 64 bits hex: " + e) f = open("script_encryption_key.gen.cpp", "wb") -f.write("#include \"global_config.h\"\nuint8_t script_encryption_key[32]={" + txt + "};\n") +f.write("#include \"project_settings.h\"\nuint8_t script_encryption_key[32]={" + txt + "};\n") f.close() diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index a5ec9c1afc..ce08b3f754 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "core_bind.h" -#include "core/global_config.h" +#include "core/project_settings.h" #include "geometry.h" #include "io/file_access_compressed.h" #include "io/file_access_encrypted.h" @@ -106,7 +106,7 @@ PoolStringArray _ResourceLoader::get_dependencies(const String &p_path) { bool _ResourceLoader::has(const String &p_path) { - String local_path = GlobalConfig::get_singleton()->localize_path(p_path); + String local_path = ProjectSettings::get_singleton()->localize_path(p_path); return ResourceCache::has(local_path); }; @@ -149,7 +149,7 @@ _ResourceSaver *_ResourceSaver::singleton = NULL; void _ResourceSaver::_bind_methods() { ClassDB::bind_method(D_METHOD("save", "path", "resource:Resource", "flags"), &_ResourceSaver::save, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("get_recognized_extensions", "type"), &_ResourceSaver::get_recognized_extensions); + ClassDB::bind_method(D_METHOD("get_recognized_extensions", "type:Resource"), &_ResourceSaver::get_recognized_extensions); BIND_CONSTANT(FLAG_RELATIVE_PATHS); BIND_CONSTANT(FLAG_BUNDLE_RESOURCES); @@ -998,7 +998,7 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("set_borderless_window", "borderless"), &_OS::set_borderless_window); ClassDB::bind_method(D_METHOD("get_borderless_window"), &_OS::get_borderless_window); - ClassDB::bind_method(D_METHOD("set_ime_position"), &_OS::set_ime_position); + ClassDB::bind_method(D_METHOD("set_ime_position", "position"), &_OS::set_ime_position); ClassDB::bind_method(D_METHOD("set_screen_orientation", "orientation"), &_OS::set_screen_orientation); ClassDB::bind_method(D_METHOD("get_screen_orientation"), &_OS::get_screen_orientation); @@ -1038,7 +1038,7 @@ void _OS::_bind_methods() { &_OS::get_unix_time_from_datetime); ClassDB::bind_method(D_METHOD("get_system_time_secs"), &_OS::get_system_time_secs); - ClassDB::bind_method(D_METHOD("set_icon", "icon"), &_OS::set_icon); + ClassDB::bind_method(D_METHOD("set_icon", "icon:Image"), &_OS::set_icon); ClassDB::bind_method(D_METHOD("get_exit_code"), &_OS::get_exit_code); ClassDB::bind_method(D_METHOD("set_exit_code", "code"), &_OS::set_exit_code); diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp index 0ed44b0cb7..2adc15447a 100644 --- a/core/core_string_names.cpp +++ b/core/core_string_names.cpp @@ -44,6 +44,7 @@ CoreStringNames::CoreStringNames() { _iter_next = StaticCString::create("_iter_next"); _iter_get = StaticCString::create("_iter_get"); get_rid = StaticCString::create("get_rid"); + _custom_features = StaticCString::create("_custom_features"); #ifdef TOOLS_ENABLED _sections_unfolded = StaticCString::create("_sections_unfolded"); #endif diff --git a/core/core_string_names.h b/core/core_string_names.h index 4b4f87a8f0..501185f5b7 100644 --- a/core/core_string_names.h +++ b/core/core_string_names.h @@ -61,6 +61,7 @@ public: StringName _iter_next; StringName _iter_get; StringName get_rid; + StringName _custom_features; #ifdef TOOLS_ENABLED StringName _sections_unfolded; #endif diff --git a/core/dictionary.cpp b/core/dictionary.cpp index e6d549b83d..1fe45aff94 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -200,6 +200,7 @@ uint32_t Dictionary::hash() const { Array Dictionary::keys() const { +#if 0 Array karr; karr.resize(size()); const Variant *K = NULL; @@ -208,6 +209,26 @@ Array Dictionary::keys() const { karr[idx++] = (*K); } return karr; +#else + + Array varr; + varr.resize(size()); + if (_p->variant_map.empty()) + return varr; + + int count = _p->variant_map.size(); + const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair **pairs = (const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair **)alloca(count * sizeof(HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair *)); + _p->variant_map.get_key_value_ptr_array(pairs); + + SortArray<const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair *, DictionaryPrivateSort> sort; + sort.sort(pairs, count); + + for (int i = 0; i < count; i++) { + varr[i] = pairs[i]->key; + } + + return varr; +#endif } Array Dictionary::values() const { diff --git a/core/image.cpp b/core/image.cpp index 6ab8bb6d46..50dc9c109d 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -2245,7 +2245,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("detect_alpha"), &Image::detect_alpha); ClassDB::bind_method(D_METHOD("is_invisible"), &Image::is_invisible); - ClassDB::bind_method(D_METHOD("compress", "mode"), &Image::compress); + ClassDB::bind_method(D_METHOD("compress", "mode", "source", "lossy_quality"), &Image::compress); ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress); ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed); diff --git a/core/input_map.cpp b/core/input_map.cpp index 1307c467e6..1abe019167 100644 --- a/core/input_map.cpp +++ b/core/input_map.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "input_map.h" -#include "global_config.h" +#include "project_settings.h" #include "os/keyboard.h" InputMap *InputMap::singleton = NULL; @@ -41,11 +41,11 @@ void InputMap::_bind_methods() { ClassDB::bind_method(D_METHOD("add_action", "action"), &InputMap::add_action); ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action); - ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event); - ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event); - ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event); + ClassDB::bind_method(D_METHOD("action_add_event", "action", "event:InputEvent"), &InputMap::action_add_event); + ClassDB::bind_method(D_METHOD("action_has_event", "action", "event:InputEvent"), &InputMap::action_has_event); + ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event:InputEvent"), &InputMap::action_erase_event); ClassDB::bind_method(D_METHOD("get_action_list", "action"), &InputMap::_get_action_list); - ClassDB::bind_method(D_METHOD("event_is_action", "event", "action"), &InputMap::event_is_action); + ClassDB::bind_method(D_METHOD("event_is_action", "event:InputEvent", "action"), &InputMap::event_is_action); ClassDB::bind_method(D_METHOD("load_from_globals"), &InputMap::load_from_globals); } @@ -189,7 +189,7 @@ void InputMap::load_from_globals() { input_map.clear(); List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); + ProjectSettings::get_singleton()->get_property_list(&pinfo); for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { const PropertyInfo &pi = E->get(); @@ -201,7 +201,7 @@ void InputMap::load_from_globals() { add_action(name); - Array va = GlobalConfig::get_singleton()->get(pi.name); + Array va = ProjectSettings::get_singleton()->get(pi.name); for (int i = 0; i < va.size(); i++) { @@ -281,7 +281,7 @@ void InputMap::load_default() { key->set_scancode(KEY_PAGEDOWN); action_add_event("ui_page_down", key); - //set("display/handheld/orientation", "landscape"); + //set("display/window/handheld/orientation", "landscape"); } InputMap::InputMap() { diff --git a/core/io/compression.cpp b/core/io/compression.cpp index b0f5448b6c..ca35ece8f5 100644 --- a/core/io/compression.cpp +++ b/core/io/compression.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "compression.h" -#include "global_config.h" +#include "project_settings.h" #include "os/copymem.h" #include "zip_io.h" diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index 32ea4ce096..2197b187eb 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "file_access_memory.h" -#include "global_config.h" +#include "project_settings.h" #include "map.h" #include "os/copymem.h" #include "os/dir_access.h" @@ -43,8 +43,8 @@ void FileAccessMemory::register_file(String p_name, Vector<uint8_t> p_data) { } String name; - if (GlobalConfig::get_singleton()) - name = GlobalConfig::get_singleton()->globalize_path(p_name); + if (ProjectSettings::get_singleton()) + name = ProjectSettings::get_singleton()->globalize_path(p_name); else name = p_name; //name = DirAccess::normalize_path(name); diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 50e78899fb..46457d1425 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "file_access_network.h" -#include "global_config.h" +#include "project_settings.h" #include "io/ip.h" #include "marshalls.h" #include "os/os.h" diff --git a/core/io/ip.cpp b/core/io/ip.cpp index 6c463b983c..c869bdad9b 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -240,7 +240,7 @@ void IP::_bind_methods() { ClassDB::bind_method(D_METHOD("get_resolve_item_address", "id"), &IP::get_resolve_item_address); ClassDB::bind_method(D_METHOD("erase_resolve_item", "id"), &IP::erase_resolve_item); ClassDB::bind_method(D_METHOD("get_local_addresses"), &IP::_get_local_addresses); - ClassDB::bind_method(D_METHOD("clear_cache"), &IP::clear_cache, DEFVAL("")); + ClassDB::bind_method(D_METHOD("clear_cache", "hostname"), &IP::clear_cache, DEFVAL("")); BIND_CONSTANT(RESOLVER_STATUS_NONE); BIND_CONSTANT(RESOLVER_STATUS_WAITING); diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index 93682e6b8a..81446a3886 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "packet_peer.h" -#include "global_config.h" +#include "project_settings.h" #include "io/marshalls.h" /* helpers / binders */ diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 728cd5d4ff..602cbe6f30 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "resource_format_binary.h" -#include "global_config.h" +#include "project_settings.h" #include "image.h" #include "io/file_access_compressed.h" #include "io/marshalls.h" @@ -317,7 +317,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path - path = GlobalConfig::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); + path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); } if (remaps.find(path)) { @@ -346,7 +346,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path - path = GlobalConfig::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); + path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); } RES res = ResourceLoader::load(path, type); @@ -1017,7 +1017,7 @@ Ref<ResourceInteractiveLoader> ResourceFormatLoaderBinary::load_interactive(cons } Ref<ResourceInteractiveLoaderBinary> ria = memnew(ResourceInteractiveLoaderBinary); - ria->local_path = GlobalConfig::get_singleton()->localize_path(p_path); + ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); ria->res_path = ria->local_path; //ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); ria->open(f); @@ -1065,7 +1065,7 @@ void ResourceFormatLoaderBinary::get_dependencies(const String &p_path, List<Str ERR_FAIL_COND(!f); Ref<ResourceInteractiveLoaderBinary> ria = memnew(ResourceInteractiveLoaderBinary); - ria->local_path = GlobalConfig::get_singleton()->localize_path(p_path); + ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); ria->res_path = ria->local_path; //ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); ria->get_dependencies(f, p_dependencies, p_add_types); @@ -1152,7 +1152,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons } Ref<ResourceInteractiveLoaderBinary> ria = memnew(ResourceInteractiveLoaderBinary); - ria->local_path = GlobalConfig::get_singleton()->localize_path(p_path); + ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); ria->res_path = ria->local_path; ria->remaps = p_map; //ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); @@ -1281,7 +1281,7 @@ String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const } Ref<ResourceInteractiveLoaderBinary> ria = memnew(ResourceInteractiveLoaderBinary); - ria->local_path = GlobalConfig::get_singleton()->localize_path(p_path); + ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); ria->res_path = ria->local_path; //ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); String r = ria->recognize(f); @@ -1984,7 +1984,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p Error ResourceFormatSaverBinary::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - String local_path = GlobalConfig::get_singleton()->localize_path(p_path); + String local_path = ProjectSettings::get_singleton()->localize_path(p_path); ResourceFormatSaverBinaryInstance saver; return saver.save(local_path, p_resource, p_flags); } diff --git a/core/io/resource_import.cpp b/core/io/resource_import.cpp index ffb27bc26a..61da4f3350 100644 --- a/core/io/resource_import.cpp +++ b/core/io/resource_import.cpp @@ -49,6 +49,7 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy int lines = 0; String error_text; + bool path_found = false; //first match must have priority while (true) { assign = Variant(); @@ -66,14 +67,16 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy } if (assign != String()) { - if (assign.begins_with("path.") && r_path_and_type.path == String()) { + if (!path_found && assign.begins_with("path.") && r_path_and_type.path == String()) { String feature = assign.get_slicec('.', 1); if (OS::get_singleton()->check_feature_support(feature)) { r_path_and_type.path = value; + path_found = true; //first match must have priority } - } else if (assign == "path") { + } else if (!path_found && assign == "path") { r_path_and_type.path = value; + path_found = true; //first match must have priority } else if (assign == "type") { r_path_and_type.type = value; } diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index bb7be38413..285cc6e3c2 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -28,12 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "resource_loader.h" -#include "global_config.h" #include "io/resource_import.h" #include "os/file_access.h" #include "os/os.h" #include "path_remap.h" #include "print_string.h" +#include "project_settings.h" #include "translation.h" ResourceFormatLoader *ResourceLoader::loader[MAX_LOADERS]; @@ -84,7 +84,7 @@ void ResourceLoader::get_recognized_extensions_for_type(const String &p_type, Li void ResourceInteractiveLoader::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_resource"), &ResourceInteractiveLoader::get_resource); + ClassDB::bind_method(D_METHOD("get_resource:Resource"), &ResourceInteractiveLoader::get_resource); ClassDB::bind_method(D_METHOD("poll"), &ResourceInteractiveLoader::poll); ClassDB::bind_method(D_METHOD("wait"), &ResourceInteractiveLoader::wait); ClassDB::bind_method(D_METHOD("get_stage"), &ResourceInteractiveLoader::get_stage); @@ -166,7 +166,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p if (p_path.is_rel_path()) local_path = "res://" + p_path; else - local_path = GlobalConfig::get_singleton()->localize_path(p_path); + local_path = ProjectSettings::get_singleton()->localize_path(p_path); bool xl_remapped = false; String path = _path_remap(local_path, &xl_remapped); @@ -233,7 +233,7 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ if (p_path.is_rel_path()) local_path = "res://" + p_path; else - local_path = GlobalConfig::get_singleton()->localize_path(p_path); + local_path = ProjectSettings::get_singleton()->localize_path(p_path); bool xl_remapped = false; String path = _path_remap(local_path, &xl_remapped); @@ -304,7 +304,7 @@ void ResourceLoader::get_dependencies(const String &p_path, List<String> *p_depe if (path.is_rel_path()) local_path = "res://" + path; else - local_path = GlobalConfig::get_singleton()->localize_path(path); + local_path = ProjectSettings::get_singleton()->localize_path(path); for (int i = 0; i < loader_count; i++) { @@ -327,7 +327,7 @@ Error ResourceLoader::rename_dependencies(const String &p_path, const Map<String if (path.is_rel_path()) local_path = "res://" + path; else - local_path = GlobalConfig::get_singleton()->localize_path(path); + local_path = ProjectSettings::get_singleton()->localize_path(path); for (int i = 0; i < loader_count; i++) { @@ -350,7 +350,7 @@ String ResourceLoader::get_resource_type(const String &p_path) { if (p_path.is_rel_path()) local_path = "res://" + p_path; else - local_path = GlobalConfig::get_singleton()->localize_path(p_path); + local_path = ProjectSettings::get_singleton()->localize_path(p_path); for (int i = 0; i < loader_count; i++) { @@ -430,7 +430,7 @@ void ResourceLoader::reload_translation_remaps() { void ResourceLoader::load_translation_remaps() { - Dictionary remaps = GlobalConfig::get_singleton()->get("locale/translation_remaps"); + Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps"); List<Variant> keys; remaps.get_key_list(&keys); for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 8592346a72..58913b80cc 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "resource_saver.h" -#include "global_config.h" +#include "project_settings.h" #include "os/file_access.h" #include "resource_loader.h" #include "script_language.h" @@ -64,7 +64,7 @@ Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t String old_path = p_resource->get_path(); - String local_path = GlobalConfig::get_singleton()->localize_path(p_path); + String local_path = ProjectSettings::get_singleton()->localize_path(p_path); RES rwcopy = p_resource; if (p_flags & FLAG_CHANGE_PATH) diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp index 29a80ecc19..4c891188ee 100644 --- a/core/io/tcp_server.cpp +++ b/core/io/tcp_server.cpp @@ -49,7 +49,7 @@ void TCP_Server::_bind_methods() { ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &TCP_Server::listen, DEFVAL("*")); ClassDB::bind_method(D_METHOD("is_connection_available"), &TCP_Server::is_connection_available); - ClassDB::bind_method(D_METHOD("take_connection"), &TCP_Server::take_connection); + ClassDB::bind_method(D_METHOD("take_connection:StreamPeerTCP"), &TCP_Server::take_connection); ClassDB::bind_method(D_METHOD("stop"), &TCP_Server::stop); } diff --git a/core/message_queue.cpp b/core/message_queue.cpp index 1c980a56e3..93d0b0730a 100644 --- a/core/message_queue.cpp +++ b/core/message_queue.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "message_queue.h" -#include "global_config.h" +#include "project_settings.h" #include "script_language.h" MessageQueue *MessageQueue::singleton = NULL; diff --git a/core/method_ptrcall.h b/core/method_ptrcall.h index c6dbfc2a7a..ead58c23c8 100644 --- a/core/method_ptrcall.h +++ b/core/method_ptrcall.h @@ -60,37 +60,37 @@ struct PtrToArg { } \ } -#define MAKE_PTRARGR(m_type, m_ret) \ - template <> \ - struct PtrToArg<m_type> { \ - _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ - return *reinterpret_cast<const m_type *>(p_ptr); \ - } \ - _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ - *((m_ret *)p_ptr) = p_val; \ - } \ - }; \ - template <> \ - struct PtrToArg<const m_type &> { \ - _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ - return *reinterpret_cast<const m_type *>(p_ptr); \ - } \ - _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ - *((m_ret *)p_ptr) = p_val; \ - } \ +#define MAKE_PTRARGCONV(m_type, m_conv) \ + template <> \ + struct PtrToArg<m_type> { \ + _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ + return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \ + } \ + _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ + *((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \ + } \ + }; \ + template <> \ + struct PtrToArg<const m_type &> { \ + _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ + return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \ + } \ + _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ + *((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \ + } \ } MAKE_PTRARG(bool); -MAKE_PTRARGR(uint8_t, int); -MAKE_PTRARGR(int8_t, int); -MAKE_PTRARGR(uint16_t, int); -MAKE_PTRARGR(int16_t, int); -MAKE_PTRARGR(uint32_t, int); -MAKE_PTRARGR(int32_t, int); -MAKE_PTRARGR(int64_t, int); -MAKE_PTRARGR(uint64_t, int); -MAKE_PTRARG(float); -MAKE_PTRARGR(double, float); +MAKE_PTRARGCONV(uint8_t, int64_t); +MAKE_PTRARGCONV(int8_t, int64_t); +MAKE_PTRARGCONV(uint16_t, int64_t); +MAKE_PTRARGCONV(int16_t, int64_t); +MAKE_PTRARGCONV(uint32_t, int64_t); +MAKE_PTRARGCONV(int32_t, int64_t); +MAKE_PTRARG(int64_t); +MAKE_PTRARG(uint64_t); +MAKE_PTRARGCONV(float, double); +MAKE_PTRARG(double); MAKE_PTRARG(String); MAKE_PTRARG(Vector2); diff --git a/core/object.cpp b/core/object.cpp index 9184fb9cd0..316c624268 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -993,6 +993,17 @@ void Object::cancel_delete() { _predelete_ok = true; } +void Object::set_script_and_instance(const RefPtr &p_script, ScriptInstance *p_instance) { + + //this function is not meant to be used in any of these ways + ERR_FAIL_COND(p_script.is_null()); + ERR_FAIL_COND(!p_instance); + ERR_FAIL_COND(script_instance != NULL || !script.is_null()); + + script = p_script; + script_instance = p_instance; +} + void Object::set_script(const RefPtr &p_script) { if (script == p_script) @@ -1723,7 +1734,7 @@ void Object::_bind_methods() { BIND_VMETHOD(MethodInfo("_set", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value"))); #ifdef TOOLS_ENABLED MethodInfo miget("_get", PropertyInfo(Variant::STRING, "property")); - miget.return_val.name = "var"; + miget.return_val.name = "Variant"; BIND_VMETHOD(miget); MethodInfo plget("_get_property_list"); diff --git a/core/object.h b/core/object.h index 556f3f1586..148a73fbc4 100644 --- a/core/object.h +++ b/core/object.h @@ -651,6 +651,8 @@ public: void set_script_instance(ScriptInstance *p_instance); _FORCE_INLINE_ ScriptInstance *get_script_instance() const { return script_instance; } + void set_script_and_instance(const RefPtr &p_script, ScriptInstance *p_instance); //some script languages can't control instance creation, so this function eases the process + void add_user_signal(const MethodInfo &p_signal); void emit_signal(const StringName &p_name, VARIANT_ARG_LIST); void emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount); diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index aa03b764ef..484942bad5 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "dir_access.h" -#include "global_config.h" +#include "project_settings.h" #include "os/file_access.h" #include "os/memory.h" #include "os/os.h" @@ -37,7 +37,7 @@ String DirAccess::_get_root_path() const { switch (_access_type) { - case ACCESS_RESOURCES: return GlobalConfig::get_singleton()->get_resource_path(); + case ACCESS_RESOURCES: return ProjectSettings::get_singleton()->get_resource_path(); case ACCESS_USERDATA: return OS::get_singleton()->get_data_dir(); default: return ""; } @@ -200,10 +200,10 @@ String DirAccess::fix_path(String p_path) const { case ACCESS_RESOURCES: { - if (GlobalConfig::get_singleton()) { + if (ProjectSettings::get_singleton()) { if (p_path.begins_with("res://")) { - String resource_path = GlobalConfig::get_singleton()->get_resource_path(); + String resource_path = ProjectSettings::get_singleton()->get_resource_path(); if (resource_path != "") { return p_path.replace_first("res:/", resource_path); diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index 805b66b983..2bb676381f 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -31,7 +31,7 @@ #include "core/io/file_access_pack.h" #include "core/io/marshalls.h" -#include "global_config.h" +#include "project_settings.h" #include "os/os.h" #include "thirdparty/misc/md5.h" @@ -135,10 +135,10 @@ String FileAccess::fix_path(const String &p_path) const { case ACCESS_RESOURCES: { - if (GlobalConfig::get_singleton()) { + if (ProjectSettings::get_singleton()) { if (r_path.begins_with("res://")) { - String resource_path = GlobalConfig::get_singleton()->get_resource_path(); + String resource_path = ProjectSettings::get_singleton()->get_resource_path(); if (resource_path != "") { return r_path.replace("res:/", resource_path); diff --git a/core/os/input.cpp b/core/os/input.cpp index bc388d0bca..18d644668c 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "input.h" -#include "global_config.h" +#include "project_settings.h" #include "input_map.h" #include "os/os.h" Input *Input::singleton = NULL; @@ -84,7 +84,7 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("action_press", "action"), &Input::action_press); ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release); ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image:Texture", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(Vector2())); - ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event); + ClassDB::bind_method(D_METHOD("parse_input_event", "event:InputEvent"), &Input::parse_input_event); BIND_CONSTANT(MOUSE_MODE_VISIBLE); BIND_CONSTANT(MOUSE_MODE_HIDDEN); @@ -101,7 +101,7 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released")) { List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); + ProjectSettings::get_singleton()->get_property_list(&pinfo); for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { const PropertyInfo &pi = E->get(); diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index 1c575aa970..0a07b6b2b7 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -103,7 +103,7 @@ bool InputEvent::is_action_type() const { if (String(p_method) == "is_action" && p_argidx == 0) { List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); + ProjectSettings::get_singleton()->get_property_list(&pinfo); for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { const PropertyInfo &pi = E->get(); diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp index 248f5537c6..93658c07c2 100644 --- a/core/os/main_loop.cpp +++ b/core/os/main_loop.cpp @@ -32,7 +32,7 @@ void MainLoop::_bind_methods() { - ClassDB::bind_method(D_METHOD("input_event", "ev"), &MainLoop::input_event); + ClassDB::bind_method(D_METHOD("input_event", "ev:InputEvent"), &MainLoop::input_event); ClassDB::bind_method(D_METHOD("input_text", "text"), &MainLoop::input_text); ClassDB::bind_method(D_METHOD("init"), &MainLoop::init); ClassDB::bind_method(D_METHOD("iteration", "delta"), &MainLoop::iteration); diff --git a/core/os/os.cpp b/core/os/os.cpp index 48463722cf..5a9766891d 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -30,9 +30,9 @@ #include "os.h" #include "dir_access.h" -#include "global_config.h" #include "input.h" #include "os/file_access.h" +#include "project_settings.h" #include <stdarg.h> @@ -260,7 +260,7 @@ String OS::get_locale() const { String OS::get_resource_dir() const { - return GlobalConfig::get_singleton()->get_resource_path(); + return ProjectSettings::get_singleton()->get_resource_path(); } String OS::get_system_dir(SystemDir p_dir) const { @@ -269,7 +269,7 @@ String OS::get_system_dir(SystemDir p_dir) const { } String OS::get_safe_application_name() const { - String an = GlobalConfig::get_singleton()->get("application/config/name"); + String an = ProjectSettings::get_singleton()->get("application/config/name"); Vector<String> invalid_char = String("\\ / : * ? \" < > |").split(" "); for (int i = 0; i < invalid_char.size(); i++) { an = an.replace(invalid_char[i], "-"); @@ -494,6 +494,24 @@ int OS::get_power_percent_left() { return -1; } +bool OS::check_feature_support(const String &p_feature) { + + if (p_feature == get_name()) + return true; +#ifdef DEBUG_ENABLED + if (p_feature == "debug") + return true; +#else + if (p_feature == "release") + return true; +#endif + + if (_check_internal_feature_support(p_feature)) + return true; + + return false; +} + OS::OS() { last_error = NULL; singleton = this; diff --git a/core/os/os.h b/core/os/os.h index cafd1f4e14..362fec8a9e 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -109,6 +109,7 @@ protected: virtual void set_cmdline(const char *p_execpath, const List<String> &p_args); void _ensure_data_dir(); + virtual bool _check_internal_feature_support(const String &p_feature) = 0; public: typedef int64_t ProcessID; @@ -408,7 +409,7 @@ public: virtual int get_power_seconds_left(); virtual int get_power_percent_left(); - virtual bool check_feature_support(const String &p_feature) = 0; + bool check_feature_support(const String &p_feature); bool is_hidpi_allowed() const { return _allow_hidpi; } OS(); diff --git a/core/global_config.cpp b/core/project_settings.cpp index 95f4ec5e22..0426af3fa0 100644 --- a/core/global_config.cpp +++ b/core/project_settings.cpp @@ -27,9 +27,10 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "global_config.h" +#include "project_settings.h" #include "bind/core_bind.h" +#include "core_string_names.h" #include "io/file_access_network.h" #include "io/file_access_pack.h" #include "io/marshalls.h" @@ -38,24 +39,23 @@ #include "os/keyboard.h" #include "os/os.h" #include "variant_parser.h" - #include <zlib.h> #define FORMAT_VERSION 3 -GlobalConfig *GlobalConfig::singleton = NULL; +ProjectSettings *ProjectSettings::singleton = NULL; -GlobalConfig *GlobalConfig::get_singleton() { +ProjectSettings *ProjectSettings::get_singleton() { return singleton; } -String GlobalConfig::get_resource_path() const { +String ProjectSettings::get_resource_path() const { return resource_path; }; -String GlobalConfig::localize_path(const String &p_path) const { +String ProjectSettings::localize_path(const String &p_path) const { if (resource_path == "") return p_path; //not initialied yet @@ -99,13 +99,13 @@ String GlobalConfig::localize_path(const String &p_path) const { }; } -void GlobalConfig::set_initial_value(const String &p_name, const Variant &p_value) { +void ProjectSettings::set_initial_value(const String &p_name, const Variant &p_value) { ERR_FAIL_COND(!props.has(p_name)); props[p_name].initial = p_value; } -String GlobalConfig::globalize_path(const String &p_path) const { +String ProjectSettings::globalize_path(const String &p_path) const { if (p_path.begins_with("res://")) { @@ -119,13 +119,44 @@ String GlobalConfig::globalize_path(const String &p_path) const { return p_path; } -bool GlobalConfig::_set(const StringName &p_name, const Variant &p_value) { +bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) { _THREAD_SAFE_METHOD_ if (p_value.get_type() == Variant::NIL) props.erase(p_name); else { + + if (p_name == CoreStringNames::get_singleton()->_custom_features) { + Vector<String> custom_feature_array = p_value; + for (int i = 0; i < custom_feature_array.size(); i++) { + + custom_features.insert(custom_feature_array[i]); + } + return true; + } + + if (!disable_feature_overrides) { + int dot = p_name.operator String().find("."); + if (dot != -1) { + Vector<String> s = p_name.operator String().split("."); + + bool override_valid = false; + for (int i = 1; i < s.size(); i++) { + String feature = s[i].strip_edges(); + if (OS::get_singleton()->check_feature_support(feature) || custom_features.has(feature)) { + override_valid = true; + break; + } + } + + if (override_valid) { + + feature_overrides[s[0]] = p_name; + } + } + } + if (props.has(p_name)) { if (!props[p_name].overrided) props[p_name].variant = p_value; @@ -137,15 +168,19 @@ bool GlobalConfig::_set(const StringName &p_name, const Variant &p_value) { return true; } -bool GlobalConfig::_get(const StringName &p_name, Variant &r_ret) const { +bool ProjectSettings::_get(const StringName &p_name, Variant &r_ret) const { _THREAD_SAFE_METHOD_ - if (!props.has(p_name)) { - print_line("WARNING: not found: " + String(p_name)); + StringName name = p_name; + if (!disable_feature_overrides && feature_overrides.has(name)) { + name = feature_overrides[name]; + } + if (!props.has(name)) { + print_line("WARNING: not found: " + String(name)); return false; } - r_ret = props[p_name].variant; + r_ret = props[name].variant; return true; } @@ -159,7 +194,7 @@ struct _VCSort { bool operator<(const _VCSort &p_vcs) const { return order == p_vcs.order ? name < p_vcs.name : order < p_vcs.order; } }; -void GlobalConfig::_get_property_list(List<PropertyInfo> *p_list) const { +void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const { _THREAD_SAFE_METHOD_ @@ -186,8 +221,13 @@ void GlobalConfig::_get_property_list(List<PropertyInfo> *p_list) const { for (Set<_VCSort>::Element *E = vclist.front(); E; E = E->next()) { - if (custom_prop_info.has(E->get().name)) { - PropertyInfo pi = custom_prop_info[E->get().name]; + String prop_info_name = E->get().name; + int dot = prop_info_name.find("."); + if (dot != -1) + prop_info_name = prop_info_name.substr(0, dot); + + if (custom_prop_info.has(prop_info_name)) { + PropertyInfo pi = custom_prop_info[prop_info_name]; pi.name = E->get().name; pi.usage = E->get().flags; p_list->push_back(pi); @@ -196,7 +236,7 @@ void GlobalConfig::_get_property_list(List<PropertyInfo> *p_list) const { } } -bool GlobalConfig::_load_resource_pack(const String &p_pack) { +bool ProjectSettings::_load_resource_pack(const String &p_pack) { if (PackedData::get_singleton()->is_disabled()) return false; @@ -213,13 +253,13 @@ bool GlobalConfig::_load_resource_pack(const String &p_pack) { return true; } -Error GlobalConfig::setup(const String &p_path, const String &p_main_pack) { +Error ProjectSettings::setup(const String &p_path, const String &p_main_pack) { //If looking for files in network, just use network! if (FileAccessNetworkClient::get_singleton()) { - if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://godot.cfb") == OK) { + if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://project.binary") == OK) { _load_settings("res://override.cfg"); } @@ -236,7 +276,7 @@ Error GlobalConfig::setup(const String &p_path, const String &p_main_pack) { bool ok = _load_resource_pack(p_main_pack); ERR_FAIL_COND_V(!ok, ERR_CANT_OPEN); - if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://godot.cfb") == OK) { + if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://project.binary") == OK) { //load override from location of the main pack _load_settings(p_main_pack.get_base_dir().plus_file("override.cfg")); } @@ -249,7 +289,7 @@ Error GlobalConfig::setup(const String &p_path, const String &p_main_pack) { if (_load_resource_pack(exec_path.get_basename() + ".pck")) { - if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://godot.cfb") == OK) { + if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://project.binary") == OK) { //load override from location of executable _load_settings(exec_path.get_base_dir().plus_file("override.cfg")); } @@ -270,7 +310,7 @@ Error GlobalConfig::setup(const String &p_path, const String &p_main_pack) { // data.pck and data.zip are deprecated and no longer supported, apologies. // make sure this is loaded from the resource path - if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://godot.cfb") == OK) { + if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://project.binary") == OK) { _load_settings("res://override.cfg"); } @@ -291,7 +331,7 @@ Error GlobalConfig::setup(const String &p_path, const String &p_main_pack) { while (true) { //try to load settings in ascending through dirs shape! - if (_load_settings(current_dir + "/project.godot") == OK || _load_settings_binary(current_dir + "/godot.cfb") == OK) { + if (_load_settings(current_dir + "/project.godot") == OK || _load_settings_binary(current_dir + "/project.binary") == OK) { _load_settings(current_dir + "/override.cfg"); candidate = current_dir; @@ -318,19 +358,19 @@ Error GlobalConfig::setup(const String &p_path, const String &p_main_pack) { return OK; } -bool GlobalConfig::has(String p_var) const { +bool ProjectSettings::has(String p_var) const { _THREAD_SAFE_METHOD_ return props.has(p_var); } -void GlobalConfig::set_registering_order(bool p_enable) { +void ProjectSettings::set_registering_order(bool p_enable) { registering_order = p_enable; } -Error GlobalConfig::_load_settings_binary(const String p_path) { +Error ProjectSettings::_load_settings_binary(const String p_path) { Error err; FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); @@ -343,7 +383,7 @@ Error GlobalConfig::_load_settings_binary(const String p_path) { if (hdr[0] != 'E' || hdr[1] != 'C' || hdr[2] != 'F' || hdr[3] != 'G') { memdelete(f); - ERR_EXPLAIN("Corrupted header in binary godot.cfb (not ECFG)"); + ERR_EXPLAIN("Corrupted header in binary project.binary (not ECFG)"); ERR_FAIL_V(ERR_FILE_CORRUPT;) } @@ -372,7 +412,7 @@ Error GlobalConfig::_load_settings_binary(const String p_path) { return OK; } -Error GlobalConfig::_load_settings(const String p_path) { +Error ProjectSettings::_load_settings(const String p_path) { Error err; FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); @@ -403,7 +443,7 @@ Error GlobalConfig::_load_settings(const String p_path) { memdelete(f); return OK; } else if (err != OK) { - ERR_PRINTS("GlobalConfig::load - " + p_path + ":" + itos(lines) + " error: " + error_text); + ERR_PRINTS("ProjectSettings::load - " + p_path + ":" + itos(lines) + " error: " + error_text); memdelete(f); return err; } @@ -427,19 +467,19 @@ Error GlobalConfig::_load_settings(const String p_path) { return OK; } -int GlobalConfig::get_order(const String &p_name) const { +int ProjectSettings::get_order(const String &p_name) const { ERR_FAIL_COND_V(!props.has(p_name), -1); return props[p_name].order; } -void GlobalConfig::set_order(const String &p_name, int p_order) { +void ProjectSettings::set_order(const String &p_name, int p_order) { ERR_FAIL_COND(!props.has(p_name)); props[p_name].order = p_order; } -void GlobalConfig::set_builtin_order(const String &p_name) { +void ProjectSettings::set_builtin_order(const String &p_name) { ERR_FAIL_COND(!props.has(p_name)); if (props[p_name].order >= NO_BUILTIN_ORDER_BASE) { @@ -447,24 +487,24 @@ void GlobalConfig::set_builtin_order(const String &p_name) { } } -void GlobalConfig::clear(const String &p_name) { +void ProjectSettings::clear(const String &p_name) { ERR_FAIL_COND(!props.has(p_name)); props.erase(p_name); } -Error GlobalConfig::save() { +Error ProjectSettings::save() { return save_custom(get_resource_path() + "/project.godot"); } -Error GlobalConfig::_save_settings_binary(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom) { +Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom, const String &p_custom_features) { Error err; FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err); if (err != OK) { - ERR_EXPLAIN("Couldn't save godot.cfb at " + p_file); + ERR_EXPLAIN("Couldn't save project.binary at " + p_file); ERR_FAIL_COND_V(err, err) } @@ -481,7 +521,34 @@ Error GlobalConfig::_save_settings_binary(const String &p_file, const Map<String } } - file->store_32(count); //store how many properties are saved + if (p_custom_features != String()) { + file->store_32(count + 1); + //store how many properties are saved, add one for custom featuers, which must always go first + String key = CoreStringNames::get_singleton()->_custom_features; + file->store_32(key.length()); + file->store_string(key); + + int len; + Error err = encode_variant(p_custom_features, NULL, len); + if (err != OK) { + memdelete(file); + ERR_FAIL_V(err); + } + + Vector<uint8_t> buff; + buff.resize(len); + + err = encode_variant(p_custom_features, &buff[0], len); + if (err != OK) { + memdelete(file); + ERR_FAIL_V(err); + } + file->store_32(len); + file->store_buffer(buff.ptr(), buff.size()); + + } else { + file->store_32(count); //store how many properties are saved + } for (Map<String, List<String> >::Element *E = props.front(); E; E = E->next()) { @@ -523,7 +590,7 @@ Error GlobalConfig::_save_settings_binary(const String &p_file, const Map<String return OK; } -Error GlobalConfig::_save_settings_text(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom) { +Error ProjectSettings::_save_settings_text(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom, const String &p_custom_features) { Error err; FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err); @@ -534,6 +601,9 @@ Error GlobalConfig::_save_settings_text(const String &p_file, const Map<String, } file->store_string("config_version=" + itos(FORMAT_VERSION) + "\n"); + if (p_custom_features != String()) + file->store_string("custom_features=\"" + p_custom_features + "\"\n"); + file->store_string("\n"); for (Map<String, List<String> >::Element *E = props.front(); E; E = E->next()) { @@ -565,12 +635,12 @@ Error GlobalConfig::_save_settings_text(const String &p_file, const Map<String, return OK; } -Error GlobalConfig::_save_custom_bnd(const String &p_file) { // add other params as dictionary and array? +Error ProjectSettings::_save_custom_bnd(const String &p_file) { // add other params as dictionary and array? return save_custom(p_file); }; -Error GlobalConfig::save_custom(const String &p_path, const CustomMap &p_custom, const Set<String> &p_ignore_masks) { +Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_custom, const Vector<String> &p_custom_features) { ERR_FAIL_COND_V(p_path == "", ERR_INVALID_PARAMETER); @@ -586,19 +656,6 @@ Error GlobalConfig::save_custom(const String &p_path, const CustomMap &p_custom, if (p_custom.has(G->key())) continue; - bool discard = false; - - for (const Set<String>::Element *E = p_ignore_masks.front(); E; E = E->next()) { - - if (String(G->key()).match(E->get())) { - discard = true; - break; - } - } - - if (discard) - continue; - _VCSort vc; vc.name = G->key(); //*k; vc.order = v->order; @@ -639,10 +696,20 @@ Error GlobalConfig::save_custom(const String &p_path, const CustomMap &p_custom, props[category].push_back(name); } + String custom_features; + + for (int i = 0; i < p_custom_features.size(); i++) { + if (i > 0) + custom_features += ","; + + String f = p_custom_features[i].strip_edges().replace("\"", ""); + custom_features += f; + } + if (p_path.ends_with(".godot")) - return _save_settings_text(p_path, props, p_custom); - else if (p_path.ends_with(".cfb")) - return _save_settings_binary(p_path, props, p_custom); + return _save_settings_text(p_path, props, p_custom, custom_features); + else if (p_path.ends_with(".binary")) + return _save_settings_binary(p_path, props, p_custom, custom_features); else { ERR_EXPLAIN("Unknown config file format: " + p_path); @@ -695,24 +762,24 @@ Error GlobalConfig::save_custom(const String &p_path, const CustomMap &p_custom, Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default) { Variant ret; - if (GlobalConfig::get_singleton()->has(p_var)) { - ret = GlobalConfig::get_singleton()->get(p_var); + if (ProjectSettings::get_singleton()->has(p_var)) { + ret = ProjectSettings::get_singleton()->get(p_var); } else { - GlobalConfig::get_singleton()->set(p_var, p_default); + ProjectSettings::get_singleton()->set(p_var, p_default); ret = p_default; } - GlobalConfig::get_singleton()->set_initial_value(p_var, p_default); - GlobalConfig::get_singleton()->set_builtin_order(p_var); + ProjectSettings::get_singleton()->set_initial_value(p_var, p_default); + ProjectSettings::get_singleton()->set_builtin_order(p_var); return ret; } -void GlobalConfig::add_singleton(const Singleton &p_singleton) { +void ProjectSettings::add_singleton(const Singleton &p_singleton) { singletons.push_back(p_singleton); singleton_ptrs[p_singleton.name] = p_singleton.ptr; } -Object *GlobalConfig::get_singleton_object(const String &p_name) const { +Object *ProjectSettings::get_singleton_object(const String &p_name) const { const Map<StringName, Object *>::Element *E = singleton_ptrs.find(p_name); if (!E) @@ -721,21 +788,21 @@ Object *GlobalConfig::get_singleton_object(const String &p_name) const { return E->get(); }; -bool GlobalConfig::has_singleton(const String &p_name) const { +bool ProjectSettings::has_singleton(const String &p_name) const { return get_singleton_object(p_name) != NULL; }; -void GlobalConfig::get_singletons(List<Singleton> *p_singletons) { +void ProjectSettings::get_singletons(List<Singleton> *p_singletons) { for (List<Singleton>::Element *E = singletons.front(); E; E = E->next()) p_singletons->push_back(E->get()); } -Vector<String> GlobalConfig::get_optimizer_presets() const { +Vector<String> ProjectSettings::get_optimizer_presets() const { List<PropertyInfo> pi; - GlobalConfig::get_singleton()->get_property_list(&pi); + ProjectSettings::get_singleton()->get_property_list(&pi); Vector<String> names; for (List<PropertyInfo>::Element *E = pi.front(); E; E = E->next()) { @@ -750,7 +817,7 @@ Vector<String> GlobalConfig::get_optimizer_presets() const { return names; } -void GlobalConfig::_add_property_info_bind(const Dictionary &p_info) { +void ProjectSettings::_add_property_info_bind(const Dictionary &p_info) { ERR_FAIL_COND(!p_info.has("name")); ERR_FAIL_COND(!p_info.has("type")); @@ -769,24 +836,24 @@ void GlobalConfig::_add_property_info_bind(const Dictionary &p_info) { set_custom_property_info(pinfo.name, pinfo); } -void GlobalConfig::set_custom_property_info(const String &p_prop, const PropertyInfo &p_info) { +void ProjectSettings::set_custom_property_info(const String &p_prop, const PropertyInfo &p_info) { ERR_FAIL_COND(!props.has(p_prop)); custom_prop_info[p_prop] = p_info; custom_prop_info[p_prop].name = p_prop; } -void GlobalConfig::set_disable_platform_override(bool p_disable) { +void ProjectSettings::set_disable_feature_overrides(bool p_disable) { - disable_platform_override = p_disable; + disable_feature_overrides = p_disable; } -bool GlobalConfig::is_using_datapack() const { +bool ProjectSettings::is_using_datapack() const { return using_datapack; } -bool GlobalConfig::property_can_revert(const String &p_name) { +bool ProjectSettings::property_can_revert(const String &p_name) { if (!props.has(p_name)) return false; @@ -794,7 +861,7 @@ bool GlobalConfig::property_can_revert(const String &p_name) { return props[p_name].initial != props[p_name].variant; } -Variant GlobalConfig::property_get_revert(const String &p_name) { +Variant ProjectSettings::property_get_revert(const String &p_name) { if (!props.has(p_name)) return Variant(); @@ -802,32 +869,32 @@ Variant GlobalConfig::property_get_revert(const String &p_name) { return props[p_name].initial; } -void GlobalConfig::_bind_methods() { - - ClassDB::bind_method(D_METHOD("has", "name"), &GlobalConfig::has); - ClassDB::bind_method(D_METHOD("set_order", "name", "pos"), &GlobalConfig::set_order); - ClassDB::bind_method(D_METHOD("get_order", "name"), &GlobalConfig::get_order); - ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &GlobalConfig::set_initial_value); - ClassDB::bind_method(D_METHOD("add_property_info", "hint"), &GlobalConfig::_add_property_info_bind); - ClassDB::bind_method(D_METHOD("clear", "name"), &GlobalConfig::clear); - ClassDB::bind_method(D_METHOD("localize_path", "path"), &GlobalConfig::localize_path); - ClassDB::bind_method(D_METHOD("globalize_path", "path"), &GlobalConfig::globalize_path); - ClassDB::bind_method(D_METHOD("save"), &GlobalConfig::save); - ClassDB::bind_method(D_METHOD("has_singleton", "name"), &GlobalConfig::has_singleton); - ClassDB::bind_method(D_METHOD("get_singleton", "name"), &GlobalConfig::get_singleton_object); - ClassDB::bind_method(D_METHOD("load_resource_pack", "pack"), &GlobalConfig::_load_resource_pack); - ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &GlobalConfig::property_can_revert); - ClassDB::bind_method(D_METHOD("property_get_revert:Variant", "name"), &GlobalConfig::property_get_revert); - - ClassDB::bind_method(D_METHOD("save_custom", "file"), &GlobalConfig::_save_custom_bnd); +void ProjectSettings::_bind_methods() { + + ClassDB::bind_method(D_METHOD("has", "name"), &ProjectSettings::has); + ClassDB::bind_method(D_METHOD("set_order", "name", "pos"), &ProjectSettings::set_order); + ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order); + ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value); + ClassDB::bind_method(D_METHOD("add_property_info", "hint"), &ProjectSettings::_add_property_info_bind); + ClassDB::bind_method(D_METHOD("clear", "name"), &ProjectSettings::clear); + ClassDB::bind_method(D_METHOD("localize_path", "path"), &ProjectSettings::localize_path); + ClassDB::bind_method(D_METHOD("globalize_path", "path"), &ProjectSettings::globalize_path); + ClassDB::bind_method(D_METHOD("save"), &ProjectSettings::save); + ClassDB::bind_method(D_METHOD("has_singleton", "name"), &ProjectSettings::has_singleton); + ClassDB::bind_method(D_METHOD("get_singleton", "name"), &ProjectSettings::get_singleton_object); + ClassDB::bind_method(D_METHOD("load_resource_pack", "pack"), &ProjectSettings::_load_resource_pack); + ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &ProjectSettings::property_can_revert); + ClassDB::bind_method(D_METHOD("property_get_revert:Variant", "name"), &ProjectSettings::property_get_revert); + + ClassDB::bind_method(D_METHOD("save_custom", "file"), &ProjectSettings::_save_custom_bnd); } -GlobalConfig::GlobalConfig() { +ProjectSettings::ProjectSettings() { singleton = this; last_order = NO_BUILTIN_ORDER_BASE; last_builtin_order = 0; - disable_platform_override = false; + disable_feature_overrides = false; registering_order = true; Array va; @@ -945,11 +1012,13 @@ GlobalConfig::GlobalConfig() { GLOBAL_DEF("input/ui_page_down", va); input_presets.push_back("input/ui_page_down"); - //GLOBAL_DEF("display/handheld/orientation", "landscape"); + //GLOBAL_DEF("display/window/handheld/orientation", "landscape"); custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::STRING, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor"); custom_prop_info["rendering/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded"); custom_prop_info["physics/2d/thread_model"] = PropertyInfo(Variant::INT, "physics/2d/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded"); + custom_prop_info["rendering/quality/intended_usage/framebuffer_allocation"] = PropertyInfo(Variant::INT, "rendering/quality/intended_usage/framebuffer_allocation", PROPERTY_HINT_ENUM, "2D,2D Without Sampling,3D,3D Without Effects"); + GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_mode", 2); GLOBAL_DEF("debug/settings/profiler/max_functions", 16384); @@ -964,7 +1033,7 @@ GlobalConfig::GlobalConfig() { using_datapack = false; } -GlobalConfig::~GlobalConfig() { +ProjectSettings::~ProjectSettings() { singleton = NULL; } diff --git a/core/global_config.h b/core/project_settings.h index 30c77bbc27..278d4b8132 100644 --- a/core/global_config.h +++ b/core/project_settings.h @@ -37,9 +37,9 @@ @author Juan Linietsky <reduzio@gmail.com> */ -class GlobalConfig : public Object { +class ProjectSettings : public Object { - GDCLASS(GlobalConfig, Object); + GDCLASS(ProjectSettings, Object); _THREAD_SAFE_CLASS_ public: @@ -53,13 +53,12 @@ public: ptr = p_ptr; } }; - -protected: enum { //properties that are not for built in values begin from this value, so builtin ones are displayed first NO_BUILTIN_ORDER_BASE = 1 << 16 }; +protected: struct VariantContainer { int order; bool persist; @@ -88,21 +87,24 @@ protected: Map<StringName, VariantContainer> props; String resource_path; Map<StringName, PropertyInfo> custom_prop_info; - bool disable_platform_override; + bool disable_feature_overrides; bool using_datapack; List<String> input_presets; + Set<String> custom_features; + Map<StringName, StringName> feature_overrides; + bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; - static GlobalConfig *singleton; + static ProjectSettings *singleton; Error _load_settings(const String p_path); Error _load_settings_binary(const String p_path); - Error _save_settings_text(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom = CustomMap()); - Error _save_settings_binary(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom = CustomMap()); + Error _save_settings_text(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String()); + Error _save_settings_binary(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String()); List<Singleton> singletons; Map<StringName, Object *> singleton_ptrs; @@ -127,7 +129,7 @@ public: String get_resource_path() const; - static GlobalConfig *get_singleton(); + static ProjectSettings *get_singleton(); void clear(const String &p_name); int get_order(const String &p_name) const; @@ -136,7 +138,7 @@ public: Error setup(const String &p_path, const String &p_main_pack); - Error save_custom(const String &p_path = "", const CustomMap &p_custom = CustomMap(), const Set<String> &p_ignore_masks = Set<String>()); + Error save_custom(const String &p_path = "", const CustomMap &p_custom = CustomMap(), const Vector<String> &p_custom_features = Vector<String>()); Error save(); void set_custom_property_info(const String &p_prop, const PropertyInfo &p_info); @@ -149,7 +151,7 @@ public: List<String> get_input_presets() const { return input_presets; } - void set_disable_platform_override(bool p_disable); + void set_disable_feature_overrides(bool p_disable); Object *get_singleton_object(const String &p_name) const; void register_global_defaults(); @@ -158,13 +160,13 @@ public: void set_registering_order(bool p_registering); - GlobalConfig(); - ~GlobalConfig(); + ProjectSettings(); + ~ProjectSettings(); }; //not a macro any longer Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default); #define GLOBAL_DEF(m_var, m_value) _GLOBAL_DEF(m_var, m_value) -#define GLOBAL_GET(m_var) GlobalConfig::get_singleton()->get(m_var) +#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var) #endif diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index d6a521a86f..07715f9718 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -36,7 +36,7 @@ #include "core_string_names.h" #include "func_ref.h" #include "geometry.h" -#include "global_config.h" +#include "project_settings.h" #include "input_map.h" #include "io/config_file.h" #include "io/http_client.h" @@ -177,18 +177,18 @@ void register_core_settings() { void register_core_singletons() { - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("GlobalConfig", GlobalConfig::get_singleton())); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("IP", IP::get_singleton())); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("Geometry", _Geometry::get_singleton())); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("ResourceLoader", _ResourceLoader::get_singleton())); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("ResourceSaver", _ResourceSaver::get_singleton())); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("OS", _OS::get_singleton())); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("Engine", _Engine::get_singleton())); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("ClassDB", _classdb)); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("Marshalls", _Marshalls::get_singleton())); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("TranslationServer", TranslationServer::get_singleton())); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("Input", Input::get_singleton())); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("InputMap", InputMap::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("ProjectSettings", ProjectSettings::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("IP", IP::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("Geometry", _Geometry::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("ResourceLoader", _ResourceLoader::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("ResourceSaver", _ResourceSaver::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("OS", _OS::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("Engine", _Engine::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("ClassDB", _classdb)); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("Marshalls", _Marshalls::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("TranslationServer", TranslationServer::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("Input", Input::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("InputMap", InputMap::get_singleton())); } void unregister_core_types() { diff --git a/core/resource.cpp b/core/resource.cpp index a7a5498ef6..5625784396 100644 --- a/core/resource.cpp +++ b/core/resource.cpp @@ -31,7 +31,6 @@ #include "core_string_names.h" #include "io/resource_loader.h" -#include "io/resource_loader.h" #include "os/file_access.h" #include "script_language.h" #include <stdio.h> @@ -340,7 +339,7 @@ void Resource::_bind_methods() { ClassDB::bind_method(D_METHOD("get_local_scene:Node"), &Resource::get_local_scene); ClassDB::bind_method(D_METHOD("setup_local_to_scene"), &Resource::setup_local_to_scene); - ClassDB::bind_method(D_METHOD("duplicate", "subresources"), &Resource::duplicate, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("duplicate:Resource", "subresources"), &Resource::duplicate, DEFVAL(false)); ADD_SIGNAL(MethodInfo("changed")); ADD_GROUP("Resource", "resource_"); ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "resource_local_to_scene"), "set_local_to_scene", "is_local_to_scene"); diff --git a/core/safe_refcount.cpp b/core/safe_refcount.cpp index 1bd16f9e4f..d7e5297321 100644 --- a/core/safe_refcount.cpp +++ b/core/safe_refcount.cpp @@ -55,7 +55,7 @@ static _ALWAYS_INLINE_ T _atomic_decrement_impl(register T *pw) { } template <class T> -static _ALWAYS_INLINE_T _atomic_increment_impl(register T *pw) { +static _ALWAYS_INLINE_ T _atomic_increment_impl(register T *pw) { (*pw)++; @@ -71,7 +71,7 @@ static _ALWAYS_INLINE_ T _atomic_sub_impl(register T *pw, register T val) { } template <class T> -static _ALWAYS_INLINE_T _atomic_add_impl(register T *pw, register T val) { +static _ALWAYS_INLINE_ T _atomic_add_impl(register T *pw, register T val) { (*pw) += val; @@ -185,7 +185,7 @@ static _ALWAYS_INLINE_ uint64_t _atomic_increment_impl(register uint64_t *pw) { static _ALWAYS_INLINE_ uint64_t _atomic_sub_impl(register uint64_t *pw, register uint64_t val) { -#if _WIN32_WINNT >= 0x0601 // Windows 7+ +#if _WIN32_WINNT >= 0x0601 && !defined(UWP_ENABLED) // Windows 7+ except UWP return InterlockedExchangeSubtract64(pw, val) - val; #else return InterlockedExchangeAdd64((LONGLONG volatile *)pw, -(int64_t)val) - val; diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 7fc151d83f..a7b6f25590 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "script_debugger_remote.h" -#include "global_config.h" +#include "project_settings.h" #include "io/ip.h" #include "os/input.h" #include "os/os.h" @@ -130,7 +130,7 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue) ERR_FAIL(); } - OS::get_singleton()->enable_for_stealing_focus(GlobalConfig::get_singleton()->get("editor_pid")); + OS::get_singleton()->enable_for_stealing_focus(ProjectSettings::get_singleton()->get("editor_pid")); packet_peer_stream->put_var("debug_enter"); packet_peer_stream->put_var(2); @@ -952,7 +952,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() { phl.userdata = this; add_print_handler(&phl); requested_quit = false; - performance = GlobalConfig::get_singleton()->get_singleton_object("Performance"); + performance = ProjectSettings::get_singleton()->get_singleton_object("Performance"); last_perf_time = 0; poll_every = 0; request_scene_tree = NULL; @@ -967,7 +967,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() { eh.userdata = this; add_error_handler(&eh); - profile_info.resize(CLAMP(int(GlobalConfig::get_singleton()->get("debug/settings/profiler/max_functions")), 128, 65535)); + profile_info.resize(CLAMP(int(ProjectSettings::get_singleton()->get("debug/settings/profiler/max_functions")), 128, 65535)); profile_info_ptrs.resize(profile_info.size()); profiling = false; max_frame_functions = 16; diff --git a/core/script_language.cpp b/core/script_language.cpp index 4a7fdc9d64..aeb1573840 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -99,6 +99,13 @@ void ScriptServer::init_languages() { } } +void ScriptServer::finish_languages() { + + for (int i = 0; i < _language_count; i++) { + _languages[i]->finish(); + } +} + void ScriptServer::set_reload_scripts_on_save(bool p_enable) { reload_scripts_on_save = p_enable; diff --git a/core/script_language.h b/core/script_language.h index a81300233f..7aba3ec0f1 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -69,6 +69,7 @@ public: static void thread_exit(); static void init_languages(); + static void finish_languages(); }; class ScriptInstance; diff --git a/core/translation.cpp b/core/translation.cpp index 72231ef295..d782006ddc 100644 --- a/core/translation.cpp +++ b/core/translation.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "translation.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" #include "os/os.h" @@ -1053,8 +1053,8 @@ TranslationServer *TranslationServer::singleton = NULL; bool TranslationServer::_load_translations(const String &p_from) { - if (GlobalConfig::get_singleton()->has(p_from)) { - PoolVector<String> translations = GlobalConfig::get_singleton()->get(p_from); + if (ProjectSettings::get_singleton()->has(p_from)) { + PoolVector<String> translations = ProjectSettings::get_singleton()->get(p_from); int tcount = translations.size(); @@ -1095,7 +1095,7 @@ void TranslationServer::setup() { options += locale_list[idx]; idx++; } - GlobalConfig::get_singleton()->set_custom_property_info("locale/fallback", PropertyInfo(Variant::STRING, "locale/fallback", PROPERTY_HINT_ENUM, options)); + ProjectSettings::get_singleton()->set_custom_property_info("locale/fallback", PropertyInfo(Variant::STRING, "locale/fallback", PROPERTY_HINT_ENUM, options)); } #endif //load translations diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp index 26a6a05a30..398f20caf3 100644 --- a/core/variant_parser.cpp +++ b/core/variant_parser.cpp @@ -1099,7 +1099,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, return OK; - } else if (id == "PoolFloatArray" || id == "FloatArray") { + } else if (id == "PoolRealArray" || id == "FloatArray") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -1855,7 +1855,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::POOL_REAL_ARRAY: { - p_store_string_func(p_store_string_ud, "PoolFloatArray( "); + p_store_string_func(p_store_string_ud, "PoolRealArray( "); PoolVector<real_t> data = p_variant; int len = data.size(); PoolVector<real_t>::Read r = data.read(); diff --git a/doc/base/classes.xml b/doc/base/classes.xml index caf86bc6e8..2075f30b36 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -752,7 +752,7 @@ <member name="Geometry" type="Geometry" setter="" getter="" brief=""> [Geometry] singleton </member> - <member name="GlobalConfig" type="GlobalConfig" setter="" getter="" brief=""> + <member name="ProjectSettings" type="ProjectSettings" setter="" getter="" brief=""> </member> <member name="IP" type="IP" setter="" getter="" brief=""> [IP] singleton @@ -4763,7 +4763,13 @@ <argument index="0" name="value" type="var"> </argument> <description> - Return true if the array contains given value. [code][ "inside", 7 ].has("inside") == true, [ "inside", 7 ].has("outside") == false, [ "inside", 7 ].has(7) == true, [ "inside", 7 ].has("7") == false[/code] + Return true if the array contains given value. + [codeblock] + [ "inside", 7 ].has("inside") == true + [ "inside", 7 ].has("outside") == false + [ "inside", 7 ].has(7) == true + [ "inside", 7 ].has("7") == false + [/codeblock] </description> </method> <method name="hash"> @@ -11496,7 +11502,7 @@ <return type="Vector2"> </return> <description> - Returns the size of the Control, computed from all margins, however the size returned will [b]never be smaller than the minimum size reported by [method get_minimum_size][/b]. This means that even if end position of the Control rectangle is smaller than the begin position, the Control will still display and interact correctly. (see description, [method get_minimum_size], [method set_margin], [method set_anchor]). + Returns the size of the Control, computed from all margins, however the size returned will [b]never be smaller than the minimum size reported by[/b] [method get_minimum_size]. This means that even if end position of the Control rectangle is smaller than the begin position, the Control will still display and interact correctly. (see description, [method get_minimum_size], [method set_margin], [method set_anchor]). </description> </method> <method name="get_stretch_ratio" qualifiers="const"> @@ -14134,6 +14140,8 @@ <argument index="1" name="event" type="InputEvent"> </argument> <description> + Implement this function if you are interested in 3D view screen input events. It will be called only if currently selected node is handled by your plugin. + If you would like to always gets those input events then additionally use [method set_input_forwarding_always_enabled]. </description> </method> <method name="get_base_control"> @@ -14157,6 +14165,13 @@ Get the general settings for the editor (the same window that appears in the Settings menu). </description> </method> + <method name="get_edited_scene_root"> + <return type="Node"> + </return> + <description> + Returns root node of currently edited scene. + </description> + </method> <method name="get_editor_viewport"> <return type="Control"> </return> @@ -14171,6 +14186,13 @@ Get the name of the editor plugin. For main scren plugins this is what will appear in the selector (which by default is 2D, 3D, Script). </description> </method> + <method name="get_open_scenes"> + <return type="Array"> + </return> + <description> + Will return an Array of Strings which represent file paths to currently open scenes. + </description> + </method> <method name="get_resource_filesystem"> <return type="EditorFileSystem"> </return> @@ -14185,6 +14207,13 @@ Get tool for generating resource previews. </description> </method> + <method name="get_script_editor"> + <return type="ScriptEditor"> + </return> + <description> + Will return ScriptEditor object which contains informations about state of the scripts which are currently open by the editor. + </description> + </method> <method name="get_selection"> <return type="EditorSelection"> </return> @@ -14309,6 +14338,7 @@ </method> <method name="set_input_event_forwarding_always_enabled"> <description> + Use this method if you always want to receive inputs from 3D view screen inside [method forward_spatial_gui_input]. It might be especially usable if your plugin will want to use raycast in the scene. </description> </method> <method name="set_state" qualifiers="virtual"> @@ -14365,6 +14395,29 @@ <constant name="DOCK_SLOT_MAX" value="8"> </constant> </constants> + <signals> + <signal name="main_screen_changed"> + <argument index="0" name="screen_name" type="String"> + </argument> + <description> + Emitted when user change main screen view (2D, 3D, Script, AssetLib). Works also with screens which are defined by plugins. + </description> + </signal> + <signal name="scene_changed"> + <argument index="0" name="scene_root" type="Node"> + </argument> + <description> + Emitted when user change scene. The argument is a root node of freshly opened scene. + </description> + </signal> + <signal name="scene_closed"> + <argument index="0" name="filepath" type="String"> + </argument> + <description> + Emitted when user close scene. The argument is file path to a closed scene. + </description> + </signal> + </signals> </class> <class name="EditorResourcePreview" inherits="Node" category="Core"> <brief_description> @@ -17738,7 +17791,7 @@ </constant> </constants> </class> -<class name="GlobalConfig" inherits="Object" category="Core"> +<class name="ProjectSettings" inherits="Object" category="Core"> <brief_description> Contains global variables accessible from everywhere. </brief_description> @@ -28709,7 +28762,7 @@ UDP packet peer. </brief_description> <description> - UDP packet peer. Can be used to send raw UDP packets as well as [Variant]s. + UDP packet peer. Can be used to send raw UDP packets as well as [Variant]\ s. </description> <methods> <method name="close"> @@ -30635,7 +30688,7 @@ collider_id: Id of the object the point is in. collider: Object the point is inside of. rid: [RID] of the object the point is in. - Additionally, the method can take an array of objects or [RID]s that are to be excluded from collisions, a bitmask representing the physics layers to check in, and another bitmask for the types of objects to check (see TYPE_MASK_* constants). + Additionally, the method can take an array of objects or [RID]\ s that are to be excluded from collisions, a bitmask representing the physics layers to check in, and another bitmask for the types of objects to check (see TYPE_MASK_* constants). </description> </method> <method name="intersect_ray"> @@ -30661,7 +30714,7 @@ collider: Object against which the ray was stopped. rid: [RID] of the object against which the ray was stopped. If the ray did not intersect anything, then an empty dictionary (dir.empty()==true) is returned instead. - Additionally, the method can take an array of objects or [RID]s that are to be excluded from collisions, a bitmask representing the physics layers to check in, and another bitmask for the types of objects to check (see TYPE_MASK_* constants). + Additionally, the method can take an array of objects or [RID]\ s that are to be excluded from collisions, a bitmask representing the physics layers to check in, and another bitmask for the types of objects to check (see TYPE_MASK_* constants). </description> </method> <method name="intersect_shape"> @@ -31752,7 +31805,7 @@ <return type="Array"> </return> <description> - Return the list of objects, or object [RID]s, that will be excluded from collisions. + Return the list of objects, or object [RID]\ s, that will be excluded from collisions. </description> </method> <method name="get_margin" qualifiers="const"> @@ -31801,7 +31854,7 @@ <argument index="0" name="exclude" type="Array"> </argument> <description> - Set the list of objects, or object [RID]s, that will be excluded from collisions. + Set the list of objects, or object [RID]\ s, that will be excluded from collisions. </description> </method> <method name="set_margin"> @@ -40041,6 +40094,44 @@ <constants> </constants> </class> +<class name="ScriptEditor" inherits="PanelContainer" category="Core"> + <brief_description> + </brief_description> + <description> + </description> + <methods> + <method name="get_current_script"> + <return type="Script"> + </return> + <description> + Returns a [Script] that is currently active in editor. + </description> + </method> + <method name="get_open_scripts"> + <return type="Array"> + </return> + <description> + Returns an array with all [Script] objects which are currently open in editor. + </description> + </method> + </methods> + <signals> + <signal name="editor_script_changed"> + <argument index="0" name="script" type="Script"> + </argument> + <description> + Emitted when user changed active script. Argument is a freshly activated [Script]. + </description> + </signal> + <signal name="script_close"> + <argument index="0" name="script" type="Script"> + </argument> + <description> + Emitted when editor is about to close the active script. Argument is a [Script] that is going to be closed. + </description> + </signal> + </signals> +</class> <class name="SegmentShape2D" inherits="Shape2D" category="Core"> <brief_description> Segment Shape for 2D Collision Detection. @@ -44981,6 +45072,15 @@ <description> </description> </method> + <method name="get_tab_rect"> + <return type="Rect2"> + </return> + <argument index="0" name="tab_idx" type="int"> + </argument> + <description> + Returns tab [Rect2] with local position and size. + </description> + </method> <method name="get_tab_title" qualifiers="const"> <return type="String"> </return> @@ -44989,6 +45089,15 @@ <description> </description> </method> + <method name="move_tab"> + <argument index="0" name="from" type="int"> + </argument> + <argument index="1" name="to" type="int"> + </argument> + <description> + Rearrange tab. + </description> + </method> <method name="remove_tab"> <argument index="0" name="tab_idx" type="int"> </argument> @@ -46328,7 +46437,7 @@ A unit of execution in a process. </brief_description> <description> - A unit of execution in a process. Can run methods on [Object]s simultaneously. The use of synchronization via [Mutex], [Semaphore] is advised if working with shared objects. + A unit of execution in a process. Can run methods on [Object]\ s simultaneously. The use of synchronization via [Mutex], [Semaphore] is advised if working with shared objects. </description> <methods> <method name="get_id" qualifiers="const"> @@ -49319,7 +49428,7 @@ Helper to manage UndoRedo in the editor or custom tools. </brief_description> <description> - Helper to maange UndoRedo in the editor or custom tools. It works by storing calls to functions in both 'do' an 'undo' lists. + Helper to manage UndoRedo in the editor or custom tools. It works by storing calls to functions in both 'do' an 'undo' lists. Common behavior is to create an action, then add do/undo calls to functions or property changes, then committing the action. </description> <methods> @@ -49372,13 +49481,12 @@ <argument index="0" name="object" type="Object"> </argument> <description> - Add an 'undo' reference that will be erased if the 'undo' history is lost. This is useful mostly for nodes rmoved with the 'do' call (not the 'undo' call!). + Add an 'undo' reference that will be erased if the 'undo' history is lost. This is useful mostly for nodes removed with the 'do' call (not the 'undo' call!). </description> </method> <method name="clear_history"> <description> - Clear the undo/redo history and associated - references. + Clear the undo/redo history and associated references. </description> </method> <method name="commit_action"> @@ -49392,8 +49500,7 @@ <argument index="1" name="merge_mode" type="int" default="0"> </argument> <description> - Create a new action. After this is called, do all your calls to [method add_do_method], [method add_undo_method], [method add_do_property] and [method add_un -do_property]. + Create a new action. After this is called, do all your calls to [method add_do_method], [method add_undo_method], [method add_do_property] and [method add_undo_property]. </description> </method> <method name="get_current_action_name" qualifiers="const"> @@ -50753,7 +50860,7 @@ do_property]. <argument index="0" name="xform" type="Transform2D"> </argument> <description> - Set the canvas transform of the viewport, useful for changing the on-screen positions of all child [CanvasItem]s. This is relative to the global canvas transform of the viewport. + Set the canvas transform of the viewport, useful for changing the on-screen positions of all child [CanvasItem]\ s. This is relative to the global canvas transform of the viewport. </description> </method> <method name="set_clear_on_new_frame"> diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py index 8a117f6450..696e3c9c78 100644 --- a/doc/tools/makerst.py +++ b/doc/tools/makerst.py @@ -172,6 +172,7 @@ def rstize_text(text, cclass): pos += 1 # Handle [tags] + inside_code = False pos = 0 while True: pos = text.find('[', pos) @@ -191,7 +192,18 @@ def rstize_text(text, cclass): else: # command cmd = tag_text space_pos = tag_text.find(' ') - if cmd.find('html') == 0: + if cmd == '/codeblock': + tag_text = '' + inside_code = False + # Strip newline if the tag was alone on one + if pre_text[-1] == '\n': + pre_text = pre_text[:-1] + elif cmd == '/code': + tag_text = '``' + inside_code = False + elif inside_code: + tag_text = '[' + tag_text + ']' + elif cmd.find('html') == 0: cmd = tag_text[:space_pos] param = tag_text[space_pos + 1:] tag_text = param @@ -216,11 +228,7 @@ def rstize_text(text, cclass): tag_text = '' elif cmd == 'codeblock': tag_text = '\n::\n' - elif cmd == '/codeblock': - tag_text = '' - # Strip newline if the tag was alone on one - if pre_text[-1] == '\n': - pre_text = pre_text[:-1] + inside_code = True elif cmd == 'br': # Make a new paragraph instead of a linebreak, rst is not so linebreak friendly tag_text = '\n\n' @@ -233,10 +241,11 @@ def rstize_text(text, cclass): tag_text = '**' elif cmd == 'u' or cmd == '/u': tag_text = '' - elif cmd == 'code' or cmd == '/code': + elif cmd == 'code': tag_text = '``' + inside_code = True else: - tag_text = ':ref:`' + tag_text + '<class_' + tag_text.lower() + '>`' + tag_text = make_type(tag_text) text = pre_text + tag_text + post_text pos = len(pre_text) + len(tag_text) diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index b32d540380..4e6739e8c0 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.cpp @@ -31,7 +31,7 @@ #ifdef ALSA_ENABLED -#include "global_config.h" +#include "project_settings.h" #include <errno.h> diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index e854abb6a1..2abdbe9d0a 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -31,8 +31,8 @@ #include "rasterizer_gles2.h" #include "gl_context/context_gl.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" #include "servers/visual/particle_system_sw.h" #include "servers/visual/shader_language.h" #include <stdio.h> @@ -3942,7 +3942,7 @@ void RasterizerGLES2::begin_frame() { //fragment_lighting=Globals::get_singleton()->get("rasterizer/use_fragment_lighting"); #ifdef TOOLS_ENABLED canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/use_2d_pixel_snap", false)); - shadow_filter = ShadowFilterTechnique(int(GlobalConfig::get_singleton()->get("rasterizer/shadow_filter"))); + shadow_filter = ShadowFilterTechnique(int(ProjectSettings::get_singleton()->get("rasterizer/shadow_filter"))); #endif canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_PCF5, shadow_filter == SHADOW_FILTER_PCF5); @@ -6819,7 +6819,7 @@ void RasterizerGLES2::end_scene() { if (current_env->bg_mode == VS::ENV_BG_COLOR) bgcolor = current_env->bg_param[VS::ENV_BG_PARAM_COLOR]; else - bgcolor = GlobalConfig::get_singleton()->get("render/default_clear_color"); + bgcolor = ProjectSettings::get_singleton()->get("render/default_clear_color"); bgcolor = _convert_color(bgcolor); float a = use_fb ? float(current_env->bg_param[VS::ENV_BG_PARAM_GLOW]) : 1.0; glClearColor(bgcolor.r, bgcolor.g, bgcolor.b, a); @@ -10718,7 +10718,7 @@ RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays, bool p_keep_ram_copy, b fragment_lighting = GLOBAL_DEF("rasterizer/use_fragment_lighting", true); read_depth_supported = true; //todo check for extension shadow_filter = ShadowFilterTechnique((int)(GLOBAL_DEF("rasterizer/shadow_filter", SHADOW_FILTER_PCF5))); - GlobalConfig::get_singleton()->set_custom_property_info("rasterizer/shadow_filter", PropertyInfo(Variant::INT, "rasterizer/shadow_filter", PROPERTY_HINT_ENUM, "None,PCF5,PCF13,ESM")); + ProjectSettings::get_singleton()->set_custom_property_info("rasterizer/shadow_filter", PropertyInfo(Variant::INT, "rasterizer/shadow_filter", PROPERTY_HINT_ENUM, "None,PCF5,PCF13,ESM")); use_fp16_fb = bool(GLOBAL_DEF("rasterizer/fp16_framebuffer", true)); use_shadow_mapping = true; use_fast_texture_filter = !bool(GLOBAL_DEF("rasterizer/trilinear_mipmap_filter", true)); diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 98e55c5a53..56d9f2cc47 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "rasterizer_canvas_gles3.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" #include "rasterizer_scene_gles3.h" #include "servers/visual/visual_server_raster.h" #ifndef GLES_OVER_GL diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 233095dec2..bb7b85e653 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -30,8 +30,8 @@ #include "rasterizer_gles3.h" #include "gl_context/context_gl.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" #include <string.h> RasterizerStorage *RasterizerGLES3::get_storage() { @@ -186,6 +186,9 @@ void RasterizerGLES3::initialize() { GL_DEBUG_SEVERITY_HIGH_ARB,5, "hello"); */ + + const GLubyte *renderer = glGetString(GL_RENDERER); + print_line("OpenGL ES 3.0 Renderer: " + String((const char *)renderer)); storage->initialize(); canvas->initialize(); scene->initialize(); @@ -336,6 +339,10 @@ void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Re glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, rt->color); + //glBindTexture(GL_TEXTURE_2D, rt->effects.mip_maps[0].color); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); + canvas->draw_generic_textured_rect(p_screen_rect, Rect2(0, 0, 1, -1)); glBindTexture(GL_TEXTURE_2D, 0); canvas->canvas_end(); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index b7547f53a8..21bdb217fc 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "rasterizer_scene_gles3.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" #include "rasterizer_canvas_gles3.h" #ifndef GLES_OVER_GL @@ -521,13 +521,7 @@ void RasterizerSceneGLES3::reflection_atlas_set_size(RID p_ref_atlas, int p_size glBindTexture(GL_TEXTURE_2D, reflection_atlas->color); int mmsize = reflection_atlas->size; - - for (int i = 0; i < 6; i++) { - glTexImage2D(GL_TEXTURE_2D, i, internal_format, mmsize, mmsize, 0, - format, type, NULL); - - mmsize >>= 1; - } + glTexStorage2DCustom(GL_TEXTURE_2D, 6, internal_format, mmsize, mmsize, format, type); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -537,8 +531,6 @@ void RasterizerSceneGLES3::reflection_atlas_set_size(RID p_ref_atlas, int p_size glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5); - mmsize = reflection_atlas->size; - for (int i = 0; i < 6; i++) { glGenFramebuffers(1, &reflection_atlas->fbo[i]); glBindFramebuffer(GL_FRAMEBUFFER, reflection_atlas->fbo[i]); @@ -1251,36 +1243,36 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m if (t->render_target) t->render_target->used_in_frame = true; - if (storage->config.srgb_decode_supported) { - //if SRGB decode extension is present, simply switch the texture to whathever is needed - bool must_srgb = false; + target = t->target; + tex = t->tex_id; + } - if (t->srgb && (texture_hints[i] == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || texture_hints[i] == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO)) { - must_srgb = true; - } + glBindTexture(target, tex); + + if (t && storage->config.srgb_decode_supported) { + //if SRGB decode extension is present, simply switch the texture to whathever is needed + bool must_srgb = false; - if (t->using_srgb != must_srgb) { - if (must_srgb) { - glTexParameteri(t->target, _TEXTURE_SRGB_DECODE_EXT, _DECODE_EXT); + if (t->srgb && (texture_hints[i] == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || texture_hints[i] == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO)) { + must_srgb = true; + } + + if (t->using_srgb != must_srgb) { + if (must_srgb) { + glTexParameteri(t->target, _TEXTURE_SRGB_DECODE_EXT, _DECODE_EXT); #ifdef TOOLS_ENABLED - if (t->detect_srgb) { - t->detect_srgb(t->detect_srgb_ud); - } + if (t->detect_srgb) { + t->detect_srgb(t->detect_srgb_ud); + } #endif - } else { - glTexParameteri(t->target, _TEXTURE_SRGB_DECODE_EXT, _SKIP_DECODE_EXT); - } - t->using_srgb = must_srgb; + } else { + glTexParameteri(t->target, _TEXTURE_SRGB_DECODE_EXT, _SKIP_DECODE_EXT); } + t->using_srgb = must_srgb; } - - target = t->target; - tex = t->tex_id; } - glBindTexture(target, tex); - if (i == 0) { state.current_main_tex = tex; } @@ -1962,6 +1954,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS, true); state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING, false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_VERTEX_LIGHTING, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL, false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW, false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4, false); @@ -1972,6 +1965,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_CONTACT_SHADOWS, false); //state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true); } else { @@ -1979,7 +1973,10 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, e->instance->gi_probe_instances.size() > 0); state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS, false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING, !p_directional_add); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_VERTEX_LIGHTING, (e->sort_key & SORT_KEY_VERTEX_LIT_FLAG)); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL, false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW, false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4, false); @@ -1988,6 +1985,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, use_radiance_map); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_CONTACT_SHADOWS, state.used_contact_shadows); if (p_directional_add || (directional_light && (e->sort_key & SORT_KEY_NO_DIRECTIONAL_FLAG) == 0)) { state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL, true); @@ -2136,6 +2134,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5, false); state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_CONTACT_SHADOWS, false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_VERTEX_LIGHTING, false); } void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, int p_material, bool p_shadow) { @@ -2281,6 +2281,11 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G e->sort_key |= SORT_KEY_UNSHADED_FLAG; } + + if (!shadow && (m->shader->spatial.uses_vertex_lighting || storage->config.force_vertex_shading)) { + + e->sort_key |= SORT_KEY_VERTEX_LIT_FLAG; + } } void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_scale, float p_energy) { @@ -2912,7 +2917,19 @@ void RasterizerSceneGLES3::_setup_reflections(RID *p_reflection_probe_cull_resul glBindBufferBase(GL_UNIFORM_BUFFER, 6, state.reflection_array_ubo); } -void RasterizerSceneGLES3::_copy_screen() { +void RasterizerSceneGLES3::_copy_screen(bool p_invalidate_color, bool p_invalidate_depth) { + +#ifndef GLES_OVER_GL + if (p_invalidate_color) { + + GLenum attachments[2] = { + GL_COLOR_ATTACHMENT0, + GL_DEPTH_STENCIL_ATTACHMENT + }; + + glInvalidateFramebuffer(GL_FRAMEBUFFER, p_invalidate_depth ? 2 : 1, attachments); + } +#endif glBindVertexArray(storage->resources.quadie_array); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -3080,7 +3097,7 @@ void RasterizerSceneGLES3::_blur_effect_buffer() { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); //previous level, since mipmaps[0] starts one level bigger glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[1].sizes[i].fbo); - _copy_screen(); + _copy_screen(true); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_HORIZONTAL, false); //vertical pass @@ -3091,7 +3108,7 @@ void RasterizerSceneGLES3::_blur_effect_buffer() { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[1].color); glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[i + 1].fbo); //next level, since mipmaps[0] starts one level bigger - _copy_screen(); + _copy_screen(true); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_VERTICAL, false); } } @@ -3139,7 +3156,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.ssao.depth_mipmap_fbos[i]); //copy to front first glViewport(0, 0, ss[0], ss[1]); - _copy_screen(); + _copy_screen(true); } ss[0] = storage->frame.current_rt->width; ss[1] = storage->frame.current_rt->height; @@ -3191,7 +3208,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ Color white(1, 1, 1, 1); glClearBufferfv(GL_COLOR, 0, white.components); // specular - _copy_screen(); + _copy_screen(true); //do the batm, i mean blur @@ -3212,7 +3229,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ if (i == 0) { glClearBufferfv(GL_COLOR, 0, white.components); // specular } - _copy_screen(); + _copy_screen(true); } } @@ -3229,7 +3246,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.ssao.blur_red[0]); //previous level, since mipmaps[0] starts one level bigger glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); // copy to base level - _copy_screen(); + _copy_screen(true); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::SSAO_MERGE, false); } else { @@ -3278,14 +3295,14 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //copy to front first - _copy_screen(); + _copy_screen(true); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::DIR, Vector2(0, 1)); glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); // copy to base level - _copy_screen(); + _copy_screen(true); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); //restore filter glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -3337,7 +3354,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[1].sizes[0].fbo); glViewport(0, 0, ssr_w, ssr_h); - _copy_screen(); + _copy_screen(true); glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); } @@ -3368,7 +3385,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_ONE, GL_ONE); //use additive to accumulate one over the other - _copy_screen(); + _copy_screen(true); glDisable(GL_BLEND); //end additive @@ -3392,7 +3409,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); - _copy_screen(); + _copy_screen(true); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::SIMPLE_COPY, false); } @@ -3413,13 +3430,16 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p //copy specular to front buffer //copy diffuse to effect buffer - glReadBuffer(GL_COLOR_ATTACHMENT0); - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); - glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + if (storage->frame.current_rt->buffers.active) { + //transfer to effect buffer if using buffers, also resolve MSAA + glReadBuffer(GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); + glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT, GL_NEAREST); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + } if (!env || storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { //no environment or transparent render, simply return and convert to SRGB @@ -3431,7 +3451,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]); storage->shaders.copy.bind(); - _copy_screen(); + _copy_screen(true); storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, false); storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); //compute luminance @@ -3487,7 +3507,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //copy to front first - _copy_screen(); + _copy_screen(true); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); @@ -3574,7 +3594,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->buffers.diffuse); } - _copy_screen(); + _copy_screen(true); if (composite_from != storage->frame.current_rt->buffers.diffuse) { @@ -3614,7 +3634,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p glBindFramebuffer(GL_FRAMEBUFFER, exposure_shrink[0].fbo); glViewport(0, 0, exposure_shrink_size, exposure_shrink_size); - _copy_screen(); + _copy_screen(true); //second step, shrink to 2x2 pixels state.exposure_shader.set_conditional(ExposureShaderGLES3::EXPOSURE_BEGIN, false); @@ -3658,7 +3678,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p state.exposure_shader.set_uniform(ExposureShaderGLES3::MAX_LUMINANCE, env->auto_exposure_max); state.exposure_shader.set_uniform(ExposureShaderGLES3::MIN_LUMINANCE, env->auto_exposure_min); - _copy_screen(); + _copy_screen(true); state.exposure_shader.set_conditional(ExposureShaderGLES3::EXPOSURE_FORCE_SET, false); state.exposure_shader.set_conditional(ExposureShaderGLES3::EXPOSURE_END, false); @@ -3729,7 +3749,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); //previous level, since mipmaps[0] starts one level bigger } glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[1].sizes[i].fbo); - _copy_screen(); + _copy_screen(true); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GLOW_GAUSSIAN_HORIZONTAL, false); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GLOW_FIRST_PASS, false); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GLOW_USE_AUTO_EXPOSURE, false); @@ -3837,7 +3857,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p state.tonemap_shader.set_uniform(TonemapShaderGLES3::BCS, Vector3(env->adjustments_brightness, env->adjustments_contrast, env->adjustments_saturation)); } - _copy_screen(); + _copy_screen(true, true); //turn off everything used state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_AUTO_EXPOSURE, false); @@ -3913,7 +3933,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const state.used_contact_shadows = true; - if (storage->frame.current_rt && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { //detect with state.used_contact_shadows too + if (!storage->config.no_depth_prepass && storage->frame.current_rt && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { //detect with state.used_contact_shadows too //pre z pass glDisable(GL_BLEND); @@ -3927,7 +3947,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glColorMask(0, 0, 0, 0); glClearDepth(1.0f); - glClear(GL_DEPTH_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); render_list.clear(); _fill_render_list(p_cull_result, p_cull_count, true); @@ -3953,6 +3973,9 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const fb_cleared = true; render_pass++; + state.using_contact_shadows = true; + } else { + state.using_contact_shadows = false; } _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_cam_projection, p_shadow_atlas); @@ -4034,8 +4057,13 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const } else { - current_fbo = storage->frame.current_rt->buffers.fbo; - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); + if (storage->frame.current_rt->buffers.active) { + current_fbo = storage->frame.current_rt->buffers.fbo; + } else { + current_fbo = storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo; + } + + glBindFramebuffer(GL_FRAMEBUFFER, current_fbo); state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, false); Vector<GLenum> draw_buffers; @@ -4045,8 +4073,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const } if (!fb_cleared) { - glClearDepth(1.0f); - glClear(GL_DEPTH_BUFFER_BIT); + glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0, 0); } Color clear_color(0, 0, 0, 0); @@ -4111,7 +4138,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const storage->shaders.copy.bind(); - _copy_screen(); + _copy_screen(true, true); //turn off everything used storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false); @@ -4178,7 +4205,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const _render_mrts(env, p_cam_projection); } else { //FIXME: check that this is possible to use - if (storage->frame.current_rt && state.used_screen_texture) { + if (storage->frame.current_rt && storage->frame.current_rt->buffers.active && state.used_screen_texture) { glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); glReadBuffer(GL_COLOR_ATTACHMENT0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); @@ -4192,7 +4219,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const } } - if (storage->frame.current_rt && state.used_screen_texture) { + if (storage->frame.current_rt && state.used_screen_texture && storage->frame.current_rt->buffers.active) { glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 7); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); } @@ -4273,6 +4300,8 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } + + //disable all stuff } void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) { @@ -4297,6 +4326,8 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ float bias = 0; float normal_bias = 0; + state.using_contact_shadows = false; + CameraMatrix light_projection; Transform light_transform; @@ -4779,8 +4810,6 @@ void RasterizerSceneGLES3::initialize() { state.scene_shader.add_custom_define("#define MAX_SKELETON_BONES " + itos(state.max_skeleton_bones) + "\n"); } - GLOBAL_DEF("rendering/quality/shadows/filter_mode", 1); - GlobalConfig::get_singleton()->set_custom_property_info("rendering/quality/shadows/filter_mode", PropertyInfo(Variant::INT, "rendering/quality/shadows/filter_mode", PROPERTY_HINT_ENUM, "Disabled,PCF5,PCF13")); shadow_filter_mode = SHADOW_FILTER_NEAREST; { //reflection cubemaps @@ -4872,9 +4901,9 @@ void RasterizerSceneGLES3::initialize() { { GLOBAL_DEF("rendering/quality/subsurface_scattering/quality", 1); - GlobalConfig::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/quality", PropertyInfo(Variant::INT, "rendering/quality/subsurface_scattering/quality", PROPERTY_HINT_ENUM, "Low,Medium,High")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/quality", PropertyInfo(Variant::INT, "rendering/quality/subsurface_scattering/quality", PROPERTY_HINT_ENUM, "Low,Medium,High")); GLOBAL_DEF("rendering/quality/subsurface_scattering/scale", 1.0); - GlobalConfig::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/scale", PropertyInfo(Variant::INT, "rendering/quality/subsurface_scattering/scale", PROPERTY_HINT_RANGE, "0.01,8,0.01")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/scale", PropertyInfo(Variant::INT, "rendering/quality/subsurface_scattering/scale", PROPERTY_HINT_RANGE, "0.01,8,0.01")); GLOBAL_DEF("rendering/quality/subsurface_scattering/follow_surface", false); GLOBAL_DEF("rendering/quality/voxel_cone_tracing/high_quality", true); @@ -4916,12 +4945,12 @@ void RasterizerSceneGLES3::initialize() { void RasterizerSceneGLES3::iteration() { - shadow_filter_mode = ShadowFilterMode(int(GlobalConfig::get_singleton()->get("rendering/quality/shadows/filter_mode"))); - subsurface_scatter_follow_surface = GlobalConfig::get_singleton()->get("rendering/quality/subsurface_scattering/follow_surface"); - subsurface_scatter_quality = SubSurfaceScatterQuality(int(GlobalConfig::get_singleton()->get("rendering/quality/subsurface_scattering/quality"))); - subsurface_scatter_size = GlobalConfig::get_singleton()->get("rendering/quality/subsurface_scattering/scale"); + shadow_filter_mode = ShadowFilterMode(int(ProjectSettings::get_singleton()->get("rendering/quality/shadows/filter_mode"))); + subsurface_scatter_follow_surface = ProjectSettings::get_singleton()->get("rendering/quality/subsurface_scattering/follow_surface"); + subsurface_scatter_quality = SubSurfaceScatterQuality(int(ProjectSettings::get_singleton()->get("rendering/quality/subsurface_scattering/quality"))); + subsurface_scatter_size = ProjectSettings::get_singleton()->get("rendering/quality/subsurface_scattering/scale"); - state.scene_shader.set_conditional(SceneShaderGLES3::VCT_QUALITY_HIGH, GlobalConfig::get_singleton()->get("rendering/quality/voxel_cone_tracing/high_quality")); + state.scene_shader.set_conditional(SceneShaderGLES3::VCT_QUALITY_HIGH, ProjectSettings::get_singleton()->get("rendering/quality/voxel_cone_tracing/high_quality")); } void RasterizerSceneGLES3::finalize() { diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index a03e3dbe3d..f6509e0041 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -187,6 +187,7 @@ public: bool cull_front; bool used_sss; bool used_screen_texture; + bool using_contact_shadows; VS::ViewportDebugDraw debug_draw; } state; @@ -645,8 +646,9 @@ public: #define SORT_KEY_UNSHADED_FLAG (uint64_t(1) << 59) #define SORT_KEY_NO_DIRECTIONAL_FLAG (uint64_t(1) << 58) #define SORT_KEY_GI_PROBES_FLAG (uint64_t(1) << 57) - SORT_KEY_SHADING_SHIFT = 57, - SORT_KEY_SHADING_MASK = 7, +#define SORT_KEY_VERTEX_LIT_FLAG (uint64_t(1) << 56) + SORT_KEY_SHADING_SHIFT = 56, + SORT_KEY_SHADING_MASK = 15, SORT_KEY_MATERIAL_INDEX_SHIFT = 40, SORT_KEY_GEOMETRY_INDEX_SHIFT = 20, SORT_KEY_GEOMETRY_TYPE_SHIFT = 15, @@ -795,7 +797,7 @@ public: void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix &p_camera_projection, RID p_shadow_atlas); void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix &p_camera_projection, RID p_reflection_atlas, Environment *p_env); - void _copy_screen(); + void _copy_screen(bool p_invalidate_color = false, bool p_invalidate_depth = false); void _copy_to_front_buffer(Environment *env); void _copy_texture_to_front_buffer(GLuint p_texture); //used for debug diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 981426f4dc..76df57d410 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "rasterizer_storage_gles3.h" -#include "global_config.h" +#include "project_settings.h" #include "rasterizer_canvas_gles3.h" #include "rasterizer_scene_gles3.h" @@ -99,6 +99,21 @@ #define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E #define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F +void glTexStorage2DCustom(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type) { + +#ifdef GLES_OVER_GL + + for (int i = 0; i < levels; i++) { + glTexImage2D(target, i, internalformat, width, height, 0, format, type, NULL); + width = MAX(1, (width / 2)); + height = MAX(1, (height / 2)); + } + +#else + glTexStorage2D(target, levels, internalformat, width, height); +#endif +} + GLuint RasterizerStorageGLES3::system_fbo = 0; Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool &srgb) { @@ -1412,18 +1427,10 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra GLenum format = GL_RGBA; GLenum type = use_float ? GL_HALF_FLOAT : GL_UNSIGNED_INT_2_10_10_10_REV; - while (mm_level) { - - glTexImage2D(GL_TEXTURE_2D, lod, internal_format, size, size * 2, 0, format, type, NULL); - lod++; - mm_level--; - - if (size > 1) - size >>= 1; - } + glTexStorage2DCustom(GL_TEXTURE_2D, mipmaps, internal_format, size, size * 2.0, format, type); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, lod - 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmaps - 1); lod = 0; mm_level = mipmaps; @@ -1593,6 +1600,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { p_shader->spatial.unshaded = false; p_shader->spatial.ontop = false; p_shader->spatial.uses_sss = false; + p_shader->spatial.uses_vertex_lighting = false; p_shader->spatial.uses_screen_texture = false; p_shader->spatial.uses_vertex = false; p_shader->spatial.writes_modelview_or_projection = false; @@ -1614,6 +1622,8 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { shaders.actions_scene.render_mode_flags["unshaded"] = &p_shader->spatial.unshaded; shaders.actions_scene.render_mode_flags["ontop"] = &p_shader->spatial.ontop; + shaders.actions_scene.render_mode_flags["vertex_lighting"] = &p_shader->spatial.uses_vertex_lighting; + shaders.actions_scene.usage_flag_pointers["ALPHA"] = &p_shader->spatial.uses_alpha; shaders.actions_scene.usage_flag_pointers["VERTEX"] = &p_shader->spatial.uses_vertex; @@ -5818,17 +5828,20 @@ void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) { rt->fbo = 0; } - if (rt->buffers.fbo) { + if (rt->buffers.active) { glDeleteFramebuffers(1, &rt->buffers.fbo); glDeleteRenderbuffers(1, &rt->buffers.depth); glDeleteRenderbuffers(1, &rt->buffers.diffuse); - glDeleteRenderbuffers(1, &rt->buffers.specular); - glDeleteRenderbuffers(1, &rt->buffers.normal_rough); - glDeleteRenderbuffers(1, &rt->buffers.sss); - glDeleteFramebuffers(1, &rt->buffers.effect_fbo); - glDeleteTextures(1, &rt->buffers.effect); + if (rt->buffers.effects_active) { + glDeleteRenderbuffers(1, &rt->buffers.specular); + glDeleteRenderbuffers(1, &rt->buffers.normal_rough); + glDeleteRenderbuffers(1, &rt->buffers.sss); + glDeleteFramebuffers(1, &rt->buffers.effect_fbo); + glDeleteTextures(1, &rt->buffers.effect); + } - rt->buffers.fbo = 0; + rt->buffers.effects_active = false; + rt->buffers.active = false; } if (rt->depth) { @@ -5866,13 +5879,15 @@ void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) { tex->active = false; for (int i = 0; i < 2; i++) { - for (int j = 0; j < rt->effects.mip_maps[i].sizes.size(); j++) { - glDeleteFramebuffers(1, &rt->effects.mip_maps[i].sizes[j].fbo); - } + if (rt->effects.mip_maps[i].color) { + for (int j = 0; j < rt->effects.mip_maps[i].sizes.size(); j++) { + glDeleteFramebuffers(1, &rt->effects.mip_maps[i].sizes[j].fbo); + } - glDeleteTextures(1, &rt->effects.mip_maps[i].color); - rt->effects.mip_maps[i].sizes.clear(); - rt->effects.mip_maps[i].levels = 0; + glDeleteTextures(1, &rt->effects.mip_maps[i].color); + rt->effects.mip_maps[i].sizes.clear(); + rt->effects.mip_maps[i].levels = 0; + } } /* @@ -5899,10 +5914,20 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { if (!hdr || rt->flags[RENDER_TARGET_NO_3D]) { - color_internal_format = GL_RGBA8; - color_format = GL_RGBA; - color_type = GL_UNSIGNED_BYTE; - image_format = Image::FORMAT_RGBA8; + if (rt->flags[RENDER_TARGET_NO_3D_EFFECTS] && !rt->flags[RENDER_TARGET_TRANSPARENT]) { + //if this is not used, linear colorspace looks pretty bad + //this is the default mode used for mobile + color_internal_format = GL_RGB10_A2; + color_format = GL_RGBA; + color_type = GL_UNSIGNED_INT_2_10_10_10_REV; + image_format = Image::FORMAT_RGBA8; + } else { + + color_internal_format = GL_RGBA8; + color_format = GL_RGBA; + color_type = GL_UNSIGNED_BYTE; + image_format = Image::FORMAT_RGBA8; + } } else { color_internal_format = GL_RGBA16F; color_format = GL_RGBA; @@ -5967,7 +5992,9 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { /* BACK FBO */ - if (!rt->flags[RENDER_TARGET_NO_3D]) { + if (!rt->flags[RENDER_TARGET_NO_3D] && (!rt->flags[RENDER_TARGET_NO_3D_EFFECTS] || rt->msaa != VS::VIEWPORT_MSAA_DISABLED)) { + + rt->buffers.active = true; static const int msaa_value[] = { 0, 2, 4, 8, 16 }; int msaa = msaa_value[rt->msaa]; @@ -5997,6 +6024,7 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { if (!rt->flags[RENDER_TARGET_NO_3D_EFFECTS]) { + rt->buffers.effects_active = true; glGenRenderbuffers(1, &rt->buffers.specular); glBindRenderbuffer(GL_RENDERBUFFER, rt->buffers.specular); @@ -6054,15 +6082,11 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->buffers.effect, 0); - if (status != GL_FRAMEBUFFER_COMPLETE) { - printf("err status: %x\n", status); - _render_target_clear(rt); - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); - } - + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); if (status != GL_FRAMEBUFFER_COMPLETE) { + printf("err status: %x\n", status); _render_target_clear(rt); ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); } @@ -6140,7 +6164,12 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { _render_target_clear(rt); ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); } + } else { + rt->buffers.effects_active = false; } + } else { + rt->buffers.active = false; + rt->buffers.effects_active = true; } if (!rt->flags[RENDER_TARGET_NO_SAMPLING]) { @@ -6164,8 +6193,6 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { while (true) { RenderTarget::Effects::MipMaps::Size mm; - - glTexImage2D(GL_TEXTURE_2D, level, color_internal_format, w, h, 0, color_format, color_type, NULL); mm.width = w; mm.height = h; rt->effects.mip_maps[i].sizes.push_back(mm); @@ -6179,8 +6206,13 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { level++; } + glTexStorage2DCustom(GL_TEXTURE_2D, level + 1, color_internal_format, rt->width, rt->height, color_format, color_type); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level); + glDisable(GL_SCISSOR_TEST); + glColorMask(1, 1, 1, 1); + glDepthMask(GL_TRUE); for (int j = 0; j < rt->effects.mip_maps[i].sizes.size(); j++) { @@ -6189,6 +6221,11 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { glGenFramebuffers(1, &mm.fbo); glBindFramebuffer(GL_FRAMEBUFFER, mm.fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->effects.mip_maps[i].color, j); + bool used_depth = false; + if (j == 0 && i == 0 && rt->buffers.active == false && !rt->flags[RENDER_TARGET_NO_3D]) { //will use this one for rendering 3D + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); + used_depth = true; + } GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { @@ -6197,7 +6234,12 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { } float zero[4] = { 1, 0, 1, 0 }; + glViewport(0, 0, rt->effects.mip_maps[i].sizes[j].width, rt->effects.mip_maps[i].sizes[j].height); + glClearBufferfv(GL_COLOR, 0, zero); + if (used_depth) { + glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0, 0); + } } glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); @@ -6838,7 +6880,6 @@ void RasterizerStorageGLES3::initialize() { int max_extensions = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &max_extensions); - print_line("GLES3: max extensions: " + itos(max_extensions)); for (int i = 0; i < max_extensions; i++) { const GLubyte *s = glGetStringi(GL_EXTENSIONS, i); if (!s) @@ -6848,7 +6889,7 @@ void RasterizerStorageGLES3::initialize() { } config.shrink_textures_x2 = false; - config.use_fast_texture_filter = int(GlobalConfig::get_singleton()->get("rendering/quality/filters/use_nearest_mipmap_filter")); + config.use_fast_texture_filter = int(ProjectSettings::get_singleton()->get("rendering/quality/filters/use_nearest_mipmap_filter")); config.use_anisotropic_filter = config.extensions.has("rendering/quality/filters/anisotropic_filter_level"); config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_dxt1") || config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc"); @@ -6864,7 +6905,6 @@ void RasterizerStorageGLES3::initialize() { config.hdr_supported = false; #endif - print_line("hdr supported: " + itos(config.hdr_supported)); config.pvrtc_supported = config.extensions.has("GL_IMG_texture_compression_pvrtc"); config.srgb_decode_supported = config.extensions.has("GL_EXT_texture_sRGB_decode"); @@ -6872,7 +6912,7 @@ void RasterizerStorageGLES3::initialize() { config.use_anisotropic_filter = config.extensions.has("GL_EXT_texture_filter_anisotropic"); if (config.use_anisotropic_filter) { glGetFloatv(_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &config.anisotropic_level); - config.anisotropic_level = MIN(int(GlobalConfig::get_singleton()->get("rendering/quality/anisotropic_filter_level")), config.anisotropic_level); + config.anisotropic_level = MIN(int(ProjectSettings::get_singleton()->get("rendering/quality/anisotropic_filter_level")), config.anisotropic_level); } frame.clear_request = false; @@ -6997,6 +7037,8 @@ void RasterizerStorageGLES3::initialize() { } shaders.cubemap_filter.init(); + bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx.mobile"); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::LOW_QUALITY, !ggx_hq); shaders.particles.init(); #ifdef GLES_OVER_GL @@ -7009,7 +7051,29 @@ void RasterizerStorageGLES3::initialize() { frame.current_rt = NULL; config.keep_original_textures = false; config.generate_wireframes = false; - config.use_texture_array_environment = GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections", true); + config.use_texture_array_environment = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections"); + + config.force_vertex_shading = GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); + + GLOBAL_DEF("rendering/quality/depth_prepass/disable", false); + + String renderer = (const char *)glGetString(GL_RENDERER); + + config.no_depth_prepass = !bool(GLOBAL_GET("rendering/quality/depth_prepass/enable")); + if (!config.no_depth_prepass) { + + String vendors = GLOBAL_GET("rendering/quality/depth_prepass/disable_for_vendors"); + Vector<String> vendor_match = vendors.split(","); + for (int i = 0; i < vendor_match.size(); i++) { + String v = vendor_match[i].strip_edges(); + if (v == String()) + continue; + + if (renderer.findn(v) != -1) { + config.no_depth_prepass = true; + } + } + } } void RasterizerStorageGLES3::finalize() { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index b24da44afd..7d0f3e5745 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -48,6 +48,8 @@ class RasterizerSceneGLES3; #define _DECODE_EXT 0x8A49 #define _SKIP_DECODE_EXT 0x8A4A +void glTexStorage2DCustom(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type); + class RasterizerStorageGLES3 : public RasterizerStorage { public: RasterizerCanvasGLES3 *canvas; @@ -91,6 +93,9 @@ public: Set<String> extensions; bool keep_original_textures; + + bool no_depth_prepass; + bool force_vertex_shading; } config; mutable struct Shaders { @@ -444,6 +449,7 @@ public: bool uses_sss; bool uses_screen_texture; bool writes_modelview_or_projection; + bool uses_vertex_lighting; } spatial; @@ -1193,6 +1199,9 @@ public: GLuint depth; struct Buffers { + + bool active; + bool effects_active; GLuint fbo; GLuint depth; GLuint specular; @@ -1282,6 +1291,8 @@ public: flags[RENDER_TARGET_NO_3D] = false; flags[RENDER_TARGET_NO_SAMPLING] = false; flags[RENDER_TARGET_HDR] = true; + buffers.active = false; + buffers.effects_active = false; last_exposure_tick = 0; } diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 33a7c9a22f..f1077e2d20 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -208,6 +208,7 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() { Vector<const char *> strings; #ifdef GLES_OVER_GL strings.push_back("#version 330\n"); + strings.push_back("#define GLES_OVER_GL\n"); #else strings.push_back("#version 300 es\n"); #endif diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index a7c388815d..d33193ee50 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -49,6 +49,9 @@ void main() { #define M_PI 3.14159265359 +#if !defined(USE_GLES_OVER_GL) +precision mediump float; +#endif #if defined(USE_CUBEMAP) || defined(USE_PANORAMA) in vec3 cube_interp; @@ -87,14 +90,6 @@ vec4 texturePanorama(vec3 normal,sampler2D pano ) { #endif -float sRGB_gamma_correct(float c){ - float a = 0.055; - if(c < 0.0031308) - return 12.92*c; - else - return (1.0+a)*pow(c, 1.0/2.4) - a; -} - uniform float stuff; uniform vec2 pixel_size; @@ -131,7 +126,7 @@ void main() { vec4 color = texture( source_cube, normalize(cube_interp) ); #else - vec4 color = texture( source, uv_interp ); + vec4 color = textureLod( source, uv_interp,0.0 ); #endif diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl index ac4e47a440..485fbb6ee0 100644 --- a/drivers/gles3/shaders/cubemap_filter.glsl +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -204,7 +204,7 @@ vec4 textureDualParaboloidArray(vec3 normal) { vec3 norm = normalize(normal); norm.xy/=1.0+abs(norm.z); norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25); - if (norm.z<0) { + if (norm.z<0.0) { norm.y=0.5-norm.y+0.5; } return textureLod(source_dual_paraboloid_array, vec3(norm.xy, float(source_array_index) ), 0.0); diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl index 2550335174..09e522866c 100644 --- a/drivers/gles3/shaders/effect_blur.glsl +++ b/drivers/gles3/shaders/effect_blur.glsl @@ -25,6 +25,9 @@ void main() { [fragment] +#if !defined(GLES_OVER_GL) +precision mediump float; +#endif in vec2 uv_interp; uniform sampler2D source_color; //texunit:0 diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl index 6a977a201e..a62c124dfe 100644 --- a/drivers/gles3/shaders/particles.glsl +++ b/drivers/gles3/shaders/particles.glsl @@ -178,7 +178,7 @@ VERTEX_SHADER_CODE #if !defined(DISABLE_FORCE) - if (true) { + if (false) { vec3 force = vec3(0.0); for(int i=0;i<attractor_count;i++) { @@ -187,7 +187,7 @@ VERTEX_SHADER_CODE float dist = length(rel_vec); if (attractors[i].radius < dist) continue; - if (attractors[i].eat_radius>0 && attractors[i].eat_radius > dist) { + if (attractors[i].eat_radius>0.0 && attractors[i].eat_radius > dist) { out_velocity_active.a=0.0; } diff --git a/drivers/gles3/shaders/resolve.glsl b/drivers/gles3/shaders/resolve.glsl index 181a3c99ec..0b50a9c57b 100644 --- a/drivers/gles3/shaders/resolve.glsl +++ b/drivers/gles3/shaders/resolve.glsl @@ -15,6 +15,9 @@ void main() { [fragment] +#if !defined(GLES_OVER_GL) +precision mediump float; +#endif in vec2 uv_interp; uniform sampler2D source_specular; //texunit:0 diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 9d474d3902..acece2e639 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -64,44 +64,45 @@ layout(std140) uniform SceneData { //ubo:0 highp mat4 camera_inverse_matrix; highp mat4 camera_matrix; - highp vec4 ambient_light_color; - highp vec4 bg_color; + mediump vec4 ambient_light_color; + mediump vec4 bg_color; - vec4 fog_color_enabled; - vec4 fog_sun_color_amount; + mediump vec4 fog_color_enabled; + mediump vec4 fog_sun_color_amount; - float ambient_energy; - float bg_energy; + mediump float ambient_energy; + mediump float bg_energy; - float z_offset; - float z_slope_scale; - float shadow_dual_paraboloid_render_zfar; - float shadow_dual_paraboloid_render_side; + mediump float z_offset; + mediump float z_slope_scale; + highp float shadow_dual_paraboloid_render_zfar; + highp float shadow_dual_paraboloid_render_side; highp vec2 screen_pixel_size; - vec2 shadow_atlas_pixel_size; - vec2 directional_shadow_pixel_size; + highp vec2 shadow_atlas_pixel_size; + highp vec2 directional_shadow_pixel_size; - float time; - float z_far; - float reflection_multiplier; - float subsurface_scatter_width; - float ambient_occlusion_affect_light; + highp float time; + highp float z_far; + mediump float reflection_multiplier; + mediump float subsurface_scatter_width; + mediump float ambient_occlusion_affect_light; bool fog_depth_enabled; - float fog_depth_begin; - float fog_depth_curve; + highp float fog_depth_begin; + highp float fog_depth_curve; bool fog_transmit_enabled; - float fog_transmit_curve; + highp float fog_transmit_curve; bool fog_height_enabled; - float fog_height_min; - float fog_height_max; - float fog_height_curve; + highp float fog_height_min; + highp float fog_height_max; + highp float fog_height_curve; }; uniform highp mat4 world_transform; + #ifdef USE_LIGHT_DIRECTIONAL layout(std140) uniform DirectionalLightData { //ubo:3 @@ -121,6 +122,90 @@ layout(std140) uniform DirectionalLightData { //ubo:3 #endif +#ifdef USE_VERTEX_LIGHTING +//omni and spot + +struct LightData { + + highp vec4 light_pos_inv_radius; + mediump vec4 light_direction_attenuation; + mediump vec4 light_color_energy; + mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled, + mediump vec4 light_clamp; + mediump vec4 shadow_color_contact; + highp mat4 shadow_matrix; + +}; + + +layout(std140) uniform OmniLightData { //ubo:4 + + LightData omni_lights[MAX_LIGHT_DATA_STRUCTS]; +}; + +layout(std140) uniform SpotLightData { //ubo:5 + + LightData spot_lights[MAX_LIGHT_DATA_STRUCTS]; +}; + +#ifdef USE_FORWARD_LIGHTING + + +uniform int omni_light_indices[MAX_FORWARD_LIGHTS]; +uniform int omni_light_count; + +uniform int spot_light_indices[MAX_FORWARD_LIGHTS]; +uniform int spot_light_count; + +#endif + +out vec4 diffuse_light_interp; +out vec4 specular_light_interp; + +void light_compute(vec3 N, vec3 L,vec3 V, vec3 light_color,float roughness,inout vec3 diffuse, inout vec3 specular) { + + float dotNL = max(dot(N,L), 0.0 ); + diffuse += dotNL * light_color; + + if (roughness > 0.0) { + + vec3 H = normalize(V + L); + float dotNH = max(dot(N,H), 0.0 ); + float intensity = pow( dotNH, (1.0-roughness) * 256.0); + specular += light_color * intensity; + + } +} + +void light_process_omni(int idx, vec3 vertex, vec3 eye_vec,vec3 normal, float roughness,inout vec3 diffuse, inout vec3 specular) { + + vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz-vertex; + float light_length = length( light_rel_vec ); + float normalized_distance = light_length*omni_lights[idx].light_pos_inv_radius.w; + vec3 light_attenuation = vec3(pow( max(1.0 - normalized_distance, 0.0), omni_lights[idx].light_direction_attenuation.w )); + + light_compute(normal,normalize(light_rel_vec),eye_vec,omni_lights[idx].light_color_energy.rgb * light_attenuation,roughness,diffuse,specular); + +} + +void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness, inout vec3 diffuse, inout vec3 specular) { + + vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz-vertex; + float light_length = length( light_rel_vec ); + float normalized_distance = light_length*spot_lights[idx].light_pos_inv_radius.w; + vec3 light_attenuation = vec3(pow( max(1.0 - normalized_distance, 0.001), spot_lights[idx].light_direction_attenuation.w )); + vec3 spot_dir = spot_lights[idx].light_direction_attenuation.xyz; + float spot_cutoff=spot_lights[idx].light_params.y; + float scos = max(dot(-normalize(light_rel_vec), spot_dir),spot_cutoff); + float spot_rim = (1.0 - scos) / (1.0 - spot_cutoff); + light_attenuation *= 1.0 - pow( max(spot_rim,0.001), spot_lights[idx].light_params.x); + + + light_compute(normal,normalize(light_rel_vec),eye_vec,spot_lights[idx].light_color_energy.rgb*light_attenuation,roughness,diffuse,specular); +} + + +#endif /* Varyings */ @@ -288,6 +373,8 @@ void main() { #endif #endif + float roughness=0.0; + //defines that make writing custom shaders easier #define projection_matrix local_projection #define world_transform world_matrix @@ -376,6 +463,54 @@ VERTEX_SHADER_CODE #endif position_interp=gl_Position; + +#ifdef USE_VERTEX_LIGHTING + + diffuse_light_interp=vec4(0.0); + specular_light_interp=vec4(0.0); + +#ifdef USE_FORWARD_LIGHTING + + for(int i=0;i<omni_light_count;i++) { + light_process_omni(omni_light_indices[i],vertex_interp,-normalize( vertex_interp ),normal_interp,roughness,diffuse_light_interp.rgb,specular_light_interp.rgb); + } + + for(int i=0;i<spot_light_count;i++) { + light_process_spot(spot_light_indices[i],vertex_interp,-normalize( vertex_interp ),normal_interp,roughness,diffuse_light_interp.rgb,specular_light_interp.rgb); + } +#endif + +#ifdef USE_LIGHT_DIRECTIONAL + + vec3 directional_diffuse = vec3(0.0); + vec3 directional_specular = vec3(0.0); + light_compute(normal_interp,-light_direction_attenuation.xyz,-normalize( vertex_interp ),normal_interp,roughness,directional_diffuse,directional_specular); + + float diff_avg = dot(diffuse_light_interp.rgb,vec3(0.33333)); + float diff_dir_avg = dot(directional_diffuse,vec3(0.33333)); + if (diff_avg>0.0) { + diffuse_light_interp.a=diff_dir_avg/(diff_avg+diff_dir_avg); + } else { + diffuse_light_interp.a=1.0; + } + + diffuse_light_interp.rgb+=directional_diffuse; + + float spec_avg = dot(specular_light_interp.rgb,vec3(0.33333)); + float spec_dir_avg = dot(directional_specular,vec3(0.33333)); + if (spec_avg>0.0) { + specular_light_interp.a=spec_dir_avg/(spec_avg+spec_dir_avg); + } else { + specular_light_interp.a=1.0; + } + + specular_light_interp.rgb+=directional_specular; + +#endif //USE_LIGHT_DIRECTIONAL + + +#endif // USE_VERTEX_LIGHTING + } @@ -455,7 +590,7 @@ vec3 textureDualParaboloid(sampler2DArray p_tex, vec3 p_vec,float p_roughness) { // we need to lie the derivatives (normg) and assume that DP side is always the same // to get proper texure filtering vec2 normg=norm.xy; - if (norm.z>0) { + if (norm.z>0.0) { norm.y=0.5-norm.y+0.5; } @@ -479,7 +614,7 @@ vec3 textureDualParaboloid(sampler2D p_tex, vec3 p_vec,float p_roughness) { vec3 norm = normalize(p_vec); norm.xy/=1.0+abs(norm.z); norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25); - if (norm.z>0) { + if (norm.z>0.0) { norm.y=0.5-norm.y+0.5; } return textureLod(p_tex, norm.xy, p_roughness * RADIANCE_MAX_LOD).xyz; @@ -511,39 +646,39 @@ layout(std140) uniform SceneData { highp mat4 camera_inverse_matrix; highp mat4 camera_matrix; - highp vec4 ambient_light_color; - highp vec4 bg_color; + mediump vec4 ambient_light_color; + mediump vec4 bg_color; - vec4 fog_color_enabled; - vec4 fog_sun_color_amount; + mediump vec4 fog_color_enabled; + mediump vec4 fog_sun_color_amount; - float ambient_energy; - float bg_energy; + mediump float ambient_energy; + mediump float bg_energy; - float z_offset; - float z_slope_scale; - float shadow_dual_paraboloid_render_zfar; - float shadow_dual_paraboloid_render_side; + mediump float z_offset; + mediump float z_slope_scale; + highp float shadow_dual_paraboloid_render_zfar; + highp float shadow_dual_paraboloid_render_side; highp vec2 screen_pixel_size; - vec2 shadow_atlas_pixel_size; - vec2 directional_shadow_pixel_size; + highp vec2 shadow_atlas_pixel_size; + highp vec2 directional_shadow_pixel_size; - float time; - float z_far; - float reflection_multiplier; - float subsurface_scatter_width; - float ambient_occlusion_affect_light; + highp float time; + highp float z_far; + mediump float reflection_multiplier; + mediump float subsurface_scatter_width; + mediump float ambient_occlusion_affect_light; bool fog_depth_enabled; - float fog_depth_begin; - float fog_depth_curve; + highp float fog_depth_begin; + highp float fog_depth_curve; bool fog_transmit_enabled; - float fog_transmit_curve; + highp float fog_transmit_curve; bool fog_height_enabled; - float fog_height_min; - float fog_height_max; - float fog_height_curve; + highp float fog_height_min; + highp float fog_height_max; + highp float fog_height_curve; }; //directional light data @@ -570,6 +705,10 @@ uniform highp sampler2DShadow directional_shadow; //texunit:-4 #endif +#ifdef USE_VERTEX_LIGHTING +in vec4 diffuse_light_interp; +in vec4 specular_light_interp; +#endif //omni and spot struct LightData { @@ -655,6 +794,8 @@ layout(location=0) out vec4 frag_color; in highp vec4 position_interp; uniform highp sampler2D depth_buffer; //texunit:-8 +#ifdef USE_CONTACT_SHADOWS + float contact_shadow_compute(vec3 pos, vec3 dir, float max_distance) { if (abs(dir.z)>0.99) @@ -715,6 +856,8 @@ float contact_shadow_compute(vec3 pos, vec3 dir, float max_distance) { return 1.0; } +#endif + // GGX Specular // Source: http://www.filmicworlds.com/images/ggx-opt/optimized-ggx.hlsl float G1V(float dotNV, float k) @@ -1010,13 +1153,16 @@ void light_process_omni(int idx, vec3 vertex, vec3 eye_vec,vec3 normal,vec3 bino splane.xy = clamp_rect.xy+splane.xy*clamp_rect.zw; float shadow = sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,clamp_rect); + +#ifdef USE_CONTACT_SHADOWS + if (shadow>0.01 && omni_lights[idx].shadow_color_contact.a>0.0) { float contact_shadow = contact_shadow_compute(vertex,normalize(light_rel_vec),min(light_length,omni_lights[idx].shadow_color_contact.a)); shadow=min(shadow,contact_shadow); - } +#endif light_attenuation*=mix(omni_lights[idx].shadow_color_contact.rgb,vec3(1.0),shadow); } @@ -1043,13 +1189,14 @@ void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 bi float shadow = sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,spot_lights[idx].light_clamp); +#ifdef USE_CONTACT_SHADOWS if (shadow>0.01 && spot_lights[idx].shadow_color_contact.a>0.0) { float contact_shadow = contact_shadow_compute(vertex,normalize(light_rel_vec),min(light_length,spot_lights[idx].shadow_color_contact.a)); shadow=min(shadow,contact_shadow); } - +#endif light_attenuation*=mix(spot_lights[idx].shadow_color_contact.rgb,vec3(1.0),shadow); } @@ -1097,7 +1244,7 @@ void reflection_process(int idx, vec3 vertex, vec3 normal,vec3 binormal, vec3 ta vec3 norm = normalize(local_ref_vec); norm.xy/=1.0+abs(norm.z); norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25); - if (norm.z>0) { + if (norm.z>0.0) { norm.y=0.5-norm.y+0.5; } @@ -1460,9 +1607,18 @@ FRAGMENT_SHADER_CODE //apply energy conservation +#ifdef USE_VERTEX_LIGHTING + + vec3 specular_light = specular_light_interp.rgb; + vec3 diffuse_light = diffuse_light_interp.rgb; +#else + vec3 specular_light = vec3(0.0,0.0,0.0); - vec3 ambient_light; vec3 diffuse_light = vec3(0.0,0.0,0.0); + +#endif + + vec3 ambient_light; vec3 env_reflection_light = vec3(0.0,0.0,0.0); vec3 eye_vec = -normalize( vertex_interp ); @@ -1515,7 +1671,7 @@ FRAGMENT_SHADER_CODE specular_blob_intensity*=specular * 2.0; #endif -#ifdef USE_LIGHT_DIRECTIONAL +#if defined(USE_LIGHT_DIRECTIONAL) vec3 light_attenuation=vec3(1.0); @@ -1640,13 +1796,14 @@ FRAGMENT_SHADER_CODE } #endif +#ifdef USE_CONTACT_SHADOWS if (shadow>0.01 && shadow_color_contact.a>0.0) { float contact_shadow = contact_shadow_compute(vertex,-light_direction_attenuation.xyz,shadow_color_contact.a); shadow=min(shadow,contact_shadow); } - +#endif light_attenuation=mix(shadow_color_contact.rgb,vec3(1.0),shadow); @@ -1654,7 +1811,13 @@ FRAGMENT_SHADER_CODE #endif //LIGHT_DIRECTIONAL_SHADOW +#ifdef USE_VERTEX_LIGHTING + diffuse_light*=mix(vec3(1.0),light_attenuation,diffuse_light_interp.a); + specular_light*=mix(vec3(1.0),light_attenuation,specular_light_interp.a); + +#else light_compute(normal,-light_direction_attenuation.xyz,eye_vec,binormal,tangent,light_color_energy.rgb*light_attenuation,albedo,light_params.z*specular_blob_intensity,roughness,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light); +#endif #endif //#USE_LIGHT_DIRECTIONAL @@ -1664,12 +1827,11 @@ FRAGMENT_SHADER_CODE #endif - #ifdef USE_FORWARD_LIGHTING + highp vec4 reflection_accum = vec4(0.0,0.0,0.0,0.0); highp vec4 ambient_accum = vec4(0.0,0.0,0.0,0.0); - for(int i=0;i<reflection_count;i++) { reflection_process(reflection_indices[i],vertex,normal,binormal,tangent,roughness,anisotropy,ambient_light,env_reflection_light,reflection_accum,ambient_accum); } @@ -1684,6 +1846,13 @@ FRAGMENT_SHADER_CODE ambient_light+=ambient_accum.rgb/ambient_accum.a; } + + +#ifdef USE_VERTEX_LIGHTING + + diffuse_light*=albedo; +#else + for(int i=0;i<omni_light_count;i++) { light_process_omni(omni_light_indices[i],vertex,eye_vec,normal,binormal,tangent,albedo,roughness,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,specular_blob_intensity,diffuse_light,specular_light); } @@ -1692,15 +1861,13 @@ FRAGMENT_SHADER_CODE light_process_spot(spot_light_indices[i],vertex,eye_vec,normal,binormal,tangent,albedo,roughness,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,specular_blob_intensity,diffuse_light,specular_light); } - +#endif //USE_VERTEX_LIGHTING #endif - - #ifdef RENDER_DEPTH //nothing happens, so a tree-ssa optimizer will result in no fragment shader :) #else @@ -1713,13 +1880,11 @@ FRAGMENT_SHADER_CODE #endif - - - - //energu conservation diffuse_light=mix(diffuse_light,vec3(0.0),metallic); ambient_light=mix(ambient_light,vec3(0.0),metallic); + + { #if defined(DIFFUSE_TOON) @@ -1744,7 +1909,7 @@ FRAGMENT_SHADER_CODE if (fog_color_enabled.a > 0.5) { - float fog_amount=0; + float fog_amount=0.0; diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index 3ce2edf4e9..c6dfc6917d 100644 --- a/drivers/gles3/shaders/tonemap.glsl +++ b/drivers/gles3/shaders/tonemap.glsl @@ -18,6 +18,10 @@ void main() { [fragment] +#if !defined(GLES_OVER_GL) +precision mediump float; +#endif + in vec2 uv_interp; diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp index 0d7e1d9d72..4f1f318aee 100644 --- a/drivers/png/resource_saver_png.cpp +++ b/drivers/png/resource_saver_png.cpp @@ -30,8 +30,8 @@ #include "resource_saver_png.h" #include "core/image.h" -#include "global_config.h" #include "os/file_access.h" +#include "project_settings.h" #include "scene/resources/texture.h" #include <png.h> diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 45827ee4f7..fb04ef0088 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -33,7 +33,7 @@ #include <pulse/error.h> -#include "global_config.h" +#include "project_settings.h" Error AudioDriverPulseAudio::init() { diff --git a/drivers/rtaudio/audio_driver_rtaudio.cpp b/drivers/rtaudio/audio_driver_rtaudio.cpp index 0cbe145b41..da998db66f 100644 --- a/drivers/rtaudio/audio_driver_rtaudio.cpp +++ b/drivers/rtaudio/audio_driver_rtaudio.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "audio_driver_rtaudio.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" #ifdef RTAUDIO_ENABLED diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 2f88296ea4..d05529ef9a 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -53,7 +53,7 @@ #if defined(__FreeBSD__) || defined(__OpenBSD__) #include <sys/param.h> #endif -#include "global_config.h" +#include "project_settings.h" #include <assert.h> #include <dlfcn.h> #include <errno.h> @@ -494,7 +494,7 @@ String OS_Unix::get_data_dir() const { if (has_environment("HOME")) { - bool use_godot = GlobalConfig::get_singleton()->get("application/config/use_shared_user_dir"); + bool use_godot = ProjectSettings::get_singleton()->get("application/config/use_shared_user_dir"); if (use_godot) return get_environment("HOME") + "/.godot/app_userdata/" + an; else @@ -502,12 +502,7 @@ String OS_Unix::get_data_dir() const { } } - return GlobalConfig::get_singleton()->get_resource_path(); -} - -bool OS_Unix::check_feature_support(const String &p_feature) { - - return VisualServer::get_singleton()->has_os_feature(p_feature); + return ProjectSettings::get_singleton()->get_resource_path(); } String OS_Unix::get_installed_templates_path() const { diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 67eb5cefdf..953b0f0431 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -117,8 +117,6 @@ public: virtual String get_executable_path() const; virtual String get_data_dir() const; - virtual bool check_feature_support(const String &p_feature); - //virtual void run( MainLoop * p_main_loop ); }; diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp index 23ba177824..a1ca2c678e 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.cpp +++ b/drivers/xaudio2/audio_driver_xaudio2.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "audio_driver_xaudio2.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" const char *AudioDriverXAudio2::get_name() const { return "XAudio2"; diff --git a/editor/animation_editor.cpp b/editor/animation_editor.cpp index 1798e66e8a..45da365695 100644 --- a/editor/animation_editor.cpp +++ b/editor/animation_editor.cpp @@ -3774,6 +3774,7 @@ AnimationKeyEditor::AnimationKeyEditor() { zoom->set_max(2.0); zoom->set_value(1.0); zoom->set_h_size_flags(SIZE_EXPAND_FILL); + zoom->set_v_size_flags(SIZE_EXPAND_FILL); zoom->set_stretch_ratio(2); hb->add_child(zoom); zoom->connect("value_changed", this, "_scroll_changed"); diff --git a/editor/animation_editor.h b/editor/animation_editor.h index 128481c837..88cc446853 100644 --- a/editor/animation_editor.h +++ b/editor/animation_editor.h @@ -45,7 +45,6 @@ #include "scene/animation/animation_cache.h" #include "scene/resources/animation.h" #include "scene_tree_editor.h" -#include "scene_tree_editor.h" class AnimationKeyEdit; class AnimationCurveEdit; diff --git a/editor/asset_library_editor_plugin.cpp b/editor/asset_library_editor_plugin.cpp index 27d468bc25..74e21b31ea 100644 --- a/editor/asset_library_editor_plugin.cpp +++ b/editor/asset_library_editor_plugin.cpp @@ -1228,8 +1228,8 @@ void EditorAssetLibrary::_asset_open() { void EditorAssetLibrary::_manage_plugins() { - ProjectSettings::get_singleton()->popup_project_settings(); - ProjectSettings::get_singleton()->set_plugins_page(); + ProjectSettingsEditor::get_singleton()->popup_project_settings(); + ProjectSettingsEditor::get_singleton()->set_plugins_page(); } void EditorAssetLibrary::_install_external_asset(String p_zip_path, String p_title) { diff --git a/editor/collada/collada.cpp b/editor/collada/collada.cpp index 2f234c441a..ab1e397ccc 100644 --- a/editor/collada/collada.cpp +++ b/editor/collada/collada.cpp @@ -306,7 +306,7 @@ void Collada::_parse_image(XMLParser &parser) { String path = parser.get_attribute_value("source").strip_edges(); if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path - image.path = GlobalConfig::get_singleton()->localize_path(state.local_path.get_base_dir() + "/" + path.percent_decode()); + image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir() + "/" + path.percent_decode()); } } else { @@ -323,11 +323,11 @@ void Collada::_parse_image(XMLParser &parser) { if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path - path = GlobalConfig::get_singleton()->localize_path(state.local_path.get_base_dir() + "/" + path); + path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir() + "/" + path); } else if (path.find("file:///") == 0) { path = path.replace_first("file:///", ""); - path = GlobalConfig::get_singleton()->localize_path(path); + path = ProjectSettings::get_singleton()->localize_path(path); } image.path = path; @@ -2556,7 +2556,7 @@ Error Collada::load(const String &p_path, int p_flags) { Error err = parser.open(p_path); ERR_FAIL_COND_V(err, err); - state.local_path = GlobalConfig::get_singleton()->localize_path(p_path); + state.local_path = ProjectSettings::get_singleton()->localize_path(p_path); state.import_flags = p_flags; /* Skip headers */ err = OK; diff --git a/editor/collada/collada.h b/editor/collada/collada.h index ca60c392dd..38e66a7e45 100644 --- a/editor/collada/collada.h +++ b/editor/collada/collada.h @@ -32,7 +32,7 @@ #ifndef COLLADA_H #define COLLADA_H -#include "global_config.h" +#include "project_settings.h" #include "io/xml_parser.h" #include "map.h" #include "scene/resources/material.h" diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp index 6a79f99354..fa90cd36b3 100644 --- a/editor/doc/doc_data.cpp +++ b/editor/doc/doc_data.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "doc_data.h" -#include "global_config.h" +#include "project_settings.h" #include "global_constants.h" #include "io/compression.h" #include "io/marshalls.h" @@ -568,14 +568,14 @@ void DocData::generate(bool p_basic_types) { c.constants.push_back(cd); } - List<GlobalConfig::Singleton> singletons; - GlobalConfig::get_singleton()->get_singletons(&singletons); + List<ProjectSettings::Singleton> singletons; + ProjectSettings::get_singleton()->get_singletons(&singletons); //servers (this is kind of hackish) - for (List<GlobalConfig::Singleton>::Element *E = singletons.front(); E; E = E->next()) { + for (List<ProjectSettings::Singleton>::Element *E = singletons.front(); E; E = E->next()) { PropertyDoc pd; - GlobalConfig::Singleton &s = E->get(); + ProjectSettings::Singleton &s = E->get(); pd.name = s.name; pd.type = s.ptr->get_class(); while (String(ClassDB::get_parent_class(pd.type)) != "Object") diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp new file mode 100644 index 0000000000..fd90c766fd --- /dev/null +++ b/editor/editor_about.cpp @@ -0,0 +1,209 @@ +/*************************************************************************/ +/* editor_about.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "editor_about.h" + +#include "authors.gen.h" +#include "license.gen.h" +#include "version.h" +#include "version_hash.gen.h" + +void EditorAbout::_license_tree_selected() { + + TreeItem *selected = _tpl_tree->get_selected(); + _tpl_text->select(0, 0, 0, 0); + _tpl_text->set_text(selected->get_metadata(0)); +} + +void EditorAbout::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_license_tree_selected"), &EditorAbout::_license_tree_selected); +} + +TextureRect *EditorAbout::get_logo() const { + + return _logo; +} + +EditorAbout::EditorAbout() { + + set_title(TTR("Thanks from the Godot community!")); + get_ok()->set_text(TTR("Thanks!")); + set_hide_on_ok(true); + set_resizable(true); + + VBoxContainer *vbc = memnew(VBoxContainer); + HBoxContainer *hbc = memnew(HBoxContainer); + hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + hbc->set_alignment(BoxContainer::ALIGN_CENTER); + hbc->add_constant_override("separation", 30 * EDSCALE); + add_child(vbc); + vbc->add_child(hbc); + + _logo = memnew(TextureRect); + hbc->add_child(_logo); + + String hash = String(VERSION_HASH); + if (hash.length() != 0) + hash = "." + hash.left(7); + + Label *about_text = memnew(Label); + about_text->set_v_size_flags(Control::SIZE_SHRINK_CENTER); + about_text->set_text(VERSION_FULL_NAME + hash + String::utf8("\n\u00A9 2007-2017 Juan Linietsky, Ariel Manzur.\n\u00A9 2014-2017 ") + + TTR("Godot Engine contributors") + "\n"); + hbc->add_child(about_text); + + TabContainer *tc = memnew(TabContainer); + tc->set_custom_minimum_size(Size2(630, 240) * EDSCALE); + tc->set_v_size_flags(Control::SIZE_EXPAND_FILL); + vbc->add_child(tc); + + ScrollContainer *dev_base = memnew(ScrollContainer); + dev_base->set_name(TTR("Authors")); + dev_base->set_v_size_flags(Control::SIZE_EXPAND); + tc->add_child(dev_base); + + VBoxContainer *dev_vbc = memnew(VBoxContainer); + dev_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + dev_base->add_child(dev_vbc); + + List<String> dev_sections; + dev_sections.push_back(TTR("Project Founders")); + dev_sections.push_back(TTR("Lead Developer")); + dev_sections.push_back(TTR("Project Manager")); + dev_sections.push_back(TTR("Developers")); + + const char **dev_src[] = { dev_founders, dev_lead, dev_manager, dev_names }; + + for (int i = 0; i < dev_sections.size(); i++) { + + Label *lbl = memnew(Label); + lbl->set_text(dev_sections[i]); + dev_vbc->add_child(lbl); + + ItemList *il = memnew(ItemList); + il->set_max_columns(16); + il->set_h_size_flags(Control::SIZE_EXPAND_FILL); + il->set_fixed_column_width(230 * EDSCALE); + il->set_auto_height(true); + const char **dev_names_ptr = dev_src[i]; + while (*dev_names_ptr) + il->add_item(String::utf8(*dev_names_ptr++), NULL, false); + dev_vbc->add_child(il); + + HSeparator *hs = memnew(HSeparator); + hs->set_modulate(Color(0, 0, 0, 0)); + dev_vbc->add_child(hs); + } + + TextEdit *license = memnew(TextEdit); + license->set_name(TTR("License")); + license->set_h_size_flags(Control::SIZE_EXPAND_FILL); + license->set_v_size_flags(Control::SIZE_EXPAND_FILL); + license->set_wrap(true); + license->set_readonly(true); + license->set_text(String::utf8(about_license)); + tc->add_child(license); + + VBoxContainer *license_thirdparty = memnew(VBoxContainer); + license_thirdparty->set_name(TTR("Thirdparty License")); + license_thirdparty->set_h_size_flags(Control::SIZE_EXPAND_FILL); + tc->add_child(license_thirdparty); + + Label *tpl_label = memnew(Label); + tpl_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + tpl_label->set_autowrap(true); + tpl_label->set_text(TTR("Godot Engine relies on a number of thirdparty free and open source libraries, all compatible with the terms of its MIT license. The following is an exhaustive list of all such thirdparty components with their respective copyright statements and license terms.")); + license_thirdparty->add_child(tpl_label); + + HSplitContainer *tpl_hbc = memnew(HSplitContainer); + tpl_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + tpl_hbc->set_v_size_flags(Control::SIZE_EXPAND_FILL); + tpl_hbc->set_split_offset(240 * EDSCALE); + license_thirdparty->add_child(tpl_hbc); + + _tpl_tree = memnew(Tree); + _tpl_tree->set_hide_root(true); + TreeItem *root = _tpl_tree->create_item(); + TreeItem *tpl_ti_all = _tpl_tree->create_item(root); + tpl_ti_all->set_text(0, TTR("All Components")); + TreeItem *tpl_ti_tp = _tpl_tree->create_item(root); + tpl_ti_tp->set_text(0, TTR("Components")); + tpl_ti_tp->set_selectable(0, false); + TreeItem *tpl_ti_lc = _tpl_tree->create_item(root); + tpl_ti_lc->set_text(0, TTR("Licenses")); + tpl_ti_lc->set_selectable(0, false); + int read_idx = 0; + String long_text = ""; + for (int i = 0; i < THIRDPARTY_COUNT; i++) { + + TreeItem *ti = _tpl_tree->create_item(tpl_ti_tp); + String thirdparty = String(about_thirdparty[i]); + ti->set_text(0, thirdparty); + String text = thirdparty + "\n"; + long_text += "- " + thirdparty + "\n\n"; + for (int j = 0; j < about_tp_copyright_count[i]; j++) { + + text += "\n Files:\n " + String(about_tp_file[read_idx]).replace("\n", "\n ") + "\n"; + String copyright = String::utf8(" \u00A9 ") + String::utf8(about_tp_copyright[read_idx]).replace("\n", String::utf8("\n \u00A9 ")); + text += copyright; + long_text += copyright; + String license = "\n License: " + String(about_tp_license[read_idx]) + "\n"; + text += license; + long_text += license + "\n"; + read_idx++; + } + ti->set_metadata(0, text); + } + for (int i = 0; i < LICENSE_COUNT; i++) { + + TreeItem *ti = _tpl_tree->create_item(tpl_ti_lc); + String licensename = String(about_license_name[i]); + ti->set_text(0, licensename); + long_text += "- " + licensename + "\n\n"; + String licensebody = String(about_license_body[i]); + ti->set_metadata(0, licensebody); + long_text += " " + licensebody.replace("\n", "\n ") + "\n\n"; + } + tpl_ti_all->set_metadata(0, long_text); + tpl_hbc->add_child(_tpl_tree); + + _tpl_text = memnew(TextEdit); + _tpl_text->set_h_size_flags(Control::SIZE_EXPAND_FILL); + _tpl_text->set_v_size_flags(Control::SIZE_EXPAND_FILL); + _tpl_text->set_wrap(true); + _tpl_text->set_readonly(true); + tpl_hbc->add_child(_tpl_text); + + _tpl_tree->connect("item_selected", this, "_license_tree_selected"); + tpl_ti_all->select(0); + _tpl_text->set_text(tpl_ti_all->get_metadata(0)); +} + +EditorAbout::~EditorAbout() {} diff --git a/editor/editor_about.h b/editor/editor_about.h new file mode 100644 index 0000000000..0bde94531a --- /dev/null +++ b/editor/editor_about.h @@ -0,0 +1,70 @@ +/*************************************************************************/ +/* editor_about.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef EDITOR_ABOUT_H +#define EDITOR_ABOUT_H + +#include "scene/gui/control.h" +#include "scene/gui/dialogs.h" +#include "scene/gui/item_list.h" +#include "scene/gui/scroll_container.h" +#include "scene/gui/separator.h" +#include "scene/gui/split_container.h" +#include "scene/gui/tab_container.h" +#include "scene/gui/text_edit.h" +#include "scene/gui/texture_rect.h" +#include "scene/gui/tree.h" + +#include "editor_scale.h" +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ + +class EditorAbout : public AcceptDialog { + + GDCLASS(EditorAbout, AcceptDialog); + +private: + void _license_tree_selected(); + + Tree *_tpl_tree; + TextEdit *_tpl_text; + TextureRect *_logo; + +protected: + static void _bind_methods(); + +public: + TextureRect *get_logo() const; + + EditorAbout(); + ~EditorAbout(); +}; + +#endif diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index b83ac69141..399c22bf2c 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -30,7 +30,7 @@ #include "editor_autoload_settings.h" #include "editor_node.h" -#include "global_config.h" +#include "project_settings.h" #include "global_constants.h" #define PREVIEW_LIST_MAX_SIZE 10 @@ -115,12 +115,12 @@ void EditorAutoloadSettings::_autoload_add() { UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(TTR("Add AutoLoad")); - undo_redo->add_do_property(GlobalConfig::get_singleton(), name, "*" + path); + undo_redo->add_do_property(ProjectSettings::get_singleton(), name, "*" + path); - if (GlobalConfig::get_singleton()->has(name)) { - undo_redo->add_undo_property(GlobalConfig::get_singleton(), name, GlobalConfig::get_singleton()->get(name)); + if (ProjectSettings::get_singleton()->has(name)) { + undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, ProjectSettings::get_singleton()->get(name)); } else { - undo_redo->add_undo_property(GlobalConfig::get_singleton(), name, Variant()); + undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, Variant()); } undo_redo->add_do_method(this, "update_autoload"); @@ -169,7 +169,7 @@ void EditorAutoloadSettings::_autoload_edited() { return; } - if (GlobalConfig::get_singleton()->has("autoload/" + name)) { + if (ProjectSettings::get_singleton()->has("autoload/" + name)) { ti->set_text(0, old_name); EditorNode::get_singleton()->show_warning(vformat(TTR("Autoload '%s' already exists!"), name)); return; @@ -179,18 +179,18 @@ void EditorAutoloadSettings::_autoload_edited() { name = "autoload/" + name; - int order = GlobalConfig::get_singleton()->get_order(selected_autoload); - String path = GlobalConfig::get_singleton()->get(selected_autoload); + int order = ProjectSettings::get_singleton()->get_order(selected_autoload); + String path = ProjectSettings::get_singleton()->get(selected_autoload); undo_redo->create_action(TTR("Rename Autoload")); - undo_redo->add_do_property(GlobalConfig::get_singleton(), name, path); - undo_redo->add_do_method(GlobalConfig::get_singleton(), "set_order", name, order); - undo_redo->add_do_method(GlobalConfig::get_singleton(), "clear", selected_autoload); + undo_redo->add_do_property(ProjectSettings::get_singleton(), name, path); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", name, order); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", selected_autoload); - undo_redo->add_undo_property(GlobalConfig::get_singleton(), selected_autoload, path); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set_order", selected_autoload, order); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "clear", name); + undo_redo->add_undo_property(ProjectSettings::get_singleton(), selected_autoload, path); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", selected_autoload, order); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", name); undo_redo->add_do_method(this, "update_autoload"); undo_redo->add_undo_method(this, "update_autoload"); @@ -207,8 +207,8 @@ void EditorAutoloadSettings::_autoload_edited() { bool checked = ti->is_checked(2); String base = "autoload/" + ti->get_text(0); - int order = GlobalConfig::get_singleton()->get_order(base); - String path = GlobalConfig::get_singleton()->get(base); + int order = ProjectSettings::get_singleton()->get_order(base); + String path = ProjectSettings::get_singleton()->get(base); if (path.begins_with("*")) path = path.substr(1, path.length()); @@ -218,11 +218,11 @@ void EditorAutoloadSettings::_autoload_edited() { undo_redo->create_action(TTR("Toggle AutoLoad Globals")); - undo_redo->add_do_property(GlobalConfig::get_singleton(), base, path); - undo_redo->add_undo_property(GlobalConfig::get_singleton(), base, GlobalConfig::get_singleton()->get(base)); + undo_redo->add_do_property(ProjectSettings::get_singleton(), base, path); + undo_redo->add_undo_property(ProjectSettings::get_singleton(), base, ProjectSettings::get_singleton()->get(base)); - undo_redo->add_do_method(GlobalConfig::get_singleton(), "set_order", base, order); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set_order", base, order); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", base, order); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", base, order); undo_redo->add_do_method(this, "update_autoload"); undo_redo->add_undo_method(this, "update_autoload"); @@ -262,16 +262,16 @@ void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_colu String swap_name = "autoload/" + swap->get_text(0); - int order = GlobalConfig::get_singleton()->get_order(name); - int swap_order = GlobalConfig::get_singleton()->get_order(swap_name); + int order = ProjectSettings::get_singleton()->get_order(name); + int swap_order = ProjectSettings::get_singleton()->get_order(swap_name); undo_redo->create_action(TTR("Move Autoload")); - undo_redo->add_do_method(GlobalConfig::get_singleton(), "set_order", name, swap_order); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set_order", name, order); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", name, swap_order); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", name, order); - undo_redo->add_do_method(GlobalConfig::get_singleton(), "set_order", swap_name, order); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set_order", swap_name, swap_order); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", swap_name, order); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", swap_name, swap_order); undo_redo->add_do_method(this, "update_autoload"); undo_redo->add_undo_method(this, "update_autoload"); @@ -283,15 +283,15 @@ void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_colu } break; case BUTTON_DELETE: { - int order = GlobalConfig::get_singleton()->get_order(name); + int order = ProjectSettings::get_singleton()->get_order(name); undo_redo->create_action(TTR("Remove Autoload")); - undo_redo->add_do_property(GlobalConfig::get_singleton(), name, Variant()); + undo_redo->add_do_property(ProjectSettings::get_singleton(), name, Variant()); - undo_redo->add_undo_property(GlobalConfig::get_singleton(), name, GlobalConfig::get_singleton()->get(name)); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set_persisting", name, true); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set_order", order); + undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, ProjectSettings::get_singleton()->get(name)); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_persisting", name, true); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", order); undo_redo->add_do_method(this, "update_autoload"); undo_redo->add_undo_method(this, "update_autoload"); @@ -322,7 +322,7 @@ void EditorAutoloadSettings::update_autoload() { TreeItem *root = tree->create_item(); List<PropertyInfo> props; - GlobalConfig::get_singleton()->get_property_list(&props); + ProjectSettings::get_singleton()->get_property_list(&props); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { @@ -332,14 +332,14 @@ void EditorAutoloadSettings::update_autoload() { continue; String name = pi.name.get_slice("/", 1); - String path = GlobalConfig::get_singleton()->get(pi.name); + String path = ProjectSettings::get_singleton()->get(pi.name); if (name.empty()) continue; AutoLoadInfo info; info.name = pi.name; - info.order = GlobalConfig::get_singleton()->get_order(pi.name); + info.order = ProjectSettings::get_singleton()->get_order(pi.name); autoload_cache.push_back(info); @@ -459,7 +459,7 @@ void EditorAutoloadSettings::drop_data_fw(const Point2 &p_point, const Variant & move_to_back = true; } - int order = GlobalConfig::get_singleton()->get_order("autoload/" + name); + int order = ProjectSettings::get_singleton()->get_order("autoload/" + name); AutoLoadInfo aux; List<AutoLoadInfo>::Element *E = NULL; @@ -476,7 +476,7 @@ void EditorAutoloadSettings::drop_data_fw(const Point2 &p_point, const Variant & orders.resize(autoload_cache.size()); for (int i = 0; i < autoloads.size(); i++) { - aux.order = GlobalConfig::get_singleton()->get_order("autoload/" + autoloads[i]); + aux.order = ProjectSettings::get_singleton()->get_order("autoload/" + autoloads[i]); List<AutoLoadInfo>::Element *I = autoload_cache.find(aux); @@ -506,8 +506,8 @@ void EditorAutoloadSettings::drop_data_fw(const Point2 &p_point, const Variant & i = 0; for (List<AutoLoadInfo>::Element *E = autoload_cache.front(); E; E = E->next()) { - undo_redo->add_do_method(GlobalConfig::get_singleton(), "set_order", E->get().name, orders[i++]); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set_order", E->get().name, E->get().order); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", E->get().name, orders[i++]); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", E->get().name, E->get().order); } orders.clear(); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 58ffa223fb..f8dbd9abe5 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -31,7 +31,7 @@ #include "editor_node.h" #include "editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" #include "os/dir_access.h" #include "os/file_access.h" @@ -353,6 +353,7 @@ void EditorData::notify_edited_scene_changed() { for (int i = 0; i < editor_plugins.size(); i++) { editor_plugins[i]->edited_scene_changed(); + editor_plugins[i]->notify_scene_changed(get_edited_scene_root()); } } @@ -488,8 +489,14 @@ void EditorData::move_edited_scene_index(int p_idx, int p_to_idx) { } void EditorData::remove_scene(int p_idx) { ERR_FAIL_INDEX(p_idx, edited_scene.size()); - if (edited_scene[p_idx].root) + if (edited_scene[p_idx].root) { + + for (int i = 0; i < editor_plugins.size(); i++) { + editor_plugins[i]->notify_scene_closed(edited_scene[p_idx].root->get_filename()); + } + memdelete(edited_scene[p_idx].root); + } if (current_edited_scene > p_idx) current_edited_scene--; @@ -615,6 +622,17 @@ int EditorData::get_edited_scene_count() const { return edited_scene.size(); } +Vector<EditorData::EditedScene> EditorData::get_edited_scenes() const { + + Vector<EditedScene> out_edited_scenes_list = Vector<EditedScene>(); + + for (int i = 0; i < edited_scene.size(); i++) { + out_edited_scenes_list.push_back(edited_scene[i]); + } + + return out_edited_scenes_list; +} + void EditorData::set_edited_scene_version(uint64_t version, int scene_idx) { ERR_FAIL_INDEX(current_edited_scene, edited_scene.size()); if (scene_idx < 0) { diff --git a/editor/editor_data.h b/editor/editor_data.h index 50f0d5fd41..a601b5019d 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -31,6 +31,7 @@ #define EDITOR_DATA_H #include "editor/editor_plugin.h" +#include "editor/plugins/script_editor_plugin.h" #include "list.h" #include "pair.h" #include "scene/resources/texture.h" @@ -109,6 +110,17 @@ public: Ref<Texture> icon; }; + struct EditedScene { + Node *root; + Dictionary editor_states; + List<Node *> selection; + Vector<EditorHistory::History> history_stored; + int history_current; + Dictionary custom_state; + uint64_t version; + NodePath live_edit_root; + }; + private: Vector<EditorPlugin *> editor_plugins; @@ -124,17 +136,6 @@ private: void _cleanup_history(); - struct EditedScene { - Node *root; - Dictionary editor_states; - List<Node *> selection; - Vector<EditorHistory::History> history_stored; - int history_current; - Dictionary custom_state; - uint64_t version; - NodePath live_edit_root; - }; - Vector<EditedScene> edited_scene; int current_edited_scene; @@ -180,6 +181,7 @@ public: int get_edited_scene() const; Node *get_edited_scene_root(int p_idx = -1); int get_edited_scene_count() const; + Vector<EditedScene> get_edited_scenes() const; String get_scene_title(int p_idx) const; String get_scene_path(int p_idx) const; String get_scene_type(int p_idx) const; diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index 5cd00738a2..6bf92ddd2d 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -33,13 +33,13 @@ #include "editor/plugins/script_editor_plugin.h" #include "editor_node.h" #include "editor_settings.h" -#include "global_config.h" #include "io/config_file.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "io/zip_io.h" #include "os/dir_access.h" #include "os/file_access.h" +#include "project_settings.h" #include "script_language.h" #include "version.h" @@ -200,6 +200,17 @@ Vector<String> EditorExportPreset::get_patches() const { return patches; } +void EditorExportPreset::set_custom_features(const String &p_custom_features) { + + custom_features = p_custom_features; + EditorExport::singleton->save_presets(); +} + +String EditorExportPreset::get_custom_features() const { + + return custom_features; +} + EditorExportPreset::EditorExportPreset() { export_filter = EXPORT_ALL_RESOURCES; @@ -491,9 +502,23 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & //save config! - String config_file = "godot.cfb"; + Vector<String> custom_list; + + if (p_preset->get_custom_features() != String()) { + + Vector<String> tmp_custom_list = p_preset->get_custom_features().split(","); + + for (int i = 0; i < tmp_custom_list.size(); i++) { + String f = tmp_custom_list[i].strip_edges(); + if (f != String()) { + custom_list.push_back(f); + } + } + } + + String config_file = "project.binary"; String engine_cfb = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmp" + config_file; - GlobalConfig::get_singleton()->save_custom(engine_cfb); + ProjectSettings::get_singleton()->save_custom(engine_cfb, ProjectSettings::CustomMap(), custom_list); Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb); p_func(p_udata, "res://" + config_file, data, idx, total); @@ -691,6 +716,7 @@ void EditorExport::_save() { config->set_value(section, "name", preset->get_name()); config->set_value(section, "platform", preset->get_platform()->get_name()); config->set_value(section, "runnable", preset->is_runnable()); + config->set_value(section, "custom_features", preset->get_custom_features()); bool save_files = false; switch (preset->get_export_filter()) { case EditorExportPreset::EXPORT_ALL_RESOURCES: { @@ -823,6 +849,10 @@ void EditorExport::load_config() { preset->set_name(config->get_value(section, "name")); preset->set_runnable(config->get_value(section, "runnable")); + if (config->has_section_key(section, "custom_features")) { + preset->set_custom_features(config->get_value(section, "custom_features")); + } + String export_filter = config->get_value(section, "export_filter"); bool get_files = false; @@ -931,6 +961,11 @@ String EditorExportPlatformPC::get_name() const { return name; } + +String EditorExportPlatformPC::get_os_name() const { + + return os_name; +} Ref<Texture> EditorExportPlatformPC::get_logo() const { return logo; @@ -1033,6 +1068,10 @@ void EditorExportPlatformPC::set_name(const String &p_name) { name = p_name; } +void EditorExportPlatformPC::set_os_name(const String &p_name) { + os_name = p_name; +} + void EditorExportPlatformPC::set_logo(const Ref<Texture> &p_logo) { logo = p_logo; } @@ -1055,6 +1094,20 @@ void EditorExportPlatformPC::set_debug_32(const String &p_file) { debug_file_32 = p_file; } +void EditorExportPlatformPC::add_platform_feature(const String &p_feature) { + + extra_features.insert(p_feature); +} + +void EditorExportPlatformPC::get_platform_features(List<String> *r_features) { + r_features->push_back("pc"); //all pcs support "pc" + r_features->push_back("s3tc"); //all pcs support "s3tc" compression + r_features->push_back(get_os_name()); //OS name is a feature + for (Set<String>::Element *E = extra_features.front(); E; E = E->next()) { + r_features->push_back(E->get()); + } +} + EditorExportPlatformPC::EditorExportPlatformPC() { } @@ -1065,7 +1118,6 @@ EditorExportPlatformPC::EditorExportPlatformPC() { #include "editor/plugins/script_editor_plugin.h" #include "editor_node.h" #include "editor_settings.h" -#include "global_config.h" #include "io/config_file.h" #include "io/md5.h" #include "io/resource_loader.h" @@ -1074,14 +1126,15 @@ EditorExportPlatformPC::EditorExportPlatformPC() { #include "io_plugins/editor_texture_import_plugin.h" #include "os/dir_access.h" #include "os/file_access.h" +#include "project_settings.h" #include "script_language.h" #include "version.h" String EditorImportPlugin::validate_source_path(const String& p_path) { - String gp = GlobalConfig::get_singleton()->globalize_path(p_path); - String rp = GlobalConfig::get_singleton()->get_resource_path(); + String gp = ProjectSettings::get_singleton()->globalize_path(p_path); + String rp = ProjectSettings::get_singleton()->get_resource_path(); if (!rp.ends_with("/")) rp+="/"; @@ -1091,7 +1144,7 @@ String EditorImportPlugin::validate_source_path(const String& p_path) { String EditorImportPlugin::expand_source_path(const String& p_path) { if (p_path.is_rel_path()) { - return GlobalConfig::get_singleton()->get_resource_path().plus_file(p_path).simplify_path(); + return ProjectSettings::get_singleton()->get_resource_path().plus_file(p_path).simplify_path(); } else { return p_path; } @@ -1766,7 +1819,7 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func { MD5_CTX ctx; MD5Init(&ctx); - String path = GlobalConfig::get_singleton()->get_resource_path()+"::"+String(E->get())+"::"+get_name(); + String path = ProjectSettings::get_singleton()->get_resource_path()+"::"+String(E->get())+"::"+get_name(); MD5Update(&ctx,(unsigned char*)path.utf8().get_data(),path.utf8().length()); MD5Final(&ctx); md5 = String::md5(ctx.digest); @@ -1875,11 +1928,11 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func int flags=0; - if (GlobalConfig::get_singleton()->get("image_loader/filter")) + if (ProjectSettings::get_singleton()->get("image_loader/filter")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_FILTER; - if (!GlobalConfig::get_singleton()->get("image_loader/gen_mipmaps")) + if (!ProjectSettings::get_singleton()->get("image_loader/gen_mipmaps")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS; - if (!GlobalConfig::get_singleton()->get("image_loader/repeat")) + if (!ProjectSettings::get_singleton()->get("image_loader/repeat")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_REPEAT; flags|=EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA; @@ -1988,7 +2041,7 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func StringName engine_cfg="res://project.godot"; StringName boot_splash; { - String splash=GlobalConfig::get_singleton()->get("application/boot_splash"); //avoid splash from being converted + String splash=ProjectSettings::get_singleton()->get("application/boot_splash"); //avoid splash from being converted splash=splash.strip_edges(); if (splash!=String()) { if (!splash.begins_with("res://")) @@ -1999,7 +2052,7 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func } StringName custom_cursor; { - String splash=GlobalConfig::get_singleton()->get("display/custom_mouse_cursor"); //avoid splash from being converted + String splash=ProjectSettings::get_singleton()->get("display/custom_mouse_cursor"); //avoid splash from being converted splash=splash.strip_edges(); if (splash!=String()) { if (!splash.begins_with("res://")) @@ -2083,9 +2136,9 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func } - String remap_file="godot.cfb"; + String remap_file="project.binary"; String engine_cfb =EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmp"+remap_file; - GlobalConfig::get_singleton()->save_custom(engine_cfb,custom); + ProjectSettings::get_singleton()->save_custom(engine_cfb,custom); Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb); Error err = p_func(p_udata,"res://"+remap_file,data,counter,files.size()); diff --git a/editor/editor_export.h b/editor/editor_export.h index 64381fbb35..dc4b198575 100644 --- a/editor/editor_export.h +++ b/editor/editor_export.h @@ -70,6 +70,8 @@ private: String name; + String custom_features; + protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; @@ -107,6 +109,9 @@ public: void remove_patch(int p_idx); Vector<String> get_patches() const; + void set_custom_features(const String &p_custom_features); + String get_custom_features() const; + const List<PropertyInfo> &get_properties() const { return properties; } EditorExportPreset(); @@ -153,12 +158,13 @@ private: static Error _save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total); protected: - virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) = 0; bool exists_export_template(String template_file_name, String *err) const; String find_export_template(String template_file_name, String *err = NULL) const; void gen_export_flags(Vector<String> &r_flags, int p_flags); public: + virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) = 0; + struct ExportOption { PropertyInfo option; Variant default_value; @@ -175,6 +181,7 @@ public: virtual void get_export_options(List<ExportOption> *r_options) = 0; virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const { return true; } + virtual String get_os_name() const = 0; virtual String get_name() const = 0; virtual Ref<Texture> get_logo() const = 0; @@ -203,6 +210,7 @@ public: virtual String get_binary_extension() const = 0; virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) = 0; + virtual void get_platform_features(List<String> *r_features) = 0; EditorExportPlatform(); }; @@ -253,6 +261,7 @@ class EditorExportPlatformPC : public EditorExportPlatform { Ref<ImageTexture> logo; String name; + String os_name; String extension; String release_file_32; @@ -260,6 +269,8 @@ class EditorExportPlatformPC : public EditorExportPlatform { String debug_file_32; String debug_file_64; + Set<String> extra_features; + bool use64; public: @@ -268,6 +279,7 @@ public: virtual void get_export_options(List<ExportOption> *r_options); virtual String get_name() const; + virtual String get_os_name() const; virtual Ref<Texture> get_logo() const; virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const; @@ -276,6 +288,7 @@ public: void set_extension(const String &p_extension); void set_name(const String &p_name); + void set_os_name(const String &p_name); void set_logo(const Ref<Texture> &p_loco); @@ -284,6 +297,9 @@ public: void set_debug_64(const String &p_file); void set_debug_32(const String &p_file); + void add_platform_feature(const String &p_feature); + virtual void get_platform_features(List<String> *r_features); + EditorExportPlatformPC(); }; diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index f314f772d1..ed58116304 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -32,12 +32,12 @@ #include "editor_node.h" #include "editor_resource_preview.h" #include "editor_settings.h" -#include "global_config.h" #include "io/resource_import.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "os/file_access.h" #include "os/os.h" +#include "project_settings.h" #include "variant_parser.h" EditorFileSystem *EditorFileSystem::singleton = NULL; @@ -137,7 +137,7 @@ EditorFileSystemDirectory *EditorFileSystemDirectory::get_parent() { void EditorFileSystemDirectory::_bind_methods() { ClassDB::bind_method(D_METHOD("get_subdir_count"), &EditorFileSystemDirectory::get_subdir_count); - ClassDB::bind_method(D_METHOD("get_subdir", "idx"), &EditorFileSystemDirectory::get_subdir); + ClassDB::bind_method(D_METHOD("get_subdir:EditorFileSystemDirectory", "idx"), &EditorFileSystemDirectory::get_subdir); ClassDB::bind_method(D_METHOD("get_file_count"), &EditorFileSystemDirectory::get_file_count); ClassDB::bind_method(D_METHOD("get_file", "idx"), &EditorFileSystemDirectory::get_file); ClassDB::bind_method(D_METHOD("get_file_path", "idx"), &EditorFileSystemDirectory::get_file_path); @@ -179,7 +179,7 @@ void EditorFileSystem::_scan_filesystem() { sources_changed.clear(); file_cache.clear(); - String project = GlobalConfig::get_singleton()->get_resource_path(); + String project = ProjectSettings::get_singleton()->get_resource_path(); String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_cache2"); FileAccess *f = FileAccess::open(fscache, FileAccess::READ); @@ -1008,7 +1008,7 @@ bool EditorFileSystem::_find_file(const String &p_file, EditorFileSystemDirector if (!filesystem || scanning) return false; - String f = GlobalConfig::get_singleton()->localize_path(p_file); + String f = ProjectSettings::get_singleton()->localize_path(p_file); if (!f.begins_with("res://")) return false; @@ -1121,7 +1121,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p if (!filesystem || scanning) return NULL; - String f = GlobalConfig::get_singleton()->localize_path(p_path); + String f = ProjectSettings::get_singleton()->localize_path(p_path); if (!f.begins_with("res://")) return NULL; @@ -1239,7 +1239,7 @@ void EditorFileSystem::_reimport_file(const String &p_file) { String importer_name; if (FileAccess::exists(p_file + ".import")) { - + //use existing Ref<ConfigFile> cf; cf.instance(); Error err = cf->load(p_file + ".import"); @@ -1254,6 +1254,7 @@ void EditorFileSystem::_reimport_file(const String &p_file) { } Ref<ResourceImporter> importer; + bool load_default = false; //find the importer if (importer_name != "") { importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name); @@ -1262,6 +1263,7 @@ void EditorFileSystem::_reimport_file(const String &p_file) { if (importer.is_null()) { //not found by name, find by extension importer = ResourceFormatImporter::get_singleton()->get_importer_by_extension(p_file.get_extension()); + load_default = true; if (importer.is_null()) { ERR_PRINT("BUG: File queued for import, but can't be imported!"); ERR_FAIL(); @@ -1278,6 +1280,17 @@ void EditorFileSystem::_reimport_file(const String &p_file) { } } + if (load_default && ProjectSettings::get_singleton()->get("importer_defaults/" + importer->get_importer_name())) { + //use defaults if exist + Dictionary d = ProjectSettings::get_singleton()->get("importer_defaults/" + importer->get_importer_name()); + List<Variant> v; + d.get_key_list(&v); + + for (List<Variant>::Element *E = v.front(); E; E = E->next()) { + params[E->get()] = d[E->get()]; + } + } + //finally, perform import!! String base_path = ResourceFormatImporter::get_singleton()->get_import_base_path(p_file); @@ -1335,7 +1348,7 @@ void EditorFileSystem::_reimport_file(const String &p_file) { f->store_line("[params]"); f->store_line(""); - //store options in provided order, to avoid file changing + //store options in provided order, to avoid file changing. Order is also important because first match is accepted first. for (List<ResourceImporter::ImportOption>::Element *E = opts.front(); E; E = E->next()) { diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 952c98d0f6..e890082ee1 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -36,7 +36,8 @@ #include "os/keyboard.h" void EditorHelpSearch::popup() { - popup_centered_ratio(0.6); + + popup_centered(Size2(700, 600) * EDSCALE); if (search_box->get_text() != "") { search_box->select_all(); _update_search(); @@ -46,7 +47,7 @@ void EditorHelpSearch::popup() { void EditorHelpSearch::popup(const String &p_term) { - popup_centered_ratio(0.6); + popup_centered(Size2(700, 600) * EDSCALE); if (p_term != "") { search_box->set_text(p_term); search_box->select_all(); @@ -262,6 +263,8 @@ void EditorHelpSearch::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { + search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + connect("confirmed", this, "_confirmed"); _update_search(); } @@ -293,12 +296,7 @@ EditorHelpSearch::EditorHelpSearch() { HBoxContainer *sb_hb = memnew(HBoxContainer); search_box = memnew(LineEdit); - sb_hb->add_child(search_box); - search_box->set_h_size_flags(SIZE_EXPAND_FILL); - Button *sb = memnew(Button(TTR("Search"))); - sb->connect("pressed", this, "_update_search"); - sb_hb->add_child(sb); - vbc->add_margin_child(TTR("Search:"), sb_hb); + vbc->add_child(search_box); search_box->connect("text_changed", this, "_text_changed"); search_box->connect("gui_input", this, "_sbox_input"); search_options = memnew(Tree); @@ -378,7 +376,7 @@ void EditorHelpIndex::select_class(const String &p_class) { void EditorHelpIndex::popup() { - popup_centered_ratio(0.6); + popup_centered(Size2(500, 600) * EDSCALE); search_box->set_text(""); _update_class_list(); @@ -388,6 +386,7 @@ void EditorHelpIndex::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { + search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); _update_class_list(); connect("confirmed", this, "_tree_item_selected"); @@ -478,7 +477,7 @@ EditorHelpIndex::EditorHelpIndex() { add_child(vbc); search_box = memnew(LineEdit); - vbc->add_margin_child(TTR("Search:"), search_box); + vbc->add_child(search_box); search_box->set_h_size_flags(SIZE_EXPAND_FILL); register_text_enter(search_box); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 00609b22d7..0c47daf5e6 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -30,7 +30,6 @@ #include "editor_node.h" #include "animation_editor.h" -#include "authors.gen.h" #include "bind/core_bind.h" #include "class_db.h" #include "core/io/resource_loader.h" @@ -39,11 +38,9 @@ #include "editor_help.h" #include "editor_settings.h" #include "editor_themes.h" -#include "global_config.h" #include "io/config_file.h" #include "io/stream_peer_ssl.h" #include "io/zip_io.h" -#include "license.gen.h" #include "main/input_default.h" #include "message_queue.h" #include "os/file_access.h" @@ -52,6 +49,7 @@ #include "os/os.h" #include "path_remap.h" #include "print_string.h" +#include "project_settings.h" #include "pvrtc_compress.h" #include "register_exporters.h" #include "scene/resources/packed_scene.h" @@ -163,7 +161,7 @@ void EditorNode::_update_scene_tabs() { void EditorNode::_update_title() { - String appname = GlobalConfig::get_singleton()->get("application/config/name"); + String appname = ProjectSettings::get_singleton()->get("application/config/name"); String title = appname.empty() ? String(VERSION_FULL_NAME) : String(_MKSTR(VERSION_NAME) + String(" - ") + appname); String edited = editor_data.get_edited_scene_root() ? editor_data.get_edited_scene_root()->get_filename() : String(); if (!edited.empty()) @@ -272,7 +270,7 @@ void EditorNode::_notification(int p_what) { } editor_selection->update(); - scene_root->set_size_override(true, Size2(GlobalConfig::get_singleton()->get("display/window/size/width"), GlobalConfig::get_singleton()->get("display/window/size/height"))); + scene_root->set_size_override(true, Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"))); ResourceImporterTexture::get_singleton()->update_imports(); } @@ -519,7 +517,7 @@ void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const St flg|=ResourceSaver::FLAG_RELATIVE_PATHS; */ - String path = GlobalConfig::get_singleton()->localize_path(p_path); + String path = ProjectSettings::get_singleton()->localize_path(p_path); Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS); if (err != OK) { @@ -870,7 +868,7 @@ void EditorNode::_save_scene_with_preview(String p_file) { //save thumbnail directly, as thumbnailer may not update due to actual scene not changing md5 String temp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp"); - String cache_base = GlobalConfig::get_singleton()->globalize_path(p_file).md5_text(); + String cache_base = ProjectSettings::get_singleton()->globalize_path(p_file).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); //does not have it, try to load a cached thumbnail @@ -950,7 +948,7 @@ void EditorNode::_save_scene(String p_file, int idx) { _save_edited_subresources(scene, processed, flg); editor_data.save_editor_external_data(); if (err == OK) { - scene->set_filename(GlobalConfig::get_singleton()->localize_path(p_file)); + scene->set_filename(ProjectSettings::get_singleton()->localize_path(p_file)); //EditorFileSystem::get_singleton()->update_file(p_file,sdata->get_type()); if (idx < 0 || idx == editor_data.get_edited_scene()) set_current_version(editor_data.get_undo_redo().get_version()); @@ -1029,7 +1027,7 @@ void EditorNode::_import_action(const String &p_action) { EditorImport::generate_version_hashes(src); - Node *dst = SceneLoader::load(editor_data.get_imported_scene(GlobalConfig::get_singleton()->localize_path(_tmp_import_path))); + Node *dst = SceneLoader::load(editor_data.get_imported_scene(ProjectSettings::get_singleton()->localize_path(_tmp_import_path))); if (!dst) { @@ -1132,8 +1130,8 @@ void EditorNode::_dialog_action(String p_file) { } break; case SETTINGS_PICK_MAIN_SCENE: { - GlobalConfig::get_singleton()->set("application/run/main_scene", p_file); - GlobalConfig::get_singleton()->save(); + ProjectSettings::get_singleton()->set("application/run/main_scene", p_file); + ProjectSettings::get_singleton()->save(); //would be nice to show the project manager opened with the highlighted field.. _run(false, ""); // automatically run the project } break; @@ -1575,6 +1573,11 @@ void EditorNode::_edit_current() { editor_plugin_screen->make_visible(true); + int plugin_count = editor_data.get_editor_plugin_count(); + for (int i = 0; i < plugin_count; i++) { + editor_data.get_editor_plugin(i)->notify_main_screen_changed(editor_plugin_screen->get_name()); + } + for (int i = 0; i < editor_table.size(); i++) { main_editor_buttons[i]->set_pressed(editor_table[i] == main_plugin); @@ -1628,7 +1631,7 @@ void EditorNode::_edit_current() { p->add_separator(); p->add_shortcut(ED_SHORTCUT("property_editor/make_subresources_unique", TTR("Make Sub-Resources Unique")), OBJECT_UNIQUE_RESOURCES); p->add_separator(); - p->add_icon_shortcut(gui_base->get_icon("Help", "EditorIcons"), ED_SHORTCUT("property_editor/open_help", TTR("Open in Help")), OBJECT_REQUEST_HELP); + p->add_icon_shortcut(gui_base->get_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("property_editor/open_help", TTR("Open in Help")), OBJECT_REQUEST_HELP); } List<MethodInfo> methods; @@ -1797,7 +1800,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) { List<String> breakpoints; editor_data.get_editor_breakpoints(&breakpoints); - args = GlobalConfig::get_singleton()->get("editor/main_run_args"); + args = ProjectSettings::get_singleton()->get("editor/main_run_args"); Error error = editor_run.run(run_filename, args, breakpoints); @@ -2264,7 +2267,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } instanced_scene->generate_instance_state(); - instanced_scene->set_filename( GlobalConfig::get_singleton()->localize_path(external_file) ); + instanced_scene->set_filename( ProjectSettings::get_singleton()->localize_path(external_file) ); editor_data.get_undo_redo().create_action("Instance Scene"); editor_data.get_undo_redo().add_do_method(parent,"add_child",instanced_scene); @@ -2515,8 +2518,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } } - if (OS::get_singleton()->is_window_minimized()) - OS::get_singleton()->request_attention(); + OS::get_singleton()->request_attention(); break; } @@ -2865,6 +2867,11 @@ void EditorNode::_editor_select(int p_which) { editor_plugin_screen->make_visible(true); editor_plugin_screen->selected_notify(); + int plugin_count = editor_data.get_editor_plugin_count(); + for (int i = 0; i < plugin_count; i++) { + editor_data.get_editor_plugin(i)->notify_main_screen_changed(editor_plugin_screen->get_name()); + } + if (EditorSettings::get_singleton()->get("interface/separate_distraction_mode")) { if (p_which == EDITOR_SCRIPT) { set_distraction_free_mode(script_distraction); @@ -2913,7 +2920,6 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor) { } } - //singleton->main_editor_tabs->add_tab(p_editor->get_name()); singleton->editor_table.erase(p_editor); } p_editor->make_visible(false); @@ -2935,9 +2941,9 @@ void EditorNode::_update_addon_config() { } if (enabled_addons.size() == 0) { - GlobalConfig::get_singleton()->set("editor_plugins/enabled", Variant()); + ProjectSettings::get_singleton()->set("editor_plugins/enabled", Variant()); } else { - GlobalConfig::get_singleton()->set("editor_plugins/enabled", enabled_addons); + ProjectSettings::get_singleton()->set("editor_plugins/enabled", enabled_addons); } project_settings->queue_save(); @@ -3278,7 +3284,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b if (p_clear_errors) load_errors->clear(); - String lpath = GlobalConfig::get_singleton()->localize_path(p_scene); + String lpath = ProjectSettings::get_singleton()->localize_path(p_scene); if (!lpath.begins_with("res://")) { @@ -3566,7 +3572,7 @@ void EditorNode::animation_editor_make_visible(bool p_visible) { #endif void EditorNode::_add_to_recent_scenes(const String &p_scene) { - String base = "_" + GlobalConfig::get_singleton()->get_resource_path().replace("\\", "::").replace("/", "::"); + String base = "_" + ProjectSettings::get_singleton()->get_resource_path().replace("\\", "::").replace("/", "::"); Vector<String> rc = EDITOR_DEF(base + "/_recent_scenes", Array()); String name = p_scene; name = name.replace("res://", ""); @@ -3583,21 +3589,12 @@ void EditorNode::_add_to_recent_scenes(const String &p_scene) { void EditorNode::_open_recent_scene(int p_idx) { - String base = "_" + GlobalConfig::get_singleton()->get_resource_path().replace("\\", "::").replace("/", "::"); + String base = "_" + ProjectSettings::get_singleton()->get_resource_path().replace("\\", "::").replace("/", "::"); Vector<String> rc = EDITOR_DEF(base + "/_recent_scenes", Array()); ERR_FAIL_INDEX(p_idx, rc.size()); String path = "res://" + rc[p_idx]; - - /*if (unsaved_cache) { - _recent_scene=rc[p_idx]; - open_recent_confirmation->set_text("Discard current scene and open:\n'"+rc[p_idx]+"'"); - open_recent_confirmation->get_label()->set_align(Label::ALIGN_CENTER); - open_recent_confirmation->popup_centered(Size2(400,100)); - return; - }*/ - load_scene(path); } @@ -3635,13 +3632,13 @@ void EditorNode::_save_optimized() { } - project_settings->add_remapped_path(GlobalConfig::get_singleton()->localize_path(get_edited_scene()->get_filename()),GlobalConfig::get_singleton()->localize_path(path),platform); + project_settings->add_remapped_path(ProjectSettings::get_singleton()->localize_path(get_edited_scene()->get_filename()),ProjectSettings::get_singleton()->localize_path(path),platform); #endif } void EditorNode::_update_recent_scenes() { - String base = "_" + GlobalConfig::get_singleton()->get_resource_path().replace("\\", "::").replace("/", "::"); + String base = "_" + ProjectSettings::get_singleton()->get_resource_path().replace("\\", "::").replace("/", "::"); Vector<String> rc = EDITOR_DEF(base + "/_recent_scenes", Array()); recent_scenes->clear(); for (int i = 0; i < rc.size(); i++) { @@ -3756,6 +3753,7 @@ void EditorNode::register_editor_types() { ClassDB::register_class<EditorResourcePreviewGenerator>(); ClassDB::register_class<EditorFileSystem>(); ClassDB::register_class<EditorFileSystemDirectory>(); + ClassDB::register_virtual_class<ScriptEditor>(); //ClassDB::register_type<EditorImporter>(); //ClassDB::register_type<EditorPostImport>(); @@ -4959,13 +4957,6 @@ void EditorNode::_check_gui_base_size() { } } -void EditorNode::_license_tree_selected() { - - TreeItem *selected = _tpl_tree->get_selected(); - _tpl_text->select(0, 0, 0, 0); - _tpl_text->set_text(selected->get_metadata(0)); -} - void EditorNode::open_export_template_manager() { export_template_manager->popup_manager(); @@ -5056,8 +5047,6 @@ void EditorNode::_bind_methods() { ClassDB::bind_method(D_METHOD("_dim_timeout"), &EditorNode::_dim_timeout); ClassDB::bind_method(D_METHOD("_check_gui_base_size"), &EditorNode::_check_gui_base_size); - ClassDB::bind_method(D_METHOD("_license_tree_selected"), &EditorNode::_license_tree_selected); - ADD_SIGNAL(MethodInfo("play_pressed")); ADD_SIGNAL(MethodInfo("pause_pressed")); ADD_SIGNAL(MethodInfo("stop_pressed")); @@ -5222,28 +5211,9 @@ EditorNode::EditorNode() { main_vbox->set_area_as_parent_rect(8); main_vbox->set_margin(MARGIN_TOP, 5); -#if 0 - PanelContainer *top_dark_panel = memnew( PanelContainer ); - Ref<StyleBoxTexture> top_dark_sb; - top_dark_sb.instance(); - top_dark_sb->set_texture(theme->get_icon("PanelTop","EditorIcons")); - for(int i=0;i<4;i++) { - top_dark_sb->set_margin_size(Margin(i),3); - top_dark_sb->set_default_margin(Margin(i),0); - } - top_dark_sb->set_expand_margin_size(MARGIN_LEFT,20); - top_dark_sb->set_expand_margin_size(MARGIN_RIGHT,20); - - top_dark_panel->add_style_override("panel",top_dark_sb); - VBoxContainer *top_dark_vb = memnew( VBoxContainer ); - main_vbox->add_child(top_dark_panel); - top_dark_panel->add_child(top_dark_vb); -#endif - menu_hb = memnew(HBoxContainer); main_vbox->add_child(menu_hb); - //top_dark_vb->add_child(scene_tabs); //left left_l_hsplit = memnew(HSplitContainer); main_vbox->add_child(left_l_hsplit); @@ -5318,10 +5288,10 @@ EditorNode::EditorNode() { main_hsplit->connect("dragged", this, "_dock_split_dragged"); right_hsplit->connect("dragged", this, "_dock_split_dragged"); - dock_select_popoup = memnew(PopupPanel); - gui_base->add_child(dock_select_popoup); + dock_select_popup = memnew(PopupPanel); + gui_base->add_child(dock_select_popup); VBoxContainer *dock_vb = memnew(VBoxContainer); - dock_select_popoup->add_child(dock_vb); + dock_select_popup->add_child(dock_vb); HBoxContainer *dock_hb = memnew(HBoxContainer); dock_tab_move_left = memnew(ToolButton); @@ -5348,14 +5318,13 @@ EditorNode::EditorNode() { dock_select->set_v_size_flags(Control::SIZE_EXPAND_FILL); dock_vb->add_child(dock_select); - dock_select_popoup->set_as_minsize(); + dock_select_popup->set_as_minsize(); dock_select_rect_over = -1; dock_popup_selected = -1; - //dock_select_popoup->set_(Size2(20,20)); for (int i = 0; i < DOCK_SLOT_MAX; i++) { dock_slot[i]->set_custom_minimum_size(Size2(230, 220) * EDSCALE); dock_slot[i]->set_v_size_flags(Control::SIZE_EXPAND_FILL); - dock_slot[i]->set_popup(dock_select_popoup); + dock_slot[i]->set_popup(dock_select_popup); dock_slot[i]->connect("pre_popup_pressed", this, "_dock_pre_popup", varray(i)); dock_slot[i]->set_tab_align(TabContainer::ALIGN_LEFT); } @@ -5376,10 +5345,6 @@ EditorNode::EditorNode() { top_split->add_child(srt); srt->add_constant_override("separation", 0); - /* main_editor_tabs = memnew( Tabs ); - main_editor_tabs->connect("tab_changed",this,"_editor_select"); - main_editor_tabs->set_tab_close_display_policy(Tabs::SHOW_NEVER); -*/ tab_preview_panel = memnew(Panel); tab_preview_panel->set_size(Size2(100, 100) * EDSCALE); tab_preview_panel->hide(); @@ -5415,6 +5380,7 @@ EditorNode::EditorNode() { distraction_free = memnew(ToolButton); tabbar_container->add_child(distraction_free); distraction_free->set_shortcut(ED_SHORTCUT("editor/distraction_free_mode", TTR("Distraction Free Mode"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F11)); + distraction_free->set_tooltip(TTR("Toggle distraction-free mode.")); distraction_free->connect("pressed", this, "_toggle_distraction_free_mode"); distraction_free->set_icon(gui_base->get_icon("DistractionFree", "EditorIcons")); distraction_free->set_toggle_mode(true); @@ -5442,7 +5408,7 @@ EditorNode::EditorNode() { VisualServer::get_singleton()->viewport_set_hide_scenario(scene_root->get_viewport_rid(), true); scene_root->set_disable_input(true); scene_root->set_as_audio_listener_2d(true); - //scene_root->set_size_override(true,Size2(GlobalConfig::get_singleton()->get("display/width"),GlobalConfig::get_singleton()->get("display/height"))); + //scene_root->set_size_override(true,Size2(ProjectSettings::get_singleton()->get("display/width"),ProjectSettings::get_singleton()->get("display/height"))); //scene_root->set_world_2d( Ref<World2D>( memnew( World2D )) ); @@ -5493,7 +5459,6 @@ EditorNode::EditorNode() { p->add_separator(); p->add_shortcut(ED_SHORTCUT("editor/close_scene", TTR("Close Scene"), KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_W), FILE_CLOSE); p->add_separator(); - //p->add_shortcut(ED_SHORTCUT("editor/save_scene",TTR("Close Goto Prev. Scene")),FILE_OPEN_PREV,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_P); p->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT); p->add_separator(); p->add_shortcut(ED_SHORTCUT("editor/quick_open_scene", TTR("Quick Open Scene.."), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_O), FILE_QUICK_OPEN_SCENE); @@ -5561,35 +5526,6 @@ EditorNode::EditorNode() { menu_hb->add_spacer(); menu_hb->add_child(editor_region); -//menu_hb->add_spacer(); -#if 0 - node_menu = memnew( MenuButton ); - node_menu->set_text("Node"); - node_menu->set_position( Point2( 50,0) ); - menu_panel->add_child( node_menu ); - - p=node_menu->get_popup(); - p->add_item("Create",NODE_CREATE); - p->add_item("Instance",NODE_INSTANCE); - p->add_separator(); - p->add_item("Reparent",NODE_REPARENT); - p->add_item("Move Up",NODE_MOVE_UP); - p->add_item("Move Down",NODE_MOVE_DOWN); - p->add_separator(); - p->add_item("Duplicate",NODE_DUPLICATE); - p->add_separator(); - p->add_item("Remove (Branch)",NODE_REMOVE_BRANCH); - p->add_item("Remove (Element)",NODE_REMOVE_ELEMENT); - p->add_separator(); - p->add_item("Edit Subscriptions..",NODE_CONNECTIONS); - p->add_item("Edit Groups..",NODE_GROUPS); - - resource_menu = memnew( MenuButton ); - resource_menu->set_text("Resource"); - resource_menu->set_position( Point2( 90,0) ); - menu_panel->add_child( resource_menu ); -#endif - debug_menu = memnew(MenuButton); debug_menu->set_text(TTR("Debug")); debug_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles")); @@ -5642,7 +5578,7 @@ EditorNode::EditorNode() { p = help_menu->get_popup(); p->connect("id_pressed", this, "_menu_option"); p->add_icon_item(gui_base->get_icon("ClassList", "EditorIcons"), TTR("Classes"), HELP_CLASSES); - p->add_icon_item(gui_base->get_icon("Help", "EditorIcons"), TTR("Search"), HELP_SEARCH); + p->add_icon_item(gui_base->get_icon("HelpSearch", "EditorIcons"), TTR("Search"), HELP_SEARCH); p->add_separator(); p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Online Docs"), HELP_DOCS); p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Q&A"), HELP_QA); @@ -5651,11 +5587,6 @@ EditorNode::EditorNode() { p->add_separator(); p->add_icon_item(gui_base->get_icon("GodotDocs", "EditorIcons"), TTR("About"), HELP_ABOUT); - //Separator *s1 = memnew( VSeparator ); - //menu_panel->add_child(s1); - //s1->set_position(Point2(210,4)); - //s1->set_size(Point2(10,15)); - play_cc = memnew(CenterContainer); play_cc->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); menu_hb->add_child(play_cc); @@ -5680,7 +5611,6 @@ EditorNode::EditorNode() { play_button->set_shortcut(ED_SHORTCUT("editor/play", TTR("Play"), KEY_F5)); pause_button = memnew(ToolButton); - //menu_panel->add_child(pause_button); - not needed for now? pause_button->set_toggle_mode(true); pause_button->set_icon(gui_base->get_icon("Pause", "EditorIcons")); pause_button->set_focus_mode(Control::FOCUS_NONE); @@ -5708,9 +5638,6 @@ EditorNode::EditorNode() { native_play_button->get_popup()->connect("id_pressed", this, "_run_in_device"); run_native->connect("native_run", this, "_menu_option", varray(RUN_PLAY_NATIVE)); - //VSeparator *s1 = memnew( VSeparator ); - //play_hb->add_child(s1); - play_scene_button = memnew(ToolButton); play_hb->add_child(play_scene_button); play_scene_button->set_toggle_mode(true); @@ -5729,24 +5656,6 @@ EditorNode::EditorNode() { play_custom_scene_button->set_tooltip(TTR("Play custom scene")); play_custom_scene_button->set_shortcut(ED_SHORTCUT("editor/play_custom_scene", TTR("Play Custom Scene"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F5)); - /* - run_settings_button = memnew( ToolButton ); - //menu_hb->add_child(run_settings_button); - //run_settings_button->set_toggle_mode(true); - run_settings_button->set_focus_mode(Control::FOCUS_NONE); - run_settings_button->set_icon(gui_base->get_icon("Run","EditorIcons")); - run_settings_button->connect("pressed", this,"_menu_option",make_binds(RUN_SCENE_SETTINGS)); -*/ - - /* - run_settings_button = memnew( ToolButton ); - menu_panel->add_child(run_settings_button); - run_settings_button->set_position(Point2(305,0)); - run_settings_button->set_focus_mode(Control::FOCUS_NONE); - run_settings_button->set_icon(gui_base->get_icon("Run","EditorIcons")); - run_settings_button->connect("pressed", this,"_menu_option",make_binds(RUN_SETTINGS)); -*/ - progress_hb = memnew(BackgroundProgress); //menu_hb->add_child(progress_hb); @@ -5785,52 +5694,15 @@ EditorNode::EditorNode() { p->add_check_item(TTR("Disable Update Spinner"), SETTINGS_UPDATE_SPINNER_HIDE); p->set_item_checked(1, true); - //sources_button->connect(); - - /* - Separator *s2 = memnew( VSeparator ); - menu_panel->add_child(s2); - s2->set_position(Point2(338,4)); - s2->set_size(Point2(10,15)); -*/ - - //editor_hsplit = memnew( HSplitContainer ); - //main_split->add_child(editor_hsplit); - //editor_hsplit->set_v_size_flags(Control::SIZE_EXPAND_FILL); - - //editor_vsplit = memnew( VSplitContainer ); - //editor_hsplit->add_child(editor_vsplit); - - //top_pallete = memnew( TabContainer ); scene_tree_dock = memnew(SceneTreeDock(this, scene_root, editor_selection, editor_data)); scene_tree_dock->set_name(TTR("Scene")); - //top_pallete->add_child(scene_tree_dock); dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(scene_tree_dock); #if 0 resources_dock = memnew( ResourcesDock(this) ); resources_dock->set_name("Resources"); - //top_pallete->add_child(resources_dock); dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(resources_dock); - //top_pallete->set_v_size_flags(Control::SIZE_EXPAND_FILL); #endif dock_slot[DOCK_SLOT_LEFT_BR]->hide(); - /*Control *editor_spacer = memnew( Control ); - editor_spacer->set_custom_minimum_size(Size2(260,200)); - editor_spacer->set_v_size_flags(Control::SIZE_EXPAND_FILL); - editor_vsplit->add_child( editor_spacer ); - editor_spacer->add_child( top_pallete ); - top_pallete->set_area_as_parent_rect();*/ - - //prop_pallete = memnew( TabContainer ); - - //prop_pallete->set_v_size_flags(Control::SIZE_EXPAND_FILL); - - /*editor_spacer = memnew( Control ); - editor_spacer->set_custom_minimum_size(Size2(260,200)); - editor_spacer->set_v_size_flags(Control::SIZE_EXPAND_FILL); - editor_vsplit->add_child( editor_spacer ); - editor_spacer->add_child( prop_pallete ); - prop_pallete->set_area_as_parent_rect();*/ VBoxContainer *prop_editor_base = memnew(VBoxContainer); prop_editor_base->set_name(TTR("Inspector")); // Properties? @@ -5972,7 +5844,6 @@ EditorNode::EditorNode() { } else { dock_slot[DOCK_SLOT_LEFT_UR]->add_child(filesystem_dock); } - //prop_pallete->add_child(filesystem_dock); filesystem_dock->connect("open", this, "open_request"); filesystem_dock->connect("instance", this, "_instance_request"); @@ -6023,17 +5894,6 @@ EditorNode::EditorNode() { //progress_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); - /* - animation_menu = memnew( ToolButton ); - animation_menu->set_position(Point2(500,0)); - animation_menu->set_size(Size2(20,20)); - animation_menu->set_toggle_mode(true); - animation_menu->set_focus_mode(Control::FOCUS_NONE); - menu_panel->add_child(animation_menu); - animation_menu->set_icon(gui_base->get_icon("Animation","EditorIcons")); - animation_menu->connect("pressed",this,"_animation_visibility_toggle"); -*/ - orphan_resources = memnew(OrphanResourcesDialog); gui_base->add_child(orphan_resources); @@ -6077,7 +5937,7 @@ EditorNode::EditorNode() { settings_config_dialog = memnew(EditorSettingsDialog); gui_base->add_child(settings_config_dialog); - project_settings = memnew(ProjectSettings(&editor_data)); + project_settings = memnew(ProjectSettingsEditor(&editor_data)); gui_base->add_child(project_settings); import_confirmation = memnew(ConfirmationDialog); @@ -6088,170 +5948,15 @@ EditorNode::EditorNode() { import_confirmation->connect("custom_action", this, "_import_action"); gui_base->add_child(import_confirmation); - open_recent_confirmation = memnew(ConfirmationDialog); - add_child(open_recent_confirmation); - open_recent_confirmation->connect("confirmed", this, "_open_recent_scene_confirm"); - run_settings_dialog = memnew(RunSettingsDialog); gui_base->add_child(run_settings_dialog); export_template_manager = memnew(ExportTemplateManager); gui_base->add_child(export_template_manager); - { - - about = memnew(AcceptDialog); - about->set_title(TTR("Thanks from the Godot community!")); - about->get_ok()->set_text(TTR("Thanks!")); - about->set_hide_on_ok(true); - about->set_resizable(true); - gui_base->add_child(about); - - VBoxContainer *vbc = memnew(VBoxContainer); - HBoxContainer *hbc = memnew(HBoxContainer); - hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); - hbc->set_alignment(BoxContainer::ALIGN_CENTER); - hbc->add_constant_override("separation", 30 * EDSCALE); - about->add_child(vbc); - vbc->add_child(hbc); - - TextureRect *logo = memnew(TextureRect); - logo->set_texture(gui_base->get_icon("Logo", "EditorIcons")); - hbc->add_child(logo); - - Label *about_text = memnew(Label); - about_text->set_v_size_flags(Control::SIZE_SHRINK_CENTER); - about_text->set_text(VERSION_FULL_NAME + String::utf8("\n\u00A9 2007-2017 Juan Linietsky, Ariel Manzur.\n\u00A9 2014-2017 ") + - TTR("Godot Engine contributors") + "\n"); - hbc->add_child(about_text); - - TabContainer *tc = memnew(TabContainer); - tc->set_custom_minimum_size(Size2(600, 240) * EDSCALE); - tc->set_v_size_flags(Control::SIZE_EXPAND_FILL); - vbc->add_child(tc); - - ScrollContainer *dev_base = memnew(ScrollContainer); - dev_base->set_name(TTR("Authors")); - dev_base->set_v_size_flags(Control::SIZE_EXPAND); - tc->add_child(dev_base); - - VBoxContainer *dev_vbc = memnew(VBoxContainer); - dev_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); - dev_base->add_child(dev_vbc); - - List<String> dev_sections; - dev_sections.push_back(TTR("Project Founders")); - dev_sections.push_back(TTR("Lead Developer")); - dev_sections.push_back(TTR("Project Manager")); - dev_sections.push_back(TTR("Developers")); - - const char **dev_src[] = { dev_founders, dev_lead, dev_manager, dev_names }; - - for (int i = 0; i < dev_sections.size(); i++) { - - Label *lbl = memnew(Label); - lbl->set_text(dev_sections[i]); - dev_vbc->add_child(lbl); - - ItemList *il = memnew(ItemList); - il->set_max_columns(32); - il->set_h_size_flags(Control::SIZE_EXPAND_FILL); - il->set_custom_minimum_size(Size2(0, i == 3 ? DEV_NAMES_COUNT * 7.6 : 30) * EDSCALE); - const char **dev_names_ptr = dev_src[i]; - while (*dev_names_ptr) - il->add_item(String::utf8(*dev_names_ptr++), NULL, false); - dev_vbc->add_child(il); - il->set_fixed_column_width(240 * EDSCALE); - - HSeparator *hs = memnew(HSeparator); - hs->set_modulate(Color(0, 0, 0, 0)); - dev_vbc->add_child(hs); - } - - TextEdit *license = memnew(TextEdit); - license->set_name(TTR("License")); - license->set_h_size_flags(Control::SIZE_EXPAND_FILL); - license->set_v_size_flags(Control::SIZE_EXPAND_FILL); - license->set_wrap(true); - license->set_readonly(true); - license->set_text(String::utf8(about_license)); - tc->add_child(license); - - VBoxContainer *license_thirdparty = memnew(VBoxContainer); - license_thirdparty->set_name(TTR("Thirdparty License")); - license_thirdparty->set_h_size_flags(Control::SIZE_EXPAND_FILL); - tc->add_child(license_thirdparty); - - Label *tpl_label = memnew(Label); - tpl_label->set_custom_minimum_size(Size2(0, 64 * EDSCALE)); - tpl_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); - tpl_label->set_autowrap(true); - tpl_label->set_text(TTR("Godot Engine relies on a number of thirdparty free and open source libraries, all compatible with the terms of its MIT license. The following is an exhaustive list of all such thirdparty components with their respective copyright statements and license terms.")); - license_thirdparty->add_child(tpl_label); - - HSplitContainer *tpl_hbc = memnew(HSplitContainer); - tpl_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); - tpl_hbc->set_v_size_flags(Control::SIZE_EXPAND_FILL); - tpl_hbc->set_split_offset(240 * EDSCALE); - license_thirdparty->add_child(tpl_hbc); - - _tpl_tree = memnew(Tree); - _tpl_tree->set_hide_root(true); - TreeItem *root = _tpl_tree->create_item(); - TreeItem *tpl_ti_all = _tpl_tree->create_item(root); - tpl_ti_all->set_text(0, TTR("All Components")); - TreeItem *tpl_ti_tp = _tpl_tree->create_item(root); - tpl_ti_tp->set_text(0, TTR("Components")); - tpl_ti_tp->set_selectable(0, false); - TreeItem *tpl_ti_lc = _tpl_tree->create_item(root); - tpl_ti_lc->set_text(0, TTR("Licenses")); - tpl_ti_lc->set_selectable(0, false); - int read_idx = 0; - String long_text = ""; - for (int i = 0; i < THIRDPARTY_COUNT; i++) { - - TreeItem *ti = _tpl_tree->create_item(tpl_ti_tp); - String thirdparty = String(about_thirdparty[i]); - ti->set_text(0, thirdparty); - String text = thirdparty + "\n"; - long_text += "- " + thirdparty + "\n\n"; - for (int j = 0; j < about_tp_copyright_count[i]; j++) { - - text += "\n Files:\n " + String(about_tp_file[read_idx]).replace("\n", "\n ") + "\n"; - String copyright = String::utf8(" \u00A9 ") + String::utf8(about_tp_copyright[read_idx]).replace("\n", String::utf8("\n \u00A9 ")); - text += copyright; - long_text += copyright; - String license = "\n License: " + String(about_tp_license[read_idx]) + "\n"; - text += license; - long_text += license + "\n"; - read_idx++; - } - ti->set_metadata(0, text); - } - for (int i = 0; i < LICENSE_COUNT; i++) { - - TreeItem *ti = _tpl_tree->create_item(tpl_ti_lc); - String licensename = String(about_license_name[i]); - ti->set_text(0, licensename); - long_text += "- " + licensename + "\n\n"; - String licensebody = String(about_license_body[i]); - ti->set_metadata(0, licensebody); - long_text += " " + licensebody.replace("\n", "\n ") + "\n\n"; - } - tpl_ti_all->set_metadata(0, long_text); - tpl_hbc->add_child(_tpl_tree); - - _tpl_text = memnew(TextEdit); - _tpl_text->set_h_size_flags(Control::SIZE_EXPAND_FILL); - _tpl_text->set_v_size_flags(Control::SIZE_EXPAND_FILL); - _tpl_text->set_wrap(true); - _tpl_text->set_readonly(true); - tpl_hbc->add_child(_tpl_text); - - _tpl_tree->connect("item_selected", this, "_license_tree_selected"); - tpl_ti_all->select(0); - _tpl_text->set_text(tpl_ti_all->get_metadata(0)); - } + about = memnew(EditorAbout); + about->get_logo()->set_texture(gui_base->get_icon("Logo", "EditorIcons")); + gui_base->add_child(about); warning = memnew(AcceptDialog); gui_base->add_child(warning); @@ -6375,7 +6080,7 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(TextureEditorPlugin(this))); add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor))); //add_editor_plugin( memnew( MaterialEditorPlugin(this) ) ); - //add_editor_plugin( memnew( MeshEditorPlugin(this) ) ); + add_editor_plugin(memnew(MeshEditorPlugin(this))); for (int i = 0; i < EditorPlugins::get_plugin_count(); i++) add_editor_plugin(EditorPlugins::create(i, this)); @@ -6408,7 +6113,7 @@ EditorNode::EditorNode() { Physics2DServer::get_singleton()->set_active(false); // no physics by default if editor ScriptServer::set_scripting_enabled(false); // no scripting by default if editor - //GlobalConfig::get_singleton()->set("render/room_cull_enabled",false); + //ProjectSettings::get_singleton()->set("render/room_cull_enabled",false); reference_resource_mem = true; save_external_resources_mem = true; @@ -6421,7 +6126,7 @@ EditorNode::EditorNode() { //store project name in ssettings String project_name; //figure it out from path - project_name = GlobalConfig::get_singleton()->get_resource_path().replace("\\", "/"); + project_name = ProjectSettings::get_singleton()->get_resource_path().replace("\\", "/"); print_line("path: " + project_name); if (project_name.length() && project_name[project_name.length() - 1] == '/') project_name = project_name.substr(0, project_name.length() - 1); @@ -6429,7 +6134,7 @@ EditorNode::EditorNode() { project_name = project_name.replace("/", "::"); if (project_name != "") { - EditorSettings::get_singleton()->set("projects/" + project_name, GlobalConfig::get_singleton()->get_resource_path()); + EditorSettings::get_singleton()->set("projects/" + project_name, ProjectSettings::get_singleton()->get_resource_path()); EditorSettings::get_singleton()->raise_order("projects/" + project_name); EditorSettings::get_singleton()->save(); } @@ -6506,12 +6211,14 @@ EditorNode::EditorNode() { editor_data.set_edited_scene(0); _update_scene_tabs(); + import_dock->initialize_import_options(); + { _initializing_addons = true; Vector<String> addons; - if (GlobalConfig::get_singleton()->has("editor_plugins/enabled")) { - addons = GlobalConfig::get_singleton()->get("editor_plugins/enabled"); + if (ProjectSettings::get_singleton()->has("editor_plugins/enabled")) { + addons = ProjectSettings::get_singleton()->get("editor_plugins/enabled"); } for (int i = 0; i < addons.size(); i++) { diff --git a/editor/editor_node.h b/editor/editor_node.h index 991cf1df71..6553d3eee2 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -33,6 +33,7 @@ #include "editor/call_dialog.h" #include "editor/connections_dialog.h" #include "editor/create_dialog.h" +#include "editor/editor_about.h" #include "editor/editor_data.h" #include "editor/editor_path.h" #include "editor/editor_run.h" @@ -64,7 +65,7 @@ #include "editor/editor_log.h" #include "editor/editor_run_script.h" #include "editor/project_export.h" -#include "editor/project_settings.h" +#include "editor/project_settings_editor.h" #include "editor/resources_dock.h" #include "editor/run_settings_dialog.h" #include "editor/scene_tree_dock.h" @@ -247,10 +248,7 @@ private: Control *vp_base; PaneDrag *pd; //PaneDrag *pd_anim; - Panel *menu_panel; - //HSplitContainer *editor_hsplit; - //VSplitContainer *editor_vsplit; CenterContainer *play_cc; HBoxContainer *menu_hb; Control *viewport; @@ -300,10 +298,9 @@ private: ConfirmationDialog *confirmation; ConfirmationDialog *save_confirmation; ConfirmationDialog *import_confirmation; - ConfirmationDialog *open_recent_confirmation; ConfirmationDialog *pick_main_scene; AcceptDialog *accept; - AcceptDialog *about; + EditorAbout *about; AcceptDialog *warning; int overridden_default_layout; @@ -314,7 +311,7 @@ private: //OptimizedPresetsDialog *optimized_presets; EditorSettingsDialog *settings_config_dialog; RunSettingsDialog *run_settings_dialog; - ProjectSettings *project_settings; + ProjectSettingsEditor *project_settings; EditorFileDialog *file; ExportTemplateManager *export_template_manager; FileDialog *file_templates; @@ -326,8 +323,6 @@ private: String current_path; MenuButton *update_menu; - //TabContainer *prop_pallete; - //TabContainer *top_pallete; String defer_load_scene; String defer_export; String defer_export_platform; @@ -363,7 +358,7 @@ private: TabContainer *dock_slot[DOCK_SLOT_MAX]; Rect2 dock_select_rect[DOCK_SLOT_MAX]; int dock_select_rect_over; - PopupPanel *dock_select_popoup; + PopupPanel *dock_select_popup; Control *dock_select; ToolButton *dock_tab_move_left; ToolButton *dock_tab_move_right; @@ -431,9 +426,6 @@ private: List<String> previous_scenes; bool opening_prev; - Tree *_tpl_tree; - TextEdit *_tpl_text; - void _dialog_action(String p_file); void _edit_current(); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 606fd8ee5e..c65065db43 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -171,6 +171,46 @@ void EditorPlugin::set_input_event_forwarding_always_enabled() { always_input_forwarding_list->add_plugin(this); } +Node *EditorPlugin::get_edited_scene_root() { + return EditorNode::get_singleton()->get_edited_scene(); +} + +Array EditorPlugin::get_open_scenes() const { + + Array ret; + Vector<EditorData::EditedScene> scenes = EditorNode::get_singleton()->get_editor_data().get_edited_scenes(); + + int scns_amount = scenes.size(); + for (int idx_scn = 0; idx_scn < scns_amount; idx_scn++) { + if (scenes[idx_scn].root == NULL) + continue; + ret.push_back(scenes[idx_scn].root->get_filename()); + } + return ret; +} + +ScriptEditor *EditorPlugin::get_script_editor() { + return ScriptEditor::get_singleton(); +} + +void EditorPlugin::notify_scene_changed(const Node *scn_root) { + if (scn_root == NULL) return; + emit_signal("scene_changed", scn_root); +} + +void EditorPlugin::notify_main_screen_changed(const String &screen_name) { + + if (screen_name == last_main_screen_name) + return; + + emit_signal("main_screen_changed", screen_name); + last_main_screen_name = screen_name; +} + +void EditorPlugin::notify_scene_closed(const String &scene_filepath) { + emit_signal("scene_closed", scene_filepath); +} + Ref<SpatialEditorGizmo> EditorPlugin::create_spatial_gizmo(Spatial *p_spatial) { //?? if (get_script_instance() && get_script_instance()->has_method("create_spatial_gizmo")) { @@ -392,13 +432,17 @@ void EditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("get_undo_redo:UndoRedo"), &EditorPlugin::_get_undo_redo); ClassDB::bind_method(D_METHOD("get_selection:EditorSelection"), &EditorPlugin::get_selection); ClassDB::bind_method(D_METHOD("get_editor_settings:EditorSettings"), &EditorPlugin::get_editor_settings); + ClassDB::bind_method(D_METHOD("get_script_editor:ScriptEditor"), &EditorPlugin::get_script_editor); ClassDB::bind_method(D_METHOD("queue_save_layout"), &EditorPlugin::queue_save_layout); - ClassDB::bind_method(D_METHOD("edit_resource"), &EditorPlugin::edit_resource); + ClassDB::bind_method(D_METHOD("edit_resource", "resource:Resource"), &EditorPlugin::edit_resource); ClassDB::bind_method(D_METHOD("open_scene_from_path", "scene_filepath"), &EditorPlugin::open_scene_from_path); ClassDB::bind_method(D_METHOD("reload_scene_from_path", "scene_filepath"), &EditorPlugin::reload_scene_from_path); - ClassDB::bind_method(D_METHOD("add_import_plugin"), &EditorPlugin::add_import_plugin); - ClassDB::bind_method(D_METHOD("remove_import_plugin"), &EditorPlugin::remove_import_plugin); + ClassDB::bind_method(D_METHOD("add_import_plugin", "importer:EditorImportPlugin"), &EditorPlugin::add_import_plugin); + ClassDB::bind_method(D_METHOD("remove_import_plugin", "importer:EditorImportPlugin"), &EditorPlugin::remove_import_plugin); ClassDB::bind_method(D_METHOD("set_input_event_forwarding_always_enabled"), &EditorPlugin::set_input_event_forwarding_always_enabled); + ClassDB::bind_method(D_METHOD("get_open_scenes"), &EditorPlugin::get_open_scenes); + ClassDB::bind_method(D_METHOD("get_edited_scene_root:Node"), &EditorPlugin::get_edited_scene_root); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_canvas_gui_input", PropertyInfo(Variant::TRANSFORM2D, "canvas_xform"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_draw_over_canvas", PropertyInfo(Variant::TRANSFORM2D, "canvas_xform"), PropertyInfo(Variant::OBJECT, "canvas:Control"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_spatial_gui_input", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); @@ -420,6 +464,10 @@ 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"))); + ADD_SIGNAL(MethodInfo("scene_changed", PropertyInfo(Variant::OBJECT, "scene_root:Node"))); + ADD_SIGNAL(MethodInfo("scene_closed", PropertyInfo(Variant::STRING, "filepath:String"))); + ADD_SIGNAL(MethodInfo("main_screen_changed", PropertyInfo(Variant::STRING, "screen_name:String"))); + BIND_CONSTANT(CONTAINER_TOOLBAR); BIND_CONSTANT(CONTAINER_SPATIAL_EDITOR_MENU); BIND_CONSTANT(CONTAINER_SPATIAL_EDITOR_SIDE); @@ -442,6 +490,7 @@ void EditorPlugin::_bind_methods() { EditorPlugin::EditorPlugin() { undo_redo = NULL; input_event_forwarding_always_enabled = false; + last_main_screen_name = ""; } EditorPlugin::~EditorPlugin() { diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 3653851d5a..a0f64fb1ea 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -52,6 +52,8 @@ class EditorImportPlugin; class EditorExportPlugin; class EditorResourcePreview; class EditorFileSystem; +class EditorToolAddons; +class ScriptEditor; class EditorPlugin : public Node { @@ -63,6 +65,8 @@ class EditorPlugin : public Node { bool input_event_forwarding_always_enabled; + String last_main_screen_name; + protected: static void _bind_methods(); UndoRedo &get_undo_redo() { return *undo_redo; } @@ -113,6 +117,14 @@ public: void set_input_event_forwarding_always_enabled(); bool is_input_event_forwarding_always_enabled() { return input_event_forwarding_always_enabled; } + Node *get_edited_scene_root(); + Array get_open_scenes() const; + ScriptEditor *get_script_editor(); + + void notify_main_screen_changed(const String &screen_name); + void notify_scene_changed(const Node *scn_root); + void notify_scene_closed(const String &scene_filepath); + virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial); virtual bool forward_canvas_gui_input(const Transform2D &p_canvas_xform, const Ref<InputEvent> &p_event); virtual void forward_draw_over_canvas(const Transform2D &p_canvas_xform, Control *p_canvas); diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index c6b9d4bb41..6ab1468b1d 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -30,7 +30,7 @@ #include "editor_plugin_settings.h" #include "editor_node.h" -#include "global_config.h" +#include "project_settings.h" #include "io/config_file.h" #include "os/file_access.h" #include "os/main_loop.h" @@ -82,7 +82,7 @@ void EditorPluginSettings::update_plugins() { plugins.sort(); - Vector<String> active_plugins = GlobalConfig::get_singleton()->get("editor_plugins/enabled"); + Vector<String> active_plugins = ProjectSettings::get_singleton()->get("editor_plugins/enabled"); for (int i = 0; i < plugins.size(); i++) { diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 5d68de3bb6..3a6b34b7b4 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -31,7 +31,7 @@ #include "editor_scale.h" #include "editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "message_queue.h" @@ -206,7 +206,7 @@ void EditorResourcePreview::_thread() { } else { String temp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp"); - String cache_base = GlobalConfig::get_singleton()->globalize_path(item.path).md5_text(); + String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); //does not have it, try to load a cached thumbnail diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp index 8d01484b34..aa97dd237b 100644 --- a/editor/editor_run.cpp +++ b/editor/editor_run.cpp @@ -30,7 +30,7 @@ #include "editor_run.h" #include "editor_settings.h" -#include "global_config.h" +#include "project_settings.h" EditorRun::Status EditorRun::get_status() const { @@ -40,7 +40,7 @@ Error EditorRun::run(const String &p_scene, const String p_custom_args, const Li List<String> args; - String resource_path = GlobalConfig::get_singleton()->get_resource_path(); + String resource_path = ProjectSettings::get_singleton()->get_resource_path(); String remote_host = EditorSettings::get_singleton()->get("network/debug/remote_host"); int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); @@ -79,12 +79,12 @@ Error EditorRun::run(const String &p_scene, const String p_custom_args, const Li Size2 desired_size; - desired_size.x = GlobalConfig::get_singleton()->get("display/window/size/width"); - desired_size.y = GlobalConfig::get_singleton()->get("display/window/size/height"); + desired_size.x = ProjectSettings::get_singleton()->get("display/window/size/width"); + desired_size.y = ProjectSettings::get_singleton()->get("display/window/size/height"); Size2 test_size; - test_size.x = GlobalConfig::get_singleton()->get("display/window/size/test_width"); - test_size.y = GlobalConfig::get_singleton()->get("display/window/size/test_height"); + test_size.x = ProjectSettings::get_singleton()->get("display/window/size/test_width"); + test_size.y = ProjectSettings::get_singleton()->get("display/window/size/test_height"); if (test_size.x > 0 && test_size.y > 0) { desired_size = test_size; diff --git a/editor/editor_run_script.cpp b/editor/editor_run_script.cpp index 8bd1b8f4fd..0e980b040e 100644 --- a/editor/editor_run_script.cpp +++ b/editor/editor_run_script.cpp @@ -81,8 +81,8 @@ void EditorScript::set_editor(EditorNode *p_editor) { void EditorScript::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_root_node", "node"), &EditorScript::add_root_node); - ClassDB::bind_method(D_METHOD("get_scene"), &EditorScript::get_scene); + ClassDB::bind_method(D_METHOD("add_root_node", "node:Node"), &EditorScript::add_root_node); + ClassDB::bind_method(D_METHOD("get_scene:Node"), &EditorScript::get_scene); BIND_VMETHOD(MethodInfo("_run")); } diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 4ab1a435f8..755ac75180 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -30,7 +30,6 @@ #include "editor_settings.h" #include "editor_node.h" -#include "global_config.h" #include "io/compression.h" #include "io/config_file.h" #include "io/file_access_memory.h" @@ -41,6 +40,7 @@ #include "os/file_access.h" #include "os/keyboard.h" #include "os/os.h" +#include "project_settings.h" #include "scene/main/node.h" #include "scene/main/scene_tree.h" #include "scene/main/viewport.h" @@ -329,7 +329,7 @@ void EditorSettings::create() { dir->change_dir("config"); - String pcp = GlobalConfig::get_singleton()->get_resource_path(); + String pcp = ProjectSettings::get_singleton()->get_resource_path(); if (pcp.ends_with("/")) pcp = config_path.substr(0, pcp.size() - 1); pcp = pcp.get_file() + "-" + pcp.md5_text(); @@ -638,6 +638,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set("editors/3d/warped_mouse_panning", true); set("editors/3d/freelook_base_speed", 1); + + set("editors/3d/freelook_activation_modifier", 0); + hints["editors/3d/freelook_activation_modifier"] = PropertyInfo(Variant::INT, "editors/3d/freelook_activation_modifier", PROPERTY_HINT_ENUM, "None,Shift,Alt,Meta,Ctrl"); + set("editors/3d/freelook_modifier_speed_factor", 5.0); set("editors/2d/bone_width", 5); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index ce9b004ce1..6b985c7b4b 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -69,6 +69,15 @@ static Ref<StyleBoxFlat> make_flat_stylebox(Color color, float p_margin_left = - return style; } +static Ref<StyleBoxLine> make_line_stylebox(Color color, int thickness = 1, float grow = 1, bool vertical = false) { + Ref<StyleBoxLine> style(memnew(StyleBoxLine)); + style->set_color(color); + style->set_grow(grow); + style->set_thickness(thickness); + style->set_vertical(vertical); + return style; +} + static Ref<StyleBoxFlat> change_border_color(Ref<StyleBoxFlat> p_style, Color p_color) { Ref<StyleBoxFlat> style = p_style->duplicate(); style->set_light_color(p_color); @@ -143,6 +152,9 @@ Ref<Theme> create_editor_theme() { Color title_color_hl_text_color = dark_bg ? Color(1, 1, 1, 0.9) : Color(0, 0, 0, 0.9); Ref<Texture> title_hl_close_icon = theme->get_icon((dark_bg ? "GuiCloseLight" : "GuiCloseDark"), "EditorIcons"); + bool dark_base = ((base_color.r + base_color.g + base_color.b) / 3.0) < 0.5; + Color separator_color = dark_base ? Color(1, 1, 1, 0.1) : Color(0, 0, 0, 0.1); + theme->set_color("highlight_color", "Editor", highlight_color); theme->set_color("base_color", "Editor", base_color); theme->set_color("dark_color_1", "Editor", dark_color_1); @@ -244,7 +256,7 @@ Ref<Theme> create_editor_theme() { theme->set_color("icon_color_pressed", "Button", Color(highlight_color.r * 1.15, highlight_color.g * 1.15, highlight_color.b * 1.15, highlight_color.a)); // OptionButton - Ref<StyleBoxFlat> style_option_button = make_flat_stylebox(dark_color_1, 4, 4, 4, 4); + Ref<StyleBoxFlat> style_option_button = make_flat_stylebox(dark_color_1, 4, 4, 8, 4); style_option_button->set_border_size(border_width); style_option_button->set_light_color(light_color_1); style_option_button->set_dark_color(light_color_1); @@ -259,6 +271,8 @@ Ref<Theme> create_editor_theme() { theme->set_color("font_color_pressed", "OptionButton", highlight_color); theme->set_color("icon_color_hover", "OptionButton", HIGHLIGHT_COLOR_LIGHT); theme->set_icon("arrow", "OptionButton", theme->get_icon("GuiOptionArrow", "EditorIcons")); + theme->set_constant("arrow_margin", "OptionButton", 4); + theme->set_constant("modulate_arrow", "OptionButton", true); // CheckButton theme->set_icon("on", "CheckButton", theme->get_icon("GuiToggleOn", "EditorIcons")); @@ -271,7 +285,7 @@ Ref<Theme> create_editor_theme() { style_popup_menu->set_dark_color(light_color_1); style_popup_menu->set_border_blend(false); theme->set_stylebox("panel", "PopupMenu", style_popup_menu); - theme->set_stylebox("separator", "PopupMenu", make_empty_stylebox()); + theme->set_stylebox("separator", "PopupMenu", make_line_stylebox(separator_color, border_width, 8 - border_width)); // Tree & ItemList background Ref<StyleBoxFlat> style_tree_bg = make_flat_stylebox(dark_color_1, 2, 4, 2, 4); @@ -362,8 +376,8 @@ Ref<Theme> create_editor_theme() { theme->set_icon("close", "Tabs", title_hl_close_icon); // Separatos (no separatos) - theme->set_stylebox("separator", "HSeparator", make_empty_stylebox()); - theme->set_stylebox("separator", "VSeparator", make_empty_stylebox()); + theme->set_stylebox("separator", "HSeparator", make_line_stylebox(separator_color, border_width)); + theme->set_stylebox("separator", "VSeparator", make_line_stylebox(separator_color, border_width, 0, true)); // Debugger Ref<StyleBoxFlat> style_panel_debugger = make_flat_stylebox(dark_color_2, 0, 4, 0, 0); @@ -420,7 +434,8 @@ Ref<Theme> create_editor_theme() { theme->set_icon("close", "WindowDialog", title_hl_close_icon); theme->set_icon("close_highlight", "WindowDialog", title_hl_close_icon); theme->set_constant("close_h_ofs", "WindowDialog", 22 * EDSCALE); - theme->set_constant("close_v_ofs", "WindowDialog", 18 * EDSCALE); + theme->set_constant("close_v_ofs", "WindowDialog", 20 * EDSCALE); + theme->set_constant("title_height", "WindowDialog", 24 * EDSCALE); // HScrollBar Ref<Texture> empty_icon = memnew(ImageTexture); diff --git a/editor/file_type_cache.cpp b/editor/file_type_cache.cpp index de6ee171ae..100ebe21cd 100644 --- a/editor/file_type_cache.cpp +++ b/editor/file_type_cache.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "file_type_cache.h" -#include "global_config.h" +#include "project_settings.h" #include "os/file_access.h" FileTypeCache *FileTypeCache::singleton = NULL; @@ -55,7 +55,7 @@ void FileTypeCache::set_file_type(const String &p_path, const String &p_type) { void FileTypeCache::load() { GLOBAL_LOCK_FUNCTION - String project = GlobalConfig::get_singleton()->get_resource_path(); + String project = ProjectSettings::get_singleton()->get_resource_path(); FileAccess *f = FileAccess::open(project + "/file_type_cache.cch", FileAccess::READ); if (!f) { @@ -80,7 +80,7 @@ void FileTypeCache::load() { void FileTypeCache::save() { GLOBAL_LOCK_FUNCTION - String project = GlobalConfig::get_singleton()->get_resource_path(); + String project = ProjectSettings::get_singleton()->get_resource_path(); FileAccess *f = FileAccess::open(project + "/file_type_cache.cch", FileAccess::WRITE); if (!f) { diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index fe66cd7009..eacb1d2cd9 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -31,7 +31,7 @@ #include "editor_node.h" #include "editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" #include "os/dir_access.h" #include "os/file_access.h" @@ -153,7 +153,7 @@ void FileSystemDock::_notification(int p_what) { files->connect("item_activated", this, "_select_file"); button_hist_next->connect("pressed", this, "_fw_history"); button_hist_prev->connect("pressed", this, "_bw_history"); - search_icon->set_texture(get_icon("Search", "EditorIcons")); + search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); button_hist_next->set_icon(get_icon("Forward", "EditorIcons")); button_hist_prev->set_icon(get_icon("Back", "EditorIcons")); @@ -879,7 +879,7 @@ void FileSystemDock::_file_option(int p_option) { String path = files->get_item_metadata(idx); if (p_option == FILE_SHOW_IN_EXPLORER) { - String dir = GlobalConfig::get_singleton()->globalize_path(path); + String dir = ProjectSettings::get_singleton()->globalize_path(path); dir = dir.substr(0, dir.find_last("/")); OS::get_singleton()->shell_open(String("file://") + dir); return; @@ -1067,7 +1067,7 @@ void FileSystemDock::_folder_option(int p_option) { break; case FOLDER_SHOW_IN_EXPLORER: String path = item->get_metadata(tree->get_selected_column()); - String dir = GlobalConfig::get_singleton()->globalize_path(path); + String dir = ProjectSettings::get_singleton()->globalize_path(path); OS::get_singleton()->shell_open(String("file://") + dir); return; } @@ -1749,10 +1749,6 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { path_hb->add_child(search_box); search_box->connect("text_changed", this, "_search_changed"); - search_icon = memnew(TextureRect); - search_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); - path_hb->add_child(search_icon); - button_display_mode = memnew(ToolButton); path_hb->add_child(button_display_mode); button_display_mode->set_toggle_mode(true); diff --git a/editor/icons/2x/icon_variant.png b/editor/icons/2x/icon_variant.png Binary files differnew file mode 100644 index 0000000000..bb8075a069 --- /dev/null +++ b/editor/icons/2x/icon_variant.png diff --git a/editor/icons/icon_variant.png b/editor/icons/icon_variant.png Binary files differindex 1ae2812ff7..af7590345e 100644 --- a/editor/icons/icon_variant.png +++ b/editor/icons/icon_variant.png diff --git a/editor/icons/source/icon_variant.svg b/editor/icons/source/icon_variant.svg new file mode 100644 index 0000000000..d966190ab0 --- /dev/null +++ b/editor/icons/source/icon_variant.svg @@ -0,0 +1,146 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + viewBox="0 0 16 16" + id="svg2" + version="1.1" + inkscape:version="0.92+devel unknown" + inkscape:export-filename="/home/djrm/Projects/godot/tools/editor/icons/icon_add_track.png" + inkscape:export-xdpi="45" + inkscape:export-ydpi="45" + sodipodi:docname="icon_variant.svg"> + <defs + id="defs4" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="22.627418" + inkscape:cx="12.635414" + inkscape:cy="11.860443" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="true" + units="px" + inkscape:snap-bbox="true" + inkscape:bbox-paths="true" + inkscape:bbox-nodes="true" + inkscape:snap-bbox-edge-midpoints="true" + inkscape:snap-bbox-midpoints="false" + inkscape:snap-object-midpoints="true" + inkscape:snap-center="true" + inkscape:window-width="1920" + inkscape:window-height="1016" + inkscape:window-x="0" + inkscape:window-y="27" + inkscape:window-maximized="1" + inkscape:snap-midpoints="true" + inkscape:snap-smooth-nodes="true" + inkscape:object-nodes="true" + inkscape:document-rotation="0"> + <inkscape:grid + type="xygrid" + id="grid3336" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-1036.3622)"> + <g + transform="translate(0,-3)" + id="layer1-5" + inkscape:label="Layer 1" + style="fill:#e0e0e0;fill-opacity:1"> + <rect + style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4320" + width="2" + height="5.9999666" + x="3" + y="1044.3622" /> + <rect + style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4324" + width="2" + height="5.9999843" + x="6" + y="1044.3622" /> + <rect + y="1044.3622" + x="3" + height="2.0000174" + width="1" + id="rect4326" + style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <path + style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 3,1044.3622 a 3,3 0 0 0 -3,3 h 2 a 1.0000174,1.0000174 0 0 1 1,-1 z" + id="path4328" + inkscape:connector-curvature="0" /> + <path + id="path4330" + d="m 14,1050.3622 a 3,3 0 0 1 -3,-3 h 2 a 1.0000174,1.0000174 0 0 0 1,1 z" + style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + inkscape:connector-curvature="0" /> + <rect + transform="scale(1,-1)" + y="-1052.3622" + x="14" + height="7.9999843" + width="2" + id="rect4334" + style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <rect + transform="scale(1,-1)" + y="-1047.3622" + x="11" + height="2.9999826" + width="2" + id="rect4338" + style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <path + inkscape:connector-curvature="0" + id="path4340" + d="m 3,1050.3622 a 3,3 0 0 1 -3,-3 h 2 a 1.0000174,1.0000174 0 0 0 1,1 z" + style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <path + inkscape:connector-curvature="0" + id="path4342" + d="m 8,1044.3622 a 3,3 0 0 1 3,3 H 9 a 1.0000174,1.0000174 0 0 0 -1,-1 z" + style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <rect + y="1047.3622" + x="9" + height="3.0000174" + width="2" + id="rect4344" + style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + </g> +</svg> diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 9bb598ec92..25548f7899 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -395,6 +395,10 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in if (!material_map.has(current_material_library)) { Map<String, Ref<SpatialMaterial> > lib; Error err = _parse_material_library(current_material_library, lib, r_missing_deps); + if (err == ERR_CANT_OPEN) { + String dir = p_path.get_base_dir(); + err = _parse_material_library(dir.plus_file(current_material_library), lib, r_missing_deps); + } if (err == OK) { material_map[current_material_library] = lib; } diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index dbf7a1bea5..8f7ca7611a 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -104,14 +104,27 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const } } + if (p_option == "materials/keep_files" && int(p_options["materials/storage"]) == 0) { + return false; + } + return true; } int ResourceImporterScene::get_preset_count() const { - return 0; + return 6; } String ResourceImporterScene::get_preset_name(int p_idx) const { + switch (p_idx) { + case PRESET_SINGLE_SCENE: return TTR("Import as Single Scene"); + case PRESET_SEPARATE_MATERIALS: return TTR("Import with Separate Materials"); + case PRESET_SEPARATE_MESHES: return TTR("Import with Separate Objects"); + case PRESET_SEPARATE_MESHES_AND_MATERIALS: return TTR("Import with Separate Objects+Materials"); + case PRESET_MULTIPLE_SCENES: return TTR("Import as Multiple Scenes"); + case PRESET_MULTIPLE_SCENES_AND_MATERIALS: return TTR("Import as Multiple Scenes+Materials"); + } + return ""; } @@ -969,7 +982,7 @@ static String _make_extname(const String &p_str) { return ext_name; } -void ResourceImporterScene::_make_external_resources(Node *p_node, const String &p_base_path, bool p_make_materials, bool p_make_meshes, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes) { +void ResourceImporterScene::_make_external_resources(Node *p_node, const String &p_base_path, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes) { List<PropertyInfo> pi; @@ -984,8 +997,8 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String if (!p_materials.has(mat)) { - String ext_name = p_base_path + "." + _make_extname(mat->get_name()) + ".material"; - if (FileAccess::exists(ext_name)) { + String ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".material"); + if (p_keep_materials && FileAccess::exists(ext_name)) { //if exists, use it Ref<Material> existing = ResourceLoader::load(ext_name); p_materials[mat] = existing; @@ -1012,17 +1025,12 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String if (!p_meshes.has(mesh)) { - String ext_name = p_base_path + "." + _make_extname(mesh->get_name()) + ".mesh"; - if (FileAccess::exists(ext_name)) { - //if exists, use it - Ref<ArrayMesh> existing = ResourceLoader::load(ext_name); - p_meshes[mesh] = existing; - } else { + //meshes are always overwritten, keeping them is not practical + String ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".mesh"); - ResourceSaver::save(ext_name, mesh, ResourceSaver::FLAG_CHANGE_PATH); - p_meshes[mesh] = mesh; - mesh_just_added = true; - } + ResourceSaver::save(ext_name, mesh, ResourceSaver::FLAG_CHANGE_PATH); + p_meshes[mesh] = mesh; + mesh_just_added = true; } } @@ -1067,7 +1075,7 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String for (int i = 0; i < p_node->get_child_count(); i++) { - _make_external_resources(p_node->get_child(i), p_base_path, p_make_materials, p_make_meshes, p_materials, p_meshes); + _make_external_resources(p_node->get_child(i), p_base_path, p_make_materials, p_keep_materials, p_make_meshes, p_materials, p_meshes); } } @@ -1087,12 +1095,19 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in script_ext_hint += "*." + E->get(); } + bool materials_out = p_preset == PRESET_SEPARATE_MATERIALS || p_preset == PRESET_SEPARATE_MESHES_AND_MATERIALS || p_preset == PRESET_MULTIPLE_SCENES_AND_MATERIALS; + bool meshes_out = p_preset == PRESET_SEPARATE_MESHES || p_preset == PRESET_SEPARATE_MESHES_AND_MATERIALS; + bool scenes_out = p_preset == PRESET_MULTIPLE_SCENES || p_preset == PRESET_MULTIPLE_SCENES_AND_MATERIALS; + r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/custom_script", PROPERTY_HINT_FILE, script_ext_hint), "")); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/location", PROPERTY_HINT_ENUM, "Node,Mesh"), 0)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/storage", PROPERTY_HINT_ENUM, "Bult-In,Files"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "nodes/storage", PROPERTY_HINT_ENUM, "Single Scene,Instanced Sub-Scenes"), scenes_out ? 1 : 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/location", PROPERTY_HINT_ENUM, "Node,Mesh"), meshes_out ? 1 : 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/storage", PROPERTY_HINT_ENUM, "Bult-In,Files", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), materials_out ? 1 : 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "materials/keep_files"), materials_out ? true : false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "geometry/compress"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "geometry/ensure_tangents"), true)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "geometry/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "geometry/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), meshes_out ? true : false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15)); r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/filter_script", PROPERTY_HINT_MULTILINE_TEXT), "")); @@ -1110,6 +1125,18 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in } } +void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner) { + + if (p_node != p_new_owner && p_node->get_owner() == p_scene) { + p_node->set_owner(p_new_owner); + } + + for (int i = 0; i < p_node->get_child_count(); i++) { + Node *n = p_node->get_child(i); + _replace_owner(n, p_scene, p_new_owner); + } +} + Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { String src_path = p_source_file; @@ -1224,11 +1251,30 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p bool external_materials = p_options["materials/storage"]; bool external_meshes = p_options["geometry/storage"]; + bool external_scenes = int(p_options["nodes/storage"]) == 1; + + String base_path = p_source_file.get_base_dir(); + + if (external_materials || external_meshes || external_scenes) { + + if (bool(p_options["external_files/store_in_subdir"])) { + String subdir_name = p_source_file.get_file().get_basename(); + DirAccess *da = DirAccess::open(base_path); + print_line("at path " + da->get_current_dir() + " making " + subdir_name); + Error err = da->make_dir(subdir_name); + memdelete(da); + ERR_FAIL_COND_V(err != OK && err != ERR_ALREADY_EXISTS, err); + base_path = base_path.plus_file(subdir_name); + } + } if (external_materials || external_meshes) { Map<Ref<Material>, Ref<Material> > mat_map; Map<Ref<ArrayMesh>, Ref<ArrayMesh> > mesh_map; - _make_external_resources(scene, p_source_file.get_basename(), external_materials, external_meshes, mat_map, mesh_map); + + bool keep_materials = bool(p_options["materials/keep_files"]); + + _make_external_resources(scene, base_path, external_materials, keep_materials, external_meshes, mat_map, mesh_map); } progress.step(TTR("Running Custom Script.."), 2); @@ -1263,10 +1309,33 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p progress.step(TTR("Saving.."), 104); + if (external_scenes) { + //save sub-scenes as instances! + for (int i = 0; i < scene->get_child_count(); i++) { + Node *child = scene->get_child(i); + if (child->get_owner() != scene) + continue; //not a real child probably created by scene type (ig, a scrollbar) + _replace_owner(child, scene, child); + + String cn = String(child->get_name()).strip_edges().replace(".", "_").replace(":", "_"); + if (cn == String()) { + cn = "ChildNode" + itos(i); + } + String path = base_path.plus_file(cn + ".scn"); + child->set_filename(path); + + Ref<PackedScene> packer = memnew(PackedScene); + packer->pack(child); + err = ResourceSaver::save(path, packer); //do not take over, let the changed files reload themselves + ERR_FAIL_COND_V(err != OK, err); + } + } + Ref<PackedScene> packer = memnew(PackedScene); packer->pack(scene); print_line("SAVING TO: " + p_save_path + ".scn"); err = ResourceSaver::save(p_save_path + ".scn", packer); //do not take over, let the changed files reload themselves + ERR_FAIL_COND_V(err != OK, err); memdelete(scene); diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index ede3028b29..f404582d7e 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -82,6 +82,17 @@ class ResourceImporterScene : public ResourceImporter { static ResourceImporterScene *singleton; + enum Presets { + PRESET_SINGLE_SCENE, + PRESET_SEPARATE_MATERIALS, + PRESET_SEPARATE_MESHES, + PRESET_SEPARATE_MESHES_AND_MATERIALS, + PRESET_MULTIPLE_SCENES, + PRESET_MULTIPLE_SCENES_AND_MATERIALS, + }; + + void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner); + public: static ResourceImporterScene *get_singleton() { return singleton; } @@ -101,7 +112,7 @@ public: virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const; virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; - void _make_external_resources(Node *p_node, const String &p_base_path, bool p_make_materials, bool p_make_meshes, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes); + void _make_external_resources(Node *p_node, const String &p_base_path, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes); Node *_fix_node(Node *p_node, Node *p_root, Map<Ref<ArrayMesh>, Ref<Shape> > &collision_map); diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index 7e23a422f7..98020ed9b8 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -416,26 +416,26 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String bool force_normal = normal == 1; if (compress_mode == COMPRESS_VIDEO_RAM) { - //must import in all formats + //must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc). //Android, GLES 2.x - if (GlobalConfig::get_singleton()->get("rendering/vram_compression/import_s3tc")) { + if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc")) { _save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, Image::COMPRESS_S3TC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); r_platform_variants->push_back("s3tc"); } - if (GlobalConfig::get_singleton()->get("rendering/vram_compression/import_etc")) { - _save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); - r_platform_variants->push_back("etc"); - } - - if (GlobalConfig::get_singleton()->get("rendering/vram_compression/import_etc2")) { + if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2")) { _save_stex(image, p_save_path + ".etc2.stex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); r_platform_variants->push_back("etc2"); } - if (GlobalConfig::get_singleton()->get("rendering/vram_compression/import_pvrtc")) { + if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc")) { + _save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); + r_platform_variants->push_back("etc"); + } + + if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) { _save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC4, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal); r_platform_variants->push_back("pvrtc"); diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 24647734ce..a4f744aa84 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -134,6 +134,14 @@ void ImportDock::set_edit_path(const String &p_path) { } } + preset->get_popup()->add_separator(); + preset->get_popup()->add_item(vformat(TTR("Set as Default for '%s'"), params->importer->get_visible_name()), ITEM_SET_AS_DEFAULT); + if (ProjectSettings::get_singleton()->has("importer_defaults/" + params->importer->get_importer_name())) { + preset->get_popup()->add_item(TTR("Load Default"), ITEM_LOAD_DEFAULT); + preset->get_popup()->add_separator(); + preset->get_popup()->add_item(vformat(TTR("Clear Default for '%s'"), params->importer->get_visible_name()), ITEM_CLEAR_DEFAULT); + } + params->paths.clear(); params->paths.push_back(p_path); import->set_disabled(false); @@ -256,17 +264,56 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) { void ImportDock::_preset_selected(int p_idx) { - print_line("preset selected? " + p_idx); - List<ResourceImporter::ImportOption> options; + switch (p_idx) { + case ITEM_SET_AS_DEFAULT: { + List<ResourceImporter::ImportOption> options; - params->importer->get_import_options(&options, p_idx); + params->importer->get_import_options(&options, p_idx); - for (List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) { + Dictionary d; + for (List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) { - params->values[E->get().option.name] = E->get().default_value; - } + d[E->get().option.name] = E->get().default_value; + } - params->update(); + ProjectSettings::get_singleton()->set("importer_defaults/" + params->importer->get_importer_name(), d); + ProjectSettings::get_singleton()->save(); + + } break; + case ITEM_LOAD_DEFAULT: { + + ERR_FAIL_COND(!ProjectSettings::get_singleton()->has("importer_defaults/" + params->importer->get_importer_name())); + + Dictionary d = ProjectSettings::get_singleton()->get("importer_defaults/" + params->importer->get_importer_name()); + List<Variant> v; + d.get_key_list(&v); + + for (List<Variant>::Element *E = v.front(); E; E = E->next()) { + params->values[E->get()] = d[E->get()]; + } + params->update(); + + } break; + case ITEM_CLEAR_DEFAULT: { + + ProjectSettings::get_singleton()->set("importer_defaults/" + params->importer->get_importer_name(), Variant()); + ProjectSettings::get_singleton()->save(); + + } break; + default: { + + List<ResourceImporter::ImportOption> options; + + params->importer->get_import_options(&options, p_idx); + + for (List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) { + + params->values[E->get().option.name] = E->get().default_value; + } + + params->update(); + } break; + } } void ImportDock::clear() { @@ -309,6 +356,13 @@ void ImportDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_preset_selected"), &ImportDock::_preset_selected); } +void ImportDock::initialize_import_options() const { + + ERR_FAIL_COND(!import_opts || !params); + + import_opts->edit(params); +} + ImportDock::ImportDock() { imported = memnew(LineEdit); @@ -339,7 +393,6 @@ ImportDock::ImportDock() { hb->add_spacer(); params = memnew(ImportDockParameters); - import_opts->edit(params); } ImportDock::~ImportDock() { diff --git a/editor/import_dock.h b/editor/import_dock.h index fc99fcc586..4844fc07ea 100644 --- a/editor/import_dock.h +++ b/editor/import_dock.h @@ -57,12 +57,19 @@ class ImportDock : public VBoxContainer { void _reimport(); + enum { + ITEM_SET_AS_DEFAULT = 100, + ITEM_LOAD_DEFAULT, + ITEM_CLEAR_DEFAULT, + }; + protected: static void _bind_methods(); public: void set_edit_path(const String &p_path); void set_edit_multiple_paths(const Vector<String> &p_paths); + void initialize_import_options() const; void clear(); ImportDock(); diff --git a/editor/io_plugins/editor_export_scene.cpp b/editor/io_plugins/editor_export_scene.cpp index bdf9dc6844..390217053a 100644 --- a/editor/io_plugins/editor_export_scene.cpp +++ b/editor/io_plugins/editor_export_scene.cpp @@ -30,7 +30,7 @@ #include "editor_export_scene.h" #if 0 #include "editor/editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "os/dir_access.h" @@ -63,7 +63,7 @@ Vector<uint8_t> EditorSceneExportPlugin::custom_export(String& p_path,const Ref< uint64_t sd=0; String smd5; - String gp = GlobalConfig::get_singleton()->globalize_path(p_path); + String gp = ProjectSettings::get_singleton()->globalize_path(p_path); String md5=gp.md5_text(); String tmp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/"); diff --git a/editor/io_plugins/editor_scene_import_plugin.cpp b/editor/io_plugins/editor_scene_import_plugin.cpp index fed02b0e72..5f0e928844 100644 --- a/editor/io_plugins/editor_scene_import_plugin.cpp +++ b/editor/io_plugins/editor_scene_import_plugin.cpp @@ -31,7 +31,7 @@ #if 0 #include "editor/create_dialog.h" #include "editor/editor_node.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_saver.h" #include "os/file_access.h" #include "os/os.h" @@ -672,9 +672,9 @@ void EditorSceneImportDialog::_choose_save_file(const String& p_path) { void EditorSceneImportDialog::_choose_script(const String& p_path) { - String p = GlobalConfig::get_singleton()->localize_path(p_path); + String p = ProjectSettings::get_singleton()->localize_path(p_path); if (!p.is_resource_file()) - p=GlobalConfig::get_singleton()->get_resource_path().path_to(p_path.get_base_dir())+p_path.get_file(); + p=ProjectSettings::get_singleton()->get_resource_path().path_to(p_path.get_base_dir())+p_path.get_file(); script_path->set_text(p); } @@ -727,7 +727,7 @@ void EditorSceneImportDialog::_import(bool p_and_open) { if (texture_action->get_selected()==0) dst_path=save_path->get_text();//.get_base_dir(); else - dst_path=GlobalConfig::get_singleton()->get("import/shared_textures"); + dst_path=ProjectSettings::get_singleton()->get("import/shared_textures"); uint32_t flags=0; @@ -1277,7 +1277,7 @@ EditorSceneImportDialog::EditorSceneImportDialog(EditorNode *p_editor, EditorSce set_hide_on_ok(false); GLOBAL_DEF("import/shared_textures","res://"); - GlobalConfig::get_singleton()->set_custom_property_info("import/shared_textures",PropertyInfo(Variant::STRING,"import/shared_textures",PROPERTY_HINT_DIR)); + ProjectSettings::get_singleton()->set_custom_property_info("import/shared_textures",PropertyInfo(Variant::STRING,"import/shared_textures",PROPERTY_HINT_DIR)); import_hb->add_constant_override("separation",30); @@ -2812,7 +2812,7 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c String path = texture->get_path(); String fname= path.get_file(); - String target_path = GlobalConfig::get_singleton()->localize_path(target_res_path.plus_file(fname)); + String target_path = ProjectSettings::get_singleton()->localize_path(target_res_path.plus_file(fname)); progress.step(TTR("Import Image:")+" "+fname,3+(idx)*100/imagemap.size()); idx++; diff --git a/editor/io_plugins/editor_texture_import_plugin.cpp b/editor/io_plugins/editor_texture_import_plugin.cpp index d48675fa30..842c43f4de 100644 --- a/editor/io_plugins/editor_texture_import_plugin.cpp +++ b/editor/io_plugins/editor_texture_import_plugin.cpp @@ -33,7 +33,7 @@ #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor_atlas.h" -#include "global_config.h" +#include "project_settings.h" #include "io/image_loader.h" #include "io/marshalls.h" #include "io/resource_saver.h" @@ -1653,7 +1653,7 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c uint8_t f4[4]; encode_uint32(flags,&f4[0]); MD5Init(&ctx); - String gp = GlobalConfig::get_singleton()->globalize_path(p_path); + String gp = ProjectSettings::get_singleton()->globalize_path(p_path); CharString cs = gp.utf8(); MD5Update(&ctx,(unsigned char*)cs.get_data(),cs.length()); MD5Update(&ctx,f4,4); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index c3e1f60ccc..82b03d3a19 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -31,7 +31,7 @@ #include "editor/animation_editor.h" #include "editor/editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "os/keyboard.h" @@ -372,7 +372,7 @@ void AnimationPlayerEditor::_animation_save_in_path(const Ref<Resource> &p_resou flg |= ResourceSaver::FLAG_RELATIVE_PATHS; */ - String path = GlobalConfig::get_singleton()->localize_path(p_path); + String path = ProjectSettings::get_singleton()->localize_path(p_path); Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS); if (err != OK) { diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index d67832e10b..156a74144c 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "animation_tree_editor_plugin.h" -#include "core/global_config.h" #include "core/io/resource_loader.h" +#include "core/project_settings.h" #include "os/input.h" #include "os/keyboard.h" #include "scene/gui/menu_button.h" @@ -371,6 +371,7 @@ void AnimationTreeEditor::_popup_edit_dialog() { edit_label[0]->show(); edit_scroll[0]->set_min(0); edit_scroll[0]->set_max(1); + edit_scroll[0]->set_step(0.01); edit_scroll[0]->set_value(anim_tree->mix_node_get_amount(edited_node)); edit_scroll[0]->set_begin(Point2(15, 25)); edit_scroll[0]->show(); @@ -383,6 +384,7 @@ void AnimationTreeEditor::_popup_edit_dialog() { edit_label[0]->show(); edit_scroll[0]->set_min(0); edit_scroll[0]->set_max(1); + edit_scroll[0]->set_step(0.01); edit_scroll[0]->set_value(anim_tree->blend2_node_get_amount(edited_node)); edit_scroll[0]->set_begin(Point2(15, 25)); edit_scroll[0]->show(); @@ -398,6 +400,7 @@ void AnimationTreeEditor::_popup_edit_dialog() { edit_label[0]->show(); edit_scroll[0]->set_min(-1); edit_scroll[0]->set_max(1); + edit_scroll[0]->set_step(0.01); edit_scroll[0]->set_value(anim_tree->blend3_node_get_amount(edited_node)); edit_scroll[0]->set_begin(Point2(15, 25)); edit_scroll[0]->show(); @@ -411,6 +414,7 @@ void AnimationTreeEditor::_popup_edit_dialog() { edit_label[0]->show(); edit_scroll[0]->set_min(0); edit_scroll[0]->set_max(1); + edit_scroll[0]->set_step(0.01); edit_scroll[0]->set_value(anim_tree->blend4_node_get_amount(edited_node).x); edit_scroll[0]->set_begin(Point2(15, 25)); edit_scroll[0]->show(); @@ -419,6 +423,7 @@ void AnimationTreeEditor::_popup_edit_dialog() { edit_label[1]->show(); edit_scroll[1]->set_min(0); edit_scroll[1]->set_max(1); + edit_scroll[1]->set_step(0.01); edit_scroll[1]->set_value(anim_tree->blend4_node_get_amount(edited_node).y); edit_scroll[1]->set_begin(Point2(15, 75)); edit_scroll[1]->show(); @@ -1408,7 +1413,7 @@ AnimationTreeEditor::AnimationTreeEditor() { file_dialog = memnew(EditorFileDialog); file_dialog->set_enable_multiple_selection(true); - file_dialog->set_current_dir(GlobalConfig::get_singleton()->get_resource_path()); + file_dialog->set_current_dir(ProjectSettings::get_singleton()->get_resource_path()); add_child(file_dialog); file_dialog->connect("file_selected", this, "_file_dialog_selected"); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index b059e63467..4c4cd88dfb 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -35,10 +35,10 @@ #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" #include "editor/script_editor_debugger.h" -#include "global_config.h" #include "os/input.h" #include "os/keyboard.h" #include "print_string.h" +#include "project_settings.h" #include "scene/2d/light_2d.h" #include "scene/2d/particles_2d.h" #include "scene/2d/polygon_2d.h" @@ -241,7 +241,6 @@ void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) { } else if (!Input::get_singleton()->is_mouse_button_pressed(0)) { List<Node *> &selection = editor_selection->get_selected_node_list(); - Vector2 mouse_pos = viewport->get_local_mouse_pos(); if (selection.size() && viewport->get_rect().has_point(mouse_pos)) { //just in case, make it work if over viewport @@ -258,7 +257,6 @@ void CanvasItemEditor::_tool_select(int p_index) { ToolButton *tb[TOOL_MAX] = { select_button, list_select_button, move_button, rotate_button, pivot_button, pan_button }; for (int i = 0; i < TOOL_MAX; i++) { - tb[i]->set_pressed(i == p_index); } @@ -449,44 +447,7 @@ bool CanvasItemEditor::_is_part_of_subscene(CanvasItem *p_item) { return item_owner && item_owner != scene_node && p_item != scene_node && item_owner->get_filename() != ""; } -// slow but modern computers should have no problem -CanvasItem *CanvasItemEditor::_select_canvas_item_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) { - - if (!p_node) - return NULL; - if (p_node->cast_to<Viewport>()) - return NULL; - - CanvasItem *c = p_node->cast_to<CanvasItem>(); - - for (int i = p_node->get_child_count() - 1; i >= 0; i--) { - - CanvasItem *r = NULL; - - if (c && !c->is_set_as_toplevel()) - r = _select_canvas_item_at_pos(p_pos, p_node->get_child(i), p_parent_xform * c->get_transform(), p_canvas_xform); - else { - CanvasLayer *cl = p_node->cast_to<CanvasLayer>(); - r = _select_canvas_item_at_pos(p_pos, p_node->get_child(i), transform, cl ? cl->get_transform() : p_canvas_xform); //use base transform - } - - if (r) - return r; - } - - if (c && c->is_visible_in_tree() && !c->has_meta("_edit_lock_") && !_is_part_of_subscene(c) && !c->cast_to<CanvasLayer>()) { - - Rect2 rect = c->get_item_rect(); - Point2 local_pos = (p_parent_xform * p_canvas_xform * c->get_transform()).affine_inverse().xform(p_pos); - - if (rect.has_point(local_pos)) - return c; - } - - return NULL; -} - -void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, Vector<_SelectResult> &r_items) { +void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, Vector<_SelectResult> &r_items, unsigned int limit) { if (!p_node) return; if (p_node->cast_to<Viewport>()) @@ -502,6 +463,9 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no CanvasLayer *cl = p_node->cast_to<CanvasLayer>(); _find_canvas_items_at_pos(p_pos, p_node->get_child(i), transform, cl ? cl->get_transform() : p_canvas_xform, r_items); //use base transform } + + if (limit != 0 && r_items.size() >= limit) + return; } if (c && c->is_visible_in_tree() && !c->has_meta("_edit_lock_") && !c->cast_to<CanvasLayer>()) { @@ -565,72 +529,50 @@ void CanvasItemEditor::_find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_n } } -bool CanvasItemEditor::_select(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag) { - - if (p_append) { - //additive selection - - if (!item) { - - if (p_drag) { - drag_from = transform.affine_inverse().xform(p_click_pos); - - box_selecting = true; - box_selecting_to = drag_from; - } +void CanvasItemEditor::_select_click_on_empty_area(Point2 p_click_pos, bool p_append, bool p_box_selection) { + if (!p_append) { + editor_selection->clear(); + viewport->update(); + }; - return false; //nothing to add - } + if (p_box_selection) { + // Start a box selection + drag_from = transform.affine_inverse().xform(p_click_pos); + box_selecting = true; + box_selecting_to = drag_from; + } +} +bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag) { + bool still_selected = true; + if (p_append) { if (editor_selection->is_selected(item)) { - //already in here, erase it + // Already in the selection, remove it from the selected nodes editor_selection->remove_node(item); - //_remove_canvas_item(c); - - viewport->update(); - return false; + still_selected = false; + } else { + // Add the item to the selection + _append_canvas_item(item); } - _append_canvas_item(item); - viewport->update(); - - return true; - } else { - //regular selection - - if (!item) { - //clear because nothing clicked - editor_selection->clear(); - - if (p_drag) { - drag_from = transform.affine_inverse().xform(p_click_pos); - - box_selecting = true; - box_selecting_to = drag_from; - } - - viewport->update(); - return false; - } - if (!editor_selection->is_selected(item)) { - //select a new one and clear previous selection + // Select a new one and clear previous selection editor_selection->clear(); editor_selection->add_node(item); - //reselect + // Reselect if (get_tree()->is_editor_hint()) { editor->call("edit_node", item); } } + } - if (p_drag) { - _prepare_drag(p_click_pos); - } - - viewport->update(); - - return true; + if (still_selected && p_drag) { + // Drag the node(s) if requested + _prepare_drag(p_click_pos); } + + viewport->update(); + return still_selected; } void CanvasItemEditor::_key_move(const Vector2 &p_dir, bool p_snap, KeyMoveMODE p_move_mode) { @@ -766,7 +708,7 @@ CanvasItem *CanvasItemEditor::get_single_item() { return single_item; } -CanvasItemEditor::DragType CanvasItemEditor::_find_drag_type(const Transform2D &p_xform, const Rect2 &p_local_rect, const Point2 &p_click, Vector2 &r_point) { +CanvasItemEditor::DragType CanvasItemEditor::_find_drag_type(const Point2 &p_click, Vector2 &r_point) { CanvasItem *canvas_item = get_single_item(); @@ -805,8 +747,6 @@ CanvasItemEditor::DragType CanvasItemEditor::_find_drag_type(const Transform2D & float radius = (select_handle->get_size().width / 2) * 1.5; - //try draggers - for (int i = 0; i < 4; i++) { int prev = (i + 3) % 4; @@ -831,14 +771,6 @@ CanvasItemEditor::DragType CanvasItemEditor::_find_drag_type(const Transform2D & return dragger[i * 2 + 1]; } - /* - if (rect.has_point(xform.affine_inverse().xform(p_click))) { - r_point=_find_topleftmost_point(); - return DRAG_ALL; - }*/ - - //try draggers - return DRAG_NONE; } @@ -966,7 +898,7 @@ void CanvasItemEditor::_selection_result_pressed(int p_result) { CanvasItem *item = selection_results[p_result].item; if (item) - _select(item, Point2(), additive_selection, false); + _select_click_on_item(item, Point2(), additive_selection, false); } void CanvasItemEditor::_selection_menu_hide() { @@ -1006,7 +938,8 @@ void CanvasItemEditor::_list_select(const Ref<InputEventMouseButton> &b) { selection_results.clear(); additive_selection = b->get_shift(); - if (!_select(item, click, additive_selection, false)) + + if (!_select_click_on_item(item, click, additive_selection, false)) return; } else if (!selection_results.empty()) { @@ -1048,7 +981,6 @@ void CanvasItemEditor::_list_select(const Ref<InputEventMouseButton> &b) { void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { { - EditorNode *en = editor; EditorPluginList *over_plugin_list = en->get_editor_plugins_over(); @@ -1062,11 +994,11 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } Ref<InputEventMouseButton> b = p_event; - if (b.is_valid()) { + // Button event if (b->get_button_index() == BUTTON_WHEEL_DOWN) { - + // Scroll or pan down if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { v_scroll->set_value(v_scroll->get_value() + int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor()); @@ -1092,7 +1024,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } if (b->get_button_index() == BUTTON_WHEEL_UP) { - + // Scroll or pan up if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { v_scroll->set_value(v_scroll->get_value() - int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor()); @@ -1116,7 +1048,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } if (b->get_button_index() == BUTTON_WHEEL_LEFT) { - + // Pan left if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { h_scroll->set_value(h_scroll->get_value() - int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor()); @@ -1124,7 +1056,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } if (b->get_button_index() == BUTTON_WHEEL_RIGHT) { - + // Pan right if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { h_scroll->set_value(h_scroll->get_value() + int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor()); @@ -1134,29 +1066,24 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { if (b->get_button_index() == BUTTON_RIGHT) { if (b->is_pressed() && (tool == TOOL_SELECT && b->get_alt())) { - + // Open the selection list _list_select(b); return; } if (get_item_count() > 0 && drag != DRAG_NONE) { - //cancel drag - + // Cancel a drag if (bone_ik_list.size()) { - for (List<BoneIK>::Element *E = bone_ik_list.back(); E; E = E->prev()) { - E->get().node->edit_set_state(E->get().orig_state); } bone_ik_list.clear(); } else { - List<Node *> &selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>(); if (!canvas_item || !canvas_item->is_visible_in_tree()) continue; @@ -1180,33 +1107,23 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { can_move_pivot = false; } else if (box_selecting) { + // Cancel box selection box_selecting = false; viewport->update(); - } else if (b->is_pressed()) { -#if 0 - ref_item = NULL; - Node* scene = get_scene()->get_root_node()->cast_to<EditorNode>()->get_edited_scene(); - if ( scene ) ref_item =_select_canvas_item_at_pos( Point2( b.x, b.y ), scene, transform ); -#endif - //popup->set_position(Point2(b.x,b.y)); - //popup->popup(); } return; } - /* - if (!canvas_items.size()) - return; - */ if (b->get_button_index() == BUTTON_LEFT && tool == TOOL_LIST_SELECT) { if (b->is_pressed()) + // Open the selection list _list_select(b); return; } if (b->get_button_index() == BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) { if (b->is_pressed()) { - + // Set the pivot point Point2 mouse_pos = b->get_position(); mouse_pos = transform.affine_inverse().xform(mouse_pos); mouse_pos = snap_point(mouse_pos); @@ -1216,16 +1133,18 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } if (tool == TOOL_PAN || b->get_button_index() != BUTTON_LEFT || Input::get_singleton()->is_key_pressed(KEY_SPACE)) + // Pan the view return; + // -- From now we consider that the button is BUTTON_LEFT -- + if (!b->is_pressed()) { if (drag != DRAG_NONE) { - + // Stop dragging if (undo_redo) { if (bone_ik_list.size()) { - undo_redo->create_action(TTR("Edit IK Chain")); for (List<BoneIK>::Element *E = bone_ik_list.back(); E; E = E->prev()) { @@ -1241,7 +1160,6 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { undo_redo->commit_action(); } else { - undo_redo->create_action(TTR("Edit CanvasItem")); List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -1285,11 +1203,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } if (box_selecting) { -#if 0 - if ( ! b->get_shift() ) _clear_canvas_items(); - if ( box_selection_end() ) return; -#endif - + // Stop box selection Node *scene = editor->get_edited_scene(); if (scene) { @@ -1316,6 +1230,8 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { return; } + // -- From now we consider that the button is BUTTON_LEFT and that it is pressed -- + Map<ObjectID, BoneList>::Element *Cbone = NULL; //closest { @@ -1390,19 +1306,16 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } } - CanvasItem *single_item = get_single_item(); - - if (single_item) { - //try single canvas_item edit - - CanvasItem *canvas_item = single_item; + // Single selected item + CanvasItem *canvas_item = get_single_item(); + if (canvas_item) { CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item); ERR_FAIL_COND(!se); Point2 click = b->get_position(); + // Rotation if ((b->get_control() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) { - drag = DRAG_ROTATE; drag_from = transform.affine_inverse().xform(click); se->undo_state = canvas_item->edit_get_state(); @@ -1413,72 +1326,59 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { return; } - Transform2D xform = transform * canvas_item->get_global_transform_with_canvas(); - Rect2 rect = canvas_item->get_item_rect(); - //float handle_radius = handle_len * 1.4144; //magic number, guess what it means! - if (tool == TOOL_SELECT) { - drag = _find_drag_type(xform, rect, click, drag_point_from); - + // Open a sub-scene on double-click if (b->is_doubleclick()) { - if (canvas_item->get_filename() != "" && canvas_item != editor->get_edited_scene()) { - editor->open_request(canvas_item->get_filename()); return; } } - if (drag != DRAG_NONE && (!Cbone || drag != DRAG_ALL)) { + // Drag + drag = _find_drag_type(click, drag_point_from); + if (drag != DRAG_NONE) { drag_from = transform.affine_inverse().xform(click); se->undo_state = canvas_item->edit_get_state(); if (canvas_item->cast_to<Node2D>()) se->undo_pivot = canvas_item->cast_to<Node2D>()->edit_get_pivot(); if (canvas_item->cast_to<Control>()) se->undo_pivot = canvas_item->cast_to<Control>()->get_pivot_offset(); - return; } - } else { - - drag = DRAG_NONE; } } - //multi canvas_item edit - + // Multiple selected items Point2 click = b->get_position(); if ((b->get_alt() || tool == TOOL_MOVE) && get_item_count()) { + // Drag the nodes _prepare_drag(click); viewport->update(); return; } - Node *scene = editor->get_edited_scene(); - if (!scene) - return; - - /* - if (current_window) { - //no window.... ? - click-=current_window->get_scroll(); - }*/ CanvasItem *c = NULL; - if (Cbone) { - Object *obj = ObjectDB::get_instance(Cbone->get().bone); if (obj) c = obj->cast_to<CanvasItem>(); if (c) c = c->get_parent_item(); } + + Node *scene = editor->get_edited_scene(); + if (!scene) + return; + // Find the item to select if (!c) { - c = _select_canvas_item_at_pos(click, scene, transform, Transform2D()); + Vector<_SelectResult> selection; + _find_canvas_items_at_pos(click, scene, transform, Transform2D(), selection, 1); + if (!selection.empty()) + c = selection[0].item; CanvasItem *cn = c; - while (cn) { if (cn->has_meta("_edit_group_")) { c = cn; @@ -1488,28 +1388,29 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } Node *n = c; - while ((n && n != scene && n->get_owner() != scene) || (n && !n->is_class("CanvasItem"))) { n = n->get_parent(); }; c = n->cast_to<CanvasItem>(); -#if 0 - if ( b->is_pressed() ) box_selection_start( click ); -#endif + // Select the item additive_selection = b->get_shift(); - if (!_select(c, click, additive_selection)) + if (!c) { + _select_click_on_empty_area(click, additive_selection, true); + } else if (!_select_click_on_item(c, click, additive_selection, true)) { return; + } } Ref<InputEventMouseMotion> m = p_event; if (m.is_valid()) { + // Mouse motion event if (!viewport->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) viewport->call_deferred("grab_focus"); if (box_selecting) { - + // Update box selection box_selecting_to = transform.affine_inverse().xform(m->get_position()); viewport->update(); return; @@ -1618,8 +1519,21 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { Vector2 minsize = canvas_item->edit_get_minimum_size(); if (uniform) { + // Keep the height/width ratio of the item float aspect = local_rect.size.aspect(); switch (drag) { + case DRAG_LEFT: { + drag_vector.y = -drag_vector.x / aspect; + } break; + case DRAG_RIGHT: { + drag_vector.y = drag_vector.x / aspect; + } break; + case DRAG_TOP: { + drag_vector.x = -drag_vector.y * aspect; + } break; + case DRAG_BOTTOM: { + drag_vector.x = drag_vector.y * aspect; + } break; case DRAG_BOTTOM_LEFT: case DRAG_TOP_RIGHT: { if (aspect > 1.0) { // width > height, take x as reference @@ -1636,7 +1550,17 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { drag_vector.x = drag_vector.y * aspect; } } break; - default: {} + } + } else { + switch (drag) { + case DRAG_RIGHT: + case DRAG_LEFT: { + drag_vector.y = 0; + } break; + case DRAG_TOP: + case DRAG_BOTTOM: { + drag_vector.x = 0; + } break; } } @@ -1645,44 +1569,25 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { begin += drag_vector; end += drag_vector; } break; - case DRAG_RIGHT: { - - incend(begin.x, end.x, drag_vector.x, minsize.x, symmetric); - - } break; - case DRAG_BOTTOM: { - - incend(begin.y, end.y, drag_vector.y, minsize.y, symmetric); - - } break; + case DRAG_RIGHT: + case DRAG_BOTTOM: case DRAG_BOTTOM_RIGHT: { - incend(begin.x, end.x, drag_vector.x, minsize.x, symmetric); incend(begin.y, end.y, drag_vector.y, minsize.y, symmetric); } break; - case DRAG_TOP_LEFT: { + case DRAG_TOP_LEFT: { incbeg(begin.x, end.x, drag_vector.x, minsize.x, symmetric); incbeg(begin.y, end.y, drag_vector.y, minsize.y, symmetric); } break; - case DRAG_TOP: { - incbeg(begin.y, end.y, drag_vector.y, minsize.y, symmetric); - - } break; - case DRAG_LEFT: { - - incbeg(begin.x, end.x, drag_vector.x, minsize.x, symmetric); - - } break; + case DRAG_TOP: case DRAG_TOP_RIGHT: { - incbeg(begin.y, end.y, drag_vector.y, minsize.y, symmetric); incend(begin.x, end.x, drag_vector.x, minsize.x, symmetric); - } break; + case DRAG_LEFT: case DRAG_BOTTOM_LEFT: { - incbeg(begin.x, end.x, drag_vector.x, minsize.x, symmetric); incend(begin.y, end.y, drag_vector.y, minsize.y, symmetric); } break; @@ -2007,7 +1912,7 @@ void CanvasItemEditor::_viewport_draw() { VisualServer::get_singleton()->canvas_item_add_line(ci, transform.xform(display_rotate_from), transform.xform(display_rotate_to), rotate_color); } - Size2 screen_size = Size2(GlobalConfig::get_singleton()->get("display/window/size/width"), GlobalConfig::get_singleton()->get("display/window/size/height")); + Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")); Vector2 screen_endpoints[4] = { transform.xform(Vector2(0, 0)), @@ -2323,7 +2228,7 @@ void CanvasItemEditor::_update_scrollbars() { h_scroll->set_begin(Point2(0, size.height - hmin.height)); h_scroll->set_end(Point2(size.width - vmin.width, size.height)); - Size2 screen_rect = Size2(GlobalConfig::get_singleton()->get("display/window/size/width"), GlobalConfig::get_singleton()->get("display/window/size/height")); + Size2 screen_rect = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")); Rect2 local_rect = Rect2(Point2(), viewport->get_size() - Size2(vmin.width, hmin.height)); @@ -3386,6 +3291,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { key_loc_button = memnew(Button("loc")); key_loc_button->set_toggle_mode(true); + key_loc_button->set_flat(true); key_loc_button->set_pressed(true); key_loc_button->set_focus_mode(FOCUS_NONE); key_loc_button->add_color_override("font_color", Color(1, 0.6, 0.6)); @@ -3394,6 +3300,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { animation_hb->add_child(key_loc_button); key_rot_button = memnew(Button("rot")); key_rot_button->set_toggle_mode(true); + key_rot_button->set_flat(true); key_rot_button->set_pressed(true); key_rot_button->set_focus_mode(FOCUS_NONE); key_rot_button->add_color_override("font_color", Color(1, 0.6, 0.6)); @@ -3402,12 +3309,14 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { animation_hb->add_child(key_rot_button); key_scale_button = memnew(Button("scl")); key_scale_button->set_toggle_mode(true); + key_scale_button->set_flat(true); key_scale_button->set_focus_mode(FOCUS_NONE); key_scale_button->add_color_override("font_color", Color(1, 0.6, 0.6)); key_scale_button->add_color_override("font_color_pressed", Color(0.6, 1, 0.6)); key_scale_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_SCALE)); animation_hb->add_child(key_scale_button); key_insert_button = memnew(Button); + key_insert_button->set_flat(true); key_insert_button->set_focus_mode(FOCUS_NONE); key_insert_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_KEY)); key_insert_button->set_tooltip(TTR("Insert Keys")); @@ -3693,7 +3602,7 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons } } - instanced_scene->set_filename(GlobalConfig::get_singleton()->localize_path(path)); + instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path)); editor_data->get_undo_redo().add_do_method(parent, "add_child", instanced_scene); editor_data->get_undo_redo().add_do_method(instanced_scene, "set_owner", editor->get_edited_scene()); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index f40a7cbc4a..4383be251c 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -303,11 +303,11 @@ class CanvasItemEditor : public VBoxContainer { int handle_len; bool _is_part_of_subscene(CanvasItem *p_item); - CanvasItem *_select_canvas_item_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform); - void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, Vector<_SelectResult> &r_items); + void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, Vector<_SelectResult> &r_items, unsigned int limit = 0); void _find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, List<CanvasItem *> *r_items); - bool _select(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag = true); + void _select_click_on_empty_area(Point2 p_click_pos, bool p_append, bool p_box_selection); + bool _select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag); ConfirmationDialog *snap_dialog; @@ -325,7 +325,7 @@ class CanvasItemEditor : public VBoxContainer { void _key_move(const Vector2 &p_dir, bool p_snap, KeyMoveMODE p_move_mode); void _list_select(const Ref<InputEventMouseButton> &b); - DragType _find_drag_type(const Transform2D &p_xform, const Rect2 &p_local_rect, const Point2 &p_click, Vector2 &r_point); + DragType _find_drag_type(const Point2 &p_click, Vector2 &r_point); void _prepare_drag(const Point2 &p_click_pos); void _popup_callback(int p_op); diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 7f8581535c..ce6eefd694 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -186,7 +186,7 @@ Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES &p_from) { Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path) { String temp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp"); - String cache_base = GlobalConfig::get_singleton()->globalize_path(p_path).md5_text(); + String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); //does not have it, try to load a cached thumbnail diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp index f377d3a7cc..23b19e61b9 100644 --- a/editor/plugins/mesh_editor_plugin.cpp +++ b/editor/plugins/mesh_editor_plugin.cpp @@ -29,18 +29,17 @@ /*************************************************************************/ #include "mesh_editor_plugin.h" -#if 0 -void MeshEditor::_gui_input(InputEvent p_event) { +void MeshEditor::_gui_input(Ref<InputEvent> p_event) { + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) { - if (p_event.type==InputEvent::MOUSE_MOTION && p_event->get_button_mask()&BUTTON_MASK_LEFT) { - - rot_x-=p_event->get_relative().y*0.01; - rot_y-=p_event->get_relative().x*0.01; - if (rot_x<-Math_PI/2) - rot_x=-Math_PI/2; - else if (rot_x>Math_PI/2) { - rot_x=Math_PI/2; + rot_x -= mm->get_relative().y * 0.01; + rot_y -= mm->get_relative().x * 0.01; + if (rot_x < -Math_PI / 2) + rot_x = -Math_PI / 2; + else if (rot_x > Math_PI / 2) { + rot_x = Math_PI / 2; } _update_rotation(); } @@ -48,35 +47,30 @@ void MeshEditor::_gui_input(InputEvent p_event) { void MeshEditor::_notification(int p_what) { - if (p_what==NOTIFICATION_FIXED_PROCESS) { - + if (p_what == NOTIFICATION_FIXED_PROCESS) { } - - if (p_what==NOTIFICATION_READY) { + if (p_what == NOTIFICATION_READY) { //get_scene()->connect("node_removed",this,"_node_removed"); if (first_enter) { - //it's in propertyeditor so.. could be moved around + //it's in propertyeditor so. could be moved around - light_1_switch->set_normal_texture(get_icon("MaterialPreviewLight1","EditorIcons")); - light_1_switch->set_pressed_texture(get_icon("MaterialPreviewLight1Off","EditorIcons")); - light_2_switch->set_normal_texture(get_icon("MaterialPreviewLight2","EditorIcons")); - light_2_switch->set_pressed_texture(get_icon("MaterialPreviewLight2Off","EditorIcons")); - first_enter=false; + light_1_switch->set_normal_texture(get_icon("MaterialPreviewLight1", "EditorIcons")); + light_1_switch->set_pressed_texture(get_icon("MaterialPreviewLight1Off", "EditorIcons")); + light_2_switch->set_normal_texture(get_icon("MaterialPreviewLight2", "EditorIcons")); + light_2_switch->set_pressed_texture(get_icon("MaterialPreviewLight2Off", "EditorIcons")); + first_enter = false; } - } - if (p_what==NOTIFICATION_DRAW) { - + if (p_what == NOTIFICATION_DRAW) { - Ref<Texture> checkerboard = get_icon("Checkerboard","EditorIcons"); + Ref<Texture> checkerboard = get_icon("Checkerboard", "EditorIcons"); Size2 size = get_size(); - draw_texture_rect(checkerboard,Rect2(Point2(),size),true); - + //draw_texture_rect(checkerboard, Rect2(Point2(), size), true); } } @@ -85,125 +79,115 @@ void MeshEditor::_update_rotation() { Transform t; t.basis.rotate(Vector3(0, 1, 0), -rot_y); t.basis.rotate(Vector3(1, 0, 0), -rot_x); - mesh_instance->set_transform(t); - + rotation->set_transform(t); } void MeshEditor::edit(Ref<Mesh> p_mesh) { - mesh=p_mesh; + mesh = p_mesh; mesh_instance->set_mesh(mesh); if (mesh.is_null()) { hide(); } else { - rot_x=0; - rot_y=0; + rot_x = 0; + rot_y = 0; _update_rotation(); - AABB aabb= mesh->get_aabb(); - Vector3 ofs = aabb.pos + aabb.size*0.5; - aabb.pos-=ofs; - float m = MAX(aabb.size.x,aabb.size.y)*0.5; - if (m!=0) { - m=1.0/m; - m*=0.5; + Rect3 aabb = mesh->get_aabb(); + print_line("aabb: " + aabb); + Vector3 ofs = aabb.position + aabb.size * 0.5; + float m = aabb.get_longest_axis_size(); + if (m != 0) { + m = 1.0 / m; + m *= 0.5; //print_line("scale: "+rtos(m)); Transform xform; - xform.basis.scale(Vector3(m,m,m)); - xform.origin=-xform.basis.xform(ofs); //-ofs*m; - xform.origin.z-=aabb.size.z*2; + xform.basis.scale(Vector3(m, m, m)); + xform.origin = -xform.basis.xform(ofs); //-ofs*m; + //xform.origin.z -= aabb.get_longest_axis_size() * 2; mesh_instance->set_transform(xform); } - } - } +void MeshEditor::_button_pressed(Node *p_button) { -void MeshEditor::_button_pressed(Node* p_button) { - - if (p_button==light_1_switch) { - light1->set_enabled(!light_1_switch->is_pressed()); + if (p_button == light_1_switch) { + light1->set_visible(!light_1_switch->is_pressed()); } - if (p_button==light_2_switch) { - light2->set_enabled(!light_2_switch->is_pressed()); + if (p_button == light_2_switch) { + light2->set_visible(!light_2_switch->is_pressed()); } - - } void MeshEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"),&MeshEditor::_gui_input); - ClassDB::bind_method(D_METHOD("_button_pressed"),&MeshEditor::_button_pressed); - + ClassDB::bind_method(D_METHOD("_gui_input"), &MeshEditor::_gui_input); + ClassDB::bind_method(D_METHOD("_button_pressed"), &MeshEditor::_button_pressed); } MeshEditor::MeshEditor() { - viewport = memnew( Viewport ); + viewport = memnew(Viewport); Ref<World> world; world.instance(); viewport->set_world(world); //use own world add_child(viewport); viewport->set_disable_input(true); + set_stretch(true); - camera = memnew( Camera ); - camera->set_transform(Transform(Matrix3(),Vector3(0,0,3))); - camera->set_perspective(45,0.1,10); + camera = memnew(Camera); + camera->set_transform(Transform(Basis(), Vector3(0, 0, 1.1))); + camera->set_perspective(45, 0.1, 10); viewport->add_child(camera); - light1 = memnew( DirectionalLight ); - light1->set_transform(Transform().looking_at(Vector3(-1,-1,-1),Vector3(0,1,0))); + light1 = memnew(DirectionalLight); + light1->set_transform(Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); viewport->add_child(light1); - light2 = memnew( DirectionalLight ); - light2->set_transform(Transform().looking_at(Vector3(0,1,0),Vector3(0,0,1))); - light2->set_color(Light::COLOR_DIFFUSE,Color(0.7,0.7,0.7)); - light2->set_color(Light::COLOR_SPECULAR,Color(0.7,0.7,0.7)); + light2 = memnew(DirectionalLight); + light2->set_transform(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); + light2->set_color(Color(0.7, 0.7, 0.7)); viewport->add_child(light2); - mesh_instance = memnew( MeshInstance ); - viewport->add_child(mesh_instance); - - + rotation = memnew(Spatial); + viewport->add_child(rotation); + mesh_instance = memnew(MeshInstance); + rotation->add_child(mesh_instance); - set_custom_minimum_size(Size2(1,150)*EDSCALE); + set_custom_minimum_size(Size2(1, 150) * EDSCALE); - HBoxContainer *hb = memnew( HBoxContainer ); + HBoxContainer *hb = memnew(HBoxContainer); add_child(hb); hb->set_area_as_parent_rect(2); hb->add_spacer(); - VBoxContainer *vb_light = memnew( VBoxContainer ); + VBoxContainer *vb_light = memnew(VBoxContainer); hb->add_child(vb_light); - light_1_switch = memnew( TextureButton ); + light_1_switch = memnew(TextureButton); light_1_switch->set_toggle_mode(true); vb_light->add_child(light_1_switch); - light_1_switch->connect("pressed",this,"_button_pressed",varray(light_1_switch)); + light_1_switch->connect("pressed", this, "_button_pressed", varray(light_1_switch)); - light_2_switch = memnew( TextureButton ); + light_2_switch = memnew(TextureButton); light_2_switch->set_toggle_mode(true); vb_light->add_child(light_2_switch); - light_2_switch->connect("pressed",this,"_button_pressed",varray(light_2_switch)); - - first_enter=true; - - rot_x=0; - rot_y=0; + light_2_switch->connect("pressed", this, "_button_pressed", varray(light_2_switch)); + first_enter = true; + rot_x = 0; + rot_y = 0; } - void MeshEditorPlugin::edit(Object *p_object) { - Mesh * s = p_object->cast_to<Mesh>(); + Mesh *s = p_object->cast_to<Mesh>(); if (!s) return; @@ -212,7 +196,7 @@ void MeshEditorPlugin::edit(Object *p_object) { bool MeshEditorPlugin::handles(Object *p_object) const { - return p_object->is_type("Mesh"); + return p_object->is_class("Mesh"); } void MeshEditorPlugin::make_visible(bool p_visible) { @@ -225,22 +209,15 @@ void MeshEditorPlugin::make_visible(bool p_visible) { mesh_editor->hide(); //mesh_editor->set_process(false); } - } MeshEditorPlugin::MeshEditorPlugin(EditorNode *p_node) { - editor=p_node; - mesh_editor = memnew( MeshEditor ); - add_control_to_container(CONTAINER_PROPERTY_EDITOR_BOTTOM,mesh_editor); + editor = p_node; + mesh_editor = memnew(MeshEditor); + add_control_to_container(CONTAINER_PROPERTY_EDITOR_BOTTOM, mesh_editor); mesh_editor->hide(); - - - } - -MeshEditorPlugin::~MeshEditorPlugin() -{ +MeshEditorPlugin::~MeshEditorPlugin() { } -#endif diff --git a/editor/plugins/mesh_editor_plugin.h b/editor/plugins/mesh_editor_plugin.h index 1d89448ed8..72d93c4126 100644 --- a/editor/plugins/mesh_editor_plugin.h +++ b/editor/plugins/mesh_editor_plugin.h @@ -30,8 +30,6 @@ #ifndef MESH_EDITOR_PLUGIN_H #define MESH_EDITOR_PLUGIN_H -#if 0 - #include "editor/editor_node.h" #include "editor/editor_plugin.h" #include "scene/3d/camera.h" @@ -39,51 +37,48 @@ #include "scene/3d/mesh_instance.h" #include "scene/resources/material.h" -class MeshEditor : public Control { - - GDCLASS(MeshEditor, Control); - +class MeshEditor : public ViewportContainer { + GDCLASS(MeshEditor, ViewportContainer); float rot_x; float rot_y; Viewport *viewport; MeshInstance *mesh_instance; + Spatial *rotation; DirectionalLight *light1; DirectionalLight *light2; Camera *camera; Ref<Mesh> mesh; - TextureButton *light_1_switch; TextureButton *light_2_switch; - void _button_pressed(Node* p_button); + void _button_pressed(Node *p_button); bool first_enter; void _update_rotation(); + protected: void _notification(int p_what); - void _gui_input(InputEvent p_event); + void _gui_input(Ref<InputEvent> p_event); static void _bind_methods(); -public: +public: void edit(Ref<Mesh> p_mesh); MeshEditor(); }; - class MeshEditorPlugin : public EditorPlugin { - GDCLASS( MeshEditorPlugin, EditorPlugin ); + GDCLASS(MeshEditorPlugin, EditorPlugin); MeshEditor *mesh_editor; EditorNode *editor; public: - virtual String get_name() const { return "Mesh"; } bool has_main_screen() const { return false; } virtual void edit(Object *p_node); @@ -92,8 +87,6 @@ public: MeshEditorPlugin(EditorNode *p_node); ~MeshEditorPlugin(); - }; -#endif // MESH_EDITOR_PLUGIN_H #endif diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp index 3524c34d62..c32ed1064f 100644 --- a/editor/plugins/path_editor_plugin.cpp +++ b/editor/plugins/path_editor_plugin.cpp @@ -204,7 +204,7 @@ void PathSpatialGizmo::redraw() { if (c.is_null()) return; - PoolVector<Vector3> v3a = c->tesselate(); + PoolVector<Vector3> v3a = c->tessellate(); //PoolVector<Vector3> v3a=c->get_baked_points(); int v3s = v3a.size(); @@ -289,7 +289,7 @@ bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<Inp if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb->get_control()))) { //click into curve, break it down - PoolVector<Vector3> v3a = c->tesselate(); + PoolVector<Vector3> v3a = c->tessellate(); int idx = 0; int rc = v3a.size(); int closest_seg = -1; diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index ea7a84d2f4..463b6360ad 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -30,7 +30,7 @@ #include "resource_preloader_editor_plugin.h" #include "editor/editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" void ResourcePreloaderEditor::_gui_input(Ref<InputEvent> p_event) { diff --git a/editor/plugins/sample_editor_plugin.cpp b/editor/plugins/sample_editor_plugin.cpp index a9af5823e3..0b99ab5460 100644 --- a/editor/plugins/sample_editor_plugin.cpp +++ b/editor/plugins/sample_editor_plugin.cpp @@ -31,7 +31,7 @@ #if 0 #include "editor/editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" diff --git a/editor/plugins/sample_library_editor_plugin.cpp b/editor/plugins/sample_library_editor_plugin.cpp index 9eb1af70d1..04c805165f 100644 --- a/editor/plugins/sample_library_editor_plugin.cpp +++ b/editor/plugins/sample_library_editor_plugin.cpp @@ -32,7 +32,7 @@ #include "sample_library_editor_plugin.h" #include "editor/editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" #include "sample_editor_plugin.h" #include "scene/main/viewport.h" diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index d10831eea1..fef7f07abb 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -32,13 +32,13 @@ #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor/script_editor_debugger.h" -#include "global_config.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "os/file_access.h" #include "os/input.h" #include "os/keyboard.h" #include "os/os.h" +#include "project_settings.h" #include "scene/main/viewport.h" /*** SCRIPT EDITOR ****/ @@ -405,6 +405,8 @@ void ScriptEditor::_go_to_tab(int p_idx) { script_icon->set_texture(c->cast_to<ScriptEditorBase>()->get_icon()); if (is_visible_in_tree()) c->cast_to<ScriptEditorBase>()->ensure_focus(); + + notify_script_changed(c->cast_to<ScriptEditorBase>()->get_edited_script()); } if (c->cast_to<EditorHelp>()) { @@ -510,12 +512,15 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save) { apply_scripts(); } current->clear_edit_menu(); - + notify_script_close(current->get_edited_script()); } else { EditorHelp *help = tab_container->get_child(selected)->cast_to<EditorHelp>(); _add_recent_script(help->get_class()); } + // roll back to previous tab + _history_back(); + //remove from history history.resize(history_pos + 1); @@ -777,6 +782,31 @@ void ScriptEditor::_file_dialog_action(String p_file) { file_dialog_option = -1; } +Ref<Script> ScriptEditor::_get_current_script() { + + int selected = tab_container->get_current_tab(); + if (selected < 0 || selected >= tab_container->get_child_count()) + return NULL; + + ScriptEditorBase *current = tab_container->get_child(selected)->cast_to<ScriptEditorBase>(); + if (current) { + return current->get_edited_script(); + } else { + return NULL; + } +} + +Array ScriptEditor::_get_open_scripts() const { + + Array ret; + Vector<Ref<Script> > scripts = get_open_scripts(); + int scrits_amount = scripts.size(); + for (int idx_script = 0; idx_script < scrits_amount; idx_script++) { + ret.push_back(scripts[idx_script]); + } + return ret; +} + void ScriptEditor::_menu_option(int p_option) { switch (p_option) { @@ -1127,6 +1157,14 @@ void ScriptEditor::edited_scene_changed() { _update_modified_scripts_for_external_editor(); } +void ScriptEditor::notify_script_close(const Ref<Script> &p_script) { + emit_signal("script_close", p_script); +} + +void ScriptEditor::notify_script_changed(const Ref<Script> &p_script) { + emit_signal("editor_script_changed", p_script); +} + static const Node *_find_node_with_script(const Node *p_node, const RefPtr &p_script) { if (p_node->get_script() == p_script) @@ -1281,7 +1319,8 @@ void ScriptEditor::ensure_focus_current() { int cidx = tab_container->get_current_tab(); if (cidx < 0 || cidx >= tab_container->get_tab_count()) - ; + return; + Control *c = tab_container->get_child(cidx)->cast_to<Control>(); if (!c) return; @@ -1371,6 +1410,11 @@ struct _ScriptEditorItemData { }; void ScriptEditor::_update_members_overview_visibility() { + + int selected = tab_container->get_current_tab(); + if (selected < 0 || selected >= tab_container->get_child_count()) + return; + Node *current = tab_container->get_child(tab_container->get_current_tab()); ScriptEditorBase *se = current->cast_to<ScriptEditorBase>(); if (!se) { @@ -1388,6 +1432,10 @@ void ScriptEditor::_update_members_overview_visibility() { void ScriptEditor::_update_members_overview() { members_overview->clear(); + int selected = tab_container->get_current_tab(); + if (selected < 0 || selected >= tab_container->get_child_count()) + return; + Node *current = tab_container->get_child(tab_container->get_current_tab()); ScriptEditorBase *se = current->cast_to<ScriptEditorBase>(); if (!se) { @@ -1568,8 +1616,8 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool String flags = EditorSettings::get_singleton()->get("text_editor/external/exec_flags"); Dictionary keys; - keys["project"] = GlobalConfig::get_singleton()->get_resource_path(); - keys["file"] = GlobalConfig::get_singleton()->globalize_path(p_script->get_path()); + keys["project"] = ProjectSettings::get_singleton()->get_resource_path(); + keys["file"] = ProjectSettings::get_singleton()->globalize_path(p_script->get_path()); keys["line"] = p_line >= 0 ? p_line : 0; keys["col"] = p_col; @@ -1662,6 +1710,7 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool if (p_line >= 0) se->goto_line(p_line - 1); + notify_script_changed(p_script); return true; } @@ -2038,6 +2087,8 @@ void ScriptEditor::_update_history_pos(int p_new_pos) { n->cast_to<ScriptEditorBase>()->set_edit_state(history[history_pos].state); n->cast_to<ScriptEditorBase>()->ensure_focus(); + + notify_script_changed(n->cast_to<ScriptEditorBase>()->get_edited_script()); } if (n->cast_to<EditorHelp>()) { @@ -2065,6 +2116,21 @@ void ScriptEditor::_history_back() { _update_history_pos(history_pos - 1); } } + +Vector<Ref<Script> > ScriptEditor::get_open_scripts() const { + + Vector<Ref<Script> > out_scripts = Vector<Ref<Script> >(); + + for (int i = 0; i < tab_container->get_child_count(); i++) { + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (!se) + continue; + out_scripts.push_back(se->get_edited_script()); + } + + return out_scripts; +} + void ScriptEditor::set_scene_root_script(Ref<Script> p_script) { bool open_dominant = EditorSettings::get_singleton()->get("text_editor/files/open_dominant_script_on_scene_change"); @@ -2158,6 +2224,12 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method("_history_back", &ScriptEditor::_history_back); ClassDB::bind_method("_live_auto_reload_running_scripts", &ScriptEditor::_live_auto_reload_running_scripts); ClassDB::bind_method("_unhandled_input", &ScriptEditor::_unhandled_input); + + ClassDB::bind_method(D_METHOD("get_current_script"), &ScriptEditor::_get_current_script); + ClassDB::bind_method(D_METHOD("get_open_scripts"), &ScriptEditor::_get_open_scripts); + + ADD_SIGNAL(MethodInfo("editor_script_changed", PropertyInfo(Variant::OBJECT, "script:Script"))); + ADD_SIGNAL(MethodInfo("script_close", PropertyInfo(Variant::STRING, "script:String"))); } ScriptEditor::ScriptEditor(EditorNode *p_editor) { diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 010a5604ec..d8a9415df1 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -321,6 +321,9 @@ class ScriptEditor : public PanelContainer { int file_dialog_option; void _file_dialog_action(String p_file); + Ref<Script> _get_current_script(); + Array _get_open_scripts() const; + static void _open_script_request(const String &p_path); static ScriptEditor *script_editor; @@ -354,11 +357,15 @@ public: void get_window_layout(Ref<ConfigFile> p_layout); void set_scene_root_script(Ref<Script> p_script); + Vector<Ref<Script> > get_open_scripts() const; bool script_goto_method(Ref<Script> p_script, const String &p_method); virtual void edited_scene_changed(); + void notify_script_close(const Ref<Script> &p_script); + void notify_script_changed(const Ref<Script> &p_script); + void close_builtin_scripts_from_scene(const String &p_scene); void goto_help(const String &p_desc) { _help_class_goto(p_desc); } diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 58fc32309f..ef7ed5f7f6 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -36,9 +36,9 @@ #include "editor/editor_settings.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/spatial_editor_gizmos.h" -#include "global_config.h" #include "os/keyboard.h" #include "print_string.h" +#include "project_settings.h" #include "scene/3d/camera.h" #include "scene/3d/visual_instance.h" #include "scene/resources/surface_tool.h" @@ -518,7 +518,7 @@ void SpatialEditorViewport::_compute_edit(const Point2 &p_point) { */ } -static int _get_key_modifier(const String &p_property) { +static int _get_key_modifier_setting(const String &p_property) { switch (EditorSettings::get_singleton()->get(p_property).operator int()) { @@ -531,6 +531,18 @@ static int _get_key_modifier(const String &p_property) { return 0; } +static int _get_key_modifier(Ref<InputEventWithModifiers> e) { + if (e->get_shift()) + return KEY_SHIFT; + if (e->get_alt()) + return KEY_ALT; + if (e->get_control()) + return KEY_CONTROL; + if (e->get_metakey()) + return KEY_META; + return 0; +} + bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_highlight_only) { if (!spatial_editor->is_gizmo_visible()) @@ -774,7 +786,15 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { set_message(TTR("Transform Aborted."), 3); } - freelook_active = b->is_pressed(); + if (b->is_pressed()) { + int mod = _get_key_modifier(b); + if (mod == _get_key_modifier_setting("editors/3d/freelook_activation_modifier")) { + freelook_active = true; + } + } else { + freelook_active = false; + } + if (freelook_active && !surface->has_focus()) { // Focus usually doesn't trigger on right-click, but in case of freelook it should, // otherwise using keyboard navigation would misbehave @@ -1297,7 +1317,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) { nav_mode = NAVIGATION_ZOOM; - } else { + } else if (freelook_active) { nav_mode = NAVIGATION_LOOK; } @@ -1305,21 +1325,13 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (nav_scheme == NAVIGATION_GODOT) { - int mod = 0; - if (m->get_shift()) - mod = KEY_SHIFT; - if (m->get_alt()) - mod = KEY_ALT; - if (m->get_control()) - mod = KEY_CONTROL; - if (m->get_metakey()) - mod = KEY_META; + int mod = _get_key_modifier(m); - if (mod == _get_key_modifier("editors/3d/pan_modifier")) + if (mod == _get_key_modifier_setting("editors/3d/pan_modifier")) nav_mode = NAVIGATION_PAN; - else if (mod == _get_key_modifier("editors/3d/zoom_modifier")) + else if (mod == _get_key_modifier_setting("editors/3d/zoom_modifier")) nav_mode = NAVIGATION_ZOOM; - else if (mod == _get_key_modifier("editors/3d/orbit_modifier")) + else if (mod == _get_key_modifier_setting("editors/3d/orbit_modifier")) nav_mode = NAVIGATION_ORBIT; } else if (nav_scheme == NAVIGATION_MAYA) { @@ -1329,22 +1341,14 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } else if (EditorSettings::get_singleton()->get("editors/3d/emulate_3_button_mouse")) { // Handle trackpad (no external mouse) use case - int mod = 0; - if (m->get_shift()) - mod = KEY_SHIFT; - if (m->get_alt()) - mod = KEY_ALT; - if (m->get_control()) - mod = KEY_CONTROL; - if (m->get_metakey()) - mod = KEY_META; + int mod = _get_key_modifier(m); if (mod) { - if (mod == _get_key_modifier("editors/3d/pan_modifier")) + if (mod == _get_key_modifier_setting("editors/3d/pan_modifier")) nav_mode = NAVIGATION_PAN; - else if (mod == _get_key_modifier("editors/3d/zoom_modifier")) + else if (mod == _get_key_modifier_setting("editors/3d/zoom_modifier")) nav_mode = NAVIGATION_ZOOM; - else if (mod == _get_key_modifier("editors/3d/orbit_modifier")) + else if (mod == _get_key_modifier_setting("editors/3d/orbit_modifier")) nav_mode = NAVIGATION_ORBIT; } } @@ -1717,11 +1721,11 @@ void SpatialEditorViewport::_notification(int p_what) { //update shadow atlas if changed - int shadowmap_size = GlobalConfig::get_singleton()->get("rendering/quality/shadow_atlas/size"); - int atlas_q0 = GlobalConfig::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_0_subdiv"); - int atlas_q1 = GlobalConfig::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_1_subdiv"); - int atlas_q2 = GlobalConfig::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_2_subdiv"); - int atlas_q3 = GlobalConfig::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_3_subdiv"); + int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/size"); + int atlas_q0 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_0_subdiv"); + int atlas_q1 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_1_subdiv"); + int atlas_q2 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_2_subdiv"); + int atlas_q3 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_3_subdiv"); viewport->set_shadow_atlas_size(shadowmap_size); viewport->set_shadow_atlas_quadrant_subdiv(0, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q0)); @@ -1731,10 +1735,10 @@ void SpatialEditorViewport::_notification(int p_what) { //update msaa if changed - int msaa_mode = GlobalConfig::get_singleton()->get("rendering/quality/filters/msaa"); + int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/filters/msaa"); viewport->set_msaa(Viewport::MSAA(msaa_mode)); - bool hdr = GlobalConfig::get_singleton()->get("rendering/quality/depth/hdr"); + bool hdr = ProjectSettings::get_singleton()->get("rendering/quality/depth/hdr"); viewport->set_hdr(hdr); bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION)); @@ -1834,7 +1838,7 @@ void SpatialEditorViewport::_draw() { if (previewing) { - Size2 ss = Size2(GlobalConfig::get_singleton()->get("display/window/size/width"), GlobalConfig::get_singleton()->get("display/window/size/height")); + Size2 ss = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")); float aspect = ss.aspect(); Size2 s = get_size(); diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index d06c065f4f..fa80894f7b 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -30,7 +30,7 @@ #include "sprite_frames_editor_plugin.h" #include "editor/editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" #include "scene/3d/sprite_3d.h" diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index c4fe15e61c..70a1227c52 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -30,7 +30,7 @@ #include "texture_editor_plugin.h" #include "editor/editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" void TextureEditor::_gui_input(Ref<InputEvent> p_event) { diff --git a/editor/project_export.cpp b/editor/project_export.cpp index ce22ed4731..b498044a65 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -32,7 +32,7 @@ #include "editor_data.h" #include "editor_node.h" #include "editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "io/image_loader.h" #include "io/resource_loader.h" #include "io/resource_saver.h" @@ -51,6 +51,7 @@ void ProjectExportDialog::_notification(int p_what) { case NOTIFICATION_READY: { delete_preset->set_icon(get_icon("Del", "EditorIcons")); connect("confirmed", this, "_export_pck_zip"); + custom_feature_display->get_parent_control()->add_style_override("panel", get_stylebox("bg", "Tree")); } break; case NOTIFICATION_POPUP_HIDE: { EditorSettings::get_singleton()->set("interface/dialogs/export_bounds", get_rect()); @@ -240,9 +241,62 @@ void ProjectExportDialog::_edit_preset(int p_index) { export_button->set_disabled(false); } + custom_features->set_text(current->get_custom_features()); + _update_feature_list(); + updating = false; } +void ProjectExportDialog::_update_feature_list() { + + Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current()); + ERR_FAIL_COND(current.is_null()); + + Set<String> fset; + List<String> features; + + current->get_platform()->get_platform_features(&features); + current->get_platform()->get_preset_features(current, &features); + + String custom = current->get_custom_features(); + Vector<String> custom_list = custom.split(","); + for (int i = 0; i < custom_list.size(); i++) { + String f = custom_list[i].strip_edges(); + if (f != String()) { + features.push_back(f); + } + } + + for (List<String>::Element *E = features.front(); E; E = E->next()) { + fset.insert(E->get()); + } + + custom_feature_display->clear(); + for (Set<String>::Element *E = fset.front(); E; E = E->next()) { + String f = E->get(); + if (E->next()) { + f += ", "; + } + custom_feature_display->add_text(f); + } +} + +void ProjectExportDialog::_custom_features_changed(const String &p_text) { + + if (updating) + return; + + Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current()); + ERR_FAIL_COND(current.is_null()); + + current->set_custom_features(p_text); + _update_feature_list(); +} + +void ProjectExportDialog::_tab_changed(int) { + _update_feature_list(); +} + void ProjectExportDialog::_patch_button_pressed(Object *p_item, int p_column, int p_id) { TreeItem *ti = (TreeItem *)p_item; @@ -294,10 +348,10 @@ void ProjectExportDialog::_patch_selected(const String &p_path) { if (patch_index >= patches.size()) { - current->add_patch(GlobalConfig::get_singleton()->get_resource_path().path_to(p_path) + "*"); + current->add_patch(ProjectSettings::get_singleton()->get_resource_path().path_to(p_path) + "*"); } else { String enabled = patches[patch_index].ends_with("*") ? String("*") : String(); - current->set_patch(patch_index, GlobalConfig::get_singleton()->get_resource_path().path_to(p_path) + enabled); + current->set_patch(patch_index, ProjectSettings::get_singleton()->get_resource_path().path_to(p_path) + enabled); } _edit_preset(presets->get_current()); @@ -705,6 +759,8 @@ void ProjectExportDialog::_bind_methods() { ClassDB::bind_method("_open_export_template_manager", &ProjectExportDialog::_open_export_template_manager); ClassDB::bind_method("_export_project", &ProjectExportDialog::_export_project); ClassDB::bind_method("_export_project_to_path", &ProjectExportDialog::_export_project_to_path); + ClassDB::bind_method("_custom_features_changed", &ProjectExportDialog::_custom_features_changed); + ClassDB::bind_method("_tab_changed", &ProjectExportDialog::_tab_changed); } ProjectExportDialog::ProjectExportDialog() { @@ -828,6 +884,21 @@ ProjectExportDialog::ProjectExportDialog() { patch_erase->connect("confirmed", this, "_patch_deleted"); add_child(patch_erase); + VBoxContainer *feature_vb = memnew(VBoxContainer); + feature_vb->set_name(TTR("Features")); + custom_features = memnew(LineEdit); + custom_features->connect("text_changed", this, "_custom_features_changed"); + feature_vb->add_margin_child(TTR("Custom (comma-separated):"), custom_features); + Panel *features_panel = memnew(Panel); + custom_feature_display = memnew(RichTextLabel); + features_panel->add_child(custom_feature_display); + custom_feature_display->set_area_as_parent_rect(10 * EDSCALE); + custom_feature_display->set_v_size_flags(SIZE_EXPAND_FILL); + feature_vb->add_margin_child(TTR("Feature List:"), features_panel, true); + sections->add_child(feature_vb); + + sections->connect("tab_changed", this, "_tab_changed"); + //disable by default name->set_editable(false); runnable->set_disabled(true); diff --git a/editor/project_export.h b/editor/project_export.h index a3bbfc52ff..29c24005e0 100644 --- a/editor/project_export.h +++ b/editor/project_export.h @@ -40,6 +40,7 @@ #include "scene/gui/label.h" #include "scene/gui/link_button.h" #include "scene/gui/option_button.h" +#include "scene/gui/rich_text_label.h" #include "scene/gui/tab_container.h" #include "scene/gui/tree.h" #include "scene/main/timer.h" @@ -91,6 +92,9 @@ private: Button *export_button; + LineEdit *custom_features; + RichTextLabel *custom_feature_display; + Label *export_error; HBoxContainer *export_templates_error; @@ -132,6 +136,11 @@ private: void _export_project(); void _export_project_to_path(const String &p_path); + void _update_feature_list(); + void _custom_features_changed(const String &p_text); + + void _tab_changed(int); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index e3f22c833e..acf5fe02cc 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -202,10 +202,10 @@ private: f->store_line("\n"); f->store_line("[application]"); f->store_line("\n"); - f->store_line("name=\"" + project_name->get_text() + "\""); - f->store_line("icon=\"res://icon.png\""); + f->store_line("config/name=\"" + project_name->get_text() + "\""); + f->store_line("config/icon=\"res://icon.png\""); f->store_line("[rendering]"); - f->store_line("viewport/default_environment=\"res://default_env.tres\""); + f->store_line("environment/default_environment=\"res://default_env.tres\""); memdelete(f); ResourceSaver::save(dir.plus_file("/icon.png"), get_icon("DefaultProjectIcon", "EditorIcons")); @@ -811,16 +811,16 @@ void ProjectManager::_load_recent_projects() { String project_name = TTR("Unnamed Project"); - if (cf->has_section_key("application", "name")) { - project_name = static_cast<String>(cf->get_value("application", "name")).xml_unescape(); + if (cf->has_section_key("application", "config/name")) { + project_name = static_cast<String>(cf->get_value("application", "config/name")).xml_unescape(); } if (filter_option == ProjectListFilter::FILTER_NAME && search_term != "" && project_name.findn(search_term) == -1) continue; Ref<Texture> icon; - if (cf->has_section_key("application", "icon")) { - String appicon = cf->get_value("application", "icon"); + if (cf->has_section_key("application", "config/icon")) { + String appicon = cf->get_value("application", "config/icon"); if (appicon != "") { Ref<Image> img; img.instance(); @@ -840,8 +840,8 @@ void ProjectManager::_load_recent_projects() { } String main_scene; - if (cf->has_section_key("application", "main_scene")) { - main_scene = cf->get_value("application", "main_scene"); + if (cf->has_section_key("application", "run/main_scene")) { + main_scene = cf->get_value("application", "run/main_scene"); } selected_list_copy.erase(project); diff --git a/editor/project_settings.cpp b/editor/project_settings_editor.cpp index f72c655561..6d23e874df 100644 --- a/editor/project_settings.cpp +++ b/editor/project_settings_editor.cpp @@ -27,17 +27,17 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "project_settings.h" +#include "project_settings_editor.h" #include "editor_node.h" -#include "global_config.h" #include "global_constants.h" #include "os/keyboard.h" +#include "project_settings.h" #include "scene/gui/margin_container.h" #include "scene/gui/tab_container.h" #include "translation.h" -ProjectSettings *ProjectSettings::singleton = NULL; +ProjectSettingsEditor *ProjectSettingsEditor::singleton = NULL; static const char *_button_names[JOY_BUTTON_MAX] = { "PS Cross, XBox A, Nintendo B", @@ -72,11 +72,11 @@ static const char *_axis_names[JOY_AXIS_MAX * 2] = { "", " (R2)" }; -void ProjectSettings::_notification(int p_what) { +void ProjectSettingsEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - globals_editor->edit(GlobalConfig::get_singleton()); + globals_editor->edit(ProjectSettings::get_singleton()); search_button->set_icon(get_icon("Search", "EditorIcons")); clear_button->set_icon(get_icon("Close", "EditorIcons")); @@ -112,7 +112,7 @@ void ProjectSettings::_notification(int p_what) { } } -void ProjectSettings::_action_selected() { +void ProjectSettingsEditor::_action_selected() { TreeItem *ti = input_editor->get_selected(); if (!ti || !ti->is_editable(0)) @@ -122,7 +122,7 @@ void ProjectSettings::_action_selected() { edit_idx = -1; } -void ProjectSettings::_action_edited() { +void ProjectSettingsEditor::_action_edited() { TreeItem *ti = input_editor->get_selected(); if (!ti) @@ -146,7 +146,7 @@ void ProjectSettings::_action_edited() { String action_prop = "input/" + new_name; - if (GlobalConfig::get_singleton()->has(action_prop)) { + if (ProjectSettings::get_singleton()->has(action_prop)) { ti->set_text(0, old_name); add_at = "input/" + old_name; @@ -156,17 +156,17 @@ void ProjectSettings::_action_edited() { return; } - int order = GlobalConfig::get_singleton()->get_order(add_at); - Array va = GlobalConfig::get_singleton()->get(add_at); + int order = ProjectSettings::get_singleton()->get_order(add_at); + Array va = ProjectSettings::get_singleton()->get(add_at); setting = true; undo_redo->create_action(TTR("Rename Input Action Event")); - undo_redo->add_do_method(GlobalConfig::get_singleton(), "clear", add_at); - undo_redo->add_do_method(GlobalConfig::get_singleton(), "set", action_prop, va); - undo_redo->add_do_method(GlobalConfig::get_singleton(), "set_order", action_prop, order); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "clear", action_prop); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set", add_at, va); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set_order", add_at, order); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", add_at); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", action_prop, va); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", action_prop, order); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", action_prop); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", add_at, va); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", add_at, order); undo_redo->add_do_method(this, "_update_actions"); undo_redo->add_undo_method(this, "_update_actions"); undo_redo->add_do_method(this, "_settings_changed"); @@ -177,12 +177,12 @@ void ProjectSettings::_action_edited() { add_at = action_prop; } -void ProjectSettings::_device_input_add() { +void ProjectSettingsEditor::_device_input_add() { Ref<InputEvent> ie; String name = add_at; int idx = edit_idx; - Variant old_val = GlobalConfig::get_singleton()->get(name); + Variant old_val = ProjectSettings::get_singleton()->get(name); Array arr = old_val; // ie.device = device_id->get_value(); // ie.type = add_type; @@ -260,8 +260,8 @@ void ProjectSettings::_device_input_add() { } undo_redo->create_action(TTR("Add Input Action Event")); - undo_redo->add_do_method(GlobalConfig::get_singleton(), "set", name, arr); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set", name, old_val); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, arr); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_val); undo_redo->add_do_method(this, "_update_actions"); undo_redo->add_undo_method(this, "_update_actions"); undo_redo->add_do_method(this, "_settings_changed"); @@ -271,7 +271,7 @@ void ProjectSettings::_device_input_add() { _show_last_added(ie, name); } -void ProjectSettings::_press_a_key_confirm() { +void ProjectSettingsEditor::_press_a_key_confirm() { if (last_wait_for_key.is_null()) return; @@ -287,7 +287,7 @@ void ProjectSettings::_press_a_key_confirm() { String name = add_at; int idx = edit_idx; - Variant old_val = GlobalConfig::get_singleton()->get(name); + Variant old_val = ProjectSettings::get_singleton()->get(name); Array arr = old_val; for (int i = 0; i < arr.size(); i++) { @@ -307,8 +307,8 @@ void ProjectSettings::_press_a_key_confirm() { } undo_redo->create_action(TTR("Add Input Action Event")); - undo_redo->add_do_method(GlobalConfig::get_singleton(), "set", name, arr); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set", name, old_val); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, arr); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_val); undo_redo->add_do_method(this, "_update_actions"); undo_redo->add_undo_method(this, "_update_actions"); undo_redo->add_do_method(this, "_settings_changed"); @@ -318,7 +318,7 @@ void ProjectSettings::_press_a_key_confirm() { _show_last_added(ie, name); } -void ProjectSettings::_show_last_added(const Ref<InputEvent> &p_event, const String &p_name) { +void ProjectSettingsEditor::_show_last_added(const Ref<InputEvent> &p_event, const String &p_name) { TreeItem *r = input_editor->get_root(); String name = p_name; @@ -351,7 +351,7 @@ void ProjectSettings::_show_last_added(const Ref<InputEvent> &p_event, const Str if (found) input_editor->ensure_cursor_is_visible(); } -void ProjectSettings::_wait_for_key(const Ref<InputEvent> &p_event) { +void ProjectSettingsEditor::_wait_for_key(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; @@ -373,7 +373,7 @@ void ProjectSettings::_wait_for_key(const Ref<InputEvent> &p_event) { } } -void ProjectSettings::_add_item(int p_item, Ref<InputEvent> p_exiting_event) { +void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_event) { add_type = InputType(p_item); @@ -458,7 +458,7 @@ void ProjectSettings::_add_item(int p_item, Ref<InputEvent> p_exiting_event) { } } -void ProjectSettings::_edit_item(Ref<InputEvent> p_exiting_event) { +void ProjectSettingsEditor::_edit_item(Ref<InputEvent> p_exiting_event) { InputType ie_type; @@ -480,7 +480,7 @@ void ProjectSettings::_edit_item(Ref<InputEvent> p_exiting_event) { _add_item(ie_type, p_exiting_event); } -void ProjectSettings::_action_activated() { +void ProjectSettingsEditor::_action_activated() { TreeItem *ti = input_editor->get_selected(); @@ -489,7 +489,7 @@ void ProjectSettings::_action_activated() { String name = "input/" + ti->get_parent()->get_text(0); int idx = ti->get_metadata(0); - Array va = GlobalConfig::get_singleton()->get(name); + Array va = ProjectSettings::get_singleton()->get(name); ERR_FAIL_INDEX(idx, va.size()); @@ -503,7 +503,7 @@ void ProjectSettings::_action_activated() { _edit_item(ie); } -void ProjectSettings::_action_button_pressed(Object *p_obj, int p_column, int p_id) { +void ProjectSettingsEditor::_action_button_pressed(Object *p_obj, int p_column, int p_id) { TreeItem *ti = p_obj->cast_to<TreeItem>(); @@ -528,13 +528,13 @@ void ProjectSettings::_action_button_pressed(Object *p_obj, int p_column, int p_ //remove main thing String name = "input/" + ti->get_text(0); - Variant old_val = GlobalConfig::get_singleton()->get(name); - int order = GlobalConfig::get_singleton()->get_order(name); + Variant old_val = ProjectSettings::get_singleton()->get(name); + int order = ProjectSettings::get_singleton()->get_order(name); undo_redo->create_action(TTR("Add Input Action")); - undo_redo->add_do_method(GlobalConfig::get_singleton(), "clear", name); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set", name, old_val); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set_order", name, order); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", name); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_val); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", name, order); undo_redo->add_do_method(this, "_update_actions"); undo_redo->add_undo_method(this, "_update_actions"); undo_redo->add_do_method(this, "_settings_changed"); @@ -544,7 +544,7 @@ void ProjectSettings::_action_button_pressed(Object *p_obj, int p_column, int p_ } else { //remove action String name = "input/" + ti->get_parent()->get_text(0); - Variant old_val = GlobalConfig::get_singleton()->get(name); + Variant old_val = ProjectSettings::get_singleton()->get(name); int idx = ti->get_metadata(0); Array va = old_val; @@ -559,8 +559,8 @@ void ProjectSettings::_action_button_pressed(Object *p_obj, int p_column, int p_ va.resize(va.size() - 1); undo_redo->create_action(TTR("Erase Input Action Event")); - undo_redo->add_do_method(GlobalConfig::get_singleton(), "set", name, va); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "set", name, old_val); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, va); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_val); undo_redo->add_do_method(this, "_update_actions"); undo_redo->add_undo_method(this, "_update_actions"); undo_redo->add_do_method(this, "_settings_changed"); @@ -579,7 +579,7 @@ void ProjectSettings::_action_button_pressed(Object *p_obj, int p_column, int p_ //edit action String name = "input/" + ti->get_parent()->get_text(0); int idx = ti->get_metadata(0); - Array va = GlobalConfig::get_singleton()->get(name); + Array va = ProjectSettings::get_singleton()->get(name); ERR_FAIL_INDEX(idx, va.size()); @@ -596,7 +596,7 @@ void ProjectSettings::_action_button_pressed(Object *p_obj, int p_column, int p_ } } -void ProjectSettings::_update_actions() { +void ProjectSettingsEditor::_update_actions() { if (setting) return; @@ -606,7 +606,7 @@ void ProjectSettings::_update_actions() { input_editor->set_hide_root(true); List<PropertyInfo> props; - GlobalConfig::get_singleton()->get_property_list(&props); + ProjectSettings::get_singleton()->get_property_list(&props); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { @@ -622,14 +622,14 @@ void ProjectSettings::_update_actions() { //item->set_cell_mode(0,TreeItem::CELL_MODE_CHECK); item->set_text(0, name); item->add_button(0, get_icon("Add", "EditorIcons"), 1, false, TTR("Add Event")); - if (!GlobalConfig::get_singleton()->get_input_presets().find(pi.name)) { + if (!ProjectSettings::get_singleton()->get_input_presets().find(pi.name)) { item->add_button(0, get_icon("Remove", "EditorIcons"), 2, false, TTR("Remove")); item->set_editable(0, true); } item->set_custom_bg_color(0, get_color("prop_subsection", "Editor")); //item->set_checked(0,pi.usage&PROPERTY_USAGE_CHECKED); - Array actions = GlobalConfig::get_singleton()->get(pi.name); + Array actions = ProjectSettings::get_singleton()->get(pi.name); for (int i = 0; i < actions.size(); i++) { @@ -706,7 +706,7 @@ void ProjectSettings::_update_actions() { } } -void ProjectSettings::popup_project_settings() { +void ProjectSettingsEditor::popup_project_settings() { // Restore valid window bounds or pop up at default size. if (EditorSettings::get_singleton()->has("interface/dialogs/project_settings_bounds")) { @@ -720,7 +720,7 @@ void ProjectSettings::popup_project_settings() { plugin_settings->update_plugins(); } -void ProjectSettings::_item_selected() { +void ProjectSettingsEditor::_item_selected() { TreeItem *ti = globals_editor->get_property_editor()->get_scene_tree()->get_selected(); if (!ti) @@ -729,15 +729,15 @@ void ProjectSettings::_item_selected() { return; category->set_text(globals_editor->get_current_section()); property->set_text(ti->get_text(0)); - popup_platform->set_disabled(false); + popup_copy_to_feature->set_disabled(false); } -void ProjectSettings::_item_adds(String) { +void ProjectSettingsEditor::_item_adds(String) { _item_add(); } -void ProjectSettings::_item_add() { +void ProjectSettingsEditor::_item_add() { Variant value; switch (type->get_selected()) { @@ -765,12 +765,12 @@ void ProjectSettings::_item_add() { undo_redo->create_action("Add Global Property"); - undo_redo->add_do_property(GlobalConfig::get_singleton(), name, value); + undo_redo->add_do_property(ProjectSettings::get_singleton(), name, value); - if (GlobalConfig::get_singleton()->has(name)) { - undo_redo->add_undo_property(GlobalConfig::get_singleton(), name, GlobalConfig::get_singleton()->get(name)); + if (ProjectSettings::get_singleton()->has(name)) { + undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, ProjectSettings::get_singleton()->get(name)); } else { - undo_redo->add_undo_property(GlobalConfig::get_singleton(), name, Variant()); + undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, Variant()); } undo_redo->add_do_method(globals_editor, "update_category_list"); @@ -786,20 +786,35 @@ void ProjectSettings::_item_add() { _settings_changed(); } -void ProjectSettings::_item_del() { +void ProjectSettingsEditor::_item_del() { - String catname = category->get_text().strip_edges(); - //ERR_FAIL_COND(!catname.is_valid_identifier()); - String propname = property->get_text().strip_edges(); - //ERR_FAIL_COND(!propname.is_valid_identifier()); + String path = globals_editor->get_property_editor()->get_selected_path(); + if (path == String()) { + EditorNode::get_singleton()->show_warning(TTR("Select an setting item first!")); + return; + } - String name = catname != "" ? catname + "/" + propname : propname; + String property = globals_editor->get_current_section().plus_file(path); - undo_redo->create_action("Delete Global Property"); + if (!ProjectSettings::get_singleton()->has(property)) { + EditorNode::get_singleton()->show_warning(TTR("No property '" + property + "' exists.")); + return; + } - undo_redo->add_do_property(GlobalConfig::get_singleton(), name, Variant()); + if (ProjectSettings::get_singleton()->get_order(property) < ProjectSettings::NO_BUILTIN_ORDER_BASE) { + EditorNode::get_singleton()->show_warning(TTR("Setting '" + property + "' is internal, and it can't be deleted.")); + return; + } - undo_redo->add_undo_property(GlobalConfig::get_singleton(), name, GlobalConfig::get_singleton()->get(name)); + print_line("to delete.. " + property); + undo_redo->create_action(TTR("Delete Item")); + + Variant value = ProjectSettings::get_singleton()->get(property); + int order = ProjectSettings::get_singleton()->get_order(property); + + undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", property); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", property, value); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", property, order); undo_redo->add_do_method(globals_editor, "update_category_list"); undo_redo->add_undo_method(globals_editor, "update_category_list"); @@ -808,16 +823,14 @@ void ProjectSettings::_item_del() { undo_redo->add_undo_method(this, "_settings_changed"); undo_redo->commit_action(); - - _settings_changed(); } -void ProjectSettings::_action_adds(String) { +void ProjectSettingsEditor::_action_adds(String) { _action_add(); } -void ProjectSettings::_action_add() { +void ProjectSettingsEditor::_action_add() { String action = action_name->get_text(); if (action.find("/") != -1 || action.find(":") != -1 || action == "") { @@ -826,7 +839,7 @@ void ProjectSettings::_action_add() { return; } - if (GlobalConfig::get_singleton()->has("input/" + action)) { + if (ProjectSettings::get_singleton()->has("input/" + action)) { message->set_text(vformat(TTR("Action '%s' already exists!"), action)); message->popup_centered(Size2(300, 100)); return; @@ -835,8 +848,8 @@ void ProjectSettings::_action_add() { Array va; String name = "input/" + action; undo_redo->create_action(TTR("Add Input Action Event")); - undo_redo->add_do_method(GlobalConfig::get_singleton(), "set", name, va); - undo_redo->add_undo_method(GlobalConfig::get_singleton(), "clear", name); + undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, va); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", name); undo_redo->add_do_method(this, "_update_actions"); undo_redo->add_undo_method(this, "_update_actions"); undo_redo->add_do_method(this, "_settings_changed"); @@ -859,66 +872,119 @@ void ProjectSettings::_action_add() { input_editor->ensure_cursor_is_visible(); } -void ProjectSettings::_item_checked(const String &p_item, bool p_check) { +void ProjectSettingsEditor::_item_checked(const String &p_item, bool p_check) { } -void ProjectSettings::_save() { +void ProjectSettingsEditor::_save() { - Error err = GlobalConfig::get_singleton()->save(); + Error err = ProjectSettings::get_singleton()->save(); message->set_text(err != OK ? TTR("Error saving settings.") : TTR("Settings saved OK.")); message->popup_centered(Size2(300, 100)); } -void ProjectSettings::_settings_prop_edited(const String &p_name) { +void ProjectSettingsEditor::_settings_prop_edited(const String &p_name) { String full_item = globals_editor->get_full_item_path(p_name); _settings_changed(); } -void ProjectSettings::_settings_changed() { +void ProjectSettingsEditor::_settings_changed() { timer->start(); } -void ProjectSettings::queue_save() { +void ProjectSettingsEditor::queue_save() { _settings_changed(); } -void ProjectSettings::_copy_to_platform(int p_which) { +void ProjectSettingsEditor::_copy_to_platform_about_to_show() { - String catname = category->get_text(); - if (!catname.is_valid_identifier()) { - message->set_text("Invalid Category.\nValid characters: a-z,A-Z,0-9 or _"); - message->popup_centered(Size2(300, 100)); - return; + Set<String> presets; + + presets.insert("s3tc"); + presets.insert("etc"); + presets.insert("etc2"); + presets.insert("pvrtc"); + presets.insert("debug"); + presets.insert("release"); + + for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) { + List<String> p; + EditorExport::get_singleton()->get_export_platform(i)->get_platform_features(&p); + for (List<String>::Element *E = p.front(); E; E = E->next()) { + presets.insert(E->get()); + } } - String propname = property->get_text(); - if (!propname.is_valid_identifier()) { - message->set_text("Invalid Property.\nValid characters: a-z,A-Z,0-9 or _"); - message->popup_centered(Size2(300, 100)); + for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) { + + List<String> p; + EditorExport::get_singleton()->get_export_preset(i)->get_platform()->get_preset_features(EditorExport::get_singleton()->get_export_preset(i), &p); + for (List<String>::Element *E = p.front(); E; E = E->next()) { + presets.insert(E->get()); + } + + String custom = EditorExport::get_singleton()->get_export_preset(i)->get_custom_features(); + Vector<String> custom_list = custom.split(","); + for (int i = 0; i < custom_list.size(); i++) { + String f = custom_list[i].strip_edges(); + if (f != String()) { + presets.insert(f); + } + } + } + + popup_copy_to_feature->get_popup()->clear(); + int id = 0; + for (Set<String>::Element *E = presets.front(); E; E = E->next()) { + popup_copy_to_feature->get_popup()->add_item(E->get(), id++); + } +} + +void ProjectSettingsEditor::_copy_to_platform(int p_which) { + + String path = globals_editor->get_property_editor()->get_selected_path(); + if (path == String()) { + EditorNode::get_singleton()->show_warning(TTR("Select an setting item first!")); return; } - String name = catname + "/" + propname; - Variant value = GlobalConfig::get_singleton()->get(name); + String property = globals_editor->get_current_section().plus_file(path); - catname += "." + popup_platform->get_popup()->get_item_text(p_which); - name = catname + "/" + propname; + undo_redo->create_action(TTR("Override for Feature")); - GlobalConfig::get_singleton()->set(name, value); - globals_editor->get_property_editor()->update_tree(); + Variant value = ProjectSettings::get_singleton()->get(property); + if (property.find(".") != -1) { //overwriting overwrite, keep overwrite + undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", property); + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", property, value); + } + + String feature = popup_copy_to_feature->get_popup()->get_item_text(p_which); + String new_path = property + "." + feature; + + undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", new_path, value); + if (ProjectSettings::get_singleton()->has(new_path)) { + undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", new_path, ProjectSettings::get_singleton()->get(new_path)); + } + + undo_redo->add_do_method(globals_editor, "update_category_list"); + undo_redo->add_undo_method(globals_editor, "update_category_list"); + + undo_redo->add_do_method(this, "_settings_changed"); + undo_redo->add_undo_method(this, "_settings_changed"); + + undo_redo->commit_action(); } -void ProjectSettings::add_translation(const String &p_translation) { +void ProjectSettingsEditor::add_translation(const String &p_translation) { _translation_add(p_translation); } -void ProjectSettings::_translation_add(const String &p_path) { +void ProjectSettingsEditor::_translation_add(const String &p_path) { - PoolStringArray translations = GlobalConfig::get_singleton()->get("locale/translations"); + PoolStringArray translations = ProjectSettings::get_singleton()->get("locale/translations"); for (int i = 0; i < translations.size(); i++) { @@ -928,8 +994,8 @@ void ProjectSettings::_translation_add(const String &p_path) { translations.push_back(p_path); undo_redo->create_action(TTR("Add Translation")); - undo_redo->add_do_property(GlobalConfig::get_singleton(), "locale/translations", translations); - undo_redo->add_undo_property(GlobalConfig::get_singleton(), "locale/translations", GlobalConfig::get_singleton()->get("locale/translations")); + undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translations", translations); + undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translations", ProjectSettings::get_singleton()->get("locale/translations")); undo_redo->add_do_method(this, "_update_translations"); undo_redo->add_undo_method(this, "_update_translations"); undo_redo->add_do_method(this, "_settings_changed"); @@ -937,27 +1003,27 @@ void ProjectSettings::_translation_add(const String &p_path) { undo_redo->commit_action(); } -void ProjectSettings::_translation_file_open() { +void ProjectSettingsEditor::_translation_file_open() { translation_file_open->popup_centered_ratio(); } -void ProjectSettings::_translation_delete(Object *p_item, int p_column, int p_button) { +void ProjectSettingsEditor::_translation_delete(Object *p_item, int p_column, int p_button) { TreeItem *ti = p_item->cast_to<TreeItem>(); ERR_FAIL_COND(!ti); int idx = ti->get_metadata(0); - PoolStringArray translations = GlobalConfig::get_singleton()->get("locale/translations"); + PoolStringArray translations = ProjectSettings::get_singleton()->get("locale/translations"); ERR_FAIL_INDEX(idx, translations.size()); translations.remove(idx); undo_redo->create_action(TTR("Remove Translation")); - undo_redo->add_do_property(GlobalConfig::get_singleton(), "locale/translations", translations); - undo_redo->add_undo_property(GlobalConfig::get_singleton(), "locale/translations", GlobalConfig::get_singleton()->get("locale/translations")); + undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translations", translations); + undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translations", ProjectSettings::get_singleton()->get("locale/translations")); undo_redo->add_do_method(this, "_update_translations"); undo_redo->add_undo_method(this, "_update_translations"); undo_redo->add_do_method(this, "_settings_changed"); @@ -965,18 +1031,18 @@ void ProjectSettings::_translation_delete(Object *p_item, int p_column, int p_bu undo_redo->commit_action(); } -void ProjectSettings::_translation_res_file_open() { +void ProjectSettingsEditor::_translation_res_file_open() { translation_res_file_open->popup_centered_ratio(); } -void ProjectSettings::_translation_res_add(const String &p_path) { +void ProjectSettingsEditor::_translation_res_add(const String &p_path) { Variant prev; Dictionary remaps; - if (GlobalConfig::get_singleton()->has("locale/translation_remaps")) { - remaps = GlobalConfig::get_singleton()->get("locale/translation_remaps"); + if (ProjectSettings::get_singleton()->has("locale/translation_remaps")) { + remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps"); prev = remaps; } @@ -986,8 +1052,8 @@ void ProjectSettings::_translation_res_add(const String &p_path) { remaps[p_path] = PoolStringArray(); undo_redo->create_action(TTR("Add Remapped Path")); - undo_redo->add_do_property(GlobalConfig::get_singleton(), "locale/translation_remaps", remaps); - undo_redo->add_undo_property(GlobalConfig::get_singleton(), "locale/translation_remaps", prev); + undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translation_remaps", remaps); + undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translation_remaps", prev); undo_redo->add_do_method(this, "_update_translations"); undo_redo->add_undo_method(this, "_update_translations"); undo_redo->add_do_method(this, "_settings_changed"); @@ -995,15 +1061,15 @@ void ProjectSettings::_translation_res_add(const String &p_path) { undo_redo->commit_action(); } -void ProjectSettings::_translation_res_option_file_open() { +void ProjectSettingsEditor::_translation_res_option_file_open() { translation_res_option_file_open->popup_centered_ratio(); } -void ProjectSettings::_translation_res_option_add(const String &p_path) { +void ProjectSettingsEditor::_translation_res_option_add(const String &p_path) { - ERR_FAIL_COND(!GlobalConfig::get_singleton()->has("locale/translation_remaps")); + ERR_FAIL_COND(!ProjectSettings::get_singleton()->has("locale/translation_remaps")); - Dictionary remaps = GlobalConfig::get_singleton()->get("locale/translation_remaps"); + Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps"); TreeItem *k = translation_remap->get_selected(); ERR_FAIL_COND(!k); @@ -1016,8 +1082,8 @@ void ProjectSettings::_translation_res_option_add(const String &p_path) { remaps[key] = r; undo_redo->create_action(TTR("Resource Remap Add Remap")); - undo_redo->add_do_property(GlobalConfig::get_singleton(), "locale/translation_remaps", remaps); - undo_redo->add_undo_property(GlobalConfig::get_singleton(), "locale/translation_remaps", GlobalConfig::get_singleton()->get("locale/translation_remaps")); + undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translation_remaps", remaps); + undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translation_remaps", ProjectSettings::get_singleton()->get("locale/translation_remaps")); undo_redo->add_do_method(this, "_update_translations"); undo_redo->add_undo_method(this, "_update_translations"); undo_redo->add_do_method(this, "_settings_changed"); @@ -1025,7 +1091,7 @@ void ProjectSettings::_translation_res_option_add(const String &p_path) { undo_redo->commit_action(); } -void ProjectSettings::_translation_res_select() { +void ProjectSettingsEditor::_translation_res_select() { if (updating_translations) return; @@ -1033,15 +1099,15 @@ void ProjectSettings::_translation_res_select() { call_deferred("_update_translations"); } -void ProjectSettings::_translation_res_option_changed() { +void ProjectSettingsEditor::_translation_res_option_changed() { if (updating_translations) return; - if (!GlobalConfig::get_singleton()->has("locale/translation_remaps")) + if (!ProjectSettings::get_singleton()->has("locale/translation_remaps")) return; - Dictionary remaps = GlobalConfig::get_singleton()->get("locale/translation_remaps"); + Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps"); TreeItem *k = translation_remap->get_selected(); ERR_FAIL_COND(!k); @@ -1065,8 +1131,8 @@ void ProjectSettings::_translation_res_option_changed() { updating_translations = true; undo_redo->create_action(TTR("Change Resource Remap Language")); - undo_redo->add_do_property(GlobalConfig::get_singleton(), "locale/translation_remaps", remaps); - undo_redo->add_undo_property(GlobalConfig::get_singleton(), "locale/translation_remaps", GlobalConfig::get_singleton()->get("locale/translation_remaps")); + undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translation_remaps", remaps); + undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translation_remaps", ProjectSettings::get_singleton()->get("locale/translation_remaps")); undo_redo->add_do_method(this, "_update_translations"); undo_redo->add_undo_method(this, "_update_translations"); undo_redo->add_do_method(this, "_settings_changed"); @@ -1075,15 +1141,15 @@ void ProjectSettings::_translation_res_option_changed() { updating_translations = false; } -void ProjectSettings::_translation_res_delete(Object *p_item, int p_column, int p_button) { +void ProjectSettingsEditor::_translation_res_delete(Object *p_item, int p_column, int p_button) { if (updating_translations) return; - if (!GlobalConfig::get_singleton()->has("locale/translation_remaps")) + if (!ProjectSettings::get_singleton()->has("locale/translation_remaps")) return; - Dictionary remaps = GlobalConfig::get_singleton()->get("locale/translation_remaps"); + Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps"); TreeItem *k = p_item->cast_to<TreeItem>(); @@ -1093,8 +1159,8 @@ void ProjectSettings::_translation_res_delete(Object *p_item, int p_column, int remaps.erase(key); undo_redo->create_action(TTR("Remove Resource Remap")); - undo_redo->add_do_property(GlobalConfig::get_singleton(), "locale/translation_remaps", remaps); - undo_redo->add_undo_property(GlobalConfig::get_singleton(), "locale/translation_remaps", GlobalConfig::get_singleton()->get("locale/translation_remaps")); + undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translation_remaps", remaps); + undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translation_remaps", ProjectSettings::get_singleton()->get("locale/translation_remaps")); undo_redo->add_do_method(this, "_update_translations"); undo_redo->add_undo_method(this, "_update_translations"); undo_redo->add_do_method(this, "_settings_changed"); @@ -1102,15 +1168,15 @@ void ProjectSettings::_translation_res_delete(Object *p_item, int p_column, int undo_redo->commit_action(); } -void ProjectSettings::_translation_res_option_delete(Object *p_item, int p_column, int p_button) { +void ProjectSettingsEditor::_translation_res_option_delete(Object *p_item, int p_column, int p_button) { if (updating_translations) return; - if (!GlobalConfig::get_singleton()->has("locale/translation_remaps")) + if (!ProjectSettings::get_singleton()->has("locale/translation_remaps")) return; - Dictionary remaps = GlobalConfig::get_singleton()->get("locale/translation_remaps"); + Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps"); TreeItem *k = translation_remap->get_selected(); ERR_FAIL_COND(!k); @@ -1127,8 +1193,8 @@ void ProjectSettings::_translation_res_option_delete(Object *p_item, int p_colum remaps[key] = r; undo_redo->create_action(TTR("Remove Resource Remap Option")); - undo_redo->add_do_property(GlobalConfig::get_singleton(), "locale/translation_remaps", remaps); - undo_redo->add_undo_property(GlobalConfig::get_singleton(), "locale/translation_remaps", GlobalConfig::get_singleton()->get("locale/translation_remaps")); + undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translation_remaps", remaps); + undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translation_remaps", ProjectSettings::get_singleton()->get("locale/translation_remaps")); undo_redo->add_do_method(this, "_update_translations"); undo_redo->add_undo_method(this, "_update_translations"); undo_redo->add_do_method(this, "_settings_changed"); @@ -1136,7 +1202,7 @@ void ProjectSettings::_translation_res_option_delete(Object *p_item, int p_colum undo_redo->commit_action(); } -void ProjectSettings::_update_translations() { +void ProjectSettingsEditor::_update_translations() { //update translations @@ -1148,9 +1214,9 @@ void ProjectSettings::_update_translations() { translation_list->clear(); TreeItem *root = translation_list->create_item(NULL); translation_list->set_hide_root(true); - if (GlobalConfig::get_singleton()->has("locale/translations")) { + if (ProjectSettings::get_singleton()->has("locale/translations")) { - PoolStringArray translations = GlobalConfig::get_singleton()->get("locale/translations"); + PoolStringArray translations = ProjectSettings::get_singleton()->get("locale/translations"); for (int i = 0; i < translations.size(); i++) { TreeItem *t = translation_list->create_item(root); @@ -1186,9 +1252,9 @@ void ProjectSettings::_update_translations() { langnames += names[i]; } - if (GlobalConfig::get_singleton()->has("locale/translation_remaps")) { + if (ProjectSettings::get_singleton()->has("locale/translation_remaps")) { - Dictionary remaps = GlobalConfig::get_singleton()->get("locale/translation_remaps"); + Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps"); List<Variant> rk; remaps.get_key_list(&rk); Vector<String> keys; @@ -1241,7 +1307,7 @@ void ProjectSettings::_update_translations() { updating_translations = false; } -void ProjectSettings::_toggle_search_bar(bool p_pressed) { +void ProjectSettingsEditor::_toggle_search_bar(bool p_pressed) { globals_editor->get_property_editor()->set_use_filter(p_pressed); @@ -1258,7 +1324,7 @@ void ProjectSettings::_toggle_search_bar(bool p_pressed) { } } -void ProjectSettings::_clear_search_box() { +void ProjectSettingsEditor::_clear_search_box() { if (search_box->get_text() == "") return; @@ -1267,52 +1333,54 @@ void ProjectSettings::_clear_search_box() { globals_editor->get_property_editor()->update_tree(); } -void ProjectSettings::set_plugins_page() { +void ProjectSettingsEditor::set_plugins_page() { tab_container->set_current_tab(plugin_settings->get_index()); } -void ProjectSettings::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_item_selected"), &ProjectSettings::_item_selected); - ClassDB::bind_method(D_METHOD("_item_add"), &ProjectSettings::_item_add); - ClassDB::bind_method(D_METHOD("_item_adds"), &ProjectSettings::_item_adds); - ClassDB::bind_method(D_METHOD("_item_del"), &ProjectSettings::_item_del); - ClassDB::bind_method(D_METHOD("_item_checked"), &ProjectSettings::_item_checked); - ClassDB::bind_method(D_METHOD("_save"), &ProjectSettings::_save); - ClassDB::bind_method(D_METHOD("_action_add"), &ProjectSettings::_action_add); - ClassDB::bind_method(D_METHOD("_action_adds"), &ProjectSettings::_action_adds); - ClassDB::bind_method(D_METHOD("_action_selected"), &ProjectSettings::_action_selected); - ClassDB::bind_method(D_METHOD("_action_edited"), &ProjectSettings::_action_edited); - ClassDB::bind_method(D_METHOD("_action_activated"), &ProjectSettings::_action_activated); - ClassDB::bind_method(D_METHOD("_action_button_pressed"), &ProjectSettings::_action_button_pressed); - ClassDB::bind_method(D_METHOD("_update_actions"), &ProjectSettings::_update_actions); - ClassDB::bind_method(D_METHOD("_wait_for_key"), &ProjectSettings::_wait_for_key); - ClassDB::bind_method(D_METHOD("_add_item"), &ProjectSettings::_add_item, DEFVAL(Variant())); - ClassDB::bind_method(D_METHOD("_device_input_add"), &ProjectSettings::_device_input_add); - ClassDB::bind_method(D_METHOD("_press_a_key_confirm"), &ProjectSettings::_press_a_key_confirm); - ClassDB::bind_method(D_METHOD("_settings_prop_edited"), &ProjectSettings::_settings_prop_edited); - ClassDB::bind_method(D_METHOD("_copy_to_platform"), &ProjectSettings::_copy_to_platform); - ClassDB::bind_method(D_METHOD("_update_translations"), &ProjectSettings::_update_translations); - ClassDB::bind_method(D_METHOD("_translation_delete"), &ProjectSettings::_translation_delete); - ClassDB::bind_method(D_METHOD("_settings_changed"), &ProjectSettings::_settings_changed); - ClassDB::bind_method(D_METHOD("_translation_add"), &ProjectSettings::_translation_add); - ClassDB::bind_method(D_METHOD("_translation_file_open"), &ProjectSettings::_translation_file_open); - - ClassDB::bind_method(D_METHOD("_translation_res_add"), &ProjectSettings::_translation_res_add); - ClassDB::bind_method(D_METHOD("_translation_res_file_open"), &ProjectSettings::_translation_res_file_open); - ClassDB::bind_method(D_METHOD("_translation_res_option_add"), &ProjectSettings::_translation_res_option_add); - ClassDB::bind_method(D_METHOD("_translation_res_option_file_open"), &ProjectSettings::_translation_res_option_file_open); - ClassDB::bind_method(D_METHOD("_translation_res_select"), &ProjectSettings::_translation_res_select); - ClassDB::bind_method(D_METHOD("_translation_res_option_changed"), &ProjectSettings::_translation_res_option_changed); - ClassDB::bind_method(D_METHOD("_translation_res_delete"), &ProjectSettings::_translation_res_delete); - ClassDB::bind_method(D_METHOD("_translation_res_option_delete"), &ProjectSettings::_translation_res_option_delete); - - ClassDB::bind_method(D_METHOD("_clear_search_box"), &ProjectSettings::_clear_search_box); - ClassDB::bind_method(D_METHOD("_toggle_search_bar"), &ProjectSettings::_toggle_search_bar); +void ProjectSettingsEditor::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_item_selected"), &ProjectSettingsEditor::_item_selected); + ClassDB::bind_method(D_METHOD("_item_add"), &ProjectSettingsEditor::_item_add); + ClassDB::bind_method(D_METHOD("_item_adds"), &ProjectSettingsEditor::_item_adds); + ClassDB::bind_method(D_METHOD("_item_del"), &ProjectSettingsEditor::_item_del); + ClassDB::bind_method(D_METHOD("_item_checked"), &ProjectSettingsEditor::_item_checked); + ClassDB::bind_method(D_METHOD("_save"), &ProjectSettingsEditor::_save); + ClassDB::bind_method(D_METHOD("_action_add"), &ProjectSettingsEditor::_action_add); + ClassDB::bind_method(D_METHOD("_action_adds"), &ProjectSettingsEditor::_action_adds); + ClassDB::bind_method(D_METHOD("_action_selected"), &ProjectSettingsEditor::_action_selected); + ClassDB::bind_method(D_METHOD("_action_edited"), &ProjectSettingsEditor::_action_edited); + ClassDB::bind_method(D_METHOD("_action_activated"), &ProjectSettingsEditor::_action_activated); + ClassDB::bind_method(D_METHOD("_action_button_pressed"), &ProjectSettingsEditor::_action_button_pressed); + ClassDB::bind_method(D_METHOD("_update_actions"), &ProjectSettingsEditor::_update_actions); + ClassDB::bind_method(D_METHOD("_wait_for_key"), &ProjectSettingsEditor::_wait_for_key); + ClassDB::bind_method(D_METHOD("_add_item"), &ProjectSettingsEditor::_add_item, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("_device_input_add"), &ProjectSettingsEditor::_device_input_add); + ClassDB::bind_method(D_METHOD("_press_a_key_confirm"), &ProjectSettingsEditor::_press_a_key_confirm); + ClassDB::bind_method(D_METHOD("_settings_prop_edited"), &ProjectSettingsEditor::_settings_prop_edited); + ClassDB::bind_method(D_METHOD("_copy_to_platform"), &ProjectSettingsEditor::_copy_to_platform); + ClassDB::bind_method(D_METHOD("_update_translations"), &ProjectSettingsEditor::_update_translations); + ClassDB::bind_method(D_METHOD("_translation_delete"), &ProjectSettingsEditor::_translation_delete); + ClassDB::bind_method(D_METHOD("_settings_changed"), &ProjectSettingsEditor::_settings_changed); + ClassDB::bind_method(D_METHOD("_translation_add"), &ProjectSettingsEditor::_translation_add); + ClassDB::bind_method(D_METHOD("_translation_file_open"), &ProjectSettingsEditor::_translation_file_open); + + ClassDB::bind_method(D_METHOD("_translation_res_add"), &ProjectSettingsEditor::_translation_res_add); + ClassDB::bind_method(D_METHOD("_translation_res_file_open"), &ProjectSettingsEditor::_translation_res_file_open); + ClassDB::bind_method(D_METHOD("_translation_res_option_add"), &ProjectSettingsEditor::_translation_res_option_add); + ClassDB::bind_method(D_METHOD("_translation_res_option_file_open"), &ProjectSettingsEditor::_translation_res_option_file_open); + ClassDB::bind_method(D_METHOD("_translation_res_select"), &ProjectSettingsEditor::_translation_res_select); + ClassDB::bind_method(D_METHOD("_translation_res_option_changed"), &ProjectSettingsEditor::_translation_res_option_changed); + ClassDB::bind_method(D_METHOD("_translation_res_delete"), &ProjectSettingsEditor::_translation_res_delete); + ClassDB::bind_method(D_METHOD("_translation_res_option_delete"), &ProjectSettingsEditor::_translation_res_option_delete); + + ClassDB::bind_method(D_METHOD("_clear_search_box"), &ProjectSettingsEditor::_clear_search_box); + ClassDB::bind_method(D_METHOD("_toggle_search_bar"), &ProjectSettingsEditor::_toggle_search_bar); + + ClassDB::bind_method(D_METHOD("_copy_to_platform_about_to_show"), &ProjectSettingsEditor::_copy_to_platform_about_to_show); } -ProjectSettings::ProjectSettings(EditorData *p_data) { +ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { singleton = this; set_title(TTR("Project Settings (project.godot)")); @@ -1388,11 +1456,6 @@ ProjectSettings::ProjectSettings(EditorData *p_data) { add->set_text(TTR("Add")); add->connect("pressed", this, "_item_add"); - Button *del = memnew(Button); - add_prop_bar->add_child(del); - del->set_text(TTR("Del")); - del->connect("pressed", this, "_item_del"); - search_bar = memnew(HBoxContainer); search_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL); hbc->add_child(search_bar); @@ -1409,6 +1472,7 @@ ProjectSettings::ProjectSettings(EditorData *p_data) { globals_editor = memnew(SectionedPropertyEditor); props_base->add_child(globals_editor); globals_editor->get_property_editor()->set_undo_redo(EditorNode::get_singleton()->get_undo_redo()); + globals_editor->get_property_editor()->set_property_selectable(true); //globals_editor->hide_top_label(); globals_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); globals_editor->register_search_box(search_box); @@ -1430,15 +1494,17 @@ ProjectSettings::ProjectSettings(EditorData *p_data) { save->connect("pressed",this,"_save"); */ - hbc = memnew(HBoxContainer); - props_base->add_child(hbc); + Button *del = memnew(Button); + hbc->add_child(del); + del->set_text(TTR("Delete")); + del->connect("pressed", this, "_item_del"); - popup_platform = memnew(MenuButton); - popup_platform->set_text(TTR("Copy To Platform..")); - popup_platform->set_disabled(true); - hbc->add_child(popup_platform); + add_prop_bar->add_child(memnew(VSeparator)); - hbc->add_spacer(); + popup_copy_to_feature = memnew(MenuButton); + popup_copy_to_feature->set_text(TTR("Override For..")); + popup_copy_to_feature->set_disabled(true); + add_prop_bar->add_child(popup_copy_to_feature); /*List<StringName> ep; EditorImportExport::get_singleton()->get_export_platforms(&ep); @@ -1446,11 +1512,13 @@ ProjectSettings::ProjectSettings(EditorData *p_data) { for(List<StringName>::Element *E=ep.front();E;E=E->next()) { - popup_platform->get_popup()->add_item( E->get() ); + popup_copy_to_feature->get_popup()->add_item( E->get() ); }*/ - popup_platform->get_popup()->connect("id_pressed", this, "_copy_to_platform"); + popup_copy_to_feature->get_popup()->connect("id_pressed", this, "_copy_to_platform"); + popup_copy_to_feature->get_popup()->connect("about_to_show", this, "_copy_to_platform_about_to_show"); + get_ok()->set_text(TTR("Close")); set_hide_on_ok(true); @@ -1665,7 +1733,7 @@ ProjectSettings::ProjectSettings(EditorData *p_data) { timer = memnew(Timer); timer->set_wait_time(1.5); - timer->connect("timeout", GlobalConfig::get_singleton(), "save"); + timer->connect("timeout", ProjectSettings::get_singleton(), "save"); timer->set_one_shot(true); add_child(timer); diff --git a/editor/project_settings.h b/editor/project_settings_editor.h index 03140a854b..4390a23d60 100644 --- a/editor/project_settings.h +++ b/editor/project_settings_editor.h @@ -40,8 +40,8 @@ //#include "project_export_settings.h" -class ProjectSettings : public AcceptDialog { - GDCLASS(ProjectSettings, AcceptDialog); +class ProjectSettingsEditor : public AcceptDialog { + GDCLASS(ProjectSettingsEditor, AcceptDialog); enum InputType { INPUT_KEY, @@ -78,7 +78,7 @@ class ProjectSettings : public AcceptDialog { SpinBox *device_id; OptionButton *device_index; Label *device_index_label; - MenuButton *popup_platform; + MenuButton *popup_copy_to_feature; LineEdit *action_name; Tree *input_editor; @@ -145,9 +145,11 @@ class ProjectSettings : public AcceptDialog { void _toggle_search_bar(bool p_pressed); void _clear_search_box(); - ProjectSettings(); + void _copy_to_platform_about_to_show(); - static ProjectSettings *singleton; + ProjectSettingsEditor(); + + static ProjectSettingsEditor *singleton; protected: void _notification(int p_what); @@ -155,13 +157,13 @@ protected: public: void add_translation(const String &p_translation); - static ProjectSettings *get_singleton() { return singleton; } + static ProjectSettingsEditor *get_singleton() { return singleton; } void popup_project_settings(); void set_plugins_page(); void queue_save(); - ProjectSettings(EditorData *p_data); + ProjectSettingsEditor(EditorData *p_data); }; #endif // PROJECT_SETTINGS_H diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 31be4e1818..c2af2445cc 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -37,8 +37,6 @@ #include "editor_help.h" #include "editor_node.h" #include "editor_settings.h" -#include "global_config.h" -#include "global_config.h" #include "io/image_loader.h" #include "io/resource_loader.h" #include "multi_node_edit.h" @@ -46,6 +44,8 @@ #include "os/keyboard.h" #include "pair.h" #include "print_string.h" +#include "project_settings.h" +#include "project_settings.h" #include "property_selector.h" #include "scene/gui/label.h" #include "scene/main/viewport.h" @@ -415,7 +415,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: int idx = i * 10 + j; CheckBox *c = checks20[idx]; - c->set_text(GlobalConfig::get_singleton()->get(basename + "/layer_" + itos(idx + 1))); + c->set_text(ProjectSettings::get_singleton()->get(basename + "/layer_" + itos(idx + 1))); c->set_pressed(flgs & (1 << (i * 10 + j))); c->show(); } @@ -1019,7 +1019,7 @@ void CustomPropertyEditor::_file_selected(String p_file) { if (hint == PROPERTY_HINT_FILE || hint == PROPERTY_HINT_DIR) { - v = GlobalConfig::get_singleton()->localize_path(p_file); + v = ProjectSettings::get_singleton()->localize_path(p_file); emit_signal("variant_changed"); hide(); } @@ -3002,8 +3002,18 @@ void PropertyEditor::update_tree() { String name = (basename.find("/") != -1) ? basename.right(basename.find_last("/") + 1) : basename; - if (capitalize_paths) - name = name.camelcase_to_underscore().capitalize(); + if (capitalize_paths) { + int dot = name.find("."); + if (dot != -1) { + String ov = name.right(dot); + name = name.substr(0, dot); + name = name.camelcase_to_underscore().capitalize(); + name += ov; + + } else { + name = name.camelcase_to_underscore().capitalize(); + } + } String path = basename.left(basename.find_last("/")); @@ -3046,7 +3056,7 @@ void PropertyEditor::update_tree() { //item->set_custom_bg_color(1,col); } item->set_editable(0, false); - item->set_selectable(0, false); + item->set_selectable(0, property_selectable); if (p.usage & PROPERTY_USAGE_CHECKABLE) { @@ -3059,6 +3069,18 @@ void PropertyEditor::update_tree() { item->set_text(0, name); item->set_tooltip(0, p.name); + if (name.find(".") != -1) { + Color textcol = get_color("font_color", "Tree"); + textcol.a *= 0.5; + //override :D + item->set_custom_color(0, textcol); + item->set_custom_color(1, textcol); + + Color iconcol(1, 1, 1, 0.6); + item->set_icon_color(0, iconcol); + item->set_icon_color(1, iconcol); + } + if (use_doc_hints) { StringName setter; StringName type; @@ -4308,6 +4330,11 @@ void PropertyEditor::register_text_enter(Node *p_line_edit) { search_box->connect("text_changed", this, "_filter_changed"); } +void PropertyEditor::set_property_selectable(bool p_selectable) { + property_selectable = p_selectable; + update_tree(); +} + void PropertyEditor::set_subsection_selectable(bool p_selectable) { if (p_selectable == subsection_selectable) @@ -4394,6 +4421,7 @@ PropertyEditor::PropertyEditor() { updating_folding = true; use_filter = false; subsection_selectable = false; + property_selectable = false; show_type_icons = EDITOR_DEF("interface/show_type_icons", false); } @@ -4647,6 +4675,8 @@ void SectionedPropertyEditor::update_category_list() { if (section_map.has(selected_category)) { section_map[selected_category]->select(0); } + + editor->update_tree(); } void SectionedPropertyEditor::register_search_box(LineEdit *p_box) { diff --git a/editor/property_editor.h b/editor/property_editor.h index 1ae44e473b..273eff371e 100644 --- a/editor/property_editor.h +++ b/editor/property_editor.h @@ -191,6 +191,7 @@ class PropertyEditor : public Control { bool subsection_selectable; bool hide_script; bool use_folding; + bool property_selectable; bool updating_folding; @@ -288,6 +289,7 @@ public: void register_text_enter(Node *p_line_edit); void set_subsection_selectable(bool p_selectable); + void set_property_selectable(bool p_selectable); void set_use_folding(bool p_enable); PropertyEditor(); diff --git a/editor/resources_dock.cpp b/editor/resources_dock.cpp index ddecfd108f..d3b68d92e4 100644 --- a/editor/resources_dock.cpp +++ b/editor/resources_dock.cpp @@ -32,10 +32,10 @@ #include "editor_file_system.h" #include "editor_node.h" #include "editor_settings.h" -#include "global_config.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "project_settings.h" +#include "project_settings_editor.h" void ResourcesDock::_tool_selected(int p_tool) { @@ -124,7 +124,7 @@ void ResourcesDock::save_resource(const String &p_path, const Ref<Resource> &p_r flg|=ResourceSaver::FLAG_RELATIVE_PATHS; */ - String path = GlobalConfig::get_singleton()->localize_path(p_path); + String path = ProjectSettings::get_singleton()->localize_path(p_path); Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS); if (err != OK) { diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index cdae9baaf2..57ab931827 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -37,7 +37,7 @@ #include "editor/plugins/spatial_editor_plugin.h" #include "editor_node.h" #include "editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "multi_node_edit.h" #include "os/keyboard.h" #include "scene/main/viewport.h" @@ -183,7 +183,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node } } - instanced_scene->set_filename(GlobalConfig::get_singleton()->localize_path(p_files[i])); + instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(p_files[i])); instances.push_back(instanced_scene); } @@ -786,7 +786,7 @@ void SceneTreeDock::_notification(int p_what) { button_create_script->set_icon(get_icon("ScriptCreate", "EditorIcons")); button_clear_script->set_icon(get_icon("ScriptRemove", "EditorIcons")); - filter_icon->set_texture(get_icon("Search", "EditorIcons")); + filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", this, "_selection_changed"); @@ -2021,11 +2021,8 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel vbc->add_child(filter_hbc); filter = memnew(LineEdit); filter->set_h_size_flags(SIZE_EXPAND_FILL); + filter->set_placeholder(TTR("Filter nodes")); filter_hbc->add_child(filter); - filter_icon = memnew(TextureRect); - filter_icon->set_custom_minimum_size(Size2(24 * EDSCALE, 0)); - filter_hbc->add_child(filter_icon); - filter_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); filter->connect("text_changed", this, "_filter_changed"); tb = memnew(ToolButton); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 4a9b64639b..c3a3410717 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -31,7 +31,7 @@ #include "editor/editor_scale.h" #include "editor_file_system.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_saver.h" #include "os/file_access.h" #include "script_language.h" @@ -167,7 +167,7 @@ void ScriptCreateDialog::_create_new() { scr->set_name(cname); if (!is_built_in) { - String lpath = GlobalConfig::get_singleton()->localize_path(file_path->get_text()); + String lpath = ProjectSettings::get_singleton()->localize_path(file_path->get_text()); scr->set_path(lpath); Error err = ResourceSaver::save(lpath, scr, ResourceSaver::FLAG_CHANGE_PATH); if (err != OK) { @@ -305,7 +305,7 @@ void ScriptCreateDialog::_browse_path(bool browse_parent) { void ScriptCreateDialog::_file_selected(const String &p_file) { - String p = GlobalConfig::get_singleton()->localize_path(p_file); + String p = ProjectSettings::get_singleton()->localize_path(p_file); if (is_browsing_parent) { parent_name->set_text("\"" + p + "\""); _class_name_changed("\"" + p + "\""); @@ -327,7 +327,7 @@ void ScriptCreateDialog::_path_changed(const String &p_path) { return; } - p = GlobalConfig::get_singleton()->localize_path(p); + p = ProjectSettings::get_singleton()->localize_path(p); if (!p.begins_with("res://")) { _msg_path_valid(false, TTR("Path is not local")); _update_dialog(); diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 9dce48937c..2af3bd5f31 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -32,7 +32,7 @@ #include "editor_node.h" #include "editor_profiler.h" #include "editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "main/performance.h" #include "property_editor.h" #include "scene/gui/dialogs.h" @@ -1625,24 +1625,24 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { hbc->add_child(memnew(VSeparator)); - step = memnew(Button); + step = memnew(ToolButton); hbc->add_child(step); step->set_tooltip(TTR("Step Into")); step->connect("pressed", this, "debug_step"); - next = memnew(Button); + next = memnew(ToolButton); hbc->add_child(next); next->set_tooltip(TTR("Step Over")); next->connect("pressed", this, "debug_next"); hbc->add_child(memnew(VSeparator)); - dobreak = memnew(Button); + dobreak = memnew(ToolButton); hbc->add_child(dobreak); dobreak->set_tooltip(TTR("Break")); dobreak->connect("pressed", this, "debug_break"); - docontinue = memnew(Button); + docontinue = memnew(ToolButton); hbc->add_child(docontinue); docontinue->set_tooltip(TTR("Continue")); docontinue->connect("pressed", this, "debug_continue"); @@ -1816,7 +1816,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { vmem_total->set_editable(false); vmem_total->set_custom_minimum_size(Size2(100, 1) * EDSCALE); vmem_hb->add_child(vmem_total); - vmem_refresh = memnew(Button); + vmem_refresh = memnew(ToolButton); vmem_hb->add_child(vmem_refresh); vmem_vb->add_child(vmem_hb); vmem_refresh->connect("pressed", this, "_video_mem_request"); @@ -1849,30 +1849,31 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { } { // misc - VBoxContainer *info_left = memnew(VBoxContainer); - info_left->set_h_size_flags(SIZE_EXPAND_FILL); + GridContainer *info_left = memnew(GridContainer); + info_left->set_columns(2); info_left->set_name(TTR("Misc")); tabs->add_child(info_left); clicked_ctrl = memnew(LineEdit); - info_left->add_margin_child(TTR("Clicked Control:"), clicked_ctrl); + clicked_ctrl->set_h_size_flags(SIZE_EXPAND_FILL); + info_left->add_child(memnew(Label(TTR("Clicked Control:")))); + info_left->add_child(clicked_ctrl); clicked_ctrl_type = memnew(LineEdit); - info_left->add_margin_child(TTR("Clicked Control Type:"), clicked_ctrl_type); + info_left->add_child(memnew(Label(TTR("Clicked Control Type:")))); + info_left->add_child(clicked_ctrl_type); live_edit_root = memnew(LineEdit); + live_edit_root->set_h_size_flags(SIZE_EXPAND_FILL); { HBoxContainer *lehb = memnew(HBoxContainer); Label *l = memnew(Label(TTR("Live Edit Root:"))); - lehb->add_child(l); - l->set_h_size_flags(SIZE_EXPAND_FILL); + info_left->add_child(l); + lehb->add_child(live_edit_root); le_set = memnew(Button(TTR("Set From Tree"))); lehb->add_child(le_set); le_clear = memnew(Button(TTR("Clear"))); lehb->add_child(le_clear); info_left->add_child(lehb); - MarginContainer *mc = memnew(MarginContainer); - mc->add_child(live_edit_root); - info_left->add_child(mc); le_set->set_disabled(true); le_clear->set_disabled(true); } diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp index 6c64f3af42..eec047cd9a 100644 --- a/editor/settings_config_dialog.cpp +++ b/editor/settings_config_dialog.cpp @@ -32,7 +32,7 @@ #include "editor_file_system.h" #include "editor_node.h" #include "editor_settings.h" -#include "global_config.h" +#include "project_settings.h" #include "os/keyboard.h" #include "scene/gui/margin_container.h" diff --git a/main/main.cpp b/main/main.cpp index ece54e7427..8960d85c45 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -31,10 +31,10 @@ #include "app_icon.gen.h" #include "core/register_core_types.h" #include "drivers/register_driver_types.h" -#include "global_config.h" #include "message_queue.h" #include "modules/register_module_types.h" #include "os/os.h" +#include "project_settings.h" #include "scene/register_scene_types.h" #include "script_debugger_local.h" #include "script_debugger_remote.h" @@ -74,7 +74,7 @@ #include "translation.h" #include "version.h" -static GlobalConfig *globals = NULL; +static ProjectSettings *globals = NULL; static Engine *engine = NULL; static InputMap *input_map = NULL; static bool _start_success = false; @@ -205,14 +205,14 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph Thread::_main_thread_id = Thread::get_caller_ID(); - globals = memnew(GlobalConfig); + globals = memnew(ProjectSettings); input_map = memnew(InputMap); register_core_settings(); //here globals is present translation_server = memnew(TranslationServer); performance = memnew(Performance); - globals->add_singleton(GlobalConfig::Singleton("Performance", performance)); + globals->add_singleton(ProjectSettings::Singleton("Performance", performance)); MAIN_PRINT("Main: Parse CMDLine"); @@ -529,7 +529,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph if (I->next()) { - GlobalConfig::get_singleton()->set("editor_scene", game_path = I->next()->get()); + ProjectSettings::get_singleton()->set("editor_scene", game_path = I->next()->get()); } else { goto error; } @@ -551,7 +551,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph if (I->next()) { int editor_pid = I->next()->get().to_int(); - GlobalConfig::get_singleton()->set("editor_pid", editor_pid); + ProjectSettings::get_singleton()->set("editor_pid", editor_pid); N = I->next()->next(); } else { goto error; @@ -642,7 +642,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph #ifdef TOOLS_ENABLED if (editor) { packed_data->set_disabled(true); - globals->set_disable_platform_override(true); + globals->set_disable_feature_overrides(true); StreamPeerSSL::initialize_certs = false; //will be initialized by editor } @@ -665,10 +665,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph use_custom_res = false; } - if (bool(GlobalConfig::get_singleton()->get("application/run/disable_stdout"))) { + if (bool(ProjectSettings::get_singleton()->get("application/run/disable_stdout"))) { quiet_stdout = true; } - if (bool(GlobalConfig::get_singleton()->get("application/run/disable_stderr"))) { + if (bool(ProjectSettings::get_singleton()->get("application/run/disable_stderr"))) { _print_error_enabled = false; }; @@ -679,7 +679,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph #ifdef TOOLS_ENABLED - if (main_args.size() == 0 && (!GlobalConfig::get_singleton()->has("application/run/main_loop_type")) && (!GlobalConfig::get_singleton()->has("application/main_scene") || String(GlobalConfig::get_singleton()->get("application/main_scene")) == "")) + if (main_args.size() == 0 && (!ProjectSettings::get_singleton()->has("application/run/main_loop_type")) && (!ProjectSettings::get_singleton()->has("application/run/main_scene") || String(ProjectSettings::get_singleton()->get("application/run/main_scene")) == "")) use_custom_res = false; //project manager (run without arguments) #endif @@ -724,6 +724,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph use_vsync = GLOBAL_DEF("display/window/vsync/use_vsync", use_vsync); GLOBAL_DEF("display/window/size/test_width", 0); GLOBAL_DEF("display/window/size/test_height", 0); + GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation", 2); + GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation.mobile", 3); + Engine::get_singleton()->_pixel_snap = GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false); OS::get_singleton()->_keep_screen_on = GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true); if (rtm == -1) { @@ -812,7 +815,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph message_queue = memnew(MessageQueue); - GlobalConfig::get_singleton()->register_global_defaults(); + ProjectSettings::get_singleton()->register_global_defaults(); if (p_second_phase) return setup2(); @@ -913,7 +916,7 @@ Error Main::setup2() { if (show_logo) { //boot logo! String boot_logo_path = GLOBAL_DEF("application/boot_splash/image", String()); bool boot_logo_scale = GLOBAL_DEF("application/boot_splash/fullsize", true); - GlobalConfig::get_singleton()->set_custom_property_info("application/boot_splash/image", PropertyInfo(Variant::STRING, "application/boot_splash/image", PROPERTY_HINT_FILE, "*.png")); + ProjectSettings::get_singleton()->set_custom_property_info("application/boot_splash/image", PropertyInfo(Variant::STRING, "application/boot_splash/image", PROPERTY_HINT_FILE, "*.png")); Ref<Image> boot_logo; @@ -933,7 +936,7 @@ Error Main::setup2() { VisualServer::get_singleton()->set_boot_image(boot_logo, boot_bg, boot_logo_scale); #ifndef TOOLS_ENABLED //no tools, so free the boot logo (no longer needed) -//GlobalConfig::get_singleton()->set("application/boot_logo",Image()); +//ProjectSettings::get_singleton()->set("application/boot_logo",Image()); #endif } else { @@ -958,7 +961,7 @@ Error Main::setup2() { MAIN_PRINT("Main: END"); GLOBAL_DEF("application/config/icon", String()); - GlobalConfig::get_singleton()->set_custom_property_info("application/config/icon", PropertyInfo(Variant::STRING, "application/config/icon", PROPERTY_HINT_FILE, "*.png,*.webp")); + ProjectSettings::get_singleton()->set_custom_property_info("application/config/icon", PropertyInfo(Variant::STRING, "application/config/icon", PROPERTY_HINT_FILE, "*.png,*.webp")); if (bool(GLOBAL_DEF("display/window/handheld/emulate_touchscreen", false))) { if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton() && !editor) { @@ -977,15 +980,15 @@ Error Main::setup2() { GLOBAL_DEF("display/mouse_cursor/custom_image", String()); GLOBAL_DEF("display/mouse_cursor/custom_image_hotspot", Vector2()); - GlobalConfig::get_singleton()->set_custom_property_info("display/mouse_cursor/custom_image", PropertyInfo(Variant::STRING, "display/mouse_cursor/custom_image", PROPERTY_HINT_FILE, "*.png,*.webp")); + ProjectSettings::get_singleton()->set_custom_property_info("display/mouse_cursor/custom_image", PropertyInfo(Variant::STRING, "display/mouse_cursor/custom_image", PROPERTY_HINT_FILE, "*.png,*.webp")); - if (String(GlobalConfig::get_singleton()->get("display/mouse_cursor/custom_image")) != String()) { + if (String(ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image")) != String()) { //print_line("use custom cursor"); - Ref<Texture> cursor = ResourceLoader::load(GlobalConfig::get_singleton()->get("display/mouse_cursor/custom_image")); + Ref<Texture> cursor = ResourceLoader::load(ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image")); if (cursor.is_valid()) { //print_line("loaded ok"); - Vector2 hotspot = GlobalConfig::get_singleton()->get("display/mouse_cursor/custom_image_hotspot"); + Vector2 hotspot = ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image_hotspot"); Input::get_singleton()->set_custom_mouse_cursor(cursor, hotspot); } } @@ -1257,6 +1260,7 @@ bool Main::start() { String stretch_mode = GLOBAL_DEF("display/window/stretch/mode", "disabled"); String stretch_aspect = GLOBAL_DEF("display/window/stretch/aspect", "ignore"); Size2i stretch_size = Size2(GLOBAL_DEF("display/window/size/width", 0), GLOBAL_DEF("display/window/size/height", 0)); + int stretch_shrink = GLOBAL_DEF("display/window/stretch/shrink", 1); SceneTree::StretchMode sml_sm = SceneTree::STRETCH_MODE_DISABLED; if (stretch_mode == "2d") @@ -1272,11 +1276,11 @@ bool Main::start() { else if (stretch_aspect == "keep_height") sml_aspect = SceneTree::STRETCH_ASPECT_KEEP_HEIGHT; - sml->set_screen_stretch(sml_sm, sml_aspect, stretch_size); + sml->set_screen_stretch(sml_sm, sml_aspect, stretch_size, stretch_shrink); sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true)); sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true)); - String appname = GlobalConfig::get_singleton()->get("application/config/name"); + String appname = ProjectSettings::get_singleton()->get("application/config/name"); appname = TranslationServer::get_singleton()->translate(appname); OS::get_singleton()->set_window_title(appname); @@ -1291,12 +1295,16 @@ bool Main::start() { sml->get_root()->set_shadow_atlas_quadrant_subdiv(1, Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q1_subdiv)); sml->get_root()->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q2_subdiv)); sml->get_root()->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q3_subdiv)); + Viewport::Usage usage = Viewport::Usage(int(GLOBAL_GET("rendering/quality/intended_usage/framebuffer_allocation"))); + sml->get_root()->set_usage(usage); } else { GLOBAL_DEF("display/window/stretch/mode", "disabled"); - GlobalConfig::get_singleton()->set_custom_property_info("display/window/stretch/mode", PropertyInfo(Variant::STRING, "display/window/stretch/mode", PROPERTY_HINT_ENUM, "disabled,2d,viewport")); + ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/mode", PropertyInfo(Variant::STRING, "display/window/stretch/mode", PROPERTY_HINT_ENUM, "disabled,2d,viewport")); GLOBAL_DEF("display/window/stretch/aspect", "ignore"); - GlobalConfig::get_singleton()->set_custom_property_info("display/window/stretch/aspect", PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height")); + ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/aspect", PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height")); + GLOBAL_DEF("display/window/stretch/shrink", 1); + ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/shrink", PropertyInfo(Variant::STRING, "display/window/stretch/shrink", PROPERTY_HINT_RANGE, "1,8,1")); sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true)); sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true)); } @@ -1311,7 +1319,7 @@ bool Main::start() { if (!absolute) { - if (GlobalConfig::get_singleton()->is_using_datapack()) { + if (ProjectSettings::get_singleton()->is_using_datapack()) { local_game_path = "res://" + local_game_path; @@ -1334,7 +1342,7 @@ bool Main::start() { } } - local_game_path = GlobalConfig::get_singleton()->localize_path(local_game_path); + local_game_path = ProjectSettings::get_singleton()->localize_path(local_game_path); #ifdef TOOLS_ENABLED if (editor) { @@ -1360,7 +1368,7 @@ bool Main::start() { if (game_path != "" || script != "") { //autoload List<PropertyInfo> props; - GlobalConfig::get_singleton()->get_property_list(&props); + ProjectSettings::get_singleton()->get_property_list(&props); //first pass, add the constants so they exist before any script is loaded for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { @@ -1369,7 +1377,7 @@ bool Main::start() { if (!s.begins_with("autoload/")) continue; String name = s.get_slicec('/', 1); - String path = GlobalConfig::get_singleton()->get(s); + String path = ProjectSettings::get_singleton()->get(s); bool global_var = false; if (path.begins_with("*")) { global_var = true; @@ -1390,7 +1398,7 @@ bool Main::start() { if (!s.begins_with("autoload/")) continue; String name = s.get_slicec('/', 1); - String path = GlobalConfig::get_singleton()->get(s); + String path = ProjectSettings::get_singleton()->get(s); bool global_var = false; if (path.begins_with("*")) { global_var = true; @@ -1689,14 +1697,16 @@ void Main::cleanup() { OS::get_singleton()->_execpath = ""; OS::get_singleton()->_local_clipboard = ""; - if (audio_server) { - memdelete(audio_server); - } + ScriptServer::finish_languages(); #ifdef TOOLS_ENABLED EditorNode::unregister_editor_types(); #endif + if (audio_server) { + memdelete(audio_server); + } + unregister_driver_types(); unregister_module_types(); unregister_scene_types(); diff --git a/main/tests/test_io.cpp b/main/tests/test_io.cpp index 6986576081..f7c49c9249 100644 --- a/main/tests/test_io.cpp +++ b/main/tests/test_io.cpp @@ -31,7 +31,7 @@ #ifdef MINIZIP_ENABLED -#include "core/global_config.h" +#include "core/project_settings.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "os/dir_access.h" @@ -91,10 +91,10 @@ MainLoop *test() { ResourceSaver::save("test_data/rock.xml", texture); print_line("localize paths"); - print_line(GlobalConfig::get_singleton()->localize_path("algo.xml")); - print_line(GlobalConfig::get_singleton()->localize_path("c:\\windows\\algo.xml")); - print_line(GlobalConfig::get_singleton()->localize_path(GlobalConfig::get_singleton()->get_resource_path() + "/something/something.xml")); - print_line(GlobalConfig::get_singleton()->localize_path("somedir/algo.xml")); + print_line(ProjectSettings::get_singleton()->localize_path("algo.xml")); + print_line(ProjectSettings::get_singleton()->localize_path("c:\\windows\\algo.xml")); + print_line(ProjectSettings::get_singleton()->localize_path(ProjectSettings::get_singleton()->get_resource_path() + "/something/something.xml")); + print_line(ProjectSettings::get_singleton()->localize_path("somedir/algo.xml")); { diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index dad9a54df6..e810c33f1c 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -29,732 +29,70 @@ /*************************************************************************/ #include "gdnative.h" -#include "global_config.h" #include "global_constants.h" #include "io/file_access_encrypted.h" #include "os/file_access.h" #include "os/os.h" +#include "project_settings.h" #include "scene/main/scene_tree.h" -#include "scene/resources/scene_format_text.h" -#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) -#include "api_generator.h" -#endif - -#ifdef TOOLS_ENABLED -#include "editor/editor_node.h" -#endif - -Error NativeLibrary::initialize(NativeLibrary *&p_native_lib, const StringName p_path) { - - if (GDNativeScriptLanguage::get_singleton()->initialized_libraries.has(p_path)) { - p_native_lib = GDNativeScriptLanguage::get_singleton()->initialized_libraries[p_path]; - return OK; - } - - NativeLibrary *lib = memnew(NativeLibrary); - lib->path = p_path; - - p_native_lib = lib; - - // Open the file - - Error error; - error = OS::get_singleton()->open_dynamic_library(p_path, lib->handle); - if (error) return error; - ERR_FAIL_COND_V(!lib->handle, ERR_BUG); - - // Get the method - - void *library_init; - error = OS::get_singleton()->get_dynamic_library_symbol_handle(lib->handle, GDNativeScriptLanguage::get_init_symbol_name(), library_init); - if (error) return error; - ERR_FAIL_COND_V(!library_init, ERR_BUG); - - void (*library_init_fpointer)(godot_native_init_options *) = (void (*)(godot_native_init_options *))library_init; - - godot_native_init_options options; - - options.in_editor = SceneTree::get_singleton()->is_editor_hint(); - options.core_api_hash = ClassDB::get_api_hash(ClassDB::API_CORE); - options.editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR); - options.no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE); - - library_init_fpointer(&options); // Catch errors? - - GDNativeScriptLanguage::get_singleton()->initialized_libraries[p_path] = lib; - - return OK; -} - -Error NativeLibrary::terminate(NativeLibrary *&p_native_lib) { - - if (!GDNativeScriptLanguage::get_singleton()->initialized_libraries.has(p_native_lib->path)) { - OS::get_singleton()->close_dynamic_library(p_native_lib->handle); - p_native_lib->handle = 0; - return OK; - } - - Error error = OK; - void *library_terminate; - error = OS::get_singleton()->get_dynamic_library_symbol_handle(p_native_lib->handle, GDNativeScriptLanguage::get_terminate_symbol_name(), library_terminate); - if (!error) { - - void (*library_terminate_pointer)(godot_native_terminate_options *) = (void (*)(godot_native_terminate_options *))library_terminate; - - godot_native_terminate_options options; - options.in_editor = SceneTree::get_singleton()->is_editor_hint(); - - library_terminate_pointer(&options); - } - - GDNativeScriptLanguage::get_singleton()->initialized_libraries.erase(p_native_lib->path); - - OS::get_singleton()->close_dynamic_library(p_native_lib->handle); - p_native_lib->handle = 0; - - return OK; -} - -// Script -#ifdef TOOLS_ENABLED - -void GDNativeScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) { - ERR_FAIL_COND(!script_data); - - List<PropertyInfo> pinfo; - Map<StringName, Variant> values; - - for (Map<StringName, GDNativeScriptData::Property>::Element *E = script_data->properties.front(); E; E = E->next()) { - PropertyInfo p = E->get().info; - p.name = String(E->key()); - pinfo.push_back(p); - values[p.name] = E->get().default_value; - } - - p_placeholder->update(pinfo, values); -} - -void GDNativeScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { - - placeholders.erase(p_placeholder); -} - -#endif - -bool GDNativeScript::can_instance() const { -#ifdef TOOLS_ENABLED - return script_data || (!is_tool() && !ScriptServer::is_scripting_enabled()); -#else - // allow defaultlibrary without editor features - if (!library.is_valid()) { - String path = GLOBAL_GET("gdnative/default_gdnativelibrary"); - - RES lib = ResourceLoader::load(path); - - if (lib.is_valid() && lib->cast_to<GDNativeLibrary>()) { - return true; - } - } +const String init_symbol = "godot_gdnative_init"; +const String terminate_symbol = "godot_gdnative_terminate"; - return script_data; -#endif - //return script_data || (!tool && !ScriptServer::is_scripting_enabled()); - // change to true enable in editor stuff. -} - -Ref<Script> GDNativeScript::get_base_script() const { - Ref<GDNativeScript> base_script; - base_script->library = library; - base_script->script_data = script_data; - base_script->script_name = script_data->base; - return base_script; -} - -StringName GDNativeScript::get_instance_base_type() const { - return script_data->base_native_type; -} - -ScriptInstance *GDNativeScript::instance_create(Object *p_this) { - -#ifdef TOOLS_ENABLED - - // find a good way to initialize stuff in the editor - if (!ScriptServer::is_scripting_enabled() && !is_tool()) { - // placeholder, for nodes. But for tools we want the real thing - - PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(GDNativeScriptLanguage::singleton, Ref<Script>((Script *)this), p_this)); - placeholders.insert(sins); - - if (!library.is_valid()) - return sins; - - if (!library->native_library) { - Error err = library->_initialize(); - if (err != OK) { - return sins; - } - } - - if (!script_data) { - script_data = library->get_script_data(script_name); - } - if (script_data && script_data->create_func.create_func) { - script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); - } - - _update_placeholder(sins); - - return sins; - } - -#endif +String GDNativeLibrary::platform_names[NUM_PLATFORMS] = { + "X11_32bit", + "X11_64bit", + "Windows_32bit", + "Windows_64bit", + "OSX", - if (!library.is_valid()) { - String path = GLOBAL_GET("gdnative/default_gdnativelibrary"); + "Android", + "iOS", - RES lib = ResourceLoader::load(path); - - if (lib.is_valid() && lib->cast_to<GDNativeLibrary>()) { - set_library(lib); - } - } + "WebAssembly" +}; +String GDNativeLibrary::platform_lib_ext[NUM_PLATFORMS] = { + "so", + "so", + "dll", + "dll", + "dylib", - GDNativeInstance *new_instance = memnew(GDNativeInstance); + "so", + "dylib", - new_instance->owner = p_this; - new_instance->script = Ref<GDNativeScript>(this); + "wasm" +}; -#ifndef TOOLS_ENABLED - if (!ScriptServer::is_scripting_enabled()) { - new_instance->userdata = 0; - } else { - new_instance->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); - } +// TODO(karroffel): make this actually do the right thing. +GDNativeLibrary::Platform GDNativeLibrary::current_platform = +#if defined(X11_ENABLED) + X11_64BIT; +#elif defined(WINDOWS_ENABLED) + WINDOWS_64BIT; +#elif defined(OSX_ENABLED) + OSX; #else - new_instance->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); + X11_64BIT; // need a sensible default.. #endif - instances.insert(p_this); - return new_instance; -} - -bool GDNativeScript::instance_has(const Object *p_this) const { - return instances.has((Object *)p_this); // TODO -} - -bool GDNativeScript::has_source_code() const { - return false; -} - -String GDNativeScript::get_source_code() const { - return ""; -} - -Error GDNativeScript::reload(bool p_keep_state) { - return FAILED; -} - -bool GDNativeScript::has_method(const StringName &p_method) const { - if (!script_data) - return false; - GDNativeScriptData *data = script_data; - - while (data) { - if (data->methods.has(p_method)) - return true; - - data = data->base_data; - } - - return false; -} - -MethodInfo GDNativeScript::get_method_info(const StringName &p_method) const { - if (!script_data) - return MethodInfo(); - GDNativeScriptData *data = script_data; - - while (data) { - if (data->methods.has(p_method)) - return data->methods[p_method].info; - - data = data->base_data; - } - - ERR_FAIL_COND_V(!script_data->methods.has(p_method), MethodInfo()); - return MethodInfo(); -} - -void GDNativeScript::get_script_method_list(List<MethodInfo> *p_list) const { - if (!script_data) return; - - Set<MethodInfo> methods; - GDNativeScriptData *data = script_data; - - while (data) { - for (Map<StringName, GDNativeScriptData::Method>::Element *E = data->methods.front(); E; E = E->next()) { - methods.insert(E->get().info); - } - data = data->base_data; - } - - for (Set<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - p_list->push_back(E->get()); - } -} - -void GDNativeScript::get_script_property_list(List<PropertyInfo> *p_list) const { - if (!script_data) return; - - Set<PropertyInfo> properties; - GDNativeScriptData *data = script_data; - - while (data) { - for (Map<StringName, GDNativeScriptData::Property>::Element *E = data->properties.front(); E; E = E->next()) { - properties.insert(E->get().info); - } - data = data->base_data; - } - - for (Set<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - p_list->push_back(E->get()); - } -} - -bool GDNativeScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { - if (!script_data) return false; - - GDNativeScriptData *data = script_data; - - while (data) { - if (data->properties.has(p_property)) { - r_value = data->properties[p_property].default_value; - return true; - } - - data = data->base_data; - } - - return false; -} - -bool GDNativeScript::is_tool() const { - ERR_FAIL_COND_V(!script_data, false); - return script_data->is_tool; -} - -String GDNativeScript::get_node_type() const { - return ""; // ? -} - -ScriptLanguage *GDNativeScript::get_language() const { - return GDNativeScriptLanguage::singleton; -} - -bool GDNativeScript::has_script_signal(const StringName &p_signal) const { - if (!script_data) - return false; - - GDNativeScriptData *data = script_data; - - while (data) { - if (data->signals_.has(p_signal)) { - return true; - } - - data = data->base_data; - } - - return false; -} - -void GDNativeScript::get_script_signal_list(List<MethodInfo> *r_signals) const { - if (!script_data) - return; - - Set<MethodInfo> signals_; - GDNativeScriptData *data = script_data; - - while (data) { - - for (Map<StringName, GDNativeScriptData::Signal>::Element *S = data->signals_.front(); S; S = S->next()) { - signals_.insert(S->get().signal); - } - - data = data->base_data; - } - - for (Set<MethodInfo>::Element *E = signals_.front(); E; E = E->next()) { - r_signals->push_back(E->get()); - } -} - -Variant GDNativeScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - - /* STEP 1, CREATE */ - - if (!library.is_valid() || ((String)script_name).empty() || !script_data) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; - return Variant(); - } - - r_error.error = Variant::CallError::CALL_OK; - REF ref; - Object *owner = NULL; - - GDNativeScriptData *_baseptr = script_data; - while (_baseptr->base_data) { - _baseptr = _baseptr->base_data; - } - - if (!(_baseptr->base_native_type == "")) { - owner = ClassDB::instance(_baseptr->base_native_type); - } else { - owner = memnew(Reference); //by default, no base means use reference - } - - Reference *r = owner->cast_to<Reference>(); - if (r) { - ref = REF(r); - } - - // GDScript does it like this: _create_instance(p_args, p_argcount, owner, r != NULL, r_error); - // @Todo support varargs for constructors. - GDNativeInstance *instance = (GDNativeInstance *)instance_create(owner); - - owner->set_script_instance(instance); - if (!instance) { - if (ref.is_null()) { - memdelete(owner); //no owner, sorry - } - return Variant(); - } - - if (ref.is_valid()) { - return ref; - } else { - return owner; - } -} - -Ref<GDNativeLibrary> GDNativeScript::get_library() const { - return library; -} - -void GDNativeScript::set_library(Ref<GDNativeLibrary> p_library) { - library = p_library; - -#ifdef TOOLS_ENABLED - if (!ScriptServer::is_scripting_enabled()) - return; -#endif - if (library.is_valid()) { - Error initalize_status = library->_initialize(); - ERR_FAIL_COND(initalize_status != OK); - if (script_name) { - script_data = library->native_library->scripts[script_name]; - ERR_FAIL_COND(!script_data); - } - } -} - -StringName GDNativeScript::get_script_name() const { - return script_name; -} - -void GDNativeScript::set_script_name(StringName p_script_name) { - script_name = p_script_name; - - if (library.is_valid()) { -#ifdef TOOLS_ENABLED - if (!library->native_library) { - library->_initialize(); - } -#endif - if (library->native_library) { - script_data = library->get_script_data(script_name); - ERR_FAIL_COND(!script_data); - } - } -} - -void GDNativeScript::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_library"), &GDNativeScript::get_library); - ClassDB::bind_method(D_METHOD("set_library", "library"), &GDNativeScript::set_library); - ClassDB::bind_method(D_METHOD("get_script_name"), &GDNativeScript::get_script_name); - ClassDB::bind_method(D_METHOD("set_script_name", "script_name"), &GDNativeScript::set_script_name); - - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &GDNativeScript::_new, MethodInfo(Variant::OBJECT, "new")); - - ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library"); - ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "script_name"), "set_script_name", "get_script_name"); -} - -GDNativeScript::GDNativeScript() { - script_data = NULL; - GDNativeScriptLanguage::get_singleton()->script_list.insert(this); -} - -GDNativeScript::~GDNativeScript() { - //hmm - GDNativeScriptLanguage::get_singleton()->script_list.erase(this); -} - -// Library - -GDNativeLibrary *GDNativeLibrary::currently_initialized_library = NULL; - -GDNativeLibrary *GDNativeLibrary::get_currently_initialized_library() { - return currently_initialized_library; -} - -static const char *_dl_platforms_info[] = { - "|unix|so|Unix", - "unix|x11|so|X11", - "unix|server|so|Server", - "unix|android|so|Android", - "unix|haiku|so|Haiku", // Right? - "|mac|dylib|Mac", - "mac|ios|dylib|iOS", - "mac|osx|dylib|OSX", - "|html5|js|HTML5", - "|windows|dll|Windows", - "windows|uwp|dll|UWP", - NULL // Finishing condition -}; - -void GDNativeLibrary::set_platform_file(StringName p_platform, String p_file) { - if (p_file.empty()) { - platform_files.erase(p_platform); - } else { - platform_files[p_platform] = p_file; - } -} - -String GDNativeLibrary::get_platform_file(StringName p_platform) const { - if (platform_files.has(p_platform)) { - return platform_files[p_platform]; - } else { - return ""; - } -} - -Error GDNativeLibrary::_initialize() { - _THREAD_SAFE_METHOD_ - - // Get the file - - const String platform_name = OS::get_singleton()->get_name(); - String platform_file(""); - char **platform_info = (char **)_dl_platforms_info; - - if (platform_files.has(platform_name.to_lower())) { - platform_file = platform_files[platform_name.to_lower()]; - } - - while (*platform_info) { - String platform_info_string(*platform_info); - - if (platform_name == platform_info_string.get_slicec('|', 3)) { - String platform_key = platform_info_string.get_slicec('|', 1); - String fallback_platform_key = platform_info_string.get_slicec('|', 0); - - if (platform_files.has(platform_key)) { - platform_file = platform_files[platform_key]; - } else if (!fallback_platform_key.empty() && platform_files.has(fallback_platform_key)) { - platform_file = platform_files[fallback_platform_key]; - } else { - return ERR_UNAVAILABLE; - } - } - platform_info++; - } - ERR_FAIL_COND_V(platform_file == "", ERR_DOES_NOT_EXIST); - - StringName path = GlobalConfig::get_singleton()->globalize_path(platform_file); - - GDNativeLibrary::currently_initialized_library = this; - - Error ret = NativeLibrary::initialize(native_library, path); - native_library->dllib = this; - - GDNativeLibrary::currently_initialized_library = NULL; - - return ret; -} - -Error GDNativeLibrary::_terminate() { - ERR_FAIL_COND_V(!native_library, ERR_BUG); - ERR_FAIL_COND_V(!native_library->handle, ERR_BUG); - - // de-init stuff - - for (Map<StringName, GDNativeScriptData *>::Element *E = native_library->scripts.front(); E; E = E->next()) { - for (Map<StringName, GDNativeScriptData::Method>::Element *M = E->get()->methods.front(); M; M = M->next()) { - if (M->get().method.free_func) { - M->get().method.free_func(M->get().method.method_data); - } - } - if (E->get()->create_func.free_func) { - E->get()->create_func.free_func(E->get()->create_func.method_data); - } - if (E->get()->destroy_func.free_func) { - E->get()->destroy_func.free_func(E->get()->destroy_func.method_data); - } - - for (Set<GDNativeScript *>::Element *S = GDNativeScriptLanguage::get_singleton()->script_list.front(); S; S = S->next()) { - if (S->get()->script_data == E->get()) { - S->get()->script_data = NULL; - } - } - - memdelete(E->get()); - } - - Error ret = NativeLibrary::terminate(native_library); - native_library->scripts.clear(); - - return ret; -} - -void GDNativeLibrary::_register_script(const StringName p_name, const StringName p_base, godot_instance_create_func p_instance_func, godot_instance_destroy_func p_destroy_func) { - ERR_FAIL_COND(!native_library); - ERR_FAIL_COND(native_library->scripts.has(p_name)); - - GDNativeScriptData *s = memnew(GDNativeScriptData); - s->base = p_base; - s->create_func = p_instance_func; - s->destroy_func = p_destroy_func; - Map<StringName, GDNativeScriptData *>::Element *E = native_library->scripts.find(p_base); - if (E) { - s->base_data = E->get(); - s->base_native_type = s->base_data->base_native_type; - } else { - if (!ClassDB::class_exists(p_base)) { - memdelete(s); - ERR_EXPLAIN("Invalid base for registered type '" + p_name + "'"); - ERR_FAIL(); - } - s->base_native_type = p_base; - } - - native_library->scripts.insert(p_name, s); -} - -void GDNativeLibrary::_register_tool_script(const StringName p_name, const StringName p_base, godot_instance_create_func p_instance_func, godot_instance_destroy_func p_destroy_func) { - ERR_FAIL_COND(!native_library); - ERR_FAIL_COND(native_library->scripts.has(p_name)); - - GDNativeScriptData *s = memnew(GDNativeScriptData); - s->base = p_base; - s->create_func = p_instance_func; - s->destroy_func = p_destroy_func; - s->is_tool = true; - Map<StringName, GDNativeScriptData *>::Element *E = native_library->scripts.find(p_base); - if (E) { - s->base_data = E->get(); - s->base_native_type = s->base_data->base_native_type; - } else { - if (!ClassDB::class_exists(p_base)) { - memdelete(s); - ERR_EXPLAIN("Invalid base for registered type '" + p_name + "'"); - ERR_FAIL(); - } - s->base_native_type = p_base; - } - - native_library->scripts.insert(p_name, s); -} - -void GDNativeLibrary::_register_script_method(const StringName p_name, const StringName p_method, godot_method_attributes p_attr, godot_instance_method p_func, MethodInfo p_info) { - ERR_FAIL_COND(!native_library); - ERR_FAIL_COND(!native_library->scripts.has(p_name)); - - p_info.name = p_method; - GDNativeScriptData::Method method; - - method = GDNativeScriptData::Method(p_func, p_info, p_attr.rpc_type); - - native_library->scripts[p_name]->methods.insert(p_method, method); -} - -void GDNativeLibrary::_register_script_property(const StringName p_name, const String p_path, godot_property_attributes *p_attr, godot_property_set_func p_setter, godot_property_get_func p_getter) { - ERR_FAIL_COND(!native_library); - ERR_FAIL_COND(!native_library->scripts.has(p_name)); - - GDNativeScriptData::Property p; - - PropertyInfo pi; - pi.name = p_path; - - if (p_attr != NULL) { - pi = PropertyInfo((Variant::Type)p_attr->type, p_path, (PropertyHint)p_attr->hint, *(String *)&p_attr->hint_string, p_attr->usage); - - p = GDNativeScriptData::Property(p_setter, p_getter, pi, *(Variant *)&p_attr->default_value, p_attr->rset_type); - } - - native_library->scripts[p_name]->properties.insert(p_path, p); +GDNativeLibrary::GDNativeLibrary() + : library_paths() { } -void GDNativeLibrary::_register_script_signal(const StringName p_name, const godot_signal *p_signal) { - ERR_FAIL_COND(!native_library); - ERR_FAIL_COND(!native_library->scripts.has(p_name)); - ERR_FAIL_COND(!p_signal); - - GDNativeScriptData::Signal signal; - - signal.signal.name = *(String *)&p_signal->name; - - { - List<PropertyInfo> arguments; - for (int i = 0; i < p_signal->num_args; i++) { - PropertyInfo info; - godot_signal_argument attrib = p_signal->args[i]; - - String *name = (String *)&attrib.name; - info.name = *name; - info.type = (Variant::Type)attrib.type; - info.hint = (PropertyHint)attrib.hint; - info.hint_string = *(String *)&attrib.hint_string; - info.usage = attrib.usage; - - arguments.push_back(info); - } - - signal.signal.arguments = arguments; - } - - { - Vector<Variant> default_arguments; - for (int i = 0; i < p_signal->num_default_args; i++) { - Variant *v; - godot_signal_argument attrib = p_signal->args[i]; - - v = (Variant *)&attrib.default_value; - - default_arguments.push_back(*v); - } - - signal.signal.default_arguments = default_arguments; - } - - native_library->scripts[p_name]->signals_.insert(*(String *)&p_signal->name, signal); +GDNativeLibrary::~GDNativeLibrary() { } -GDNativeScriptData *GDNativeLibrary::get_script_data(const StringName p_name) { - ERR_FAIL_COND_V(!native_library, NULL); - - ERR_FAIL_COND_V(!native_library->scripts.has(p_name), NULL); - - return native_library->scripts[p_name]; +void GDNativeLibrary::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_library_path", "platform", "path"), &GDNativeLibrary::set_library_path); + ClassDB::bind_method(D_METHOD("get_library_path", "platform"), &GDNativeLibrary::get_library_path); } bool GDNativeLibrary::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; if (name.begins_with("platform/")) { - set_platform_file(name.get_slice("/", 1), p_value); + set_library_path(name.get_slice("/", 1), p_value); return true; } return false; @@ -763,517 +101,231 @@ bool GDNativeLibrary::_set(const StringName &p_name, const Variant &p_value) { bool GDNativeLibrary::_get(const StringName &p_name, Variant &r_ret) const { String name = p_name; if (name.begins_with("platform/")) { - r_ret = get_platform_file(name.get_slice("/", 1)); + r_ret = get_library_path(name.get_slice("/", 1)); return true; } return false; } void GDNativeLibrary::_get_property_list(List<PropertyInfo> *p_list) const { - char **platform_info = (char **)_dl_platforms_info; - - Set<String> registered_platform_names; - { - List<StringName> ep; - // ep.push_back("X11"); - // EditorImportExport::get_singleton()->get_export_platforms(&ep); - - // @Todo - // get export platforms with the new export system somehow. - for (List<StringName>::Element *E = ep.front(); E; E = E->next()) { - registered_platform_names.insert(String(E->get()).to_lower()); - } + for (int i = 0; i < NUM_PLATFORMS; i++) { + p_list->push_back(PropertyInfo(Variant::STRING, + "platform/" + platform_names[i], + PROPERTY_HINT_FILE, + "*." + platform_lib_ext[i])); } +} - while (*platform_info) { - String platform_info_string(*platform_info); - String fallback_platform_key = platform_info_string.get_slicec('|', 0); - String platform_key = platform_info_string.get_slicec('|', 1); - String platform_extension = platform_info_string.get_slicec('|', 2); - String platform_name = platform_info_string.get_slicec('|', 3); - - registered_platform_names.erase(platform_name); - - if (fallback_platform_key.empty()) { - p_list->push_back(PropertyInfo(Variant::STRING, "platform/" + platform_key, PROPERTY_HINT_FILE, "*." + platform_extension)); - - } else { - if (platform_files.has(platform_key)) { - p_list->push_back(PropertyInfo(Variant::STRING, "platform/" + platform_key, PROPERTY_HINT_FILE, "*." + platform_extension, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CHECKABLE | PROPERTY_USAGE_CHECKED)); - } else { - p_list->push_back(PropertyInfo(Variant::STRING, "platform/" + platform_key, PROPERTY_HINT_FILE, "*." + platform_extension, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CHECKABLE)); - } +void GDNativeLibrary::set_library_path(StringName p_platform, String p_path) { + int i; + for (i = 0; i <= NUM_PLATFORMS; i++) { + if (i == NUM_PLATFORMS) break; + if (platform_names[i] == p_platform) { + break; } - platform_info++; - } - - while (registered_platform_names.size()) { - const String platform_name = registered_platform_names.front()->get(); - registered_platform_names.erase(platform_name); - p_list->push_back(PropertyInfo(Variant::STRING, "platform/" + platform_name.to_lower(), PROPERTY_HINT_FILE, "*")); } -} - -void GDNativeLibrary::_notification(int what) { - // TODO -} - -void GDNativeLibrary::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_platform_file", "platform", "file"), &GDNativeLibrary::set_platform_file); - ClassDB::bind_method(D_METHOD("get_platform_file", "platform"), &GDNativeLibrary::get_platform_file); -} - -GDNativeLibrary::GDNativeLibrary() { - native_library = NULL; -} - -GDNativeLibrary::~GDNativeLibrary() { - if (!native_library) { - return; + if (i == NUM_PLATFORMS) { + ERR_EXPLAIN(String("No such platform: ") + p_platform); + ERR_FAIL(); } - if (native_library->handle) { - _terminate(); - } + library_paths[i] = p_path; } -// Instance - -bool GDNativeInstance::set(const StringName &p_name, const Variant &p_value) { - if (!script->script_data) - return false; - if (script->script_data->properties.has(p_name)) { - script->script_data->properties[p_name].setter.set_func((godot_object *)owner, script->script_data->properties[p_name].setter.method_data, userdata, *(godot_variant *)&p_value); - return true; +String GDNativeLibrary::get_library_path(StringName p_platform) const { + int i; + for (i = 0; i <= NUM_PLATFORMS; i++) { + if (i == NUM_PLATFORMS) break; + if (platform_names[i] == p_platform) { + break; + } } - return false; -} -bool GDNativeInstance::get(const StringName &p_name, Variant &r_ret) const { - if (!script->script_data) - return false; - if (script->script_data->properties.has(p_name)) { - godot_variant value = script->script_data->properties[p_name].getter.get_func((godot_object *)owner, script->script_data->properties[p_name].getter.method_data, userdata); - r_ret = *(Variant *)&value; - return true; + if (i == NUM_PLATFORMS) { + ERR_EXPLAIN(String("No such platform: ") + p_platform); + ERR_FAIL_V(""); } - return false; -} - -void GDNativeInstance::get_property_list(List<PropertyInfo> *p_properties) const { - script->get_script_property_list(p_properties); - // TODO: dynamic properties -} -Variant::Type GDNativeInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { - if (script->script_data->properties.has(p_name)) { - *r_is_valid = true; - return script->script_data->properties[p_name].info.type; - } - *r_is_valid = false; - return Variant::NIL; + return library_paths[i]; } -void GDNativeInstance::get_method_list(List<MethodInfo> *p_list) const { - script->get_script_method_list(p_list); +String GDNativeLibrary::get_active_library_path() const { + return library_paths[GDNativeLibrary::current_platform]; } -bool GDNativeInstance::has_method(const StringName &p_method) const { - return script->has_method(p_method); +GDNative::GDNative() { + initialized = false; + native_handle = NULL; } -Variant GDNativeInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - // TODO: validated methods & errors - - GDNativeScriptData *data_ptr = script->script_data; - while (data_ptr) { - Map<StringName, GDNativeScriptData::Method>::Element *E = data_ptr->methods.find(p_method); - if (E) { - godot_variant result = E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, p_argcount, (godot_variant **)p_args); - return *(Variant *)&result; - } - data_ptr = data_ptr->base_data; - } - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; - return Variant(); +GDNative::~GDNative() { + // TODO(karroffel): implement ALL the things! } -void GDNativeInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - // TODO: validated methods & errors +extern "C" void _api_anchor(); - GDNativeScriptData *data_ptr = script->script_data; - while (data_ptr) { - Map<StringName, GDNativeScriptData::Method>::Element *E = data_ptr->methods.find(p_method); - if (E) { - E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, p_argcount, (godot_variant **)p_args); - } - data_ptr = data_ptr->base_data; - } +void GDNative::_compile_dummy_for_api() { + _api_anchor(); } -void GDNativeInstance::_ml_call_reversed(GDNativeScriptData *data_ptr, const StringName &p_method, const Variant **p_args, int p_argcount) { - // TODO: validated methods & errors +void GDNative::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_library", "library:GDNativeLibrary"), &GDNative::set_library); + ClassDB::bind_method(D_METHOD("get_library:GDNativeLibrary"), &GDNative::get_library); - if (data_ptr->base_data) - _ml_call_reversed(data_ptr->base_data, p_method, p_args, p_argcount); + ClassDB::bind_method(D_METHOD("initialize"), &GDNative::initialize); + ClassDB::bind_method(D_METHOD("terminate"), &GDNative::terminate); - // Variant::CallError ce; + // TODO(karroffel): get_native_(raw_)call_types binding? - Map<StringName, GDNativeScriptData::Method>::Element *E = data_ptr->methods.find(p_method); - if (E) { - E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, p_argcount, (godot_variant **)p_args); - } -} + // TODO(karroffel): make this a varargs function? + ClassDB::bind_method(D_METHOD("call_native:Variant", "procedure_name", "arguments:Array"), &GDNative::call_native); -void GDNativeInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - if (script.ptr() && script->script_data) { - _ml_call_reversed(script->script_data, p_method, p_args, p_argcount); - } -} - -void GDNativeInstance::notification(int p_notification) { - Variant value = p_notification; - const Variant *args[1] = { &value }; - call_multilevel(GDNativeScriptLanguage::singleton->strings._notification, args, 1); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library"); } -Ref<Script> GDNativeInstance::get_script() const { - return script; +void GDNative::set_library(Ref<GDNativeLibrary> p_library) { + library = p_library; } -ScriptLanguage *GDNativeInstance::get_language() { - return GDNativeScriptLanguage::singleton; +Ref<GDNativeLibrary> GDNative::get_library() { + return library; } -ScriptInstance::RPCMode GDNativeInstance::get_rpc_mode(const StringName &p_method) const { - GDNativeScriptData::Method m = script->script_data->methods[p_method]; - switch (m.rpc_mode) { - case GODOT_METHOD_RPC_MODE_DISABLED: - return RPC_MODE_DISABLED; - case GODOT_METHOD_RPC_MODE_REMOTE: - return RPC_MODE_REMOTE; - case GODOT_METHOD_RPC_MODE_SYNC: - return RPC_MODE_SYNC; - case GODOT_METHOD_RPC_MODE_MASTER: - return RPC_MODE_MASTER; - case GODOT_METHOD_RPC_MODE_SLAVE: - return RPC_MODE_SLAVE; - default: - return RPC_MODE_DISABLED; +bool GDNative::initialize() { + if (library.is_null()) { + ERR_PRINT("No library set, can't initialize GDNative object"); + return false; } -} -ScriptInstance::RPCMode GDNativeInstance::get_rset_mode(const StringName &p_variable) const { - GDNativeScriptData::Property p = script->script_data->properties[p_variable]; - switch (p.rset_mode) { - case GODOT_METHOD_RPC_MODE_DISABLED: - return RPC_MODE_DISABLED; - case GODOT_METHOD_RPC_MODE_REMOTE: - return RPC_MODE_REMOTE; - case GODOT_METHOD_RPC_MODE_SYNC: - return RPC_MODE_SYNC; - case GODOT_METHOD_RPC_MODE_MASTER: - return RPC_MODE_MASTER; - case GODOT_METHOD_RPC_MODE_SLAVE: - return RPC_MODE_SLAVE; - default: - return RPC_MODE_DISABLED; + String lib_path = library->get_active_library_path(); + if (lib_path.empty()) { + ERR_PRINT("No library set for this platform"); + return false; } -} - -GDNativeInstance::GDNativeInstance() { - owner = NULL; - userdata = NULL; -} -GDNativeInstance::~GDNativeInstance() { - if (script.is_valid()) { - if (owner) { - script->instances.erase(owner); - } - if (!script->script_data) - return; - script->script_data->destroy_func.destroy_func((godot_object *)owner, script->script_data->destroy_func.method_data, userdata); - if (script->script_data->destroy_func.free_func) - script->script_data->destroy_func.free_func(script->script_data->destroy_func.method_data); - if (script->script_data->create_func.free_func) - script->script_data->create_func.free_func(script->script_data->create_func.method_data); + String path = ProjectSettings::get_singleton()->globalize_path(lib_path); + Error err = OS::get_singleton()->open_dynamic_library(path, native_handle); + if (err != OK) { + return false; } -} - -// Language - -GDNativeScriptLanguage *GDNativeScriptLanguage::singleton = NULL; - -String GDNativeScriptLanguage::get_name() const { - return "Native"; -} - -void _add_reload_node() { -#ifdef TOOLS_ENABLED - GDNativeReloadNode *rn = memnew(GDNativeReloadNode); - EditorNode::get_singleton()->add_child(rn); -#endif -} - -void GDNativeScriptLanguage::init() { - // TODO: Expose globals - GLOBAL_DEF("gdnative/default_gdnativelibrary", ""); - PropertyInfo prop_info(Variant::STRING, "gdnative/default_gdnativelibrary", PROPERTY_HINT_FILE, "tres,res,dllib"); - GlobalConfig::get_singleton()->set_custom_property_info("gdnative/default_gdnativelibrary", prop_info); - -// generate bindings -#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) - - List<String> args = OS::get_singleton()->get_cmdline_args(); - List<String>::Element *E = args.find("--gdnative-generate-json-api"); + void *library_init; + err = OS::get_singleton()->get_dynamic_library_symbol_handle( + native_handle, + init_symbol, + library_init); - if (E && E->next()) { - if (generate_c_api(E->next()->get()) != OK) { - ERR_PRINT("Failed to generate C API\n"); - } + if (err || !library_init) { + return false; } -#endif - -#ifdef TOOLS_ENABLED - // if (SceneTree::get_singleton()->is_editor_hint()) { - EditorNode::add_init_callback(&_add_reload_node); -// } -#endif -} -String GDNativeScriptLanguage::get_type() const { - return "Native"; -} - -String GDNativeScriptLanguage::get_extension() const { - return "gdn"; -} - -Error GDNativeScriptLanguage::execute_file(const String &p_path) { - return OK; // ?? -} - -void GDNativeScriptLanguage::finish() { - // cleanup is for noobs -} + godot_gdnative_init_fn library_init_fpointer; + library_init_fpointer = (godot_gdnative_init_fn)library_init; -// scons doesn't want to link in the api source so we need to call a dummy function to cause it to link -extern "C" void _api_anchor(); - -void GDNativeScriptLanguage::_compile_dummy_for_the_api() { - _api_anchor(); -} + godot_gdnative_init_options options; -Ref<Script> GDNativeScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { - GDNativeScript *src = memnew(GDNativeScript); - src->set_script_name(p_class_name); - return Ref<GDNativeScript>(src); -} - -bool GDNativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { - return false; // TODO -} + options.in_editor = SceneTree::get_singleton()->is_editor_hint(); + options.core_api_hash = ClassDB::get_api_hash(ClassDB::API_CORE); + options.editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR); + options.no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE); -Script *GDNativeScriptLanguage::create_script() const { - GDNativeScript *scr = memnew(GDNativeScript); - return scr; -} + library_init_fpointer(&options); -bool GDNativeScriptLanguage::has_named_classes() const { return true; } -int GDNativeScriptLanguage::find_function(const String &p_function, const String &p_code) const { - return -1; // No source code! -} - -String GDNativeScriptLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const { - return ""; // No source code! -} - -void GDNativeScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) { - // TODO TODO TODO -} - -// TODO: Any debugging? (research) -String GDNativeScriptLanguage::debug_get_error() const { - return ""; -} - -int GDNativeScriptLanguage::debug_get_stack_level_count() const { - return 1; // ? -} +bool GDNative::terminate() { -int GDNativeScriptLanguage::debug_get_stack_level_line(int p_level) const { - return -1; -} - -String GDNativeScriptLanguage::debug_get_stack_level_function(int p_level) const { - return "[native code]"; // ? -} - -String GDNativeScriptLanguage::debug_get_stack_level_source(int p_level) const { - return ""; -} - -void GDNativeScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} - -void GDNativeScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} - -String GDNativeScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { - return ""; // ?? -} + if (native_handle == NULL) { + ERR_PRINT("No valid library handle, can't terminate GDNative object"); + return false; + } -void GDNativeScriptLanguage::reload_all_scripts() { - // @Todo -} + Error error = OK; + void *library_terminate; + error = OS::get_singleton()->get_dynamic_library_symbol_handle( + native_handle, + terminate_symbol, + library_terminate); + if (error) { + OS::get_singleton()->close_dynamic_library(native_handle); + native_handle = NULL; + return true; + } -void GDNativeScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) { - // @Todo - OS::get_singleton()->print("reload tool scripts\n"); -} + godot_gdnative_terminate_fn library_terminate_pointer; + library_terminate_pointer = (godot_gdnative_terminate_fn)library_terminate; -void GDNativeScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("gdn"); // Container file format -} + // TODO(karroffel): remove this? Should be part of NativeScript, not + // GDNative IMO + godot_gdnative_terminate_options options; + options.in_editor = SceneTree::get_singleton()->is_editor_hint(); -void GDNativeScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const { -} + library_terminate_pointer(&options); -void GDNativeScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const { -} + // GDNativeScriptLanguage::get_singleton()->initialized_libraries.erase(p_native_lib->path); -// TODO: all profilling -void GDNativeScriptLanguage::profiling_start() { -} + OS::get_singleton()->close_dynamic_library(native_handle); + native_handle = NULL; -void GDNativeScriptLanguage::profiling_stop() { + return false; } -int GDNativeScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) { - return 0; +void GDNativeCallRegistry::register_native_call_type(StringName p_call_type, native_call_cb p_callback) { + native_calls.insert(p_call_type, p_callback); } -int GDNativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) { - return 0; +void GDNativeCallRegistry::register_native_raw_call_type(StringName p_raw_call_type, native_raw_call_cb p_callback) { + native_raw_calls.insert(p_raw_call_type, p_callback); } -void GDNativeScriptLanguage::frame() { -} +Vector<StringName> GDNativeCallRegistry::get_native_call_types() { + Vector<StringName> call_types; + call_types.resize(native_calls.size()); -String GDNativeScriptLanguage::get_init_symbol_name() { - return "godot_native_init"; // TODO: Maybe make some internal function which would do the actual stuff -} + size_t idx = 0; + for (Map<StringName, native_call_cb>::Element *E = native_calls.front(); E; E = E->next(), idx++) { + call_types[idx] = E->key(); + } -String GDNativeScriptLanguage::get_terminate_symbol_name() { - return "godot_native_terminate"; + return call_types; } -GDNativeScriptLanguage::GDNativeScriptLanguage() { - ERR_FAIL_COND(singleton); - strings._notification = StringName("_notification"); - singleton = this; - initialized_libraries = Map<StringName, NativeLibrary *>(); -} +Vector<StringName> GDNativeCallRegistry::get_native_raw_call_types() { + Vector<StringName> call_types; + call_types.resize(native_raw_calls.size()); -GDNativeScriptLanguage::~GDNativeScriptLanguage() { - singleton = NULL; -} - -// DLReloadNode + size_t idx = 0; + for (Map<StringName, native_raw_call_cb>::Element *E = native_raw_calls.front(); E; E = E->next(), idx++) { + call_types[idx] = E->key(); + } -void GDNativeReloadNode::_bind_methods() { - ClassDB::bind_method("_notification", &GDNativeReloadNode::_notification); + return call_types; } -void GDNativeReloadNode::_notification(int p_what) { -#ifdef TOOLS_ENABLED - - switch (p_what) { - case MainLoop::NOTIFICATION_WM_FOCUS_IN: { - - Set<NativeLibrary *> libs_to_reload; - - for (Map<StringName, NativeLibrary *>::Element *L = GDNativeScriptLanguage::get_singleton()->initialized_libraries.front(); L; L = L->next()) { - // check if file got modified at all - // @Todo - - libs_to_reload.insert(L->get()); - } - - for (Set<NativeLibrary *>::Element *L = libs_to_reload.front(); L; L = L->next()) { - - GDNativeLibrary *lib = L->get()->dllib; - - lib->_terminate(); - lib->_initialize(); - - // update placeholders (if any) - - Set<GDNativeScript *> scripts; - - for (Set<GDNativeScript *>::Element *S = GDNativeScriptLanguage::get_singleton()->script_list.front(); S; S = S->next()) { - - if (lib->native_library->scripts.has(S->get()->get_script_name())) { - GDNativeScript *script = S->get(); - script->script_data = lib->get_script_data(script->get_script_name()); - scripts.insert(script); - } - } - - for (Set<GDNativeScript *>::Element *S = scripts.front(); S; S = S->next()) { - GDNativeScript *script = S->get(); - if (script->placeholders.size() == 0) - continue; +Variant GDNative::call_native(StringName p_native_call_type, StringName p_procedure_name, Array p_arguments) { - for (Set<PlaceHolderScriptInstance *>::Element *P = script->placeholders.front(); P; P = P->next()) { - PlaceHolderScriptInstance *p = P->get(); - script->_update_placeholder(p); - } - } - } - - } break; - default: { - }; + Map<StringName, native_call_cb>::Element *E = GDNativeCallRegistry::singleton->native_calls.find(p_native_call_type); + if (!E) { + ERR_PRINT((String("No handler for native call type \"" + p_native_call_type) + "\" found").utf8().get_data()); + return Variant(); } -#endif -} -// Resource loader/saver + String procedure_name = p_procedure_name; + godot_variant result = E->get()(native_handle, (godot_string *)&procedure_name, (godot_array *)&p_arguments); -RES ResourceFormatLoaderGDNativeScript::load(const String &p_path, const String &p_original_path, Error *r_error) { - ResourceFormatLoaderText rsflt; - return rsflt.load(p_path, p_original_path, r_error); + return *(Variant *)&result; } -void ResourceFormatLoaderGDNativeScript::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("gdn"); -} -bool ResourceFormatLoaderGDNativeScript::handles_type(const String &p_type) const { - return (p_type == "Script" || p_type == "Native"); -} -String ResourceFormatLoaderGDNativeScript::get_resource_type(const String &p_path) const { - String el = p_path.get_extension().to_lower(); - if (el == "gdn") - return "Native"; - return ""; -} +void GDNative::call_native_raw(StringName p_raw_call_type, StringName p_procedure_name, void *data, int num_args, void **args, void *r_return) { -Error ResourceFormatSaverGDNativeScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - ResourceFormatSaverText rfst; - return rfst.save(p_path, p_resource, p_flags); -} - -bool ResourceFormatSaverGDNativeScript::recognize(const RES &p_resource) const { - return p_resource->cast_to<GDNativeScript>() != NULL; -} - -void ResourceFormatSaverGDNativeScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { - if (p_resource->cast_to<GDNativeScript>()) { - p_extensions->push_back("gdn"); + Map<StringName, native_raw_call_cb>::Element *E = GDNativeCallRegistry::singleton->native_raw_calls.find(p_raw_call_type); + if (!E) { + ERR_PRINT((String("No handler for native raw call type \"" + p_raw_call_type) + "\" found").utf8().get_data()); + return; } + + String procedure_name = p_procedure_name; + E->get()(native_handle, (godot_string *)&procedure_name, data, num_args, args, r_return); } diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h index 650f999192..dd845cab7a 100644 --- a/modules/gdnative/gdnative.h +++ b/modules/gdnative/gdnative.h @@ -34,382 +34,112 @@ #include "io/resource_saver.h" #include "os/thread_safe.h" #include "resource.h" -#include "scene/main/node.h" -#include "script_language.h" -#include "self_list.h" -#include "godot.h" +#include "godot/gdnative.h" -struct GDNativeScriptData; -class GDNativeLibrary; - -struct NativeLibrary { - StringName path; - void *handle; - - GDNativeLibrary *dllib; - - Map<StringName, GDNativeScriptData *> scripts; - - static Error initialize(NativeLibrary *&p_native_lib, const StringName p_path); - static Error terminate(NativeLibrary *&p_native_lib); -}; - -struct GDNativeScriptData { - /* typedef void* (InstanceFunc)(godot_object* instance); - typedef void (DestroyFunc)(godot_object* instance,void* userdata); - typedef godot_variant (MethodFunc)(godot_object *instance, void *userdata, void *method_data, int arg_count,godot_variant **args); - typedef void (MethodDataFreeFunc)(void *method_data); - typedef void (SetterFunc)(godot_object* instance,void* userdata,godot_variant value); - typedef godot_variant (GetterFunc)(godot_object* instance,void* userdata);*/ - - struct Method { - godot_instance_method method; - MethodInfo info; - int rpc_mode; - - Method() { - } - Method(godot_instance_method p_method, MethodInfo p_info, int p_rpc_mode) { - method = p_method; - info = p_info; - rpc_mode = p_rpc_mode; - } - }; - struct Property { - godot_property_set_func setter; - godot_property_get_func getter; - PropertyInfo info; - Variant default_value; - int rset_mode; - - Property() { - } - Property(godot_property_set_func p_setter, godot_property_get_func p_getter) { - setter = p_setter; - getter = p_getter; - } - Property(godot_property_set_func p_setter, godot_property_get_func p_getter, PropertyInfo p_info, Variant p_default_value, int p_rset_mode) { - setter = p_setter; - getter = p_getter; - info = p_info; - default_value = p_default_value; - rset_mode = p_rset_mode; - } - }; - - struct Signal { - MethodInfo signal; - }; - - Map<StringName, Method> methods; - Map<StringName, Property> properties; - Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals - StringName base; - StringName base_native_type; - GDNativeScriptData *base_data; - godot_instance_create_func create_func; - godot_instance_destroy_func destroy_func; - - bool is_tool; - - GDNativeScriptData() { - base = StringName(); - base_data = NULL; - is_tool = false; - } - GDNativeScriptData(StringName p_base, godot_instance_create_func p_instance, godot_instance_destroy_func p_free) { - base = p_base; - base_data = NULL; - create_func = p_instance; - destroy_func = p_free; - is_tool = false; - } -}; - -class GDNativeScript : public Script { - GDCLASS(GDNativeScript, Script); - - Ref<GDNativeLibrary> library; - StringName script_name; - StringName base_native_type; - Set<Object *> instances; - GDNativeScriptData *script_data; - -#ifdef TOOLS_ENABLED - Set<PlaceHolderScriptInstance *> placeholders; - void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); - virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder); -#endif - - friend class GDNativeInstance; - friend class GDNativeScriptLanguage; - friend class GDNativeReloadNode; - friend class GDNativeLibrary; - -protected: - static void _bind_methods(); - -public: - virtual bool can_instance() const; - - virtual Ref<Script> get_base_script() const; //for script inheritance - - virtual StringName get_instance_base_type() const; // this may not work in all scripts, will return empty if so - virtual ScriptInstance *instance_create(Object *p_this); - virtual bool instance_has(const Object *p_this) const; - - virtual bool has_source_code() const; - virtual String get_source_code() const; - virtual void set_source_code(const String &p_code) {} - virtual Error reload(bool p_keep_state = false); - - virtual bool has_method(const StringName &p_method) const; - virtual MethodInfo get_method_info(const StringName &p_method) const; - - virtual bool is_tool() const; - - virtual String get_node_type() const; +class GDNativeLibrary : public Resource { + GDCLASS(GDNativeLibrary, Resource) - virtual ScriptLanguage *get_language() const; + enum Platform { + X11_32BIT, + X11_64BIT, + WINDOWS_32BIT, + WINDOWS_64BIT, + // NOTE(karroffel): I heard OSX 32 bit is dead, so 64 only + OSX, - virtual bool has_script_signal(const StringName &p_signal) const; - virtual void get_script_signal_list(List<MethodInfo> *r_signals) const; + // TODO(karroffel): all different android versions and archs + ANDROID, - virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const; + // TODO(karroffe): all different iOS versions and archs + IOS, - virtual void update_exports() {} //editor tool - virtual void get_script_method_list(List<MethodInfo> *p_list) const; - virtual void get_script_property_list(List<PropertyInfo> *p_list) const; + // TODO(karroffel): figure out how to deal with web stuff at all... + WASM, - Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + // TODO(karroffel): does UWP have different libs?? + // UWP, - Ref<GDNativeLibrary> get_library() const; - void set_library(Ref<GDNativeLibrary> p_library); + NUM_PLATFORMS - StringName get_script_name() const; - void set_script_name(StringName p_script_name); + }; - GDNativeScript(); - ~GDNativeScript(); -}; + static String platform_names[NUM_PLATFORMS]; + static String platform_lib_ext[NUM_PLATFORMS]; -class GDNativeLibrary : public Resource { - _THREAD_SAFE_CLASS_ + // TODO(karroffel): make this actually do something lol. + static Platform current_platform; - GDCLASS(GDNativeLibrary, Resource); - OBJ_SAVE_TYPE(GDNativeLibrary); - - Map<StringName, String> platform_files; - NativeLibrary *native_library; - static GDNativeLibrary *currently_initialized_library; + String library_paths[NUM_PLATFORMS]; protected: - friend class GDNativeScript; - friend struct NativeLibrary; - friend class GDNativeReloadNode; - - GDNativeScriptData *get_script_data(const StringName p_name); - bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; - void _notification(int p_what); - static void _bind_methods(); public: - Error _initialize(); - Error _terminate(); - - static GDNativeLibrary *get_currently_initialized_library(); - - void _register_script(const StringName p_name, const StringName p_base, godot_instance_create_func p_instance_func, godot_instance_destroy_func p_destroy_func); - void _register_tool_script(const StringName p_name, const StringName p_base, godot_instance_create_func p_instance_func, godot_instance_destroy_func p_destroy_func); - void _register_script_method(const StringName p_name, const StringName p_method, godot_method_attributes p_attr, godot_instance_method p_func, MethodInfo p_info); - void _register_script_property(const StringName p_name, const String p_path, godot_property_attributes *p_attr, godot_property_set_func p_setter, godot_property_get_func p_getter); - void _register_script_signal(const StringName p_name, const godot_signal *p_signal); - - void set_platform_file(StringName p_platform, String p_file); - String get_platform_file(StringName p_platform) const; - GDNativeLibrary(); ~GDNativeLibrary(); -}; - -class GDNativeInstance : public ScriptInstance { - friend class GDNativeScript; - Object *owner; - Ref<GDNativeScript> script; - void *userdata; - - void _ml_call_reversed(GDNativeScriptData *data_ptr, const StringName &p_method, const Variant **p_args, int p_argcount); - -public: - _FORCE_INLINE_ Object *get_owner() { return owner; } - - _FORCE_INLINE_ void *get_userdata() { return userdata; } - - virtual bool set(const StringName &p_name, const Variant &p_value); - virtual bool get(const StringName &p_name, Variant &r_ret) const; - virtual void get_property_list(List<PropertyInfo> *p_properties) const; - virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const; - - virtual void get_method_list(List<MethodInfo> *p_list) const; - virtual bool has_method(const StringName &p_method) const; - virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error); - virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); - virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); - - Variant debug_get_member_by_index(int p_idx) const { return Variant(); } - - virtual void notification(int p_notification); - - virtual Ref<Script> get_script() const; - - virtual ScriptLanguage *get_language(); - - void set_path(const String &p_path); - - void reload_members(); + static void _bind_methods(); - virtual RPCMode get_rpc_mode(const StringName &p_method) const; - virtual RPCMode get_rset_mode(const StringName &p_variable) const; + void set_library_path(StringName p_platform, String p_path); + String get_library_path(StringName p_platform) const; - GDNativeInstance(); - ~GDNativeInstance(); + String get_active_library_path() const; }; -class GDNativeReloadNode; +typedef godot_variant (*native_call_cb)(void *, godot_string *, godot_array *); +typedef void (*native_raw_call_cb)(void *, godot_string *, void *, int, void **, void *); -class GDNativeScriptLanguage : public ScriptLanguage { - friend class GDNativeScript; - friend class GDNativeInstance; - friend class GDNativeReloadNode; - friend class GDNativeLibrary; +struct GDNativeCallRegistry { + static GDNativeCallRegistry *singleton; - static GDNativeScriptLanguage *singleton; + inline GDNativeCallRegistry *get_singleton() { + return singleton; + } - Variant *_global_array; // @Unused necessary? - Vector<Variant> global_array; // @Unused necessary? - Map<StringName, int> globals; // @Unused necessary? + inline GDNativeCallRegistry() + : native_calls(), + native_raw_calls() {} - // @Unused necessary? - void _add_global(const StringName &p_name, const Variant &p_value); + Map<StringName, native_call_cb> native_calls; + Map<StringName, native_raw_call_cb> native_raw_calls; - Mutex *lock; + void register_native_call_type(StringName p_call_type, native_call_cb p_callback); + void register_native_raw_call_type(StringName p_raw_call_type, native_raw_call_cb p_callback); - Set<GDNativeScript *> script_list; + Vector<StringName> get_native_call_types(); + Vector<StringName> get_native_raw_call_types(); +}; - bool profiling; - uint64_t script_frame_time; +class GDNative : public Reference { + GDCLASS(GDNative, Reference) - struct { + Ref<GDNativeLibrary> library; + bool initialized; - StringName _notification; + // TODO(karroffel): different platforms? WASM???? + void *native_handle; - } strings; + void _compile_dummy_for_api(); public: - Map<StringName, NativeLibrary *> initialized_libraries; - - _FORCE_INLINE_ static GDNativeScriptLanguage *get_singleton() { return singleton; } - - virtual String get_name() const; - - /* LANGUAGE FUNCTIONS */ - virtual void init(); - virtual String get_type() const; - virtual String get_extension() const; - virtual Error execute_file(const String &p_path); - virtual void finish(); - - /* EDITOR FUNCTIONS */ - - virtual void get_reserved_words(List<String> *p_words) const {}; - virtual void get_comment_delimiters(List<String> *p_delimiters) const {}; - virtual void get_string_delimiters(List<String> *p_delimiters) const {}; - virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const; - virtual Script *create_script() const; - virtual bool has_named_classes() const; - virtual int find_function(const String &p_function, const String &p_code) const; - virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const; - virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; } - virtual Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, String &r_call_hint) { return ERR_UNAVAILABLE; } - - virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_base_path, Object *p_owner, LookupResult &r_result) { return ERR_UNAVAILABLE; } + GDNative(); + ~GDNative(); - virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const {}; - virtual void add_global_constant(const StringName &p_variable, const Variant &p_value); - - /* MULTITHREAD FUNCTIONS */ - - //some VMs need to be notified of thread creation/exiting to allocate a stack - virtual void thread_enter() {} - virtual void thread_exit() {} - - /* DEBUGGER FUNCTIONS */ - - virtual String debug_get_error() const; - virtual int debug_get_stack_level_count() const; - virtual int debug_get_stack_level_line(int p_level) const; - virtual String debug_get_stack_level_function(int p_level) const; - virtual String debug_get_stack_level_source(int p_level) const; - virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1){}; - virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); - virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); - virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1); - - virtual Vector<StackInfo> debug_get_current_stack_info() { return Vector<StackInfo>(); } - - virtual void reload_all_scripts(); - virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload); - /* LOADER FUNCTIONS */ - - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual void get_public_functions(List<MethodInfo> *p_functions) const; - virtual void get_public_constants(List<Pair<String, Variant> > *p_constants) const; - - /* PROFILLER FUNCTIONS */ - - virtual void profiling_start(); - virtual void profiling_stop(); - - virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max); - virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max); - - virtual void frame(); - - static String get_init_symbol_name(); - static String get_terminate_symbol_name(); - - /* HACKER FUNCTIONS */ - void _compile_dummy_for_the_api(); + static void _bind_methods(); - GDNativeScriptLanguage(); - ~GDNativeScriptLanguage(); -}; + void set_library(Ref<GDNativeLibrary> p_library); + Ref<GDNativeLibrary> get_library(); -class GDNativeReloadNode : public Node { - GDCLASS(GDNativeReloadNode, Node) -public: - static void _bind_methods(); - void _notification(int p_what); -}; + bool is_initialized(); -class ResourceFormatLoaderGDNativeScript : public 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; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; -}; + bool initialize(); + bool terminate(); -class ResourceFormatSaverGDNativeScript : public 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; + Variant call_native(StringName p_call_type, StringName p_procedure_name, Array p_arguments = Array()); + void call_native_raw(StringName p_raw_call_type, StringName p_procedure_name, void *data, int num_args, void **args, void *r_return); }; #endif // GDNATIVE_H diff --git a/modules/gdnative/godot/godot_array.cpp b/modules/gdnative/godot/array.cpp index 5497dde520..c068eecf8f 100644 --- a/modules/gdnative/godot/godot_array.cpp +++ b/modules/gdnative/godot/array.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_array.cpp */ +/* array.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_array.h" +#include "array.h" #include "core/array.h" #include "core/os/memory.h" diff --git a/modules/gdnative/godot/godot_array.h b/modules/gdnative/godot/array.h index bf8bc61977..cbdbfbdde3 100644 --- a/modules/gdnative/godot/godot_array.h +++ b/modules/gdnative/godot/array.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_array.h */ +/* array.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -37,16 +37,19 @@ extern "C" { #include <stdint.h> +#define GODOT_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_ARRAY_TYPE_DEFINED -typedef struct godot_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_ARRAY_SIZE]; } godot_array; #endif -#include "godot_pool_arrays.h" -#include "godot_variant.h" +#include "pool_arrays.h" +#include "variant.h" -#include "../godot.h" +#include "gdnative.h" void GDAPI godot_array_new(godot_array *r_dest); void GDAPI godot_array_new_copy(godot_array *r_dest, const godot_array *p_src); diff --git a/modules/gdnative/godot/godot_basis.cpp b/modules/gdnative/godot/basis.cpp index 46464932c5..7188215d04 100644 --- a/modules/gdnative/godot/godot_basis.cpp +++ b/modules/gdnative/godot/basis.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_basis.cpp */ +/* basis.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_basis.h" +#include "basis.h" #include "core/variant.h" #include "core/math/matrix3.h" diff --git a/modules/gdnative/godot/godot_basis.h b/modules/gdnative/godot/basis.h index a096a8cc08..79b2b45fdd 100644 --- a/modules/gdnative/godot/godot_basis.h +++ b/modules/gdnative/godot/basis.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_basis.h */ +/* basis.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,15 +36,18 @@ extern "C" { #include <stdint.h> +#define GODOT_BASIS_SIZE 36 + #ifndef GODOT_CORE_API_GODOT_BASIS_TYPE_DEFINED #define GODOT_CORE_API_GODOT_BASIS_TYPE_DEFINED -typedef struct godot_basis { - uint8_t _dont_touch_that[36]; +typedef struct { + uint8_t _dont_touch_that[GODOT_BASIS_SIZE]; } godot_basis; #endif -#include "../godot.h" -#include "godot_vector3.h" +#include "gdnative.h" +#include "quat.h" +#include "vector3.h" void GDAPI godot_basis_new_with_rows(godot_basis *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis); void GDAPI godot_basis_new_with_axis_and_angle(godot_basis *r_dest, const godot_vector3 *p_axis, const godot_real p_phi); diff --git a/modules/gdnative/godot/godot_color.cpp b/modules/gdnative/godot/color.cpp index 6dedf2ab10..eac966ca1f 100644 --- a/modules/gdnative/godot/godot_color.cpp +++ b/modules/gdnative/godot/color.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_color.cpp */ +/* color.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_color.h" +#include "color.h" #include "core/variant.h" #include "core/color.h" diff --git a/modules/gdnative/godot/godot_color.h b/modules/gdnative/godot/color.h index 10dc228b1c..77e709fbe3 100644 --- a/modules/gdnative/godot/godot_color.h +++ b/modules/gdnative/godot/color.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_color.h */ +/* color.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,15 +36,17 @@ extern "C" { #include <stdint.h> +#define GODOT_COLOR_SIZE 16 + #ifndef GODOT_CORE_API_GODOT_COLOR_TYPE_DEFINED #define GODOT_CORE_API_GODOT_COLOR_TYPE_DEFINED -typedef struct godot_color { - uint8_t _dont_touch_that[16]; +typedef struct { + uint8_t _dont_touch_that[GODOT_COLOR_SIZE]; } godot_color; #endif -#include "../godot.h" -#include "godot_string.h" +#include "gdnative.h" +#include "string.h" void GDAPI godot_color_new_rgba(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b, const godot_real p_a); void GDAPI godot_color_new_rgb(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b); diff --git a/modules/gdnative/godot/godot_dictionary.cpp b/modules/gdnative/godot/dictionary.cpp index a14a86248b..1c0761edfd 100644 --- a/modules/gdnative/godot/godot_dictionary.cpp +++ b/modules/gdnative/godot/dictionary.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_dictionary.cpp */ +/* dictionary.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_dictionary.h" +#include "dictionary.h" #include "core/variant.h" #include "core/dictionary.h" diff --git a/modules/gdnative/godot/godot_dictionary.h b/modules/gdnative/godot/dictionary.h index 4ded0d38da..a08deb27df 100644 --- a/modules/gdnative/godot/godot_dictionary.h +++ b/modules/gdnative/godot/dictionary.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_dictionary.h */ +/* dictionary.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,16 +36,18 @@ extern "C" { #include <stdint.h> +#define GODOT_DICTIONARY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_DICTIONARY_TYPE_DEFINED #define GODOT_CORE_API_GODOT_DICTIONARY_TYPE_DEFINED -typedef struct godot_dictionary { - uint8_t _dont_touch_that[8]; +typedef struct { + uint8_t _dont_touch_that[GODOT_DICTIONARY_SIZE]; } godot_dictionary; #endif -#include "../godot.h" -#include "godot_array.h" -#include "godot_variant.h" +#include "array.h" +#include "gdnative.h" +#include "variant.h" void GDAPI godot_dictionary_new(godot_dictionary *r_dest); void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src); diff --git a/modules/gdnative/godot.cpp b/modules/gdnative/godot/gdnative.cpp index 4dbb72bba1..7b94b75a52 100644 --- a/modules/gdnative/godot.cpp +++ b/modules/gdnative/godot/gdnative.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot.cpp */ +/* gdnative.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,13 +27,13 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot.h" +#include "gdnative.h" #include "class_db.h" #include "error_macros.h" #include "gdnative.h" -#include "global_config.h" #include "global_constants.h" +#include "project_settings.h" #include "variant.h" #ifdef __cplusplus @@ -79,13 +79,6 @@ void _api_anchor() { _variant_api_anchor(); } -extern "C++" { -template <class a, class b> -_FORCE_INLINE_ a memcast(b v) { - return *((a *)&v); -} -} - void GDAPI godot_object_destroy(godot_object *p_o) { memdelete((Object *)p_o); } @@ -93,7 +86,7 @@ void GDAPI godot_object_destroy(godot_object *p_o) { // Singleton API godot_object GDAPI *godot_global_get_singleton(char *p_name) { - return (godot_object *)GlobalConfig::get_singleton()->get_singleton_object(String(p_name)); + return (godot_object *)ProjectSettings::get_singleton()->get_singleton_object(String(p_name)); } // result shouldn't be freed // MethodBind API @@ -142,65 +135,6 @@ void GDAPI godot_method_bind_varcall(godot_method_bind *p_method_bind) } */ -// Script API - -void GDAPI godot_script_register_class(const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func) { - GDNativeLibrary *library = GDNativeLibrary::get_currently_initialized_library(); - if (!library) { - ERR_EXPLAIN("Attempt to register script after initializing library!"); - ERR_FAIL(); - } - library->_register_script(p_name, p_base, p_create_func, p_destroy_func); -} - -void GDAPI godot_script_register_tool_class(const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func) { - GDNativeLibrary *library = GDNativeLibrary::get_currently_initialized_library(); - if (!library) { - ERR_EXPLAIN("Attempt to register script after initializing library!"); - ERR_FAIL(); - } - library->_register_tool_script(p_name, p_base, p_create_func, p_destroy_func); -} - -void GDAPI godot_script_register_method(const char *p_name, const char *p_function_name, godot_method_attributes p_attr, godot_instance_method p_method) { - GDNativeLibrary *library = GDNativeLibrary::get_currently_initialized_library(); - if (!library) { - ERR_EXPLAIN("Attempt to register script after initializing library!"); - ERR_FAIL(); - } - library->_register_script_method(p_name, p_function_name, p_attr, p_method, MethodInfo()); -} - -void GDAPI godot_script_register_property(const char *p_name, const char *p_path, godot_property_attributes *p_attr, godot_property_set_func p_set_func, godot_property_get_func p_get_func) { - GDNativeLibrary *library = GDNativeLibrary::get_currently_initialized_library(); - if (!library) { - ERR_EXPLAIN("Attempt to register script after initializing library!"); - ERR_FAIL(); - } - - library->_register_script_property(p_name, p_path, p_attr, p_set_func, p_get_func); -} - -void GDAPI godot_script_register_signal(const char *p_name, const godot_signal *p_signal) { - GDNativeLibrary *library = GDNativeLibrary::get_currently_initialized_library(); - if (!library) { - ERR_EXPLAIN("Attempt to register script after initializing library!"); - ERR_FAIL(); - } - - library->_register_script_signal(p_name, p_signal); -} - -void GDAPI *godot_native_get_userdata(godot_object *p_instance) { - Object *instance = (Object *)p_instance; - if (!instance) - return NULL; - if (instance->get_script_instance() && instance->get_script_instance()->get_language() == GDNativeScriptLanguage::get_singleton()) { - return ((GDNativeInstance *)instance->get_script_instance())->get_userdata(); - } - return NULL; -} - godot_class_constructor GDAPI godot_get_class_constructor(const char *p_classname) { ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(StringName(p_classname)); if (class_info) diff --git a/modules/gdnative/godot/gdnative.h b/modules/gdnative/godot/gdnative.h new file mode 100644 index 0000000000..4b79706b52 --- /dev/null +++ b/modules/gdnative/godot/gdnative.h @@ -0,0 +1,298 @@ +/*************************************************************************/ +/* gdnative.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef GODOT_GDNATIVE_H +#define GODOT_GDNATIVE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef GDAPI_BUILT_IN +#define GDAPI_EXPORT +#endif + +#ifdef _WIN32 +#if defined(GDAPI_EXPORT) +#define GDCALLINGCONV +#define GDAPI __declspec(dllexport) GDCALLINGCONV +#else +#define GDCALLINGCONV +#define GDAPI __declspec(dllimport) GDCALLINGCONV +#endif +#elif defined(__APPLE__) +#include "TargetConditionals.h" +#if TARGET_OS_IPHONE +#define GDCALLINGCONV +#define GDAPI +#elif TARGET_OS_MAC +#define GDCALLINGCONV __attribute__((sysv_abi)) +#define GDAPI GDCALLINGCONV +#endif +#else +#define GDCALLINGCONV __attribute__((sysv_abi)) +#define GDAPI GDCALLINGCONV +#endif + +// This is for libraries *using* the header, NOT GODOT EXPOSING STUFF!! +#ifdef _WIN32 +#define GDN_EXPORT __declspec(dllexport) +#else +#define GDN_EXPORT +#endif + +#include <stdbool.h> +#include <stdint.h> + +#define GODOT_API_VERSION 1 + +////// Error + +typedef enum { + GODOT_OK, + GODOT_FAILED, ///< Generic fail error + GODOT_ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable + GODOT_ERR_UNCONFIGURED, ///< The object being used hasnt been properly set up yet + GODOT_ERR_UNAUTHORIZED, ///< Missing credentials for requested resource + GODOT_ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5) + GODOT_ERR_OUT_OF_MEMORY, ///< Out of memory + GODOT_ERR_FILE_NOT_FOUND, + GODOT_ERR_FILE_BAD_DRIVE, + GODOT_ERR_FILE_BAD_PATH, + GODOT_ERR_FILE_NO_PERMISSION, // (10) + GODOT_ERR_FILE_ALREADY_IN_USE, + GODOT_ERR_FILE_CANT_OPEN, + GODOT_ERR_FILE_CANT_WRITE, + GODOT_ERR_FILE_CANT_READ, + GODOT_ERR_FILE_UNRECOGNIZED, // (15) + GODOT_ERR_FILE_CORRUPT, + GODOT_ERR_FILE_MISSING_DEPENDENCIES, + GODOT_ERR_FILE_EOF, + GODOT_ERR_CANT_OPEN, ///< Can't open a resource/socket/file + GODOT_ERR_CANT_CREATE, // (20) + GODOT_ERR_QUERY_FAILED, + GODOT_ERR_ALREADY_IN_USE, + GODOT_ERR_LOCKED, ///< resource is locked + GODOT_ERR_TIMEOUT, + GODOT_ERR_CANT_CONNECT, // (25) + GODOT_ERR_CANT_RESOLVE, + GODOT_ERR_CONNECTION_ERROR, + GODOT_ERR_CANT_AQUIRE_RESOURCE, + GODOT_ERR_CANT_FORK, + GODOT_ERR_INVALID_DATA, ///< Data passed is invalid (30) + GODOT_ERR_INVALID_PARAMETER, ///< Parameter passed is invalid + GODOT_ERR_ALREADY_EXISTS, ///< When adding, item already exists + GODOT_ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, it item does not exist + GODOT_ERR_DATABASE_CANT_READ, ///< database is full + GODOT_ERR_DATABASE_CANT_WRITE, ///< database is full (35) + GODOT_ERR_COMPILATION_FAILED, + GODOT_ERR_METHOD_NOT_FOUND, + GODOT_ERR_LINK_FAILED, + GODOT_ERR_SCRIPT_FAILED, + GODOT_ERR_CYCLIC_LINK, // (40) + GODOT_ERR_INVALID_DECLARATION, + GODOT_ERR_DUPLICATE_SYMBOL, + GODOT_ERR_PARSE_ERROR, + GODOT_ERR_BUSY, + GODOT_ERR_SKIP, // (45) + GODOT_ERR_HELP, ///< user requested help!! + GODOT_ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior. + GODOT_ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames + GODOT_ERR_OMFG_THIS_IS_VERY_VERY_BAD, ///< shit happens, has never been used, though + GODOT_ERR_WTF = GODOT_ERR_OMFG_THIS_IS_VERY_VERY_BAD ///< short version of the above +} godot_error; + +////// bool + +typedef bool godot_bool; + +#define GODOT_TRUE 1 +#define GODOT_FALSE 0 + +/////// int + +typedef int godot_int; + +/////// real + +typedef float godot_real; + +/////// Object (forward declared) +typedef void godot_object; + +/////// Brute force forward declarations for the rest +/* +typedef struct godot_variant godot_variant; +typedef struct godot_string godot_string; +typedef struct godot_vector2 godot_vector2; +typedef struct godot_rect2 godot_rect2; +typedef struct godot_vector3 godot_vector3; +typedef struct godot_transform2d godot_transform2d; +typedef struct godot_plane godot_plane; +typedef struct godot_quat godot_quat; +typedef struct godot_rect3 godot_rect3; +typedef struct godot_basis godot_basis; +typedef struct godot_transform godot_transform; +typedef struct godot_color godot_color; +typedef struct godot_node_path godot_node_path; +typedef struct godot_rid godot_rid; +typedef struct godot_dictionary godot_dictionary; +typedef struct godot_array godot_array; +typedef struct godot_pool_byte_array godot_pool_byte_array; +typedef struct godot_pool_int_array godot_pool_int_array; +typedef struct godot_pool_real_array godot_pool_real_array; +typedef struct godot_pool_string_array godot_pool_string_array; +typedef struct godot_pool_vector2_array godot_pool_vector2_array; +typedef struct godot_pool_vector3_array godot_pool_vector3_array; +typedef struct godot_pool_color_array godot_pool_color_array; +*/ +/////// String + +#include "string.h" + +////// Vector2 + +#include "vector2.h" + +////// Rect2 + +#include "rect2.h" + +////// Vector3 + +#include "vector3.h" + +////// Transform2D + +#include "transform2d.h" + +/////// Plane + +#include "plane.h" + +/////// Quat + +#include "quat.h" + +/////// Rect3 + +#include "rect3.h" + +/////// Basis + +#include "basis.h" + +/////// Transform + +#include "transform.h" + +/////// Color + +#include "color.h" + +/////// NodePath + +#include "node_path.h" + +/////// RID + +#include "rid.h" + +/////// Dictionary + +#include "dictionary.h" + +/////// Array + +#include "array.h" + +// single API file for Pool*Array +#include "pool_arrays.h" + +void GDAPI godot_object_destroy(godot_object *p_o); + +////// Variant + +#include "variant.h" + +////// Singleton API + +godot_object GDAPI *godot_global_get_singleton(char *p_name); // result shouldn't be freed + +////// MethodBind API + +typedef struct { + uint8_t _dont_touch_that[1]; // TODO +} godot_method_bind; + +godot_method_bind GDAPI *godot_method_bind_get_method(const char *p_classname, const char *p_methodname); +void GDAPI godot_method_bind_ptrcall(godot_method_bind *p_method_bind, godot_object *p_instance, const void **p_args, void *p_ret); +godot_variant GDAPI godot_method_bind_call(godot_method_bind *p_method_bind, godot_object *p_instance, const godot_variant **p_args, const int p_arg_count, godot_variant_call_error *p_call_error); +////// Script API + +typedef struct { + godot_bool in_editor; + uint64_t core_api_hash; + uint64_t editor_api_hash; + uint64_t no_api_hash; +} godot_gdnative_init_options; + +typedef struct { + godot_bool in_editor; +} godot_gdnative_terminate_options; + +// Calling convention? +typedef godot_object *(*godot_class_constructor)(); + +godot_class_constructor GDAPI godot_get_class_constructor(const char *p_classname); + +godot_dictionary GDAPI godot_get_global_constants(); + +////// GDNative procedure types +typedef void (*godot_gdnative_init_fn)(godot_gdnative_init_options *); +typedef void (*godot_gdnative_terminate_fn)(godot_gdnative_terminate_options *); +typedef godot_variant (*godot_gdnative_procedure_fn)(void *, godot_array *); + +////// System Functions + +//using these will help Godot track how much memory is in use in debug mode +void GDAPI *godot_alloc(int p_bytes); +void GDAPI *godot_realloc(void *p_ptr, int p_bytes); +void GDAPI godot_free(void *p_ptr); + +//print using Godot's error handler list +void GDAPI godot_print_error(const char *p_description, const char *p_function, const char *p_file, int p_line); +void GDAPI godot_print_warning(const char *p_description, const char *p_function, const char *p_file, int p_line); +void GDAPI godot_print(const godot_string *p_message); + +#ifdef __cplusplus +} +#endif + +#endif // GODOT_C_H diff --git a/modules/gdnative/godot/icon.png.import b/modules/gdnative/godot/icon.png.import new file mode 100644 index 0000000000..27920124f9 --- /dev/null +++ b/modules/gdnative/godot/icon.png.import @@ -0,0 +1,23 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon.png-aa47d037a37fb38b3b7e7828e4eec407.stex" + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +stream=false +size_limit=0 +detect_3d=true diff --git a/modules/gdnative/godot/godot_node_path.cpp b/modules/gdnative/godot/node_path.cpp index c8eacd05af..a9edbc8352 100644 --- a/modules/gdnative/godot/godot_node_path.cpp +++ b/modules/gdnative/godot/node_path.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_node_path.cpp */ +/* node_path.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_node_path.h" +#include "node_path.h" #include "core/variant.h" #include "core/path_db.h" diff --git a/modules/gdnative/godot/godot_node_path.h b/modules/gdnative/godot/node_path.h index b0c9d44859..06955a052e 100644 --- a/modules/gdnative/godot/godot_node_path.h +++ b/modules/gdnative/godot/node_path.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_node_path.h */ +/* node_path.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,15 +36,17 @@ extern "C" { #include <stdint.h> +#define GODOT_NODE_PATH_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_NODE_PATH_TYPE_DEFINED #define GODOT_CORE_API_GODOT_NODE_PATH_TYPE_DEFINED -typedef struct godot_node_path { - uint8_t _dont_touch_that[8]; +typedef struct { + uint8_t _dont_touch_that[GODOT_NODE_PATH_SIZE]; } godot_node_path; #endif -#include "../godot.h" -#include "godot_string.h" +#include "gdnative.h" +#include "string.h" void GDAPI godot_node_path_new(godot_node_path *r_dest, const godot_string *p_from); void GDAPI godot_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src); diff --git a/modules/gdnative/godot/godot_plane.cpp b/modules/gdnative/godot/plane.cpp index 68adbd4a98..e9e659e5da 100644 --- a/modules/gdnative/godot/godot_plane.cpp +++ b/modules/gdnative/godot/plane.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_plane.cpp */ +/* plane.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_plane.h" +#include "plane.h" #include "core/variant.h" #include "core/math/plane.h" diff --git a/modules/gdnative/godot/godot_plane.h b/modules/gdnative/godot/plane.h index cfc955f277..e9e3b71e03 100644 --- a/modules/gdnative/godot/godot_plane.h +++ b/modules/gdnative/godot/plane.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_plane.h */ +/* plane.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,15 +36,17 @@ extern "C" { #include <stdint.h> +#define GODOT_PLANE_SIZE 16 + #ifndef GODOT_CORE_API_GODOT_PLANE_TYPE_DEFINED #define GODOT_CORE_API_GODOT_PLANE_TYPE_DEFINED -typedef struct godot_plane { - uint8_t _dont_touch_that[16]; +typedef struct { + uint8_t _dont_touch_that[GODOT_PLANE_SIZE]; } godot_plane; #endif -#include "../godot.h" -#include "godot_vector3.h" +#include "gdnative.h" +#include "vector3.h" void GDAPI godot_plane_new_with_reals(godot_plane *r_dest, const godot_real p_a, const godot_real p_b, const godot_real p_c, const godot_real p_d); void GDAPI godot_plane_new_with_vectors(godot_plane *r_dest, const godot_vector3 *p_v1, const godot_vector3 *p_v2, const godot_vector3 *p_v3); diff --git a/modules/gdnative/godot/godot_pool_arrays.cpp b/modules/gdnative/godot/pool_arrays.cpp index ea9aceea81..6a6ee0f126 100644 --- a/modules/gdnative/godot/godot_pool_arrays.cpp +++ b/modules/gdnative/godot/pool_arrays.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_pool_arrays.cpp */ +/* pool_arrays.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,11 +27,15 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_pool_arrays.h" +#include "pool_arrays.h" #include "array.h" +#include "core/variant.h" #include "dvector.h" -#include "variant.h" + +#include "core/color.h" +#include "core/math/math_2d.h" +#include "core/math/vector3.h" #ifdef __cplusplus extern "C" { diff --git a/modules/gdnative/godot/godot_pool_arrays.h b/modules/gdnative/godot/pool_arrays.h index a794d03f01..1e2916cea9 100644 --- a/modules/gdnative/godot/godot_pool_arrays.h +++ b/modules/gdnative/godot/pool_arrays.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_pool_arrays.h */ +/* pool_arrays.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -38,66 +38,87 @@ extern "C" { /////// PoolByteArray +#define GODOT_POOL_BYTE_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_BYTE_ARRAY_TYPE_DEFINED -typedef struct godot_pool_byte_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_BYTE_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_BYTE_ARRAY_SIZE]; } godot_pool_byte_array; #endif /////// PoolIntArray +#define GODOT_POOL_INT_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_INT_ARRAY_TYPE_DEFINED -typedef struct godot_pool_int_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_INT_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_INT_ARRAY_SIZE]; } godot_pool_int_array; #endif /////// PoolRealArray +#define GODOT_POOL_REAL_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_REAL_ARRAY_TYPE_DEFINED -typedef struct godot_pool_real_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_REAL_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_REAL_ARRAY_SIZE]; } godot_pool_real_array; #endif /////// PoolStringArray +#define GODOT_POOL_STRING_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_STRING_ARRAY_TYPE_DEFINED -typedef struct godot_pool_string_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_STRING_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_STRING_ARRAY_SIZE]; } godot_pool_string_array; #endif /////// PoolVector2Array +#define GODOT_POOL_VECTOR2_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_VECTOR2_ARRAY_TYPE_DEFINED -typedef struct godot_pool_vector2_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_VECTOR2_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_VECTOR2_ARRAY_SIZE]; } godot_pool_vector2_array; #endif /////// PoolVector3Array +#define GODOT_POOL_VECTOR3_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_VECTOR3_ARRAY_TYPE_DEFINED -typedef struct godot_pool_vector3_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_VECTOR3_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_VECTOR3_ARRAY_SIZE]; } godot_pool_vector3_array; #endif /////// PoolColorArray +#define GODOT_POOL_COLOR_ARRAY_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_POOL_COLOR_ARRAY_TYPE_DEFINED -typedef struct godot_pool_color_array { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_POOL_COLOR_ARRAY_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_POOL_COLOR_ARRAY_SIZE]; } godot_pool_color_array; #endif -#include "godot_array.h" -#include "godot_color.h" -#include "godot_vector2.h" -#include "godot_vector3.h" +#include "array.h" +#include "color.h" +#include "vector2.h" +#include "vector3.h" -#include "../godot.h" +#include "gdnative.h" // byte diff --git a/modules/gdnative/godot/godot_quat.cpp b/modules/gdnative/godot/quat.cpp index 7235e4fcec..6800f7fc7e 100644 --- a/modules/gdnative/godot/godot_quat.cpp +++ b/modules/gdnative/godot/quat.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_quat.cpp */ +/* quat.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_quat.h" +#include "quat.h" #include "core/variant.h" #include "core/math/quat.h" diff --git a/modules/gdnative/godot/godot_quat.h b/modules/gdnative/godot/quat.h index 2289b6cbab..b86cbacc62 100644 --- a/modules/gdnative/godot/godot_quat.h +++ b/modules/gdnative/godot/quat.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_quat.h */ +/* quat.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,15 +36,17 @@ extern "C" { #include <stdint.h> +#define GODOT_QUAT_SIZE 16 + #ifndef GODOT_CORE_API_GODOT_QUAT_TYPE_DEFINED #define GODOT_CORE_API_GODOT_QUAT_TYPE_DEFINED -typedef struct godot_quat { - uint8_t _dont_touch_that[16]; +typedef struct { + uint8_t _dont_touch_that[GODOT_QUAT_SIZE]; } godot_quat; #endif -#include "../godot.h" -#include "godot_vector3.h" +#include "gdnative.h" +#include "vector3.h" void GDAPI godot_quat_new(godot_quat *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_z, const godot_real p_w); void GDAPI godot_quat_new_with_axis_angle(godot_quat *r_dest, const godot_vector3 *p_axis, const godot_real p_angle); diff --git a/modules/gdnative/godot/godot_rect2.cpp b/modules/gdnative/godot/rect2.cpp index 0e456ea3ba..830d7bb496 100644 --- a/modules/gdnative/godot/godot_rect2.cpp +++ b/modules/gdnative/godot/rect2.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_rect2.cpp */ +/* rect2.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_rect2.h" +#include "rect2.h" #include "core/variant.h" #include "core/math/math_2d.h" diff --git a/modules/gdnative/godot/godot_rect2.h b/modules/gdnative/godot/rect2.h index 488a1204f7..7b6613d9dd 100644 --- a/modules/gdnative/godot/godot_rect2.h +++ b/modules/gdnative/godot/rect2.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_rect2.h */ +/* rect2.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -43,8 +43,8 @@ typedef struct godot_rect2 { } godot_rect2; #endif -#include "../godot.h" -#include "godot_vector2.h" +#include "gdnative.h" +#include "vector2.h" void GDAPI godot_rect2_new_with_position_and_size(godot_rect2 *r_dest, const godot_vector2 *p_pos, const godot_vector2 *p_size); void GDAPI godot_rect2_new(godot_rect2 *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_width, const godot_real p_height); diff --git a/modules/gdnative/godot/godot_rect3.cpp b/modules/gdnative/godot/rect3.cpp index e524fa8463..0fabba5b7b 100644 --- a/modules/gdnative/godot/godot_rect3.cpp +++ b/modules/gdnative/godot/rect3.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_rect3.cpp */ +/* rect3.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_rect3.h" +#include "rect3.h" #include "core/variant.h" #include "core/math/rect3.h" diff --git a/modules/gdnative/godot/godot_rect3.h b/modules/gdnative/godot/rect3.h index 9e9a49ac27..638d89f76f 100644 --- a/modules/gdnative/godot/godot_rect3.h +++ b/modules/gdnative/godot/rect3.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_rect3.h */ +/* rect3.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,16 +36,18 @@ extern "C" { #include <stdint.h> +#define GODOT_RECT3_SIZE 24 + #ifndef GODOT_CORE_API_GODOT_RECT3_TYPE_DEFINED #define GODOT_CORE_API_GODOT_RECT3_TYPE_DEFINED -typedef struct godot_rect3 { - uint8_t _dont_touch_that[24]; +typedef struct { + uint8_t _dont_touch_that[GODOT_RECT3_SIZE]; } godot_rect3; #endif -#include "../godot.h" -#include "godot_plane.h" -#include "godot_vector3.h" +#include "gdnative.h" +#include "plane.h" +#include "vector3.h" void GDAPI godot_rect3_new(godot_rect3 *r_dest, const godot_vector3 *p_pos, const godot_vector3 *p_size); diff --git a/modules/gdnative/godot/godot_rid.cpp b/modules/gdnative/godot/rid.cpp index 343c004bff..2b724e554d 100644 --- a/modules/gdnative/godot/godot_rid.cpp +++ b/modules/gdnative/godot/rid.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_rid.cpp */ +/* rid.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_rid.h" +#include "rid.h" #include "core/variant.h" #include "core/resource.h" diff --git a/modules/gdnative/godot/godot_rid.h b/modules/gdnative/godot/rid.h index 25dc8d965e..92e101fd2e 100644 --- a/modules/gdnative/godot/godot_rid.h +++ b/modules/gdnative/godot/rid.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_rid.h */ +/* rid.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,14 +36,16 @@ extern "C" { #include <stdint.h> +#define GODOT_RID_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_RID_TYPE_DEFINED #define GODOT_CORE_API_GODOT_RID_TYPE_DEFINED -typedef struct godot_rid { - uint8_t _dont_touch_that[8]; +typedef struct { + uint8_t _dont_touch_that[GODOT_RID_SIZE]; } godot_rid; #endif -#include "../godot.h" +#include "gdnative.h" void GDAPI godot_rid_new(godot_rid *r_dest); diff --git a/modules/gdnative/godot/godot_string.cpp b/modules/gdnative/godot/string.cpp index 679011e715..e54ef3655f 100644 --- a/modules/gdnative/godot/godot_string.cpp +++ b/modules/gdnative/godot/string.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_string.cpp */ +/* string.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_string.h" +#include "string.h" #include "string_db.h" #include "ustring.h" diff --git a/modules/gdnative/godot/godot_string.h b/modules/gdnative/godot/string.h index df848abb76..d4d6d6c1d0 100644 --- a/modules/gdnative/godot/godot_string.h +++ b/modules/gdnative/godot/string.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_string.h */ +/* string.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -37,13 +37,16 @@ extern "C" { #include <stdint.h> #include <wchar.h> +#define GODOT_STRING_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED -typedef struct godot_string { - uint8_t _dont_touch_that[8]; +#define GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_STRING_SIZE]; } godot_string; #endif -#include "../godot.h" +#include "gdnative.h" void GDAPI godot_string_new(godot_string *r_dest); void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src); diff --git a/modules/gdnative/godot/godot_transform.cpp b/modules/gdnative/godot/transform.cpp index eb9e1e207b..e566ed0b6e 100644 --- a/modules/gdnative/godot/godot_transform.cpp +++ b/modules/gdnative/godot/transform.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_transform.cpp */ +/* transform.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_transform.h" +#include "transform.h" #include "core/variant.h" #include "core/math/transform.h" diff --git a/modules/gdnative/godot/godot_transform.h b/modules/gdnative/godot/transform.h index ee87e1d33f..d14190ec49 100644 --- a/modules/gdnative/godot/godot_transform.h +++ b/modules/gdnative/godot/transform.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_transform.h */ +/* transform.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,17 +36,19 @@ extern "C" { #include <stdint.h> +#define GODOT_TRANSFORM_SIZE 48 + #ifndef GODOT_CORE_API_GODOT_TRANSFORM_TYPE_DEFINED #define GODOT_CORE_API_GODOT_TRANSFORM_TYPE_DEFINED -typedef struct godot_transform { - uint8_t _dont_touch_that[48]; +typedef struct { + uint8_t _dont_touch_that[GODOT_TRANSFORM_SIZE]; } godot_transform; #endif -#include "../godot.h" -#include "godot_basis.h" -#include "godot_variant.h" -#include "godot_vector3.h" +#include "basis.h" +#include "gdnative.h" +#include "variant.h" +#include "vector3.h" void GDAPI godot_transform_new_with_axis_origin(godot_transform *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis, const godot_vector3 *p_origin); void GDAPI godot_transform_new(godot_transform *r_dest, const godot_basis *p_basis, const godot_vector3 *p_origin); diff --git a/modules/gdnative/godot/godot_transform2d.cpp b/modules/gdnative/godot/transform2d.cpp index bdb5476f7d..01db3f7ae0 100644 --- a/modules/gdnative/godot/godot_transform2d.cpp +++ b/modules/gdnative/godot/transform2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_transform2d.cpp */ +/* transform2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_transform2d.h" +#include "transform2d.h" #include "core/variant.h" #include "core/math/math_2d.h" diff --git a/modules/gdnative/godot/godot_transform2d.h b/modules/gdnative/godot/transform2d.h index c375e90af7..7171e528f2 100644 --- a/modules/gdnative/godot/godot_transform2d.h +++ b/modules/gdnative/godot/transform2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_transform2d.h */ +/* transform2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,16 +36,18 @@ extern "C" { #include <stdint.h> +#define GODOT_TRANSFORM2D_SIZE 24 + #ifndef GODOT_CORE_API_GODOT_TRANSFORM2D_TYPE_DEFINED #define GODOT_CORE_API_GODOT_TRANSFORM2D_TYPE_DEFINED -typedef struct godot_transform2d { - uint8_t _dont_touch_that[24]; +typedef struct { + uint8_t _dont_touch_that[GODOT_TRANSFORM2D_SIZE]; } godot_transform2d; #endif -#include "../godot.h" -#include "godot_variant.h" -#include "godot_vector2.h" +#include "gdnative.h" +#include "variant.h" +#include "vector2.h" void GDAPI godot_transform2d_new(godot_transform2d *r_dest, const godot_real p_rot, const godot_vector2 *p_pos); void GDAPI godot_transform2d_new_axis_origin(godot_transform2d *r_dest, const godot_vector2 *p_x_axis, const godot_vector2 *p_y_axis, const godot_vector2 *p_origin); diff --git a/modules/gdnative/godot/godot_variant.cpp b/modules/gdnative/godot/variant.cpp index c9607fb21a..3469058cfd 100644 --- a/modules/gdnative/godot/godot_variant.cpp +++ b/modules/gdnative/godot/variant.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_variant.cpp */ +/* variant.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_variant.h" +#include "variant.h" #include "core/variant.h" #ifdef __cplusplus diff --git a/modules/gdnative/godot/godot_variant.h b/modules/gdnative/godot/variant.h index 9b6d287249..b56d5824fa 100644 --- a/modules/gdnative/godot/godot_variant.h +++ b/modules/gdnative/godot/variant.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_variant.h */ +/* variant.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,9 +36,12 @@ extern "C" { #include <stdint.h> +#define GODOT_VARIANT_SIZE 24 + #ifndef GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED -typedef struct godot_variant { - uint8_t _dont_touch_that[24]; +#define GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED +typedef struct { + uint8_t _dont_touch_that[GODOT_VARIANT_SIZE]; } godot_variant; #endif @@ -96,25 +99,25 @@ typedef struct godot_variant_call_error { godot_variant_type expected; } godot_variant_call_error; -#include "godot_array.h" -#include "godot_basis.h" -#include "godot_color.h" -#include "godot_dictionary.h" -#include "godot_node_path.h" -#include "godot_plane.h" -#include "godot_pool_arrays.h" -#include "godot_quat.h" -#include "godot_rect2.h" -#include "godot_rect3.h" -#include "godot_rid.h" -#include "godot_string.h" -#include "godot_transform.h" -#include "godot_transform2d.h" -#include "godot_variant.h" -#include "godot_vector2.h" -#include "godot_vector3.h" - -#include "../godot.h" +#include "array.h" +#include "basis.h" +#include "color.h" +#include "dictionary.h" +#include "node_path.h" +#include "plane.h" +#include "pool_arrays.h" +#include "quat.h" +#include "rect2.h" +#include "rect3.h" +#include "rid.h" +#include "string.h" +#include "transform.h" +#include "transform2d.h" +#include "variant.h" +#include "vector2.h" +#include "vector3.h" + +#include "gdnative.h" godot_variant_type GDAPI godot_variant_get_type(const godot_variant *p_v); diff --git a/modules/gdnative/godot/godot_vector2.cpp b/modules/gdnative/godot/vector2.cpp index 0ced800872..6b40e31a89 100644 --- a/modules/gdnative/godot/godot_vector2.cpp +++ b/modules/gdnative/godot/vector2.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_vector2.cpp */ +/* vector2.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_vector2.h" +#include "vector2.h" #include "core/variant.h" #include "core/math/math_2d.h" diff --git a/modules/gdnative/godot/godot_vector2.h b/modules/gdnative/godot/vector2.h index 9c7590fedf..9934ddadbb 100644 --- a/modules/gdnative/godot/godot_vector2.h +++ b/modules/gdnative/godot/vector2.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_vector2.h */ +/* vector2.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,14 +36,16 @@ extern "C" { #include <stdint.h> +#define GODOT_VECTOR2_SIZE 8 + #ifndef GODOT_CORE_API_GODOT_VECTOR2_TYPE_DEFINED #define GODOT_CORE_API_GODOT_VECTOR2_TYPE_DEFINED -typedef struct godot_vector2 { - uint8_t _dont_touch_that[8]; +typedef struct { + uint8_t _dont_touch_that[GODOT_VECTOR2_SIZE]; } godot_vector2; #endif -#include "../godot.h" +#include "gdnative.h" void GDAPI godot_vector2_new(godot_vector2 *r_dest, const godot_real p_x, const godot_real p_y); diff --git a/modules/gdnative/godot/godot_vector3.cpp b/modules/gdnative/godot/vector3.cpp index adca0d1e2a..904cdad9d0 100644 --- a/modules/gdnative/godot/godot_vector3.cpp +++ b/modules/gdnative/godot/vector3.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_vector3.cpp */ +/* vector3.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -27,7 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "godot_vector3.h" +#include "vector3.h" #include "core/variant.h" #include "core/vector.h" diff --git a/modules/gdnative/godot/godot_vector3.h b/modules/gdnative/godot/vector3.h index 98d9ddf6ac..b5f8d0f49a 100644 --- a/modules/gdnative/godot/godot_vector3.h +++ b/modules/gdnative/godot/vector3.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_vector3.h */ +/* vector3.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,15 +36,17 @@ extern "C" { #include <stdint.h> +#define GODOT_VECTOR3_SIZE 12 + #ifndef GODOT_CORE_API_GODOT_VECTOR3_TYPE_DEFINED #define GODOT_CORE_API_GODOT_VECTOR3_TYPE_DEFINED -typedef struct godot_vector3 { - uint8_t _dont_touch_that[12]; +typedef struct { + uint8_t _dont_touch_that[GODOT_VECTOR3_SIZE]; } godot_vector3; #endif -#include "../godot.h" -#include "godot_basis.h" +#include "basis.h" +#include "gdnative.h" typedef enum { GODOT_VECTOR3_AXIS_X, diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index 8789c9a267..20ac1ecc0c 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -33,34 +33,46 @@ #include "io/resource_loader.h" #include "io/resource_saver.h" -GDNativeScriptLanguage *script_language_gdn = NULL; -ResourceFormatLoaderGDNativeScript *resource_loader_gdn = NULL; -ResourceFormatSaverGDNativeScript *resource_saver_gdn = NULL; -//ResourceFormatLoaderDLLibrary *resource_loader_dllib=NULL; +#include "core/os/os.h" -void register_gdnative_types() { +godot_variant cb_standard_varcall(void *handle, godot_string *p_procedure, godot_array *p_args) { + if (handle == NULL) { + ERR_PRINT("No valid library handle, can't call standard varcall procedure"); + godot_variant ret; + godot_variant_new_nil(&ret); + return ret; + } - ClassDB::register_class<GDNativeLibrary>(); - ClassDB::register_class<GDNativeScript>(); + void *library_proc; + Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( + handle, + *(String *)p_procedure, + library_proc); + if (err != OK) { + ERR_PRINT((String("GDNative procedure \"" + *(String *)p_procedure) + "\" does not exists and can't be called").utf8().get_data()); + godot_variant ret; + godot_variant_new_nil(&ret); + return ret; + } + + godot_gdnative_procedure_fn proc; + proc = (godot_gdnative_procedure_fn)library_proc; - script_language_gdn = memnew(GDNativeScriptLanguage); - ScriptServer::register_language(script_language_gdn); - resource_loader_gdn = memnew(ResourceFormatLoaderGDNativeScript); - ResourceLoader::add_resource_format_loader(resource_loader_gdn); - resource_saver_gdn = memnew(ResourceFormatSaverGDNativeScript); - ResourceSaver::add_resource_format_saver(resource_saver_gdn); + return proc(NULL, p_args); } -void unregister_gdnative_types() { +GDNativeCallRegistry *GDNativeCallRegistry::singleton; - ScriptServer::unregister_language(script_language_gdn); +void register_gdnative_types() { - if (script_language_gdn) - memdelete(script_language_gdn); + ClassDB::register_class<GDNativeLibrary>(); + ClassDB::register_class<GDNative>(); + + GDNativeCallRegistry::singleton = memnew(GDNativeCallRegistry); - if (resource_loader_gdn) - memdelete(resource_loader_gdn); + GDNativeCallRegistry::singleton->register_native_call_type("standard_varcall", cb_standard_varcall); +} - if (resource_saver_gdn) - memdelete(resource_saver_gdn); +void unregister_gdnative_types() { + memdelete(GDNativeCallRegistry::singleton); } diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index adf3c8edc4..c88889767c 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -30,8 +30,8 @@ #include "editor/editor_settings.h" #include "gd_compiler.h" #include "gd_script.h" -#include "global_config.h" #include "os/file_access.h" +#include "project_settings.h" #ifdef TOOLS_ENABLED #include "editor/editor_file_system.h" #include "editor/editor_settings.h" @@ -638,7 +638,7 @@ static bool _guess_expression_type(GDCompletionContext &context, const GDParser: String which = arg1.get_slice("/", 2); if (which != "") { List<PropertyInfo> props; - GlobalConfig::get_singleton()->get_property_list(&props); + ProjectSettings::get_singleton()->get_property_list(&props); //print_line("find singleton"); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { @@ -650,7 +650,7 @@ static bool _guess_expression_type(GDCompletionContext &context, const GDParser: String name = s.get_slice("/", 1); //print_line("name: "+name+", which: "+which); if (name == which) { - String script = GlobalConfig::get_singleton()->get(s); + String script = ProjectSettings::get_singleton()->get(s); if (!script.begins_with("res://")) { script = "res://" + script; @@ -1105,7 +1105,7 @@ static bool _guess_identifier_type(GDCompletionContext &context, int p_line, con //autoloads as singletons List<PropertyInfo> props; - GlobalConfig::get_singleton()->get_property_list(&props); + ProjectSettings::get_singleton()->get_property_list(&props); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { @@ -1115,7 +1115,7 @@ static bool _guess_identifier_type(GDCompletionContext &context, int p_line, con String name = s.get_slice("/", 1); if (name == String(p_identifier)) { - String path = GlobalConfig::get_singleton()->get(s); + String path = ProjectSettings::get_singleton()->get(s); if (path.begins_with("*")) { String script = path.substr(1, path.length()); @@ -1334,8 +1334,8 @@ static void _find_identifiers(GDCompletionContext &context, int p_line, bool p_o static const char *_type_names[Variant::VARIANT_MAX] = { "null", "bool", "int", "float", "String", "Vector2", "Rect2", "Vector3", "Transform2D", "Plane", "Quat", "AABB", "Basis", "Transform", - "Color", "NodePath", "RID", "Object", "Dictionary", "Array", "RawArray", "IntArray", "FloatArray", "StringArray", - "Vector2Array", "Vector3Array", "ColorArray" + "Color", "NodePath", "RID", "Object", "Dictionary", "Array", "PoolByteArray", "PoolIntArray", "PoolRealArray", "PoolStringArray", + "PoolVector2Array", "PoolVector3Array", "PoolColorArray" }; for (int i = 0; i < Variant::VARIANT_MAX; i++) { @@ -1344,7 +1344,7 @@ static void _find_identifiers(GDCompletionContext &context, int p_line, bool p_o //autoload singletons List<PropertyInfo> props; - GlobalConfig::get_singleton()->get_property_list(&props); + ProjectSettings::get_singleton()->get_property_list(&props); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { @@ -1352,7 +1352,7 @@ static void _find_identifiers(GDCompletionContext &context, int p_line, bool p_o if (!s.begins_with("autoload/")) continue; String name = s.get_slice("/", 1); - String path = GlobalConfig::get_singleton()->get(s); + String path = ProjectSettings::get_singleton()->get(s); if (path.begins_with("*")) { result.insert(name); } @@ -1685,7 +1685,7 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N if (p_argidx == 0 && (String(p_method) == "get_node" || String(p_method) == "has_node") && ClassDB::is_parent_class(id.obj_type, "Node")) { List<PropertyInfo> props; - GlobalConfig::get_singleton()->get_property_list(&props); + ProjectSettings::get_singleton()->get_property_list(&props); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { @@ -2660,7 +2660,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol //guess in autoloads as singletons List<PropertyInfo> props; - GlobalConfig::get_singleton()->get_property_list(&props); + ProjectSettings::get_singleton()->get_property_list(&props); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { @@ -2670,7 +2670,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol String name = s.get_slice("/", 1); if (name == String(p_symbol)) { - String path = GlobalConfig::get_singleton()->get(s); + String path = ProjectSettings::get_singleton()->get(s); if (path.begins_with("*")) { String script = path.substr(1, path.length()); diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index a361971ef4..8bc3b24a5e 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -1587,13 +1587,13 @@ MethodInfo GDFunctions::get_info(Function p_func) { } break; case TO_JSON: { - MethodInfo mi("to_json", PropertyInfo(Variant::NIL, "var:Variant")); + MethodInfo mi("to_json", PropertyInfo(Variant::NIL, "var")); mi.return_val.type = Variant::STRING; return mi; } break; case HASH: { - MethodInfo mi("hash", PropertyInfo(Variant::NIL, "var:Variant")); + MethodInfo mi("hash", PropertyInfo(Variant::NIL, "var")); mi.return_val.type = Variant::INT; return mi; } break; diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index 75029a020b..ba0413a5a9 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -185,8 +185,8 @@ void GDParser::_make_completable_call(int p_arg) { bool GDParser::_get_completable_identifier(CompletionType p_type, StringName &identifier) { identifier = StringName(); - if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) { - identifier = tokenizer->get_token_identifier(); + if (tokenizer->is_token_literal()) { + identifier = tokenizer->get_token_literal(); tokenizer->advance(); } if (tokenizer->get_token() == GDTokenizer::TK_CURSOR) { @@ -201,8 +201,8 @@ bool GDParser::_get_completable_identifier(CompletionType p_type, StringName &id completion_ident_is_call = false; tokenizer->advance(); - if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) { - identifier = identifier.operator String() + tokenizer->get_token_identifier().operator String(); + if (tokenizer->is_token_literal()) { + identifier = identifier.operator String() + tokenizer->get_token_literal().operator String(); tokenizer->advance(); } @@ -296,17 +296,6 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool need_identifier = false; } break; - case GDTokenizer::TK_IDENTIFIER: { - if (!need_identifier) { - done = true; - break; - } - - path += String(tokenizer->get_token_identifier()); - tokenizer->advance(); - need_identifier = false; - - } break; case GDTokenizer::TK_OP_DIV: { if (need_identifier) { @@ -320,6 +309,13 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool } break; default: { + // Instead of checking for TK_IDENTIFIER, we check with is_token_literal, as this allows us to use match/sync/etc. as a name + if (need_identifier && tokenizer->is_token_literal()) { + path += String(tokenizer->get_token_literal()); + tokenizer->advance(); + need_identifier = false; + } + done = true; break; } @@ -585,7 +581,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool cn->value = Variant::get_numeric_constant_value(bi_type, identifier); expr = cn; - } else if (tokenizer->get_token(1) == GDTokenizer::TK_PARENTHESIS_OPEN && (tokenizer->get_token() == GDTokenizer::TK_BUILT_IN_TYPE || tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER || tokenizer->get_token() == GDTokenizer::TK_BUILT_IN_FUNC)) { + } else if (tokenizer->get_token(1) == GDTokenizer::TK_PARENTHESIS_OPEN && tokenizer->is_token_literal()) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name //function or constructor OperatorNode *op = alloc_node<OperatorNode>(); @@ -627,7 +624,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool expr = op; - } else if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) { + } else if (tokenizer->is_token_literal(0, true)) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name //identifier (reference) const ClassNode *cln = current_class; @@ -827,10 +825,11 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool if (expecting == DICT_EXPECT_KEY) { - if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1) == GDTokenizer::TK_OP_ASSIGN) { + if (tokenizer->is_token_literal() && tokenizer->get_token(1) == GDTokenizer::TK_OP_ASSIGN) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name //lua style identifier, easier to write ConstantNode *cn = alloc_node<ConstantNode>(); - cn->value = tokenizer->get_token_identifier(); + cn->value = tokenizer->get_token_literal(); key = cn; tokenizer->advance(2); expecting = DICT_EXPECT_VALUE; @@ -870,7 +869,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool expr = dict; - } else if (tokenizer->get_token() == GDTokenizer::TK_PERIOD && (tokenizer->get_token(1) == GDTokenizer::TK_IDENTIFIER || tokenizer->get_token(1) == GDTokenizer::TK_CURSOR) && tokenizer->get_token(2) == GDTokenizer::TK_PARENTHESIS_OPEN) { + } else if (tokenizer->get_token() == GDTokenizer::TK_PERIOD && (tokenizer->is_token_literal(1) || tokenizer->get_token(1) == GDTokenizer::TK_CURSOR) && tokenizer->get_token(2) == GDTokenizer::TK_PARENTHESIS_OPEN) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name // parent call tokenizer->advance(); //goto identifier @@ -922,7 +922,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool //indexing using "." - if (tokenizer->get_token(1) != GDTokenizer::TK_CURSOR && tokenizer->get_token(1) != GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1) != GDTokenizer::TK_BUILT_IN_FUNC) { + if (tokenizer->get_token(1) != GDTokenizer::TK_CURSOR && !tokenizer->is_token_literal(1)) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name _set_error("Expected identifier as member"); return NULL; } else if (tokenizer->get_token(2) == GDTokenizer::TK_PARENTHESIS_OPEN) { @@ -2341,12 +2342,12 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) { //variale declaration and (eventual) initialization tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected identifier for local variable name."); return; } - StringName n = tokenizer->get_token_identifier(); + StringName n = tokenizer->get_token_literal(); tokenizer->advance(); if (current_function) { for (int i = 0; i < current_function->arguments.size(); i++) { @@ -2571,7 +2572,7 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) { tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("identifier expected after 'for'"); } @@ -3108,7 +3109,7 @@ void GDParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); //var before the identifier is allowed } - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected identifier for argument."); return; @@ -3260,7 +3261,7 @@ void GDParser::_parse_class(ClassNode *p_class) { case GDTokenizer::TK_PR_SIGNAL: { tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal()) { _set_error("Expected identifier after 'signal'."); return; } @@ -3282,7 +3283,7 @@ void GDParser::_parse_class(ClassNode *p_class) { break; } - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected identifier in signal argument."); return; } @@ -3847,13 +3848,13 @@ void GDParser::_parse_class(ClassNode *p_class) { bool onready = tokenizer->get_token(-1) == GDTokenizer::TK_PR_ONREADY; tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected identifier for member variable name."); return; } - member.identifier = tokenizer->get_token_identifier(); + member.identifier = tokenizer->get_token_literal(); member.expression = NULL; member._export.name = member.identifier; member.line = tokenizer->get_token_line(); @@ -3979,11 +3980,11 @@ void GDParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() != GDTokenizer::TK_COMMA) { //just comma means using only getter - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { - _set_error("Expected identifier for setter function after 'notify'."); + if (!tokenizer->is_token_literal()) { + _set_error("Expected identifier for setter function after 'setget'."); } - member.setter = tokenizer->get_token_identifier(); + member.setter = tokenizer->get_token_literal(); tokenizer->advance(); } @@ -3992,11 +3993,11 @@ void GDParser::_parse_class(ClassNode *p_class) { //there is a getter tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal()) { _set_error("Expected identifier for getter function after ','."); } - member.getter = tokenizer->get_token_identifier(); + member.getter = tokenizer->get_token_literal(); tokenizer->advance(); } } @@ -4014,13 +4015,13 @@ void GDParser::_parse_class(ClassNode *p_class) { ClassNode::Constant constant; tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected name (identifier) for constant."); return; } - constant.identifier = tokenizer->get_token_identifier(); + constant.identifier = tokenizer->get_token_literal(); tokenizer->advance(); if (tokenizer->get_token() != GDTokenizer::TK_OP_ASSIGN) { @@ -4061,8 +4062,8 @@ void GDParser::_parse_class(ClassNode *p_class) { Dictionary enum_dict; tokenizer->advance(); - if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) { - enum_name = tokenizer->get_token_identifier(); + if (tokenizer->is_token_literal(0, true)) { + enum_name = tokenizer->get_token_literal(); tokenizer->advance(); } if (tokenizer->get_token() != GDTokenizer::TK_CURLY_BRACKET_OPEN) { @@ -4079,7 +4080,7 @@ void GDParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); break; // End of enum - } else if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + } else if (!tokenizer->is_token_literal(0, true)) { if (tokenizer->get_token() == GDTokenizer::TK_EOF) { _set_error("Unexpected end of file."); @@ -4088,10 +4089,10 @@ void GDParser::_parse_class(ClassNode *p_class) { } return; - } else { // tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER + } else { // tokenizer->is_token_literal(0, true) ClassNode::Constant constant; - constant.identifier = tokenizer->get_token_identifier(); + constant.identifier = tokenizer->get_token_literal(); tokenizer->advance(); diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 0afb6ac179..fe87433a89 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -29,11 +29,11 @@ /*************************************************************************/ #include "gd_script.h" #include "gd_compiler.h" -#include "global_config.h" #include "global_constants.h" #include "io/file_access_encrypted.h" #include "os/file_access.h" #include "os/os.h" +#include "project_settings.h" /////////////////////////// @@ -1454,9 +1454,9 @@ void GDScriptLanguage::init() { //populate singletons - List<GlobalConfig::Singleton> singletons; - GlobalConfig::get_singleton()->get_singletons(&singletons); - for (List<GlobalConfig::Singleton>::Element *E = singletons.front(); E; E = E->next()) { + List<ProjectSettings::Singleton> singletons; + ProjectSettings::get_singleton()->get_singletons(&singletons); + for (List<ProjectSettings::Singleton>::Element *E = singletons.front(); E; E = E->next()) { _add_global(E->get().name, E->get().ptr); } diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index f4e0cc8e29..5803046185 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -130,12 +130,222 @@ const char *GDTokenizer::token_names[TK_MAX] = { "Cursor" }; +struct _bit { + Variant::Type type; + const char *text; +}; +//built in types + +static const _bit _type_list[] = { + //types + { Variant::BOOL, "bool" }, + { Variant::INT, "int" }, + { Variant::REAL, "float" }, + { Variant::STRING, "String" }, + { Variant::VECTOR2, "Vector2" }, + { Variant::RECT2, "Rect2" }, + { Variant::TRANSFORM2D, "Transform2D" }, + { Variant::VECTOR3, "Vector3" }, + { Variant::RECT3, "Rect3" }, + { Variant::PLANE, "Plane" }, + { Variant::QUAT, "Quat" }, + { Variant::BASIS, "Basis" }, + { Variant::TRANSFORM, "Transform" }, + { Variant::COLOR, "Color" }, + { Variant::_RID, "RID" }, + { Variant::OBJECT, "Object" }, + { Variant::NODE_PATH, "NodePath" }, + { Variant::DICTIONARY, "Dictionary" }, + { Variant::ARRAY, "Array" }, + { Variant::POOL_BYTE_ARRAY, "PoolByteArray" }, + { Variant::POOL_INT_ARRAY, "PoolIntArray" }, + { Variant::POOL_REAL_ARRAY, "PoolRealArray" }, + { Variant::POOL_STRING_ARRAY, "PoolStringArray" }, + { Variant::POOL_VECTOR2_ARRAY, "PoolVector2Array" }, + { Variant::POOL_VECTOR3_ARRAY, "PoolVector3Array" }, + { Variant::POOL_COLOR_ARRAY, "PoolColorArray" }, + { Variant::VARIANT_MAX, NULL }, +}; + +struct _kws { + GDTokenizer::Token token; + const char *text; +}; + +static const _kws _keyword_list[] = { + //ops + { GDTokenizer::TK_OP_IN, "in" }, + { GDTokenizer::TK_OP_NOT, "not" }, + { GDTokenizer::TK_OP_OR, "or" }, + { GDTokenizer::TK_OP_AND, "and" }, + //func + { GDTokenizer::TK_PR_FUNCTION, "func" }, + { GDTokenizer::TK_PR_CLASS, "class" }, + { GDTokenizer::TK_PR_EXTENDS, "extends" }, + { GDTokenizer::TK_PR_IS, "is" }, + { GDTokenizer::TK_PR_ONREADY, "onready" }, + { GDTokenizer::TK_PR_TOOL, "tool" }, + { GDTokenizer::TK_PR_STATIC, "static" }, + { GDTokenizer::TK_PR_EXPORT, "export" }, + { GDTokenizer::TK_PR_SETGET, "setget" }, + { GDTokenizer::TK_PR_VAR, "var" }, + { GDTokenizer::TK_PR_PRELOAD, "preload" }, + { GDTokenizer::TK_PR_ASSERT, "assert" }, + { GDTokenizer::TK_PR_YIELD, "yield" }, + { GDTokenizer::TK_PR_SIGNAL, "signal" }, + { GDTokenizer::TK_PR_BREAKPOINT, "breakpoint" }, + { GDTokenizer::TK_PR_REMOTE, "remote" }, + { GDTokenizer::TK_PR_MASTER, "master" }, + { GDTokenizer::TK_PR_SLAVE, "slave" }, + { GDTokenizer::TK_PR_SYNC, "sync" }, + { GDTokenizer::TK_PR_CONST, "const" }, + { GDTokenizer::TK_PR_ENUM, "enum" }, + //controlflow + { GDTokenizer::TK_CF_IF, "if" }, + { GDTokenizer::TK_CF_ELIF, "elif" }, + { GDTokenizer::TK_CF_ELSE, "else" }, + { GDTokenizer::TK_CF_FOR, "for" }, + { GDTokenizer::TK_CF_WHILE, "while" }, + { GDTokenizer::TK_CF_DO, "do" }, + { GDTokenizer::TK_CF_SWITCH, "switch" }, + { GDTokenizer::TK_CF_CASE, "case" }, + { GDTokenizer::TK_CF_BREAK, "break" }, + { GDTokenizer::TK_CF_CONTINUE, "continue" }, + { GDTokenizer::TK_CF_RETURN, "return" }, + { GDTokenizer::TK_CF_MATCH, "match" }, + { GDTokenizer::TK_CF_PASS, "pass" }, + { GDTokenizer::TK_SELF, "self" }, + { GDTokenizer::TK_CONST_PI, "PI" }, + { GDTokenizer::TK_WILDCARD, "_" }, + { GDTokenizer::TK_CONST_INF, "INF" }, + { GDTokenizer::TK_CONST_NAN, "NAN" }, + { GDTokenizer::TK_ERROR, NULL } +}; + const char *GDTokenizer::get_token_name(Token p_token) { ERR_FAIL_INDEX_V(p_token, TK_MAX, "<error>"); return token_names[p_token]; } +bool GDTokenizer::is_token_literal(int p_offset, bool variable_safe) const { + switch (get_token(p_offset)) { + // Can always be literal: + case TK_IDENTIFIER: + + case TK_PR_ONREADY: + case TK_PR_TOOL: + case TK_PR_STATIC: + case TK_PR_EXPORT: + case TK_PR_SETGET: + case TK_PR_SIGNAL: + case TK_PR_REMOTE: + case TK_PR_MASTER: + case TK_PR_SLAVE: + case TK_PR_SYNC: + return true; + + // Literal for non-variables only: + case TK_BUILT_IN_TYPE: + case TK_BUILT_IN_FUNC: + + case TK_OP_IN: + //case TK_OP_NOT: + //case TK_OP_OR: + //case TK_OP_AND: + + case TK_PR_CLASS: + case TK_PR_CONST: + case TK_PR_ENUM: + case TK_PR_PRELOAD: + case TK_PR_FUNCTION: + case TK_PR_EXTENDS: + case TK_PR_ASSERT: + case TK_PR_YIELD: + case TK_PR_VAR: + + case TK_CF_IF: + case TK_CF_ELIF: + case TK_CF_ELSE: + case TK_CF_FOR: + case TK_CF_WHILE: + case TK_CF_DO: + case TK_CF_SWITCH: + case TK_CF_CASE: + case TK_CF_BREAK: + case TK_CF_CONTINUE: + case TK_CF_RETURN: + case TK_CF_MATCH: + case TK_CF_PASS: + case TK_SELF: + case TK_CONST_PI: + case TK_WILDCARD: + case TK_CONST_INF: + case TK_CONST_NAN: + case TK_ERROR: + return !variable_safe; + + case TK_CONSTANT: { + switch (get_token_constant(p_offset).get_type()) { + case Variant::NIL: + case Variant::BOOL: + return true; + default: + return false; + } + } + default: + return false; + } +} + +StringName GDTokenizer::get_token_literal(int p_offset) const { + Token token = get_token(p_offset); + switch (token) { + case TK_IDENTIFIER: + return get_token_identifier(p_offset); + case TK_BUILT_IN_TYPE: { + Variant::Type type = get_token_type(p_offset); + int idx = 0; + + while (_type_list[idx].text) { + if (type == _type_list[idx].type) { + return _type_list[idx].text; + } + idx++; + } + } break; // Shouldn't get here, stuff happens + case TK_BUILT_IN_FUNC: + return GDFunctions::get_func_name(get_token_built_in_func(p_offset)); + case TK_CONSTANT: { + const Variant value = get_token_constant(p_offset); + + switch (value.get_type()) { + case Variant::NIL: + return "null"; + case Variant::BOOL: + return value ? "true" : "false"; + default: {} + } + } + case TK_OP_AND: + case TK_OP_OR: + break; // Don't get into default, since they can be non-literal + default: { + int idx = 0; + + while (_keyword_list[idx].text) { + if (token == _keyword_list[idx].token) { + return _keyword_list[idx].text; + } + idx++; + } + } + } + ERR_EXPLAIN("Failed to get token literal"); + ERR_FAIL_V(""); +} + static bool _is_text_char(CharType c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; @@ -779,51 +989,14 @@ void GDTokenizerText::_advance() { bool found = false; - struct _bit { - Variant::Type type; - const char *text; - }; - //built in types - - static const _bit type_list[] = { - //types - { Variant::BOOL, "bool" }, - { Variant::INT, "int" }, - { Variant::REAL, "float" }, - { Variant::STRING, "String" }, - { Variant::VECTOR2, "Vector2" }, - { Variant::RECT2, "Rect2" }, - { Variant::TRANSFORM2D, "Transform2D" }, - { Variant::VECTOR3, "Vector3" }, - { Variant::RECT3, "Rect3" }, - { Variant::PLANE, "Plane" }, - { Variant::QUAT, "Quat" }, - { Variant::BASIS, "Basis" }, - { Variant::TRANSFORM, "Transform" }, - { Variant::COLOR, "Color" }, - { Variant::_RID, "RID" }, - { Variant::OBJECT, "Object" }, - { Variant::NODE_PATH, "NodePath" }, - { Variant::DICTIONARY, "Dictionary" }, - { Variant::ARRAY, "Array" }, - { Variant::POOL_BYTE_ARRAY, "PoolByteArray" }, - { Variant::POOL_INT_ARRAY, "PoolIntArray" }, - { Variant::POOL_REAL_ARRAY, "PoolFloatArray" }, - { Variant::POOL_STRING_ARRAY, "PoolStringArray" }, - { Variant::POOL_VECTOR2_ARRAY, "PoolVector2Array" }, - { Variant::POOL_VECTOR3_ARRAY, "PoolVector3Array" }, - { Variant::POOL_COLOR_ARRAY, "PoolColorArray" }, - { Variant::VARIANT_MAX, NULL }, - }; - { int idx = 0; - while (type_list[idx].text) { + while (_type_list[idx].text) { - if (str == type_list[idx].text) { - _make_type(type_list[idx].type); + if (str == _type_list[idx].text) { + _make_type(_type_list[idx].type); found = true; break; } @@ -844,74 +1017,18 @@ void GDTokenizerText::_advance() { break; } } - - //keywor } if (!found) { - - struct _kws { - Token token; - const char *text; - }; - - static const _kws keyword_list[] = { - //ops - { TK_OP_IN, "in" }, - { TK_OP_NOT, "not" }, - { TK_OP_OR, "or" }, - { TK_OP_AND, "and" }, - //func - { TK_PR_FUNCTION, "func" }, - { TK_PR_CLASS, "class" }, - { TK_PR_EXTENDS, "extends" }, - { TK_PR_IS, "is" }, - { TK_PR_ONREADY, "onready" }, - { TK_PR_TOOL, "tool" }, - { TK_PR_STATIC, "static" }, - { TK_PR_EXPORT, "export" }, - { TK_PR_SETGET, "setget" }, - { TK_PR_VAR, "var" }, - { TK_PR_PRELOAD, "preload" }, - { TK_PR_ASSERT, "assert" }, - { TK_PR_YIELD, "yield" }, - { TK_PR_SIGNAL, "signal" }, - { TK_PR_BREAKPOINT, "breakpoint" }, - { TK_PR_REMOTE, "remote" }, - { TK_PR_MASTER, "master" }, - { TK_PR_SLAVE, "slave" }, - { TK_PR_SYNC, "sync" }, - { TK_PR_CONST, "const" }, - { TK_PR_ENUM, "enum" }, - //controlflow - { TK_CF_IF, "if" }, - { TK_CF_ELIF, "elif" }, - { TK_CF_ELSE, "else" }, - { TK_CF_FOR, "for" }, - { TK_CF_WHILE, "while" }, - { TK_CF_DO, "do" }, - { TK_CF_SWITCH, "switch" }, - { TK_CF_CASE, "case" }, - { TK_CF_BREAK, "break" }, - { TK_CF_CONTINUE, "continue" }, - { TK_CF_RETURN, "return" }, - { TK_CF_MATCH, "match" }, - { TK_CF_PASS, "pass" }, - { TK_SELF, "self" }, - { TK_CONST_PI, "PI" }, - { TK_WILDCARD, "_" }, - { TK_CONST_INF, "INF" }, - { TK_CONST_NAN, "NAN" }, - { TK_ERROR, NULL } - }; + //keyword int idx = 0; found = false; - while (keyword_list[idx].text) { + while (_keyword_list[idx].text) { - if (str == keyword_list[idx].text) { - _make_token(keyword_list[idx].token); + if (str == _keyword_list[idx].text) { + _make_token(_keyword_list[idx].token); found = true; break; } @@ -992,6 +1109,7 @@ const Variant &GDTokenizerText::get_token_constant(int p_offset) const { ERR_FAIL_COND_V(tk_rb[ofs].type != TK_CONSTANT, tk_rb[0].constant); return tk_rb[ofs].constant; } + StringName GDTokenizerText::get_token_identifier(int p_offset) const { ERR_FAIL_COND_V(p_offset <= -MAX_LOOKAHEAD, StringName()); diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h index c051176097..4e868301a3 100644 --- a/modules/gdscript/gd_tokenizer.h +++ b/modules/gdscript/gd_tokenizer.h @@ -149,6 +149,9 @@ protected: public: static const char *get_token_name(Token p_token); + bool is_token_literal(int p_offset = 0, bool variable_safe = false) const; + StringName get_token_literal(int p_offset = 0) const; + virtual const Variant &get_token_constant(int p_offset = 0) const = 0; virtual Token get_token(int p_offset = 0) const = 0; virtual StringName get_token_identifier(int p_offset = 0) const = 0; diff --git a/modules/nativescript/SCsub b/modules/nativescript/SCsub new file mode 100644 index 0000000000..e980e40e8e --- /dev/null +++ b/modules/nativescript/SCsub @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +Import('env') + +mod_env = env.Clone() +mod_env.add_source_files(env.modules_sources, "*.cpp") +mod_env.Append(CPPPATH='#modules/gdnative') +mod_env.Append(CPPFLAGS=['-DGDAPI_BUILT_IN']) + +Export('mod_env') diff --git a/modules/gdnative/api_generator.cpp b/modules/nativescript/api_generator.cpp index d5f22ee7a3..47162bfc49 100644 --- a/modules/gdnative/api_generator.cpp +++ b/modules/nativescript/api_generator.cpp @@ -32,8 +32,8 @@ #ifdef TOOLS_ENABLED #include "class_db.h" -#include "core/global_config.h" #include "core/global_constants.h" +#include "core/project_settings.h" #include "os/file_access.h" // helper stuff @@ -150,7 +150,7 @@ List<ClassAPI> generate_c_api_classes() { if (name.begins_with("_")) { name.remove(0); } - class_api.is_singleton = GlobalConfig::get_singleton()->has_singleton(name); + class_api.is_singleton = ProjectSettings::get_singleton()->has_singleton(name); } class_api.is_instanciable = !class_api.is_singleton && ClassDB::can_instance(class_name); @@ -268,6 +268,8 @@ List<ClassAPI> generate_c_api_classes() { method_api.method_name = method_api.method_name.get_slice(":", 0); } else if (m->get().return_val.type != Variant::NIL) { method_api.return_type = m->get().return_val.hint == PROPERTY_HINT_RESOURCE_TYPE ? m->get().return_val.hint_string : Variant::get_type_name(m->get().return_val.type); + } else if (m->get().return_val.name != "") { + method_api.return_type = m->get().return_val.name; } else { method_api.return_type = "void"; } diff --git a/modules/gdnative/api_generator.h b/modules/nativescript/api_generator.h index a108d7a7b6..a108d7a7b6 100644 --- a/modules/gdnative/api_generator.h +++ b/modules/nativescript/api_generator.h diff --git a/modules/nativescript/config.py b/modules/nativescript/config.py new file mode 100644 index 0000000000..9f57b9bb74 --- /dev/null +++ b/modules/nativescript/config.py @@ -0,0 +1,8 @@ + + +def can_build(platform): + return True + + +def configure(env): + env.use_ptrcall = True diff --git a/modules/nativescript/godot_nativescript.cpp b/modules/nativescript/godot_nativescript.cpp new file mode 100644 index 0000000000..453cee3a18 --- /dev/null +++ b/modules/nativescript/godot_nativescript.cpp @@ -0,0 +1,205 @@ +/*************************************************************************/ +/* godot_nativescript.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "godot_nativescript.h" + +#include "nativescript.h" + +#include "class_db.h" +#include "error_macros.h" +#include "gdnative.h" +#include "global_constants.h" +#include "project_settings.h" +#include "variant.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern "C" void _native_script_hook() { +} + +#define NSL NativeScriptLanguage::get_singleton() + +// Script API + +void GDAPI godot_nativescript_register_class(void *p_gdnative_handle, const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func) { + + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc> *classes = &NSL->library_classes[*s]; + + NativeScriptDesc desc; + + desc.create_func = p_create_func; + desc.destroy_func = p_destroy_func; + desc.is_tool = false; + + desc.base = p_base; + + if (classes->has(p_base)) { + desc.base_data = &(*classes)[p_base]; + desc.base_native_type = desc.base_data->base_native_type; + } else { + desc.base_data = NULL; + desc.base_native_type = p_base; + } + + classes->insert(p_name, desc); +} + +void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func) { + + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc> *classes = &NSL->library_classes[*s]; + + NativeScriptDesc desc; + + desc.create_func = p_create_func; + desc.destroy_func = p_destroy_func; + desc.is_tool = true; + desc.base = p_base; + + if (classes->has(p_base)) { + desc.base_data = &(*classes)[p_base]; + desc.base_native_type = desc.base_data->base_native_type; + } else { + desc.base_data = NULL; + desc.base_native_type = p_base; + } + + classes->insert(p_name, desc); +} + +void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_method_attributes p_attr, godot_instance_method p_method) { + + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempt to register method on non-existant class!"); + ERR_FAIL(); + } + + NativeScriptDesc::Method method; + method.method = p_method; + method.rpc_mode = p_attr.rpc_type; + method.info = MethodInfo(p_function_name); + + E->get().methods.insert(p_function_name, method); +} + +void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_property_attributes *p_attr, godot_property_set_func p_set_func, godot_property_get_func p_get_func) { + + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempt to register method on non-existant class!"); + ERR_FAIL(); + } + + NativeScriptDesc::Property property; + property.default_value = *(Variant *)&p_attr->default_value; + property.getter = p_get_func; + property.rset_mode = p_attr->rset_type; + property.setter = p_set_func; + property.info = PropertyInfo((Variant::Type)p_attr->type, + p_path, + (PropertyHint)p_attr->hint, + *(String *)&p_attr->hint_string, + (PropertyUsageFlags)p_attr->usage); + + E->get().properties.insert(p_path, property); +} + +void GDAPI godot_nativescript_register_signal(void *p_gdnative_handle, const char *p_name, const godot_signal *p_signal) { + + String *s = (String *)p_gdnative_handle; + + Map<StringName, NativeScriptDesc>::Element *E = NSL->library_classes[*s].find(p_name); + + if (!E) { + ERR_EXPLAIN("Attempt to register method on non-existant class!"); + ERR_FAIL(); + } + + List<PropertyInfo> args; + Vector<Variant> default_args; + + for (int i = 0; i < p_signal->num_args; i++) { + PropertyInfo info; + + godot_signal_argument arg = p_signal->args[i]; + + info.hint = (PropertyHint)arg.hint; + info.hint_string = *(String *)&arg.hint_string; + info.name = *(String *)&arg.name; + info.type = (Variant::Type)arg.type; + info.usage = (PropertyUsageFlags)arg.usage; + + args.push_back(info); + } + + for (int i = 0; i < p_signal->num_default_args; i++) { + Variant *v; + godot_signal_argument attrib = p_signal->args[i]; + + v = (Variant *)&attrib.default_value; + + default_args.push_back(*v); + } + + MethodInfo method_info; + method_info.name = *(String *)&p_signal->name; + method_info.arguments = args; + method_info.default_arguments = default_args; + + NativeScriptDesc::Signal signal; + signal.signal = method_info; + + E->get().signals_.insert(*(String *)&p_signal->name, signal); +} + +void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance) { + Object *instance = (Object *)p_instance; + if (!instance) + return NULL; + if (instance->get_script_instance() && instance->get_script_instance()->get_language() == NativeScriptLanguage::get_singleton()) { + return ((NativeScriptInstance *)instance->get_script_instance())->userdata; + } + return NULL; +} + +#ifdef __cplusplus +} +#endif diff --git a/modules/gdnative/godot.h b/modules/nativescript/godot_nativescript.h index 1d86998291..cfd445086b 100644 --- a/modules/gdnative/godot.h +++ b/modules/nativescript/godot_nativescript.h @@ -27,8 +27,10 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GODOT_C_H -#define GODOT_C_H +#ifndef GODOT_NATIVESCRIPT_H +#define GODOT_NATIVESCRIPT_H + +#include <godot/gdnative.h> #ifdef __cplusplus extern "C" { @@ -70,203 +72,7 @@ extern "C" { #include <stdbool.h> #include <stdint.h> -#define GODOT_API_VERSION 1 - -////// Error - -typedef enum godot_error { - GODOT_OK, - GODOT_FAILED, ///< Generic fail error - GODOT_ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable - GODOT_ERR_UNCONFIGURED, ///< The object being used hasnt been properly set up yet - GODOT_ERR_UNAUTHORIZED, ///< Missing credentials for requested resource - GODOT_ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5) - GODOT_ERR_OUT_OF_MEMORY, ///< Out of memory - GODOT_ERR_FILE_NOT_FOUND, - GODOT_ERR_FILE_BAD_DRIVE, - GODOT_ERR_FILE_BAD_PATH, - GODOT_ERR_FILE_NO_PERMISSION, // (10) - GODOT_ERR_FILE_ALREADY_IN_USE, - GODOT_ERR_FILE_CANT_OPEN, - GODOT_ERR_FILE_CANT_WRITE, - GODOT_ERR_FILE_CANT_READ, - GODOT_ERR_FILE_UNRECOGNIZED, // (15) - GODOT_ERR_FILE_CORRUPT, - GODOT_ERR_FILE_MISSING_DEPENDENCIES, - GODOT_ERR_FILE_EOF, - GODOT_ERR_CANT_OPEN, ///< Can't open a resource/socket/file - GODOT_ERR_CANT_CREATE, // (20) - GODOT_ERR_QUERY_FAILED, - GODOT_ERR_ALREADY_IN_USE, - GODOT_ERR_LOCKED, ///< resource is locked - GODOT_ERR_TIMEOUT, - GODOT_ERR_CANT_CONNECT, // (25) - GODOT_ERR_CANT_RESOLVE, - GODOT_ERR_CONNECTION_ERROR, - GODOT_ERR_CANT_AQUIRE_RESOURCE, - GODOT_ERR_CANT_FORK, - GODOT_ERR_INVALID_DATA, ///< Data passed is invalid (30) - GODOT_ERR_INVALID_PARAMETER, ///< Parameter passed is invalid - GODOT_ERR_ALREADY_EXISTS, ///< When adding, item already exists - GODOT_ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, it item does not exist - GODOT_ERR_DATABASE_CANT_READ, ///< database is full - GODOT_ERR_DATABASE_CANT_WRITE, ///< database is full (35) - GODOT_ERR_COMPILATION_FAILED, - GODOT_ERR_METHOD_NOT_FOUND, - GODOT_ERR_LINK_FAILED, - GODOT_ERR_SCRIPT_FAILED, - GODOT_ERR_CYCLIC_LINK, // (40) - GODOT_ERR_INVALID_DECLARATION, - GODOT_ERR_DUPLICATE_SYMBOL, - GODOT_ERR_PARSE_ERROR, - GODOT_ERR_BUSY, - GODOT_ERR_SKIP, // (45) - GODOT_ERR_HELP, ///< user requested help!! - GODOT_ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior. - GODOT_ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames - GODOT_ERR_OMFG_THIS_IS_VERY_VERY_BAD, ///< shit happens, has never been used, though - GODOT_ERR_WTF = GODOT_ERR_OMFG_THIS_IS_VERY_VERY_BAD ///< short version of the above -} godot_error; - -////// bool - -typedef bool godot_bool; - -#define GODOT_TRUE 1 -#define GODOT_FALSE 0 - -/////// int - -typedef int godot_int; - -/////// real - -typedef float godot_real; - -/////// Object (forward declared) -typedef void godot_object; - -/////// Brute force forward declarations for the rest -typedef struct godot_variant godot_variant; -typedef struct godot_string godot_string; -typedef struct godot_vector2 godot_vector2; -typedef struct godot_rect2 godot_rect2; -typedef struct godot_vector3 godot_vector3; -typedef struct godot_transform2d godot_transform2d; -typedef struct godot_plane godot_plane; -typedef struct godot_quat godot_quat; -typedef struct godot_rect3 godot_rect3; -typedef struct godot_basis godot_basis; -typedef struct godot_transform godot_transform; -typedef struct godot_color godot_color; -typedef struct godot_node_path godot_node_path; -typedef struct godot_rid godot_rid; -typedef struct godot_dictionary godot_dictionary; -typedef struct godot_array godot_array; -typedef struct godot_pool_byte_array godot_pool_byte_array; -typedef struct godot_pool_int_array godot_pool_int_array; -typedef struct godot_pool_real_array godot_pool_real_array; -typedef struct godot_pool_string_array godot_pool_string_array; -typedef struct godot_pool_vector2_array godot_pool_vector2_array; -typedef struct godot_pool_vector3_array godot_pool_vector3_array; -typedef struct godot_pool_color_array godot_pool_color_array; - -/////// String - -#include "godot/godot_string.h" - -////// Vector2 - -#include "godot/godot_vector2.h" - -////// Rect2 - -#include "godot/godot_rect2.h" - -////// Vector3 - -#include "godot/godot_vector3.h" - -////// Transform2D - -#include "godot/godot_transform2d.h" - -/////// Plane - -#include "godot/godot_plane.h" - -/////// Quat - -#include "godot/godot_quat.h" - -/////// Rect3 - -#include "godot/godot_rect3.h" - -/////// Basis - -#include "godot/godot_basis.h" - -/////// Transform - -#include "godot/godot_transform.h" - -/////// Color - -#include "godot/godot_color.h" - -/////// NodePath - -#include "godot/godot_node_path.h" - -/////// RID - -#include "godot/godot_rid.h" - -/////// Dictionary - -#include "godot/godot_dictionary.h" - -/////// Array - -#include "godot/godot_array.h" - -// single API file for Pool*Array -#include "godot/godot_pool_arrays.h" - -void GDAPI godot_object_destroy(godot_object *p_o); - -////// Variant - -#include "godot/godot_variant.h" - -////// Singleton API - -godot_object GDAPI *godot_global_get_singleton(char *p_name); // result shouldn't be freed - -////// MethodBind API - -typedef struct godot_method_bind { - uint8_t _dont_touch_that[1]; // TODO -} godot_method_bind; - -godot_method_bind GDAPI *godot_method_bind_get_method(const char *p_classname, const char *p_methodname); -void GDAPI godot_method_bind_ptrcall(godot_method_bind *p_method_bind, godot_object *p_instance, const void **p_args, void *p_ret); -godot_variant GDAPI godot_method_bind_call(godot_method_bind *p_method_bind, godot_object *p_instance, const godot_variant **p_args, const int p_arg_count, godot_variant_call_error *p_call_error); -////// Script API - -typedef struct godot_native_init_options { - godot_bool in_editor; - uint64_t core_api_hash; - uint64_t editor_api_hash; - uint64_t no_api_hash; -} godot_native_init_options; - -typedef struct godot_native_terminate_options { - godot_bool in_editor; -} godot_native_terminate_options; - -typedef enum godot_method_rpc_mode { +typedef enum { GODOT_METHOD_RPC_MODE_DISABLED, GODOT_METHOD_RPC_MODE_REMOTE, GODOT_METHOD_RPC_MODE_SYNC, @@ -274,11 +80,7 @@ typedef enum godot_method_rpc_mode { GODOT_METHOD_RPC_MODE_SLAVE, } godot_method_rpc_mode; -typedef struct godot_method_attributes { - godot_method_rpc_mode rpc_type; -} godot_method_attributes; - -typedef enum godot_property_hint { +typedef enum { GODOT_PROPERTY_HINT_NONE, ///< no hint provided. GODOT_PROPERTY_HINT_RANGE, ///< hint_text = "min,max,step,slider; //slider is optional" GODOT_PROPERTY_HINT_EXP_RANGE, ///< hint_text = "min,max,step", exponential edit @@ -315,7 +117,7 @@ typedef enum godot_property_hint { GODOT_PROPERTY_HINT_MAX, } godot_property_hint; -typedef enum godot_property_usage_flags { +typedef enum { GODOT_PROPERTY_USAGE_STORAGE = 1, GODOT_PROPERTY_USAGE_EDITOR = 2, @@ -340,7 +142,7 @@ typedef enum godot_property_usage_flags { GODOT_PROPERTY_USAGE_NOEDITOR = GODOT_PROPERTY_USAGE_STORAGE | GODOT_PROPERTY_USAGE_NETWORK, } godot_property_usage_flags; -typedef struct godot_property_attributes { +typedef struct { godot_method_rpc_mode rset_type; godot_int type; @@ -350,50 +152,54 @@ typedef struct godot_property_attributes { godot_variant default_value; } godot_property_attributes; -typedef struct godot_instance_create_func { +typedef struct { // instance pointer, method_data - return user data GDCALLINGCONV void *(*create_func)(godot_object *, void *); void *method_data; GDCALLINGCONV void (*free_func)(void *); } godot_instance_create_func; -typedef struct godot_instance_destroy_func { +typedef struct { // instance pointer, method data, user data GDCALLINGCONV void (*destroy_func)(godot_object *, void *, void *); void *method_data; GDCALLINGCONV void (*free_func)(void *); } godot_instance_destroy_func; -void GDAPI godot_script_register_class(const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func); +void GDAPI godot_nativescript_register_class(void *p_gdnative_handle, const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func); -void GDAPI godot_script_register_tool_class(const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func); +void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func); + +typedef struct { + godot_method_rpc_mode rpc_type; +} godot_method_attributes; -typedef struct godot_instance_method { +typedef struct { // instance pointer, method data, user data, num args, args - return result as varaint GDCALLINGCONV godot_variant (*method)(godot_object *, void *, void *, int, godot_variant **); void *method_data; GDCALLINGCONV void (*free_func)(void *); } godot_instance_method; -void GDAPI godot_script_register_method(const char *p_name, const char *p_function_name, godot_method_attributes p_attr, godot_instance_method p_method); +void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_method_attributes p_attr, godot_instance_method p_method); -typedef struct godot_property_set_func { +typedef struct { // instance pointer, method data, user data, value - GDCALLINGCONV void (*set_func)(godot_object *, void *, void *, godot_variant); + GDCALLINGCONV void (*set_func)(godot_object *, void *, void *, godot_variant *); void *method_data; GDCALLINGCONV void (*free_func)(void *); } godot_property_set_func; -typedef struct godot_property_get_func { +typedef struct { // instance pointer, method data, user data, value GDCALLINGCONV godot_variant (*get_func)(godot_object *, void *, void *); void *method_data; GDCALLINGCONV void (*free_func)(void *); } godot_property_get_func; -void GDAPI godot_script_register_property(const char *p_name, const char *p_path, godot_property_attributes *p_attr, godot_property_set_func p_set_func, godot_property_get_func p_get_func); +void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_property_attributes *p_attr, godot_property_set_func p_set_func, godot_property_get_func p_get_func); -typedef struct godot_signal_argument { +typedef struct { godot_string name; godot_int type; godot_property_hint hint; @@ -402,7 +208,7 @@ typedef struct godot_signal_argument { godot_variant default_value; } godot_signal_argument; -typedef struct godot_signal { +typedef struct { godot_string name; int num_args; godot_signal_argument *args; @@ -410,31 +216,12 @@ typedef struct godot_signal { godot_variant *default_args; } godot_signal; -void GDAPI godot_script_register_signal(const char *p_name, const godot_signal *p_signal); - -void GDAPI *godot_native_get_userdata(godot_object *p_instance); - -// Calling convention? -typedef godot_object *(*godot_class_constructor)(); - -godot_class_constructor GDAPI godot_get_class_constructor(const char *p_classname); +void GDAPI godot_nativescript_register_signal(void *p_gdnative_handle, const char *p_name, const godot_signal *p_signal); -godot_dictionary GDAPI godot_get_global_constants(); - -////// System Functions - -//using these will help Godot track how much memory is in use in debug mode -void GDAPI *godot_alloc(int p_bytes); -void GDAPI *godot_realloc(void *p_ptr, int p_bytes); -void GDAPI godot_free(void *p_ptr); - -//print using Godot's error handler list -void GDAPI godot_print_error(const char *p_description, const char *p_function, const char *p_file, int p_line); -void GDAPI godot_print_warning(const char *p_description, const char *p_function, const char *p_file, int p_line); -void GDAPI godot_print(const godot_string *p_message); +void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance); #ifdef __cplusplus } #endif -#endif // GODOT_C_H +#endif diff --git a/modules/nativescript/nativescript.cpp b/modules/nativescript/nativescript.cpp new file mode 100644 index 0000000000..541fe951e4 --- /dev/null +++ b/modules/nativescript/nativescript.cpp @@ -0,0 +1,1063 @@ +/*************************************************************************/ +/* nativescript.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "nativescript.h" + +#include "modules/gdnative/godot/gdnative.h" + +#include "global_constants.h" +#include "io/file_access_encrypted.h" +#include "os/file_access.h" +#include "os/os.h" +#include "project_settings.h" + +#include "scene/main/scene_tree.h" +#include "scene/resources/scene_format_text.h" + +#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) +#include "api_generator.h" +#endif + +#ifdef TOOLS_ENABLED +#include "editor/editor_node.h" +#endif + +////// Script stuff + +void NativeScript::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_class_name", "class_name:String"), &NativeScript::set_class_name); + ClassDB::bind_method(D_METHOD("get_class_name:String"), &NativeScript::get_class_name); + + ClassDB::bind_method(D_METHOD("set_library", "library:GDNativeLibrary"), &NativeScript::set_library); + ClassDB::bind_method(D_METHOD("get_library:GDNativeLibrary"), &NativeScript::get_library); + + ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "class_name"), "set_class_name", "get_class_name"); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library"); + + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &NativeScript::_new, MethodInfo(Variant::OBJECT, "new")); +} + +#define NSL NativeScriptLanguage::get_singleton() + +#ifdef TOOLS_ENABLED + +void NativeScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) { + NativeScriptDesc *script_data = get_script_desc(); + + ERR_FAIL_COND(!script_data); + + List<PropertyInfo> info; + Map<StringName, Variant> values; + + for (Map<StringName, NativeScriptDesc::Property>::Element *E = script_data->properties.front(); E; E = E->next()) { + PropertyInfo p = E->get().info; + p.name = String(E->key()); + + info.push_back(p); + values[p.name] = E->get().default_value; + } + + p_placeholder->update(info, values); +} + +void NativeScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { + placeholders.erase(p_placeholder); +} + +#endif + +void NativeScript::set_class_name(String p_class_name) { + class_name = p_class_name; +} + +String NativeScript::get_class_name() const { + return class_name; +} + +void NativeScript::set_library(Ref<GDNativeLibrary> p_library) { + if (!library.is_null()) { + WARN_PRINT("library on NativeScript already set. Do nothing."); + return; + } + library = p_library; + + // See if this library was "registered" already. + + lib_path = library->get_active_library_path(); + Map<String, Ref<GDNative> >::Element *E = NSL->library_gdnatives.find(lib_path); + + if (!E) { + Ref<GDNative> gdn; + gdn.instance(); + gdn->set_library(library); + + // TODO(karroffel): check the return value? + gdn->initialize(); + + NSL->library_gdnatives.insert(lib_path, gdn); + + NSL->library_classes.insert(lib_path, Map<StringName, NativeScriptDesc>()); + + if (!NSL->library_script_users.has(lib_path)) + NSL->library_script_users.insert(lib_path, Set<NativeScript *>()); + + NSL->library_script_users[lib_path].insert(this); + + void *args[1] = { + (void *)&lib_path + }; + + // here the library registers all the classes and stuff. + gdn->call_native_raw(NSL->_init_call_type, + NSL->_init_call_name, + NULL, + 1, + args, + NULL); + } else { + // already initialized. Nice. + } +} + +Ref<GDNativeLibrary> NativeScript::get_library() const { + return library; +} + +bool NativeScript::can_instance() const { + + NativeScriptDesc *script_data = get_script_desc(); + +#ifdef TOOLS_ENABLED + + return script_data || (!is_tool() && !ScriptServer::is_scripting_enabled()); +#else + return script_data; +#endif +} + +// TODO(karroffel): implement this +Ref<Script> NativeScript::get_base_script() const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return Ref<Script>(); + + Ref<NativeScript> ns = Ref<NativeScript>(NSL->create_script()); + ns->set_class_name(script_data->base); + ns->set_library(get_library()); + return ns; +} + +StringName NativeScript::get_instance_base_type() const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return ""; + + return script_data->base_native_type; +} + +ScriptInstance *NativeScript::instance_create(Object *p_this) { + + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) { + return NULL; + } + +#ifdef TOOLS_ENABLED + if (!ScriptServer::is_scripting_enabled() && !is_tool()) { + // placeholder for nodes. For tools we want the rool thing. + + PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(NSL, Ref<Script>(this), p_this)); + placeholders.insert(sins); + + if (script_data->create_func.create_func) { + script_data->create_func.create_func( + (godot_object *)p_this, + script_data->create_func.method_data); + } + + _update_placeholder(sins); + + return sins; + } +#endif + + NativeScriptInstance *nsi = memnew(NativeScriptInstance); + + nsi->owner = p_this; + nsi->script = Ref<NativeScript>(this); + +#ifndef TOOLS_ENABLED + if (!ScriptServer::is_scripting_enabled()) { + nsi->userdata = NULL; + } else { + nsi->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); + } +#else + nsi->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); +#endif + + instance_owners.insert(p_this); + return nsi; +} + +bool NativeScript::instance_has(const Object *p_this) const { + return instance_owners.has((Object *)p_this); +} + +bool NativeScript::has_source_code() const { + return false; +} + +String NativeScript::get_source_code() const { + return ""; +} + +void NativeScript::set_source_code(const String &p_code) { +} + +Error NativeScript::reload(bool p_keep_state) { + return FAILED; +} + +bool NativeScript::has_method(const StringName &p_method) const { + NativeScriptDesc *script_data = get_script_desc(); + + while (script_data) { + if (script_data->methods.has(p_method)) + return true; + + script_data = script_data->base_data; + } + return false; +} + +MethodInfo NativeScript::get_method_info(const StringName &p_method) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return MethodInfo(); + + while (script_data) { + Map<StringName, NativeScriptDesc::Method>::Element *M = script_data->methods.find(p_method); + + if (M) + return M->get().info; + + script_data = script_data->base_data; + } + return MethodInfo(); +} + +bool NativeScript::is_tool() const { + NativeScriptDesc *script_data = get_script_desc(); + + if (script_data) + return script_data->is_tool; + + return false; +} + +String NativeScript::get_node_type() const { + return ""; // NOTE(karroffel): uhm? +} + +ScriptLanguage *NativeScript::get_language() const { + return NativeScriptLanguage::get_singleton(); +} + +bool NativeScript::has_script_signal(const StringName &p_signal) const { + NativeScriptDesc *script_data = get_script_desc(); + if (!script_data) + return false; + return script_data->signals_.has(p_signal); +} + +void NativeScript::get_script_signal_list(List<MethodInfo> *r_signals) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return; + + Set<MethodInfo> signals_; + + while (script_data) { + + for (Map<StringName, NativeScriptDesc::Signal>::Element *S = script_data->signals_.front(); S; S = S->next()) { + signals_.insert(S->get().signal); + } + + script_data = script_data->base_data; + } + + for (Set<MethodInfo>::Element *E = signals_.front(); E; E = E->next()) { + r_signals->push_back(E->get()); + } +} + +bool NativeScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return false; + + Map<StringName, NativeScriptDesc::Property>::Element *P = script_data->properties.find(p_property); + + if (!P) + return false; + + r_value = P->get().default_value; + return true; +} + +void NativeScript::update_exports() { +} + +void NativeScript::get_script_method_list(List<MethodInfo> *p_list) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return; + + Set<MethodInfo> methods; + + while (script_data) { + + for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) { + methods.insert(E->get().info); + } + + script_data = script_data->base_data; + } + + for (Set<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + p_list->push_back(E->get()); + } +} + +void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const { + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) + return; + + Set<PropertyInfo> properties; + + while (script_data) { + + for (Map<StringName, NativeScriptDesc::Property>::Element *E = script_data->properties.front(); E; E = E->next()) { + properties.insert(E->get().info); + } + + script_data = script_data->base_data; + } + + for (Set<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { + p_list->push_back(E->get()); + } +} + +Variant NativeScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + + if (lib_path.empty() || class_name.empty() || library.is_null()) { + r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL; + return Variant(); + } + + NativeScriptDesc *script_data = get_script_desc(); + + if (!script_data) { + r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL; + return Variant(); + } + + r_error.error = Variant::CallError::CALL_OK; + + REF ref; + Object *owner = NULL; + + if (!(script_data->base_native_type == "")) { + owner = ClassDB::instance(script_data->base_native_type); + } else { + owner = memnew(Reference); + } + + Reference *r = owner->cast_to<Reference>(); + if (r) { + ref = REF(r); + } + + // GDScript does it like this: _create_instance(p_args, p_argcount, owner, r != NULL, r_error); + // TODO(karroffel): support varargs for constructors. + + NativeScriptInstance *instance = (NativeScriptInstance *)instance_create(owner); + + owner->set_script_instance(instance); + + if (!instance) { + if (ref.is_null()) { + memdelete(owner); //no owner, sorry + } + return Variant(); + } + + if (ref.is_valid()) { + return ref; + } else { + return owner; + } +} + +// TODO(karroffel): implement this +NativeScript::NativeScript() { + library = Ref<GDNative>(); + lib_path = ""; + class_name = ""; +} + +// TODO(karroffel): implement this +NativeScript::~NativeScript() { + NSL->library_script_users[lib_path].erase(this); +} + +////// ScriptInstance stuff + +#define GET_SCRIPT_DESC() script->get_script_desc() + +void NativeScriptInstance::_ml_call_reversed(NativeScriptDesc *script_data, const StringName &p_method, const Variant **p_args, int p_argcount) { + if (script_data->base_data) { + _ml_call_reversed(script_data->base_data, p_method, p_args, p_argcount); + } + + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); + if (E) { + godot_variant res = E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, p_argcount, (godot_variant **)p_args); + godot_variant_destroy(&res); + } +} + +bool NativeScriptInstance::set(const StringName &p_name, const Variant &p_value) { + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + Map<StringName, NativeScriptDesc::Property>::Element *P = script_data->properties.find(p_name); + if (P) { + P->get().setter.set_func((godot_object *)owner, + P->get().setter.method_data, + userdata, + (godot_variant *)&p_value); + return true; + } + + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find("_set"); + if (E) { + Variant name = p_name; + const Variant *args[2] = { &name, &p_value }; + + E->get().method.method((godot_object *)owner, + E->get().method.method_data, + userdata, + 2, + (godot_variant **)args); + return true; + } + + script_data = script_data->base_data; + } + return false; +} +bool NativeScriptInstance::get(const StringName &p_name, Variant &r_ret) const { + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + Map<StringName, NativeScriptDesc::Property>::Element *P = script_data->properties.find(p_name); + if (P) { + godot_variant value; + value = P->get().getter.get_func((godot_object *)owner, + P->get().setter.method_data, + userdata); + r_ret = *(Variant *)&value; + godot_variant_destroy(&value); + return true; + } + + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find("_get"); + if (E) { + Variant name = p_name; + const Variant *args[1] = { &name }; + + godot_variant result; + result = E->get().method.method((godot_object *)owner, + E->get().method.method_data, + userdata, + 1, + (godot_variant **)args); + r_ret = *(Variant *)&result; + godot_variant_destroy(&result); + if (r_ret.get_type() == Variant::NIL) { + return false; + } + return true; + } + + script_data = script_data->base_data; + } + return false; +} + +void NativeScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { + script->get_script_property_list(p_properties); + + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find("_get_property_list"); + if (E) { + + godot_variant result; + result = E->get().method.method((godot_object *)owner, + E->get().method.method_data, + userdata, + 0, + NULL); + Variant res = *(Variant *)&result; + godot_variant_destroy(&result); + + if (res.get_type() != Variant::ARRAY) { + ERR_EXPLAIN("_get_property_list must return an array of dictionaries"); + ERR_FAIL(); + } + + Array arr = res; + for (int i = 0; i < arr.size(); i++) { + Dictionary d = arr[i]; + + ERR_CONTINUE(!d.has("name")); + ERR_CONTINUE(!d.has("type")); + + PropertyInfo info; + + info.type = Variant::Type(d["type"].operator int64_t()); + ERR_CONTINUE(info.type < 0 || info.type >= Variant::VARIANT_MAX); + + info.name = d["name"]; + ERR_CONTINUE(info.name == ""); + + if (d.has("hint")) { + info.hint = PropertyHint(d["hint"].operator int64_t()); + } + + if (d.has("hint_string")) { + info.hint_string = d["hint_string"]; + } + + if (d.has("usage")) { + info.usage = d["usage"]; + } + + p_properties->push_back(info); + } + } + + script_data = script_data->base_data; + } + return; +} + +Variant::Type NativeScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { + + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + + Map<StringName, NativeScriptDesc::Property>::Element *P = script_data->properties.find(p_name); + if (P) { + *r_is_valid = true; + return P->get().info.type; + } + + script_data = script_data->base_data; + } + return Variant::NIL; +} + +void NativeScriptInstance::get_method_list(List<MethodInfo> *p_list) const { + script->get_method_list(p_list); +} + +bool NativeScriptInstance::has_method(const StringName &p_method) const { + return script->has_method(p_method); +} + +Variant NativeScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); + if (E) { + godot_variant result; + result = E->get().method.method((godot_object *)owner, + E->get().method.method_data, + userdata, + p_argcount, + (godot_variant **)p_args); + Variant res = *(Variant *)&result; + godot_variant_destroy(&result); + r_error.error = Variant::CallError::CALL_OK; + return res; + } + + script_data = script_data->base_data; + } + + r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; + return Variant(); +} + +void NativeScriptInstance::notification(int p_notification) { + Variant value = p_notification; + const Variant *args[1] = { &value }; + call_multilevel("_notification", args, 1); +} + +Ref<Script> NativeScriptInstance::get_script() const { + return script; +} + +NativeScriptInstance::RPCMode NativeScriptInstance::get_rpc_mode(const StringName &p_method) const { + + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); + if (E) { + switch (E->get().rpc_mode) { + case GODOT_METHOD_RPC_MODE_DISABLED: + return RPC_MODE_DISABLED; + case GODOT_METHOD_RPC_MODE_REMOTE: + return RPC_MODE_REMOTE; + case GODOT_METHOD_RPC_MODE_SYNC: + return RPC_MODE_SYNC; + case GODOT_METHOD_RPC_MODE_MASTER: + return RPC_MODE_MASTER; + case GODOT_METHOD_RPC_MODE_SLAVE: + return RPC_MODE_SLAVE; + default: + return RPC_MODE_DISABLED; + } + } + + script_data = script_data->base_data; + } + + return RPC_MODE_DISABLED; +} + +// TODO(karroffel): implement this +NativeScriptInstance::RPCMode NativeScriptInstance::get_rset_mode(const StringName &p_variable) const { + + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + + Map<StringName, NativeScriptDesc::Property>::Element *E = script_data->properties.find(p_variable); + if (E) { + switch (E->get().rset_mode) { + case GODOT_METHOD_RPC_MODE_DISABLED: + return RPC_MODE_DISABLED; + case GODOT_METHOD_RPC_MODE_REMOTE: + return RPC_MODE_REMOTE; + case GODOT_METHOD_RPC_MODE_SYNC: + return RPC_MODE_SYNC; + case GODOT_METHOD_RPC_MODE_MASTER: + return RPC_MODE_MASTER; + case GODOT_METHOD_RPC_MODE_SLAVE: + return RPC_MODE_SLAVE; + default: + return RPC_MODE_DISABLED; + } + } + + script_data = script_data->base_data; + } + + return RPC_MODE_DISABLED; +} + +ScriptLanguage *NativeScriptInstance::get_language() { + return NativeScriptLanguage::get_singleton(); +} + +void NativeScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + while (script_data) { + Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); + if (E) { + godot_variant res = E->get().method.method((godot_object *)owner, + E->get().method.method_data, + userdata, + p_argcount, + (godot_variant **)p_args); + godot_variant_destroy(&res); + } + script_data = script_data->base_data; + } +} + +void NativeScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + if (script_data) { + _ml_call_reversed(script_data, p_method, p_args, p_argcount); + } +} + +NativeScriptInstance::~NativeScriptInstance() { + + NativeScriptDesc *script_data = GET_SCRIPT_DESC(); + + if (!script_data) + return; + + script_data->destroy_func.destroy_func((godot_object *)owner, script_data->destroy_func.method_data, userdata); + + if (owner) { + script->instance_owners.erase(owner); + } +} + +////// ScriptingLanguage stuff + +NativeScriptLanguage *NativeScriptLanguage::singleton; + +extern "C" void _native_script_hook(); +void NativeScriptLanguage::_hacky_api_anchor() { + _native_script_hook(); +} + +void NativeScriptLanguage::_unload_stuff() { + for (Map<String, Map<StringName, NativeScriptDesc> >::Element *L = library_classes.front(); L; L = L->next()) { + for (Map<StringName, NativeScriptDesc>::Element *C = L->get().front(); C; C = C->next()) { + + // free property stuff first + for (Map<StringName, NativeScriptDesc::Property>::Element *P = C->get().properties.front(); P; P = P->next()) { + if (P->get().getter.free_func) + P->get().getter.free_func(P->get().getter.method_data); + + if (P->get().setter.free_func) + P->get().setter.free_func(P->get().setter.method_data); + } + + // free method stuff + for (Map<StringName, NativeScriptDesc::Method>::Element *M = C->get().methods.front(); M; M = M->next()) { + if (M->get().method.free_func) + M->get().method.free_func(M->get().method.method_data); + } + + // free constructor/destructor + if (C->get().create_func.free_func) + C->get().create_func.free_func(C->get().create_func.method_data); + + if (C->get().destroy_func.free_func) + C->get().destroy_func.free_func(C->get().destroy_func.method_data); + } + } +} + +NativeScriptLanguage::NativeScriptLanguage() { + NativeScriptLanguage::singleton = this; +} + +// TODO(karroffel): implement this +NativeScriptLanguage::~NativeScriptLanguage() { + // _unload_stuff(); // NOTE(karroffel): This gets called in ::finish() + + for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) { + + L->get()->terminate(); + NSL->library_classes.clear(); + NSL->library_gdnatives.clear(); + NSL->library_script_users.clear(); + } +} + +String NativeScriptLanguage::get_name() const { + return "NativeScript"; +} + +void _add_reload_node() { +#ifdef TOOLS_ENABLED + NativeReloadNode *rn = memnew(NativeReloadNode); + EditorNode::get_singleton()->add_child(rn); +#endif +} + +// TODO(karroffel): implement this +void NativeScriptLanguage::init() { + +#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) + + List<String> args = OS::get_singleton()->get_cmdline_args(); + + List<String>::Element *E = args.find("--gdnative-generate-json-api"); + + if (E && E->next()) { + if (generate_c_api(E->next()->get()) != OK) { + ERR_PRINT("Failed to generate C API\n"); + } + } +#endif + +#ifdef TOOLS_ENABLED + EditorNode::add_init_callback(&_add_reload_node); +#endif +} +String NativeScriptLanguage::get_type() const { + return "NativeScript"; +} +String NativeScriptLanguage::get_extension() const { + return "gdns"; +} +Error NativeScriptLanguage::execute_file(const String &p_path) { + return OK; // Qué? +} +void NativeScriptLanguage::finish() { + _unload_stuff(); +} +void NativeScriptLanguage::get_reserved_words(List<String> *p_words) const { +} +void NativeScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { +} +void NativeScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { +} + +// TODO(karroffel): implement this +Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { + NativeScript *s = memnew(NativeScript); + s->set_class_name(p_class_name); + // TODO(karroffel): use p_base_class_name + return Ref<NativeScript>(s); +} +bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { + return false; +} + +Script *NativeScriptLanguage::create_script() const { + NativeScript *script = memnew(NativeScript); + return script; +} +bool NativeScriptLanguage::has_named_classes() const { + return true; +} +int NativeScriptLanguage::find_function(const String &p_function, const String &p_code) const { + return -1; +} +String NativeScriptLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const { + return ""; +} +void NativeScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const { +} +void NativeScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) { +} + +// Debugging stuff here. Not used for now. +String NativeScriptLanguage::debug_get_error() const { + return ""; +} +int NativeScriptLanguage::debug_get_stack_level_count() const { + return -1; +} +int NativeScriptLanguage::debug_get_stack_level_line(int p_level) const { + return -1; +} +String NativeScriptLanguage::debug_get_stack_level_function(int p_level) const { + return ""; +} +String NativeScriptLanguage::debug_get_stack_level_source(int p_level) const { + return ""; +} +void NativeScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { +} +void NativeScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { +} +void NativeScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { +} +String NativeScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { + return ""; +} +// Debugging stuff end. + +void NativeScriptLanguage::reload_all_scripts() { +} + +void NativeScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) { +} +void NativeScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("gdns"); +} + +void NativeScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const { +} + +void NativeScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const { +} + +void NativeScriptLanguage::profiling_start() { +} + +void NativeScriptLanguage::profiling_stop() { +} + +int NativeScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) { + return -1; +} + +int NativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) { + return -1; +} + +void NativeReloadNode::_bind_methods() { + ClassDB::bind_method(D_METHOD("_notification"), &NativeReloadNode::_notification); +} + +void NativeReloadNode::_notification(int p_what) { +#ifdef TOOLS_ENABLED + + switch (p_what) { + case MainLoop::NOTIFICATION_WM_FOCUS_OUT: { + + if (unloaded) + break; + + NSL->_unload_stuff(); + for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) { + + L->get()->terminate(); + NSL->library_classes.erase(L->key()); + } + + unloaded = true; + + } break; + + case MainLoop::NOTIFICATION_WM_FOCUS_IN: { + + if (!unloaded) + break; + + Set<StringName> libs_to_remove; + + for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) { + + if (!L->get()->initialize()) { + libs_to_remove.insert(L->key()); + continue; + } + + NSL->library_classes.insert(L->key(), Map<StringName, NativeScriptDesc>()); + + void *args[1] = { + (void *)&L->key() + }; + + // here the library registers all the classes and stuff. + L->get()->call_native_raw(NSL->_init_call_type, + NSL->_init_call_name, + NULL, + 1, + args, + NULL); + + for (Map<String, Set<NativeScript *> >::Element *U = NSL->library_script_users.front(); U; U = U->next()) { + for (Set<NativeScript *>::Element *S = U->get().front(); S; S = S->next()) { + NativeScript *script = S->get(); + + if (script->placeholders.size() == 0) + continue; + + for (Set<PlaceHolderScriptInstance *>::Element *P = script->placeholders.front(); P; P = P->next()) { + script->_update_placeholder(P->get()); + } + } + } + } + + unloaded = false; + + for (Set<StringName>::Element *R = libs_to_remove.front(); R; R = R->next()) { + NSL->library_gdnatives.erase(R->get()); + } + + } break; + default: { + }; + } +#endif +} + +RES ResourceFormatLoaderNativeScript::load(const String &p_path, const String &p_original_path, Error *r_error) { + ResourceFormatLoaderText rsflt; + return rsflt.load(p_path, p_original_path, r_error); +} + +void ResourceFormatLoaderNativeScript::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("gdns"); +} + +bool ResourceFormatLoaderNativeScript::handles_type(const String &p_type) const { + return (p_type == "Script" || p_type == "NativeScript"); +} + +String ResourceFormatLoaderNativeScript::get_resource_type(const String &p_path) const { + String el = p_path.get_extension().to_lower(); + if (el == "gdns") + return "NativeScript"; + return ""; +} + +Error ResourceFormatSaverNativeScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { + ResourceFormatSaverText rfst; + return rfst.save(p_path, p_resource, p_flags); +} + +bool ResourceFormatSaverNativeScript::recognize(const RES &p_resource) const { + return p_resource->cast_to<NativeScript>() != NULL; +} + +void ResourceFormatSaverNativeScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { + if (p_resource->cast_to<NativeScript>()) { + p_extensions->push_back("gdns"); + } +} diff --git a/modules/nativescript/nativescript.h b/modules/nativescript/nativescript.h new file mode 100644 index 0000000000..bc7a6e3ed6 --- /dev/null +++ b/modules/nativescript/nativescript.h @@ -0,0 +1,283 @@ +/*************************************************************************/ +/* nativescript.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef NATIVE_SCRIPT_H +#define NATIVE_SCRIPT_H + +#include "io/resource_loader.h" +#include "io/resource_saver.h" +#include "os/thread_safe.h" +#include "resource.h" +#include "scene/main/node.h" +#include "script_language.h" +#include "self_list.h" + +#include "godot_nativescript.h" +#include "modules/gdnative/gdnative.h" + +struct NativeScriptDesc { + + struct Method { + godot_instance_method method; + MethodInfo info; + int rpc_mode; + }; + struct Property { + godot_property_set_func setter; + godot_property_get_func getter; + PropertyInfo info; + Variant default_value; + int rset_mode; + }; + + struct Signal { + MethodInfo signal; + }; + + Map<StringName, Method> methods; + Map<StringName, Property> properties; + Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals + StringName base; + StringName base_native_type; + NativeScriptDesc *base_data; + godot_instance_create_func create_func; + godot_instance_destroy_func destroy_func; + + bool is_tool; + + inline NativeScriptDesc() + : methods(), + properties(), + signals_(), + base(), + base_native_type() { + zeromem(&create_func, sizeof(godot_instance_create_func)); + zeromem(&destroy_func, sizeof(godot_instance_destroy_func)); + } +}; + +class NativeScript : public Script { + GDCLASS(NativeScript, Script) + +#ifdef TOOLS_ENABLED + Set<PlaceHolderScriptInstance *> placeholders; + void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); + virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder); +#endif + + friend class NativeScriptInstance; + friend class NativeScriptLanguage; + friend class NativeReloadNode; + friend class GDNativeLibrary; + + Ref<GDNativeLibrary> library; + + String lib_path; + + String class_name; + + Set<Object *> instance_owners; + +protected: + static void _bind_methods(); + +public: + inline NativeScriptDesc *get_script_desc() const; + + void set_class_name(String p_class_name); + String get_class_name() const; + + void set_library(Ref<GDNativeLibrary> library); + Ref<GDNativeLibrary> get_library() const; + + virtual bool can_instance() const; + + virtual Ref<Script> get_base_script() const; //for script inheritance + + virtual StringName get_instance_base_type() const; // this may not work in all scripts, will return empty if so + virtual ScriptInstance *instance_create(Object *p_this); + virtual bool instance_has(const Object *p_this) const; + + virtual bool has_source_code() const; + virtual String get_source_code() const; + virtual void set_source_code(const String &p_code); + virtual Error reload(bool p_keep_state = false); + + virtual bool has_method(const StringName &p_method) const; + virtual MethodInfo get_method_info(const StringName &p_method) const; + + virtual bool is_tool() const; + + virtual String get_node_type() const; + + virtual ScriptLanguage *get_language() const; + + virtual bool has_script_signal(const StringName &p_signal) const; + virtual void get_script_signal_list(List<MethodInfo> *r_signals) const; + + virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const; + + virtual void update_exports(); //editor tool + virtual void get_script_method_list(List<MethodInfo> *p_list) const; + virtual void get_script_property_list(List<PropertyInfo> *p_list) const; + + Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + + NativeScript(); + ~NativeScript(); +}; + +class NativeScriptInstance : public ScriptInstance { + + friend class NativeScript; + + Object *owner; + Ref<NativeScript> script; + + void _ml_call_reversed(NativeScriptDesc *script_data, const StringName &p_method, const Variant **p_args, int p_argcount); + +public: + void *userdata; + + virtual bool set(const StringName &p_name, const Variant &p_value); + virtual bool get(const StringName &p_name, Variant &r_ret) const; + virtual void get_property_list(List<PropertyInfo> *p_properties) const; + virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid) const; + virtual void get_method_list(List<MethodInfo> *p_list) const; + virtual bool has_method(const StringName &p_method) const; + virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error); + virtual void notification(int p_notification); + virtual Ref<Script> get_script() const; + virtual RPCMode get_rpc_mode(const StringName &p_method) const; + virtual RPCMode get_rset_mode(const StringName &p_variable) const; + virtual ScriptLanguage *get_language(); + + virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); + virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); + + ~NativeScriptInstance(); +}; + +class NativeReloadNode; + +class NativeScriptLanguage : public ScriptLanguage { + + friend class NativeScript; + friend class NativeScriptInstance; + friend class NativeReloadNode; + +private: + static NativeScriptLanguage *singleton; + + void _unload_stuff(); + +public: + Map<String, Map<StringName, NativeScriptDesc> > library_classes; + Map<String, Ref<GDNative> > library_gdnatives; + + Map<String, Set<NativeScript *> > library_script_users; + + const StringName _init_call_type = "nativescript_init"; + const StringName _init_call_name = "godot_nativescript_init"; + + NativeScriptLanguage(); + ~NativeScriptLanguage(); + + inline static NativeScriptLanguage *get_singleton() { + return singleton; + } + + void _hacky_api_anchor(); + + virtual String get_name() const; + virtual void init(); + virtual String get_type() const; + virtual String get_extension() const; + virtual Error execute_file(const String &p_path); + virtual void finish(); + virtual void get_reserved_words(List<String> *p_words) const; + virtual void get_comment_delimiters(List<String> *p_delimiters) const; + virtual void get_string_delimiters(List<String> *p_delimiters) const; + virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; + virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const; + virtual Script *create_script() const; + virtual bool has_named_classes() const; + virtual int find_function(const String &p_function, const String &p_code) const; + virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const; + virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const; + virtual void add_global_constant(const StringName &p_variable, const Variant &p_value); + virtual String debug_get_error() const; + virtual int debug_get_stack_level_count() const; + virtual int debug_get_stack_level_line(int p_level) const; + virtual String debug_get_stack_level_function(int p_level) const; + virtual String debug_get_stack_level_source(int p_level) const; + virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth); + virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth); + virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth); + virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth); + virtual void reload_all_scripts(); + virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual void get_public_functions(List<MethodInfo> *p_functions) const; + virtual void get_public_constants(List<Pair<String, Variant> > *p_constants) const; + virtual void profiling_start(); + virtual void profiling_stop(); + virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max); + virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max); +}; + +inline NativeScriptDesc *NativeScript::get_script_desc() const { + Map<StringName, NativeScriptDesc>::Element *E = NativeScriptLanguage::singleton->library_classes[lib_path].find(class_name); + return E ? &E->get() : NULL; +} + +class NativeReloadNode : public Node { + GDCLASS(NativeReloadNode, Node) + bool unloaded = false; + +public: + static void _bind_methods(); + void _notification(int p_what); +}; + +class ResourceFormatLoaderNativeScript : public 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; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; + +class ResourceFormatSaverNativeScript : public 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; +}; + +#endif // GDNATIVE_H diff --git a/modules/nativescript/register_types.cpp b/modules/nativescript/register_types.cpp new file mode 100644 index 0000000000..6c88b04a56 --- /dev/null +++ b/modules/nativescript/register_types.cpp @@ -0,0 +1,93 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "io/resource_loader.h" +#include "io/resource_saver.h" + +#include "nativescript.h" + +#include "core/os/os.h" + +NativeScriptLanguage *native_script_language; + +typedef void (*native_script_init_fn)(void *); + +void init_call_cb(void *p_handle, godot_string *p_proc_name, void *p_data, int p_num_args, void **args, void *r_ret) { + if (p_handle == NULL) { + ERR_PRINT("No valid library handle, can't call nativescript init procedure"); + return; + } + + void *library_proc; + Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( + p_handle, + *(String *)p_proc_name, + library_proc); + if (err != OK) { + ERR_PRINT((String("GDNative procedure \"" + *(String *)p_proc_name) + "\" does not exists and can't be called").utf8().get_data()); + return; + } + + native_script_init_fn fn = (native_script_init_fn)library_proc; + + fn(args[0]); +} + +ResourceFormatLoaderNativeScript *resource_loader_gdns = NULL; +ResourceFormatSaverNativeScript *resource_saver_gdns = NULL; + +void register_nativescript_types() { + native_script_language = memnew(NativeScriptLanguage); + + ClassDB::register_class<NativeScript>(); + + ScriptServer::register_language(native_script_language); + + GDNativeCallRegistry::singleton->register_native_raw_call_type(native_script_language->_init_call_type, init_call_cb); + + resource_saver_gdns = memnew(ResourceFormatSaverNativeScript); + ResourceSaver::add_resource_format_saver(resource_saver_gdns); + + resource_loader_gdns = memnew(ResourceFormatLoaderNativeScript); + ResourceLoader::add_resource_format_loader(resource_loader_gdns); +} + +void unregister_nativescript_types() { + + memdelete(resource_loader_gdns); + + memdelete(resource_saver_gdns); + + if (native_script_language) { + ScriptServer::unregister_language(native_script_language); + memdelete(native_script_language); + } +} diff --git a/modules/nativescript/register_types.h b/modules/nativescript/register_types.h new file mode 100644 index 0000000000..319da9c42f --- /dev/null +++ b/modules/nativescript/register_types.h @@ -0,0 +1,31 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_nativescript_types(); +void unregister_nativescript_types(); diff --git a/modules/openssl/stream_peer_openssl.cpp b/modules/openssl/stream_peer_openssl.cpp index 8159296b3c..7a9d5195a9 100644 --- a/modules/openssl/stream_peer_openssl.cpp +++ b/modules/openssl/stream_peer_openssl.cpp @@ -560,7 +560,7 @@ void StreamPeerOpenSSL::initialize_ssl() { ERR_load_BIO_strings(); // Load BIO error strings OpenSSL_add_all_algorithms(); // Load all available encryption algorithms String certs_path = GLOBAL_DEF("network/ssl/certificates", ""); - GlobalConfig::get_singleton()->set_custom_property_info("network/ssl/certificates", PropertyInfo(Variant::STRING, "network/ssl/certificates", PROPERTY_HINT_FILE, "*.crt")); + ProjectSettings::get_singleton()->set_custom_property_info("network/ssl/certificates", PropertyInfo(Variant::STRING, "network/ssl/certificates", PROPERTY_HINT_FILE, "*.crt")); if (certs_path != "") { FileAccess *f = FileAccess::open(certs_path, FileAccess::READ); @@ -581,7 +581,7 @@ void StreamPeerOpenSSL::initialize_ssl() { } } String config_path = GLOBAL_DEF("network/ssl/config", ""); - GlobalConfig::get_singleton()->set_custom_property_info("network/ssl/config", PropertyInfo(Variant::STRING, "network/ssl/config", PROPERTY_HINT_FILE, "*.cnf")); + ProjectSettings::get_singleton()->set_custom_property_info("network/ssl/config", PropertyInfo(Variant::STRING, "network/ssl/config", PROPERTY_HINT_FILE, "*.cnf")); if (config_path != "") { Vector<uint8_t> data = FileAccess::get_file_as_array(config_path); diff --git a/modules/openssl/stream_peer_openssl.h b/modules/openssl/stream_peer_openssl.h index 5c830ebf37..b1da5e1d95 100644 --- a/modules/openssl/stream_peer_openssl.h +++ b/modules/openssl/stream_peer_openssl.h @@ -30,9 +30,9 @@ #ifndef STREAM_PEER_OPEN_SSL_H #define STREAM_PEER_OPEN_SSL_H -#include "global_config.h" #include "io/stream_peer_ssl.h" #include "os/file_access.h" +#include "project_settings.h" #include "thirdparty/misc/curl_hostcheck.h" diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index d895f60280..977062dd14 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "video_stream_theora.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" #include "thirdparty/misc/yuv2rgb.h" @@ -728,7 +728,7 @@ void VideoStreamPlaybackTheora::play() { } playing = true; - delay_compensation = GlobalConfig::get_singleton()->get("audio/video_delay_compensation_ms"); + delay_compensation = ProjectSettings::get_singleton()->get("audio/video_delay_compensation_ms"); delay_compensation /= 1000.0; }; diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 84b4b0cab1..f15abec7e2 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "visual_script.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" #include "scene/main/node.h" #include "visual_script_nodes.h" @@ -1264,14 +1264,14 @@ void VisualScript::_bind_methods() { ClassDB::bind_method(D_METHOD("has_function", "name"), &VisualScript::has_function); ClassDB::bind_method(D_METHOD("remove_function", "name"), &VisualScript::remove_function); ClassDB::bind_method(D_METHOD("rename_function", "name", "new_name"), &VisualScript::rename_function); - ClassDB::bind_method(D_METHOD("set_function_scroll", "ofs"), &VisualScript::set_function_scroll); - ClassDB::bind_method(D_METHOD("get_function_scroll"), &VisualScript::get_function_scroll); + ClassDB::bind_method(D_METHOD("set_function_scroll", "name", "ofs"), &VisualScript::set_function_scroll); + ClassDB::bind_method(D_METHOD("get_function_scroll", "name"), &VisualScript::get_function_scroll); - ClassDB::bind_method(D_METHOD("add_node", "func", "id", "node", "pos"), &VisualScript::add_node, DEFVAL(Point2())); + ClassDB::bind_method(D_METHOD("add_node", "func", "id", "node:VisualScriptNode", "pos"), &VisualScript::add_node, DEFVAL(Point2())); ClassDB::bind_method(D_METHOD("remove_node", "func", "id"), &VisualScript::remove_node); ClassDB::bind_method(D_METHOD("get_function_node_id", "name"), &VisualScript::get_function_node_id); - ClassDB::bind_method(D_METHOD("get_node", "func", "id"), &VisualScript::get_node); + ClassDB::bind_method(D_METHOD("get_node:VisualScriptNode", "func", "id"), &VisualScript::get_node); ClassDB::bind_method(D_METHOD("has_node", "func", "id"), &VisualScript::has_node); ClassDB::bind_method(D_METHOD("set_node_pos", "func", "id", "pos"), &VisualScript::set_node_pos); ClassDB::bind_method(D_METHOD("get_node_pos", "func", "id"), &VisualScript::get_node_pos); @@ -1302,7 +1302,7 @@ void VisualScript::_bind_methods() { ClassDB::bind_method(D_METHOD("custom_signal_get_argument_type", "name", "argidx"), &VisualScript::custom_signal_get_argument_type); ClassDB::bind_method(D_METHOD("custom_signal_set_argument_name", "name", "argidx", "argname"), &VisualScript::custom_signal_set_argument_name); ClassDB::bind_method(D_METHOD("custom_signal_get_argument_name", "name", "argidx"), &VisualScript::custom_signal_get_argument_name); - ClassDB::bind_method(D_METHOD("custom_signal_remove_argument", "argidx"), &VisualScript::custom_signal_remove_argument); + ClassDB::bind_method(D_METHOD("custom_signal_remove_argument", "name", "argidx"), &VisualScript::custom_signal_remove_argument); ClassDB::bind_method(D_METHOD("custom_signal_get_argument_count", "name"), &VisualScript::custom_signal_get_argument_count); ClassDB::bind_method(D_METHOD("custom_signal_swap_argument", "name", "argidx", "withidx"), &VisualScript::custom_signal_swap_argument); ClassDB::bind_method(D_METHOD("remove_custom_signal", "name"), &VisualScript::remove_custom_signal); diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 08757f4c61..ba3463445d 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -2746,7 +2746,7 @@ void VisualScriptEditor::_node_filter_changed(const String &p_text) { void VisualScriptEditor::_notification(int p_what) { if (p_what == NOTIFICATION_READY) { - node_filter_icon->set_texture(Control::get_icon("Search", "EditorIcons")); + node_filter->add_icon_override("right_icon", Control::get_icon("Search", "EditorIcons")); variable_editor->connect("changed", this, "_update_members"); signal_editor->connect("changed", this, "_update_members"); } @@ -3215,9 +3215,6 @@ VisualScriptEditor::VisualScriptEditor() { node_filter->connect("text_changed", this, "_node_filter_changed"); hbc_nodes->add_child(node_filter); node_filter->set_h_size_flags(SIZE_EXPAND_FILL); - node_filter_icon = memnew(TextureRect); - node_filter_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); - hbc_nodes->add_child(node_filter_icon); vbc_nodes->add_child(hbc_nodes); nodes = memnew(Tree); diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index b53a21c53b..77f3111d94 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -29,9 +29,9 @@ /*************************************************************************/ #include "visual_script_flow_control.h" -#include "global_config.h" #include "io/resource_loader.h" #include "os/keyboard.h" +#include "project_settings.h" ////////////////////////////////////////// ////////////////RETURN//////////////////// @@ -138,11 +138,11 @@ public: if (with_value) { *p_working_mem = *p_inputs[0]; + return STEP_EXIT_FUNCTION_BIT; } else { *p_working_mem = Variant(); + return 0; } - - return 0; } }; @@ -875,7 +875,7 @@ String VisualScriptInputFilter::get_output_sequence_port_text(int p_port) const case Ref<InputEvent>::ACTION: { List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); + ProjectSettings::get_singleton()->get_property_list(&pinfo); int index = 1; text = "No Action"; @@ -1119,7 +1119,7 @@ bool VisualScriptInputFilter::_set(const StringName &p_name, const Variant &p_va if (what == "action_name") { List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); + ProjectSettings::get_singleton()->get_property_list(&pinfo); int index = 1; for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { @@ -1325,7 +1325,7 @@ bool VisualScriptInputFilter::_get(const StringName &p_name, Variant &r_ret) con if (what == "action_name") { List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); + ProjectSettings::get_singleton()->get_property_list(&pinfo); int index = 1; for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { @@ -1456,7 +1456,7 @@ void VisualScriptInputFilter::_get_property_list(List<PropertyInfo> *p_list) con actions = "None"; List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); + ProjectSettings::get_singleton()->get_property_list(&pinfo); Vector<String> al; for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 93b2aa2982..c438edd21f 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -29,9 +29,9 @@ /*************************************************************************/ #include "visual_script_func_nodes.h" -#include "global_config.h" #include "io/resource_loader.h" #include "os/os.h" +#include "project_settings.h" #include "scene/main/node.h" #include "scene/main/scene_tree.h" #include "visual_script_nodes.h" @@ -347,7 +347,7 @@ void VisualScriptFunctionCall::set_singleton(const StringName &p_path) { return; singleton = p_path; - Object *obj = GlobalConfig::get_singleton()->get_singleton_object(singleton); + Object *obj = ProjectSettings::get_singleton()->get_singleton_object(singleton); if (obj) { base_type = obj->get_class(); } @@ -383,7 +383,7 @@ void VisualScriptFunctionCall::_update_method_cache() { } else if (call_mode == CALL_MODE_SINGLETON) { - Object *obj = GlobalConfig::get_singleton()->get_singleton_object(singleton); + Object *obj = ProjectSettings::get_singleton()->get_singleton_object(singleton); if (obj) { type = obj->get_class(); script = obj->get_script(); @@ -568,11 +568,11 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const if (call_mode != CALL_MODE_SINGLETON) { property.usage = 0; } else { - List<GlobalConfig::Singleton> names; - GlobalConfig::get_singleton()->get_singletons(&names); + List<ProjectSettings::Singleton> names; + ProjectSettings::get_singleton()->get_singletons(&names); property.hint = PROPERTY_HINT_ENUM; String sl; - for (List<GlobalConfig::Singleton>::Element *E = names.front(); E; E = E->next()) { + for (List<ProjectSettings::Singleton>::Element *E = names.front(); E; E = E->next()) { if (sl != String()) sl += ","; sl += E->get().name; @@ -606,7 +606,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const property.hint_string = itos(get_visual_script()->get_instance_ID()); } else if (call_mode == CALL_MODE_SINGLETON) { - Object *obj = GlobalConfig::get_singleton()->get_singleton_object(singleton); + Object *obj = ProjectSettings::get_singleton()->get_singleton_object(singleton); if (obj) { property.hint = PROPERTY_HINT_METHOD_OF_INSTANCE; property.hint_string = itos(obj->get_instance_ID()); @@ -867,7 +867,7 @@ public: } break; case VisualScriptFunctionCall::CALL_MODE_SINGLETON: { - Object *object = GlobalConfig::get_singleton()->get_singleton_object(singleton); + Object *object = ProjectSettings::get_singleton()->get_singleton_object(singleton); if (!object) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = "Invalid singleton name: '" + String(singleton) + "'"; diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 5f24bcc2c3..69aa10ebca 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -29,10 +29,10 @@ /*************************************************************************/ #include "visual_script_nodes.h" -#include "global_config.h" #include "global_constants.h" #include "os/input.h" #include "os/os.h" +#include "project_settings.h" #include "scene/main/node.h" #include "scene/main/scene_tree.h" @@ -1190,8 +1190,8 @@ Ref<Resource> VisualScriptPreload::get_preload() const { void VisualScriptPreload::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_preload", "resource"), &VisualScriptPreload::set_preload); - ClassDB::bind_method(D_METHOD("get_preload"), &VisualScriptPreload::get_preload); + ClassDB::bind_method(D_METHOD("set_preload", "resource:Resource"), &VisualScriptPreload::set_preload); + ClassDB::bind_method(D_METHOD("get_preload:Resource"), &VisualScriptPreload::get_preload); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), "set_preload", "get_preload"); } @@ -1939,13 +1939,13 @@ public: VisualScriptNodeInstance *VisualScriptEngineSingleton::instance(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceEngineSingleton *instance = memnew(VisualScriptNodeInstanceEngineSingleton); - instance->singleton = GlobalConfig::get_singleton()->get_singleton_object(singleton); + instance->singleton = ProjectSettings::get_singleton()->get_singleton_object(singleton); return instance; } VisualScriptEngineSingleton::TypeGuess VisualScriptEngineSingleton::guess_output_type(TypeGuess *p_inputs, int p_output) const { - Object *obj = GlobalConfig::get_singleton()->get_singleton_object(singleton); + Object *obj = ProjectSettings::get_singleton()->get_singleton_object(singleton); TypeGuess tg; tg.type = Variant::OBJECT; if (obj) { @@ -1963,11 +1963,11 @@ void VisualScriptEngineSingleton::_bind_methods() { String cc; - List<GlobalConfig::Singleton> singletons; + List<ProjectSettings::Singleton> singletons; - GlobalConfig::get_singleton()->get_singletons(&singletons); + ProjectSettings::get_singleton()->get_singletons(&singletons); - for (List<GlobalConfig::Singleton>::Element *E = singletons.front(); E; E = E->next()) { + for (List<ProjectSettings::Singleton>::Element *E = singletons.front(); E; E = E->next()) { if (E->get().name == "VS" || E->get().name == "PS" || E->get().name == "PS2D" || E->get().name == "AS" || E->get().name == "TS" || E->get().name == "SS" || E->get().name == "SS2D") continue; //skip these, too simple named @@ -2596,10 +2596,10 @@ public: in_values.resize(in_count); for (int i = 0; i < in_count; i++) { - in_values[i] = p_inputs[i]; + in_values[i] = *p_inputs[i]; } - out_values.resize(in_count); + out_values.resize(out_count); work_mem.resize(work_mem_size); @@ -2645,6 +2645,7 @@ VisualScriptNodeInstance *VisualScriptCustomNode::instance(VisualScriptInstance VisualScriptNodeInstanceCustomNode *instance = memnew(VisualScriptNodeInstanceCustomNode); instance->instance = p_instance; + instance->node = this; instance->in_count = get_input_value_port_count(); instance->out_count = get_output_value_port_count(); @@ -2657,6 +2658,10 @@ VisualScriptNodeInstance *VisualScriptCustomNode::instance(VisualScriptInstance return instance; } +void VisualScriptCustomNode::_script_changed() { + ports_changed_notify(); +} + void VisualScriptCustomNode::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_sequence_port_count")); @@ -2679,6 +2684,8 @@ void VisualScriptCustomNode::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::INT, "_get_working_memory_size")); BIND_VMETHOD(MethodInfo(Variant::NIL, "_step:Variant", PropertyInfo(Variant::ARRAY, "inputs"), PropertyInfo(Variant::ARRAY, "outputs"), PropertyInfo(Variant::INT, "start_mode"), PropertyInfo(Variant::ARRAY, "working_mem"))); + ClassDB::bind_method(D_METHOD("_script_changed"), &VisualScriptCustomNode::_script_changed); + BIND_CONSTANT(START_MODE_BEGIN_SEQUENCE); BIND_CONSTANT(START_MODE_CONTINUE_SEQUENCE); BIND_CONSTANT(START_MODE_RESUME_YIELD); @@ -2691,6 +2698,7 @@ void VisualScriptCustomNode::_bind_methods() { } VisualScriptCustomNode::VisualScriptCustomNode() { + connect("script_changed", this, "_script_changed"); } ////////////////////////////////////////// @@ -3466,7 +3474,7 @@ void VisualScriptInputAction::_validate_property(PropertyInfo &property) const { String actions; List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); + ProjectSettings::get_singleton()->get_property_list(&pinfo); Vector<String> al; for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h index 5ae9a1b30b..7a3b26fe55 100644 --- a/modules/visual_script/visual_script_nodes.h +++ b/modules/visual_script/visual_script_nodes.h @@ -712,6 +712,8 @@ public: virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance); + void _script_changed(); + VisualScriptCustomNode(); }; diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp index eaf4215302..72f10b4f45 100644 --- a/modules/webm/video_stream_webm.cpp +++ b/modules/webm/video_stream_webm.cpp @@ -34,8 +34,8 @@ #include "mkvparser/mkvparser.h" -#include "global_config.h" #include "os/file_access.h" +#include "project_settings.h" #include "thirdparty/misc/yuv2rgb.h" @@ -168,7 +168,7 @@ void VideoStreamPlaybackWebm::play() { stop(); - delay_compensation = GlobalConfig::get_singleton()->get("audio/video_delay_compensation_ms"); + delay_compensation = ProjectSettings::get_singleton()->get("audio/video_delay_compensation_ms"); delay_compensation /= 1000.0; playing = true; diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp index 7b2127a211..d293f3ed30 100644 --- a/platform/android/audio_driver_jandroid.cpp +++ b/platform/android/audio_driver_jandroid.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "audio_driver_jandroid.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" #include "thread_jandroid.h" #ifndef ANDROID_NATIVE_ACTIVITY diff --git a/platform/android/detect.py b/platform/android/detect.py index 7508c9ed0e..fae1df3f27 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -87,20 +87,6 @@ def configure(env): env['SPAWN'] = mySpawn - ## Build type - - if (env["target"].startswith("release")): - env.Append(LINKFLAGS=['-O2']) - env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-ffast-math', '-funsafe-math-optimizations', '-fomit-frame-pointer']) - if (can_vectorize): - env.Append(CPPFLAGS=['-ftree-vectorize']) - if (env["target"] == "release_debug"): - env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) - elif (env["target"] == "debug"): - env.Append(LINKFLAGS=['-O0']) - env.Append(CPPFLAGS=['-O0', '-D_DEBUG', '-UNDEBUG', '-DDEBUG_ENABLED', - '-DDEBUG_MEMORY_ENABLED', '-g', '-fno-limit-debug-info']) - ## Architecture if env['android_arch'] not in ['armv7', 'armv6', 'x86']: @@ -133,6 +119,20 @@ def configure(env): else: env.extra_suffix = ".armv7" + env.extra_suffix + ## Build type + + if (env["target"].startswith("release")): + env.Append(LINKFLAGS=['-O2']) + env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-ffast-math', '-funsafe-math-optimizations', '-fomit-frame-pointer']) + if (can_vectorize): + env.Append(CPPFLAGS=['-ftree-vectorize']) + if (env["target"] == "release_debug"): + env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) + elif (env["target"] == "debug"): + env.Append(LINKFLAGS=['-O0']) + env.Append(CPPFLAGS=['-O0', '-D_DEBUG', '-UNDEBUG', '-DDEBUG_ENABLED', + '-DDEBUG_MEMORY_ENABLED', '-g', '-fno-limit-debug-info']) + ## Compiler configuration env['SHLIBSUFFIX'] = '.so' @@ -178,7 +178,7 @@ def configure(env): env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"]) env.Append(CPPFLAGS=string.split('-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing')) - env.Append(CPPFLAGS=string.split('-DANDROID -DNO_STATVFS -DGLES2_ENABLED')) + env.Append(CPPFLAGS=string.split('-DNO_STATVFS -DGLES2_ENABLED')) env['neon_enabled'] = False if env['android_arch'] == 'x86': diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 95f48521f8..97f239c4da 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -31,13 +31,13 @@ #include "editor/editor_export.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" -#include "global_config.h" #include "io/marshalls.h" #include "io/zip_io.h" #include "os/file_access.h" #include "os/os.h" #include "platform/android/logo.gen.h" #include "platform/android/run_icon.gen.h" +#include "project_settings.h" #include "version.h" #include <string.h> #if 0 @@ -555,8 +555,8 @@ void EditorExportPlatformAndroid::_fix_resources(Vector<uint8_t>& p_manifest) { String lang = str.substr(str.find_last("-")+1,str.length()).replace("-","_"); String prop = "application/config/name_"+lang; - if (GlobalConfig::get_singleton()->has(prop)) { - str = GlobalConfig::get_singleton()->get(prop); + if (ProjectSettings::get_singleton()->has(prop)) { + str = ProjectSettings::get_singleton()->get(prop); } else { str = get_project_name(); } @@ -628,7 +628,7 @@ String EditorExportPlatformAndroid::get_project_name() const { if (this->name!="") { aname=this->name; } else { - aname = GlobalConfig::get_singleton()->get("application/config/name"); + aname = ProjectSettings::get_singleton()->get("application/config/name"); } @@ -1144,7 +1144,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d if (!found) { - String appicon = GlobalConfig::get_singleton()->get("application/config/icon"); + String appicon = ProjectSettings::get_singleton()->get("application/config/icon"); if (appicon!="" && appicon.ends_with(".png")) { FileAccess*f = FileAccess::open(appicon,FileAccess::READ); if (f) { @@ -1763,7 +1763,7 @@ Error EditorExportPlatformAndroid::run(int p_device, int p_flags) { String EditorExportPlatformAndroid::get_package_name() { String pname = package; - String basename = GlobalConfig::get_singleton()->get("application/config/name"); + String basename = ProjectSettings::get_singleton()->get("application/config/name"); basename=basename.to_lower(); String name; @@ -2208,7 +2208,7 @@ class EditorExportAndroid : public EditorExportPlatform { if (p_name != "") { aname = p_name; } else { - aname = GlobalConfig::get_singleton()->get("application/config/name"); + aname = ProjectSettings::get_singleton()->get("application/config/name"); } if (aname == "") { @@ -2221,7 +2221,7 @@ class EditorExportAndroid : public EditorExportPlatform { String get_package_name(const String &p_package) { String pname = p_package; - String basename = GlobalConfig::get_singleton()->get("application/config/name"); + String basename = ProjectSettings::get_singleton()->get("application/config/name"); basename = basename.to_lower(); String name; @@ -2537,6 +2537,10 @@ class EditorExportAndroid : public EditorExportPlatform { }*/ } + if (tname == "uses-feature" && /*nspace=="android" &&*/ attrname == "glEsVersion") { + print_line("version number: " + itos(decode_uint32(&p_manifest[iofs + 16]))); + } + if (tname == "uses-permission" && /*nspace=="android" &&*/ attrname == "name") { if (value.begins_with("godot.custom")) { @@ -2751,8 +2755,8 @@ class EditorExportAndroid : public EditorExportPlatform { String lang = str.substr(str.find_last("-") + 1, str.length()).replace("-", "_"); String prop = "application/config/name_" + lang; - if (GlobalConfig::get_singleton()->has(prop)) { - str = GlobalConfig::get_singleton()->get(prop); + if (ProjectSettings::get_singleton()->has(prop)) { + str = ProjectSettings::get_singleton()->get(prop); } else { str = get_project_name(package_name); } @@ -2826,11 +2830,17 @@ public: public: virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { - r_features->push_back("etc"); + int api = p_preset->get("graphics/api"); + if (api == 0) + r_features->push_back("etc"); + else + r_features->push_back("etc2"); } virtual void get_export_options(List<ExportOption> *r_options) { + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "graphics/api", PROPERTY_HINT_ENUM, "OpenGL ES 2.0,OpenGL ES 3.0"), 1)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/32_bits_framebuffer"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "apk"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE, "apk"), "")); @@ -2843,7 +2853,6 @@ public: r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architecture/arm"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architecture/x86"), false)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/use_32_bits_view"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "screen/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true)); @@ -2875,6 +2884,11 @@ public: virtual String get_name() const { return "Android"; } + + virtual String get_os_name() const { + return "Android"; + } + virtual Ref<Texture> get_logo() const { return logo; } @@ -3219,7 +3233,7 @@ public: if (!found) { - String appicon = GlobalConfig::get_singleton()->get("application/config/icon"); + String appicon = ProjectSettings::get_singleton()->get("application/config/icon"); if (appicon != "" && appicon.ends_with(".png")) { FileAccess *f = FileAccess::open(appicon, FileAccess::READ); if (f) { @@ -3527,6 +3541,12 @@ public: return OK; } + virtual void get_platform_features(List<String> *r_features) { + + r_features->push_back("mobile"); + r_features->push_back("Android"); + } + EditorExportAndroid() { Ref<Image> img = memnew(Image(_android_logo)); diff --git a/platform/android/globals/global_defaults.cpp b/platform/android/globals/global_defaults.cpp index f708ad5dd7..6bdc6b337c 100644 --- a/platform/android/globals/global_defaults.cpp +++ b/platform/android/globals/global_defaults.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "global_defaults.h" -#include "global_config.h" +#include "project_settings.h" void register_android_global_defaults() { @@ -37,6 +37,6 @@ void register_android_global_defaults() { GLOBAL_DEF("display.Android/driver","GLES2"); //GLOBAL_DEF("rasterizer.Android/trilinear_mipmap_filter",false); - GlobalConfig::get_singleton()->set_custom_property_info("display.Android/driver",PropertyInfo(Variant::STRING,"display.Android/driver",PROPERTY_HINT_ENUM,"GLES2")); + ProjectSettings::get_singleton()->set_custom_property_info("display.Android/driver",PropertyInfo(Variant::STRING,"display.Android/driver",PROPERTY_HINT_ENUM,"GLES2")); */ } diff --git a/platform/android/godot_android.cpp b/platform/android/godot_android.cpp index 3a21f9212f..71db03049a 100644 --- a/platform/android/godot_android.cpp +++ b/platform/android/godot_android.cpp @@ -36,9 +36,9 @@ #include <GLES2/gl2.h> #include "file_access_android.h" -#include "global_config.h" #include "main/main.h" #include "os_android.h" +#include "project_settings.h" #include <android/log.h> #include <android/sensor.h> #include <android/window.h> @@ -623,7 +623,7 @@ static void engine_handle_cmd(struct android_app *app, int32_t cmd) { #else Error err = Main::setup("apk", 0, NULL); - String modules = GlobalConfig::get_singleton()->get("android/modules"); + String modules = ProjectSettings::get_singleton()->get("android/modules"); Vector<String> mods = modules.split(",", false); mods.push_back("GodotOS"); __android_log_print(ANDROID_LOG_INFO, "godot", "mod count: %i", mods.size()); @@ -859,7 +859,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerSingleton(JNIEnv s->set_instance(env->NewGlobalRef(p_object)); jni_singletons[singname] = s; - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton(singname, s)); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton(singname, s)); } static Variant::Type get_jni_type(const String &p_type) { @@ -926,7 +926,7 @@ JNIEXPORT jstring JNICALL Java_org_godotengine_godot_Godot_getGlobal(JNIEnv *env String js = env->GetStringUTFChars(path, NULL); - return env->NewStringUTF(GlobalConfig::get_singleton()->get(js).operator String().utf8().get_data()); + return env->NewStringUTF(ProjectSettings::get_singleton()->get(js).operator String().utf8().get_data()); } JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerMethod(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args) { diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index d4bd443689..0508989d2f 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -36,11 +36,11 @@ #include "dir_access_jandroid.h" #include "file_access_android.h" #include "file_access_jandroid.h" -#include "global_config.h" #include "java_class_wrapper.h" #include "main/input_default.h" #include "main/main.h" #include "os_android.h" +#include "project_settings.h" #include "thread_jandroid.h" #include <unistd.h> @@ -883,7 +883,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en __android_log_print(ANDROID_LOG_INFO, "godot", "*****SETUP OK"); //video driver is determined here, because once initialized, it can't be changed - String vd = GlobalConfig::get_singleton()->get("display/driver"); + String vd = ProjectSettings::get_singleton()->get("display/driver"); env->CallVoidMethod(_godot_instance, _on_video_init, (jboolean) true); @@ -930,12 +930,12 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, job static void _initialize_java_modules() { - if (!GlobalConfig::get_singleton()->has("android/modules")) { + if (!ProjectSettings::get_singleton()->has("android/modules")) { print_line("ANDROID MODULES: Nothing to load, aborting"); return; } - String modules = GlobalConfig::get_singleton()->get("android/modules"); + String modules = ProjectSettings::get_singleton()->get("android/modules"); modules = modules.strip_edges(); if (modules == String()) { return; @@ -1005,7 +1005,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job // because of the way android forces you to do everything with threads java_class_wrapper = memnew(JavaClassWrapper(_godot_instance)); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("JavaClassWrapper", java_class_wrapper)); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("JavaClassWrapper", java_class_wrapper)); _initialize_java_modules(); Main::setup2(); @@ -1504,8 +1504,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_singleton(JNIEnv *env s->set_instance(env->NewGlobalRef(p_object)); jni_singletons[singname] = s; - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton(singname, s)); - GlobalConfig::get_singleton()->set(singname, s); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton(singname, s)); + ProjectSettings::get_singleton()->set(singname, s); } static Variant::Type get_jni_type(const String &p_type) { @@ -1578,7 +1578,7 @@ JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv * String js = env->GetStringUTFChars(path, NULL); - return env->NewStringUTF(GlobalConfig::get_singleton()->get(js).operator String().utf8().get_data()); + return env->NewStringUTF(ProjectSettings::get_singleton()->get(js).operator String().utf8().get_data()); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args) { diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 9010b9e7da..ad46ceb43f 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "os_android.h" -#include "core/global_config.h" #include "core/io/file_access_buffered_fa.h" +#include "core/project_settings.h" #include "drivers/gles3/rasterizer_gles3.h" #include "drivers/unix/dir_access_unix.h" #include "drivers/unix/file_access_unix.h" @@ -677,7 +677,7 @@ String OS_Android::get_data_dir() const { } return "."; - //return GlobalConfig::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir"); + //return ProjectSettings::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir"); } void OS_Android::set_screen_orientation(ScreenOrientation p_orientation) { @@ -741,6 +741,10 @@ String OS_Android::get_joy_guid(int p_device) const { return input->get_joy_guid_remapped(p_device); } +bool OS_Android::_check_internal_feature_support(const String &p_feature) { + return p_feature == "mobile" || p_feature == "etc" || p_feature == "etc2"; //TODO support etc2 only if GLES3 driver is selected +} + OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion) { use_apk_expansion = p_use_apk_expansion; diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 897c71a7df..393bc68d8a 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -243,6 +243,7 @@ public: virtual String get_joy_guid(int p_device) const; void joy_connection_changed(int p_device, bool p_connected, String p_name); + virtual bool _check_internal_feature_support(const String &p_feature); OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion); ~OS_Android(); }; diff --git a/platform/haiku/audio_driver_media_kit.cpp b/platform/haiku/audio_driver_media_kit.cpp index 9c4f6d3aba..93351e0799 100644 --- a/platform/haiku/audio_driver_media_kit.cpp +++ b/platform/haiku/audio_driver_media_kit.cpp @@ -31,7 +31,7 @@ #ifdef MEDIA_KIT_ENABLED -#include "global_config.h" +#include "project_settings.h" int32_t *AudioDriverMediaKit::samples_in = NULL; diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp index 3131f2bf1e..e897d4c385 100644 --- a/platform/haiku/os_haiku.cpp +++ b/platform/haiku/os_haiku.cpp @@ -331,3 +331,8 @@ void OS_Haiku::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) c String OS_Haiku::get_executable_path() const { return OS::get_executable_path(); } + +bool OS_Haiku::_check_internal_feature_support(const String &p_feature) { + + return p_feature == "pc" || p_feature == "s3tc"; +} diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h index 83e44734a6..256c9eecf7 100644 --- a/platform/haiku/os_haiku.h +++ b/platform/haiku/os_haiku.h @@ -120,6 +120,8 @@ public: virtual PowerState get_power_state(); virtual int get_power_seconds_left(); virtual int get_power_percent_left(); + + virtual bool _check_internal_feature_support(const String &p_feature); }; #endif diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm index b6cd43b3a2..da6dfcf53f 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -30,7 +30,7 @@ #import "app_delegate.h" #include "audio_driver_iphone.h" -#include "core/global_config.h" +#include "core/project_settings.h" #import "gl_view.h" #include "main/main.h" #include "os_iphone.h" @@ -449,14 +449,14 @@ static int frame_count = 0; NSString *str = (NSString *)value; String uval = String::utf8([str UTF8String]); - GlobalConfig::get_singleton()->set("Info.plist/" + ukey, uval); + ProjectSettings::get_singleton()->set("Info.plist/" + ukey, uval); } else if ([value isKindOfClass:[NSNumber class]]) { NSNumber *n = (NSNumber *)value; double dval = [n doubleValue]; - GlobalConfig::get_singleton()->set("Info.plist/" + ukey, dval); + ProjectSettings::get_singleton()->set("Info.plist/" + ukey, dval); }; // do stuff } @@ -645,10 +645,10 @@ static int frame_count = 0; #ifdef MODULE_GAME_ANALYTICS_ENABLED printf("********************* didFinishLaunchingWithOptions\n"); - if (!GlobalConfig::get_singleton()->has("mobileapptracker/advertiser_id")) { + if (!ProjectSettings::get_singleton()->has("mobileapptracker/advertiser_id")) { return; } - if (!GlobalConfig::get_singleton()->has("mobileapptracker/conversion_key")) { + if (!ProjectSettings::get_singleton()->has("mobileapptracker/conversion_key")) { return; } diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 0960ec8791..a5efae8678 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -32,13 +32,13 @@ #include "editor/editor_export.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" -#include "global_config.h" #include "io/marshalls.h" #include "io/resource_saver.h" #include "io/zip_io.h" #include "os/file_access.h" #include "os/os.h" #include "platform/osx/logo.gen.h" +#include "project_settings.h" #include "string.h" #include "version.h" @@ -60,6 +60,7 @@ protected: public: virtual String get_name() const { return "iOS"; } + virtual String get_os_name() const { return "iOS"; } virtual Ref<Texture> get_logo() const { return logo; } virtual String get_binary_extension() const { return "xcodeproj"; } @@ -67,6 +68,12 @@ public: virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const; + virtual void get_platform_features(List<String> *r_features) { + + r_features->push_back("mobile"); + r_features->push_back("iOS"); + } + EditorExportPlatformIOS(); ~EditorExportPlatformIOS(); }; @@ -175,8 +182,8 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p String pkg_name; if (p_preset->get("application/name") != "") pkg_name = p_preset->get("application/name"); // app_name - else if (String(GlobalConfig::get_singleton()->get("application/name")) != "") - pkg_name = String(GlobalConfig::get_singleton()->get("application/name")); + else if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") + pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name")); else pkg_name = "Unnamed"; diff --git a/platform/iphone/gl_view.mm b/platform/iphone/gl_view.mm index 6270fa85f2..4b137b7ffa 100644 --- a/platform/iphone/gl_view.mm +++ b/platform/iphone/gl_view.mm @@ -29,7 +29,7 @@ /*************************************************************************/ #import "gl_view.h" -#include "core/global_config.h" +#include "core/project_settings.h" #include "core/os/keyboard.h" #include "os_iphone.h" #include "servers/audio_server.h" @@ -77,7 +77,7 @@ void _hide_keyboard() { }; bool _play_video(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) { - p_path = GlobalConfig::get_singleton()->globalize_path(p_path); + p_path = ProjectSettings::get_singleton()->globalize_path(p_path); NSString *file_path = [[[NSString alloc] initWithUTF8String:p_path.utf8().get_data()] autorelease]; diff --git a/platform/iphone/globals/global_defaults.cpp b/platform/iphone/globals/global_defaults.cpp index b320be2f85..aa4662302d 100644 --- a/platform/iphone/globals/global_defaults.cpp +++ b/platform/iphone/globals/global_defaults.cpp @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "global_defaults.h" -#include "global_config.h" +#include "project_settings.h" void register_iphone_global_defaults() { /*GLOBAL_DEF("rasterizer.iOS/use_fragment_lighting",false); GLOBAL_DEF("rasterizer.iOS/fp16_framebuffer",false); GLOBAL_DEF("display.iOS/driver","GLES2"); - GlobalConfig::get_singleton()->set_custom_property_info("display.iOS/driver",PropertyInfo(Variant::STRING,"display.iOS/driver",PROPERTY_HINT_ENUM,"GLES1,GLES2")); + ProjectSettings::get_singleton()->set_custom_property_info("display.iOS/driver",PropertyInfo(Variant::STRING,"display.iOS/driver",PROPERTY_HINT_ENUM,"GLES1,GLES2")); GLOBAL_DEF("display.iOS/use_cadisplaylink",true); */ } diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index b244edbff6..1329c94198 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -38,10 +38,10 @@ #include "audio_driver_iphone.h" #include "main/main.h" -#include "core/global_config.h" #include "core/io/file_access_pack.h" #include "core/os/dir_access.h" #include "core/os/file_access.h" +#include "core/project_settings.h" #include "sem_iphone.h" @@ -138,28 +138,28 @@ void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_ /* #ifdef IOS_SCORELOOP_ENABLED scoreloop = memnew(ScoreloopIOS); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("Scoreloop", scoreloop)); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("Scoreloop", scoreloop)); scoreloop->connect(); #endif */ #ifdef GAME_CENTER_ENABLED game_center = memnew(GameCenter); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("GameCenter", game_center)); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("GameCenter", game_center)); game_center->connect(); #endif #ifdef STOREKIT_ENABLED store_kit = memnew(InAppStore); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("InAppStore", store_kit)); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("InAppStore", store_kit)); #endif #ifdef ICLOUD_ENABLED icloud = memnew(ICloud); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("ICloud", icloud)); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("ICloud", icloud)); //icloud->connect(); #endif - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("iOS", memnew(iOS))); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("iOS", memnew(iOS))); }; MainLoop *OSIPhone::get_main_loop() const { @@ -517,7 +517,7 @@ Error OSIPhone::native_video_play(String p_path, float p_volume, String p_audio_ print("Unable to play %S using the native player as it resides in a .pck file\n", p_path.c_str()); return ERR_INVALID_PARAMETER; } else { - p_path = p_path.replace("res:/", GlobalConfig::get_singleton()->get_resource_path()); + p_path = p_path.replace("res:/", ProjectSettings::get_singleton()->get_resource_path()); } } else if (p_path.begins_with("user://")) p_path = p_path.replace("user:/", get_data_dir()); @@ -552,6 +552,11 @@ void OSIPhone::native_video_stop() { _stop_video(); } +bool OSIPhone::_check_internal_feature_support(const String &p_feature) { + + return p_feature == "mobile" || p_feature == "etc" || p_feature == "pvrtc" || p_feature == "etc2"; +} + OSIPhone::OSIPhone(int width, int height) { main_loop = NULL; diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 4031b7524c..b15e9fdffb 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -200,6 +200,7 @@ public: virtual void native_video_focus_out(); virtual void native_video_stop(); + virtual bool _check_internal_feature_support(const String &p_feature); OSIPhone(int width, int height); ~OSIPhone(); }; diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub index ca9fcb54e4..b804863ee1 100644 --- a/platform/javascript/SCsub +++ b/platform/javascript/SCsub @@ -19,7 +19,7 @@ javascript_objects = [] for x in javascript_files: javascript_objects.append(env_javascript.Object(x)) -env.Append(LINKFLAGS=["-s", "EXPORTED_FUNCTIONS=\"['_main','_audio_server_mix_function','_main_after_fs_sync']\""]) +env.Append(LINKFLAGS=["-s", "EXPORTED_FUNCTIONS=\"['_main','_audio_server_mix_function','_main_after_fs_sync','_send_notification']\""]) env.Append(LINKFLAGS=["--shell-file", '"platform/javascript/godot_shell.html"']) # output file name without file extension diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index 4bdfdae39e..b436d52363 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -61,6 +61,7 @@ public: virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; virtual String get_name() const; + virtual String get_os_name() const; virtual Ref<Texture> get_logo() const; virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const; @@ -74,6 +75,12 @@ public: virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags); virtual Ref<Texture> get_run_icon() const; + virtual void get_platform_features(List<String> *r_features) { + + r_features->push_back("web"); + r_features->push_back("JavaScript"); + } + EditorExportPlatformJavaScript(); }; @@ -167,6 +174,11 @@ String EditorExportPlatformJavaScript::get_name() const { return "HTML5"; } +String EditorExportPlatformJavaScript::get_os_name() const { + + return "JavaScript"; +} + Ref<Texture> EditorExportPlatformJavaScript::get_logo() const { return logo; diff --git a/platform/javascript/godot_shell.html b/platform/javascript/godot_shell.html index 6c7069a8f0..ee7399a129 100644 --- a/platform/javascript/godot_shell.html +++ b/platform/javascript/godot_shell.html @@ -83,6 +83,10 @@ color: white; } + #canvas:focus { + outline: none; + } + /* Status display * ============== */ @@ -147,7 +151,7 @@ $GODOT_HEAD_INCLUDE </head> <body> <div id="container"> - <canvas id="canvas" width="640" height="480" onclick="canvas.ownerDocument.defaultView.focus();" oncontextmenu="event.preventDefault();"> + <canvas id="canvas" width="640" height="480" tabindex="0" oncontextmenu="event.preventDefault();"> HTML5 canvas appears to be unsupported in the current browser.<br /> Please try updating or use a different browser. </canvas> diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 9df26f1471..0708d46196 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "os_javascript.h" -#include "core/global_config.h" #include "core/io/file_access_buffered_fa.h" +#include "core/project_settings.h" #include "dom_keys.h" #include "drivers/gles3/rasterizer_gles3.h" #include "drivers/unix/dir_access_unix.h" @@ -145,6 +145,31 @@ static EM_BOOL _fullscreen_change_callback(int event_type, const EmscriptenFulls static InputDefault *_input; +static bool is_canvas_focused() { + + /* clang-format off */ + return EM_ASM_INT_V( + return document.activeElement == Module.canvas; + ); + /* clang-format on */ +} + +static void focus_canvas() { + + /* clang-format off */ + EM_ASM( + Module.canvas.focus(); + ); + /* clang-format on */ +} + +static bool _cursor_inside_canvas = true; + +static bool is_cursor_inside_canvas() { + + return _cursor_inside_canvas; +} + static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent *mouse_event, void *user_data) { ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_MOUSEDOWN && event_type != EMSCRIPTEN_EVENT_MOUSEUP, false); @@ -164,26 +189,42 @@ static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent } int mask = _input->get_mouse_button_mask(); - if (ev->is_pressed()) + if (ev->is_pressed()) { + // since the event is consumed, focus manually + if (!is_canvas_focused()) { + focus_canvas(); + } mask |= 1 << ev->get_button_index(); - else + } else if (mask & (1 << ev->get_button_index())) { mask &= ~(1 << ev->get_button_index()); + } else { + // release event, but press was outside the canvas, so ignore + return false; + } ev->set_button_mask(mask >> 1); _input->parse_input_event(ev); + // prevent selection dragging return true; } static EM_BOOL _mousemove_callback(int event_type, const EmscriptenMouseEvent *mouse_event, void *user_data) { ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_MOUSEMOVE, false); + OS_JavaScript *os = static_cast<OS_JavaScript *>(user_data); + int input_mask = _input->get_mouse_button_mask(); + Point2 pos = Point2(mouse_event->canvasX, mouse_event->canvasY); + // outside the canvas, only read mouse movement if dragging started inside + // the canvas; imitating desktop app behaviour + if (!is_cursor_inside_canvas() && !input_mask) + return false; Ref<InputEventMouseMotion> ev; ev.instance(); dom2godot_mod(mouse_event, ev); - ev->set_button_mask(_input->get_mouse_button_mask() >> 1); + ev->set_button_mask(input_mask >> 1); - ev->set_position(Point2(mouse_event->canvasX, mouse_event->canvasY)); + ev->set_position(pos); ev->set_global_position(ev->get_position()); ev->set_relative(_input->get_mouse_position() - ev->get_position()); @@ -191,12 +232,20 @@ static EM_BOOL _mousemove_callback(int event_type, const EmscriptenMouseEvent *m ev->set_speed(_input->get_last_mouse_speed()); _input->parse_input_event(ev); - return true; + // don't suppress mouseover/leave events + return false; } static EM_BOOL _wheel_callback(int event_type, const EmscriptenWheelEvent *wheel_event, void *user_data) { ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_WHEEL, false); + if (!is_canvas_focused()) { + if (is_cursor_inside_canvas()) { + focus_canvas(); + } else { + return false; + } + } Ref<InputEventMouseButton> ev; ev.instance(); @@ -387,6 +436,15 @@ static EM_BOOL joy_callback_func(int p_type, const EmscriptenGamepadEvent *p_eve return false; } +extern "C" { +void send_notification(int notif) { + if (notif == MainLoop::NOTIFICATION_WM_MOUSE_ENTER || notif == MainLoop::NOTIFICATION_WM_MOUSE_EXIT) { + _cursor_inside_canvas = notif == MainLoop::NOTIFICATION_WM_MOUSE_ENTER; + } + OS_JavaScript::get_singleton()->get_main_loop()->notification(notif); +} +} + void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { print_line("Init OS"); @@ -465,17 +523,17 @@ void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, i EM_CHECK(ev) EMSCRIPTEN_RESULT result; - SET_EM_CALLBACK("#canvas", mousemove, _mousemove_callback) + SET_EM_CALLBACK("#window", mousemove, _mousemove_callback) SET_EM_CALLBACK("#canvas", mousedown, _mousebutton_callback) - SET_EM_CALLBACK("#canvas", mouseup, _mousebutton_callback) - SET_EM_CALLBACK("#canvas", wheel, _wheel_callback) - SET_EM_CALLBACK("#canvas", touchstart, _touchpress_callback) - SET_EM_CALLBACK("#canvas", touchmove, _touchmove_callback) - SET_EM_CALLBACK("#canvas", touchend, _touchpress_callback) - SET_EM_CALLBACK("#canvas", touchcancel, _touchpress_callback) - SET_EM_CALLBACK(NULL, keydown, _keydown_callback) - SET_EM_CALLBACK(NULL, keypress, _keypress_callback) - SET_EM_CALLBACK(NULL, keyup, _keyup_callback) + SET_EM_CALLBACK("#window", mouseup, _mousebutton_callback) + SET_EM_CALLBACK("#window", wheel, _wheel_callback) + SET_EM_CALLBACK("#window", touchstart, _touchpress_callback) + SET_EM_CALLBACK("#window", touchmove, _touchmove_callback) + SET_EM_CALLBACK("#window", touchend, _touchpress_callback) + SET_EM_CALLBACK("#window", touchcancel, _touchpress_callback) + SET_EM_CALLBACK("#canvas", keydown, _keydown_callback) + SET_EM_CALLBACK("#canvas", keypress, _keypress_callback) + SET_EM_CALLBACK("#canvas", keyup, _keyup_callback) SET_EM_CALLBACK(NULL, resize, _browser_resize_callback) SET_EM_CALLBACK(NULL, fullscreenchange, _fullscreen_change_callback) SET_EM_CALLBACK_NODATA(gamepadconnected, joy_callback_func) @@ -485,9 +543,24 @@ void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, i #undef SET_EM_CALLBACK #undef EM_CHECK + /* clang-format off */ + EM_ASM_ARGS({ + const send_notification = Module.cwrap('send_notification', null, ['number']); + const notifs = arguments; + (['mouseover', 'mouseleave', 'focus', 'blur']).forEach(function(event, i) { + Module.canvas.addEventListener(event, send_notification.bind(this, notifs[i])); + }); + }, + MainLoop::NOTIFICATION_WM_MOUSE_ENTER, + MainLoop::NOTIFICATION_WM_MOUSE_EXIT, + MainLoop::NOTIFICATION_WM_FOCUS_IN, + MainLoop::NOTIFICATION_WM_FOCUS_OUT + ); +/* clang-format on */ + #ifdef JAVASCRIPT_EVAL_ENABLED javascript_eval = memnew(JavaScript); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("JavaScript", javascript_eval)); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("JavaScript", javascript_eval)); #endif visual_server->init(); @@ -777,20 +850,6 @@ void OS_JavaScript::main_loop_end() { main_loop->finish(); } -void OS_JavaScript::main_loop_focusout() { - - if (main_loop) - main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT); - //audio_driver_javascript.set_pause(true); -} - -void OS_JavaScript::main_loop_focusin() { - - if (main_loop) - main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN); - //audio_driver_javascript.set_pause(false); -} - void OS_JavaScript::process_accelerometer(const Vector3 &p_accelerometer) { input->set_accelerometer(p_accelerometer); @@ -828,7 +887,7 @@ String OS_JavaScript::get_data_dir() const { return get_data_dir_func(); */ return "/userfs"; - //return GlobalConfig::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir"); + //return ProjectSettings::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir"); }; String OS_JavaScript::get_executable_path() const { @@ -911,6 +970,11 @@ int OS_JavaScript::get_power_percent_left() { return power_manager->get_power_percent_left(); } +bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) { + + return p_feature == "web" || p_feature == "s3tc"; // TODO check for these features really being available +} + OS_JavaScript::OS_JavaScript(const char *p_execpath, GetDataDirFunc p_get_data_dir_func) { set_cmdline(p_execpath, get_cmdline_args()); main_loop = NULL; diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 65269148ec..24e96e20dd 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -164,6 +164,8 @@ public: virtual int get_power_seconds_left(); virtual int get_power_percent_left(); + virtual bool _check_internal_feature_support(const String &p_feature); + OS_JavaScript(const char *p_execpath, GetDataDirFunc p_get_data_dir_func); ~OS_JavaScript(); }; diff --git a/platform/osx/audio_driver_osx.cpp b/platform/osx/audio_driver_osx.cpp index a4233b5264..dabc7989c0 100644 --- a/platform/osx/audio_driver_osx.cpp +++ b/platform/osx/audio_driver_osx.cpp @@ -60,13 +60,14 @@ Error AudioDriverOSX::initDevice() { zeromem(&desc, sizeof(desc)); desc.componentType = kAudioUnitType_Output; - desc.componentSubType = 0; /* !!! FIXME: ? */ - comp = AudioComponentFindNext(NULL, &desc); + desc.componentSubType = kAudioUnitSubType_HALOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; + comp = AudioComponentFindNext(NULL, &desc); + ERR_FAIL_COND_V(comp == NULL, FAILED); + result = AudioComponentInstanceNew(comp, &audio_unit); ERR_FAIL_COND_V(result != noErr, FAILED); - ERR_FAIL_COND_V(comp == NULL, FAILED); result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, scope, bus, &strdesc, sizeof(strdesc)); ERR_FAIL_COND_V(result != noErr, FAILED); diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index ca5535f771..03f424de8d 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -32,13 +32,13 @@ #include "editor/editor_export.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" -#include "global_config.h" #include "io/marshalls.h" #include "io/resource_saver.h" #include "io/zip_io.h" #include "os/file_access.h" #include "os/os.h" #include "platform/osx/logo.gen.h" +#include "project_settings.h" #include "string.h" #include "version.h" #include <sys/stat.h> @@ -64,6 +64,7 @@ protected: public: virtual String get_name() const { return "Mac OSX"; } + virtual String get_os_name() const { return "OSX"; } virtual Ref<Texture> get_logo() const { return logo; } #ifdef OSX_ENABLED @@ -75,6 +76,13 @@ public: virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const; + virtual void get_platform_features(List<String> *r_features) { + + r_features->push_back("pc"); + r_features->push_back("s3tc"); + r_features->push_back("OSX"); + } + EditorExportPlatformOSX(); ~EditorExportPlatformOSX(); }; @@ -275,8 +283,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p String pkg_name; if (p_preset->get("application/name") != "") pkg_name = p_preset->get("application/name"); // app_name - else if (String(GlobalConfig::get_singleton()->get("application/name")) != "") - pkg_name = String(GlobalConfig::get_singleton()->get("application/name")); + else if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") + pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name")); else pkg_name = "Unnamed"; @@ -345,7 +353,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p if (p_preset->get("application/icon") != "") iconpath = p_preset->get("application/icon"); else - iconpath = GlobalConfig::get_singleton()->get("application/config/icon"); + iconpath = ProjectSettings::get_singleton()->get("application/config/icon"); print_line("icon? " + iconpath); if (iconpath != "") { Ref<Image> icon; @@ -438,7 +446,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p /** When exporting for OSX from any other platform we don't have access to code signing or creating DMGs so we'll wrap the bundle into a zip file. - Should probably find a nicer way to have just one export method instead of duplicating the method like this but I would the code got very + Should probably find a nicer way to have just one export method instead of duplicating the method like this but I would the code got very messy with switches inside of it. **/ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { @@ -484,8 +492,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p String pkg_name; if (p_preset->get("application/name") != "") pkg_name = p_preset->get("application/name"); // app_name - else if (String(GlobalConfig::get_singleton()->get("application/config/name")) != "") - pkg_name = String(GlobalConfig::get_singleton()->get("application/config/name")); + else if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") + pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name")); else pkg_name = "Unnamed"; @@ -539,7 +547,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p if (p_preset->get("application/icon") != "") iconpath = p_preset->get("application/icon"); else - iconpath = GlobalConfig::get_singleton()->get("application/config/icon"); + iconpath = ProjectSettings::get_singleton()->get("application/config/icon"); print_line("icon? " + iconpath); if (iconpath != "") { Ref<Image> icon; diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index a3036b1a8a..44f4334786 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -210,6 +210,8 @@ public: virtual int get_power_seconds_left(); virtual int get_power_percent_left(); + virtual bool _check_internal_feature_support(const String &p_feature); + void run(); void set_mouse_mode(MouseMode p_mode); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 87c25a5356..82c1313326 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -80,6 +80,7 @@ static int mouse_y = 0; static int prev_mouse_x = 0; static int prev_mouse_y = 0; static int button_mask = 0; +static bool mouse_down_control = false; @interface GodotApplication : NSApplication @end @@ -285,41 +286,48 @@ static int button_mask = 0; //setModeCursor(window, window->cursorMode); } -- (void)mouseDown:(NSEvent *)event { - - button_mask |= BUTTON_MASK_LEFT; +static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { + if (pressed) { + button_mask |= mask; + } else { + button_mask &= ~mask; + } Ref<InputEventMouseButton> mb; mb.instance(); get_key_modifier_state([event modifierFlags], mb); - mb->set_button_index(BUTTON_LEFT); - mb->set_pressed(true); + mb->set_button_index(index); + mb->set_pressed(pressed); mb->set_position(Vector2(mouse_x, mouse_y)); mb->set_global_position(Vector2(mouse_x, mouse_y)); mb->set_button_mask(button_mask); - mb->set_doubleclick([event clickCount] == 2); + if (index == BUTTON_LEFT && pressed) { + mb->set_doubleclick([event clickCount] == 2); + } OS_OSX::singleton->push_input(mb); } +- (void)mouseDown:(NSEvent *)event { + if (([event modifierFlags] & NSControlKeyMask)) { + mouse_down_control = true; + _mouseDownEvent(event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true); + } else { + mouse_down_control = false; + _mouseDownEvent(event, BUTTON_LEFT, BUTTON_MASK_LEFT, true); + } +} + - (void)mouseDragged:(NSEvent *)event { [self mouseMoved:event]; } - (void)mouseUp:(NSEvent *)event { - - button_mask &= ~BUTTON_MASK_LEFT; - Ref<InputEventMouseButton> mb; - mb.instance(); - - get_key_modifier_state([event modifierFlags], mb); - mb->set_button_index(BUTTON_LEFT); - mb->set_pressed(false); - mb->set_position(Vector2(mouse_x, mouse_y)); - mb->set_global_position(Vector2(mouse_x, mouse_y)); - mb->set_button_mask(button_mask); - mb->set_doubleclick([event clickCount] == 2); - OS_OSX::singleton->push_input(mb); + if (mouse_down_control) { + _mouseDownEvent(event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false); + } else { + _mouseDownEvent(event, BUTTON_LEFT, BUTTON_MASK_LEFT, false); + } } - (void)mouseMoved:(NSEvent *)event { @@ -347,20 +355,7 @@ static int button_mask = 0; } - (void)rightMouseDown:(NSEvent *)event { - - button_mask |= BUTTON_MASK_RIGHT; - - Ref<InputEventMouseButton> mb; - mb.instance(); - - get_key_modifier_state([event modifierFlags], mb); - mb->set_button_index(BUTTON_RIGHT); - mb->set_pressed(true); - mb->set_position(Vector2(mouse_x, mouse_y)); - mb->set_global_position(Vector2(mouse_x, mouse_y)); - mb->set_button_mask(button_mask); - mb->set_doubleclick([event clickCount] == 2); - OS_OSX::singleton->push_input(mb); + _mouseDownEvent(event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true); } - (void)rightMouseDragged:(NSEvent *)event { @@ -368,20 +363,7 @@ static int button_mask = 0; } - (void)rightMouseUp:(NSEvent *)event { - - button_mask &= ~BUTTON_MASK_RIGHT; - - Ref<InputEventMouseButton> mb; - mb.instance(); - - get_key_modifier_state([event modifierFlags], mb); - mb->set_button_index(BUTTON_RIGHT); - mb->set_pressed(false); - mb->set_position(Vector2(mouse_x, mouse_y)); - mb->set_global_position(Vector2(mouse_x, mouse_y)); - mb->set_button_mask(button_mask); - mb->set_doubleclick([event clickCount] == 2); - OS_OSX::singleton->push_input(mb); + _mouseDownEvent(event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false); } - (void)otherMouseDown:(NSEvent *)event { @@ -389,19 +371,7 @@ static int button_mask = 0; if ((int)[event buttonNumber] != 2) return; - button_mask |= BUTTON_MASK_MIDDLE; - - Ref<InputEventMouseButton> mb; - mb.instance(); - - get_key_modifier_state([event modifierFlags], mb); - mb->set_button_index(BUTTON_MIDDLE); - mb->set_pressed(true); - mb->set_position(Vector2(mouse_x, mouse_y)); - mb->set_global_position(Vector2(mouse_x, mouse_y)); - mb->set_button_mask(button_mask); - mb->set_doubleclick([event clickCount] == 2); - OS_OSX::singleton->push_input(mb); + _mouseDownEvent(event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, true); } - (void)otherMouseDragged:(NSEvent *)event { @@ -413,19 +383,7 @@ static int button_mask = 0; if ((int)[event buttonNumber] != 2) return; - button_mask &= ~BUTTON_MASK_MIDDLE; - - Ref<InputEventMouseButton> mb; - mb.instance(); - - get_key_modifier_state([event modifierFlags], mb); - mb->set_button_index(BUTTON_MIDDLE); - mb->set_pressed(false); - mb->set_position(Vector2(mouse_x, mouse_y)); - mb->set_global_position(Vector2(mouse_x, mouse_y)); - mb->set_button_mask(button_mask); - mb->set_doubleclick([event clickCount] == 2); - OS_OSX::singleton->push_input(mb); + _mouseDownEvent(event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, false); } - (void)mouseExited:(NSEvent *)event { @@ -1726,3 +1684,7 @@ OS_OSX::OS_OSX() { zoomed = false; display_scale = 1.0; } + +bool OS_OSX::_check_internal_feature_support(const String &p_feature) { + return p_feature == "pc" || p_feature == "s3tc"; +} diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index 92a7b2c112..a1aa58a5e7 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -32,12 +32,12 @@ #include "bind/core_bind.h" #include "editor/editor_export.h" #include "editor/editor_node.h" -#include "global_config.h" #include "io/marshalls.h" #include "io/zip_io.h" #include "object.h" #include "os/file_access.h" #include "platform/uwp/logo.gen.h" +#include "project_settings.h" #include "version.h" #include "thirdparty/minizip/unzip.h" @@ -774,7 +774,8 @@ class EditorExportUWP : public EditorExportPlatform { String architecture = arch == ARM ? "ARM" : arch == X86 ? "x86" : "x64"; result = result.replace("$architecture$", architecture); - result = result.replace("$display_name$", String(p_preset->get("package/display_name")).empty() ? (String)GlobalConfig::get_singleton()->get("application/name") : String(p_preset->get("package/display_name"))); + result = result.replace("$display_name$", String(p_preset->get("package/display_name")).empty() ? (String)ProjectSettings::get_singleton()->get("application/config/name") : String(p_preset->get("package/display_name"))); + result = result.replace("$publisher_display_name$", p_preset->get("package/publisher_display_name")); result = result.replace("$app_description$", p_preset->get("package/description")); result = result.replace("$bg_color$", p_preset->get("images/background_color")); @@ -1008,6 +1009,9 @@ public: virtual String get_name() const { return "Windows Universal"; } + virtual String get_os_name() const { + return "UWP"; + } virtual String get_binary_extension() const { return "appx"; @@ -1369,6 +1373,12 @@ public: return OK; } + virtual void get_platform_features(List<String> *r_features) { + + r_features->push_back("pc"); + r_features->push_back("UWP"); + } + EditorExportUWP() { Ref<Image> img = memnew(Image(_uwp_logo)); logo.instance(); diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index b9ef778e01..fabb227bf5 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -35,12 +35,12 @@ #include "drivers/windows/mutex_windows.h" #include "drivers/windows/rw_lock_windows.h" #include "drivers/windows/semaphore_windows.h" -#include "global_config.h" #include "io/marshalls.h" #include "main/main.h" #include "platform/windows/packet_peer_udp_winsock.h" #include "platform/windows/stream_peer_winsock.h" #include "platform/windows/tcp_server_winsock.h" +#include "project_settings.h" #include "servers/audio_server.h" #include "servers/visual/visual_server_raster.h" #include "thread_uwp.h" @@ -851,9 +851,8 @@ String OSUWP::get_data_dir() const { return String(data_folder->Path->Data()).replace("\\", "/"); } -bool OSUWP::check_feature_support(const String &p_feature) { - - return VisualServer::get_singleton()->has_os_feature(p_feature); +bool OSUWP::_check_internal_feature_support(const String &p_feature) { + return p_feature == "pc" || p_feature == "s3tc"; } PowerState OSUWP::get_power_state() { diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 45b8eefdee..dfa21a0934 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -236,7 +236,7 @@ public: virtual void move_window_to_foreground(); virtual String get_data_dir() const; - virtual bool check_feature_support(const String &p_feature); + virtual bool _check_internal_feature_support(const String &p_feature); void set_gl_context(ContextEGL *p_context); void screen_size_changed(); diff --git a/platform/windows/detect.py b/platform/windows/detect.py index a2bc5a11ab..4d93b3f244 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -48,7 +48,7 @@ def can_build(): if (os.getenv("MINGW64_PREFIX")): mingw64 = os.getenv("MINGW64_PREFIX") - test = "gcc --version &>/dev/null" + test = "gcc --version > /dev/null 2>&1" if (os.system(mingw + test) == 0 or os.system(mingw64 + test) == 0 or os.system(mingw32 + test) == 0): return True @@ -65,7 +65,7 @@ def get_opts(): mingw32 = "i686-w64-mingw32-" mingw64 = "x86_64-w64-mingw32-" - if os.system(mingw32 + "gcc --version &>/dev/null") != 0: + if os.system(mingw32 + "gcc --version > /dev/null 2>&1") != 0: mingw32 = mingw if (os.getenv("MINGW32_PREFIX")): @@ -252,13 +252,6 @@ def configure(env): env.Append(LINKFLAGS=['-static']) mingw_prefix = env["mingw_prefix_64"] - nulstr = "" - - if (os.name == "posix"): - nulstr = ">/dev/null" - else: - nulstr = ">nul" - env["CC"] = mingw_prefix + "gcc" env['AS'] = mingw_prefix + "as" env['CXX'] = mingw_prefix + "g++" diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index c9271f6266..6cb33e2ff0 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -46,6 +46,7 @@ void register_windows_exporter() { platform->set_debug_32("windows_32_debug.exe"); platform->set_release_64("windows_64_release.exe"); platform->set_debug_64("windows_64_debug.exe"); + platform->set_os_name("Windows"); EditorExport::get_singleton()->add_export_platform(platform); } diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 36d6cd8565..3413050f4a 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -37,12 +37,12 @@ #include "drivers/windows/rw_lock_windows.h" #include "drivers/windows/semaphore_windows.h" #include "drivers/windows/thread_windows.h" -#include "global_config.h" #include "io/marshalls.h" #include "joypad.h" #include "lang_table.h" #include "main/main.h" #include "packet_peer_udp_winsock.h" +#include "project_settings.h" #include "servers/audio_server.h" #include "servers/visual/visual_server_raster.h" #include "servers/visual/visual_server_wrap_mt.h" @@ -2229,7 +2229,7 @@ String OS_Windows::get_data_dir() const { if (has_environment("APPDATA")) { - bool use_godot = GlobalConfig::get_singleton()->get("application/config/use_shared_user_dir"); + bool use_godot = ProjectSettings::get_singleton()->get("application/config/use_shared_user_dir"); if (!use_godot) return (OS::get_singleton()->get_environment("APPDATA") + "/" + an).replace("\\", "/"); else @@ -2237,7 +2237,7 @@ String OS_Windows::get_data_dir() const { } } - return GlobalConfig::get_singleton()->get_resource_path(); + return ProjectSettings::get_singleton()->get_resource_path(); } bool OS_Windows::is_joy_known(int p_device) { @@ -2274,9 +2274,9 @@ int OS_Windows::get_power_percent_left() { return power_manager->get_power_percent_left(); } -bool OS_Windows::check_feature_support(const String &p_feature) { +bool OS_Windows::_check_internal_feature_support(const String &p_feature) { - return VisualServer::get_singleton()->has_os_feature(p_feature); + return p_feature == "pc" || p_feature == "s3tc"; } OS_Windows::OS_Windows(HINSTANCE _hInstance) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 835141145f..e6589ddfad 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -288,7 +288,7 @@ public: virtual int get_power_seconds_left(); virtual int get_power_percent_left(); - virtual bool check_feature_support(const String &p_feature); + virtual bool _check_internal_feature_support(const String &p_feature); OS_Windows(HINSTANCE _hInstance); ~OS_Windows(); diff --git a/platform/x11/export/export.cpp b/platform/x11/export/export.cpp index 69784a473d..c8d6220aed 100644 --- a/platform/x11/export/export.cpp +++ b/platform/x11/export/export.cpp @@ -48,6 +48,7 @@ void register_x11_exporter() { platform->set_debug_32("linux_x11_32_debug"); platform->set_release_64("linux_x11_64_release"); platform->set_debug_64("linux_x11_64_debug"); + platform->set_os_name("X11"); EditorExport::get_singleton()->add_export_platform(platform); diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 04f41b2e89..5bfe31b8c2 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -1858,7 +1858,7 @@ void OS_X11::set_clipboard(const String &p_text) { XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), x11_window, CurrentTime); }; -static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard) { +static String _get_clipboard_impl(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard, Atom target) { String ret; @@ -1875,7 +1875,7 @@ static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_di }; if (Sown != None) { - XConvertSelection(x11_display, p_source, XA_STRING, selection, + XConvertSelection(x11_display, p_source, target, selection, x11_window, CurrentTime); XFlush(x11_display); while (true) { @@ -1915,6 +1915,18 @@ static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_di return ret; } +static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard) { + String ret; + Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True); + if (utf8_atom != None) { + ret = _get_clipboard_impl(p_source, x11_window, x11_display, p_internal_clipboard, utf8_atom); + } + if (ret == "") { + ret = _get_clipboard_impl(p_source, x11_window, x11_display, p_internal_clipboard, XA_STRING); + } + return ret; +} + String OS_X11::get_clipboard() const { String ret; @@ -1947,6 +1959,11 @@ Error OS_X11::shell_open(String p_uri) { return ok; } +bool OS_X11::_check_internal_feature_support(const String &p_feature) { + + return p_feature == "pc" || p_feature == "s3tc"; +} + String OS_X11::get_system_dir(SystemDir p_dir) const { String xdgparam; diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 12e4bbb086..db70f8f84a 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -269,6 +269,8 @@ public: virtual int get_power_seconds_left(); virtual int get_power_percent_left(); + virtual bool _check_internal_feature_support(const String &p_feature); + void run(); OS_X11(); diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index a1ab51b3c8..22649cedd7 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -223,10 +223,10 @@ void SpriteFrames::_bind_methods() { ClassDB::bind_method(D_METHOD("set_animation_loop", "anim", "loop"), &SpriteFrames::set_animation_loop); ClassDB::bind_method(D_METHOD("get_animation_loop", "anim"), &SpriteFrames::get_animation_loop); - ClassDB::bind_method(D_METHOD("add_frame", "anim", "frame", "atpos"), &SpriteFrames::add_frame, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_frame", "anim", "frame:Texture", "atpos"), &SpriteFrames::add_frame, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_frame_count", "anim"), &SpriteFrames::get_frame_count); - ClassDB::bind_method(D_METHOD("get_frame", "anim", "idx"), &SpriteFrames::get_frame); - ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "txt"), &SpriteFrames::set_frame); + ClassDB::bind_method(D_METHOD("get_frame:Texture", "anim", "idx"), &SpriteFrames::get_frame); + ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "txt:Texture"), &SpriteFrames::set_frame); ClassDB::bind_method(D_METHOD("remove_frame", "anim", "idx"), &SpriteFrames::remove_frame); ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear); ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all); diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 68a3166aa7..40c25c8bf6 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -949,7 +949,7 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("get_canvas_item"), &CanvasItem::get_canvas_item); - ClassDB::bind_method(D_METHOD("set_visible"), &CanvasItem::set_visible); + ClassDB::bind_method(D_METHOD("set_visible", "visible"), &CanvasItem::set_visible); ClassDB::bind_method(D_METHOD("is_visible"), &CanvasItem::is_visible); ClassDB::bind_method(D_METHOD("is_visible_in_tree"), &CanvasItem::is_visible_in_tree); ClassDB::bind_method(D_METHOD("show"), &CanvasItem::show); @@ -1001,7 +1001,7 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("get_local_mouse_pos"), &CanvasItem::get_local_mouse_pos); ClassDB::bind_method(D_METHOD("get_global_mouse_position"), &CanvasItem::get_global_mouse_position); ClassDB::bind_method(D_METHOD("get_canvas"), &CanvasItem::get_canvas); - ClassDB::bind_method(D_METHOD("get_world_2d"), &CanvasItem::get_world_2d); + ClassDB::bind_method(D_METHOD("get_world_2d:World2D"), &CanvasItem::get_world_2d); //ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasItem::get_viewport); ClassDB::bind_method(D_METHOD("set_material", "material:Material"), &CanvasItem::set_material); @@ -1018,7 +1018,7 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("make_canvas_pos_local", "screen_point"), &CanvasItem::make_canvas_pos_local); - ClassDB::bind_method(D_METHOD("make_input_local", "event"), &CanvasItem::make_input_local); + ClassDB::bind_method(D_METHOD("make_input_local:InputEvent", "event:InputEvent"), &CanvasItem::make_input_local); BIND_VMETHOD(MethodInfo("_draw")); diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index 0821b00dd9..eb47682884 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -152,6 +152,16 @@ void CollisionObject2D::get_shape_owners(List<uint32_t> *r_owners) { } } +Array CollisionObject2D::_get_shape_owners() { + + Array ret; + for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { + ret.push_back(E->key()); + } + + return ret; +} + void CollisionObject2D::shape_owner_set_transform(uint32_t p_owner, const Transform2D &p_transform) { ERR_FAIL_COND(!shapes.has(p_owner)); @@ -323,6 +333,23 @@ void CollisionObject2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable); ClassDB::bind_method(D_METHOD("is_pickable"), &CollisionObject2D::is_pickable); + ClassDB::bind_method(D_METHOD("create_shape_owner", "owner:Object"), &CollisionObject2D::create_shape_owner); + ClassDB::bind_method(D_METHOD("remove_shape_owner", "owner_id"), &CollisionObject2D::remove_shape_owner); + ClassDB::bind_method(D_METHOD("get_shape_owners"), &CollisionObject2D::_get_shape_owners); + ClassDB::bind_method(D_METHOD("shape_owner_set_transform", "owner_id", "transform:Transform2D"), &CollisionObject2D::shape_owner_set_transform); + ClassDB::bind_method(D_METHOD("shape_owner_get_transform", "owner_id"), &CollisionObject2D::shape_owner_get_transform); + ClassDB::bind_method(D_METHOD("shape_owner_get_owner", "owner_id"), &CollisionObject2D::shape_owner_get_owner); + ClassDB::bind_method(D_METHOD("shape_owner_set_disabled", "owner_id", "disabled"), &CollisionObject2D::shape_owner_set_disabled); + ClassDB::bind_method(D_METHOD("is_shape_owner_disabled", "owner_id"), &CollisionObject2D::is_shape_owner_disabled); + ClassDB::bind_method(D_METHOD("shape_owner_set_one_way_collision", "owner_id", "enable"), &CollisionObject2D::shape_owner_set_one_way_collision); + ClassDB::bind_method(D_METHOD("is_shape_owner_one_way_collision_enabled", "owner_id"), &CollisionObject2D::is_shape_owner_one_way_collision_enabled); + ClassDB::bind_method(D_METHOD("shape_owner_add_shape", "owner_id", "shape:Shape2D"), &CollisionObject2D::shape_owner_add_shape); + ClassDB::bind_method(D_METHOD("shape_owner_get_shape_count", "owner_id"), &CollisionObject2D::shape_owner_get_shape_count); + ClassDB::bind_method(D_METHOD("shape_owner_get_shape", "owner_id", "shape_id"), &CollisionObject2D::shape_owner_get_shape); + ClassDB::bind_method(D_METHOD("shape_owner_get_shape_index", "owner_id", "shape_id"), &CollisionObject2D::shape_owner_get_shape_index); + ClassDB::bind_method(D_METHOD("shape_owner_remove_shape", "owner_id", "shape_id"), &CollisionObject2D::shape_owner_remove_shape); + ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject2D::shape_owner_clear_shapes); + ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject2D::shape_find_owner); BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "viewport"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::INT, "shape_idx"))); diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index 3580d3d942..36bf39ff4e 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -81,6 +81,7 @@ public: uint32_t create_shape_owner(Object *p_owner); void remove_shape_owner(uint32_t owner); void get_shape_owners(List<uint32_t> *r_owners); + Array _get_shape_owners(); void shape_owner_set_transform(uint32_t p_owner, const Transform2D &p_transform); Transform2D shape_owner_get_transform(uint32_t p_owner) const; diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index ff4aa245ec..890ac0c1f3 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -201,8 +201,8 @@ bool CollisionShape2D::is_one_way_collision_enabled() const { void CollisionShape2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_shape", "shape"), &CollisionShape2D::set_shape); - ClassDB::bind_method(D_METHOD("get_shape"), &CollisionShape2D::get_shape); + ClassDB::bind_method(D_METHOD("set_shape", "shape:Shape2D"), &CollisionShape2D::set_shape); + ClassDB::bind_method(D_METHOD("get_shape:Shape2D"), &CollisionShape2D::get_shape); ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionShape2D::set_disabled); ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionShape2D::is_disabled); ClassDB::bind_method(D_METHOD("set_one_way_collision", "enabled"), &CollisionShape2D::set_one_way_collision); diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index e8c2122bd1..044cb06c02 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -355,8 +355,8 @@ void Light2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_editor_only", "editor_only"), &Light2D::set_editor_only); ClassDB::bind_method(D_METHOD("is_editor_only"), &Light2D::is_editor_only); - ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Light2D::set_texture); - ClassDB::bind_method(D_METHOD("get_texture"), &Light2D::get_texture); + ClassDB::bind_method(D_METHOD("set_texture", "texture:Texture"), &Light2D::set_texture); + ClassDB::bind_method(D_METHOD("get_texture:Texture"), &Light2D::get_texture); ClassDB::bind_method(D_METHOD("set_texture_offset", "texture_offset"), &Light2D::set_texture_offset); ClassDB::bind_method(D_METHOD("get_texture_offset"), &Light2D::get_texture_offset); diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 5438557d0b..22e54cfb54 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -283,11 +283,11 @@ void Line2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_default_color", "color"), &Line2D::set_default_color); ClassDB::bind_method(D_METHOD("get_default_color"), &Line2D::get_default_color); - ClassDB::bind_method(D_METHOD("set_gradient", "color"), &Line2D::set_gradient); - ClassDB::bind_method(D_METHOD("get_gradient"), &Line2D::get_gradient); + ClassDB::bind_method(D_METHOD("set_gradient", "color:Gradient"), &Line2D::set_gradient); + ClassDB::bind_method(D_METHOD("get_gradient:Gradient"), &Line2D::get_gradient); - ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Line2D::set_texture); - ClassDB::bind_method(D_METHOD("get_texture"), &Line2D::get_texture); + ClassDB::bind_method(D_METHOD("set_texture", "texture:Texture"), &Line2D::set_texture); + ClassDB::bind_method(D_METHOD("get_texture:Texture"), &Line2D::get_texture); ClassDB::bind_method(D_METHOD("set_texture_mode", "mode"), &Line2D::set_texture_mode); ClassDB::bind_method(D_METHOD("get_texture_mode"), &Line2D::get_texture_mode); diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index bd6ab99801..0acc85681d 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -398,6 +398,16 @@ float Node2D::get_angle_to(const Vector2 &p_pos) const { return (get_global_transform().affine_inverse().xform(p_pos)).angle(); } +Point2 Node2D::to_local(Point2 p_global) const { + + return get_global_transform().affine_inverse().xform(p_global); +} + +Point2 Node2D::to_global(Point2 p_local) const { + + return get_global_transform().xform(p_local); +} + void Node2D::_bind_methods() { // TODO: Obsolete those two methods (old name) properly (GH-4397) @@ -436,6 +446,9 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("look_at", "point"), &Node2D::look_at); ClassDB::bind_method(D_METHOD("get_angle_to", "point"), &Node2D::get_angle_to); + ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Node2D::to_local); + ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Node2D::to_global); + ClassDB::bind_method(D_METHOD("set_z", "z"), &Node2D::set_z); ClassDB::bind_method(D_METHOD("get_z"), &Node2D::get_z); @@ -444,7 +457,7 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("edit_set_pivot", "pivot"), &Node2D::edit_set_pivot); - ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent); + ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent:Node"), &Node2D::get_relative_transform_to_parent); ADD_GROUP("Transform", ""); ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position"); diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index 65331a4d58..5b3a28d5c3 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -104,6 +104,9 @@ public: void look_at(const Vector2 &p_pos); float get_angle_to(const Vector2 &p_pos) const; + Point2 to_local(Point2 p_global) const; + Point2 to_global(Point2 p_local) const; + void set_z_as_relative(bool p_enabled); bool is_z_relative() const; diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index 5c1c953a37..4a68df5706 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -330,8 +330,8 @@ void Polygon2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_vertex_colors", "vertex_colors"), &Polygon2D::set_vertex_colors); ClassDB::bind_method(D_METHOD("get_vertex_colors"), &Polygon2D::get_vertex_colors); - ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Polygon2D::set_texture); - ClassDB::bind_method(D_METHOD("get_texture"), &Polygon2D::get_texture); + ClassDB::bind_method(D_METHOD("set_texture", "texture:Texture"), &Polygon2D::set_texture); + ClassDB::bind_method(D_METHOD("get_texture:Texture"), &Polygon2D::get_texture); ClassDB::bind_method(D_METHOD("set_texture_offset", "texture_offset"), &Polygon2D::set_texture_offset); ClassDB::bind_method(D_METHOD("get_texture_offset"), &Polygon2D::get_texture_offset); diff --git a/scene/2d/screen_button.cpp b/scene/2d/screen_button.cpp index 37139b2b93..24c9137807 100644 --- a/scene/2d/screen_button.cpp +++ b/scene/2d/screen_button.cpp @@ -356,17 +356,17 @@ bool TouchScreenButton::is_passby_press_enabled() const { void TouchScreenButton::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_texture", "texture"), &TouchScreenButton::set_texture); - ClassDB::bind_method(D_METHOD("get_texture"), &TouchScreenButton::get_texture); + ClassDB::bind_method(D_METHOD("set_texture", "texture:Texture"), &TouchScreenButton::set_texture); + ClassDB::bind_method(D_METHOD("get_texture:Texture"), &TouchScreenButton::get_texture); - ClassDB::bind_method(D_METHOD("set_texture_pressed", "texture_pressed"), &TouchScreenButton::set_texture_pressed); - ClassDB::bind_method(D_METHOD("get_texture_pressed"), &TouchScreenButton::get_texture_pressed); + ClassDB::bind_method(D_METHOD("set_texture_pressed", "texture_pressed:Texture"), &TouchScreenButton::set_texture_pressed); + ClassDB::bind_method(D_METHOD("get_texture_pressed:Texture"), &TouchScreenButton::get_texture_pressed); - ClassDB::bind_method(D_METHOD("set_bitmask", "bitmask"), &TouchScreenButton::set_bitmask); - ClassDB::bind_method(D_METHOD("get_bitmask"), &TouchScreenButton::get_bitmask); + ClassDB::bind_method(D_METHOD("set_bitmask", "bitmask:BitMap"), &TouchScreenButton::set_bitmask); + ClassDB::bind_method(D_METHOD("get_bitmask:BitMap"), &TouchScreenButton::get_bitmask); - ClassDB::bind_method(D_METHOD("set_shape", "shape"), &TouchScreenButton::set_shape); - ClassDB::bind_method(D_METHOD("get_shape"), &TouchScreenButton::get_shape); + ClassDB::bind_method(D_METHOD("set_shape", "shape:Shape2D"), &TouchScreenButton::set_shape); + ClassDB::bind_method(D_METHOD("get_shape:Shape2D"), &TouchScreenButton::get_shape); ClassDB::bind_method(D_METHOD("set_shape_centered", "bool"), &TouchScreenButton::set_shape_centered); ClassDB::bind_method(D_METHOD("is_shape_centered"), &TouchScreenButton::is_shape_centered); diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index 450f8e2474..b469013819 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -105,20 +105,7 @@ void Sprite::set_texture(const Ref<Texture> &p_texture) { if (p_texture == texture) return; -#ifdef DEBUG_ENABLED - if (texture.is_valid()) { - texture->disconnect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->update); - } -#endif texture = p_texture; - /* this should no longer be needed in 3.0 -#ifdef DEBUG_ENABLED - if (texture.is_valid()) { - texture->set_flags(texture->get_flags()); //remove repeat from texture, it looks bad in sprites - texture->connect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->update); - } -#endif -*/ update(); emit_signal("texture_changed"); item_rect_changed(); diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp index 874e5f01ea..5a3d8e013f 100644 --- a/scene/3d/collision_object.cpp +++ b/scene/3d/collision_object.cpp @@ -128,6 +128,22 @@ void CollisionObject::_bind_methods() { ClassDB::bind_method(D_METHOD("set_capture_input_on_drag", "enable"), &CollisionObject::set_capture_input_on_drag); ClassDB::bind_method(D_METHOD("get_capture_input_on_drag"), &CollisionObject::get_capture_input_on_drag); ClassDB::bind_method(D_METHOD("get_rid"), &CollisionObject::get_rid); + ClassDB::bind_method(D_METHOD("create_shape_owner", "owner:Object"), &CollisionObject::create_shape_owner); + ClassDB::bind_method(D_METHOD("remove_shape_owner", "owner_id"), &CollisionObject::remove_shape_owner); + ClassDB::bind_method(D_METHOD("get_shape_owners"), &CollisionObject::_get_shape_owners); + ClassDB::bind_method(D_METHOD("shape_owner_set_transform", "owner_id", "transform:Transform"), &CollisionObject::shape_owner_set_transform); + ClassDB::bind_method(D_METHOD("shape_owner_get_transform", "owner_id"), &CollisionObject::shape_owner_get_transform); + ClassDB::bind_method(D_METHOD("shape_owner_get_owner", "owner_id"), &CollisionObject::shape_owner_get_owner); + ClassDB::bind_method(D_METHOD("shape_owner_set_disabled", "owner_id", "disabled"), &CollisionObject::shape_owner_set_disabled); + ClassDB::bind_method(D_METHOD("is_shape_owner_disabled", "owner_id"), &CollisionObject::is_shape_owner_disabled); + ClassDB::bind_method(D_METHOD("shape_owner_add_shape", "owner_id", "shape:Shape"), &CollisionObject::shape_owner_add_shape); + ClassDB::bind_method(D_METHOD("shape_owner_get_shape_count", "owner_id"), &CollisionObject::shape_owner_get_shape_count); + ClassDB::bind_method(D_METHOD("shape_owner_get_shape", "owner_id", "shape_id"), &CollisionObject::shape_owner_get_shape); + ClassDB::bind_method(D_METHOD("shape_owner_get_shape_index", "owner_id", "shape_id"), &CollisionObject::shape_owner_get_shape_index); + ClassDB::bind_method(D_METHOD("shape_owner_remove_shape", "owner_id", "shape_id"), &CollisionObject::shape_owner_remove_shape); + ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject::shape_owner_clear_shapes); + ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject::shape_find_owner); + BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_pos"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx"))); ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_pos"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx"))); @@ -193,6 +209,16 @@ void CollisionObject::get_shape_owners(List<uint32_t> *r_owners) { } } +Array CollisionObject::_get_shape_owners() { + + Array ret; + for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { + ret.push_back(E->key()); + } + + return ret; +} + void CollisionObject::shape_owner_set_transform(uint32_t p_owner, const Transform &p_transform) { ERR_FAIL_COND(!shapes.has(p_owner)); diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h index fac05b6e8c..6c13e5d505 100644 --- a/scene/3d/collision_object.h +++ b/scene/3d/collision_object.h @@ -81,6 +81,7 @@ public: uint32_t create_shape_owner(Object *p_owner); void remove_shape_owner(uint32_t owner); void get_shape_owners(List<uint32_t> *r_owners); + Array _get_shape_owners(); void shape_owner_set_transform(uint32_t p_owner, const Transform &p_transform); Transform shape_owner_get_transform(uint32_t p_owner) const; diff --git a/scene/3d/collision_shape.cpp b/scene/3d/collision_shape.cpp index 4fd215bd1a..a7cfc6fef2 100644 --- a/scene/3d/collision_shape.cpp +++ b/scene/3d/collision_shape.cpp @@ -127,9 +127,9 @@ String CollisionShape::get_configuration_warning() const { void CollisionShape::_bind_methods() { //not sure if this should do anything - ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &CollisionShape::resource_changed); - ClassDB::bind_method(D_METHOD("set_shape", "shape"), &CollisionShape::set_shape); - ClassDB::bind_method(D_METHOD("get_shape"), &CollisionShape::get_shape); + ClassDB::bind_method(D_METHOD("resource_changed", "resource:Resource"), &CollisionShape::resource_changed); + ClassDB::bind_method(D_METHOD("set_shape", "shape:Shape"), &CollisionShape::set_shape); + ClassDB::bind_method(D_METHOD("get_shape:Shape"), &CollisionShape::get_shape); ClassDB::bind_method(D_METHOD("set_disabled", "enable"), &CollisionShape::set_disabled); ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionShape::is_disabled); ClassDB::bind_method(D_METHOD("make_convex_from_brothers"), &CollisionShape::make_convex_from_brothers); diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 581dfb32c8..0c31282a6c 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -1443,8 +1443,8 @@ PoolVector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const { void GIProbe::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_probe_data", "data"), &GIProbe::set_probe_data); - ClassDB::bind_method(D_METHOD("get_probe_data"), &GIProbe::get_probe_data); + ClassDB::bind_method(D_METHOD("set_probe_data", "data:GIProbeData"), &GIProbe::set_probe_data); + ClassDB::bind_method(D_METHOD("get_probe_data:GIProbeData"), &GIProbe::get_probe_data); ClassDB::bind_method(D_METHOD("set_subdiv", "subdiv"), &GIProbe::set_subdiv); ClassDB::bind_method(D_METHOD("get_subdiv"), &GIProbe::get_subdiv); @@ -1473,7 +1473,7 @@ void GIProbe::_bind_methods() { ClassDB::bind_method(D_METHOD("set_compress", "enable"), &GIProbe::set_compress); ClassDB::bind_method(D_METHOD("is_compressed"), &GIProbe::is_compressed); - ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &GIProbe::bake, DEFVAL(Variant()), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("bake", "from_node:Node", "create_visual_debug"), &GIProbe::bake, DEFVAL(Variant()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("debug_bake"), &GIProbe::_debug_bake); ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 9c87acec6e..977f1f81a7 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "light.h" -#include "global_config.h" +#include "project_settings.h" #include "scene/resources/surface_tool.h" bool Light::_can_gizmo_scale() const { diff --git a/scene/3d/multimesh_instance.cpp b/scene/3d/multimesh_instance.cpp index b51953f27c..b4558698cc 100644 --- a/scene/3d/multimesh_instance.cpp +++ b/scene/3d/multimesh_instance.cpp @@ -31,8 +31,8 @@ void MultiMeshInstance::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_multimesh", "multimesh"), &MultiMeshInstance::set_multimesh); - ClassDB::bind_method(D_METHOD("get_multimesh"), &MultiMeshInstance::get_multimesh); + ClassDB::bind_method(D_METHOD("set_multimesh", "multimesh:MultiMesh"), &MultiMeshInstance::set_multimesh); + ClassDB::bind_method(D_METHOD("get_multimesh:MultiMesh"), &MultiMeshInstance::get_multimesh); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multimesh", PROPERTY_HINT_RESOURCE_TYPE, "MultiMesh"), "set_multimesh", "get_multimesh"); } diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index 4c93bcfb5e..7392998d57 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -374,8 +374,8 @@ String NavigationMeshInstance::get_configuration_warning() const { void NavigationMeshInstance::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_navigation_mesh", "navmesh"), &NavigationMeshInstance::set_navigation_mesh); - ClassDB::bind_method(D_METHOD("get_navigation_mesh"), &NavigationMeshInstance::get_navigation_mesh); + ClassDB::bind_method(D_METHOD("set_navigation_mesh", "navmesh:NavigationMesh"), &NavigationMeshInstance::set_navigation_mesh); + ClassDB::bind_method(D_METHOD("get_navigation_mesh:NavigationMesh"), &NavigationMeshInstance::get_navigation_mesh); ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationMeshInstance::set_enabled); ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationMeshInstance::is_enabled); diff --git a/scene/3d/portal.cpp b/scene/3d/portal.cpp index 64a9dc14ab..d77dde1dd8 100644 --- a/scene/3d/portal.cpp +++ b/scene/3d/portal.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "portal.h" -#include "global_config.h" +#include "project_settings.h" #include "scene/resources/surface_tool.h" #include "servers/visual_server.h" diff --git a/scene/3d/room_instance.cpp b/scene/3d/room_instance.cpp index 85713cf43a..7827768c09 100644 --- a/scene/3d/room_instance.cpp +++ b/scene/3d/room_instance.cpp @@ -32,7 +32,7 @@ #include "servers/visual_server.h" #include "geometry.h" -#include "global_config.h" +#include "project_settings.h" #include "scene/resources/surface_tool.h" void Room::_notification(int p_what) { diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index d498947a41..71af77c027 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -31,7 +31,7 @@ #include "message_queue.h" -#include "core/global_config.h" +#include "core/project_settings.h" #include "scene/resources/surface_tool.h" bool Skeleton::_set(const StringName &p_path, const Variant &p_value) { diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index 20c2cc1eb5..6106b0904a 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -674,6 +674,16 @@ void Spatial::look_at_from_pos(const Vector3 &p_pos, const Vector3 &p_target, co set_global_transform(lookat); } +Vector3 Spatial::to_local(Vector3 p_global) const { + + return get_global_transform().affine_inverse().xform(p_global); +} + +Vector3 Spatial::to_global(Vector3 p_local) const { + + return get_global_transform().xform(p_local); +} + void Spatial::set_notify_transform(bool p_enable) { data.notify_transform = p_enable; } @@ -704,7 +714,7 @@ void Spatial::_bind_methods() { ClassDB::bind_method(D_METHOD("get_scale"), &Spatial::get_scale); ClassDB::bind_method(D_METHOD("set_global_transform", "global"), &Spatial::set_global_transform); ClassDB::bind_method(D_METHOD("get_global_transform"), &Spatial::get_global_transform); - ClassDB::bind_method(D_METHOD("get_parent_spatial"), &Spatial::get_parent_spatial); + ClassDB::bind_method(D_METHOD("get_parent_spatial:Spatial"), &Spatial::get_parent_spatial); ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Spatial::set_ignore_transform_notification); ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &Spatial::set_as_toplevel); ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &Spatial::is_set_as_toplevel); @@ -722,7 +732,7 @@ void Spatial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_gizmo", "gizmo:SpatialGizmo"), &Spatial::set_gizmo); ClassDB::bind_method(D_METHOD("get_gizmo:SpatialGizmo"), &Spatial::get_gizmo); - ClassDB::bind_method(D_METHOD("set_visible"), &Spatial::set_visible); + ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Spatial::set_visible); ClassDB::bind_method(D_METHOD("is_visible"), &Spatial::is_visible); ClassDB::bind_method(D_METHOD("is_visible_in_tree"), &Spatial::is_visible_in_tree); ClassDB::bind_method(D_METHOD("show"), &Spatial::show); @@ -756,6 +766,9 @@ void Spatial::_bind_methods() { ClassDB::bind_method(D_METHOD("look_at", "target", "up"), &Spatial::look_at); ClassDB::bind_method(D_METHOD("look_at_from_pos", "pos", "target", "up"), &Spatial::look_at_from_pos); + ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Spatial::to_local); + ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Spatial::to_global); + BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED); BIND_CONSTANT(NOTIFICATION_ENTER_WORLD); BIND_CONSTANT(NOTIFICATION_EXIT_WORLD); diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index d114a6231b..f22b19d3cc 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -173,6 +173,9 @@ public: void look_at(const Vector3 &p_target, const Vector3 &p_up_normal); void look_at_from_pos(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up_normal); + Vector3 to_local(Vector3 p_global) const; + Vector3 to_global(Vector3 p_local) const; + void set_notify_transform(bool p_enable); bool is_transform_notification_enabled() const; diff --git a/scene/audio/audio_player.cpp b/scene/audio/audio_player.cpp index bcca834642..fdf61c40d8 100644 --- a/scene/audio/audio_player.cpp +++ b/scene/audio/audio_player.cpp @@ -263,7 +263,7 @@ void AudioStreamPlayer::_bus_layout_changed() { void AudioStreamPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stream", "stream:AudioStream"), &AudioStreamPlayer::set_stream); - ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer::get_stream); + ClassDB::bind_method(D_METHOD("get_stream:AudioStream"), &AudioStreamPlayer::get_stream); ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &AudioStreamPlayer::set_volume_db); ClassDB::bind_method(D_METHOD("get_volume_db"), &AudioStreamPlayer::get_volume_db); diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index c1dbc82f3c..9a5f55698e 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -493,11 +493,11 @@ void BaseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enabled_focus_mode", "mode"), &BaseButton::set_enabled_focus_mode); ClassDB::bind_method(D_METHOD("get_enabled_focus_mode"), &BaseButton::get_enabled_focus_mode); - ClassDB::bind_method(D_METHOD("set_shortcut", "shortcut"), &BaseButton::set_shortcut); - ClassDB::bind_method(D_METHOD("get_shortcut"), &BaseButton::get_shortcut); + ClassDB::bind_method(D_METHOD("set_shortcut", "shortcut:ShortCut"), &BaseButton::set_shortcut); + ClassDB::bind_method(D_METHOD("get_shortcut:ShortCut"), &BaseButton::get_shortcut); - ClassDB::bind_method(D_METHOD("set_button_group", "button_group"), &BaseButton::set_button_group); - ClassDB::bind_method(D_METHOD("get_button_group"), &BaseButton::get_button_group); + ClassDB::bind_method(D_METHOD("set_button_group", "button_group:ButtonGroup"), &BaseButton::set_button_group); + ClassDB::bind_method(D_METHOD("get_button_group:ButtonGroup"), &BaseButton::get_button_group); BIND_VMETHOD(MethodInfo("_pressed")); BIND_VMETHOD(MethodInfo("_toggled", PropertyInfo(Variant::BOOL, "pressed"))); diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index a456759281..03798c01a2 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -89,7 +89,8 @@ void Button::_notification(int p_what) { case DRAW_PRESSED: { style = get_stylebox("pressed"); - style->draw(ci, Rect2(Point2(0, 0), size)); + if (!flat) + style->draw(ci, Rect2(Point2(0, 0), size)); if (has_color("font_color_pressed")) color = get_color("font_color_pressed"); else @@ -101,7 +102,8 @@ void Button::_notification(int p_what) { case DRAW_HOVER: { style = get_stylebox("hover"); - style->draw(ci, Rect2(Point2(0, 0), size)); + if (!flat) + style->draw(ci, Rect2(Point2(0, 0), size)); color = get_color("font_color_hover"); if (has_color("icon_color_hover")) color_icon = get_color("icon_color_hover"); @@ -110,7 +112,8 @@ void Button::_notification(int p_what) { case DRAW_DISABLED: { style = get_stylebox("disabled"); - style->draw(ci, Rect2(Point2(0, 0), size)); + if (!flat) + style->draw(ci, Rect2(Point2(0, 0), size)); color = get_color("font_color_disabled"); if (has_color("icon_color_disabled")) color_icon = get_color("icon_color_disabled"); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index faaf761598..48cac69956 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -478,7 +478,7 @@ void ColorPicker::_bind_methods() { ClassDB::bind_method(D_METHOD("is_raw_mode"), &ColorPicker::is_raw_mode); ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPicker::set_edit_alpha); ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPicker::is_editing_alpha); - ClassDB::bind_method(D_METHOD("add_preset"), &ColorPicker::add_preset); + ClassDB::bind_method(D_METHOD("add_preset", "color"), &ColorPicker::add_preset); ClassDB::bind_method(D_METHOD("_value_changed"), &ColorPicker::_value_changed); ClassDB::bind_method(D_METHOD("_html_entered"), &ColorPicker::_html_entered); ClassDB::bind_method(D_METHOD("_text_type_toggled"), &ColorPicker::_text_type_toggled); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index a9034b738b..ee908428d9 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "control.h" -#include "global_config.h" +#include "project_settings.h" #include "scene/main/canvas_layer.h" #include "scene/main/viewport.h" #include "servers/visual_server.h" @@ -2469,7 +2469,7 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("set_focus_neighbour", "margin", "neighbour"), &Control::set_focus_neighbour); ClassDB::bind_method(D_METHOD("get_focus_neighbour", "margin"), &Control::get_focus_neighbour); - ClassDB::bind_method(D_METHOD("force_drag", "data", "preview"), &Control::force_drag); + ClassDB::bind_method(D_METHOD("force_drag", "data", "preview:Control"), &Control::force_drag); ClassDB::bind_method(D_METHOD("set_mouse_filter", "filter"), &Control::set_mouse_filter); ClassDB::bind_method(D_METHOD("get_mouse_filter"), &Control::get_mouse_filter); diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index d5e852f840..7d7c636bc2 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -584,5 +584,8 @@ Button *ConfirmationDialog::get_cancel() { ConfirmationDialog::ConfirmationDialog() { set_title(RTR("Please Confirm...")); +#ifdef TOOLS_ENABLED + set_custom_minimum_size(Size2(200, 70) * EDSCALE); +#endif cancel = add_cancel(); } diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 9d45b6e70a..1d37529a87 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -1193,7 +1193,7 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_scroll_offset"), &GraphEdit::_update_scroll_offset); ClassDB::bind_method(D_METHOD("_connections_layer_draw"), &GraphEdit::_connections_layer_draw); - ClassDB::bind_method(D_METHOD("set_selected", "node"), &GraphEdit::set_selected); + ClassDB::bind_method(D_METHOD("set_selected", "node:Node"), &GraphEdit::set_selected); ADD_SIGNAL(MethodInfo("connection_request", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING, "to"), PropertyInfo(Variant::INT, "to_slot"))); ADD_SIGNAL(MethodInfo("disconnection_request", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING, "to"), PropertyInfo(Variant::INT, "to_slot"))); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 19768d344a..97f49da2be 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "item_list.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" void ItemList::add_item(const String &p_item, const Ref<Texture> &p_texture, bool p_selectable) { @@ -534,7 +534,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { uint64_t now = OS::get_singleton()->get_ticks_msec(); uint64_t diff = now - search_time_msec; - if (diff < int(GlobalConfig::get_singleton()->get("gui/timers/incremental_search_max_interval_msec")) * 2) { + if (diff < int(ProjectSettings::get_singleton()->get("gui/timers/incremental_search_max_interval_msec")) * 2) { for (int i = current - 1; i >= 0; i--) { @@ -569,7 +569,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { uint64_t now = OS::get_singleton()->get_ticks_msec(); uint64_t diff = now - search_time_msec; - if (diff < int(GlobalConfig::get_singleton()->get("gui/timers/incremental_search_max_interval_msec")) * 2) { + if (diff < int(ProjectSettings::get_singleton()->get("gui/timers/incremental_search_max_interval_msec")) * 2) { for (int i = current + 1; i < items.size(); i++) { @@ -743,12 +743,10 @@ void ItemList::_notification(int p_what) { Size2 size = get_size(); - float page = size.height - bg->get_minimum_size().height; int width = size.width - bg->get_minimum_size().width; if (scroll_bar->is_visible()) { width -= mw + bg->get_margin(MARGIN_RIGHT); } - scroll_bar->set_page(page); draw_style_box(bg, Rect2(Point2(), size)); @@ -883,8 +881,12 @@ void ItemList::_notification(int p_what) { } if (all_fit) { + float page = size.height - bg->get_minimum_size().height; float max = MAX(page, ofs.y + max_h); + if (auto_height) + auto_height_value = ofs.y + max_h + bg->get_minimum_size().height; scroll_bar->set_max(max); + scroll_bar->set_page(page); //print_line("max: "+rtos(max)+" page "+rtos(page)); if (max <= page) { scroll_bar->set_value(0); @@ -1253,6 +1255,26 @@ Array ItemList::_get_items() const { return items; } +Size2 ItemList::get_minimum_size() const { + + if (auto_height) { + return Size2(0, auto_height_value); + } + return Size2(); +} + +void ItemList::set_auto_height(bool p_enable) { + + auto_height = p_enable; + shape_changed = true; + update(); +} + +bool ItemList::has_auto_height() const { + + return auto_height; +} + void ItemList::_bind_methods() { ClassDB::bind_method(D_METHOD("add_item", "text", "icon:Texture", "selectable"), &ItemList::add_item, DEFVAL(Variant()), DEFVAL(true)); @@ -1323,11 +1345,14 @@ void ItemList::_bind_methods() { ClassDB::bind_method(D_METHOD("set_allow_rmb_select", "allow"), &ItemList::set_allow_rmb_select); ClassDB::bind_method(D_METHOD("get_allow_rmb_select"), &ItemList::get_allow_rmb_select); + ClassDB::bind_method(D_METHOD("set_auto_height", "enable"), &ItemList::set_auto_height); + ClassDB::bind_method(D_METHOD("has_auto_height"), &ItemList::has_auto_height); + ClassDB::bind_method(D_METHOD("get_item_at_pos", "pos", "exact"), &ItemList::get_item_at_pos, DEFVAL(false)); ClassDB::bind_method(D_METHOD("ensure_current_is_visible"), &ItemList::ensure_current_is_visible); - ClassDB::bind_method(D_METHOD("get_v_scroll"), &ItemList::get_v_scroll); + ClassDB::bind_method(D_METHOD("get_v_scroll:VScrollBar"), &ItemList::get_v_scroll); ClassDB::bind_method(D_METHOD("_scroll_changed"), &ItemList::_scroll_changed); ClassDB::bind_method(D_METHOD("_gui_input"), &ItemList::_gui_input); @@ -1340,6 +1365,7 @@ void ItemList::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Multi"), "set_select_mode", "get_select_mode"); ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select"); ADD_PROPERTYNO(PropertyInfo(Variant::INT, "max_text_lines"), "set_max_text_lines", "get_max_text_lines"); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "auto_height"), "set_auto_height", "has_auto_height"); ADD_GROUP("Columns", ""); ADD_PROPERTYNO(PropertyInfo(Variant::INT, "max_columns"), "set_max_columns", "get_max_columns"); ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "same_column_width"), "set_same_column_width", "is_same_column_width"); @@ -1372,6 +1398,8 @@ ItemList::ItemList() { same_column_width = false; max_text_lines = 1; max_columns = 1; + auto_height = false; + auto_height_value = 0.0f; scroll_bar = memnew(VScrollBar); add_child(scroll_bar); diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 9cb7016b60..137eff8885 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -78,6 +78,9 @@ private: bool ensure_selected_visible; bool same_column_width; + bool auto_height; + float auto_height_value; + Vector<Item> items; Vector<int> separators; @@ -198,6 +201,11 @@ public: void set_icon_scale(real_t p_scale); real_t get_icon_scale() const; + void set_auto_height(bool p_enable); + bool has_auto_height() const; + + Size2 get_minimum_size() const; + VScrollBar *get_v_scroll() { return scroll_bar; } ItemList(); diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index f02e01d85a..874156821e 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -28,15 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "label.h" -#include "global_config.h" #include "print_string.h" +#include "project_settings.h" #include "translation.h" void Label::set_autowrap(bool p_autowrap) { autowrap = p_autowrap; word_cache_dirty = true; - minimum_size_changed(); update(); } bool Label::has_autowrap() const { @@ -48,7 +47,6 @@ void Label::set_uppercase(bool p_uppercase) { uppercase = p_uppercase; word_cache_dirty = true; - minimum_size_changed(); update(); } bool Label::is_uppercase() const { @@ -71,7 +69,6 @@ void Label::_notification(int p_what) { xl_text = new_text; regenerate_word_cache(); - minimum_size_changed(); update(); } @@ -292,7 +289,7 @@ void Label::_notification(int p_what) { Size2 Label::get_minimum_size() const { if (autowrap) - return Size2(1, 1); + return Size2(1, clip ? 1 : minsize.height); else { // don't want to mutable everything @@ -487,15 +484,16 @@ void Label::regenerate_word_cache() { } } - if (!autowrap) { + if (!autowrap) minsize.width = width; - if (max_lines_visible > 0 && line_count > max_lines_visible) { - minsize.height = (font->get_height() * max_lines_visible) + (line_spacing * (max_lines_visible - 1)); - } else { - minsize.height = (font->get_height() * line_count) + (line_spacing * (line_count - 1)); - } + + if (max_lines_visible > 0 && line_count > max_lines_visible) { + minsize.height = (font->get_height() * max_lines_visible) + (line_spacing * (max_lines_visible - 1)); + } else { + minsize.height = (font->get_height() * line_count) + (line_spacing * (line_count - 1)); } + minimum_size_changed(); word_cache_dirty = false; } @@ -533,9 +531,6 @@ void Label::set_text(const String &p_string) { if (percent_visible < 1) visible_chars = get_total_character_count() * percent_visible; update(); - if (!autowrap) { - minimum_size_changed(); - } } void Label::set_clip_text(bool p_clip) { diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index adcf86357d..f4dd3e92cd 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -628,6 +628,12 @@ void LineEdit::_notification(int p_what) { font_color.a *= placeholder_alpha; font_color.a *= disabled_alpha; + if (has_icon("right_icon")) { + Ref<Texture> r_icon = Control::get_icon("right_icon"); + ofs_max -= r_icon->get_width(); + r_icon->draw(ci, Point2(width - r_icon->get_width() - x_ofs, y_ofs), Color(1, 1, 1, disabled_alpha * .9)); + } + int caret_height = font->get_height() > y_area ? y_area : font->get_height(); while (true) { diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index f75e0986c1..b842419eab 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -52,11 +52,26 @@ void OptionButton::_notification(int p_what) { RID ci = get_canvas_item(); Ref<Texture> arrow = Control::get_icon("arrow"); Ref<StyleBox> normal = get_stylebox("normal"); + Color clr = Color(1, 1, 1); + if (get_constant("modulate_arrow")) + switch (get_draw_mode()) { + case DRAW_PRESSED: + clr = get_color("font_color_pressed"); + break; + case DRAW_HOVER: + clr = get_color("font_color_hover"); + break; + case DRAW_DISABLED: + clr = get_color("font_color_disabled"); + break; + default: + clr = get_color("font_color"); + } Size2 size = get_size(); Point2 ofs(size.width - arrow->get_width() - get_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2))); - arrow->draw(ci, ofs); + arrow->draw(ci, ofs, clr); } break; } diff --git a/scene/gui/patch_9_rect.cpp b/scene/gui/patch_9_rect.cpp index 735f36b55d..16f2bb6b6f 100644 --- a/scene/gui/patch_9_rect.cpp +++ b/scene/gui/patch_9_rect.cpp @@ -54,8 +54,8 @@ Size2 NinePatchRect::get_minimum_size() const { } void NinePatchRect::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_texture", "texture"), &NinePatchRect::set_texture); - ClassDB::bind_method(D_METHOD("get_texture"), &NinePatchRect::get_texture); + ClassDB::bind_method(D_METHOD("set_texture", "texture:Texture"), &NinePatchRect::set_texture); + ClassDB::bind_method(D_METHOD("get_texture:Texture"), &NinePatchRect::get_texture); ClassDB::bind_method(D_METHOD("set_patch_margin", "margin", "value"), &NinePatchRect::set_patch_margin); ClassDB::bind_method(D_METHOD("get_patch_margin", "margin"), &NinePatchRect::get_patch_margin); ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &NinePatchRect::set_region_rect); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 864fb3d3d5..f59a2e06eb 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -1075,19 +1075,19 @@ void PopupMenu::clear_autohide_areas() { void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &PopupMenu::_gui_input); - ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_item, DEFVAL(-1), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("add_icon_item", "texture:Texture", "label", "id", "accel"), &PopupMenu::add_icon_item, DEFVAL(-1), DEFVAL(0)); ClassDB::bind_method(D_METHOD("add_item", "label", "id", "accel"), &PopupMenu::add_item, DEFVAL(-1), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("add_icon_check_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_check_item, DEFVAL(-1), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("add_icon_check_item", "texture:Texture", "label", "id", "accel"), &PopupMenu::add_icon_check_item, DEFVAL(-1), DEFVAL(0)); ClassDB::bind_method(D_METHOD("add_check_item", "label", "id", "accel"), &PopupMenu::add_check_item, DEFVAL(-1), DEFVAL(0)); ClassDB::bind_method(D_METHOD("add_submenu_item", "label", "submenu", "id"), &PopupMenu::add_submenu_item, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("add_icon_shortcut", "texture", "shortcut:ShortCut", "id", "global"), &PopupMenu::add_icon_shortcut, DEFVAL(-1), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("add_icon_shortcut", "texture:Texture", "shortcut:ShortCut", "id", "global"), &PopupMenu::add_icon_shortcut, DEFVAL(-1), DEFVAL(false)); ClassDB::bind_method(D_METHOD("add_shortcut", "shortcut:ShortCut", "id", "global"), &PopupMenu::add_shortcut, DEFVAL(-1), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("add_icon_check_shortcut", "texture", "shortcut:ShortCut", "id", "global"), &PopupMenu::add_icon_check_shortcut, DEFVAL(-1), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("add_icon_check_shortcut", "texture:Texture", "shortcut:ShortCut", "id", "global"), &PopupMenu::add_icon_check_shortcut, DEFVAL(-1), DEFVAL(false)); ClassDB::bind_method(D_METHOD("add_check_shortcut", "shortcut:ShortCut", "id", "global"), &PopupMenu::add_check_shortcut, DEFVAL(-1), DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_item_text", "idx", "text"), &PopupMenu::set_item_text); - ClassDB::bind_method(D_METHOD("set_item_icon", "idx", "icon"), &PopupMenu::set_item_icon); + ClassDB::bind_method(D_METHOD("set_item_icon", "idx", "icon:Texture"), &PopupMenu::set_item_icon); ClassDB::bind_method(D_METHOD("set_item_checked", "idx", "checked"), &PopupMenu::set_item_checked); ClassDB::bind_method(D_METHOD("set_item_ID", "idx", "id"), &PopupMenu::set_item_ID); ClassDB::bind_method(D_METHOD("set_item_accelerator", "idx", "accel"), &PopupMenu::set_item_accelerator); @@ -1102,7 +1102,7 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("toggle_item_checked", "idx"), &PopupMenu::toggle_item_checked); ClassDB::bind_method(D_METHOD("get_item_text", "idx"), &PopupMenu::get_item_text); - ClassDB::bind_method(D_METHOD("get_item_icon", "idx"), &PopupMenu::get_item_icon); + ClassDB::bind_method(D_METHOD("get_item_icon:Texture", "idx"), &PopupMenu::get_item_icon); ClassDB::bind_method(D_METHOD("is_item_checked", "idx"), &PopupMenu::is_item_checked); ClassDB::bind_method(D_METHOD("get_item_ID", "idx"), &PopupMenu::get_item_ID); ClassDB::bind_method(D_METHOD("get_item_index", "id"), &PopupMenu::get_item_index); diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index 7158592bb1..6bec365dcf 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -234,7 +234,7 @@ void Range::_bind_methods() { ClassDB::bind_method(D_METHOD("set_exp_ratio", "enabled"), &Range::set_exp_ratio); ClassDB::bind_method(D_METHOD("is_ratio_exp"), &Range::is_ratio_exp); - ClassDB::bind_method(D_METHOD("share", "with"), &Range::_share); + ClassDB::bind_method(D_METHOD("share", "with:Node"), &Range::_share); ClassDB::bind_method(D_METHOD("unshare"), &Range::unshare); ADD_SIGNAL(MethodInfo("value_changed", PropertyInfo(Variant::REAL, "value"))); @@ -273,8 +273,8 @@ Range::Range() { shared = memnew(Shared); shared->min = 0; shared->max = 100; - shared->val = - shared->step = 1; + shared->val = 0; + shared->step = 1; shared->page = 0; shared->owners.insert(this); shared->exp_ratio = false; diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index c6b8398736..9f71fa070c 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1855,7 +1855,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text); ClassDB::bind_method(D_METHOD("add_image", "image:Texture"), &RichTextLabel::add_image); ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline); - ClassDB::bind_method(D_METHOD("remove_line"), &RichTextLabel::remove_line); + ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line); ClassDB::bind_method(D_METHOD("push_font", "font:Font"), &RichTextLabel::push_font); ClassDB::bind_method(D_METHOD("push_color", "color"), &RichTextLabel::push_color); ClassDB::bind_method(D_METHOD("push_align", "align"), &RichTextLabel::push_align); diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index c84608ef2e..9ba17ce34f 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -167,7 +167,8 @@ void Slider::_notification(int p_what) { if (orientation == VERTICAL) { - style->draw(ci, Rect2i(Point2i(), Size2i(style->get_minimum_size().width + style->get_center_size().width, size.height))); + int widget_width = style->get_minimum_size().width + style->get_center_size().width; + style->draw(ci, Rect2i(Point2i(size.width / 2 - widget_width / 2, 0), Size2i(widget_width, size.height))); /* if (mouse_inside||has_focus()) focus->draw(ci,Rect2i(Point2i(),Size2i(style->get_minimum_size().width+style->get_center_size().width,size.height))); @@ -183,7 +184,9 @@ void Slider::_notification(int p_what) { } grabber->draw(ci, Point2i(size.width / 2 - grabber->get_size().width / 2, size.height - get_as_ratio() * areasize - grabber->get_size().height)); } else { - style->draw(ci, Rect2i(Point2i(), Size2i(size.width, style->get_minimum_size().height + style->get_center_size().height))); + + int widget_height = style->get_minimum_size().height + style->get_center_size().height; + style->draw(ci, Rect2i(Point2i(0, size.height / 2 - widget_height / 2), Size2i(size.width, widget_height))); /* if (mouse_inside||has_focus()) focus->draw(ci,Rect2i(Point2i(),Size2i(size.width,style->get_minimum_size().height+style->get_center_size().height))); diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index c5b9df15b9..1ba6e6e4bd 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -253,7 +253,7 @@ void SpinBox::_bind_methods() { ClassDB::bind_method(D_METHOD("set_editable", "editable"), &SpinBox::set_editable); ClassDB::bind_method(D_METHOD("is_editable"), &SpinBox::is_editable); ClassDB::bind_method(D_METHOD("_line_edit_focus_exit"), &SpinBox::_line_edit_focus_exit); - ClassDB::bind_method(D_METHOD("get_line_edit"), &SpinBox::get_line_edit); + ClassDB::bind_method(D_METHOD("get_line_edit:LineEdit"), &SpinBox::get_line_edit); ClassDB::bind_method(D_METHOD("_line_edit_input"), &SpinBox::_line_edit_input); ClassDB::bind_method(D_METHOD("_range_click_timeout"), &SpinBox::_range_click_timeout); diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 4316f06a53..c477a3156f 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -630,6 +630,7 @@ int Tabs::get_tab_idx_at_point(const Point2 &p_point) const { void Tabs::set_tab_align(TabAlign p_align) { + ERR_FAIL_INDEX(p_align, ALIGN_MAX); tab_align = p_align; update(); } @@ -639,6 +640,22 @@ Tabs::TabAlign Tabs::get_tab_align() const { return tab_align; } +void Tabs::move_tab(int from, int to) { + + if (from == to) + return; + + ERR_FAIL_INDEX(from, tabs.size()); + ERR_FAIL_INDEX(to, tabs.size()); + + Tab tab_from = tabs[from]; + tabs.remove(from); + tabs.insert(to, tab_from); + + _update_cache(); + update(); +} + int Tabs::get_tab_width(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, tabs.size(), 0); @@ -748,10 +765,17 @@ Rect2 Tabs::get_tab_rect(int p_tab) const { } void Tabs::set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy) { + + ERR_FAIL_INDEX(p_policy, CLOSE_BUTTON_MAX); cb_displaypolicy = p_policy; update(); } +Tabs::CloseButtonDisplayPolicy Tabs::get_tab_close_display_policy() const { + + return cb_displaypolicy; +} + void Tabs::set_min_width(int p_width) { min_width = p_width; } @@ -773,6 +797,10 @@ void Tabs::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tab_align", "align"), &Tabs::set_tab_align); ClassDB::bind_method(D_METHOD("get_tab_align"), &Tabs::get_tab_align); ClassDB::bind_method(D_METHOD("ensure_tab_visible", "idx"), &Tabs::ensure_tab_visible); + ClassDB::bind_method(D_METHOD("get_tab_rect", "tab_idx"), &Tabs::get_tab_rect); + ClassDB::bind_method(D_METHOD("move_tab", "from", "to"), &Tabs::move_tab); + ClassDB::bind_method(D_METHOD("set_tab_close_display_policy", "policy"), &Tabs::set_tab_close_display_policy); + ClassDB::bind_method(D_METHOD("get_tab_close_display_policy"), &Tabs::get_tab_close_display_policy); ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("right_button_pressed", PropertyInfo(Variant::INT, "tab"))); @@ -781,14 +809,17 @@ void Tabs::_bind_methods() { ADD_SIGNAL(MethodInfo("reposition_active_tab_request", PropertyInfo(Variant::INT, "idx_to"))); ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab"); + ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "tab_close_display_policy", PROPERTY_HINT_ENUM, "Show Never,Show Active Only,Show Always"), "set_tab_close_display_policy", "get_tab_close_display_policy"); BIND_CONSTANT(ALIGN_LEFT); BIND_CONSTANT(ALIGN_CENTER); BIND_CONSTANT(ALIGN_RIGHT); + BIND_CONSTANT(ALIGN_MAX); BIND_CONSTANT(CLOSE_BUTTON_SHOW_ACTIVE_ONLY); BIND_CONSTANT(CLOSE_BUTTON_SHOW_ALWAYS); BIND_CONSTANT(CLOSE_BUTTON_SHOW_NEVER); + BIND_CONSTANT(CLOSE_BUTTON_MAX); } Tabs::Tabs() { diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h index 613c604b12..86ad128dcd 100644 --- a/scene/gui/tabs.h +++ b/scene/gui/tabs.h @@ -41,7 +41,8 @@ public: ALIGN_LEFT, ALIGN_CENTER, - ALIGN_RIGHT + ALIGN_RIGHT, + ALIGN_MAX }; enum CloseButtonDisplayPolicy { @@ -49,6 +50,7 @@ public: CLOSE_BUTTON_SHOW_NEVER, CLOSE_BUTTON_SHOW_ACTIVE_ONLY, CLOSE_BUTTON_SHOW_ALWAYS, + CLOSE_BUTTON_MAX }; private: @@ -119,7 +121,10 @@ public: void set_tab_align(TabAlign p_align); TabAlign get_tab_align() const; + void move_tab(int from, int to); + void set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy); + CloseButtonDisplayPolicy get_tab_close_display_policy() const; int get_tab_count() const; void set_current_tab(int p_current); @@ -140,5 +145,6 @@ public: }; VARIANT_ENUM_CAST(Tabs::TabAlign); +VARIANT_ENUM_CAST(Tabs::CloseButtonDisplayPolicy); #endif // TABS_H diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index ffa23ce771..8baca50d32 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -33,8 +33,8 @@ #include "os/keyboard.h" #include "os/os.h" -#include "global_config.h" #include "message_queue.h" +#include "project_settings.h" #include "scene/main/viewport.h" #define TAB_PIXELS @@ -4597,7 +4597,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("add_keyword_color", "keyword", "color"), &TextEdit::add_keyword_color); ClassDB::bind_method(D_METHOD("add_color_region", "begin_key", "end_key", "color", "line_only"), &TextEdit::add_color_region, DEFVAL(false)); ClassDB::bind_method(D_METHOD("clear_colors"), &TextEdit::clear_colors); - ClassDB::bind_method(D_METHOD("menu_option"), &TextEdit::menu_option); + ClassDB::bind_method(D_METHOD("menu_option", "option"), &TextEdit::menu_option); ClassDB::bind_method(D_METHOD("get_menu:PopupMenu"), &TextEdit::get_menu); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "syntax_highlighting"), "set_syntax_coloring", "is_syntax_coloring_enabled"); diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp index 081c7ddb73..40995b19fa 100644 --- a/scene/gui/texture_progress.cpp +++ b/scene/gui/texture_progress.cpp @@ -242,14 +242,14 @@ Point2 TextureProgress::get_radial_center_offset() { void TextureProgress::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_under_texture", "tex"), &TextureProgress::set_under_texture); - ClassDB::bind_method(D_METHOD("get_under_texture"), &TextureProgress::get_under_texture); + ClassDB::bind_method(D_METHOD("set_under_texture", "tex:Texture"), &TextureProgress::set_under_texture); + ClassDB::bind_method(D_METHOD("get_under_texture:Texture"), &TextureProgress::get_under_texture); - ClassDB::bind_method(D_METHOD("set_progress_texture", "tex"), &TextureProgress::set_progress_texture); - ClassDB::bind_method(D_METHOD("get_progress_texture"), &TextureProgress::get_progress_texture); + ClassDB::bind_method(D_METHOD("set_progress_texture", "tex:Texture"), &TextureProgress::set_progress_texture); + ClassDB::bind_method(D_METHOD("get_progress_texture:Texture"), &TextureProgress::get_progress_texture); - ClassDB::bind_method(D_METHOD("set_over_texture", "tex"), &TextureProgress::set_over_texture); - ClassDB::bind_method(D_METHOD("get_over_texture"), &TextureProgress::get_over_texture); + ClassDB::bind_method(D_METHOD("set_over_texture", "tex:Texture"), &TextureProgress::set_over_texture); + ClassDB::bind_method(D_METHOD("get_over_texture:Texture"), &TextureProgress::get_over_texture); ClassDB::bind_method(D_METHOD("set_fill_mode", "mode"), &TextureProgress::set_fill_mode); ClassDB::bind_method(D_METHOD("get_fill_mode"), &TextureProgress::get_fill_mode); diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp index 92a3db6a74..9459002bc0 100644 --- a/scene/gui/texture_rect.cpp +++ b/scene/gui/texture_rect.cpp @@ -101,8 +101,8 @@ Size2 TextureRect::get_minimum_size() const { } void TextureRect::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_texture", "texture"), &TextureRect::set_texture); - ClassDB::bind_method(D_METHOD("get_texture"), &TextureRect::get_texture); + ClassDB::bind_method(D_METHOD("set_texture", "texture:Texture"), &TextureRect::set_texture); + ClassDB::bind_method(D_METHOD("get_texture:Texture"), &TextureRect::get_texture); ClassDB::bind_method(D_METHOD("set_expand", "enable"), &TextureRect::set_expand); ClassDB::bind_method(D_METHOD("has_expand"), &TextureRect::has_expand); ClassDB::bind_method(D_METHOD("set_stretch_mode", "stretch_mode"), &TextureRect::set_stretch_mode); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 44f71a2c4e..1456ab51c0 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "tree.h" -#include "global_config.h" #include "os/input.h" #include "os/keyboard.h" #include "os/os.h" #include "print_string.h" +#include "project_settings.h" #include "scene/main/viewport.h" void TreeItem::move_to_top() { @@ -70,7 +70,7 @@ Size2 TreeItem::Cell::get_icon_size() const { return icon_region.size; } -void TreeItem::Cell::draw_icon(const RID &p_where, const Point2 &p_pos, const Size2 &p_size) const { +void TreeItem::Cell::draw_icon(const RID &p_where, const Point2 &p_pos, const Size2 &p_size, const Color &p_color) const { if (icon.is_null()) return; @@ -79,10 +79,10 @@ void TreeItem::Cell::draw_icon(const RID &p_where, const Point2 &p_pos, const Si if (icon_region == Rect2i()) { - icon->draw_rect_region(p_where, Rect2(p_pos, dsize), Rect2(Point2(), icon->get_size())); + icon->draw_rect_region(p_where, Rect2(p_pos, dsize), Rect2(Point2(), icon->get_size()), p_color); } else { - icon->draw_rect_region(p_where, Rect2(p_pos, dsize), icon_region); + icon->draw_rect_region(p_where, Rect2(p_pos, dsize), icon_region, p_color); } } @@ -203,6 +203,19 @@ Rect2 TreeItem::get_icon_region(int p_column) const { return cells[p_column].icon_region; } +void TreeItem::set_icon_color(int p_column, const Color &p_icon_color) { + + ERR_FAIL_INDEX(p_column, cells.size()); + cells[p_column].icon_color = p_icon_color; + _changed_notify(p_column); +} + +Color TreeItem::get_icon_color(int p_column) const { + + ERR_FAIL_INDEX_V(p_column, cells.size(), Color()); + return cells[p_column].icon_color; +} + void TreeItem::set_icon_max_width(int p_column, int p_max) { ERR_FAIL_INDEX(p_column, cells.size()); @@ -697,7 +710,7 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("get_next_visible:TreeItem"), &TreeItem::get_next_visible); ClassDB::bind_method(D_METHOD("get_prev_visible:TreeItem"), &TreeItem::get_prev_visible); - ClassDB::bind_method(D_METHOD("remove_child:TreeItem", "child"), &TreeItem::_remove_child); + ClassDB::bind_method(D_METHOD("remove_child", "child"), &TreeItem::_remove_child); ClassDB::bind_method(D_METHOD("set_selectable", "column", "selectable"), &TreeItem::set_selectable); ClassDB::bind_method(D_METHOD("is_selectable", "column"), &TreeItem::is_selectable); @@ -933,7 +946,7 @@ int Tree::get_item_height(TreeItem *p_item) const { return height; } -void Tree::draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color) { +void Tree::draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color) { Rect2i rect = p_rect; Ref<Font> font = cache.font; @@ -972,7 +985,7 @@ void Tree::draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, co bmsize.width = p_cell.icon_max_w; } - p_cell.draw_icon(ci, rect.position + Size2i(0, Math::floor((real_t)(rect.size.y - bmsize.y) / 2)), bmsize); + p_cell.draw_icon(ci, rect.position + Size2i(0, Math::floor((real_t)(rect.size.y - bmsize.y) / 2)), bmsize, p_icon_color); rect.position.x += bmsize.x + cache.hseparation; rect.size.x -= bmsize.x + cache.hseparation; } @@ -1176,6 +1189,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } Color col = p_item->cells[i].custom_color ? p_item->cells[i].color : get_color(p_item->cells[i].selected ? "font_color_selected" : "font_color"); + Color icon_col = p_item->cells[i].icon_color; Point2i text_pos = item_rect.position; text_pos.y += Math::floor((item_rect.size.y - font->get_height()) / 2) + font_ascent; @@ -1184,7 +1198,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 case TreeItem::CELL_MODE_STRING: { - draw_item_rect(p_item->cells[i], item_rect, col); + draw_item_rect(p_item->cells[i], item_rect, col, icon_col); } break; case TreeItem::CELL_MODE_CHECK: { @@ -1195,9 +1209,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (p_item->cells[i].checked) { - checked->draw(ci, check_ofs); + checked->draw(ci, check_ofs, icon_col); } else { - unchecked->draw(ci, check_ofs); + unchecked->draw(ci, check_ofs, icon_col); } int check_w = checked->get_width() + cache.hseparation; @@ -1207,7 +1221,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 item_rect.size.x -= check_w; item_rect.position.x += check_w; - draw_item_rect(p_item->cells[i], item_rect, col); + draw_item_rect(p_item->cells[i], item_rect, col, icon_col); //font->draw( ci, text_pos, p_item->cells[i].text, col,item_rect.size.x-check_w ); @@ -1237,7 +1251,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 arrow_pos.x += item_rect.size.x - downarrow->get_width(); arrow_pos.y += Math::floor(((item_rect.size.y - downarrow->get_height())) / 2.0); - downarrow->draw(ci, arrow_pos); + downarrow->draw(ci, arrow_pos, icon_col); } else { Ref<Texture> updown = cache.updown; @@ -1257,7 +1271,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 updown_pos.x += item_rect.size.x - updown->get_width(); updown_pos.y += Math::floor(((item_rect.size.y - updown->get_height())) / 2.0); - updown->draw(ci, updown_pos); + updown->draw(ci, updown_pos, icon_col); } } break; @@ -1274,7 +1288,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 Point2i icon_ofs = (item_rect.size - icon_size) / 2; icon_ofs += item_rect.position; - draw_texture_rect(p_item->cells[i].icon, Rect2(icon_ofs, icon_size)); + draw_texture_rect(p_item->cells[i].icon, Rect2(icon_ofs, icon_size), false, icon_col); //p_item->cells[i].icon->draw(ci, icon_ofs); } break; @@ -1291,7 +1305,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (!p_item->cells[i].editable) { - draw_item_rect(p_item->cells[i], item_rect, col); + draw_item_rect(p_item->cells[i], item_rect, col, icon_col); break; } @@ -1319,7 +1333,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 ir.position += cache.custom_button->get_offset(); } - draw_item_rect(p_item->cells[i], ir, col); + draw_item_rect(p_item->cells[i], ir, col, icon_col); downarrow->draw(ci, arrow_pos); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 59e35bb230..694f91f9a6 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -89,6 +89,7 @@ private: Color bg_color; bool custom_button; bool expand_right; + Color icon_color; TextAlign text_align; @@ -133,10 +134,11 @@ private: icon_max_w = 0; text_align = ALIGN_LEFT; expand_right = false; + icon_color = Color(1, 1, 1); } Size2 get_icon_size() const; - void draw_icon(const RID &p_where, const Point2 &p_pos, const Size2 &p_size = Size2()) const; + void draw_icon(const RID &p_where, const Point2 &p_pos, const Size2 &p_size = Size2(), const Color &p_color = Color()) const; }; Vector<Cell> cells; @@ -193,6 +195,9 @@ public: void set_icon_region(int p_column, const Rect2 &p_icon_region); Rect2 get_icon_region(int p_column) const; + void set_icon_color(int p_column, const Color &p_icon_color); + Color get_icon_color(int p_column) const; + void set_icon_max_width(int p_column, int p_max); int get_icon_max_width(int p_column) const; @@ -361,7 +366,7 @@ private: int compute_item_height(TreeItem *p_item) const; int get_item_height(TreeItem *p_item) const; //void draw_item_text(String p_text,const Ref<Texture>& p_icon,int p_icon_max_w,bool p_tool,Rect2i p_rect,const Color& p_color); - void draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color); + void draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color); int draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item); void select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev = NULL, bool *r_in_range = NULL, bool p_force_deselect = false); int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_doubleclick, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod); diff --git a/scene/io/resource_format_image.cpp b/scene/io/resource_format_image.cpp index 6c0a6128d2..8b3f939f1a 100644 --- a/scene/io/resource_format_image.cpp +++ b/scene/io/resource_format_image.cpp @@ -30,7 +30,7 @@ #include "resource_format_image.h" #if 0 -#include "global_config.h" +#include "project_settings.h" #include "io/image_loader.h" #include "os/os.h" #include "scene/resources/texture.h" @@ -128,7 +128,7 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String& p_origin if (max_texture_size && (image.get_width() > max_texture_size || image.get_height() > max_texture_size)) { - if (bool(GlobalConfig::get_singleton()->get("debug/image_loader/max_texture_size_alert"))) { + if (bool(ProjectSettings::get_singleton()->get("debug/image_loader/max_texture_size_alert"))) { OS::get_singleton()->alert("Texture is too large: '"+p_path+"', at "+itos(image.get_width())+"x"+itos(image.get_height())+". Max allowed size is: "+itos(max_texture_size)+"x"+itos(max_texture_size)+".","BAD ARTIST, NO COOKIE!"); } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 61e563143c..c3849f79df 100755 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -311,6 +311,11 @@ void Node::move_child(Node *p_child, int p_pos) { ERR_FAIL_COND(data.blocked > 0); } + // Specifying one place beyond the end + // means the same as moving to the last position + if (p_pos == data.children.size()) + p_pos--; + if (p_child->data.pos == p_pos) return; //do nothing @@ -1258,7 +1263,7 @@ String Node::_generate_serial_child_name(Node *p_child) { name = p_child->get_class(); // Adjust casing according to project setting. The current type name is expected to be in PascalCase. - switch (GlobalConfig::get_singleton()->get("node/name_casing").operator int()) { + switch (ProjectSettings::get_singleton()->get("node/name_casing").operator int()) { case NAME_CASING_PASCAL_CASE: break; case NAME_CASING_CAMEL_CASE: @@ -2712,9 +2717,9 @@ void Node::request_ready() { void Node::_bind_methods() { GLOBAL_DEF("node/name_num_separator", 0); - GlobalConfig::get_singleton()->set_custom_property_info("node/name_num_separator", PropertyInfo(Variant::INT, "node/name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash")); + ProjectSettings::get_singleton()->set_custom_property_info("node/name_num_separator", PropertyInfo(Variant::INT, "node/name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash")); GLOBAL_DEF("node/name_casing", NAME_CASING_PASCAL_CASE); - GlobalConfig::get_singleton()->set_custom_property_info("node/name_casing", PropertyInfo(Variant::INT, "node/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case")); + ProjectSettings::get_singleton()->set_custom_property_info("node/name_casing", PropertyInfo(Variant::INT, "node/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case")); ClassDB::bind_method(D_METHOD("_add_child_below_node", "node:Node", "child_node:Node", "legible_unique_name"), &Node::add_child_below_node, DEFVAL(false)); @@ -2786,7 +2791,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("set_scene_instance_load_placeholder", "load_placeholder"), &Node::set_scene_instance_load_placeholder); ClassDB::bind_method(D_METHOD("get_scene_instance_load_placeholder"), &Node::get_scene_instance_load_placeholder); - ClassDB::bind_method(D_METHOD("get_viewport"), &Node::get_viewport); + ClassDB::bind_method(D_METHOD("get_viewport:Viewport"), &Node::get_viewport); ClassDB::bind_method(D_METHOD("queue_free"), &Node::queue_delete); @@ -2890,7 +2895,7 @@ void Node::_bind_methods() { } String Node::_get_name_num_separator() { - switch (GlobalConfig::get_singleton()->get("node/name_num_separator").operator int()) { + switch (ProjectSettings::get_singleton()->get("node/name_num_separator").operator int()) { case 0: return ""; case 1: return " "; case 2: return "_"; diff --git a/scene/main/node.h b/scene/main/node.h index 7baa65c022..cfd5c07921 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -31,7 +31,7 @@ #define NODE_H #include "class_db.h" -#include "global_config.h" +#include "project_settings.h" #include "map.h" #include "object.h" #include "path_db.h" diff --git a/scene/main/resource_preloader.cpp b/scene/main/resource_preloader.cpp index ae323ba021..febb95a181 100644 --- a/scene/main/resource_preloader.cpp +++ b/scene/main/resource_preloader.cpp @@ -153,11 +153,11 @@ void ResourcePreloader::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_resources"), &ResourcePreloader::_set_resources); ClassDB::bind_method(D_METHOD("_get_resources"), &ResourcePreloader::_get_resources); - ClassDB::bind_method(D_METHOD("add_resource", "name", "resource"), &ResourcePreloader::add_resource); + ClassDB::bind_method(D_METHOD("add_resource", "name", "resource:Resource"), &ResourcePreloader::add_resource); ClassDB::bind_method(D_METHOD("remove_resource", "name"), &ResourcePreloader::remove_resource); ClassDB::bind_method(D_METHOD("rename_resource", "name", "newname"), &ResourcePreloader::rename_resource); ClassDB::bind_method(D_METHOD("has_resource", "name"), &ResourcePreloader::has_resource); - ClassDB::bind_method(D_METHOD("get_resource", "name"), &ResourcePreloader::get_resource); + ClassDB::bind_method(D_METHOD("get_resource:Resource", "name"), &ResourcePreloader::get_resource); ClassDB::bind_method(D_METHOD("get_resource_list"), &ResourcePreloader::_get_resource_list); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "resources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_resources", "_get_resources"); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 65c7c1a36f..48e6a44745 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -29,12 +29,12 @@ /*************************************************************************/ #include "scene_tree.h" -#include "global_config.h" #include "message_queue.h" #include "node.h" #include "os/keyboard.h" #include "os/os.h" #include "print_string.h" +#include "project_settings.h" #include <stdio.h> //#include "servers/spatial_sound_2d_server.h" @@ -614,7 +614,7 @@ bool SceneTree::idle(float p_time) { if (is_editor_hint()) { //simple hack to reload fallback environment if it changed from editor - String env_path = GlobalConfig::get_singleton()->get("rendering/environment/default_environment"); + String env_path = ProjectSettings::get_singleton()->get("rendering/environment/default_environment"); env_path = env_path.strip_edges(); //user may have added a space or two String cpath; Ref<Environment> fallback = get_root()->get_world()->get_fallback_environment(); @@ -1153,7 +1153,7 @@ void SceneTree::_update_root_rect() { if (stretch_mode == STRETCH_MODE_DISABLED) { - root->set_size(last_screen_size); + root->set_size((last_screen_size / stretch_shrink).floor()); root->set_attach_to_screen_rect(Rect2(Point2(), last_screen_size)); root->set_size_override_stretch(false); root->set_size_override(false, Size2()); @@ -1231,15 +1231,15 @@ void SceneTree::_update_root_rect() { switch (stretch_mode) { case STRETCH_MODE_2D: { - root->set_size(screen_size); + root->set_size((screen_size / stretch_shrink).floor()); root->set_attach_to_screen_rect(Rect2(margin, screen_size)); root->set_size_override_stretch(true); - root->set_size_override(true, viewport_size); + root->set_size_override(true, (viewport_size / stretch_shrink).floor()); } break; case STRETCH_MODE_VIEWPORT: { - root->set_size(viewport_size); + root->set_size((viewport_size / stretch_shrink).floor()); root->set_attach_to_screen_rect(Rect2(margin, screen_size)); root->set_size_override_stretch(false); root->set_size_override(false, Size2()); @@ -1248,11 +1248,12 @@ void SceneTree::_update_root_rect() { } } -void SceneTree::set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 p_minsize) { +void SceneTree::set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 p_minsize, int p_shrink) { stretch_mode = p_mode; stretch_aspect = p_aspect; stretch_min = p_minsize; + stretch_shrink = p_shrink; _update_root_rect(); } @@ -2192,8 +2193,8 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("is_debugging_navigation_hint"), &SceneTree::is_debugging_navigation_hint); #ifdef TOOLS_ENABLED - ClassDB::bind_method(D_METHOD("set_edited_scene_root", "scene"), &SceneTree::set_edited_scene_root); - ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &SceneTree::get_edited_scene_root); + ClassDB::bind_method(D_METHOD("set_edited_scene_root", "scene:Node"), &SceneTree::set_edited_scene_root); + ClassDB::bind_method(D_METHOD("get_edited_scene_root:Node"), &SceneTree::get_edited_scene_root); #endif ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause); @@ -2207,7 +2208,7 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_frame"), &SceneTree::get_frame); ClassDB::bind_method(D_METHOD("quit"), &SceneTree::quit); - ClassDB::bind_method(D_METHOD("set_screen_stretch", "mode", "aspect", "minsize"), &SceneTree::set_screen_stretch); + ClassDB::bind_method(D_METHOD("set_screen_stretch", "mode", "aspect", "minsize", "shrink"), &SceneTree::set_screen_stretch, DEFVAL(1)); ClassDB::bind_method(D_METHOD("queue_delete", "obj"), &SceneTree::queue_delete); @@ -2351,9 +2352,13 @@ SceneTree::SceneTree() { int ref_atlas_size = GLOBAL_DEF("rendering/quality/reflections/atlas_size", 2048); int ref_atlas_subdiv = GLOBAL_DEF("rendering/quality/reflections/atlas_subdiv", 8); int msaa_mode = GLOBAL_DEF("rendering/quality/filters/msaa", 0); - GlobalConfig::get_singleton()->set_custom_property_info("rendering/quality/filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x")); root->set_msaa(Viewport::MSAA(msaa_mode)); - bool hdr = GLOBAL_DEF("rendering/quality/depth/hdr", true); + + GLOBAL_DEF("rendering/quality/depth/hdr", true); + GLOBAL_DEF("rendering/quality/depth/hdr.mobile", false); + + bool hdr = GLOBAL_GET("rendering/quality/depth/hdr"); root->set_hdr(hdr); VS::get_singleton()->scenario_set_reflection_atlas_size(root->get_world()->get_scenario(), ref_atlas_size, ref_atlas_subdiv); @@ -2371,7 +2376,7 @@ SceneTree::SceneTree() { //get path String env_path = GLOBAL_DEF("rendering/environment/default_environment", ""); //setup property - GlobalConfig::get_singleton()->set_custom_property_info("rendering/environment/default_environment", PropertyInfo(Variant::STRING, "rendering/viewport/default_environment", PROPERTY_HINT_FILE, ext_hint)); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/default_environment", PropertyInfo(Variant::STRING, "rendering/viewport/default_environment", PROPERTY_HINT_FILE, ext_hint)); env_path = env_path.strip_edges(); if (env_path != String()) { Ref<Environment> env = ResourceLoader::load(env_path); @@ -2380,7 +2385,7 @@ SceneTree::SceneTree() { } else { if (is_editor_hint()) { //file was erased, clear the field. - GlobalConfig::get_singleton()->set("rendering/environment/default_environment", ""); + ProjectSettings::get_singleton()->set("rendering/environment/default_environment", ""); } else { //file was erased, notify user. ERR_PRINTS(RTR("Default Environment as specified in Project Setings (Rendering -> Viewport -> Default Environment) could not be loaded.")); @@ -2391,6 +2396,7 @@ SceneTree::SceneTree() { stretch_mode = STRETCH_MODE_DISABLED; stretch_aspect = STRETCH_ASPECT_IGNORE; + stretch_shrink = 1; last_screen_size = Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height); _update_root_rect(); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 76a4becdbc..90d42ef01b 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -149,6 +149,7 @@ private: StretchMode stretch_mode; StretchAspect stretch_aspect; Size2i stretch_min; + int stretch_shrink; void _update_root_rect(); @@ -420,7 +421,7 @@ public: void get_nodes_in_group(const StringName &p_group, List<Node *> *p_list); bool has_group(const StringName &p_identifier) const; - void set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 p_minsize); + void set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 p_minsize, int p_shrink = 1); //void change_scene(const String& p_path); //Node *get_loaded_scene(); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 824f968c49..5ce347d79b 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -48,7 +48,7 @@ #include "scene/main/timer.h" #include "scene/scene_string_names.h" -#include "global_config.h" +#include "project_settings.h" #include "scene/3d/scenario_fx.h" void ViewportTexture::setup_local_to_scene() { @@ -2606,8 +2606,8 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("get_physics_object_picking"), &Viewport::get_physics_object_picking); ClassDB::bind_method(D_METHOD("get_viewport_rid"), &Viewport::get_viewport_rid); - ClassDB::bind_method(D_METHOD("input", "local_event"), &Viewport::input); - ClassDB::bind_method(D_METHOD("unhandled_input", "local_event"), &Viewport::unhandled_input); + ClassDB::bind_method(D_METHOD("input", "local_event:InputEvent"), &Viewport::input); + ClassDB::bind_method(D_METHOD("unhandled_input", "local_event:InputEvent"), &Viewport::unhandled_input); ClassDB::bind_method(D_METHOD("update_worlds"), &Viewport::update_worlds); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index c6d26f4d4c..74c556931c 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "register_scene_types.h" -#include "global_config.h" +#include "project_settings.h" #include "os/os.h" #include "scene/io/resource_format_image.h" #include "scene/io/resource_format_wav.h" @@ -271,11 +271,11 @@ void register_scene_types() { ResourceLoader::add_resource_format_loader(resource_loader_theme); bool default_theme_hidpi = GLOBAL_DEF("gui/theme/use_hidpi", false); - GlobalConfig::get_singleton()->set_custom_property_info("gui/theme/use_hidpi", PropertyInfo(Variant::BOOL, "gui/theme/use_hidpi", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/use_hidpi", PropertyInfo(Variant::BOOL, "gui/theme/use_hidpi", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); String theme_path = GLOBAL_DEF("gui/theme/custom", ""); - GlobalConfig::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); String font_path = GLOBAL_DEF("gui/theme/custom_font", ""); - GlobalConfig::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); if (theme_path != String()) { Ref<Theme> theme = ResourceLoader::load(theme_path); diff --git a/scene/resources/audio_stream_resampled.cpp b/scene/resources/audio_stream_resampled.cpp index 213ac4400b..1b1d6f8587 100644 --- a/scene/resources/audio_stream_resampled.cpp +++ b/scene/resources/audio_stream_resampled.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "audio_stream_resampled.h" -#include "global_config.h" +#include "project_settings.h" #if 0 int AudioStreamResampled::get_channel_count() const { diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp index a473067937..73a759278b 100644 --- a/scene/resources/bit_mask.cpp +++ b/scene/resources/bit_mask.cpp @@ -170,7 +170,7 @@ Dictionary BitMap::_get_data() const { void BitMap::_bind_methods() { ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create); - ClassDB::bind_method(D_METHOD("create_from_image_alpha", "image"), &BitMap::create_from_image_alpha); + ClassDB::bind_method(D_METHOD("create_from_image_alpha", "image:Image"), &BitMap::create_from_image_alpha); ClassDB::bind_method(D_METHOD("set_bit", "pos", "bit"), &BitMap::set_bit); ClassDB::bind_method(D_METHOD("get_bit", "pos"), &BitMap::get_bit); diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index 338311b87b..fe0759fcba 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -1188,7 +1188,7 @@ void Curve2D::_set_data(const Dictionary &p_data) { baked_cache_dirty = true; } -PoolVector2Array Curve2D::tesselate(int p_max_stages, float p_tolerance) const { +PoolVector2Array Curve2D::tessellate(int p_max_stages, float p_tolerance) const { PoolVector2Array tess; @@ -1250,7 +1250,7 @@ void Curve2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve2D::get_baked_length); ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve2D::interpolate_baked, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve2D::get_baked_points); - ClassDB::bind_method(D_METHOD("tesselate", "max_stages", "tolerance_degrees"), &Curve2D::tesselate, DEFVAL(5), DEFVAL(4)); + ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve2D::tessellate, DEFVAL(5), DEFVAL(4)); ClassDB::bind_method(D_METHOD("_get_data"), &Curve2D::_get_data); ClassDB::bind_method(D_METHOD("_set_data"), &Curve2D::_set_data); @@ -1683,7 +1683,7 @@ void Curve3D::_set_data(const Dictionary &p_data) { baked_cache_dirty = true; } -PoolVector3Array Curve3D::tesselate(int p_max_stages, float p_tolerance) const { +PoolVector3Array Curve3D::tessellate(int p_max_stages, float p_tolerance) const { PoolVector3Array tess; @@ -1748,7 +1748,7 @@ void Curve3D::_bind_methods() { ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve3D::interpolate_baked, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve3D::get_baked_points); ClassDB::bind_method(D_METHOD("get_baked_tilts"), &Curve3D::get_baked_tilts); - ClassDB::bind_method(D_METHOD("tesselate", "max_stages", "tolerance_degrees"), &Curve3D::tesselate, DEFVAL(5), DEFVAL(4)); + ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve3D::tessellate, DEFVAL(5), DEFVAL(4)); ClassDB::bind_method(D_METHOD("_get_data"), &Curve3D::_get_data); ClassDB::bind_method(D_METHOD("_set_data"), &Curve3D::_set_data); diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 83a4357bfb..2815c12c4b 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -249,7 +249,7 @@ public: Vector2 interpolate_baked(float p_offset, bool p_cubic = false) const; PoolVector2Array get_baked_points() const; //useful for going through - PoolVector2Array tesselate(int p_max_stages = 5, float p_tolerance = 4) const; //useful for display + PoolVector2Array tessellate(int p_max_stages = 5, float p_tolerance = 4) const; //useful for display Curve2D(); }; @@ -318,7 +318,7 @@ public: PoolVector3Array get_baked_points() const; //useful for going through PoolRealArray get_baked_tilts() const; //useful for going through - PoolVector3Array tesselate(int p_max_stages = 5, float p_tolerance = 4) const; //useful for display + PoolVector3Array tessellate(int p_max_stages = 5, float p_tolerance = 4) const; //useful for display Curve3D(); }; diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index d2848076a0..2fdc4c9e24 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -338,7 +338,7 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT cpos.y += ch->v_align; ERR_FAIL_COND_V(ch->texture_idx < -1 || ch->texture_idx >= fb->textures.size(), 0); if (ch->texture_idx != -1) - VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), fb->textures[ch->texture_idx].texture->get_rid(), ch->rect, p_modulate); + VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), fb->textures[ch->texture_idx].texture->get_rid(), ch->rect, p_modulate, false, RID(), false); advance = ch->advance; used_fallback = true; break; @@ -360,7 +360,7 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT cpos.y += c->v_align; ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0); if (c->texture_idx != -1) - VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx].texture->get_rid(), c->rect, p_modulate); + VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx].texture->get_rid(), c->rect, p_modulate, false, RID(), false); advance = c->advance; //textures[c->texture_idx].texture->draw(p_canvas_item,Vector2()); } diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 125bbd2d64..ae89d8ed94 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "environment.h" -#include "global_config.h" +#include "project_settings.h" #include "servers/visual_server.h" #include "texture.h" @@ -1103,8 +1103,8 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("set_adjustment_saturation", "saturation"), &Environment::set_adjustment_saturation); ClassDB::bind_method(D_METHOD("get_adjustment_saturation"), &Environment::get_adjustment_saturation); - ClassDB::bind_method(D_METHOD("set_adjustment_color_correction", "color_correction"), &Environment::set_adjustment_color_correction); - ClassDB::bind_method(D_METHOD("get_adjustment_color_correction"), &Environment::get_adjustment_color_correction); + ClassDB::bind_method(D_METHOD("set_adjustment_color_correction", "color_correction:Texture"), &Environment::set_adjustment_color_correction); + ClassDB::bind_method(D_METHOD("get_adjustment_color_correction:Texture"), &Environment::get_adjustment_color_correction); ADD_GROUP("Adjustments", "adjustment_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "adjustment_enabled"), "set_adjustment_enable", "is_adjustment_enabled"); diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 225a42f651..a6a70d775f 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -506,7 +506,7 @@ float BitmapFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_c cpos.y += c->v_align; ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0); if (c->texture_idx != -1) - VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx]->get_rid(), c->rect, p_modulate); + VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx]->get_rid(), c->rect, p_modulate, false, RID(), false); return get_char_size(p_char, p_next).width; } @@ -570,8 +570,8 @@ void BitmapFont::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_textures"), &BitmapFont::_set_textures); ClassDB::bind_method(D_METHOD("_get_textures"), &BitmapFont::_get_textures); - ClassDB::bind_method(D_METHOD("set_fallback", "fallback"), &BitmapFont::set_fallback); - ClassDB::bind_method(D_METHOD("get_fallback"), &BitmapFont::get_fallback); + ClassDB::bind_method(D_METHOD("set_fallback", "fallback:BitmapFont"), &BitmapFont::set_fallback); + ClassDB::bind_method(D_METHOD("get_fallback:BitmapFont"), &BitmapFont::get_fallback); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_textures", "_get_textures"); ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY, "chars", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_chars", "_get_chars"); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index a0b192259b..24ec39afe3 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -334,6 +334,9 @@ void SpatialMaterial::_update_shader() { if (flags[FLAG_ONTOP]) { code += ",ontop"; } + if (flags[FLAG_USE_VERTEX_LIGHTING]) { + code += ",vertex_lighting"; + } if (flags[FLAG_UV1_USE_TRIPLANAR] || flags[FLAG_UV2_USE_TRIPLANAR]) { code += ",world_vertex_coords"; @@ -444,6 +447,11 @@ void SpatialMaterial::_update_shader() { code += "\tPOINT_SIZE=point_size;\n"; } + if (flags[FLAG_USE_VERTEX_LIGHTING]) { + + code += "\tROUGHNESS=roughness;\n"; + } + if (!flags[FLAG_UV1_USE_TRIPLANAR]) { code += "\tUV=UV*uv1_scale.xy+uv1_offset.xy;\n"; } @@ -1391,13 +1399,13 @@ void SpatialMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("get_specular_mode"), &SpatialMaterial::get_specular_mode); ClassDB::bind_method(D_METHOD("set_flag", "flag", "enable"), &SpatialMaterial::set_flag); - ClassDB::bind_method(D_METHOD("get_flag"), &SpatialMaterial::get_flag); + ClassDB::bind_method(D_METHOD("get_flag", "flag"), &SpatialMaterial::get_flag); ClassDB::bind_method(D_METHOD("set_feature", "feature", "enable"), &SpatialMaterial::set_feature); ClassDB::bind_method(D_METHOD("get_feature", "feature"), &SpatialMaterial::get_feature); - ClassDB::bind_method(D_METHOD("set_texture", "param:Texture", "texture"), &SpatialMaterial::set_texture); - ClassDB::bind_method(D_METHOD("get_texture:Texture", "param:Texture"), &SpatialMaterial::get_texture); + ClassDB::bind_method(D_METHOD("set_texture", "param", "texture:Texture"), &SpatialMaterial::set_texture); + ClassDB::bind_method(D_METHOD("get_texture:Texture", "param"), &SpatialMaterial::get_texture); ClassDB::bind_method(D_METHOD("set_detail_blend_mode", "detail_blend_mode"), &SpatialMaterial::set_detail_blend_mode); ClassDB::bind_method(D_METHOD("get_detail_blend_mode"), &SpatialMaterial::get_detail_blend_mode); @@ -1450,6 +1458,7 @@ void SpatialMaterial::_bind_methods() { ADD_GROUP("Flags", "flags_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_transparent"), "set_feature", "get_feature", FEATURE_TRANSPARENT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_unshaded"), "set_flag", "get_flag", FLAG_UNSHADED); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_vertex_lighting"), "set_flag", "get_flag", FLAG_USE_VERTEX_LIGHTING); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_on_top"), "set_flag", "get_flag", FLAG_ONTOP); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_use_point_size"), "set_flag", "get_flag", FLAG_USE_POINT_SIZE); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_fixed_size"), "set_flag", "get_flag", FLAG_FIXED_SIZE); @@ -1605,6 +1614,7 @@ void SpatialMaterial::_bind_methods() { BIND_CONSTANT(CULL_DISABLED); BIND_CONSTANT(FLAG_UNSHADED); + BIND_CONSTANT(FLAG_USE_VERTEX_LIGHTING); BIND_CONSTANT(FLAG_ONTOP); BIND_CONSTANT(FLAG_ALBEDO_FROM_VERTEX_COLOR); BIND_CONSTANT(FLAG_SRGB_VERTEX_COLOR) diff --git a/scene/resources/material.h b/scene/resources/material.h index 276064bce4..7587fc7927 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -155,6 +155,7 @@ public: enum Flags { FLAG_UNSHADED, + FLAG_USE_VERTEX_LIGHTING, FLAG_ONTOP, FLAG_ALBEDO_FROM_VERTEX_COLOR, FLAG_SRGB_VERTEX_COLOR, diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 414d0a6240..310ab5e371 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -32,7 +32,7 @@ #include "scene/resources/convex_polygon_shape.h" #include "surface_tool.h" -void Mesh::_clear_triangle_mesh() { +void Mesh::_clear_triangle_mesh() const { triangle_mesh.unref(); ; diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 4adb871e09..e40ef99237 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -44,7 +44,7 @@ class Mesh : public Resource { mutable Ref<TriangleMesh> triangle_mesh; //cached protected: - void _clear_triangle_mesh(); + void _clear_triangle_mesh() const; static void _bind_methods(); diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp index bf1b3d40be..5dc596abff 100644 --- a/scene/resources/mesh_data_tool.cpp +++ b/scene/resources/mesh_data_tool.cpp @@ -520,8 +520,8 @@ void MeshDataTool::set_material(const Ref<Material> &p_material) { void MeshDataTool::_bind_methods() { ClassDB::bind_method(D_METHOD("clear"), &MeshDataTool::clear); - ClassDB::bind_method(D_METHOD("create_from_surface", "mesh", "surface"), &MeshDataTool::create_from_surface); - ClassDB::bind_method(D_METHOD("commit_to_surface", "mesh"), &MeshDataTool::commit_to_surface); + ClassDB::bind_method(D_METHOD("create_from_surface", "mesh:ArrayMesh", "surface"), &MeshDataTool::create_from_surface); + ClassDB::bind_method(D_METHOD("commit_to_surface", "mesh:ArrayMesh"), &MeshDataTool::commit_to_surface); ClassDB::bind_method(D_METHOD("get_format"), &MeshDataTool::get_format); @@ -574,7 +574,7 @@ void MeshDataTool::_bind_methods() { ClassDB::bind_method(D_METHOD("get_face_normal", "idx"), &MeshDataTool::get_face_normal); ClassDB::bind_method(D_METHOD("set_material", "material:Material"), &MeshDataTool::set_material); - ClassDB::bind_method(D_METHOD("get_material", "material"), &MeshDataTool::get_material); + ClassDB::bind_method(D_METHOD("get_material:Material", "material"), &MeshDataTool::get_material); } MeshDataTool::MeshDataTool() { diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 1afaed2284..01a8342fed 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "packed_scene.h" #include "core/core_string_names.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" #include "scene/2d/node_2d.h" #include "scene/3d/spatial.h" diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 81cfd0e5f0..327de2f6f3 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -34,42 +34,44 @@ /** PrimitiveMesh */ -void PrimitiveMesh::_update() { - if (!cache_is_dirty) - return; +void PrimitiveMesh::_update() const { Array arr; arr.resize(VS::ARRAY_MAX); _create_mesh_array(arr); + PoolVector<Vector3> points = arr[VS::ARRAY_VERTEX]; + + aabb = Rect3(); + + int pc = points.size(); + ERR_FAIL_COND(pc == 0); + { + + PoolVector<Vector3>::Read r = points.read(); + for (int i = 0; i < pc; i++) { + if (i == 0) + aabb.position = r[i]; + else + aabb.expand_to(r[i]); + } + } + // in with the new VisualServer::get_singleton()->mesh_clear(mesh); VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh, (VisualServer::PrimitiveType)primitive_type, arr); VisualServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid()); - cache_is_dirty = false; + pending_request = false; _clear_triangle_mesh(); - emit_changed(); } -void PrimitiveMesh::_queue_update(bool p_first_mesh) { +void PrimitiveMesh::_request_update() { - if (first_mesh && p_first_mesh) { - first_mesh = false; - cache_is_dirty = true; - _update(); + if (pending_request) return; - } - - if (!cache_is_dirty) { - cache_is_dirty = true; - call_deferred("_update"); - } -} - -void PrimitiveMesh::set_aabb(Rect3 p_aabb) { - aabb = p_aabb; + _update(); } int PrimitiveMesh::get_surface_count() const { @@ -78,21 +80,37 @@ int PrimitiveMesh::get_surface_count() const { int PrimitiveMesh::surface_get_array_len(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, 1, -1); + if (pending_request) { + _update(); + } + return VisualServer::get_singleton()->mesh_surface_get_array_len(mesh, 0); } int PrimitiveMesh::surface_get_array_index_len(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, 1, -1); + if (pending_request) { + _update(); + } + return VisualServer::get_singleton()->mesh_surface_get_array_index_len(mesh, 0); } Array PrimitiveMesh::surface_get_arrays(int p_surface) const { ERR_FAIL_INDEX_V(p_surface, 1, Array()); + if (pending_request) { + _update(); + } + return VisualServer::get_singleton()->mesh_surface_get_arrays(mesh, 0); } uint32_t PrimitiveMesh::surface_get_format(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, 1, 0); + if (pending_request) { + _update(); + } + return VisualServer::get_singleton()->mesh_surface_get_format(mesh, 0); } @@ -113,10 +131,17 @@ StringName PrimitiveMesh::get_blend_shape_name(int p_index) const { } Rect3 PrimitiveMesh::get_aabb() const { + if (pending_request) { + _update(); + } + return aabb; } RID PrimitiveMesh::get_rid() const { + if (pending_request) { + _update(); + } return mesh; } @@ -131,10 +156,9 @@ void PrimitiveMesh::_bind_methods() { void PrimitiveMesh::set_material(const Ref<Material> &p_material) { material = p_material; - if (!cache_is_dirty) { + if (!pending_request) { // just apply it, else it'll happen when _update is called. VisualServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid()); - _change_notify(); emit_changed(); }; @@ -152,9 +176,7 @@ PrimitiveMesh::PrimitiveMesh() { primitive_type = Mesh::PRIMITIVE_TRIANGLES; // make sure we do an update after we've finished constructing our object - cache_is_dirty = false; - first_mesh = true; - _queue_update(); + pending_request = true; } PrimitiveMesh::~PrimitiveMesh() { @@ -165,7 +187,7 @@ PrimitiveMesh::~PrimitiveMesh() { CapsuleMesh */ -void CapsuleMesh::_create_mesh_array(Array &p_arr) { +void CapsuleMesh::_create_mesh_array(Array &p_arr) const { int i, j, prevrow, thisrow, point; float x, y, z, u, v, w; float onethird = 1.0 / 3.0; @@ -173,8 +195,6 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) { // note, this has been aligned with our collision shape but I've left the descriptions as top/middle/bottom - set_aabb(Rect3(Vector3(-radius, -radius, (mid_height * -0.5) - radius), Vector3(radius * 2.0, radius * 2.0, mid_height + (2.0 * radius)))); - PoolVector<Vector3> points; PoolVector<Vector3> normals; PoolVector<float> tangents; @@ -334,7 +354,7 @@ void CapsuleMesh::_bind_methods() { void CapsuleMesh::set_radius(const float p_radius) { radius = p_radius; - _queue_update(); + _request_update(); } float CapsuleMesh::get_radius() const { @@ -343,7 +363,7 @@ float CapsuleMesh::get_radius() const { void CapsuleMesh::set_mid_height(const float p_mid_height) { mid_height = p_mid_height; - _queue_update(); + _request_update(); } float CapsuleMesh::get_mid_height() const { @@ -352,7 +372,7 @@ float CapsuleMesh::get_mid_height() const { void CapsuleMesh::set_radial_segments(const int p_segments) { radial_segments = p_segments > 4 ? p_segments : 4; - _queue_update(); + _request_update(); } int CapsuleMesh::get_radial_segments() const { @@ -361,7 +381,7 @@ int CapsuleMesh::get_radial_segments() const { void CapsuleMesh::set_rings(const int p_rings) { rings = p_rings > 1 ? p_rings : 1; - _queue_update(true); //last property set, force update mesh + _request_update(); } int CapsuleMesh::get_rings() const { @@ -380,7 +400,7 @@ CapsuleMesh::CapsuleMesh() { CubeMesh */ -void CubeMesh::_create_mesh_array(Array &p_arr) { +void CubeMesh::_create_mesh_array(Array &p_arr) const { int i, j, prevrow, thisrow, point; float x, y, z; float onethird = 1.0 / 3.0; @@ -389,7 +409,6 @@ void CubeMesh::_create_mesh_array(Array &p_arr) { Vector3 start_pos = size * -0.5; // set our bounding box - set_aabb(Rect3(start_pos, size)); PoolVector<Vector3> points; PoolVector<Vector3> normals; @@ -592,7 +611,7 @@ void CubeMesh::_bind_methods() { void CubeMesh::set_size(const Vector3 &p_size) { size = p_size; - _queue_update(); + _request_update(); } Vector3 CubeMesh::get_size() const { @@ -601,7 +620,7 @@ Vector3 CubeMesh::get_size() const { void CubeMesh::set_subdivide_width(const int p_subdivide) { subdivide_w = p_subdivide > 0 ? p_subdivide : 0; - _queue_update(); + _request_update(); } int CubeMesh::get_subdivide_width() const { @@ -610,7 +629,7 @@ int CubeMesh::get_subdivide_width() const { void CubeMesh::set_subdivide_height(const int p_subdivide) { subdivide_h = p_subdivide > 0 ? p_subdivide : 0; - _queue_update(); + _request_update(); } int CubeMesh::get_subdivide_height() const { @@ -619,7 +638,7 @@ int CubeMesh::get_subdivide_height() const { void CubeMesh::set_subdivide_depth(const int p_subdivide) { subdivide_d = p_subdivide > 0 ? p_subdivide : 0; - _queue_update(true); //last property set, force update mesh + _request_update(); } int CubeMesh::get_subdivide_depth() const { @@ -638,14 +657,12 @@ CubeMesh::CubeMesh() { CylinderMesh */ -void CylinderMesh::_create_mesh_array(Array &p_arr) { +void CylinderMesh::_create_mesh_array(Array &p_arr) const { int i, j, prevrow, thisrow, point; float x, y, z, u, v, radius; radius = bottom_radius > top_radius ? bottom_radius : top_radius; - set_aabb(Rect3(Vector3(-radius, height * -0.5, -radius), Vector3(radius * 2.0, height, radius * 2.0))); - PoolVector<Vector3> points; PoolVector<Vector3> normals; PoolVector<float> tangents; @@ -800,7 +817,7 @@ void CylinderMesh::_bind_methods() { void CylinderMesh::set_top_radius(const float p_radius) { top_radius = p_radius; - _queue_update(); + _request_update(); } float CylinderMesh::get_top_radius() const { @@ -809,7 +826,7 @@ float CylinderMesh::get_top_radius() const { void CylinderMesh::set_bottom_radius(const float p_radius) { bottom_radius = p_radius; - _queue_update(); + _request_update(); } float CylinderMesh::get_bottom_radius() const { @@ -818,7 +835,7 @@ float CylinderMesh::get_bottom_radius() const { void CylinderMesh::set_height(const float p_height) { height = p_height; - _queue_update(); + _request_update(); } float CylinderMesh::get_height() const { @@ -827,7 +844,7 @@ float CylinderMesh::get_height() const { void CylinderMesh::set_radial_segments(const int p_segments) { radial_segments = p_segments > 4 ? p_segments : 4; - _queue_update(); + _request_update(); } int CylinderMesh::get_radial_segments() const { @@ -836,7 +853,7 @@ int CylinderMesh::get_radial_segments() const { void CylinderMesh::set_rings(const int p_rings) { rings = p_rings > 0 ? p_rings : 0; - _queue_update(true); //last property set, force update mesh + _request_update(); } int CylinderMesh::get_rings() const { @@ -856,14 +873,12 @@ CylinderMesh::CylinderMesh() { PlaneMesh */ -void PlaneMesh::_create_mesh_array(Array &p_arr) { +void PlaneMesh::_create_mesh_array(Array &p_arr) const { int i, j, prevrow, thisrow, point; float x, z; Size2 start_pos = size * -0.5; - set_aabb(Rect3(Vector3(start_pos.x, 0.0, start_pos.y), Vector3(size.x, 0.0, size.y))); - PoolVector<Vector3> points; PoolVector<Vector3> normals; PoolVector<float> tangents; @@ -935,7 +950,7 @@ void PlaneMesh::_bind_methods() { void PlaneMesh::set_size(const Size2 &p_size) { size = p_size; - _queue_update(); + _request_update(); } Size2 PlaneMesh::get_size() const { @@ -944,7 +959,7 @@ Size2 PlaneMesh::get_size() const { void PlaneMesh::set_subdivide_width(const int p_subdivide) { subdivide_w = p_subdivide > 0 ? p_subdivide : 0; - _queue_update(); + _request_update(); } int PlaneMesh::get_subdivide_width() const { @@ -953,7 +968,7 @@ int PlaneMesh::get_subdivide_width() const { void PlaneMesh::set_subdivide_depth(const int p_subdivide) { subdivide_d = p_subdivide > 0 ? p_subdivide : 0; - _queue_update(true); //last property set, force update mesh + _request_update(); } int PlaneMesh::get_subdivide_depth() const { @@ -971,7 +986,7 @@ PlaneMesh::PlaneMesh() { PrismMesh */ -void PrismMesh::_create_mesh_array(Array &p_arr) { +void PrismMesh::_create_mesh_array(Array &p_arr) const { int i, j, prevrow, thisrow, point; float x, y, z; float onethird = 1.0 / 3.0; @@ -980,7 +995,6 @@ void PrismMesh::_create_mesh_array(Array &p_arr) { Vector3 start_pos = size * -0.5; // set our bounding box - set_aabb(Rect3(start_pos, size)); PoolVector<Vector3> points; PoolVector<Vector3> normals; @@ -1207,7 +1221,7 @@ void PrismMesh::_bind_methods() { void PrismMesh::set_left_to_right(const float p_left_to_right) { left_to_right = p_left_to_right; - _queue_update(); + _request_update(); } float PrismMesh::get_left_to_right() const { @@ -1216,7 +1230,7 @@ float PrismMesh::get_left_to_right() const { void PrismMesh::set_size(const Vector3 &p_size) { size = p_size; - _queue_update(); + _request_update(); } Vector3 PrismMesh::get_size() const { @@ -1225,7 +1239,7 @@ Vector3 PrismMesh::get_size() const { void PrismMesh::set_subdivide_width(const int p_divisions) { subdivide_w = p_divisions > 0 ? p_divisions : 0; - _queue_update(); + _request_update(); } int PrismMesh::get_subdivide_width() const { @@ -1234,7 +1248,7 @@ int PrismMesh::get_subdivide_width() const { void PrismMesh::set_subdivide_height(const int p_divisions) { subdivide_h = p_divisions > 0 ? p_divisions : 0; - _queue_update(); + _request_update(); } int PrismMesh::get_subdivide_height() const { @@ -1243,7 +1257,7 @@ int PrismMesh::get_subdivide_height() const { void PrismMesh::set_subdivide_depth(const int p_divisions) { subdivide_d = p_divisions > 0 ? p_divisions : 0; - _queue_update(true); //last property set, force update mesh + _request_update(); } int PrismMesh::get_subdivide_depth() const { @@ -1263,7 +1277,7 @@ PrismMesh::PrismMesh() { QuadMesh */ -void QuadMesh::_create_mesh_array(Array &p_arr) { +void QuadMesh::_create_mesh_array(Array &p_arr) const { PoolVector<Vector3> faces; PoolVector<Vector3> normals; PoolVector<float> tangents; @@ -1312,19 +1326,17 @@ void QuadMesh::_bind_methods() { QuadMesh::QuadMesh() { primitive_type = PRIMITIVE_TRIANGLE_FAN; - _queue_update(true); } /** SphereMesh */ -void SphereMesh::_create_mesh_array(Array &p_arr) { +void SphereMesh::_create_mesh_array(Array &p_arr) const { int i, j, prevrow, thisrow, point; float x, y, z; // set our bounding box - set_aabb(Rect3(Vector3(-radius, height * -0.5, -radius), Vector3(radius * 2.0, height, radius * 2.0))); PoolVector<Vector3> points; PoolVector<Vector3> normals; @@ -1413,7 +1425,7 @@ void SphereMesh::_bind_methods() { void SphereMesh::set_radius(const float p_radius) { radius = p_radius; - _queue_update(); + _request_update(); } float SphereMesh::get_radius() const { @@ -1422,7 +1434,7 @@ float SphereMesh::get_radius() const { void SphereMesh::set_height(const float p_height) { height = p_height; - _queue_update(); + _request_update(); } float SphereMesh::get_height() const { @@ -1431,7 +1443,7 @@ float SphereMesh::get_height() const { void SphereMesh::set_radial_segments(const int p_radial_segments) { radial_segments = p_radial_segments > 4 ? p_radial_segments : 4; - _queue_update(); + _request_update(); } int SphereMesh::get_radial_segments() const { @@ -1440,7 +1452,7 @@ int SphereMesh::get_radial_segments() const { void SphereMesh::set_rings(const int p_rings) { rings = p_rings > 1 ? p_rings : 1; - _queue_update(); + _request_update(); } int SphereMesh::get_rings() const { @@ -1449,7 +1461,7 @@ int SphereMesh::get_rings() const { void SphereMesh::set_is_hemisphere(const bool p_is_hemisphere) { is_hemisphere = p_is_hemisphere; - _queue_update(true); //last property set, force update mesh + _request_update(); } bool SphereMesh::get_is_hemisphere() const { diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 5e1387e864..bcd5d30dd3 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -47,23 +47,20 @@ class PrimitiveMesh : public Mesh { private: RID mesh; - Rect3 aabb; + mutable Rect3 aabb; Ref<Material> material; - bool first_mesh; - bool cache_is_dirty; - void _update(); + mutable bool pending_request; + void _update() const; protected: Mesh::PrimitiveType primitive_type; static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr) = 0; - void _queue_update(bool p_first_mesh = false); //pretty bad hack to have the mesh built firt time parameters are set without delay - - void set_aabb(Rect3 p_aabb); + virtual void _create_mesh_array(Array &p_arr) const = 0; + void _request_update(); public: virtual int get_surface_count() const; @@ -99,7 +96,7 @@ private: protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr); + virtual void _create_mesh_array(Array &p_arr) const; public: void set_radius(const float p_radius); @@ -132,7 +129,7 @@ private: protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr); + virtual void _create_mesh_array(Array &p_arr) const; public: void set_size(const Vector3 &p_size); @@ -167,7 +164,7 @@ private: protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr); + virtual void _create_mesh_array(Array &p_arr) const; public: void set_top_radius(const float p_radius); @@ -202,7 +199,7 @@ private: protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr); + virtual void _create_mesh_array(Array &p_arr) const; public: void set_size(const Size2 &p_size); @@ -233,7 +230,7 @@ private: protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr); + virtual void _create_mesh_array(Array &p_arr) const; public: void set_left_to_right(const float p_left_to_right); @@ -267,7 +264,7 @@ private: protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr); + virtual void _create_mesh_array(Array &p_arr) const; public: QuadMesh(); @@ -289,7 +286,7 @@ private: protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr); + virtual void _create_mesh_array(Array &p_arr) const; public: void set_radius(const float p_radius); diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp index 8ad2970005..585579aad5 100644 --- a/scene/resources/scene_format_text.cpp +++ b/scene/resources/scene_format_text.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "scene_format_text.h" -#include "global_config.h" +#include "project_settings.h" #include "os/dir_access.h" #include "version.h" @@ -110,7 +110,7 @@ Error ResourceInteractiveLoaderText::_parse_ext_resource(VariantParser::Stream * if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path - path = GlobalConfig::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); + path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); } r_res = ResourceLoader::load(path, type); @@ -165,7 +165,7 @@ Error ResourceInteractiveLoaderText::poll() { if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path - path = GlobalConfig::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); + path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); } if (remaps.has(path)) { @@ -648,7 +648,7 @@ void ResourceInteractiveLoaderText::get_dependencies(FileAccess *f, List<String> if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path - path = GlobalConfig::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); + path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); } if (p_add_types) { @@ -905,9 +905,9 @@ Ref<ResourceInteractiveLoader> ResourceFormatLoaderText::load_interactive(const } Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); - ria->local_path = GlobalConfig::get_singleton()->localize_path(p_path); + ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); ria->res_path = ria->local_path; - //ria->set_local_path( GlobalConfig::get_singleton()->localize_path(p_path) ); + //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); ria->open(f); return ria; @@ -953,9 +953,9 @@ String ResourceFormatLoaderText::get_resource_type(const String &p_path) const { } Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); - ria->local_path = GlobalConfig::get_singleton()->localize_path(p_path); + ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); ria->res_path = ria->local_path; - //ria->set_local_path( GlobalConfig::get_singleton()->localize_path(p_path) ); + //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); String r = ria->recognize(f); return r; } @@ -969,9 +969,9 @@ void ResourceFormatLoaderText::get_dependencies(const String &p_path, List<Strin } Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); - ria->local_path = GlobalConfig::get_singleton()->localize_path(p_path); + ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); ria->res_path = ria->local_path; - //ria->set_local_path( GlobalConfig::get_singleton()->localize_path(p_path) ); + //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); ria->get_dependencies(f, p_dependencies, p_add_types); } @@ -984,9 +984,9 @@ Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const } Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); - ria->local_path = GlobalConfig::get_singleton()->localize_path(p_path); + ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); ria->res_path = ria->local_path; - //ria->set_local_path( GlobalConfig::get_singleton()->localize_path(p_path) ); + //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); return ria->rename_dependencies(f, p_path, p_map); } @@ -1118,7 +1118,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r ERR_FAIL_COND_V(err, ERR_CANT_OPEN); FileAccessRef _fref(f); - local_path = GlobalConfig::get_singleton()->localize_path(p_path); + local_path = ProjectSettings::get_singleton()->localize_path(p_path); relative_paths = p_flags & ResourceSaver::FLAG_RELATIVE_PATHS; skip_editor = p_flags & ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES; diff --git a/scene/resources/sky_box.cpp b/scene/resources/sky_box.cpp index c373ad67ee..b1ca72571e 100644 --- a/scene/resources/sky_box.cpp +++ b/scene/resources/sky_box.cpp @@ -47,8 +47,11 @@ void Sky::_bind_methods() { ClassDB::bind_method(D_METHOD("set_radiance_size", "size"), &Sky::set_radiance_size); ClassDB::bind_method(D_METHOD("get_radiance_size"), &Sky::get_radiance_size); - ADD_PROPERTY(PropertyInfo(Variant::INT, "radiance_size", PROPERTY_HINT_ENUM, "256,512,1024,2048"), "set_radiance_size", "get_radiance_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "radiance_size", PROPERTY_HINT_ENUM, "32,64,128,256,512,1024,2048"), "set_radiance_size", "get_radiance_size"); + BIND_CONSTANT(RADIANCE_SIZE_32); + BIND_CONSTANT(RADIANCE_SIZE_64); + BIND_CONSTANT(RADIANCE_SIZE_128); BIND_CONSTANT(RADIANCE_SIZE_256); BIND_CONSTANT(RADIANCE_SIZE_512); BIND_CONSTANT(RADIANCE_SIZE_1024); @@ -66,7 +69,7 @@ void PanoramaSky::_radiance_changed() { if (panorama.is_valid()) { static const int size[RADIANCE_SIZE_MAX] = { - 256, 512, 1024, 2048 + 32, 64, 128, 256, 512, 1024, 2048 }; VS::get_singleton()->sky_set_texture(sky, panorama->get_rid(), size[get_radiance_size()]); } @@ -120,7 +123,7 @@ void ProceduralSky::_radiance_changed() { return; //do nothing yet static const int size[RADIANCE_SIZE_MAX] = { - 256, 512, 1024, 2048 + 32, 64, 128, 256, 512, 1024, 2048 }; VS::get_singleton()->sky_set_texture(sky, texture, size[get_radiance_size()]); } @@ -132,7 +135,7 @@ void ProceduralSky::_update_sky() { PoolVector<uint8_t> imgdata; static const int size[TEXTURE_SIZE_MAX] = { - 1024, 2048, 4096 + 256, 512, 1024, 2048, 4096 }; int w = size[texture_size]; @@ -465,7 +468,14 @@ void ProceduralSky::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sun_energy", "get_sun_energy"); ADD_GROUP("Texture", "texture_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_size", PROPERTY_HINT_ENUM, "1024,2048,4096"), "set_texture_size", "get_texture_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_size", PROPERTY_HINT_ENUM, "256,512,1024,2048,4096"), "set_texture_size", "get_texture_size"); + + BIND_CONSTANT(TEXTURE_SIZE_256); + BIND_CONSTANT(TEXTURE_SIZE_512); + BIND_CONSTANT(TEXTURE_SIZE_1024); + BIND_CONSTANT(TEXTURE_SIZE_2048); + BIND_CONSTANT(TEXTURE_SIZE_4096); + BIND_CONSTANT(TEXTURE_SIZE_MAX); } ProceduralSky::ProceduralSky() { diff --git a/scene/resources/sky_box.h b/scene/resources/sky_box.h index 7b707af3a6..8298d1b3c0 100644 --- a/scene/resources/sky_box.h +++ b/scene/resources/sky_box.h @@ -37,6 +37,9 @@ class Sky : public Resource { public: enum RadianceSize { + RADIANCE_SIZE_32, + RADIANCE_SIZE_64, + RADIANCE_SIZE_128, RADIANCE_SIZE_256, RADIANCE_SIZE_512, RADIANCE_SIZE_1024, @@ -85,6 +88,8 @@ class ProceduralSky : public Sky { public: enum TextureSize { + TEXTURE_SIZE_256, + TEXTURE_SIZE_512, TEXTURE_SIZE_1024, TEXTURE_SIZE_2048, TEXTURE_SIZE_4096, diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 2714ffec10..e0a9de6062 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -437,3 +437,81 @@ StyleBoxFlat::StyleBoxFlat() { } StyleBoxFlat::~StyleBoxFlat() { } + +void StyleBoxLine::set_color(const Color &p_color) { + color = p_color; + emit_changed(); +} +Color StyleBoxLine::get_color() const { + return color; +} + +void StyleBoxLine::set_thickness(int p_thickness) { + thickness = p_thickness; + emit_changed(); +} +int StyleBoxLine::get_thickness() const { + return thickness; +} + +void StyleBoxLine::set_vertical(bool p_vertical) { + vertical = p_vertical; +} +bool StyleBoxLine::is_vertical() const { + return vertical; +} + +void StyleBoxLine::set_grow(float p_grow) { + grow = p_grow; + emit_changed(); +} +float StyleBoxLine::get_grow() const { + return grow; +} + +void StyleBoxLine::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_color", "color"), &StyleBoxLine::set_color); + ClassDB::bind_method(D_METHOD("get_color"), &StyleBoxLine::get_color); + ClassDB::bind_method(D_METHOD("set_thickness", "thickness"), &StyleBoxLine::set_thickness); + ClassDB::bind_method(D_METHOD("get_thickness"), &StyleBoxLine::get_thickness); + ClassDB::bind_method(D_METHOD("set_grow", "grow"), &StyleBoxLine::set_grow); + ClassDB::bind_method(D_METHOD("get_grow"), &StyleBoxLine::get_grow); + ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &StyleBoxLine::set_vertical); + ClassDB::bind_method(D_METHOD("is_vertical"), &StyleBoxLine::is_vertical); + + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "thickness", PROPERTY_HINT_RANGE, "0,10"), "set_thickness", "get_thickness"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical"); +} +float StyleBoxLine::get_style_margin(Margin p_margin) const { + return thickness; +} +Size2 StyleBoxLine::get_center_size() const { + return Size2(); +} + +void StyleBoxLine::draw(RID p_canvas_item, const Rect2 &p_rect) const { + VisualServer *vs = VisualServer::get_singleton(); + Rect2i r = p_rect; + + if (vertical) { + r.position.y -= grow; + r.size.y += grow * 2; + r.size.x = thickness; + } else { + r.position.x -= grow; + r.size.x += grow * 2; + r.size.y = thickness; + } + + vs->canvas_item_add_rect(p_canvas_item, r, color); +} + +StyleBoxLine::StyleBoxLine() { + grow = 1.0; + thickness = 1; + color = Color(0.0, 0.0, 0.0); + vertical = false; +} +StyleBoxLine::~StyleBoxLine() {} diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index 7547c2ea81..64ce3528aa 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -164,4 +164,38 @@ public: ~StyleBoxFlat(); }; +// just used to draw lines. +class StyleBoxLine : public StyleBox { + + GDCLASS(StyleBoxLine, StyleBox); + Color color; + int thickness; + bool vertical; + float grow; + +protected: + virtual float get_style_margin(Margin p_margin) const; + static void _bind_methods(); + +public: + void set_color(const Color &p_color); + Color get_color() const; + + void set_thickness(int p_thickness); + int get_thickness() const; + + void set_vertical(bool p_vertical); + bool is_vertical() const; + + void set_grow(float p_grow); + float get_grow() const; + + virtual Size2 get_center_size() const; + + virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const; + + StyleBoxLine(); + ~StyleBoxLine(); +}; + #endif diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 171826cb2f..5cd75b5a69 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -1323,8 +1323,8 @@ void CubeMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_flags", "flags"), &CubeMap::set_flags); ClassDB::bind_method(D_METHOD("get_flags"), &CubeMap::get_flags); - ClassDB::bind_method(D_METHOD("set_side", "side", "image"), &CubeMap::set_side); - ClassDB::bind_method(D_METHOD("get_side", "side"), &CubeMap::get_side); + ClassDB::bind_method(D_METHOD("set_side", "side", "image:Image"), &CubeMap::set_side); + ClassDB::bind_method(D_METHOD("get_side:Image", "side"), &CubeMap::get_side); ClassDB::bind_method(D_METHOD("set_storage", "mode"), &CubeMap::set_storage); ClassDB::bind_method(D_METHOD("get_storage"), &CubeMap::get_storage); ClassDB::bind_method(D_METHOD("set_lossy_storage_quality", "quality"), &CubeMap::set_lossy_storage_quality); diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index faf9f31b43..d5c68457d0 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -660,8 +660,8 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_constant", "name", "type"), &Theme::clear_constant); ClassDB::bind_method(D_METHOD("get_constant_list", "type"), &Theme::_get_constant_list); - ClassDB::bind_method(D_METHOD("set_default_font", "font"), &Theme::set_default_theme_font); - ClassDB::bind_method(D_METHOD("get_default_font"), &Theme::get_default_theme_font); + ClassDB::bind_method(D_METHOD("set_default_font", "font:Font"), &Theme::set_default_theme_font); + ClassDB::bind_method(D_METHOD("get_default_font:Font"), &Theme::get_default_theme_font); ClassDB::bind_method(D_METHOD("get_type_list", "type"), &Theme::_get_type_list); diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index 9ec89e4003..056c49f1ae 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -31,7 +31,7 @@ #include "servers/physics_2d_server.h" #include "servers/visual_server.h" //#include "servers/spatial_sound_2d_server.h" -#include "global_config.h" +#include "project_settings.h" #include "scene/2d/camera_2d.h" #include "scene/2d/visibility_notifier_2d.h" #include "scene/main/viewport.h" diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h index 35c8ce390f..f968b08a15 100644 --- a/scene/resources/world_2d.h +++ b/scene/resources/world_2d.h @@ -30,7 +30,7 @@ #ifndef WORLD_2D_H #define WORLD_2D_H -#include "global_config.h" +#include "project_settings.h" #include "resource.h" #include "servers/physics_2d_server.h" diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp index 3aaf73df03..0f15b43b41 100644 --- a/servers/audio/audio_driver_dummy.cpp +++ b/servers/audio/audio_driver_dummy.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "audio_driver_dummy.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" Error AudioDriverDummy::init() { diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 43f1175c79..5303aea6d0 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -28,10 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "audio_server.h" -#include "global_config.h" #include "io/resource_loader.h" #include "os/file_access.h" #include "os/os.h" +#include "project_settings.h" #include "servers/audio/effects/audio_effect_compressor.h" #ifdef TOOLS_ENABLED @@ -984,10 +984,10 @@ void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bus_bypass_effects", "bus_idx", "enable"), &AudioServer::set_bus_bypass_effects); ClassDB::bind_method(D_METHOD("is_bus_bypassing_effects", "bus_idx"), &AudioServer::is_bus_bypassing_effects); - ClassDB::bind_method(D_METHOD("add_bus_effect", "bus_idx", "effect:AudioEffect"), &AudioServer::add_bus_effect, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_bus_effect", "bus_idx", "effect:AudioEffect", "at_pos"), &AudioServer::add_bus_effect, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("remove_bus_effect", "bus_idx", "effect_idx"), &AudioServer::remove_bus_effect); - ClassDB::bind_method(D_METHOD("get_bus_effect_count", "bus_idx"), &AudioServer::add_bus_effect); + ClassDB::bind_method(D_METHOD("get_bus_effect_count", "bus_idx"), &AudioServer::get_bus_effect_count); ClassDB::bind_method(D_METHOD("get_bus_effect:AudioEffect", "bus_idx", "effect_idx"), &AudioServer::get_bus_effect); ClassDB::bind_method(D_METHOD("swap_bus_effects", "bus_idx", "effect_idx", "by_effect_idx"), &AudioServer::swap_bus_effects); diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp index 2d71fd6061..5679fc8f60 100644 --- a/servers/physics/space_sw.cpp +++ b/servers/physics/space_sw.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "space_sw.h" #include "collision_solver_sw.h" -#include "global_config.h" #include "physics_server_sw.h" +#include "project_settings.h" _FORCE_INLINE_ static bool _match_object_type_query(CollisionObjectSW *p_object, uint32_t p_collision_layer, uint32_t p_type_mask) { diff --git a/servers/physics/space_sw.h b/servers/physics/space_sw.h index 6ef12dbeae..dc7799d992 100644 --- a/servers/physics/space_sw.h +++ b/servers/physics/space_sw.h @@ -36,8 +36,8 @@ #include "body_sw.h" #include "broad_phase_sw.h" #include "collision_object_sw.h" -#include "global_config.h" #include "hash_map.h" +#include "project_settings.h" #include "typedefs.h" class PhysicsDirectSpaceStateSW : public PhysicsDirectSpaceState { diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp index 29f3396a1d..5b6c7e2f38 100644 --- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp +++ b/servers/physics_2d/broad_phase_2d_hash_grid.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "broad_phase_2d_hash_grid.h" -#include "global_config.h" +#include "project_settings.h" #define LARGE_ELEMENT_FI 1.01239812 diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index fe016d4d0c..c20d0d14a2 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -31,8 +31,8 @@ #include "broad_phase_2d_basic.h" #include "broad_phase_2d_hash_grid.h" #include "collision_solver_2d_sw.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" #include "script_language.h" RID Physics2DServerSW::shape_create(ShapeType p_shape) { @@ -1264,7 +1264,7 @@ Physics2DServerSW::Physics2DServerSW() { island_count = 0; active_objects = 0; collision_pairs = 0; - using_threads = int(GlobalConfig::get_singleton()->get("physics/2d/thread_model")) == 2; + using_threads = int(ProjectSettings::get_singleton()->get("physics/2d/thread_model")) == 2; }; Physics2DServerSW::~Physics2DServerSW(){ diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h index ac9066582e..8b6609d119 100644 --- a/servers/physics_2d/physics_2d_server_wrap_mt.h +++ b/servers/physics_2d/physics_2d_server_wrap_mt.h @@ -31,8 +31,8 @@ #define PHYSICS2DSERVERWRAPMT_H #include "command_queue_mt.h" -#include "global_config.h" #include "os/thread.h" +#include "project_settings.h" #include "servers/physics_2d_server.h" #ifdef DEBUG_SYNC diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index c407a17bc6..a17d1f6a12 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -553,7 +553,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co const CollisionObject2DSW *col_obj = intersection_query_results[i]; int shape_idx = intersection_query_subindex_results[i]; - if (col_obj->is_shape_set_as_one_way_collision(j)) { + if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { cbk.valid_dir = body_shape_xform.get_axis(1).normalized(); cbk.valid_depth = p_margin; //only valid depth is the collision margin diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index a28233a4a6..4bd81c054f 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -36,8 +36,8 @@ #include "body_pair_2d_sw.h" #include "broad_phase_2d_sw.h" #include "collision_object_2d_sw.h" -#include "global_config.h" #include "hash_map.h" +#include "project_settings.h" #include "typedefs.h" class Physics2DDirectSpaceStateSW : public Physics2DDirectSpaceState { diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 8ee431cc68..c5029d1e13 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "register_server_types.h" -#include "global_config.h" +#include "project_settings.h" #include "audio/audio_effect.h" #include "audio/audio_stream.h" @@ -73,10 +73,10 @@ ShaderTypes *shader_types = NULL; void register_server_types() { - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("VisualServer", VisualServer::get_singleton())); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("AudioServer", AudioServer::get_singleton())); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("PhysicsServer", PhysicsServer::get_singleton())); - GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("Physics2DServer", Physics2DServer::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("VisualServer", VisualServer::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("AudioServer", AudioServer::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("PhysicsServer", PhysicsServer::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("Physics2DServer", Physics2DServer::get_singleton())); shader_types = memnew(ShaderTypes); diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index 599a6419a7..3de0841f2a 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -66,6 +66,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["POINT_SIZE"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["INSTANCE_ID"] = ShaderLanguage::TYPE_INT; shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["INSTANCE_CUSTOM"] = ShaderLanguage::TYPE_VEC4; + shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT; //builtins shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4; @@ -147,6 +148,8 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].modes.insert("skip_vertex_transform"); shader_modes[VS::SHADER_SPATIAL].modes.insert("world_vertex_coords"); + shader_modes[VS::SHADER_SPATIAL].modes.insert("vertex_lighting"); + /************ CANVAS ITEM **************************/ shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["SRC_VERTEX"] = ShaderLanguage::TYPE_VEC2; diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 8d332b3e6c..f17411f11a 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -29,9 +29,9 @@ /*************************************************************************/ #include "visual_server_raster.h" #include "default_mouse_cursor.xpm" -#include "global_config.h" #include "io/marshalls.h" #include "os/os.h" +#include "project_settings.h" #include "sort.h" #include "visual_server_canvas.h" #include "visual_server_global.h" diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index d13c24ae24..168dfddfd4 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -36,7 +36,6 @@ #include "geometry.h" #include "octree.h" #include "os/semaphore.h" -#include "os/semaphore.h" #include "os/thread.h" #include "self_list.h" diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 4d53181b43..2a37b64759 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "visual_server_viewport.h" -#include "global_config.h" +#include "project_settings.h" #include "visual_server_canvas.h" #include "visual_server_global.h" #include "visual_server_scene.h" diff --git a/servers/visual/visual_server_wrap_mt.cpp b/servers/visual/visual_server_wrap_mt.cpp index a358e99fb3..525e3dc2f9 100644 --- a/servers/visual/visual_server_wrap_mt.cpp +++ b/servers/visual/visual_server_wrap_mt.cpp @@ -27,8 +27,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "visual_server_wrap_mt.h" -#include "global_config.h" #include "os/os.h" +#include "project_settings.h" void VisualServerWrapMT::thread_exit() { diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 1e217649ba..080e538cbf 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "visual_server.h" -#include "global_config.h" #include "method_bind_ext.gen.inc" +#include "project_settings.h" VisualServer *VisualServer::singleton = NULL; VisualServer *(*VisualServer::create_func)() = NULL; @@ -1475,14 +1475,14 @@ Array VisualServer::mesh_surface_get_arrays(RID p_mesh, int p_surface) const { void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_create"), &VisualServer::texture_create); - ClassDB::bind_method(D_METHOD("texture_create_from_image"), &VisualServer::texture_create_from_image, DEFVAL(TEXTURE_FLAGS_DEFAULT)); + ClassDB::bind_method(D_METHOD("texture_create_from_image", "image:Image", "flags"), &VisualServer::texture_create_from_image, DEFVAL(TEXTURE_FLAGS_DEFAULT)); //ClassDB::bind_method(D_METHOD("texture_allocate"),&VisualServer::texture_allocate,DEFVAL( TEXTURE_FLAGS_DEFAULT ) ); //ClassDB::bind_method(D_METHOD("texture_set_data"),&VisualServer::texture_blit_rect,DEFVAL( CUBEMAP_LEFT ) ); //ClassDB::bind_method(D_METHOD("texture_get_rect"),&VisualServer::texture_get_rect ); - ClassDB::bind_method(D_METHOD("texture_set_flags"), &VisualServer::texture_set_flags); - ClassDB::bind_method(D_METHOD("texture_get_flags"), &VisualServer::texture_get_flags); - ClassDB::bind_method(D_METHOD("texture_get_width"), &VisualServer::texture_get_width); - ClassDB::bind_method(D_METHOD("texture_get_height"), &VisualServer::texture_get_height); + ClassDB::bind_method(D_METHOD("texture_set_flags", "texture"), &VisualServer::texture_set_flags); + ClassDB::bind_method(D_METHOD("texture_get_flags", "texture", "flags"), &VisualServer::texture_get_flags); + ClassDB::bind_method(D_METHOD("texture_get_width", "texture"), &VisualServer::texture_get_width); + ClassDB::bind_method(D_METHOD("texture_get_height", "texture"), &VisualServer::texture_get_height); ClassDB::bind_method(D_METHOD("texture_set_shrink_all_x2_on_set_data", "shrink"), &VisualServer::texture_set_shrink_all_x2_on_set_data); } @@ -1573,16 +1573,33 @@ VisualServer::VisualServer() { GLOBAL_DEF("rendering/vram_compression/import_pvrtc", false); GLOBAL_DEF("rendering/quality/directional_shadow/size", 4096); + GLOBAL_DEF("rendering/quality/directional_shadow/size.mobile", 2048); GLOBAL_DEF("rendering/quality/shadow_atlas/size", 4096); - GlobalConfig::get_singleton()->set_custom_property_info("rendering/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384")); + GLOBAL_DEF("rendering/quality/shadow_atlas/size.mobile", 2048); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384")); GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_0_subdiv", 1); GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_1_subdiv", 2); GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_2_subdiv", 3); GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_3_subdiv", 4); - GlobalConfig::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - GlobalConfig::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - GlobalConfig::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - GlobalConfig::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + + GLOBAL_DEF("rendering/quality/shadows/filter_mode", 1); + GLOBAL_DEF("rendering/quality/shadows/filter_mode.mobile", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadows/filter_mode", PropertyInfo(Variant::INT, "rendering/quality/shadows/filter_mode", PROPERTY_HINT_ENUM, "Disabled,PCF5,PCF13")); + + GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections", true); + GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections.mobile", false); + GLOBAL_DEF("rendering/quality/reflections/high_quality_ggx", true); + GLOBAL_DEF("rendering/quality/reflections/high_quality_ggx.mobile", false); + + GLOBAL_DEF("rendering/quality/shading/force_vertex_shading", false); + GLOBAL_DEF("rendering/quality/shading/force_vertex_shading.mobile", true); + + GLOBAL_DEF("rendering/quality/depth_prepass/enable", true); + GLOBAL_DEF("rendering/quality/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno"); } VisualServer::~VisualServer() { diff --git a/thirdparty/README.md b/thirdparty/README.md index 0067f0ff26..4ed17168e8 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -107,7 +107,7 @@ Files extracted from upstream source: ## libpng - Upstream: http://libpng.org/pub/png/libpng.html -- Version: 1.6.30 +- Version: 1.6.31rc01 - License: libpng/zlib Files extracted from upstream source: @@ -371,7 +371,7 @@ Files extracted from upstream source: ## zstd - Upstream: https://github.com/facebook/zstd -- Version: 1.2.0 +- Version: 1.3.0 - License: BSD-3-Clause Files extracted from upstream source: diff --git a/thirdparty/libpng/arm/filter_neon.S b/thirdparty/libpng/arm/filter_neon.S index 3b061d6bbf..09267c6030 100644 --- a/thirdparty/libpng/arm/filter_neon.S +++ b/thirdparty/libpng/arm/filter_neon.S @@ -1,9 +1,9 @@ /* filter_neon.S - NEON optimised filter functions * - * Copyright (c) 2014 Glenn Randers-Pehrson + * Copyright (c) 2014,2017 Glenn Randers-Pehrson * Written by Mans Rullgard, 2011. - * Last changed in libpng 1.6.16 [December 22, 2014] + * Last changed in libpng 1.6.31 [(PENDING RELEASE)] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -16,7 +16,7 @@ #define PNG_VERSION_INFO_ONLY #include "../pngpriv.h" -#if defined(__linux__) && defined(__ELF__) +#if (defined(__linux__) || defined(__FreeBSD__)) && defined(__ELF__) .section .note.GNU-stack,"",%progbits /* mark stack as non-executable */ #endif diff --git a/thirdparty/libpng/png.c b/thirdparty/libpng/png.c index 40688be123..87fda0b306 100644 --- a/thirdparty/libpng/png.c +++ b/thirdparty/libpng/png.c @@ -1,7 +1,7 @@ /* png.c - location for general purpose libpng functions * - * Last changed in libpng 1.6.30 [(PENDING RELEASE)] + * Last changed in libpng 1.6.31 [(PENDING RELEASE)] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -14,7 +14,27 @@ #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_6_30 Your_png_h_is_not_version_1_6_30; +typedef png_libpng_version_1_6_31rc01 Your_png_h_is_not_version_1_6_31rc01; + +#ifdef __GNUC__ +/* The version tests may need to be added to, but the problem warning has + * consistently been fixed in GCC versions which obtain wide-spread release. + * The problem is that many versions of GCC rearrange comparison expressions in + * the optimizer in such a way that the results of the comparison will change + * if signed integer overflow occurs. Such comparisons are not permitted in + * ANSI C90, however GCC isn't clever enough to work out that that do not occur + * below in png_ascii_from_fp and png_muldiv, so it produces a warning with + * -Wextra. Unfortunately this is highly dependent on the optimizer and the + * machine architecture so the warning comes and goes unpredictably and is + * impossible to "fix", even were that a good idea. + */ +#if __GNUC__ == 7 && __GNUC_MINOR__ == 1 +#define GCC_STRICT_OVERFLOW 1 +#endif /* GNU 7.1.x */ +#endif /* GNU */ +#ifndef GCC_STRICT_OVERFLOW +#define GCC_STRICT_OVERFLOW 0 +#endif /* Tells libpng that we have already handled the first "num_bytes" bytes * of the PNG file signature. If the PNG data is embedded into another @@ -595,6 +615,16 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, } #endif +#ifdef PNG_eXIf_SUPPORTED + /* Free any eXIf entry */ + if (((mask & PNG_FREE_EXIF) & info_ptr->free_me) != 0) + { + png_free(png_ptr, info_ptr->exif); + info_ptr->exif = NULL; + info_ptr->valid &= ~PNG_INFO_eXIf; + } +#endif + #ifdef PNG_hIST_SUPPORTED /* Free any hIST entry */ if (((mask & PNG_FREE_HIST) & info_ptr->free_me) != 0) @@ -776,14 +806,14 @@ png_get_copyright(png_const_structrp png_ptr) #else # ifdef __STDC__ return PNG_STRING_NEWLINE \ - "libpng version 1.6.30 - June 28, 2017" PNG_STRING_NEWLINE \ + "libpng version 1.6.31rc01 - July 19, 2017" PNG_STRING_NEWLINE \ "Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson" \ PNG_STRING_NEWLINE \ "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ PNG_STRING_NEWLINE; # else - return "libpng version 1.6.30 - June 28, 2017\ + return "libpng version 1.6.31rc01 - July 19, 2017\ Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson\ Copyright (c) 1996-1997 Andreas Dilger\ Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."; @@ -2857,6 +2887,14 @@ png_pow10(int power) /* Function to format a floating point value in ASCII with a given * precision. */ +#if GCC_STRICT_OVERFLOW +#pragma GCC diagnostic push +/* The problem arises below with exp_b10, which can never overflow because it + * comes, originally, from frexp and is therefore limited to a range which is + * typically +/-710 (log2(DBL_MAX)/log2(DBL_MIN)). + */ +#pragma GCC diagnostic warning "-Wstrict-overflow=2" +#endif /* GCC_STRICT_OVERFLOW */ void /* PRIVATE */ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, double fp, unsigned int precision) @@ -2946,7 +2984,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, */ if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */ { - czero = (unsigned int)(-exp_b10); /* PLUS 2 digits: TOTAL 3 */ + czero = 0U-exp_b10; /* PLUS 2 digits: TOTAL 3 */ exp_b10 = 0; /* Dot added below before first output. */ } else @@ -3087,7 +3125,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, /* Check for an exponent, if we don't need one we are * done and just need to terminate the string. At - * this point exp_b10==(-1) is effectively if flag - it got + * this point exp_b10==(-1) is effectively a flag - it got * to '-1' because of the decrement after outputting * the decimal point above (the exponent required is * *not* -1!) @@ -3101,7 +3139,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, * zeros were *not* output, so this doesn't increase * the output count. */ - while (--exp_b10 >= 0) *ascii++ = 48; + while (exp_b10-- > 0) *ascii++ = 48; *ascii = 0; @@ -3131,11 +3169,11 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, if (exp_b10 < 0) { *ascii++ = 45; --size; /* '-': PLUS 1 TOTAL 3+precision */ - uexp_b10 = (unsigned int)(-exp_b10); + uexp_b10 = 0U-exp_b10; } else - uexp_b10 = (unsigned int)exp_b10; + uexp_b10 = 0U+exp_b10; cdigits = 0; @@ -3178,6 +3216,9 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, /* Here on buffer too small. */ png_error(png_ptr, "ASCII conversion buffer too small"); } +#if GCC_STRICT_OVERFLOW +#pragma GCC diagnostic pop +#endif /* GCC_STRICT_OVERFLOW */ # endif /* FLOATING_POINT */ @@ -3291,6 +3332,15 @@ png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text) * the nearest .00001). Overflow and divide by zero are signalled in * the result, a boolean - true on success, false on overflow. */ +#if GCC_STRICT_OVERFLOW /* from above */ +/* It is not obvious which comparison below gets optimized in such a way that + * signed overflow would change the result; looking through the code does not + * reveal any tests which have the form GCC complains about, so presumably the + * optimizer is moving an add or subtract into the 'if' somewhere. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic warning "-Wstrict-overflow=2" +#endif /* GCC_STRICT_OVERFLOW */ int png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, png_int_32 divisor) @@ -3405,6 +3455,9 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, return 0; } +#if GCC_STRICT_OVERFLOW +#pragma GCC diagnostic pop +#endif /* GCC_STRICT_OVERFLOW */ #endif /* READ_GAMMA || INCH_CONVERSIONS */ #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) diff --git a/thirdparty/libpng/png.h b/thirdparty/libpng/png.h index c2c4fdf251..80ecc82c3a 100644 --- a/thirdparty/libpng/png.h +++ b/thirdparty/libpng/png.h @@ -1,7 +1,7 @@ /* png.h - header file for PNG reference library * - * libpng version 1.6.30, June 28, 2017 + * libpng version 1.6.31rc01, July 19, 2017 * * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) @@ -12,7 +12,7 @@ * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat * libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.6.30, June 28, 2017: + * libpng versions 0.97, January 1998, through 1.6.31rc01, July 19, 2017: * Glenn Randers-Pehrson. * See also "Contributing Authors", below. */ @@ -25,7 +25,7 @@ * * This code is released under the libpng license. * - * libpng versions 1.0.7, July 1, 2000 through 1.6.30, June 28, 2017 are + * libpng versions 1.0.7, July 1, 2000 through 1.6.31rc01, July 19, 2017 are * Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson, are * derived from libpng-1.0.6, and are distributed according to the same * disclaimer and license as libpng-1.0.6 with the following individuals @@ -213,7 +213,7 @@ * ... * 1.5.28 15 10527 15.so.15.28[.0] * ... - * 1.6.30 16 10630 16.so.16.30[.0] + * 1.6.31 16 10631 16.so.16.31[.0] * * Henceforth the source version will match the shared-library major * and minor numbers; the shared-library major version number will be @@ -241,13 +241,13 @@ * Y2K compliance in libpng: * ========================= * - * June 28, 2017 + * July 19, 2017 * * Since the PNG Development group is an ad-hoc body, we can't make * an official declaration. * * This is your unofficial assurance that libpng from version 0.71 and - * upward through 1.6.30 are Y2K compliant. It is my belief that + * upward through 1.6.31rc01 are Y2K compliant. It is my belief that * earlier versions were also Y2K compliant. * * Libpng only has two year fields. One is a 2-byte unsigned integer @@ -309,8 +309,8 @@ */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.6.30" -#define PNG_HEADER_VERSION_STRING " libpng version 1.6.30 - June 28, 2017\n" +#define PNG_LIBPNG_VER_STRING "1.6.31rc01" +#define PNG_HEADER_VERSION_STRING " libpng version 1.6.31rc01 - July 19, 2017\n" #define PNG_LIBPNG_VER_SONUM 16 #define PNG_LIBPNG_VER_DLLNUM 16 @@ -318,13 +318,13 @@ /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ #define PNG_LIBPNG_VER_MAJOR 1 #define PNG_LIBPNG_VER_MINOR 6 -#define PNG_LIBPNG_VER_RELEASE 30 +#define PNG_LIBPNG_VER_RELEASE 31 /* This should match the numeric part of the final component of * PNG_LIBPNG_VER_STRING, omitting any leading zero: */ -#define PNG_LIBPNG_VER_BUILD 0 +#define PNG_LIBPNG_VER_BUILD 01 /* Release Status */ #define PNG_LIBPNG_BUILD_ALPHA 1 @@ -341,7 +341,7 @@ #define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with PNG_LIBPNG_BUILD_PRIVATE */ -#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE +#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_RC /* Careful here. At one time, Guy wanted to use 082, but that would be octal. * We must not include leading zeros. @@ -349,7 +349,7 @@ * version 1.0.0 was mis-numbered 100 instead of 10000). From * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */ -#define PNG_LIBPNG_VER 10630 /* 1.6.30 */ +#define PNG_LIBPNG_VER 10631 /* 1.6.31 */ /* Library configuration: these options cannot be changed after * the library has been built. @@ -459,7 +459,7 @@ extern "C" { /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ -typedef char* png_libpng_version_1_6_30; +typedef char* png_libpng_version_1_6_31rc01; /* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. * @@ -776,6 +776,7 @@ typedef png_unknown_chunk * * png_unknown_chunkpp; #define PNG_INFO_sPLT 0x2000U /* ESR, 1.0.6 */ #define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */ #define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */ +#define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */ /* This is used for the transformation routines, as some of them * change these values for the row. It also should enable using @@ -1788,7 +1789,8 @@ PNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr, #define PNG_FREE_PLTE 0x1000U #define PNG_FREE_TRNS 0x2000U #define PNG_FREE_TEXT 0x4000U -#define PNG_FREE_ALL 0x7fffU +#define PNG_FREE_EXIF 0x8000U /* Added at libpng-1.6.31 */ +#define PNG_FREE_ALL 0xffffU #define PNG_FREE_MUL 0x4220U /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ #ifdef PNG_USER_MEM_SUPPORTED @@ -2007,6 +2009,13 @@ PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr, png_fixed_point int_blue_Z)) #endif +#ifdef PNG_eXIf_SUPPORTED +PNG_EXPORT(246, png_uint_32, png_get_eXIf, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep *exif)); +PNG_EXPORT(247, void, png_set_eXIf, (png_const_structrp png_ptr, + png_inforp info_ptr, const png_bytep exif)); +#endif + #ifdef PNG_gAMA_SUPPORTED PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr, png_const_inforp info_ptr, double *file_gamma)) @@ -2025,9 +2034,6 @@ PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr, #ifdef PNG_hIST_SUPPORTED PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr, png_inforp info_ptr, png_uint_16p *hist)); -#endif - -#ifdef PNG_hIST_SUPPORTED PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr, png_inforp info_ptr, png_const_uint_16p hist)); #endif @@ -3253,7 +3259,7 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, * one to use is one more than this.) */ #ifdef PNG_EXPORT_LAST_ORDINAL - PNG_EXPORT_LAST_ORDINAL(245); + PNG_EXPORT_LAST_ORDINAL(247); #endif #ifdef __cplusplus diff --git a/thirdparty/libpng/pngconf.h b/thirdparty/libpng/pngconf.h index f64592acd7..9308d6a60a 100644 --- a/thirdparty/libpng/pngconf.h +++ b/thirdparty/libpng/pngconf.h @@ -1,7 +1,7 @@ /* pngconf.h - machine configurable file for libpng * - * libpng version 1.6.30, June 28, 2017 + * libpng version 1.6.31rc01, July 19, 2017 * * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) diff --git a/thirdparty/libpng/pngerror.c b/thirdparty/libpng/pngerror.c index 00d76f7c05..37f26c6558 100644 --- a/thirdparty/libpng/pngerror.c +++ b/thirdparty/libpng/pngerror.c @@ -1,8 +1,8 @@ /* pngerror.c - stub functions for i/o and memory allocation * - * Last changed in libpng 1.6.26 [October 20, 2016] - * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson + * Last changed in libpng 1.6.31 [(PENDING RELEASE)] + * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -163,7 +163,7 @@ png_format_number(png_const_charp start, png_charp end, int format, case PNG_NUMBER_FORMAT_02u: /* Expects at least 2 digits. */ mincount = 2; - /* FALL THROUGH */ + /* FALLTHROUGH */ case PNG_NUMBER_FORMAT_u: *--end = digits[number % 10]; @@ -173,7 +173,7 @@ png_format_number(png_const_charp start, png_charp end, int format, case PNG_NUMBER_FORMAT_02x: /* This format expects at least two digits */ mincount = 2; - /* FALL THROUGH */ + /* FALLTHROUGH */ case PNG_NUMBER_FORMAT_x: *--end = digits[number & 0xf]; diff --git a/thirdparty/libpng/pngget.c b/thirdparty/libpng/pngget.c index 141c393330..ace9e6351f 100644 --- a/thirdparty/libpng/pngget.c +++ b/thirdparty/libpng/pngget.c @@ -773,6 +773,24 @@ png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr, } #endif +#ifdef PNG_eXIf_SUPPORTED +png_uint_32 PNGAPI +png_get_eXIf(png_const_structrp png_ptr, png_inforp info_ptr, + png_bytep *exif) +{ + png_debug1(1, "in %s retrieval function", "eXIf"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_eXIf) != 0 && exif != NULL) + { + *exif = info_ptr->exif; + return (PNG_INFO_eXIf); + } + + return (0); +} +#endif + #ifdef PNG_hIST_SUPPORTED png_uint_32 PNGAPI png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr, diff --git a/thirdparty/libpng/pnginfo.h b/thirdparty/libpng/pnginfo.h index 361ed8be70..6e6d46a62b 100644 --- a/thirdparty/libpng/pnginfo.h +++ b/thirdparty/libpng/pnginfo.h @@ -185,6 +185,11 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ #endif +#ifdef PNG_eXIf_SUPPORTED + int num_exif; + png_bytep exif; +#endif + #ifdef PNG_hIST_SUPPORTED /* The hIST chunk contains the relative frequency or importance of the * various palette entries, so that a viewer can intelligently select a diff --git a/thirdparty/libpng/pnglibconf.h b/thirdparty/libpng/pnglibconf.h index da3d8359f4..8738ebdfc2 100644 --- a/thirdparty/libpng/pnglibconf.h +++ b/thirdparty/libpng/pnglibconf.h @@ -1,8 +1,8 @@ -/* libpng 1.6.30 STANDARD API DEFINITION */ +/* libpng 1.6.31rc01 STANDARD API DEFINITION */ /* pnglibconf.h - library build configuration */ -/* Libpng version 1.6.30 - June 28, 2017 */ +/* Libpng version 1.6.31rc01 - July 19, 2017 */ /* Copyright (c) 1998-2017 Glenn Randers-Pehrson */ @@ -84,6 +84,7 @@ #define PNG_READ_USER_TRANSFORM_SUPPORTED #define PNG_READ_bKGD_SUPPORTED #define PNG_READ_cHRM_SUPPORTED +#define PNG_READ_eXIf_SUPPORTED #define PNG_READ_gAMA_SUPPORTED #define PNG_READ_hIST_SUPPORTED #define PNG_READ_iCCP_SUPPORTED @@ -153,6 +154,7 @@ #define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED #define PNG_WRITE_bKGD_SUPPORTED #define PNG_WRITE_cHRM_SUPPORTED +#define PNG_WRITE_eXIf_SUPPORTED #define PNG_WRITE_gAMA_SUPPORTED #define PNG_WRITE_hIST_SUPPORTED #define PNG_WRITE_iCCP_SUPPORTED @@ -170,6 +172,7 @@ #define PNG_WRITE_zTXt_SUPPORTED #define PNG_bKGD_SUPPORTED #define PNG_cHRM_SUPPORTED +#define PNG_eXIf_SUPPORTED #define PNG_gAMA_SUPPORTED #define PNG_hIST_SUPPORTED #define PNG_iCCP_SUPPORTED diff --git a/thirdparty/libpng/pngpriv.h b/thirdparty/libpng/pngpriv.h index a062a8da16..7c273bd5e3 100644 --- a/thirdparty/libpng/pngpriv.h +++ b/thirdparty/libpng/pngpriv.h @@ -1,7 +1,7 @@ /* pngpriv.h - private declarations for use inside libpng * - * Last changed in libpng 1.6.30 [(PENDING RELEASE)] + * Last changed in libpng 1.6.31 [(PENDING RELEASE)] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -35,7 +35,9 @@ * Windows/Visual Studio) there is no effect; the OS specific tests below are * still required (as of 2011-05-02.) */ -#define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ +#endif #ifndef PNG_VERSION_INFO_ONLY /* Standard library headers not required by png.h: */ @@ -452,6 +454,21 @@ # define png_fixed_error(s1,s2) png_err(s1) #endif +/* Some fixed point APIs are still required even if not exported because + * they get used by the corresponding floating point APIs. This magic + * deals with this: + */ +#ifdef PNG_FIXED_POINT_SUPPORTED +# define PNGFAPI PNGAPI +#else +# define PNGFAPI /* PRIVATE */ +#endif + +#ifndef PNG_VERSION_INFO_ONLY +/* Other defines specific to compilers can go here. Try to keep + * them inside an appropriate ifdef/endif pair for portability. + */ + /* C allows up-casts from (void*) to any pointer and (const void*) to any * pointer to a const object. C++ regards this as a type error and requires an * explicit, static, cast and provides the static_cast<> rune to ensure that @@ -480,20 +497,6 @@ # define png_aligncastconst(type, value) ((const void*)(value)) #endif /* __cplusplus */ -/* Some fixed point APIs are still required even if not exported because - * they get used by the corresponding floating point APIs. This magic - * deals with this: - */ -#ifdef PNG_FIXED_POINT_SUPPORTED -# define PNGFAPI PNGAPI -#else -# define PNGFAPI /* PRIVATE */ -#endif - -#ifndef PNG_VERSION_INFO_ONLY -/* Other defines specific to compilers can go here. Try to keep - * them inside an appropriate ifdef/endif pair for portability. - */ #if defined(PNG_FLOATING_POINT_SUPPORTED) ||\ defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) /* png.c requires the following ANSI-C constants if the conversion of @@ -839,6 +842,7 @@ #define png_PLTE PNG_U32( 80, 76, 84, 69) #define png_bKGD PNG_U32( 98, 75, 71, 68) #define png_cHRM PNG_U32( 99, 72, 82, 77) +#define png_eXIf PNG_U32(101, 88, 73, 102) /* registered July 2017 */ #define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ #define png_gAMA PNG_U32(103, 65, 77, 65) #define png_gIFg PNG_U32(103, 73, 70, 103) @@ -1438,6 +1442,11 @@ PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif +#ifdef PNG_READ_eXIf_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_eXIf,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + #ifdef PNG_READ_gAMA_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); diff --git a/thirdparty/libpng/pngread.c b/thirdparty/libpng/pngread.c index 106a80588c..b44d4dfbb5 100644 --- a/thirdparty/libpng/pngread.c +++ b/thirdparty/libpng/pngread.c @@ -1,8 +1,8 @@ /* pngread.c - read a PNG file * - * Last changed in libpng 1.6.26 [October 20, 2016] - * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson + * Last changed in libpng 1.6.31 [(PENDING RELEASE)] + * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -1883,7 +1883,7 @@ png_create_colormap_entry(png_image_read_control *display, { case 4: entry[afirst ? 0 : 3] = (png_uint_16)alpha; - /* FALL THROUGH */ + /* FALLTHROUGH */ case 3: if (alpha < 65535) @@ -1905,7 +1905,7 @@ png_create_colormap_entry(png_image_read_control *display, case 2: entry[1 ^ afirst] = (png_uint_16)alpha; - /* FALL THROUGH */ + /* FALLTHROUGH */ case 1: if (alpha < 65535) @@ -1934,6 +1934,7 @@ png_create_colormap_entry(png_image_read_control *display, { case 4: entry[afirst ? 0 : 3] = (png_byte)alpha; + /* FALLTHROUGH */ case 3: entry[afirst + (2 ^ bgr)] = (png_byte)blue; entry[afirst + 1] = (png_byte)green; @@ -1942,6 +1943,7 @@ png_create_colormap_entry(png_image_read_control *display, case 2: entry[1 ^ afirst] = (png_byte)alpha; + /* FALLTHROUGH */ case 1: entry[afirst] = (png_byte)green; break; @@ -2861,7 +2863,7 @@ png_image_read_colormap(png_voidp argument) case P_sRGB: /* Change to 8-bit sRGB */ png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB); - /* FALL THROUGH */ + /* FALLTHROUGH */ case P_FILE: if (png_ptr->bit_depth > 8) @@ -3179,8 +3181,7 @@ png_image_read_colormapped(png_voidp argument) image->colormap_entries == 244 /* 216 + 1 + 27 */) break; - /* goto bad_output; */ - /* FALL THROUGH */ + goto bad_output; default: bad_output: diff --git a/thirdparty/libpng/pngrtran.c b/thirdparty/libpng/pngrtran.c index 3886833af0..9285983848 100644 --- a/thirdparty/libpng/pngrtran.c +++ b/thirdparty/libpng/pngrtran.c @@ -1,7 +1,7 @@ /* pngrtran.c - transforms the data in a row for PNG readers * - * Last changed in libpng 1.6.30 [(PENDING RELEASE)] + * Last changed in libpng 1.6.31 [(PENDING RELEASE)] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -49,6 +49,7 @@ png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action) case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */ png_warning(png_ptr, "Can't discard critical data on CRC error"); + /* FALLTHROUGH */ case PNG_CRC_ERROR_QUIT: /* Error/quit */ case PNG_CRC_DEFAULT: @@ -1253,7 +1254,7 @@ png_init_rgb_transformations(png_structrp png_ptr) default: case 8: - /* FALL THROUGH (Already 8 bits) */ + /* FALLTHROUGH */ /* (Already 8 bits) */ case 16: /* Already a full 16 bits */ diff --git a/thirdparty/libpng/pngrutil.c b/thirdparty/libpng/pngrutil.c index f60545bf90..9cde64845c 100644 --- a/thirdparty/libpng/pngrutil.c +++ b/thirdparty/libpng/pngrutil.c @@ -1,7 +1,7 @@ /* pngrutil.c - utilities to read a PNG file * - * Last changed in libpng 1.6.30 [(PENDING RELEASE)] + * Last changed in libpng 1.6.31 [(PENDING RELEASE)] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -2009,6 +2009,44 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) } #endif +#ifdef PNG_READ_eXIf_SUPPORTED +void /* PRIVATE */ +png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + unsigned int i; + png_bytep eXIf_buf; + + png_debug(1, "in png_handle_eXIf"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_eXIf) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + eXIf_buf = png_voidcast(png_bytep, + png_malloc_warn(png_ptr, length)); + + for (i = 0; i < length; i++) + { + png_byte buf[1]; + png_crc_read(png_ptr, buf, 1); + eXIf_buf[i] = buf[0]; + } + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + info_ptr->num_exif = length; + + png_set_eXIf(png_ptr, info_ptr, eXIf_buf); +} +#endif + #ifdef PNG_READ_hIST_SUPPORTED void /* PRIVATE */ png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) @@ -2978,7 +3016,7 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, case 2: png_ptr->user_chunk_cache_max = 1; png_chunk_benign_error(png_ptr, "no space in chunk cache"); - /* FALL THROUGH */ + /* FALLTHROUGH */ case 1: /* NOTE: prior to 1.6.0 this case resulted in an unknown critical * chunk being skipped, now there will be a hard error below. @@ -2987,7 +3025,7 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, default: /* not at limit */ --(png_ptr->user_chunk_cache_max); - /* FALL THROUGH */ + /* FALLTHROUGH */ case 0: /* no limit */ # endif /* USER_LIMITS */ /* Here when the limit isn't reached or when limits are compiled diff --git a/thirdparty/libpng/pngset.c b/thirdparty/libpng/pngset.c index fb495ac3fb..998473557f 100644 --- a/thirdparty/libpng/pngset.c +++ b/thirdparty/libpng/pngset.c @@ -1,7 +1,7 @@ /* pngset.c - storage of image information into info struct * - * Last changed in libpng 1.6.30 [(PENDING RELEASE)] + * Last changed in libpng 1.6.30 [June 28, 2017] * Copyright (c) 1998-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -134,6 +134,39 @@ png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, #endif /* cHRM */ +#ifdef PNG_eXIf_SUPPORTED +void PNGAPI +png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr, + const png_bytep eXIf_buf) +{ + int i; + + png_debug1(1, "in %s storage function", "eXIf"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_free_data(png_ptr, info_ptr, PNG_FREE_EXIF, 0); + + info_ptr->exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, + info_ptr->num_exif)); + + if (info_ptr->exif == NULL) + { + png_warning(png_ptr, "Insufficient memory for eXIf chunk data"); + + return; + } + + info_ptr->free_me |= PNG_FREE_EXIF; + + for (i = 0; i < info_ptr->num_exif; i++) + info_ptr->exif[i] = eXIf_buf[i]; + + info_ptr->valid |= PNG_INFO_eXIf; +} +#endif /* eXIf */ + #ifdef PNG_gAMA_SUPPORTED void PNGFAPI png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr, diff --git a/thirdparty/libpng/pngstruct.h b/thirdparty/libpng/pngstruct.h index 749d7e35b1..44b79dea74 100644 --- a/thirdparty/libpng/pngstruct.h +++ b/thirdparty/libpng/pngstruct.h @@ -479,5 +479,8 @@ struct png_struct_def png_colorspace colorspace; #endif #endif + +/* New member added in libpng-1.6.31 */ + int num_exif; }; #endif /* PNGSTRUCT_H */ diff --git a/thirdparty/libpng/pngtrans.c b/thirdparty/libpng/pngtrans.c index 6c8c646239..326ac33f0e 100644 --- a/thirdparty/libpng/pngtrans.c +++ b/thirdparty/libpng/pngtrans.c @@ -1,7 +1,7 @@ /* pngtrans.c - transforms the data in a row (used by both readers and writers) * - * Last changed in libpng 1.6.30 [(PENDING RELEASE)] + * Last changed in libpng 1.6.30 [June 28, 2017] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) diff --git a/thirdparty/libpng/pngwrite.c b/thirdparty/libpng/pngwrite.c index 07088ee75e..8c2952e794 100644 --- a/thirdparty/libpng/pngwrite.c +++ b/thirdparty/libpng/pngwrite.c @@ -1,8 +1,8 @@ /* pngwrite.c - general routines to write a PNG file * - * Last changed in libpng 1.6.26 [October 20, 2016] - * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson + * Last changed in libpng 1.6.31 [(PENDING RELEASE)] + * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -1007,8 +1007,8 @@ png_set_filter(png_structrp png_ptr, int method, int filters) case 5: case 6: case 7: png_app_error(png_ptr, "Unknown row filter for method 0"); - /* FALL THROUGH */ #endif /* WRITE_FILTER */ + /* FALLTHROUGH */ case PNG_FILTER_VALUE_NONE: png_ptr->do_filter = PNG_FILTER_NONE; break; @@ -1875,7 +1875,7 @@ png_image_set_PLTE(png_image_write_control *display) tRNS[i] = entry[afirst ? 0 : 3]; if (tRNS[i] < 255) num_trans = i+1; - /* FALL THROUGH */ + /* FALLTHROUGH */ case 3: palette[i].blue = entry[afirst + (2 ^ bgr)]; palette[i].green = entry[afirst + 1]; @@ -1886,7 +1886,7 @@ png_image_set_PLTE(png_image_write_control *display) tRNS[i] = entry[1 ^ afirst]; if (tRNS[i] < 255) num_trans = i+1; - /* FALL THROUGH */ + /* FALLTHROUGH */ case 1: palette[i].blue = palette[i].red = palette[i].green = entry[afirst]; diff --git a/thirdparty/libpng/pngwutil.c b/thirdparty/libpng/pngwutil.c index dd800586be..348bb524dd 100644 --- a/thirdparty/libpng/pngwutil.c +++ b/thirdparty/libpng/pngwutil.c @@ -1473,6 +1473,37 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) } #endif +#ifdef PNG_WRITE_eXIf_SUPPORTED +/* Write the Exif data */ +void /* PRIVATE */ +png_write_eXIf(png_structrp png_ptr, png_bytep exif, int num_exif) +{ + int i; + png_byte buf[3]; + + png_debug(1, "in png_write_eXIf"); + + if (num_exif > (int)png_ptr->num_exif) + { + png_debug2(3, "num_exif = %d, png_ptr->num_exif = %d", num_exif, + png_ptr->num_exif); + + png_warning(png_ptr, "Invalid number of exif bytes specified"); + return; + } + + png_write_chunk_header(png_ptr, png_eXIf, (png_uint_32)(num_exif)); + + for (i = 0; i < num_exif; i++) + { + buf[i] = exif[i]; + png_write_chunk_data(png_ptr, buf, (png_size_t)1); + } + + png_write_chunk_end(png_ptr); +} +#endif + #ifdef PNG_WRITE_hIST_SUPPORTED /* Write the histogram */ void /* PRIVATE */ diff --git a/thirdparty/zstd/README.md b/thirdparty/zstd/README.md index 7caee5fd3f..f37be4542c 100644 --- a/thirdparty/zstd/README.md +++ b/thirdparty/zstd/README.md @@ -6,10 +6,17 @@ and a command line utility producing and decoding `.zst` and `.gz` files. For other programming languages, you can consult a list of known ports on [Zstandard homepage](http://www.zstd.net/#other-languages). -|Branch |Status | -|------------|---------| -|master | [![Build Status](https://travis-ci.org/facebook/zstd.svg?branch=master)](https://travis-ci.org/facebook/zstd) | -|dev | [![Build Status](https://travis-ci.org/facebook/zstd.svg?branch=dev)](https://travis-ci.org/facebook/zstd) | +| dev branch status | +|-------------------| +| [![Build Status][travisDevBadge]][travisLink] [![Build status][AppveyorDevBadge]][AppveyorLink] [![Build status][CircleDevBadge]][CircleLink] + +[travisDevBadge]: https://travis-ci.org/facebook/zstd.svg?branch=dev "Continuous Integration test suite" +[travisLink]: https://travis-ci.org/facebook/zstd +[AppveyorDevBadge]: https://ci.appveyor.com/api/projects/status/xt38wbdxjk5mrbem/branch/dev?svg=true "Windows test suite" +[AppveyorLink]: https://ci.appveyor.com/project/YannCollet/zstd-p0yf0 +[CircleDevBadge]: https://circleci.com/gh/facebook/zstd/tree/dev.svg?style=shield "Short test suite" +[CircleLink]: https://circleci.com/gh/facebook/zstd + As a reference, several fast compression algorithms were tested and compared on a server running Linux Debian (`Linux version 4.8.0-1-amd64`), @@ -60,11 +67,11 @@ Previous charts provide results applicable to typical file and stream scenarios The smaller the amount of data to compress, the more difficult it is to compress. This problem is common to all compression algorithms, and reason is, compression algorithms learn from past data how to compress future data. But at the beginning of a new data set, there is no "past" to build upon. To solve this situation, Zstd offers a __training mode__, which can be used to tune the algorithm for a selected type of data. -Training Zstandard is achieved by provide it with a few samples (one file per sample). The result of this training is stored in a file called "dictionary", which must be loaded before compression and decompression. +Training Zstandard is achieved by providing it with a few samples (one file per sample). The result of this training is stored in a file called "dictionary", which must be loaded before compression and decompression. Using this dictionary, the compression ratio achievable on small data improves dramatically. The following example uses the `github-users` [sample set](https://github.com/facebook/zstd/releases/tag/v1.1.3), created from [github public API](https://developer.github.com/v3/users/#get-all-users). -It consists of roughly 10K records weighting about 1KB each. +It consists of roughly 10K records weighing about 1KB each. Compression Ratio | Compression Speed | Decompression Speed ------------------|-------------------|-------------------- diff --git a/thirdparty/zstd/common/bitstream.h b/thirdparty/zstd/common/bitstream.h index ca42850df3..07b85026c9 100644 --- a/thirdparty/zstd/common/bitstream.h +++ b/thirdparty/zstd/common/bitstream.h @@ -39,7 +39,6 @@ extern "C" { #endif - /* * This API consists of small unitary functions, which must be inlined for best performance. * Since link-time-optimization is not available for all compilers, @@ -59,7 +58,9 @@ extern "C" { #if defined(BIT_DEBUG) && (BIT_DEBUG>=1) # include <assert.h> #else -# define assert(condition) ((void)0) +# ifndef assert +# define assert(condition) ((void)0) +# endif #endif @@ -74,6 +75,7 @@ extern "C" { #define STREAM_ACCUMULATOR_MIN_64 57 #define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64)) + /*-****************************************** * bitStream encoding API (write forward) ********************************************/ @@ -303,13 +305,25 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si bitD->bitContainer = *(const BYTE*)(bitD->start); switch(srcSize) { - case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16); - case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24); - case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32); - case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24; - case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16; - case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8; - default:; + case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16); + /* fall-through */ + + case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24); + /* fall-through */ + + case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32); + /* fall-through */ + + case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24; + /* fall-through */ + + case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16; + /* fall-through */ + + case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8; + /* fall-through */ + + default: break; } { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; diff --git a/thirdparty/zstd/common/error_private.c b/thirdparty/zstd/common/error_private.c index b3287245f1..2d752cd23a 100644 --- a/thirdparty/zstd/common/error_private.c +++ b/thirdparty/zstd/common/error_private.c @@ -24,7 +24,8 @@ const char* ERR_getErrorString(ERR_enum code) case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; case PREFIX(frameParameter_unsupportedBy32bits): return "Frame parameter unsupported in 32-bits mode"; case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding"; - case PREFIX(compressionParameter_unsupported): return "Compression parameter is out of bound"; + case PREFIX(compressionParameter_unsupported): return "Compression parameter is not supported"; + case PREFIX(compressionParameter_outOfBound): return "Compression parameter is out of bound"; case PREFIX(init_missing): return "Context should be init first"; case PREFIX(memory_allocation): return "Allocation error : not enough memory"; case PREFIX(stage_wrong): return "Operation not authorized at current processing stage"; @@ -38,6 +39,8 @@ const char* ERR_getErrorString(ERR_enum code) case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; case PREFIX(dictionary_wrong): return "Dictionary mismatch"; case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples"; + case PREFIX(frameIndex_tooLarge): return "Frame index is too large"; + case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking"; case PREFIX(maxCode): default: return notErrorCode; } diff --git a/thirdparty/zstd/common/huf.h b/thirdparty/zstd/common/huf.h index 7873ca3d42..dabd359915 100644 --- a/thirdparty/zstd/common/huf.h +++ b/thirdparty/zstd/common/huf.h @@ -111,6 +111,18 @@ HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity, const void* #define HUF_WORKSPACE_SIZE_U32 (HUF_WORKSPACE_SIZE / sizeof(U32)) HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); +/** + * The minimum workspace size for the `workSpace` used in + * HUF_readDTableX2_wksp() and HUF_readDTableX4_wksp(). + * + * The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when + * HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15. + * Buffer overflow errors may potentially occur if code modifications result in + * a required workspace size greater than that specified in the following + * macro. + */ +#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10) +#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32)) /* ****************************************************************** @@ -170,8 +182,11 @@ size_t HUF_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cS size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */ size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */ +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< considers RLE and uncompressed as errors */ size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ size_t HUF_decompress4X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ /* **************************************** @@ -243,7 +258,9 @@ HUF_decompress() does the following: U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize); size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize); +size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); size_t HUF_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize); +size_t HUF_readDTableX4_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); @@ -266,8 +283,11 @@ size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cS size_t HUF_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */ size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); +size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ size_t HUF_decompress1X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */ size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); diff --git a/thirdparty/zstd/common/mem.h b/thirdparty/zstd/common/mem.h index 4773a8b930..b0e5bf60b4 100644 --- a/thirdparty/zstd/common/mem.h +++ b/thirdparty/zstd/common/mem.h @@ -352,20 +352,6 @@ MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val) } -/* function safe only for comparisons */ -MEM_STATIC U32 MEM_readMINMATCH(const void* memPtr, U32 length) -{ - switch (length) - { - default : - case 4 : return MEM_read32(memPtr); - case 3 : if (MEM_isLittleEndian()) - return MEM_read32(memPtr)<<8; - else - return MEM_read32(memPtr)>>8; - } -} - #if defined (__cplusplus) } #endif diff --git a/thirdparty/zstd/common/pool.c b/thirdparty/zstd/common/pool.c index e439fe1b0d..749fa4f2f7 100644 --- a/thirdparty/zstd/common/pool.c +++ b/thirdparty/zstd/common/pool.c @@ -146,6 +146,13 @@ void POOL_free(POOL_ctx *ctx) { free(ctx); } +size_t POOL_sizeof(POOL_ctx *ctx) { + if (ctx==NULL) return 0; /* supports sizeof NULL */ + return sizeof(*ctx) + + ctx->queueSize * sizeof(POOL_job) + + ctx->numThreads * sizeof(pthread_t); +} + void POOL_add(void *ctxVoid, POOL_function function, void *opaque) { POOL_ctx *ctx = (POOL_ctx *)ctxVoid; if (!ctx) { return; } @@ -191,4 +198,9 @@ void POOL_add(void *ctx, POOL_function function, void *opaque) { function(opaque); } +size_t POOL_sizeof(POOL_ctx *ctx) { + if (ctx==NULL) return 0; /* supports sizeof NULL */ + return sizeof(*ctx); +} + #endif /* ZSTD_MULTITHREAD */ diff --git a/thirdparty/zstd/common/pool.h b/thirdparty/zstd/common/pool.h index 50cb25b12c..386cd674b7 100644 --- a/thirdparty/zstd/common/pool.h +++ b/thirdparty/zstd/common/pool.h @@ -32,6 +32,11 @@ POOL_ctx *POOL_create(size_t numThreads, size_t queueSize); */ void POOL_free(POOL_ctx *ctx); +/*! POOL_sizeof() : + return memory usage of pool returned by POOL_create(). +*/ +size_t POOL_sizeof(POOL_ctx *ctx); + /*! POOL_function : The function type that can be added to a thread pool. */ diff --git a/thirdparty/zstd/common/threading.c b/thirdparty/zstd/common/threading.c index 32d58796a9..141376c561 100644 --- a/thirdparty/zstd/common/threading.c +++ b/thirdparty/zstd/common/threading.c @@ -1,4 +1,3 @@ - /** * Copyright (c) 2016 Tino Reichardt * All rights reserved. diff --git a/thirdparty/zstd/common/zstd_common.c b/thirdparty/zstd/common/zstd_common.c index 8408a589ae..f681672381 100644 --- a/thirdparty/zstd/common/zstd_common.c +++ b/thirdparty/zstd/common/zstd_common.c @@ -12,16 +12,19 @@ /*-************************************* * Dependencies ***************************************/ -#include <stdlib.h> /* malloc */ +#include <stdlib.h> /* malloc, calloc, free */ +#include <string.h> /* memset */ #include "error_private.h" #define ZSTD_STATIC_LINKING_ONLY -#include "zstd.h" /* declaration of ZSTD_isError, ZSTD_getErrorName, ZSTD_getErrorCode, ZSTD_getErrorString, ZSTD_versionNumber */ +#include "zstd.h" /*-**************************************** * Version ******************************************/ -unsigned ZSTD_versionNumber (void) { return ZSTD_VERSION_NUMBER; } +unsigned ZSTD_versionNumber(void) { return ZSTD_VERSION_NUMBER; } + +const char* ZSTD_versionString(void) { return ZSTD_VERSION_STRING; } /*-**************************************** @@ -47,27 +50,31 @@ const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString /*=************************************************************** * Custom allocator ****************************************************************/ -/* default uses stdlib */ -void* ZSTD_defaultAllocFunction(void* opaque, size_t size) -{ - void* address = malloc(size); - (void)opaque; - return address; -} - -void ZSTD_defaultFreeFunction(void* opaque, void* address) +void* ZSTD_malloc(size_t size, ZSTD_customMem customMem) { - (void)opaque; - free(address); + if (customMem.customAlloc) + return customMem.customAlloc(customMem.opaque, size); + return malloc(size); } -void* ZSTD_malloc(size_t size, ZSTD_customMem customMem) +void* ZSTD_calloc(size_t size, ZSTD_customMem customMem) { - return customMem.customAlloc(customMem.opaque, size); + if (customMem.customAlloc) { + /* calloc implemented as malloc+memset; + * not as efficient as calloc, but next best guess for custom malloc */ + void* const ptr = customMem.customAlloc(customMem.opaque, size); + memset(ptr, 0, size); + return ptr; + } + return calloc(1, size); } void ZSTD_free(void* ptr, ZSTD_customMem customMem) { - if (ptr!=NULL) - customMem.customFree(customMem.opaque, ptr); + if (ptr!=NULL) { + if (customMem.customFree) + customMem.customFree(customMem.opaque, ptr); + else + free(ptr); + } } diff --git a/thirdparty/zstd/common/zstd_errors.h b/thirdparty/zstd/common/zstd_errors.h index 3d579d9693..19f1597aa3 100644 --- a/thirdparty/zstd/common/zstd_errors.h +++ b/thirdparty/zstd/common/zstd_errors.h @@ -19,10 +19,12 @@ extern "C" { /* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */ -#if defined(__GNUC__) && (__GNUC__ >= 4) -# define ZSTDERRORLIB_VISIBILITY __attribute__ ((visibility ("default"))) -#else -# define ZSTDERRORLIB_VISIBILITY +#ifndef ZSTDERRORLIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define ZSTDERRORLIB_VISIBILITY __attribute__ ((visibility ("default"))) +# else +# define ZSTDERRORLIB_VISIBILITY +# endif #endif #if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) # define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBILITY @@ -33,8 +35,11 @@ extern "C" { #endif /*-**************************************** -* error codes list -******************************************/ + * error codes list + * note : this API is still considered unstable + * it should not be used with a dynamic library + * only static linking is allowed + ******************************************/ typedef enum { ZSTD_error_no_error, ZSTD_error_GENERIC, @@ -45,6 +50,7 @@ typedef enum { ZSTD_error_frameParameter_unsupportedBy32bits, ZSTD_error_frameParameter_windowTooLarge, ZSTD_error_compressionParameter_unsupported, + ZSTD_error_compressionParameter_outOfBound, ZSTD_error_init_missing, ZSTD_error_memory_allocation, ZSTD_error_stage_wrong, @@ -58,12 +64,14 @@ typedef enum { ZSTD_error_dictionary_corrupted, ZSTD_error_dictionary_wrong, ZSTD_error_dictionaryCreation_failed, + ZSTD_error_frameIndex_tooLarge, + ZSTD_error_seekableIO, ZSTD_error_maxCode } ZSTD_ErrorCode; /*! ZSTD_getErrorCode() : convert a `size_t` function result into a `ZSTD_ErrorCode` enum type, - which can be used to compare directly with enum list published into "error_public.h" */ + which can be used to compare with enum list published above */ ZSTDERRORLIB_API ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult); ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); diff --git a/thirdparty/zstd/common/zstd_internal.h b/thirdparty/zstd/common/zstd_internal.h index 2533333ba8..49a4796476 100644 --- a/thirdparty/zstd/common/zstd_internal.h +++ b/thirdparty/zstd/common/zstd_internal.h @@ -18,6 +18,7 @@ # include <intrin.h> /* For Visual 2005 */ # pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ # pragma warning(disable : 4324) /* disable: C4324: padded structure */ #else # if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ @@ -50,9 +51,42 @@ #define ZSTD_STATIC_LINKING_ONLY #include "zstd.h" #ifndef XXH_STATIC_LINKING_ONLY -# define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ +# define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ +#endif +#include "xxhash.h" /* XXH_reset, update, digest */ + + +/*-************************************* +* Debug +***************************************/ +#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1) +# include <assert.h> +#else +# ifndef assert +# define assert(condition) ((void)0) +# endif +#endif + +#define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; } + +#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=2) +# include <stdio.h> +/* recommended values for ZSTD_DEBUG display levels : + * 1 : no display, enables assert() only + * 2 : reserved for currently active debugging path + * 3 : events once per object lifetime (CCtx, CDict) + * 4 : events once per frame + * 5 : events once per block + * 6 : events once per sequence (*very* verbose) */ +# define DEBUGLOG(l, ...) { \ + if (l<=ZSTD_DEBUG) { \ + fprintf(stderr, __FILE__ ": "); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " \n"); \ + } } +#else +# define DEBUGLOG(l, ...) {} /* disabled */ #endif -#include "xxhash.h" /* XXH_reset, update, digest */ /*-************************************* @@ -70,7 +104,6 @@ * Common constants ***************************************/ #define ZSTD_OPT_NUM (1<<12) -#define ZSTD_DICT_MAGIC 0xEC30A437 /* v0.7+ */ #define ZSTD_REP_NUM 3 /* number of repcodes */ #define ZSTD_REP_CHECK (ZSTD_REP_NUM) /* number of repcodes to check by the optimal parser */ @@ -235,15 +268,10 @@ typedef struct { const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); -int ZSTD_isSkipFrame(ZSTD_DCtx* dctx); /* custom memory allocation functions */ -void* ZSTD_defaultAllocFunction(void* opaque, size_t size); -void ZSTD_defaultFreeFunction(void* opaque, void* address); -#ifndef ZSTD_DLL_IMPORT -static const ZSTD_customMem defaultCustomMem = { ZSTD_defaultAllocFunction, ZSTD_defaultFreeFunction, NULL }; -#endif void* ZSTD_malloc(size_t size, ZSTD_customMem customMem); +void* ZSTD_calloc(size_t size, ZSTD_customMem customMem); void ZSTD_free(void* ptr, ZSTD_customMem customMem); @@ -281,4 +309,38 @@ MEM_STATIC U32 ZSTD_highbit32(U32 val) void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx); +/*! ZSTD_initCStream_internal() : + * Private use only. Init streaming operation. + * expects params to be valid. + * must receive dict, or cdict, or none, but not both. + * @return : 0, or an error code */ +size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + const ZSTD_CDict* cdict, + ZSTD_parameters params, unsigned long long pledgedSrcSize); + +/*! ZSTD_compressStream_generic() : + * Private use only. To be called from zstdmt_compress.c in single-thread mode. */ +size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input, + ZSTD_EndDirective const flushMode); + +/*! ZSTD_getParamsFromCDict() : + * as the name implies */ +ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict); + + +typedef struct { + blockType_e blockType; + U32 lastBlock; + U32 origSize; +} blockProperties_t; + +/*! ZSTD_getcBlockSize() : + * Provides the size of compressed block from block header `src` */ + size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, + blockProperties_t* bpPtr); + + #endif /* ZSTD_CCOMMON_H_MODULE */ diff --git a/thirdparty/zstd/compress/huf_compress.c b/thirdparty/zstd/compress/huf_compress.c index fe11aafb8f..7af0789a9c 100644 --- a/thirdparty/zstd/compress/huf_compress.c +++ b/thirdparty/zstd/compress/huf_compress.c @@ -266,7 +266,8 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) if (highTotal <= lowTotal) break; } } /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */ - while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol)) /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */ + /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */ + while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol)) nBitsToDecrease ++; totalCost -= 1 << (nBitsToDecrease-1); if (rankLast[nBitsToDecrease-1] == noSymbol) @@ -463,12 +464,15 @@ size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, si { case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable); HUF_FLUSHBITS_2(&bitC); + /* fall-through */ case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable); HUF_FLUSHBITS_1(&bitC); + /* fall-through */ case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable); HUF_FLUSHBITS(&bitC); - case 0 : - default: ; + /* fall-through */ + case 0 : /* fall-through */ + default: break; } for (; n>0; n-=4) { /* note : n&3==0 at this stage */ diff --git a/thirdparty/zstd/compress/zstd_compress.c b/thirdparty/zstd/compress/zstd_compress.c index c08b315dab..9300357f2d 100644 --- a/thirdparty/zstd/compress/zstd_compress.c +++ b/thirdparty/zstd/compress/zstd_compress.c @@ -9,6 +9,14 @@ /*-************************************* +* Tuning parameters +***************************************/ +#ifndef ZSTD_CLEVEL_DEFAULT +# define ZSTD_CLEVEL_DEFAULT 3 +#endif + + +/*-************************************* * Dependencies ***************************************/ #include <string.h> /* memset */ @@ -18,26 +26,7 @@ #define HUF_STATIC_LINKING_ONLY #include "huf.h" #include "zstd_internal.h" /* includes zstd.h */ - - -/*-************************************* -* Debug -***************************************/ -#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1) -# include <assert.h> -#else -# define assert(condition) ((void)0) -#endif - -#define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; } - -#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=2) -# include <stdio.h> - static unsigned g_debugLevel = ZSTD_DEBUG; -# define DEBUGLOG(l, ...) if (l<=g_debugLevel) { fprintf(stderr, __FILE__ ": "); fprintf(stderr, __VA_ARGS__); fprintf(stderr, " \n"); } -#else -# define DEBUGLOG(l, ...) {} /* disabled */ -#endif +#include "zstdmt_compress.h" /*-************************************* @@ -79,6 +68,15 @@ static void ZSTD_resetSeqStore(seqStore_t* ssPtr) /*-************************************* * Context memory management ***************************************/ +typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage; + +struct ZSTD_CDict_s { + void* dictBuffer; + const void* dictContent; + size_t dictContentSize; + ZSTD_CCtx* refContext; +}; /* typedef'd to ZSTD_CDict within "zstd.h" */ + struct ZSTD_CCtx_s { const BYTE* nextSrc; /* next block here to continue on current prefix */ const BYTE* base; /* All regular indexes relative to this position */ @@ -90,19 +88,21 @@ struct ZSTD_CCtx_s { U32 hashLog3; /* dispatch table : larger == faster, more memory */ U32 loadedDictEnd; /* index of end of dictionary */ U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */ - U32 forceRawDict; /* Force loading dictionary in "content-only" mode (no header analysis) */ ZSTD_compressionStage_e stage; U32 rep[ZSTD_REP_NUM]; U32 repToConfirm[ZSTD_REP_NUM]; U32 dictID; - ZSTD_parameters params; + int compressionLevel; + ZSTD_parameters requestedParams; + ZSTD_parameters appliedParams; void* workSpace; size_t workSpaceSize; size_t blockSize; - U64 frameContentSize; + U64 pledgedSrcSizePlusOne; /* this way, 0 (default) == unknown */ U64 consumedSrcSize; XXH64_state_t xxhState; ZSTD_customMem customMem; + size_t staticSize; seqStore_t seqStore; /* sequences storage ptrs */ U32* hashTable; @@ -115,31 +115,92 @@ struct ZSTD_CCtx_s { FSE_CTable* matchlengthCTable; FSE_CTable* litlengthCTable; unsigned* entropyScratchSpace; + + /* streaming */ + char* inBuff; + size_t inBuffSize; + size_t inToCompress; + size_t inBuffPos; + size_t inBuffTarget; + char* outBuff; + size_t outBuffSize; + size_t outBuffContentSize; + size_t outBuffFlushedSize; + ZSTD_cStreamStage streamStage; + U32 frameEnded; + + /* Dictionary */ + ZSTD_dictMode_e dictMode; /* select restricting dictionary to "rawContent" or "fullDict" only */ + U32 dictContentByRef; + ZSTD_CDict* cdictLocal; + const ZSTD_CDict* cdict; + const void* prefix; + size_t prefixSize; + + /* Multi-threading */ + U32 nbThreads; + ZSTDMT_CCtx* mtctx; }; + ZSTD_CCtx* ZSTD_createCCtx(void) { - return ZSTD_createCCtx_advanced(defaultCustomMem); + return ZSTD_createCCtx_advanced(ZSTD_defaultCMem); } ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) { ZSTD_CCtx* cctx; - if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem; - if (!customMem.customAlloc || !customMem.customFree) return NULL; + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem); + cctx = (ZSTD_CCtx*) ZSTD_calloc(sizeof(ZSTD_CCtx), customMem); if (!cctx) return NULL; - memset(cctx, 0, sizeof(ZSTD_CCtx)); cctx->customMem = customMem; + cctx->compressionLevel = ZSTD_CLEVEL_DEFAULT; + ZSTD_STATIC_ASSERT(zcss_init==0); + ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); + return cctx; +} + +ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize) +{ + ZSTD_CCtx* cctx = (ZSTD_CCtx*) workspace; + if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */ + if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */ + memset(workspace, 0, workspaceSize); /* may be a bit generous, could memset be smaller ? */ + cctx->staticSize = workspaceSize; + cctx->workSpace = (void*)(cctx+1); + cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx); + + /* entropy space (never moves) */ + /* note : this code should be shared with resetCCtx, rather than copy/pasted */ + { void* ptr = cctx->workSpace; + cctx->hufCTable = (HUF_CElt*)ptr; + ptr = (char*)cctx->hufCTable + hufCTable_size; + cctx->offcodeCTable = (FSE_CTable*) ptr; + ptr = (char*)ptr + offcodeCTable_size; + cctx->matchlengthCTable = (FSE_CTable*) ptr; + ptr = (char*)ptr + matchlengthCTable_size; + cctx->litlengthCTable = (FSE_CTable*) ptr; + ptr = (char*)ptr + litlengthCTable_size; + assert(((size_t)ptr & 3) == 0); /* ensure correct alignment */ + cctx->entropyScratchSpace = (unsigned*) ptr; + } + return cctx; } size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) { if (cctx==NULL) return 0; /* support free on NULL */ + if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */ ZSTD_free(cctx->workSpace, cctx->customMem); + cctx->workSpace = NULL; + ZSTD_freeCDict(cctx->cdictLocal); + cctx->cdictLocal = NULL; + ZSTDMT_freeCCtx(cctx->mtctx); + cctx->mtctx = NULL; ZSTD_free(cctx, cctx->customMem); return 0; /* reserved as a potential error code in the future */ } @@ -147,46 +208,294 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) { if (cctx==NULL) return 0; /* support sizeof on NULL */ - return sizeof(*cctx) + cctx->workSpaceSize; + DEBUGLOG(5, "sizeof(*cctx) : %u", (U32)sizeof(*cctx)); + DEBUGLOG(5, "workSpaceSize : %u", (U32)cctx->workSpaceSize); + DEBUGLOG(5, "streaming buffers : %u", (U32)(cctx->outBuffSize + cctx->inBuffSize)); + DEBUGLOG(5, "inner MTCTX : %u", (U32)ZSTDMT_sizeof_CCtx(cctx->mtctx)); + return sizeof(*cctx) + cctx->workSpaceSize + + ZSTD_sizeof_CDict(cctx->cdictLocal) + + cctx->outBuffSize + cctx->inBuffSize + + ZSTDMT_sizeof_CCtx(cctx->mtctx); } +size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) +{ + return ZSTD_sizeof_CCtx(zcs); /* same object */ +} + +/* private API call, for dictBuilder only */ +const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } + +static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { return cctx->appliedParams; } + +/* older variant; will be deprecated */ size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value) { switch(param) { case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0; - case ZSTD_p_forceRawDict : cctx->forceRawDict = value>0; return 0; + ZSTD_STATIC_ASSERT(ZSTD_dm_auto==0); + ZSTD_STATIC_ASSERT(ZSTD_dm_rawContent==1); + case ZSTD_p_forceRawDict : cctx->dictMode = (ZSTD_dictMode_e)(value>0); return 0; default: return ERROR(parameter_unknown); } } -const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */ + +#define ZSTD_CLEVEL_CUSTOM 999 +static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx) { - return &(ctx->seqStore); + if (cctx->compressionLevel==ZSTD_CLEVEL_CUSTOM) return; + cctx->requestedParams.cParams = ZSTD_getCParams(cctx->compressionLevel, + cctx->pledgedSrcSizePlusOne-1, 0); + cctx->compressionLevel = ZSTD_CLEVEL_CUSTOM; } -static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) +#define CLAMPCHECK(val,min,max) { \ + if (((val)<(min)) | ((val)>(max))) { \ + return ERROR(compressionParameter_outOfBound); \ +} } + +size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value) { - return cctx->params; + if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); + + switch(param) + { + case ZSTD_p_compressionLevel : + if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel(); /* cap max compression level */ + if (value == 0) return 0; /* special value : 0 means "don't change anything" */ + if (cctx->cdict) return ERROR(stage_wrong); + cctx->compressionLevel = value; + return 0; + + case ZSTD_p_windowLog : + DEBUGLOG(5, "setting ZSTD_p_windowLog = %u (cdict:%u)", + value, (cctx->cdict!=NULL)); + if (value == 0) return 0; /* special value : 0 means "don't change anything" */ + if (cctx->cdict) return ERROR(stage_wrong); + CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); + ZSTD_cLevelToCParams(cctx); + cctx->requestedParams.cParams.windowLog = value; + return 0; + + case ZSTD_p_hashLog : + if (value == 0) return 0; /* special value : 0 means "don't change anything" */ + if (cctx->cdict) return ERROR(stage_wrong); + CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); + ZSTD_cLevelToCParams(cctx); + cctx->requestedParams.cParams.hashLog = value; + return 0; + + case ZSTD_p_chainLog : + if (value == 0) return 0; /* special value : 0 means "don't change anything" */ + if (cctx->cdict) return ERROR(stage_wrong); + CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); + ZSTD_cLevelToCParams(cctx); + cctx->requestedParams.cParams.chainLog = value; + return 0; + + case ZSTD_p_searchLog : + if (value == 0) return 0; /* special value : 0 means "don't change anything" */ + if (cctx->cdict) return ERROR(stage_wrong); + CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); + ZSTD_cLevelToCParams(cctx); + cctx->requestedParams.cParams.searchLog = value; + return 0; + + case ZSTD_p_minMatch : + if (value == 0) return 0; /* special value : 0 means "don't change anything" */ + if (cctx->cdict) return ERROR(stage_wrong); + CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); + ZSTD_cLevelToCParams(cctx); + cctx->requestedParams.cParams.searchLength = value; + return 0; + + case ZSTD_p_targetLength : + if (value == 0) return 0; /* special value : 0 means "don't change anything" */ + if (cctx->cdict) return ERROR(stage_wrong); + CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); + ZSTD_cLevelToCParams(cctx); + cctx->requestedParams.cParams.targetLength = value; + return 0; + + case ZSTD_p_compressionStrategy : + if (value == 0) return 0; /* special value : 0 means "don't change anything" */ + if (cctx->cdict) return ERROR(stage_wrong); + CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra); + ZSTD_cLevelToCParams(cctx); + cctx->requestedParams.cParams.strategy = (ZSTD_strategy)value; + return 0; + + case ZSTD_p_contentSizeFlag : + DEBUGLOG(5, "set content size flag = %u", (value>0)); + /* Content size written in frame header _when known_ (default:1) */ + cctx->requestedParams.fParams.contentSizeFlag = value>0; + return 0; + + case ZSTD_p_checksumFlag : + /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ + cctx->requestedParams.fParams.checksumFlag = value>0; + return 0; + + case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ + DEBUGLOG(5, "set dictIDFlag = %u", (value>0)); + cctx->requestedParams.fParams.noDictIDFlag = (value==0); + return 0; + + /* Dictionary parameters */ + case ZSTD_p_dictMode : + if (cctx->cdict) return ERROR(stage_wrong); /* must be set before loading */ + /* restrict dictionary mode, to "rawContent" or "fullDict" only */ + ZSTD_STATIC_ASSERT((U32)ZSTD_dm_fullDict > (U32)ZSTD_dm_rawContent); + if (value > (unsigned)ZSTD_dm_fullDict) + return ERROR(compressionParameter_outOfBound); + cctx->dictMode = (ZSTD_dictMode_e)value; + return 0; + + case ZSTD_p_refDictContent : + if (cctx->cdict) return ERROR(stage_wrong); /* must be set before loading */ + /* dictionary content will be referenced, instead of copied */ + cctx->dictContentByRef = value>0; + return 0; + + case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize, + * even when referencing into Dictionary content + * default : 0 when using a CDict, 1 when using a Prefix */ + cctx->forceWindow = value>0; + cctx->loadedDictEnd = 0; + return 0; + + case ZSTD_p_nbThreads: + if (value==0) return 0; + DEBUGLOG(5, " setting nbThreads : %u", value); +#ifndef ZSTD_MULTITHREAD + if (value > 1) return ERROR(compressionParameter_unsupported); +#endif + if ((value>1) && (cctx->nbThreads != value)) { + if (cctx->staticSize) /* MT not compatible with static alloc */ + return ERROR(compressionParameter_unsupported); + ZSTDMT_freeCCtx(cctx->mtctx); + cctx->nbThreads = 1; + cctx->mtctx = ZSTDMT_createCCtx(value); + if (cctx->mtctx == NULL) return ERROR(memory_allocation); + } + cctx->nbThreads = value; + return 0; + + case ZSTD_p_jobSize: + if (cctx->nbThreads <= 1) return ERROR(compressionParameter_unsupported); + assert(cctx->mtctx != NULL); + return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_sectionSize, value); + + case ZSTD_p_overlapSizeLog: + DEBUGLOG(5, " setting overlap with nbThreads == %u", cctx->nbThreads); + if (cctx->nbThreads <= 1) return ERROR(compressionParameter_unsupported); + assert(cctx->mtctx != NULL); + return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_overlapSectionLog, value); + + default: return ERROR(parameter_unknown); + } +} + +ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) +{ + DEBUGLOG(5, " setting pledgedSrcSize to %u", (U32)pledgedSrcSize); + if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); + cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; + return 0; +} + +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) +{ + if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); + if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */ + DEBUGLOG(5, "load dictionary of size %u", (U32)dictSize); + ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */ + if (dict==NULL || dictSize==0) { /* no dictionary mode */ + cctx->cdictLocal = NULL; + cctx->cdict = NULL; + } else { + ZSTD_compressionParameters const cParams = + cctx->compressionLevel == ZSTD_CLEVEL_CUSTOM ? + cctx->requestedParams.cParams : + ZSTD_getCParams(cctx->compressionLevel, 0, dictSize); + cctx->cdictLocal = ZSTD_createCDict_advanced( + dict, dictSize, + cctx->dictContentByRef, cctx->dictMode, + cParams, cctx->customMem); + cctx->cdict = cctx->cdictLocal; + if (cctx->cdictLocal == NULL) + return ERROR(memory_allocation); + } + return 0; +} + +size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) +{ + if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); + cctx->cdict = cdict; + cctx->prefix = NULL; /* exclusive */ + cctx->prefixSize = 0; + return 0; +} + +size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize) +{ + if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); + cctx->cdict = NULL; /* prefix discards any prior cdict */ + cctx->prefix = prefix; + cctx->prefixSize = prefixSize; + return 0; +} + +static void ZSTD_startNewCompression(ZSTD_CCtx* cctx) +{ + cctx->streamStage = zcss_init; + cctx->pledgedSrcSizePlusOne = 0; } +/*! ZSTD_CCtx_reset() : + * Also dumps dictionary */ +void ZSTD_CCtx_reset(ZSTD_CCtx* cctx) +{ + ZSTD_startNewCompression(cctx); + cctx->cdict = NULL; +} -/** ZSTD_checkParams() : - ensure param values remain within authorized range. +/** ZSTD_checkCParams() : + control CParam values remain within authorized range. @return : 0, or an error code if one value is beyond authorized range */ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) { -# define CLAMPCHECK(val,min,max) { if ((val<min) | (val>max)) return ERROR(compressionParameter_unsupported); } CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); - if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2) return ERROR(compressionParameter_unsupported); + if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) return ERROR(compressionParameter_unsupported); return 0; } +/** ZSTD_clampCParams() : + * make CParam values within valid range. + * @return : valid CParams */ +static ZSTD_compressionParameters ZSTD_clampCParams(ZSTD_compressionParameters cParams) +{ +# define CLAMP(val,min,max) { \ + if (val<min) val=min; \ + else if (val>max) val=max; \ + } + CLAMP(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); + CLAMP(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); + CLAMP(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); + CLAMP(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); + CLAMP(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); + CLAMP(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); + if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) cParams.strategy = ZSTD_btultra; + return cParams; +} /** ZSTD_cycleLog() : * condition for correct operation : hashLog > 1 */ @@ -196,14 +505,15 @@ static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) return hashLog - btScale; } -/** ZSTD_adjustCParams() : +/** ZSTD_adjustCParams_internal() : optimize `cPar` for a given input (`srcSize` and `dictSize`). mostly downsizing to reduce memory consumption and initialization. Both `srcSize` and `dictSize` are optional (use 0 if unknown), but if both are 0, no optimization can be done. Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */ -ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize) +ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize) { + assert(ZSTD_checkCParams(cPar)==0); if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */ /* resize params, to use less memory when necessary */ @@ -223,10 +533,16 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u return cPar; } +ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize) +{ + cPar = ZSTD_clampCParams(cPar); + return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); +} -size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams) + +size_t ZSTD_estimateCCtxSize_advanced(ZSTD_compressionParameters cParams) { - size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog); + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); U32 const divider = (cParams.searchLength==3) ? 3 : 4; size_t const maxNbSeq = blockSize / divider; size_t const tokenSpace = blockSize + 11*maxNbSeq; @@ -240,31 +556,64 @@ size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams) + entropyScratchSpace_size; size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); - size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32) + size_t const optBudget = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32) + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t)); - size_t const neededSpace = entropySpace + tableSpace + tokenSpace - + (((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btopt2)) ? optSpace : 0); + size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0; + size_t const neededSpace = entropySpace + tableSpace + tokenSpace + optSpace; + DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx)); + DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace); return sizeof(ZSTD_CCtx) + neededSpace; } +size_t ZSTD_estimateCCtxSize(int compressionLevel) +{ + ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); + return ZSTD_estimateCCtxSize_advanced(cParams); +} -static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2) +size_t ZSTD_estimateCStreamSize_advanced(ZSTD_compressionParameters cParams) { - return (param1.cParams.hashLog == param2.cParams.hashLog) - & (param1.cParams.chainLog == param2.cParams.chainLog) - & (param1.cParams.strategy == param2.cParams.strategy) - & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3)); + size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced(cParams); + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); + size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize; + size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; + size_t const streamingSize = inBuffSize + outBuffSize; + + return CCtxSize + streamingSize; +} + +size_t ZSTD_estimateCStreamSize(int compressionLevel) { + ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); + return ZSTD_estimateCStreamSize_advanced(cParams); +} + + +static U32 ZSTD_equivalentParams(ZSTD_compressionParameters cParams1, + ZSTD_compressionParameters cParams2) +{ + U32 bslog1 = MIN(cParams1.windowLog, ZSTD_BLOCKSIZELOG_MAX); + U32 bslog2 = MIN(cParams2.windowLog, ZSTD_BLOCKSIZELOG_MAX); + return (bslog1 == bslog2) /* same block size */ + & (cParams1.hashLog == cParams2.hashLog) + & (cParams1.chainLog == cParams2.chainLog) + & (cParams1.strategy == cParams2.strategy) /* opt parser space */ + & ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */ } /*! ZSTD_continueCCtx() : - reuse CCtx without reset (note : requires no dictionary) */ -static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize) + * reuse CCtx without reset (note : requires no dictionary) */ +static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 pledgedSrcSize) { U32 const end = (U32)(cctx->nextSrc - cctx->base); - cctx->params = params; - cctx->frameContentSize = frameContentSize; + DEBUGLOG(5, "continue mode"); + cctx->appliedParams = params; + cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; cctx->consumedSrcSize = 0; + if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) + cctx->appliedParams.fParams.contentSizeFlag = 0; + DEBUGLOG(5, "pledged content size : %u ; flag : %u", + (U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag); cctx->lowLimit = end; cctx->dictLimit = end; cctx->nextToUpdate = end+1; @@ -277,30 +626,39 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 fra return 0; } -typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e; +typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e; +typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e; /*! ZSTD_resetCCtx_internal() : - note : `params` must be validated */ -static size_t ZSTD_resetCCtx_internal (ZSTD_CCtx* zc, - ZSTD_parameters params, U64 frameContentSize, - ZSTD_compResetPolicy_e const crp) + note : `params` are assumed fully validated at this stage */ +static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, + ZSTD_parameters params, U64 pledgedSrcSize, + ZSTD_compResetPolicy_e const crp, + ZSTD_buffered_policy_e const zbuff) { - if (crp == ZSTDcrp_continue) - if (ZSTD_equivalentParams(params, zc->params)) { + assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + + if (crp == ZSTDcrp_continue) { + if (ZSTD_equivalentParams(params.cParams, zc->appliedParams.cParams)) { + DEBUGLOG(5, "ZSTD_equivalentParams()==1"); zc->fseCTables_ready = 0; zc->hufCTable_repeatMode = HUF_repeat_none; - return ZSTD_continueCCtx(zc, params, frameContentSize); - } + return ZSTD_continueCCtx(zc, params, pledgedSrcSize); + } } - { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog); + { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog); U32 const divider = (params.cParams.searchLength==3) ? 3 : 4; size_t const maxNbSeq = blockSize / divider; size_t const tokenSpace = blockSize + 11*maxNbSeq; - size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog); + size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? + 0 : (1 << params.cParams.chainLog); size_t const hSize = ((size_t)1) << params.cParams.hashLog; - U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog); + U32 const hashLog3 = (params.cParams.searchLength>3) ? + 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog); size_t const h3Size = ((size_t)1) << hashLog3; size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); + size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0; + size_t const buffInSize = (zbuff==ZSTDb_buffered) ? ((size_t)1 << params.cParams.windowLog) + blockSize : 0; void* ptr; /* Check if workSpace is large enough, alloc a new one if needed */ @@ -309,9 +667,20 @@ static size_t ZSTD_resetCCtx_internal (ZSTD_CCtx* zc, + entropyScratchSpace_size; size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32) + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t)); - size_t const optSpace = ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) ? optPotentialSpace : 0; - size_t const neededSpace = entropySpace + optSpace + tableSpace + tokenSpace; - if (zc->workSpaceSize < neededSpace) { + size_t const optSpace = ( (params.cParams.strategy == ZSTD_btopt) + || (params.cParams.strategy == ZSTD_btultra)) ? + optPotentialSpace : 0; + size_t const bufferSpace = buffInSize + buffOutSize; + size_t const neededSpace = entropySpace + optSpace + tableSpace + + tokenSpace + bufferSpace; + + if (zc->workSpaceSize < neededSpace) { /* too small : resize /*/ + DEBUGLOG(5, "Need to update workSpaceSize from %uK to %uK \n", + (unsigned)zc->workSpaceSize>>10, + (unsigned)neededSpace>>10); + /* static cctx : no resize, error out */ + if (zc->staticSize) return ERROR(memory_allocation); + zc->workSpaceSize = 0; ZSTD_free(zc->workSpace, zc->customMem); zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem); @@ -333,10 +702,14 @@ static size_t ZSTD_resetCCtx_internal (ZSTD_CCtx* zc, } } /* init params */ - zc->params = params; - zc->blockSize = blockSize; - zc->frameContentSize = frameContentSize; + zc->appliedParams = params; + zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; zc->consumedSrcSize = 0; + if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) + zc->appliedParams.fParams.contentSizeFlag = 0; + DEBUGLOG(5, "pledged content size : %u ; flag : %u", + (U32)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag); + zc->blockSize = blockSize; XXH64_reset(&zc->xxhState, 0); zc->stage = ZSTDcs_init; @@ -363,7 +736,8 @@ static size_t ZSTD_resetCCtx_internal (ZSTD_CCtx* zc, ptr = (char*)zc->entropyScratchSpace + entropyScratchSpace_size; /* opt parser space */ - if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) { + if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btultra)) { + DEBUGLOG(5, "reserving optimal parser space"); assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ zc->seqStore.litFreq = (U32*)ptr; zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits); @@ -391,6 +765,13 @@ static size_t ZSTD_resetCCtx_internal (ZSTD_CCtx* zc, zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq; zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq; zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq; + ptr = zc->seqStore.litStart + blockSize; + + /* buffers */ + zc->inBuffSize = buffInSize; + zc->inBuff = (char*)ptr; + zc->outBuffSize = buffOutSize; + zc->outBuff = zc->inBuff + buffInSize; return 0; } @@ -411,21 +792,25 @@ void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) { * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). * pledgedSrcSize=0 means "empty" if fParams.contentSizeFlag=1 * @return : 0, or an error code */ -size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, - ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize) +static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, + const ZSTD_CCtx* srcCCtx, + ZSTD_frameParameters fParams, + unsigned long long pledgedSrcSize, + ZSTD_buffered_policy_e zbuff) { + DEBUGLOG(5, "ZSTD_copyCCtx_internal"); if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong); memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); - { ZSTD_parameters params = srcCCtx->params; + { ZSTD_parameters params = srcCCtx->appliedParams; params.fParams = fParams; - DEBUGLOG(5, "ZSTD_resetCCtx_internal : dictIDFlag : %u \n", !fParams.noDictIDFlag); - ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, ZSTDcrp_noMemset); + ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, + ZSTDcrp_noMemset, zbuff); } /* copy tables */ - { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog); - size_t const hSize = (size_t)1 << srcCCtx->params.cParams.hashLog; + { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->appliedParams.cParams.chainLog); + size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog; size_t const h3Size = (size_t)1 << srcCCtx->hashLog3; size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); assert((U32*)dstCCtx->chainTable == (U32*)dstCCtx->hashTable + hSize); /* chainTable must follow hashTable */ @@ -467,9 +852,11 @@ size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) { ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; + ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0); + ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1); fParams.contentSizeFlag = pledgedSrcSize>0; - return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, fParams, pledgedSrcSize); + return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, fParams, pledgedSrcSize, zbuff); } @@ -488,10 +875,10 @@ static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reduce * rescale all indexes to avoid future overflow (indexes are U32) */ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue) { - { U32 const hSize = 1 << zc->params.cParams.hashLog; + { U32 const hSize = 1 << zc->appliedParams.cParams.hashLog; ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); } - { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog); + { U32 const chainSize = (zc->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->appliedParams.cParams.chainLog); ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); } { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0; @@ -529,10 +916,11 @@ static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void case 2: /* 2 - 2 - 12 */ MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4))); break; - default: /*note : should not be necessary : flSize is within {1,2,3} */ case 3: /* 2 - 2 - 20 */ MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4))); break; + default: /* not necessary : flSize is {1,2,3} */ + assert(0); } memcpy(ostart + flSize, src, srcSize); @@ -554,10 +942,11 @@ static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, cons case 2: /* 2 - 2 - 12 */ MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4))); break; - default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */ case 3: /* 2 - 2 - 20 */ MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4))); break; + default: /* not necessary : flSize is {1,2,3} */ + assert(0); } ostart[flSize] = *(const BYTE*)src; @@ -587,7 +976,7 @@ static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */ { HUF_repeat repeat = zc->hufCTable_repeatMode; - int const preferRepeat = zc->params.cParams.strategy < ZSTD_lazy ? srcSize <= 1024 : 0; + int const preferRepeat = zc->appliedParams.cParams.strategy < ZSTD_lazy ? srcSize <= 1024 : 0; if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1; cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->entropyScratchSpace, entropyScratchSpace_size, zc->hufCTable, &repeat, preferRepeat) @@ -619,13 +1008,14 @@ static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, MEM_writeLE32(ostart, lhc); break; } - default: /* should not be necessary, lhSize is only {3,4,5} */ case 5: /* 2 - 2 - 18 - 18 */ { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22); MEM_writeLE32(ostart, lhc); ostart[4] = (BYTE)(cLitSize >> 10); break; } + default: /* not possible : lhSize is {3,4,5} */ + assert(0); } return lhSize+cLitSize; } @@ -676,7 +1066,7 @@ MEM_STATIC size_t ZSTD_compressSequences (ZSTD_CCtx* zc, void* dst, size_t dstCapacity, size_t srcSize) { - const int longOffsets = zc->params.cParams.windowLog > STREAM_ACCUMULATOR_MIN; + const int longOffsets = zc->appliedParams.cParams.windowLog > STREAM_ACCUMULATOR_MIN; const seqStore_t* seqStorePtr = &(zc->seqStore); U32 count[MaxSeq+1]; S16 norm[MaxSeq+1]; @@ -881,12 +1271,6 @@ _check_compressibility: return op - ostart; } -#if 0 /* for debug */ -# define STORESEQ_DEBUG -#include <stdio.h> /* fprintf */ -U32 g_startDebug = 0; -const BYTE* g_start = NULL; -#endif /*! ZSTD_storeSeq() : Store a sequence (literal length, literals, offset code and match length code) into seqStore_t. @@ -895,16 +1279,16 @@ const BYTE* g_start = NULL; */ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode) { -#ifdef STORESEQ_DEBUG - if (g_startDebug) { - const U32 pos = (U32)((const BYTE*)literals - g_start); - if (g_start==NULL) g_start = (const BYTE*)literals; - if ((pos > 1895000) && (pos < 1895300)) - DEBUGLOG(5, "Cpos %6u :%5u literals & match %3u bytes at distance %6u \n", - pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode); - } +#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6) + static const BYTE* g_start = NULL; + U32 const pos = (U32)((const BYTE*)literals - g_start); + if (g_start==NULL) g_start = (const BYTE*)literals; + if ((pos > 0) && (pos < 1000000000)) + DEBUGLOG(6, "Cpos %6u :%5u literals & match %3u bytes at distance %6u", + pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode); #endif /* copy Literals */ + assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + 128 KB); ZSTD_wildcopy(seqStorePtr->lit, literals, litLength); seqStorePtr->lit += litLength; @@ -1078,7 +1462,7 @@ static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls) { U32* const hashTable = zc->hashTable; - U32 const hBits = zc->params.cParams.hashLog; + U32 const hBits = zc->appliedParams.cParams.hashLog; const BYTE* const base = zc->base; const BYTE* ip = base + zc->nextToUpdate; const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; @@ -1097,7 +1481,7 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx, const U32 mls) { U32* const hashTable = cctx->hashTable; - U32 const hBits = cctx->params.cParams.hashLog; + U32 const hBits = cctx->appliedParams.cParams.hashLog; seqStore_t* seqStorePtr = &(cctx->seqStore); const BYTE* const base = cctx->base; const BYTE* const istart = (const BYTE*)src; @@ -1182,7 +1566,7 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx, static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - const U32 mls = ctx->params.cParams.searchLength; + const U32 mls = ctx->appliedParams.cParams.searchLength; switch(mls) { default: /* includes case 3 */ @@ -1203,7 +1587,7 @@ static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, const U32 mls) { U32* hashTable = ctx->hashTable; - const U32 hBits = ctx->params.cParams.hashLog; + const U32 hBits = ctx->appliedParams.cParams.hashLog; seqStore_t* seqStorePtr = &(ctx->seqStore); const BYTE* const base = ctx->base; const BYTE* const dictBase = ctx->dictBase; @@ -1296,7 +1680,7 @@ static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - U32 const mls = ctx->params.cParams.searchLength; + U32 const mls = ctx->appliedParams.cParams.searchLength; switch(mls) { default: /* includes case 3 */ @@ -1318,9 +1702,9 @@ static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls) { U32* const hashLarge = cctx->hashTable; - U32 const hBitsL = cctx->params.cParams.hashLog; + U32 const hBitsL = cctx->appliedParams.cParams.hashLog; U32* const hashSmall = cctx->chainTable; - U32 const hBitsS = cctx->params.cParams.chainLog; + U32 const hBitsS = cctx->appliedParams.cParams.chainLog; const BYTE* const base = cctx->base; const BYTE* ip = base + cctx->nextToUpdate; const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; @@ -1340,9 +1724,9 @@ void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx, const U32 mls) { U32* const hashLong = cctx->hashTable; - const U32 hBitsL = cctx->params.cParams.hashLog; + const U32 hBitsL = cctx->appliedParams.cParams.hashLog; U32* const hashSmall = cctx->chainTable; - const U32 hBitsS = cctx->params.cParams.chainLog; + const U32 hBitsS = cctx->appliedParams.cParams.chainLog; seqStore_t* seqStorePtr = &(cctx->seqStore); const BYTE* const base = cctx->base; const BYTE* const istart = (const BYTE*)src; @@ -1452,7 +1836,7 @@ void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx, static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - const U32 mls = ctx->params.cParams.searchLength; + const U32 mls = ctx->appliedParams.cParams.searchLength; switch(mls) { default: /* includes case 3 */ @@ -1473,9 +1857,9 @@ static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx, const U32 mls) { U32* const hashLong = ctx->hashTable; - U32 const hBitsL = ctx->params.cParams.hashLog; + U32 const hBitsL = ctx->appliedParams.cParams.hashLog; U32* const hashSmall = ctx->chainTable; - U32 const hBitsS = ctx->params.cParams.chainLog; + U32 const hBitsS = ctx->appliedParams.cParams.chainLog; seqStore_t* seqStorePtr = &(ctx->seqStore); const BYTE* const base = ctx->base; const BYTE* const dictBase = ctx->dictBase; @@ -1602,7 +1986,7 @@ static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx, static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - U32 const mls = ctx->params.cParams.searchLength; + U32 const mls = ctx->appliedParams.cParams.searchLength; switch(mls) { default: /* includes case 3 */ @@ -1628,10 +2012,10 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co U32 extDict) { U32* const hashTable = zc->hashTable; - U32 const hashLog = zc->params.cParams.hashLog; + U32 const hashLog = zc->appliedParams.cParams.hashLog; size_t const h = ZSTD_hashPtr(ip, hashLog, mls); U32* const bt = zc->chainTable; - U32 const btLog = zc->params.cParams.chainLog - 1; + U32 const btLog = zc->appliedParams.cParams.chainLog - 1; U32 const btMask = (1 << btLog) - 1; U32 matchIndex = hashTable[h]; size_t commonLengthSmaller=0, commonLengthLarger=0; @@ -1733,10 +2117,10 @@ static size_t ZSTD_insertBtAndFindBestMatch ( U32 extDict) { U32* const hashTable = zc->hashTable; - U32 const hashLog = zc->params.cParams.hashLog; + U32 const hashLog = zc->appliedParams.cParams.hashLog; size_t const h = ZSTD_hashPtr(ip, hashLog, mls); U32* const bt = zc->chainTable; - U32 const btLog = zc->params.cParams.chainLog - 1; + U32 const btLog = zc->appliedParams.cParams.chainLog - 1; U32 const btMask = (1 << btLog) - 1; U32 matchIndex = hashTable[h]; size_t commonLengthSmaller=0, commonLengthLarger=0; @@ -1896,9 +2280,9 @@ FORCE_INLINE U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls) { U32* const hashTable = zc->hashTable; - const U32 hashLog = zc->params.cParams.hashLog; + const U32 hashLog = zc->appliedParams.cParams.hashLog; U32* const chainTable = zc->chainTable; - const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1; + const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1; const BYTE* const base = zc->base; const U32 target = (U32)(ip - base); U32 idx = zc->nextToUpdate; @@ -1915,8 +2299,8 @@ U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls) } - -FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ +/* inlining is important to hardwire a hot branch (template emulation) */ +FORCE_INLINE size_t ZSTD_HcFindBestMatch_generic ( ZSTD_CCtx* zc, /* Index table will be updated */ const BYTE* const ip, const BYTE* const iLimit, @@ -1924,7 +2308,7 @@ size_t ZSTD_HcFindBestMatch_generic ( const U32 maxNbAttempts, const U32 mls, const U32 extDict) { U32* const chainTable = zc->chainTable; - const U32 chainSize = (1 << zc->params.cParams.chainLog); + const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog); const U32 chainMask = chainSize-1; const BYTE* const base = zc->base; const BYTE* const dictBase = zc->dictBase; @@ -2018,8 +2402,8 @@ void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, const BYTE* const ilimit = iend - 8; const BYTE* const base = ctx->base + ctx->dictLimit; - U32 const maxSearches = 1 << ctx->params.cParams.searchLog; - U32 const mls = ctx->params.cParams.searchLength; + U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog; + U32 const mls = ctx->appliedParams.cParams.searchLength; typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr, @@ -2101,15 +2485,19 @@ void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, break; /* nothing found : store previous solution */ } + /* NOTE: + * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior. + * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which + * overflows the pointer, which is undefined behavior. + */ /* catch up */ if (offset) { while ( (start > anchor) && (start > base+offset-ZSTD_REP_MOVE) - && (start[-1] == start[-1-offset+ZSTD_REP_MOVE]) ) /* only search for offset within prefix */ + && (start[-1] == (start-offset+ZSTD_REP_MOVE)[-1]) ) /* only search for offset within prefix */ { start--; matchLength++; } offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE); } - /* store sequence */ _storeSequence: { size_t const litLength = start - anchor; @@ -2182,8 +2570,8 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const dictStart = dictBase + ctx->lowLimit; - const U32 maxSearches = 1 << ctx->params.cParams.searchLog; - const U32 mls = ctx->params.cParams.searchLength; + const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog; + const U32 mls = ctx->appliedParams.cParams.searchLength; typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr, @@ -2370,7 +2758,7 @@ static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t src #endif } -static void ZSTD_compressBlock_btopt2(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { #ifdef ZSTD_OPT_H_91842398743 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1); @@ -2390,7 +2778,7 @@ static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, si #endif } -static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { #ifdef ZSTD_OPT_H_91842398743 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1); @@ -2401,26 +2789,32 @@ static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx* ctx, const void* src, s } +/* ZSTD_selectBlockCompressor() : + * assumption : strat is a valid strategy */ typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize); - static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict) { - static const ZSTD_blockCompressor blockCompressor[2][8] = { - { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, + static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = { + { ZSTD_compressBlock_fast /* default for 0 */, + ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, - ZSTD_compressBlock_btopt, ZSTD_compressBlock_btopt2 }, - { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict, + ZSTD_compressBlock_btopt, ZSTD_compressBlock_btultra }, + { ZSTD_compressBlock_fast_extDict /* default for 0 */, + ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, - ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btopt2_extDict } + ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict } }; + ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); + assert((U32)strat >= (U32)ZSTD_fast); + assert((U32)strat <= (U32)ZSTD_btultra); - return blockCompressor[extDict][(U32)strat]; + return blockCompressor[extDict!=0][(U32)strat]; } static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit); + ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, zc->lowLimit < zc->dictLimit); const BYTE* const base = zc->base; const BYTE* const istart = (const BYTE*)src; const U32 current = (U32)(istart-base); @@ -2433,14 +2827,14 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCa } -/*! ZSTD_compress_generic() : +/*! ZSTD_compress_frameChunk() : * Compress a chunk of data into one or multiple blocks. * All blocks will be terminated, all input will be consumed. * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content. * Frame is supposed already started (header already produced) * @return : compressed size, or an error code */ -static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, +static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastFrameChunk) @@ -2450,9 +2844,9 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, const BYTE* ip = (const BYTE*)src; BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; - U32 const maxDist = 1 << cctx->params.cParams.windowLog; + U32 const maxDist = 1 << cctx->appliedParams.cParams.windowLog; - if (cctx->params.fParams.checksumFlag && srcSize) + if (cctx->appliedParams.fParams.checksumFlag && srcSize) XXH64_update(&cctx->xxhState, src, srcSize); while (remaining) { @@ -2465,9 +2859,9 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, /* preemptive overflow correction */ if (cctx->lowLimit > (3U<<29)) { - U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1; + U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->appliedParams.cParams.hashLog, cctx->appliedParams.cParams.strategy)) - 1; U32 const current = (U32)(ip - cctx->base); - U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog); + U32 const newCurrent = (current & cycleMask) + (1 << cctx->appliedParams.cParams.windowLog); U32 const correction = current - newCurrent; ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30); ZSTD_reduceIndex(cctx, correction); @@ -2522,22 +2916,20 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize); BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3); U32 const fcsCode = params.fParams.contentSizeFlag ? - (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */ - 0; + (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */ BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) ); size_t pos; if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall); - DEBUGLOG(5, "ZSTD_writeFrameHeader : dictIDFlag : %u \n", !params.fParams.noDictIDFlag); - DEBUGLOG(5, "ZSTD_writeFrameHeader : dictID : %u \n", dictID); - DEBUGLOG(5, "ZSTD_writeFrameHeader : dictIDSizeCode : %u \n", dictIDSizeCode); + DEBUGLOG(5, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u", + !params.fParams.noDictIDFlag, dictID, dictIDSizeCode); MEM_writeLE32(dst, ZSTD_MAGICNUMBER); op[4] = frameHeaderDecriptionByte; pos=5; if (!singleSegment) op[pos++] = windowLogByte; switch(dictIDSizeCode) { - default: /* impossible */ + default: assert(0); /* impossible */ case 0 : break; case 1 : op[pos] = (BYTE)(dictID); pos++; break; case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break; @@ -2545,7 +2937,7 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, } switch(fcsCode) { - default: /* impossible */ + default: assert(0); /* impossible */ case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break; case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break; case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break; @@ -2563,10 +2955,13 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, const BYTE* const ip = (const BYTE*) src; size_t fhSize = 0; + DEBUGLOG(5, "ZSTD_compressContinue_internal"); + DEBUGLOG(5, "stage: %u", cctx->stage); if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */ if (frame && (cctx->stage==ZSTDcs_init)) { - fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID); + fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, + cctx->pledgedSrcSizePlusOne-1, cctx->dictID); if (ZSTD_isError(fhSize)) return fhSize; dstCapacity -= fhSize; dst = (char*)dst + fhSize; @@ -2596,7 +2991,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, if (srcSize) { size_t const cSize = frame ? - ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) : + ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) : ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize); if (ZSTD_isError(cSize)) return cSize; cctx->consumedSrcSize += srcSize; @@ -2614,14 +3009,18 @@ size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, } -size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx) +size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) { - return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog); + U32 const cLevel = cctx->compressionLevel; + ZSTD_compressionParameters cParams = (cLevel == ZSTD_CLEVEL_CUSTOM) ? + cctx->appliedParams.cParams : + ZSTD_getCParams(cLevel, 0, 0); + return MIN (ZSTD_BLOCKSIZE_MAX, 1 << cParams.windowLog); } size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx); + size_t const blockSizeMax = ZSTD_getBlockSize(cctx); if (srcSize > blockSizeMax) return ERROR(srcSize_wrong); return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */); } @@ -2645,32 +3044,32 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t zc->nextSrc = iend; if (srcSize <= HASH_READ_SIZE) return 0; - switch(zc->params.cParams.strategy) + switch(zc->appliedParams.cParams.strategy) { case ZSTD_fast: - ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength); + ZSTD_fillHashTable (zc, iend, zc->appliedParams.cParams.searchLength); break; case ZSTD_dfast: - ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength); + ZSTD_fillDoubleHashTable (zc, iend, zc->appliedParams.cParams.searchLength); break; case ZSTD_greedy: case ZSTD_lazy: case ZSTD_lazy2: if (srcSize >= HASH_READ_SIZE) - ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength); + ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->appliedParams.cParams.searchLength); break; case ZSTD_btlazy2: case ZSTD_btopt: - case ZSTD_btopt2: + case ZSTD_btultra: if (srcSize >= HASH_READ_SIZE) - ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength); + ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->appliedParams.cParams.searchLog, zc->appliedParams.cParams.searchLength); break; default: - return ERROR(GENERIC); /* strategy doesn't exist; impossible */ + assert(0); /* not possible : not a valid strategy id */ } zc->nextToUpdate = (U32)(iend - zc->base); @@ -2710,7 +3109,7 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)]; dictPtr += 4; /* skip magic number */ - cctx->dictID = cctx->params.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr); + cctx->dictID = cctx->appliedParams.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr); dictPtr += 4; { size_t const hufHeaderSize = HUF_readCTable(cctx->hufCTable, 255, dictPtr, dictEnd-dictPtr); @@ -2781,28 +3180,56 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t /** ZSTD_compress_insertDictionary() : * @return : 0, or an error code */ -static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) +static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx, + const void* dict, size_t dictSize, + ZSTD_dictMode_e dictMode) { + DEBUGLOG(5, "ZSTD_compress_insertDictionary"); if ((dict==NULL) || (dictSize<=8)) return 0; - /* dict as pure content */ - if ((MEM_readLE32(dict) != ZSTD_DICT_MAGIC) || (cctx->forceRawDict)) + /* dict restricted modes */ + if (dictMode==ZSTD_dm_rawContent) return ZSTD_loadDictionaryContent(cctx, dict, dictSize); - /* dict as zstd dictionary */ + if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { + if (dictMode == ZSTD_dm_auto) { + DEBUGLOG(5, "raw content dictionary detected"); + return ZSTD_loadDictionaryContent(cctx, dict, dictSize); + } + if (dictMode == ZSTD_dm_fullDict) + return ERROR(dictionary_wrong); + assert(0); /* impossible */ + } + + /* dict as full zstd dictionary */ return ZSTD_loadZstdDictionary(cctx, dict, dictSize); } /*! ZSTD_compressBegin_internal() : -* @return : 0, or an error code */ + * @return : 0, or an error code */ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, - ZSTD_parameters params, U64 pledgedSrcSize) + ZSTD_dictMode_e dictMode, + const ZSTD_CDict* cdict, + ZSTD_parameters params, U64 pledgedSrcSize, + ZSTD_buffered_policy_e zbuff) { - ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue; + DEBUGLOG(4, "ZSTD_compressBegin_internal"); + DEBUGLOG(4, "dict ? %s", dict ? "dict" : (cdict ? "cdict" : "none")); + DEBUGLOG(4, "dictMode : %u", (U32)dictMode); + /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); - CHECK_F(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, crp)); - return ZSTD_compress_insertDictionary(cctx, dict, dictSize); + assert(!((dict) && (cdict))); /* either dict or cdict, not both */ + + if (cdict && cdict->dictContentSize>0) { + return ZSTD_copyCCtx_internal(cctx, cdict->refContext, + params.fParams, pledgedSrcSize, + zbuff); + } + + CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, + ZSTDcrp_continue, zbuff) ); + return ZSTD_compress_insertDictionary(cctx, dict, dictSize, dictMode); } @@ -2814,14 +3241,16 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, { /* compression parameters verification and optimization */ CHECK_F(ZSTD_checkCParams(params.cParams)); - return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize); + return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL, + params, pledgedSrcSize, ZSTDb_not_buffered); } size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) { ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); - return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0); + return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL, + params, 0, ZSTDb_not_buffered); } @@ -2840,11 +3269,12 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) BYTE* op = ostart; size_t fhSize = 0; + DEBUGLOG(5, "ZSTD_writeEpilogue"); if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */ /* special case : empty frame */ if (cctx->stage == ZSTDcs_init) { - fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0); + fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0); if (ZSTD_isError(fhSize)) return fhSize; dstCapacity -= fhSize; op += fhSize; @@ -2860,7 +3290,7 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) dstCapacity -= ZSTD_blockHeaderSize; } - if (cctx->params.fParams.checksumFlag) { + if (cctx->appliedParams.fParams.checksumFlag) { U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); if (dstCapacity<4) return ERROR(dstSize_tooSmall); MEM_writeLE32(op, checksum); @@ -2877,13 +3307,19 @@ size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, const void* src, size_t srcSize) { size_t endResult; - size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 1 /* last chunk */); + size_t const cSize = ZSTD_compressContinue_internal(cctx, + dst, dstCapacity, src, srcSize, + 1 /* frame mode */, 1 /* last chunk */); if (ZSTD_isError(cSize)) return cSize; endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize); if (ZSTD_isError(endResult)) return endResult; - if (cctx->params.fParams.contentSizeFlag) { /* control src size */ - if (cctx->frameContentSize != cctx->consumedSrcSize) return ERROR(srcSize_wrong); - } + if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */ + DEBUGLOG(5, "end of frame : controlling src size"); + if (cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1) { + DEBUGLOG(5, "error : pledgedSrcSize = %u, while realSrcSize = %u", + (U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize); + return ERROR(srcSize_wrong); + } } return cSize + endResult; } @@ -2894,7 +3330,8 @@ static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, const void* dict,size_t dictSize, ZSTD_parameters params) { - CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize)); + CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL, + params, srcSize, ZSTDb_not_buffered) ); return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); } @@ -2926,25 +3363,36 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcS size_t result; ZSTD_CCtx ctxBody; memset(&ctxBody, 0, sizeof(ctxBody)); - memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem)); + ctxBody.customMem = ZSTD_defaultCMem; result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); - ZSTD_free(ctxBody.workSpace, defaultCustomMem); /* can't free ctxBody itself, as it's on stack; free only heap content */ + ZSTD_free(ctxBody.workSpace, ZSTD_defaultCMem); /* can't free ctxBody itself, as it's on stack; free only heap content */ return result; } /* ===== Dictionary API ===== */ -struct ZSTD_CDict_s { - void* dictBuffer; - const void* dictContent; - size_t dictContentSize; - ZSTD_CCtx* refContext; -}; /* typedef'd tp ZSTD_CDict within "zstd.h" */ +/*! ZSTD_estimateCDictSize_advanced() : + * Estimate amount of memory that will be needed to create a dictionary with following arguments */ +size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference) +{ + DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict)); + DEBUGLOG(5, "CCtx estimate : %u", (U32)ZSTD_estimateCCtxSize_advanced(cParams)); + return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced(cParams) + + (byReference ? 0 : dictSize); +} + +size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) +{ + ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); + return ZSTD_estimateCDictSize_advanced(dictSize, cParams, 0); +} size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) { if (cdict==NULL) return 0; /* support sizeof on NULL */ + DEBUGLOG(5, "sizeof(*cdict) : %u", (U32)sizeof(*cdict)); + DEBUGLOG(5, "ZSTD_sizeof_CCtx : %u", (U32)ZSTD_sizeof_CCtx(cdict->refContext)); return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict); } @@ -2956,13 +3404,46 @@ static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_ return params; } -ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference, +static size_t ZSTD_initCDict_internal( + ZSTD_CDict* cdict, + const void* dictBuffer, size_t dictSize, + unsigned byReference, ZSTD_dictMode_e dictMode, + ZSTD_compressionParameters cParams) +{ + DEBUGLOG(5, "ZSTD_initCDict_internal, mode %u", (U32)dictMode); + if ((byReference) || (!dictBuffer) || (!dictSize)) { + cdict->dictBuffer = NULL; + cdict->dictContent = dictBuffer; + } else { + void* const internalBuffer = ZSTD_malloc(dictSize, cdict->refContext->customMem); + cdict->dictBuffer = internalBuffer; + cdict->dictContent = internalBuffer; + if (!internalBuffer) return ERROR(memory_allocation); + memcpy(internalBuffer, dictBuffer, dictSize); + } + cdict->dictContentSize = dictSize; + + { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, + 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */ + ZSTD_parameters const params = ZSTD_makeParams(cParams, fParams); + CHECK_F( ZSTD_compressBegin_internal(cdict->refContext, + cdict->dictContent, dictSize, dictMode, + NULL, + params, ZSTD_CONTENTSIZE_UNKNOWN, + ZSTDb_not_buffered) ); + } + + return 0; +} + +ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, + unsigned byReference, ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams, ZSTD_customMem customMem) { - if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem; - if (!customMem.customAlloc || !customMem.customFree) return NULL; + DEBUGLOG(5, "ZSTD_createCDict_advanced, mode %u", (U32)dictMode); + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem); + { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem); if (!cdict || !cctx) { @@ -2970,46 +3451,34 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, u ZSTD_freeCCtx(cctx); return NULL; } + cdict->refContext = cctx; - if ((byReference) || (!dictBuffer) || (!dictSize)) { - cdict->dictBuffer = NULL; - cdict->dictContent = dictBuffer; - } else { - void* const internalBuffer = ZSTD_malloc(dictSize, customMem); - if (!internalBuffer) { ZSTD_free(cctx, customMem); ZSTD_free(cdict, customMem); return NULL; } - memcpy(internalBuffer, dictBuffer, dictSize); - cdict->dictBuffer = internalBuffer; - cdict->dictContent = internalBuffer; + if (ZSTD_isError( ZSTD_initCDict_internal(cdict, + dictBuffer, dictSize, + byReference, dictMode, + cParams) )) { + ZSTD_freeCDict(cdict); + return NULL; } - { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */ - ZSTD_parameters const params = ZSTD_makeParams(cParams, fParams); - size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0); - if (ZSTD_isError(errorCode)) { - ZSTD_free(cdict->dictBuffer, customMem); - ZSTD_free(cdict, customMem); - ZSTD_freeCCtx(cctx); - return NULL; - } } - - cdict->refContext = cctx; - cdict->dictContentSize = dictSize; return cdict; } } ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_customMem const allocator = { NULL, NULL, NULL }; ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); - return ZSTD_createCDict_advanced(dict, dictSize, 0, cParams, allocator); + return ZSTD_createCDict_advanced(dict, dictSize, + 0 /* byReference */, ZSTD_dm_auto, + cParams, ZSTD_defaultCMem); } ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_customMem const allocator = { NULL, NULL, NULL }; ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); - return ZSTD_createCDict_advanced(dict, dictSize, 1, cParams, allocator); + return ZSTD_createCDict_advanced(dict, dictSize, + 1 /* byReference */, ZSTD_dm_auto, + cParams, ZSTD_defaultCMem); } size_t ZSTD_freeCDict(ZSTD_CDict* cdict) @@ -3023,7 +3492,54 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) } } -static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) { +/*! ZSTD_initStaticCDict_advanced() : + * Generate a digested dictionary in provided memory area. + * workspace: The memory area to emplace the dictionary into. + * Provided pointer must 8-bytes aligned. + * It must outlive dictionary usage. + * workspaceSize: Use ZSTD_estimateCDictSize() + * to determine how large workspace must be. + * cParams : use ZSTD_getCParams() to transform a compression level + * into its relevants cParams. + * @return : pointer to ZSTD_CDict*, or NULL if error (size too small) + * Note : there is no corresponding "free" function. + * Since workspace was allocated externally, it must be freed externally. + */ +ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + unsigned byReference, ZSTD_dictMode_e dictMode, + ZSTD_compressionParameters cParams) +{ + size_t const cctxSize = ZSTD_estimateCCtxSize_advanced(cParams); + size_t const neededSize = sizeof(ZSTD_CDict) + (byReference ? 0 : dictSize) + + cctxSize; + ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; + void* ptr; + DEBUGLOG(5, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7); + if ((size_t)workspace & 7) return NULL; /* 8-aligned */ + DEBUGLOG(5, "(workspaceSize < neededSize) : (%u < %u) => %u", + (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize)); + if (workspaceSize < neededSize) return NULL; + + if (!byReference) { + memcpy(cdict+1, dict, dictSize); + dict = cdict+1; + ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize; + } else { + ptr = cdict+1; + } + cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize); + + if (ZSTD_isError( ZSTD_initCDict_internal(cdict, + dict, dictSize, + 1 /* byReference */, dictMode, + cParams) )) + return NULL; + + return cdict; +} + +ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) { return ZSTD_getParamsFromCCtx(cdict->refContext); } @@ -3033,16 +3549,16 @@ size_t ZSTD_compressBegin_usingCDict_advanced( ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) { - if (cdict==NULL) return ERROR(GENERIC); /* does not support NULL cdict */ - DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced : dictIDFlag == %u \n", !fParams.noDictIDFlag); - if (cdict->dictContentSize) - CHECK_F( ZSTD_copyCCtx_internal(cctx, cdict->refContext, fParams, pledgedSrcSize) ) - else { - ZSTD_parameters params = cdict->refContext->params; + if (cdict==NULL) return ERROR(dictionary_wrong); + { ZSTD_parameters params = cdict->refContext->appliedParams; params.fParams = fParams; - CHECK_F(ZSTD_compressBegin_internal(cctx, NULL, 0, params, pledgedSrcSize)); + DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced"); + return ZSTD_compressBegin_internal(cctx, + NULL, 0, ZSTD_dm_auto, + cdict, + params, pledgedSrcSize, + ZSTDb_not_buffered); } - return 0; } /* ZSTD_compressBegin_usingCDict() : @@ -3051,7 +3567,7 @@ size_t ZSTD_compressBegin_usingCDict_advanced( size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; - DEBUGLOG(5, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u \n", !fParams.noDictIDFlag); + DEBUGLOG(5, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag); return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0); } @@ -3084,176 +3600,133 @@ size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, * Streaming ********************************************************************/ -typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage; - -struct ZSTD_CStream_s { - ZSTD_CCtx* cctx; - ZSTD_CDict* cdictLocal; - const ZSTD_CDict* cdict; - char* inBuff; - size_t inBuffSize; - size_t inToCompress; - size_t inBuffPos; - size_t inBuffTarget; - size_t blockSize; - char* outBuff; - size_t outBuffSize; - size_t outBuffContentSize; - size_t outBuffFlushedSize; - ZSTD_cStreamStage stage; - U32 checksum; - U32 frameEnded; - U64 pledgedSrcSize; - ZSTD_parameters params; - ZSTD_customMem customMem; -}; /* typedef'd to ZSTD_CStream within "zstd.h" */ - ZSTD_CStream* ZSTD_createCStream(void) { - return ZSTD_createCStream_advanced(defaultCustomMem); + return ZSTD_createCStream_advanced(ZSTD_defaultCMem); } -ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem) +ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize) { - ZSTD_CStream* zcs; - - if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem; - if (!customMem.customAlloc || !customMem.customFree) return NULL; + return ZSTD_initStaticCCtx(workspace, workspaceSize); +} - zcs = (ZSTD_CStream*)ZSTD_malloc(sizeof(ZSTD_CStream), customMem); - if (zcs==NULL) return NULL; - memset(zcs, 0, sizeof(ZSTD_CStream)); - memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem)); - zcs->cctx = ZSTD_createCCtx_advanced(customMem); - if (zcs->cctx == NULL) { ZSTD_freeCStream(zcs); return NULL; } - return zcs; +ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem) +{ /* CStream and CCtx are now same object */ + return ZSTD_createCCtx_advanced(customMem); } size_t ZSTD_freeCStream(ZSTD_CStream* zcs) { - if (zcs==NULL) return 0; /* support free on NULL */ - { ZSTD_customMem const cMem = zcs->customMem; - ZSTD_freeCCtx(zcs->cctx); - zcs->cctx = NULL; - ZSTD_freeCDict(zcs->cdictLocal); - zcs->cdictLocal = NULL; - ZSTD_free(zcs->inBuff, cMem); - zcs->inBuff = NULL; - ZSTD_free(zcs->outBuff, cMem); - zcs->outBuff = NULL; - ZSTD_free(zcs, cMem); - return 0; - } + return ZSTD_freeCCtx(zcs); /* same object */ } + /*====== Initialization ======*/ -size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; } +size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; } size_t ZSTD_CStreamOutSize(void) { - return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; + return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; } -static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) +static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, + const ZSTD_CDict* cdict, + ZSTD_parameters params, unsigned long long pledgedSrcSize) { - if (zcs->inBuffSize==0) return ERROR(stage_wrong); /* zcs has not been init at least once => can't reset */ - - DEBUGLOG(5, "ZSTD_resetCStream_internal : dictIDFlag == %u \n", !zcs->params.fParams.noDictIDFlag); + DEBUGLOG(4, "ZSTD_resetCStream_internal"); + /* params are supposed to be fully validated at this point */ + assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + assert(!((dict) && (cdict))); /* either dict or cdict, not both */ - if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict_advanced(zcs->cctx, zcs->cdict, zcs->params.fParams, pledgedSrcSize)) - else CHECK_F(ZSTD_compressBegin_internal(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize)); + CHECK_F( ZSTD_compressBegin_internal(zcs, + dict, dictSize, dictMode, + cdict, + params, pledgedSrcSize, + ZSTDb_buffered) ); zcs->inToCompress = 0; zcs->inBuffPos = 0; zcs->inBuffTarget = zcs->blockSize; zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; - zcs->stage = zcss_load; + zcs->streamStage = zcss_load; zcs->frameEnded = 0; - zcs->pledgedSrcSize = pledgedSrcSize; return 0; /* ready to go */ } size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) { - - zcs->params.fParams.contentSizeFlag = (pledgedSrcSize > 0); - DEBUGLOG(5, "ZSTD_resetCStream : dictIDFlag == %u \n", !zcs->params.fParams.noDictIDFlag); - return ZSTD_resetCStream_internal(zcs, pledgedSrcSize); + ZSTD_parameters params = zcs->requestedParams; + params.fParams.contentSizeFlag = (pledgedSrcSize > 0); + DEBUGLOG(5, "ZSTD_resetCStream"); + if (zcs->compressionLevel != ZSTD_CLEVEL_CUSTOM) { + params.cParams = ZSTD_getCParams(zcs->compressionLevel, pledgedSrcSize, 0 /* dictSize */); + } + return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->dictMode, zcs->cdict, params, pledgedSrcSize); } -/* ZSTD_initCStream_internal() : - * params are supposed validated at this stage - * and zcs->cdict is supposed to be correct */ -static size_t ZSTD_initCStream_stage2(ZSTD_CStream* zcs, - const ZSTD_parameters params, - unsigned long long pledgedSrcSize) +/*! ZSTD_initCStream_internal() : + * Note : not static, but hidden (not exposed). Used by zstdmt_compress.c + * Assumption 1 : params are valid + * Assumption 2 : either dict, or cdict, is defined, not both */ +size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, const ZSTD_CDict* cdict, + ZSTD_parameters params, unsigned long long pledgedSrcSize) { + DEBUGLOG(5, "ZSTD_initCStream_internal"); assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + assert(!((dict) && (cdict))); /* either dict or cdict, not both */ - /* allocate buffers */ - { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog; - if (zcs->inBuffSize < neededInBuffSize) { - zcs->inBuffSize = 0; - ZSTD_free(zcs->inBuff, zcs->customMem); - zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem); - if (zcs->inBuff == NULL) return ERROR(memory_allocation); - zcs->inBuffSize = neededInBuffSize; + if (dict && dictSize >= 8) { + DEBUGLOG(5, "loading dictionary of size %u", (U32)dictSize); + if (zcs->staticSize) { /* static CCtx : never uses malloc */ + /* incompatible with internal cdict creation */ + return ERROR(memory_allocation); } - zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize); - } - if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) { - size_t const outBuffSize = ZSTD_compressBound(zcs->blockSize)+1; - zcs->outBuffSize = 0; - ZSTD_free(zcs->outBuff, zcs->customMem); - zcs->outBuff = (char*) ZSTD_malloc(outBuffSize, zcs->customMem); - if (zcs->outBuff == NULL) return ERROR(memory_allocation); - zcs->outBuffSize = outBuffSize; + ZSTD_freeCDict(zcs->cdictLocal); + zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, + zcs->dictContentByRef, zcs->dictMode, + params.cParams, zcs->customMem); + zcs->cdict = zcs->cdictLocal; + if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); + } else { + if (cdict) { + ZSTD_parameters const cdictParams = ZSTD_getParamsFromCDict(cdict); + params.cParams = cdictParams.cParams; /* cParams are enforced from cdict */ + } + ZSTD_freeCDict(zcs->cdictLocal); + zcs->cdictLocal = NULL; + zcs->cdict = cdict; } - zcs->checksum = params.fParams.checksumFlag > 0; - zcs->params = params; - - DEBUGLOG(5, "ZSTD_initCStream_stage2 : dictIDFlag == %u \n", !params.fParams.noDictIDFlag); - return ZSTD_resetCStream_internal(zcs, pledgedSrcSize); + zcs->requestedParams = params; + zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM; + return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->dictMode, zcs->cdict, params, pledgedSrcSize); } /* ZSTD_initCStream_usingCDict_advanced() : * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */ -size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize, ZSTD_frameParameters fParams) -{ - if (!cdict) return ERROR(GENERIC); /* cannot handle NULL cdict (does not know what to do) */ +size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fParams, + unsigned long long pledgedSrcSize) +{ /* cannot handle NULL cdict (does not know what to do) */ + if (!cdict) return ERROR(dictionary_wrong); { ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict); params.fParams = fParams; - zcs->cdict = cdict; - return ZSTD_initCStream_stage2(zcs, params, pledgedSrcSize); + return ZSTD_initCStream_internal(zcs, + NULL, 0, cdict, + params, pledgedSrcSize); } } /* note : cdict must outlive compression session */ size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict) { - ZSTD_frameParameters const fParams = { 0 /* content */, 0 /* checksum */, 0 /* noDictID */ }; - return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, 0, fParams); -} - -static size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, - const void* dict, size_t dictSize, - ZSTD_parameters params, unsigned long long pledgedSrcSize) -{ - assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); - zcs->cdict = NULL; - - if (dict && dictSize >= 8) { - ZSTD_freeCDict(zcs->cdictLocal); - zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0 /* copy */, params.cParams, zcs->customMem); - if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); - zcs->cdict = zcs->cdictLocal; - } - - DEBUGLOG(5, "ZSTD_initCStream_internal : dictIDFlag == %u \n", !params.fParams.noDictIDFlag); - return ZSTD_initCStream_stage2(zcs, params, pledgedSrcSize); + ZSTD_frameParameters const fParams = { 0 /* contentSize */, 0 /* checksum */, 0 /* hideDictID */ }; + return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, 0); /* note : will check that cdict != NULL */ } size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, @@ -3261,120 +3734,180 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, ZSTD_parameters params, unsigned long long pledgedSrcSize) { CHECK_F( ZSTD_checkCParams(params.cParams) ); - DEBUGLOG(5, "ZSTD_initCStream_advanced : dictIDFlag == %u \n", !params.fParams.noDictIDFlag); - return ZSTD_initCStream_internal(zcs, dict, dictSize, params, pledgedSrcSize); + zcs->requestedParams = params; + zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM; + return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, pledgedSrcSize); } size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) { ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); - return ZSTD_initCStream_internal(zcs, dict, dictSize, params, 0); + zcs->compressionLevel = compressionLevel; + return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, 0); } size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize) { ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0); params.fParams.contentSizeFlag = (pledgedSrcSize>0); - return ZSTD_initCStream_internal(zcs, NULL, 0, params, pledgedSrcSize); + return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, params, pledgedSrcSize); } size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) { ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0); - return ZSTD_initCStream_internal(zcs, NULL, 0, params, 0); -} - -size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) -{ - if (zcs==NULL) return 0; /* support sizeof on NULL */ - return sizeof(*zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + ZSTD_sizeof_CDict(zcs->cdictLocal) + zcs->outBuffSize + zcs->inBuffSize; + return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, params, 0); } /*====== Compression ======*/ -typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e; - -MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) +MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, + const void* src, size_t srcSize) { size_t const length = MIN(dstCapacity, srcSize); - memcpy(dst, src, length); + if (length) memcpy(dst, src, length); return length; } -static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, - void* dst, size_t* dstCapacityPtr, - const void* src, size_t* srcSizePtr, - ZSTD_flush_e const flush) +/** ZSTD_compressStream_generic(): + * internal function for all *compressStream*() variants and *compress_generic() + * @return : hint size for next input */ +size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input, + ZSTD_EndDirective const flushMode) { + const char* const istart = (const char*)input->src; + const char* const iend = istart + input->size; + const char* ip = istart + input->pos; + char* const ostart = (char*)output->dst; + char* const oend = ostart + output->size; + char* op = ostart + output->pos; U32 someMoreWork = 1; - const char* const istart = (const char*)src; - const char* const iend = istart + *srcSizePtr; - const char* ip = istart; - char* const ostart = (char*)dst; - char* const oend = ostart + *dstCapacityPtr; - char* op = ostart; + + /* check expectations */ + DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (U32)flushMode); + assert(zcs->inBuff != NULL); + assert(zcs->inBuffSize>0); + assert(zcs->outBuff!= NULL); + assert(zcs->outBuffSize>0); + assert(output->pos <= output->size); + assert(input->pos <= input->size); while (someMoreWork) { - switch(zcs->stage) + switch(zcs->streamStage) { - case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */ + case zcss_init: + /* call ZSTD_initCStream() first ! */ + return ERROR(init_missing); case zcss_load: - /* complete inBuffer */ + if ( (flushMode == ZSTD_e_end) + && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */ + && (zcs->inBuffPos == 0) ) { + /* shortcut to compression pass directly into output buffer */ + size_t const cSize = ZSTD_compressEnd(zcs, + op, oend-op, ip, iend-ip); + DEBUGLOG(4, "ZSTD_compressEnd : %u", (U32)cSize); + if (ZSTD_isError(cSize)) return cSize; + ip = iend; + op += cSize; + zcs->frameEnded = 1; + ZSTD_startNewCompression(zcs); + someMoreWork = 0; break; + } + /* complete loading into inBuffer */ { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; - size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip); + size_t const loaded = ZSTD_limitCopy( + zcs->inBuff + zcs->inBuffPos, toLoad, + ip, iend-ip); zcs->inBuffPos += loaded; ip += loaded; - if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) { - someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */ - } } + if ( (flushMode == ZSTD_e_continue) + && (zcs->inBuffPos < zcs->inBuffTarget) ) { + /* not enough input to fill full block : stop here */ + someMoreWork = 0; break; + } + if ( (flushMode == ZSTD_e_flush) + && (zcs->inBuffPos == zcs->inToCompress) ) { + /* empty */ + someMoreWork = 0; break; + } + } /* compress current block (note : this stage cannot be stopped in the middle) */ + DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode); { void* cDst; size_t cSize; size_t const iSize = zcs->inBuffPos - zcs->inToCompress; size_t oSize = oend-op; + unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); if (oSize >= ZSTD_compressBound(iSize)) - cDst = op; /* compress directly into output buffer (avoid flush stage) */ + cDst = op; /* compress into output buffer, to skip flush stage */ else cDst = zcs->outBuff, oSize = zcs->outBuffSize; - cSize = (flush == zsf_end) ? - ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) : - ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize); + cSize = lastBlock ? + ZSTD_compressEnd(zcs, cDst, oSize, + zcs->inBuff + zcs->inToCompress, iSize) : + ZSTD_compressContinue(zcs, cDst, oSize, + zcs->inBuff + zcs->inToCompress, iSize); if (ZSTD_isError(cSize)) return cSize; - if (flush == zsf_end) zcs->frameEnded = 1; + zcs->frameEnded = lastBlock; /* prepare next block */ zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; if (zcs->inBuffTarget > zcs->inBuffSize) - zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */ + zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; + DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", + (U32)zcs->inBuffTarget, (U32)zcs->inBuffSize); + if (!lastBlock) + assert(zcs->inBuffTarget <= zcs->inBuffSize); zcs->inToCompress = zcs->inBuffPos; - if (cDst == op) { op += cSize; break; } /* no need to flush */ + if (cDst == op) { /* no need to flush */ + op += cSize; + if (zcs->frameEnded) { + DEBUGLOG(5, "Frame completed directly in outBuffer"); + someMoreWork = 0; + ZSTD_startNewCompression(zcs); + } + break; + } zcs->outBuffContentSize = cSize; zcs->outBuffFlushedSize = 0; - zcs->stage = zcss_flush; /* pass-through to flush stage */ + zcs->streamStage = zcss_flush; /* pass-through to flush stage */ } - + /* fall-through */ case zcss_flush: + DEBUGLOG(5, "flush stage"); { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; - size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush); + size_t const flushed = ZSTD_limitCopy(op, oend-op, + zcs->outBuff + zcs->outBuffFlushedSize, toFlush); + DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u", + (U32)toFlush, (U32)(oend-op), (U32)flushed); op += flushed; zcs->outBuffFlushedSize += flushed; - if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */ + if (toFlush!=flushed) { + /* flush not fully completed, presumably because dst is too small */ + assert(op==oend); + someMoreWork = 0; + break; + } zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; - zcs->stage = zcss_load; + if (zcs->frameEnded) { + DEBUGLOG(5, "Frame completed on flush"); + someMoreWork = 0; + ZSTD_startNewCompression(zcs); + break; + } + zcs->streamStage = zcss_load; break; } - case zcss_final: - someMoreWork = 0; /* do nothing */ - break; - - default: - return ERROR(GENERIC); /* impossible */ + default: /* impossible */ + assert(0); } } - *srcSizePtr = ip - istart; - *dstCapacityPtr = op - ostart; + input->pos = ip - istart; + output->pos = op - ostart; if (zcs->frameEnded) return 0; { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos; if (hintInSize==0) hintInSize = zcs->blockSize; @@ -3384,14 +3917,86 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input) { - size_t sizeRead = input->size - input->pos; - size_t sizeWritten = output->size - output->pos; - size_t const result = ZSTD_compressStream_generic(zcs, - (char*)(output->dst) + output->pos, &sizeWritten, - (const char*)(input->src) + input->pos, &sizeRead, zsf_gather); - input->pos += sizeRead; - output->pos += sizeWritten; - return result; + /* check conditions */ + if (output->pos > output->size) return ERROR(GENERIC); + if (input->pos > input->size) return ERROR(GENERIC); + + return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue); +} + +/*! ZSTDMT_initCStream_internal() : + * Private use only. Init streaming operation. + * expects params to be valid. + * must receive dict, or cdict, or none, but not both. + * @return : 0, or an error code */ +size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, + const void* dict, size_t dictSize, const ZSTD_CDict* cdict, + ZSTD_parameters params, unsigned long long pledgedSrcSize); + + +size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input, + ZSTD_EndDirective endOp) +{ + /* check conditions */ + if (output->pos > output->size) return ERROR(GENERIC); + if (input->pos > input->size) return ERROR(GENERIC); + assert(cctx!=NULL); + + /* transparent initialization stage */ + if (cctx->streamStage == zcss_init) { + const void* const prefix = cctx->prefix; + size_t const prefixSize = cctx->prefixSize; + ZSTD_parameters params = cctx->requestedParams; + if (cctx->compressionLevel != ZSTD_CLEVEL_CUSTOM) + params.cParams = ZSTD_getCParams(cctx->compressionLevel, + cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); + cctx->prefix = NULL; cctx->prefixSize = 0; /* single usage */ + assert(prefix==NULL || cctx->cdict==NULL); /* only one can be set */ + +#ifdef ZSTD_MULTITHREAD + if (cctx->nbThreads > 1) { + DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", cctx->nbThreads); + CHECK_F( ZSTDMT_initCStream_internal(cctx->mtctx, prefix, prefixSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); + cctx->streamStage = zcss_load; + } else +#endif + { + CHECK_F( ZSTD_resetCStream_internal(cctx, prefix, prefixSize, cctx->dictMode, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); + } } + + /* compression stage */ +#ifdef ZSTD_MULTITHREAD + if (cctx->nbThreads > 1) { + size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); + DEBUGLOG(5, "ZSTDMT_compressStream_generic : %u", (U32)flushMin); + if ( ZSTD_isError(flushMin) + || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ + ZSTD_startNewCompression(cctx); + } + return flushMin; + } +#endif + + CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) ); + DEBUGLOG(5, "completed ZSTD_compress_generic"); + return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */ +} + +size_t ZSTD_compress_generic_simpleArgs ( + ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos, + ZSTD_EndDirective endOp) +{ + ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; + ZSTD_inBuffer input = { src, srcSize, *srcPos }; + /* ZSTD_compress_generic() will check validity of dstPos and srcPos */ + size_t const cErr = ZSTD_compress_generic(cctx, &output, &input, endOp); + *dstPos = output.pos; + *srcPos = input.pos; + return cErr; } @@ -3401,89 +4006,59 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf * @return : amount of data remaining to flush */ size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) { - size_t srcSize = 0; - size_t sizeWritten = output->size - output->pos; - size_t const result = ZSTD_compressStream_generic(zcs, - (char*)(output->dst) + output->pos, &sizeWritten, - &srcSize, &srcSize, /* use a valid src address instead of NULL */ - zsf_flush); - output->pos += sizeWritten; - if (ZSTD_isError(result)) return result; - return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */ + ZSTD_inBuffer input = { NULL, 0, 0 }; + if (output->pos > output->size) return ERROR(GENERIC); + CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_flush) ); + return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */ } size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) { - BYTE* const ostart = (BYTE*)(output->dst) + output->pos; - BYTE* const oend = (BYTE*)(output->dst) + output->size; - BYTE* op = ostart; - - if (zcs->stage != zcss_final) { - /* flush whatever remains */ - size_t srcSize = 0; - size_t sizeWritten = output->size - output->pos; - size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, - &srcSize /* use a valid src address instead of NULL */, &srcSize, zsf_end); - size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; - op += sizeWritten; - if (remainingToFlush) { - output->pos += sizeWritten; - return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */ + (zcs->checksum * 4); - } - /* create epilogue */ - zcs->stage = zcss_final; - zcs->outBuffContentSize = !notEnded ? 0 : - /* write epilogue, including final empty block, into outBuff */ - ZSTD_compressEnd(zcs->cctx, zcs->outBuff, zcs->outBuffSize, NULL, 0); - if (ZSTD_isError(zcs->outBuffContentSize)) return zcs->outBuffContentSize; - } - - /* flush epilogue */ - { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; - size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush); - op += flushed; - zcs->outBuffFlushedSize += flushed; - output->pos += op-ostart; - if (toFlush==flushed) zcs->stage = zcss_init; /* end reached */ - return toFlush - flushed; + ZSTD_inBuffer input = { NULL, 0, 0 }; + if (output->pos > output->size) return ERROR(GENERIC); + CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_end) ); + { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; + size_t const checksumSize = zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4; + size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize + lastBlockSize + checksumSize; + DEBUGLOG(5, "ZSTD_endStream : remaining to flush : %u", + (unsigned)toFlush); + return toFlush; } } - /*-===== Pre-defined compression levels =====-*/ -#define ZSTD_DEFAULT_CLEVEL 1 #define ZSTD_MAX_CLEVEL 22 int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { -{ /* "default" */ +{ /* "default" - guarantees a monotonically increasing memory budget */ /* W, C, H, S, L, TL, strat */ { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */ { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */ { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */ - { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/ - { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/ - { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */ - { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */ - { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */ + { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3 */ + { 20, 17, 18, 1, 5, 16, ZSTD_dfast }, /* level 4 */ + { 20, 17, 18, 2, 5, 16, ZSTD_greedy }, /* level 5 */ + { 21, 17, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */ + { 21, 18, 19, 3, 5, 16, ZSTD_lazy }, /* level 7 */ { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */ - { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */ + { 21, 19, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */ { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */ { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */ { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */ { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */ - { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */ + { 22, 21, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */ { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */ - { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */ + { 23, 22, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */ { 23, 22, 22, 5, 4, 32, ZSTD_btopt }, /* level 18 */ { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */ - { 25, 25, 23, 7, 3, 64, ZSTD_btopt2 }, /* level 20 */ - { 26, 26, 23, 7, 3,256, ZSTD_btopt2 }, /* level 21 */ - { 27, 27, 25, 9, 3,512, ZSTD_btopt2 }, /* level 22 */ + { 25, 25, 23, 7, 3, 64, ZSTD_btultra }, /* level 20 */ + { 26, 26, 24, 7, 3,256, ZSTD_btultra }, /* level 21 */ + { 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */ }, { /* for srcSize <= 256 KB */ /* W, C, H, S, L, T, strat */ @@ -3507,9 +4082,9 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/ { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/ { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/ - { 18, 19, 18, 11, 3,512, ZSTD_btopt2 }, /* level 20.*/ - { 18, 19, 18, 12, 3,512, ZSTD_btopt2 }, /* level 21.*/ - { 18, 19, 18, 13, 3,512, ZSTD_btopt2 }, /* level 22.*/ + { 18, 19, 18, 11, 3,512, ZSTD_btultra }, /* level 20.*/ + { 18, 19, 18, 12, 3,512, ZSTD_btultra }, /* level 21.*/ + { 18, 19, 18, 13, 3,512, ZSTD_btultra }, /* level 22.*/ }, { /* for srcSize <= 128 KB */ /* W, C, H, S, L, T, strat */ @@ -3533,9 +4108,9 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/ { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/ { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/ - { 17, 18, 17, 9, 3,256, ZSTD_btopt2 }, /* level 20.*/ - { 17, 18, 17, 10, 3,256, ZSTD_btopt2 }, /* level 21.*/ - { 17, 18, 17, 11, 3,512, ZSTD_btopt2 }, /* level 22.*/ + { 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/ + { 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/ + { 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/ }, { /* for srcSize <= 16 KB */ /* W, C, H, S, L, T, strat */ @@ -3559,39 +4134,59 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/ { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/ { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/ - { 14, 15, 15, 8, 3,256, ZSTD_btopt2 }, /* level 20.*/ - { 14, 15, 15, 9, 3,256, ZSTD_btopt2 }, /* level 21.*/ - { 14, 15, 15, 10, 3,256, ZSTD_btopt2 }, /* level 22.*/ + { 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/ + { 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/ + { 14, 15, 15, 10, 3,256, ZSTD_btultra }, /* level 22.*/ }, }; +#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1) +/* This function just controls + * the monotonic memory budget increase of ZSTD_defaultCParameters[0]. + * Run once, on first ZSTD_getCParams() usage, if ZSTD_DEBUG is enabled + */ +MEM_STATIC void ZSTD_check_compressionLevel_monotonicIncrease_memoryBudget(void) +{ + int level; + for (level=1; level<ZSTD_maxCLevel(); level++) { + ZSTD_compressionParameters const c1 = ZSTD_defaultCParameters[0][level]; + ZSTD_compressionParameters const c2 = ZSTD_defaultCParameters[0][level+1]; + assert(c1.windowLog <= c2.windowLog); +# define ZSTD_TABLECOST(h,c) ((1<<(h)) + (1<<(c))) + assert(ZSTD_TABLECOST(c1.hashLog, c1.chainLog) <= ZSTD_TABLECOST(c2.hashLog, c2.chainLog)); + } +} +#endif + /*! ZSTD_getCParams() : * @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`. * Size values are optional, provide 0 if not known or unused */ -ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) +ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { - ZSTD_compressionParameters cp; - size_t const addedSize = srcSize ? 0 : 500; - U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1; + size_t const addedSize = srcSizeHint ? 0 : 500; + U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1; U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */ - if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */ - if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL; - cp = ZSTD_defaultCParameters[tableID][compressionLevel]; - if (MEM_32bits()) { /* auto-correction, for 32-bits mode */ - if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX; - if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX; - if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX; + +#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1) + static int g_monotonicTest = 1; + if (g_monotonicTest) { + ZSTD_check_compressionLevel_monotonicIncrease_memoryBudget(); + g_monotonicTest=0; } - cp = ZSTD_adjustCParams(cp, srcSize, dictSize); - return cp; +#endif + + if (compressionLevel <= 0) compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default; no negative compressionLevel yet */ + if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL; + { ZSTD_compressionParameters const cp = ZSTD_defaultCParameters[tableID][compressionLevel]; + return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); } } /*! ZSTD_getParams() : * same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`). * All fields of `ZSTD_frameParameters` are set to default (0) */ -ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) { +ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { ZSTD_parameters params; - ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize); + ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize); memset(¶ms, 0, sizeof(params)); params.cParams = cParams; return params; diff --git a/thirdparty/zstd/compress/zstd_opt.h b/thirdparty/zstd/compress/zstd_opt.h index 5437611912..e8e98915ea 100644 --- a/thirdparty/zstd/compress/zstd_opt.h +++ b/thirdparty/zstd/compress/zstd_opt.h @@ -43,6 +43,7 @@ MEM_STATIC void ZSTD_rescaleFreqs(seqStore_t* ssPtr, const BYTE* src, size_t src if (ssPtr->litLengthSum == 0) { if (srcSize <= 1024) ssPtr->staticPrices = 1; + assert(ssPtr->litFreq!=NULL); for (u=0; u<=MaxLit; u++) ssPtr->litFreq[u] = 0; for (u=0; u<srcSize; u++) @@ -201,6 +202,20 @@ MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const B } +/* function safe only for comparisons */ +MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length) +{ + switch (length) + { + default : + case 4 : return MEM_read32(memPtr); + case 3 : if (MEM_isLittleEndian()) + return MEM_read32(memPtr)<<8; + else + return MEM_read32(memPtr)>>8; + } +} + /* Update hashTable3 up to ip (excluded) Assumption : always within prefix (i.e. not within extDict) */ @@ -234,12 +249,12 @@ static U32 ZSTD_insertBtAndGetAllMatches ( { const BYTE* const base = zc->base; const U32 current = (U32)(ip-base); - const U32 hashLog = zc->params.cParams.hashLog; + const U32 hashLog = zc->appliedParams.cParams.hashLog; const size_t h = ZSTD_hashPtr(ip, hashLog, mls); U32* const hashTable = zc->hashTable; U32 matchIndex = hashTable[h]; U32* const bt = zc->chainTable; - const U32 btLog = zc->params.cParams.chainLog - 1; + const U32 btLog = zc->appliedParams.cParams.chainLog - 1; const U32 btMask= (1U << btLog) - 1; size_t commonLengthSmaller=0, commonLengthLarger=0; const BYTE* const dictBase = zc->dictBase; @@ -267,7 +282,7 @@ static U32 ZSTD_insertBtAndGetAllMatches ( if (match[bestLength] == ip[bestLength]) currentMl = ZSTD_count(ip, match, iLimit); } else { match = dictBase + matchIndex3; - if (MEM_readMINMATCH(match, MINMATCH) == MEM_readMINMATCH(ip, MINMATCH)) /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */ + if (ZSTD_readMINMATCH(match, MINMATCH) == ZSTD_readMINMATCH(ip, MINMATCH)) /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */ currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH; } @@ -410,10 +425,10 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, const BYTE* const base = ctx->base; const BYTE* const prefixStart = base + ctx->dictLimit; - const U32 maxSearches = 1U << ctx->params.cParams.searchLog; - const U32 sufficient_len = ctx->params.cParams.targetLength; - const U32 mls = ctx->params.cParams.searchLength; - const U32 minMatch = (ctx->params.cParams.searchLength == 3) ? 3 : 4; + const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog; + const U32 sufficient_len = ctx->appliedParams.cParams.targetLength; + const U32 mls = ctx->appliedParams.cParams.searchLength; + const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4; ZSTD_optimal_t* opt = seqStorePtr->priceTable; ZSTD_match_t* matches = seqStorePtr->matchTable; @@ -439,7 +454,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, for (i=(ip == anchor); i<last_i; i++) { const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i]; if ( (repCur > 0) && (repCur < (S32)(ip-prefixStart)) - && (MEM_readMINMATCH(ip, minMatch) == MEM_readMINMATCH(ip - repCur, minMatch))) { + && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repCur, minMatch))) { mlen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repCur, iend) + minMatch; if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) { best_mlen = mlen; best_off = i; cur = 0; last_pos = 1; @@ -524,7 +539,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, for (i=(opt[cur].mlen != 1); i<last_i; i++) { /* check rep */ const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i]; if ( (repCur > 0) && (repCur < (S32)(inr-prefixStart)) - && (MEM_readMINMATCH(inr, minMatch) == MEM_readMINMATCH(inr - repCur, minMatch))) { + && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(inr - repCur, minMatch))) { mlen = (U32)ZSTD_count(inr+minMatch, inr+minMatch - repCur, iend) + minMatch; if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) { @@ -663,10 +678,10 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, const BYTE* const dictBase = ctx->dictBase; const BYTE* const dictEnd = dictBase + dictLimit; - const U32 maxSearches = 1U << ctx->params.cParams.searchLog; - const U32 sufficient_len = ctx->params.cParams.targetLength; - const U32 mls = ctx->params.cParams.searchLength; - const U32 minMatch = (ctx->params.cParams.searchLength == 3) ? 3 : 4; + const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog; + const U32 sufficient_len = ctx->appliedParams.cParams.targetLength; + const U32 mls = ctx->appliedParams.cParams.searchLength; + const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4; ZSTD_optimal_t* opt = seqStorePtr->priceTable; ZSTD_match_t* matches = seqStorePtr->matchTable; @@ -698,7 +713,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, const BYTE* const repMatch = repBase + repIndex; if ( (repCur > 0 && repCur <= (S32)current) && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex)) /* intentional overflow */ - && (MEM_readMINMATCH(ip, minMatch) == MEM_readMINMATCH(repMatch, minMatch)) ) { + && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { /* repcode detected we should take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; mlen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch; @@ -794,7 +809,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, const BYTE* const repMatch = repBase + repIndex; if ( (repCur > 0 && repCur <= (S32)(current+cur)) && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex)) /* intentional overflow */ - && (MEM_readMINMATCH(inr, minMatch) == MEM_readMINMATCH(repMatch, minMatch)) ) { + && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { /* repcode detected */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; mlen = (U32)ZSTD_count_2segments(inr+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch; diff --git a/thirdparty/zstd/compress/zstdmt_compress.c b/thirdparty/zstd/compress/zstdmt_compress.c index fc7f52a290..0cee01eacb 100644 --- a/thirdparty/zstd/compress/zstdmt_compress.c +++ b/thirdparty/zstd/compress/zstdmt_compress.c @@ -14,34 +14,31 @@ /* ====== Compiler specifics ====== */ #if defined(_MSC_VER) -# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ +# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ #endif /* ====== Dependencies ====== */ -#include <stdlib.h> /* malloc */ -#include <string.h> /* memcpy */ -#include "pool.h" /* threadpool */ -#include "threading.h" /* mutex */ -#include "zstd_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */ +#include <string.h> /* memcpy, memset */ +#include "pool.h" /* threadpool */ +#include "threading.h" /* mutex */ +#include "zstd_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */ #include "zstdmt_compress.h" /* ====== Debug ====== */ -#if 0 +#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=2) # include <stdio.h> # include <unistd.h> # include <sys/times.h> - static unsigned g_debugLevel = 5; -# define DEBUGLOGRAW(l, ...) if (l<=g_debugLevel) { fprintf(stderr, __VA_ARGS__); } -# define DEBUGLOG(l, ...) if (l<=g_debugLevel) { fprintf(stderr, __FILE__ ": "); fprintf(stderr, __VA_ARGS__); fprintf(stderr, " \n"); } +# define DEBUGLOGRAW(l, ...) if (l<=ZSTD_DEBUG) { fprintf(stderr, __VA_ARGS__); } -# define DEBUG_PRINTHEX(l,p,n) { \ - unsigned debug_u; \ - for (debug_u=0; debug_u<(n); debug_u++) \ +# define DEBUG_PRINTHEX(l,p,n) { \ + unsigned debug_u; \ + for (debug_u=0; debug_u<(n); debug_u++) \ DEBUGLOGRAW(l, "%02X ", ((const unsigned char*)(p))[debug_u]); \ - DEBUGLOGRAW(l, " \n"); \ + DEBUGLOGRAW(l, " \n"); \ } static unsigned long long GetCurrentClockTimeMicroseconds(void) @@ -53,22 +50,22 @@ static unsigned long long GetCurrentClockTimeMicroseconds(void) return ((((unsigned long long)newTicks)*(1000000))/_ticksPerSecond); } } -#define MUTEX_WAIT_TIME_DLEVEL 5 -#define PTHREAD_MUTEX_LOCK(mutex) \ -if (g_debugLevel>=MUTEX_WAIT_TIME_DLEVEL) { \ - unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \ - pthread_mutex_lock(mutex); \ - { unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \ - unsigned long long const elapsedTime = (afterTime-beforeTime); \ - if (elapsedTime > 1000) { /* or whatever threshold you like; I'm using 1 millisecond here */ \ - DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, "Thread took %llu microseconds to acquire mutex %s \n", \ - elapsedTime, #mutex); \ - } } \ -} else pthread_mutex_lock(mutex); +#define MUTEX_WAIT_TIME_DLEVEL 6 +#define PTHREAD_MUTEX_LOCK(mutex) { \ + if (ZSTD_DEBUG>=MUTEX_WAIT_TIME_DLEVEL) { \ + unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \ + pthread_mutex_lock(mutex); \ + { unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \ + unsigned long long const elapsedTime = (afterTime-beforeTime); \ + if (elapsedTime > 1000) { /* or whatever threshold you like; I'm using 1 millisecond here */ \ + DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, "Thread took %llu microseconds to acquire mutex %s \n", \ + elapsedTime, #mutex); \ + } } \ + } else pthread_mutex_lock(mutex); \ +} #else -# define DEBUGLOG(l, ...) {} /* disabled */ # define PTHREAD_MUTEX_LOCK(m) pthread_mutex_lock(m) # define DEBUG_PRINTHEX(l,p,n) {} @@ -87,16 +84,19 @@ static const buffer_t g_nullBuffer = { NULL, 0 }; typedef struct ZSTDMT_bufferPool_s { unsigned totalBuffers; unsigned nbBuffers; + ZSTD_customMem cMem; buffer_t bTable[1]; /* variable size */ } ZSTDMT_bufferPool; -static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbThreads) +static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbThreads, ZSTD_customMem cMem) { unsigned const maxNbBuffers = 2*nbThreads + 2; - ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)calloc(1, sizeof(ZSTDMT_bufferPool) + (maxNbBuffers-1) * sizeof(buffer_t)); + ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_calloc( + sizeof(ZSTDMT_bufferPool) + (maxNbBuffers-1) * sizeof(buffer_t), cMem); if (bufPool==NULL) return NULL; bufPool->totalBuffers = maxNbBuffers; bufPool->nbBuffers = 0; + bufPool->cMem = cMem; return bufPool; } @@ -105,23 +105,39 @@ static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool) unsigned u; if (!bufPool) return; /* compatibility with free on NULL */ for (u=0; u<bufPool->totalBuffers; u++) - free(bufPool->bTable[u].start); - free(bufPool); + ZSTD_free(bufPool->bTable[u].start, bufPool->cMem); + ZSTD_free(bufPool, bufPool->cMem); +} + +/* only works at initialization, not during compression */ +static size_t ZSTDMT_sizeof_bufferPool(ZSTDMT_bufferPool* bufPool) +{ + size_t const poolSize = sizeof(*bufPool) + + (bufPool->totalBuffers - 1) * sizeof(buffer_t); + unsigned u; + size_t totalBufferSize = 0; + for (u=0; u<bufPool->totalBuffers; u++) + totalBufferSize += bufPool->bTable[u].size; + + return poolSize + totalBufferSize; } -/* assumption : invocation from main thread only ! */ +/** ZSTDMT_getBuffer() : + * assumption : invocation from main thread only ! */ static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* pool, size_t bSize) { if (pool->nbBuffers) { /* try to use an existing buffer */ buffer_t const buf = pool->bTable[--(pool->nbBuffers)]; size_t const availBufferSize = buf.size; - if ((availBufferSize >= bSize) & (availBufferSize <= 10*bSize)) /* large enough, but not too much */ + if ((availBufferSize >= bSize) & (availBufferSize <= 10*bSize)) + /* large enough, but not too much */ return buf; - free(buf.start); /* size conditions not respected : scratch this buffer and create a new one */ + /* size conditions not respected : scratch this buffer, create new one */ + ZSTD_free(buf.start, pool->cMem); } /* create new buffer */ { buffer_t buffer; - void* const start = malloc(bSize); + void* const start = ZSTD_malloc(bSize, pool->cMem); if (start==NULL) bSize = 0; buffer.start = start; /* note : start can be NULL if malloc fails ! */ buffer.size = bSize; @@ -138,7 +154,7 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* pool, buffer_t buf) return; } /* Reached bufferPool capacity (should not happen) */ - free(buf.start); + ZSTD_free(buf.start, pool->cMem); } @@ -147,6 +163,7 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* pool, buffer_t buf) typedef struct { unsigned totalCCtx; unsigned availCCtx; + ZSTD_customMem cMem; ZSTD_CCtx* cctx[1]; /* variable size */ } ZSTDMT_CCtxPool; @@ -158,23 +175,40 @@ static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool) unsigned u; for (u=0; u<pool->totalCCtx; u++) ZSTD_freeCCtx(pool->cctx[u]); /* note : compatible with free on NULL */ - free(pool); + ZSTD_free(pool, pool->cMem); } /* ZSTDMT_createCCtxPool() : * implies nbThreads >= 1 , checked by caller ZSTDMT_createCCtx() */ -static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(unsigned nbThreads) +static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(unsigned nbThreads, + ZSTD_customMem cMem) { - ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) calloc(1, sizeof(ZSTDMT_CCtxPool) + (nbThreads-1)*sizeof(ZSTD_CCtx*)); + ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_calloc( + sizeof(ZSTDMT_CCtxPool) + (nbThreads-1)*sizeof(ZSTD_CCtx*), cMem); if (!cctxPool) return NULL; + cctxPool->cMem = cMem; cctxPool->totalCCtx = nbThreads; cctxPool->availCCtx = 1; /* at least one cctx for single-thread mode */ - cctxPool->cctx[0] = ZSTD_createCCtx(); + cctxPool->cctx[0] = ZSTD_createCCtx_advanced(cMem); if (!cctxPool->cctx[0]) { ZSTDMT_freeCCtxPool(cctxPool); return NULL; } - DEBUGLOG(1, "cctxPool created, with %u threads", nbThreads); + DEBUGLOG(3, "cctxPool created, with %u threads", nbThreads); return cctxPool; } +/* only works during initialization phase, not during compression */ +static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool) +{ + unsigned const nbThreads = cctxPool->totalCCtx; + size_t const poolSize = sizeof(*cctxPool) + + (nbThreads-1)*sizeof(ZSTD_CCtx*); + unsigned u; + size_t totalCCtxSize = 0; + for (u=0; u<nbThreads; u++) + totalCCtxSize += ZSTD_sizeof_CCtx(cctxPool->cctx[u]); + + return poolSize + totalCCtxSize; +} + static ZSTD_CCtx* ZSTDMT_getCCtx(ZSTDMT_CCtxPool* pool) { if (pool->availCCtx) { @@ -218,7 +252,7 @@ typedef struct { pthread_mutex_t* jobCompleted_mutex; pthread_cond_t* jobCompleted_cond; ZSTD_parameters params; - ZSTD_CDict* cdict; + const ZSTD_CDict* cdict; unsigned long long fullFrameSize; } ZSTDMT_jobDescription; @@ -228,11 +262,11 @@ void ZSTDMT_compressChunk(void* jobDescription) ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)jobDescription; const void* const src = (const char*)job->srcStart + job->dictSize; buffer_t const dstBuff = job->dstBuff; - DEBUGLOG(3, "job (first:%u) (last:%u) : dictSize %u, srcSize %u", + DEBUGLOG(5, "job (first:%u) (last:%u) : dictSize %u, srcSize %u", job->firstChunk, job->lastChunk, (U32)job->dictSize, (U32)job->srcSize); if (job->cdict) { /* should only happen for first segment */ size_t const initError = ZSTD_compressBegin_usingCDict_advanced(job->cctx, job->cdict, job->params.fParams, job->fullFrameSize); - if (job->cdict) DEBUGLOG(3, "using CDict "); + DEBUGLOG(5, "using CDict"); if (ZSTD_isError(initError)) { job->cSize = initError; goto _endJob; } } else { /* srcStart points at reloaded section */ if (!job->firstChunk) job->params.fParams.contentSizeFlag = 0; /* ensure no srcSize control */ @@ -247,12 +281,12 @@ void ZSTDMT_compressChunk(void* jobDescription) ZSTD_invalidateRepCodes(job->cctx); } - DEBUGLOG(4, "Compressing : "); + DEBUGLOG(5, "Compressing : "); DEBUG_PRINTHEX(4, job->srcStart, 12); job->cSize = (job->lastChunk) ? ZSTD_compressEnd (job->cctx, dstBuff.start, dstBuff.size, src, job->srcSize) : ZSTD_compressContinue(job->cctx, dstBuff.start, dstBuff.size, src, job->srcSize); - DEBUGLOG(3, "compressed %u bytes into %u bytes (first:%u) (last:%u)", + DEBUGLOG(5, "compressed %u bytes into %u bytes (first:%u) (last:%u)", (unsigned)job->srcSize, (unsigned)job->cSize, job->firstChunk, job->lastChunk); DEBUGLOG(5, "dstBuff.size : %u ; => %s", (U32)dstBuff.size, ZSTD_getErrorName(job->cSize)); @@ -271,6 +305,7 @@ _endJob: struct ZSTDMT_CCtx_s { POOL_ctx* factory; + ZSTDMT_jobDescription* jobs; ZSTDMT_bufferPool* buffPool; ZSTDMT_CCtxPool* cctxPool; pthread_mutex_t jobCompleted_mutex; @@ -292,50 +327,64 @@ struct ZSTDMT_CCtx_s { unsigned overlapRLog; unsigned long long frameContentSize; size_t sectionSize; - ZSTD_CDict* cdict; - ZSTD_CStream* cstream; - ZSTDMT_jobDescription jobs[1]; /* variable size (must lies at the end) */ + ZSTD_customMem cMem; + ZSTD_CDict* cdictLocal; + const ZSTD_CDict* cdict; }; -ZSTDMT_CCtx *ZSTDMT_createCCtx(unsigned nbThreads) +static ZSTDMT_jobDescription* ZSTDMT_allocJobsTable(U32* nbJobsPtr, ZSTD_customMem cMem) { - ZSTDMT_CCtx* cctx; - U32 const minNbJobs = nbThreads + 2; - U32 const nbJobsLog2 = ZSTD_highbit32(minNbJobs) + 1; + U32 const nbJobsLog2 = ZSTD_highbit32(*nbJobsPtr) + 1; U32 const nbJobs = 1 << nbJobsLog2; - DEBUGLOG(5, "nbThreads : %u ; minNbJobs : %u ; nbJobsLog2 : %u ; nbJobs : %u \n", - nbThreads, minNbJobs, nbJobsLog2, nbJobs); + *nbJobsPtr = nbJobs; + return (ZSTDMT_jobDescription*) ZSTD_calloc( + nbJobs * sizeof(ZSTDMT_jobDescription), cMem); +} + +ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem) +{ + ZSTDMT_CCtx* mtctx; + U32 nbJobs = nbThreads + 2; + DEBUGLOG(3, "ZSTDMT_createCCtx_advanced"); + if ((nbThreads < 1) | (nbThreads > ZSTDMT_NBTHREADS_MAX)) return NULL; - cctx = (ZSTDMT_CCtx*) calloc(1, sizeof(ZSTDMT_CCtx) + nbJobs*sizeof(ZSTDMT_jobDescription)); - if (!cctx) return NULL; - cctx->nbThreads = nbThreads; - cctx->jobIDMask = nbJobs - 1; - cctx->allJobsCompleted = 1; - cctx->sectionSize = 0; - cctx->overlapRLog = 3; - cctx->factory = POOL_create(nbThreads, 1); - cctx->buffPool = ZSTDMT_createBufferPool(nbThreads); - cctx->cctxPool = ZSTDMT_createCCtxPool(nbThreads); - if (!cctx->factory | !cctx->buffPool | !cctx->cctxPool) { /* one object was not created */ - ZSTDMT_freeCCtx(cctx); + if ((cMem.customAlloc!=NULL) ^ (cMem.customFree!=NULL)) + /* invalid custom allocator */ + return NULL; + + mtctx = (ZSTDMT_CCtx*) ZSTD_calloc(sizeof(ZSTDMT_CCtx), cMem); + if (!mtctx) return NULL; + mtctx->cMem = cMem; + mtctx->nbThreads = nbThreads; + mtctx->allJobsCompleted = 1; + mtctx->sectionSize = 0; + mtctx->overlapRLog = 3; + mtctx->factory = POOL_create(nbThreads, 1); + mtctx->jobs = ZSTDMT_allocJobsTable(&nbJobs, cMem); + mtctx->jobIDMask = nbJobs - 1; + mtctx->buffPool = ZSTDMT_createBufferPool(nbThreads, cMem); + mtctx->cctxPool = ZSTDMT_createCCtxPool(nbThreads, cMem); + if (!mtctx->factory | !mtctx->jobs | !mtctx->buffPool | !mtctx->cctxPool) { + ZSTDMT_freeCCtx(mtctx); return NULL; } - if (nbThreads==1) { - cctx->cstream = ZSTD_createCStream(); - if (!cctx->cstream) { - ZSTDMT_freeCCtx(cctx); return NULL; - } } - pthread_mutex_init(&cctx->jobCompleted_mutex, NULL); /* Todo : check init function return */ - pthread_cond_init(&cctx->jobCompleted_cond, NULL); - DEBUGLOG(4, "mt_cctx created, for %u threads \n", nbThreads); - return cctx; + pthread_mutex_init(&mtctx->jobCompleted_mutex, NULL); /* Todo : check init function return */ + pthread_cond_init(&mtctx->jobCompleted_cond, NULL); + DEBUGLOG(3, "mt_cctx created, for %u threads", nbThreads); + return mtctx; +} + +ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbThreads) +{ + return ZSTDMT_createCCtx_advanced(nbThreads, ZSTD_defaultCMem); } /* ZSTDMT_releaseAllJobResources() : - * Ensure all workers are killed first. */ + * note : ensure all workers are killed first ! */ static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx) { unsigned jobID; + DEBUGLOG(3, "ZSTDMT_releaseAllJobResources"); for (jobID=0; jobID <= mtctx->jobIDMask; jobID++) { ZSTDMT_releaseBuffer(mtctx->buffPool, mtctx->jobs[jobID].dstBuff); mtctx->jobs[jobID].dstBuff = g_nullBuffer; @@ -356,15 +405,26 @@ size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx) POOL_free(mtctx->factory); if (!mtctx->allJobsCompleted) ZSTDMT_releaseAllJobResources(mtctx); /* stop workers first */ ZSTDMT_freeBufferPool(mtctx->buffPool); /* release job resources into pools first */ + ZSTD_free(mtctx->jobs, mtctx->cMem); ZSTDMT_freeCCtxPool(mtctx->cctxPool); - ZSTD_freeCDict(mtctx->cdict); - ZSTD_freeCStream(mtctx->cstream); + ZSTD_freeCDict(mtctx->cdictLocal); pthread_mutex_destroy(&mtctx->jobCompleted_mutex); pthread_cond_destroy(&mtctx->jobCompleted_cond); - free(mtctx); + ZSTD_free(mtctx, mtctx->cMem); return 0; } +size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx) +{ + if (mtctx == NULL) return 0; /* supports sizeof NULL */ + return sizeof(*mtctx) + + POOL_sizeof(mtctx->factory) + + ZSTDMT_sizeof_bufferPool(mtctx->buffPool) + + (mtctx->jobIDMask+1) * sizeof(ZSTDMT_jobDescription) + + ZSTDMT_sizeof_CCtxPool(mtctx->cctxPool) + + ZSTD_sizeof_CDict(mtctx->cdictLocal); +} + size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSDTMT_parameter parameter, unsigned value) { switch(parameter) @@ -373,7 +433,7 @@ size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSDTMT_parameter parameter, mtctx->sectionSize = value; return 0; case ZSTDMT_p_overlapSectionLog : - DEBUGLOG(4, "ZSTDMT_p_overlapSectionLog : %u", value); + DEBUGLOG(5, "ZSTDMT_p_overlapSectionLog : %u", value); mtctx->overlapRLog = (value >= 9) ? 0 : 9 - value; return 0; default : @@ -386,31 +446,49 @@ size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSDTMT_parameter parameter, /* ===== Multi-threaded compression ===== */ /* ------------------------------------------ */ -size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx, +static unsigned computeNbChunks(size_t srcSize, unsigned windowLog, unsigned nbThreads) { + size_t const chunkSizeTarget = (size_t)1 << (windowLog + 2); + size_t const chunkMaxSize = chunkSizeTarget << 2; + size_t const passSizeMax = chunkMaxSize * nbThreads; + unsigned const multiplier = (unsigned)(srcSize / passSizeMax) + 1; + unsigned const nbChunksLarge = multiplier * nbThreads; + unsigned const nbChunksMax = (unsigned)(srcSize / chunkSizeTarget) + 1; + unsigned const nbChunksSmall = MIN(nbChunksMax, nbThreads); + return (multiplier>1) ? nbChunksLarge : nbChunksSmall; +} + + +size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, - int compressionLevel) + const ZSTD_CDict* cdict, + ZSTD_parameters const params, + unsigned overlapRLog) { - ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, 0); - U32 const overlapLog = (compressionLevel >= ZSTD_maxCLevel()) ? 0 : 3; - size_t const overlapSize = (size_t)1 << (params.cParams.windowLog - overlapLog); - size_t const chunkTargetSize = (size_t)1 << (params.cParams.windowLog + 2); - unsigned const nbChunksMax = (unsigned)(srcSize / chunkTargetSize) + 1; - unsigned nbChunks = MIN(nbChunksMax, mtctx->nbThreads); + size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (params.cParams.windowLog - overlapRLog); + unsigned nbChunks = computeNbChunks(srcSize, params.cParams.windowLog, mtctx->nbThreads); size_t const proposedChunkSize = (srcSize + (nbChunks-1)) / nbChunks; - size_t const avgChunkSize = ((proposedChunkSize & 0x1FFFF) < 0xFFFF) ? proposedChunkSize + 0xFFFF : proposedChunkSize; /* avoid too small last block */ - size_t remainingSrcSize = srcSize; + size_t const avgChunkSize = ((proposedChunkSize & 0x1FFFF) < 0x7FFF) ? proposedChunkSize + 0xFFFF : proposedChunkSize; /* avoid too small last block */ const char* const srcStart = (const char*)src; + size_t remainingSrcSize = srcSize; unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbChunks : (unsigned)(dstCapacity / ZSTD_compressBound(avgChunkSize)); /* presumes avgChunkSize >= 256 KB, which should be the case */ size_t frameStartPos = 0, dstBufferPos = 0; - DEBUGLOG(3, "windowLog : %2u => chunkTargetSize : %u bytes ", params.cParams.windowLog, (U32)chunkTargetSize); - DEBUGLOG(2, "nbChunks : %2u (chunkSize : %u bytes) ", nbChunks, (U32)avgChunkSize); - params.fParams.contentSizeFlag = 1; - + DEBUGLOG(4, "nbChunks : %2u (chunkSize : %u bytes) ", nbChunks, (U32)avgChunkSize); if (nbChunks==1) { /* fallback to single-thread mode */ ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0]; - return ZSTD_compressCCtx(cctx, dst, dstCapacity, src, srcSize, compressionLevel); + if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, params.fParams); + return ZSTD_compress_advanced(cctx, dst, dstCapacity, src, srcSize, NULL, 0, params); + } + assert(avgChunkSize >= 256 KB); /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), which is useful to avoid allocating extra buffers */ + + if (nbChunks > mtctx->jobIDMask+1) { /* enlarge job table */ + U32 nbJobs = nbChunks; + ZSTD_free(mtctx->jobs, mtctx->cMem); + mtctx->jobIDMask = 0; + mtctx->jobs = ZSTDMT_allocJobsTable(&nbJobs, mtctx->cMem); + if (mtctx->jobs==NULL) return ERROR(memory_allocation); + mtctx->jobIDMask = nbJobs - 1; } { unsigned u; @@ -425,15 +503,18 @@ size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx, if ((cctx==NULL) || (dstBuffer.start==NULL)) { mtctx->jobs[u].cSize = ERROR(memory_allocation); /* job result */ mtctx->jobs[u].jobCompleted = 1; - nbChunks = u+1; + nbChunks = u+1; /* only wait and free u jobs, instead of initially expected nbChunks ones */ break; /* let's wait for previous jobs to complete, but don't start new ones */ } mtctx->jobs[u].srcStart = srcStart + frameStartPos - dictSize; mtctx->jobs[u].dictSize = dictSize; mtctx->jobs[u].srcSize = chunkSize; + mtctx->jobs[u].cdict = mtctx->nextJobID==0 ? cdict : NULL; mtctx->jobs[u].fullFrameSize = srcSize; mtctx->jobs[u].params = params; + /* do not calculate checksum within sections, but write it in header for first section */ + if (u!=0) mtctx->jobs[u].params.fParams.checksumFlag = 0; mtctx->jobs[u].dstBuff = dstBuffer; mtctx->jobs[u].cctx = cctx; mtctx->jobs[u].firstChunk = (u==0); @@ -442,27 +523,27 @@ size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx, mtctx->jobs[u].jobCompleted_mutex = &mtctx->jobCompleted_mutex; mtctx->jobs[u].jobCompleted_cond = &mtctx->jobCompleted_cond; - DEBUGLOG(3, "posting job %u (%u bytes)", u, (U32)chunkSize); - DEBUG_PRINTHEX(3, mtctx->jobs[u].srcStart, 12); + DEBUGLOG(5, "posting job %u (%u bytes)", u, (U32)chunkSize); + DEBUG_PRINTHEX(6, mtctx->jobs[u].srcStart, 12); POOL_add(mtctx->factory, ZSTDMT_compressChunk, &mtctx->jobs[u]); frameStartPos += chunkSize; dstBufferPos += dstBufferCapacity; remainingSrcSize -= chunkSize; } } - /* note : since nbChunks <= nbThreads, all jobs should be running immediately in parallel */ + /* collect result */ { unsigned chunkID; size_t error = 0, dstPos = 0; for (chunkID=0; chunkID<nbChunks; chunkID++) { - DEBUGLOG(3, "waiting for chunk %u ", chunkID); + DEBUGLOG(5, "waiting for chunk %u ", chunkID); PTHREAD_MUTEX_LOCK(&mtctx->jobCompleted_mutex); while (mtctx->jobs[chunkID].jobCompleted==0) { - DEBUGLOG(4, "waiting for jobCompleted signal from chunk %u", chunkID); + DEBUGLOG(5, "waiting for jobCompleted signal from chunk %u", chunkID); pthread_cond_wait(&mtctx->jobCompleted_cond, &mtctx->jobCompleted_mutex); } pthread_mutex_unlock(&mtctx->jobCompleted_mutex); - DEBUGLOG(3, "ready to write chunk %u ", chunkID); + DEBUGLOG(5, "ready to write chunk %u ", chunkID); ZSTDMT_releaseCCtx(mtctx->cctxPool, mtctx->jobs[chunkID].cctx); mtctx->jobs[chunkID].cctx = NULL; @@ -470,20 +551,33 @@ size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx, { size_t const cSize = mtctx->jobs[chunkID].cSize; if (ZSTD_isError(cSize)) error = cSize; if ((!error) && (dstPos + cSize > dstCapacity)) error = ERROR(dstSize_tooSmall); - if (chunkID) { /* note : chunk 0 is already written directly into dst */ + if (chunkID) { /* note : chunk 0 is written directly at dst, which is correct position */ if (!error) - memmove((char*)dst + dstPos, mtctx->jobs[chunkID].dstBuff.start, cSize); /* may overlap if chunk decompressed within dst */ - if (chunkID >= compressWithinDst) /* otherwise, it decompresses within dst */ + memmove((char*)dst + dstPos, mtctx->jobs[chunkID].dstBuff.start, cSize); /* may overlap when chunk compressed within dst */ + if (chunkID >= compressWithinDst) { /* chunk compressed into its own buffer, which must be released */ + DEBUGLOG(5, "releasing buffer %u>=%u", chunkID, compressWithinDst); ZSTDMT_releaseBuffer(mtctx->buffPool, mtctx->jobs[chunkID].dstBuff); + } mtctx->jobs[chunkID].dstBuff = g_nullBuffer; } dstPos += cSize ; } } - if (!error) DEBUGLOG(3, "compressed size : %u ", (U32)dstPos); + if (!error) DEBUGLOG(4, "compressed size : %u ", (U32)dstPos); return error ? error : dstPos; } +} + +size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + int compressionLevel) +{ + U32 const overlapRLog = (compressionLevel >= ZSTD_maxCLevel()) ? 0 : 3; + ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, 0); + params.fParams.contentSizeFlag = 1; + return ZSTDMT_compress_advanced(mtctx, dst, dstCapacity, src, srcSize, NULL, params, overlapRLog); } @@ -491,12 +585,14 @@ size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx, /* ======= Streaming API ======= */ /* ====================================== */ -static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs) { +static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs) +{ + DEBUGLOG(4, "ZSTDMT_waitForAllJobsCompleted"); while (zcs->doneJobID < zcs->nextJobID) { unsigned const jobID = zcs->doneJobID & zcs->jobIDMask; PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex); while (zcs->jobs[jobID].jobCompleted==0) { - DEBUGLOG(4, "waiting for jobCompleted signal from chunk %u", zcs->doneJobID); /* we want to block when waiting for data to flush */ + DEBUGLOG(5, "waiting for jobCompleted signal from chunk %u", zcs->doneJobID); /* we want to block when waiting for data to flush */ pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex); } pthread_mutex_unlock(&zcs->jobCompleted_mutex); @@ -505,33 +601,54 @@ static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs) { } -static size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, - const void* dict, size_t dictSize, unsigned updateDict, - ZSTD_parameters params, unsigned long long pledgedSrcSize) +/** ZSTDMT_initCStream_internal() : + * internal usage only */ +size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, + const void* dict, size_t dictSize, const ZSTD_CDict* cdict, + ZSTD_parameters params, unsigned long long pledgedSrcSize) { - ZSTD_customMem const cmem = { NULL, NULL, NULL }; - DEBUGLOG(3, "Started new compression, with windowLog : %u", params.cParams.windowLog); - if (zcs->nbThreads==1) return ZSTD_initCStream_advanced(zcs->cstream, dict, dictSize, params, pledgedSrcSize); - if (zcs->allJobsCompleted == 0) { /* previous job not correctly finished */ + DEBUGLOG(4, "ZSTDMT_initCStream_internal"); + /* params are supposed to be fully validated at this point */ + assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + assert(!((dict) && (cdict))); /* either dict or cdict, not both */ + + if (zcs->nbThreads==1) { + DEBUGLOG(4, "single thread mode"); + return ZSTD_initCStream_internal(zcs->cctxPool->cctx[0], + dict, dictSize, cdict, + params, pledgedSrcSize); + } + + if (zcs->allJobsCompleted == 0) { /* previous compression not correctly finished */ ZSTDMT_waitForAllJobsCompleted(zcs); ZSTDMT_releaseAllJobResources(zcs); zcs->allJobsCompleted = 1; } + zcs->params = params; - if (updateDict) { - ZSTD_freeCDict(zcs->cdict); zcs->cdict = NULL; - if (dict && dictSize) { - zcs->cdict = ZSTD_createCDict_advanced(dict, dictSize, 0, params.cParams, cmem); - if (zcs->cdict == NULL) return ERROR(memory_allocation); - } } zcs->frameContentSize = pledgedSrcSize; + if (dict) { + DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal); + ZSTD_freeCDict(zcs->cdictLocal); + zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, + 0 /* byRef */, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */ + params.cParams, zcs->cMem); + zcs->cdict = zcs->cdictLocal; + if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); + } else { + DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal); + ZSTD_freeCDict(zcs->cdictLocal); + zcs->cdictLocal = NULL; + zcs->cdict = cdict; + } + zcs->targetDictSize = (zcs->overlapRLog>=9) ? 0 : (size_t)1 << (zcs->params.cParams.windowLog - zcs->overlapRLog); DEBUGLOG(4, "overlapRLog : %u ", zcs->overlapRLog); - DEBUGLOG(3, "overlap Size : %u KB", (U32)(zcs->targetDictSize>>10)); + DEBUGLOG(4, "overlap Size : %u KB", (U32)(zcs->targetDictSize>>10)); zcs->targetSectionSize = zcs->sectionSize ? zcs->sectionSize : (size_t)1 << (zcs->params.cParams.windowLog + 2); zcs->targetSectionSize = MAX(ZSTDMT_SECTION_SIZE_MIN, zcs->targetSectionSize); zcs->targetSectionSize = MAX(zcs->targetDictSize, zcs->targetSectionSize); - DEBUGLOG(3, "Section Size : %u KB", (U32)(zcs->targetSectionSize>>10)); + DEBUGLOG(4, "Section Size : %u KB", (U32)(zcs->targetSectionSize>>10)); zcs->marginSize = zcs->targetSectionSize >> 2; zcs->inBuffSize = zcs->targetDictSize + zcs->targetSectionSize + zcs->marginSize; zcs->inBuff.buffer = ZSTDMT_getBuffer(zcs->buffPool, zcs->inBuffSize); @@ -546,24 +663,39 @@ static size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, return 0; } -size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* zcs, +size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize) { - return ZSTDMT_initCStream_internal(zcs, dict, dictSize, 1, params, pledgedSrcSize); + DEBUGLOG(5, "ZSTDMT_initCStream_advanced"); + return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, NULL, params, pledgedSrcSize); } +size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fParams, + unsigned long long pledgedSrcSize) +{ + ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict); + if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */ + params.fParams = fParams; + return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, cdict, + params, pledgedSrcSize); +} + + /* ZSTDMT_resetCStream() : * pledgedSrcSize is optional and can be zero == unknown */ size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* zcs, unsigned long long pledgedSrcSize) { - if (zcs->nbThreads==1) return ZSTD_resetCStream(zcs->cstream, pledgedSrcSize); + if (zcs->nbThreads==1) + return ZSTD_resetCStream(zcs->cctxPool->cctx[0], pledgedSrcSize); return ZSTDMT_initCStream_internal(zcs, NULL, 0, 0, zcs->params, pledgedSrcSize); } size_t ZSTDMT_initCStream(ZSTDMT_CCtx* zcs, int compressionLevel) { ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0); - return ZSTDMT_initCStream_internal(zcs, NULL, 0, 1, params, 0); + return ZSTDMT_initCStream_internal(zcs, NULL, 0, NULL, params, 0); } @@ -582,13 +714,16 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi return ERROR(memory_allocation); } - DEBUGLOG(4, "preparing job %u to compress %u bytes with %u preload ", zcs->nextJobID, (U32)srcSize, (U32)zcs->dictSize); + DEBUGLOG(4, "preparing job %u to compress %u bytes with %u preload ", + zcs->nextJobID, (U32)srcSize, (U32)zcs->dictSize); zcs->jobs[jobID].src = zcs->inBuff.buffer; zcs->jobs[jobID].srcStart = zcs->inBuff.buffer.start; zcs->jobs[jobID].srcSize = srcSize; - zcs->jobs[jobID].dictSize = zcs->dictSize; /* note : zcs->inBuff.filled is presumed >= srcSize + dictSize */ + zcs->jobs[jobID].dictSize = zcs->dictSize; + assert(zcs->inBuff.filled >= srcSize + zcs->dictSize); zcs->jobs[jobID].params = zcs->params; - if (zcs->nextJobID) zcs->jobs[jobID].params.fParams.checksumFlag = 0; /* do not calculate checksum within sections, just keep it in header for first section */ + /* do not calculate checksum within sections, but write it in header for first section */ + if (zcs->nextJobID) zcs->jobs[jobID].params.fParams.checksumFlag = 0; zcs->jobs[jobID].cdict = zcs->nextJobID==0 ? zcs->cdict : NULL; zcs->jobs[jobID].fullFrameSize = zcs->frameContentSize; zcs->jobs[jobID].dstBuff = dstBuffer; @@ -603,6 +738,7 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi /* get a new buffer for next input */ if (!endFrame) { size_t const newDictSize = MIN(srcSize + zcs->dictSize, zcs->targetDictSize); + DEBUGLOG(5, "ZSTDMT_createCompressionJob::endFrame = %u", endFrame); zcs->inBuff.buffer = ZSTDMT_getBuffer(zcs->buffPool, zcs->inBuffSize); if (zcs->inBuff.buffer.start == NULL) { /* not enough memory to allocate next input buffer */ zcs->jobs[jobID].jobCompleted = 1; @@ -611,22 +747,33 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi ZSTDMT_releaseAllJobResources(zcs); return ERROR(memory_allocation); } - DEBUGLOG(5, "inBuff filled to %u", (U32)zcs->inBuff.filled); + DEBUGLOG(5, "inBuff currently filled to %u", (U32)zcs->inBuff.filled); zcs->inBuff.filled -= srcSize + zcs->dictSize - newDictSize; - DEBUGLOG(5, "new job : filled to %u, with %u dict and %u src", (U32)zcs->inBuff.filled, (U32)newDictSize, (U32)(zcs->inBuff.filled - newDictSize)); - memmove(zcs->inBuff.buffer.start, (const char*)zcs->jobs[jobID].srcStart + zcs->dictSize + srcSize - newDictSize, zcs->inBuff.filled); + DEBUGLOG(5, "new job : inBuff filled to %u, with %u dict and %u src", + (U32)zcs->inBuff.filled, (U32)newDictSize, + (U32)(zcs->inBuff.filled - newDictSize)); + memmove(zcs->inBuff.buffer.start, + (const char*)zcs->jobs[jobID].srcStart + zcs->dictSize + srcSize - newDictSize, + zcs->inBuff.filled); DEBUGLOG(5, "new inBuff pre-filled"); zcs->dictSize = newDictSize; - } else { + } else { /* if (endFrame==1) */ + DEBUGLOG(5, "ZSTDMT_createCompressionJob::endFrame = %u", endFrame); zcs->inBuff.buffer = g_nullBuffer; zcs->inBuff.filled = 0; zcs->dictSize = 0; zcs->frameEnded = 1; if (zcs->nextJobID == 0) - zcs->params.fParams.checksumFlag = 0; /* single chunk : checksum is calculated directly within worker thread */ + /* single chunk exception : checksum is calculated directly within worker thread */ + zcs->params.fParams.checksumFlag = 0; } - DEBUGLOG(3, "posting job %u : %u bytes (end:%u) (note : doneJob = %u=>%u)", zcs->nextJobID, (U32)zcs->jobs[jobID].srcSize, zcs->jobs[jobID].lastChunk, zcs->doneJobID, zcs->doneJobID & zcs->jobIDMask); + DEBUGLOG(4, "posting job %u : %u bytes (end:%u) (note : doneJob = %u=>%u)", + zcs->nextJobID, + (U32)zcs->jobs[jobID].srcSize, + zcs->jobs[jobID].lastChunk, + zcs->doneJobID, + zcs->doneJobID & zcs->jobIDMask); POOL_add(zcs->factory, ZSTDMT_compressChunk, &zcs->jobs[jobID]); /* this call is blocking when thread worker pool is exhausted */ zcs->nextJobID++; return 0; @@ -664,7 +811,7 @@ static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsi XXH64_update(&zcs->xxhState, (const char*)job.srcStart + job.dictSize, job.srcSize); if (zcs->frameEnded && (zcs->doneJobID+1 == zcs->nextJobID)) { /* write checksum at end of last section */ U32 const checksum = (U32)XXH64_digest(&zcs->xxhState); - DEBUGLOG(4, "writing checksum : %08X \n", checksum); + DEBUGLOG(5, "writing checksum : %08X \n", checksum); MEM_writeLE32((char*)job.dstBuff.start + job.cSize, checksum); job.cSize += 4; zcs->jobs[wJobID].cSize += 4; @@ -675,7 +822,7 @@ static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsi zcs->jobs[wJobID].jobScanned = 1; } { size_t const toWrite = MIN(job.cSize - job.dstFlushed, output->size - output->pos); - DEBUGLOG(4, "Flushing %u bytes from job %u ", (U32)toWrite, zcs->doneJobID); + DEBUGLOG(5, "Flushing %u bytes from job %u ", (U32)toWrite, zcs->doneJobID); memcpy((char*)output->dst + output->pos, (const char*)job.dstBuff.start + job.dstFlushed, toWrite); output->pos += toWrite; job.dstFlushed += toWrite; @@ -696,26 +843,81 @@ static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsi } } -size_t ZSTDMT_compressStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input) +/** ZSTDMT_compressStream_generic() : + * internal use only + * assumption : output and input are valid (pos <= size) + * @return : minimum amount of data remaining to flush, 0 if none */ +size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input, + ZSTD_EndDirective endOp) { - size_t const newJobThreshold = zcs->dictSize + zcs->targetSectionSize + zcs->marginSize; - if (zcs->frameEnded) return ERROR(stage_wrong); /* current frame being ended. Only flush is allowed. Restart with init */ - if (zcs->nbThreads==1) return ZSTD_compressStream(zcs->cstream, output, input); + size_t const newJobThreshold = mtctx->dictSize + mtctx->targetSectionSize + mtctx->marginSize; + assert(output->pos <= output->size); + assert(input->pos <= input->size); + if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) { + /* current frame being ended. Only flush/end are allowed. Or start new frame with init */ + return ERROR(stage_wrong); + } + if (mtctx->nbThreads==1) { + return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp); + } + + /* single-pass shortcut (note : this is blocking-mode) */ + if ( (mtctx->nextJobID==0) /* just started */ + && (mtctx->inBuff.filled==0) /* nothing buffered */ + && (endOp==ZSTD_e_end) /* end order */ + && (output->size - output->pos >= ZSTD_compressBound(input->size - input->pos)) ) { /* enough room */ + size_t const cSize = ZSTDMT_compress_advanced(mtctx, + (char*)output->dst + output->pos, output->size - output->pos, + (const char*)input->src + input->pos, input->size - input->pos, + mtctx->cdict, mtctx->params, mtctx->overlapRLog); + if (ZSTD_isError(cSize)) return cSize; + input->pos = input->size; + output->pos += cSize; + ZSTDMT_releaseBuffer(mtctx->buffPool, mtctx->inBuff.buffer); /* was allocated in initStream */ + mtctx->allJobsCompleted = 1; + mtctx->frameEnded = 1; + return 0; + } /* fill input buffer */ - { size_t const toLoad = MIN(input->size - input->pos, zcs->inBuffSize - zcs->inBuff.filled); - memcpy((char*)zcs->inBuff.buffer.start + zcs->inBuff.filled, input->src, toLoad); + if ((input->src) && (mtctx->inBuff.buffer.start)) { /* support NULL input */ + size_t const toLoad = MIN(input->size - input->pos, mtctx->inBuffSize - mtctx->inBuff.filled); + DEBUGLOG(2, "inBuff:%08X; inBuffSize=%u; ToCopy=%u", (U32)(size_t)mtctx->inBuff.buffer.start, (U32)mtctx->inBuffSize, (U32)toLoad); + memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, toLoad); input->pos += toLoad; - zcs->inBuff.filled += toLoad; + mtctx->inBuff.filled += toLoad; } - if ( (zcs->inBuff.filled >= newJobThreshold) /* filled enough : let's compress */ - && (zcs->nextJobID <= zcs->doneJobID + zcs->jobIDMask) ) { /* avoid overwriting job round buffer */ - CHECK_F( ZSTDMT_createCompressionJob(zcs, zcs->targetSectionSize, 0) ); + if ( (mtctx->inBuff.filled >= newJobThreshold) /* filled enough : let's compress */ + && (mtctx->nextJobID <= mtctx->doneJobID + mtctx->jobIDMask) ) { /* avoid overwriting job round buffer */ + CHECK_F( ZSTDMT_createCompressionJob(mtctx, mtctx->targetSectionSize, 0 /* endFrame */) ); } - /* check for data to flush */ - CHECK_F( ZSTDMT_flushNextJob(zcs, output, (zcs->inBuff.filled == zcs->inBuffSize)) ); /* block if it wasn't possible to create new job due to saturation */ + /* check for potential compressed data ready to be flushed */ + CHECK_F( ZSTDMT_flushNextJob(mtctx, output, (mtctx->inBuff.filled == mtctx->inBuffSize) /* blockToFlush */) ); /* block if it wasn't possible to create new job due to saturation */ + + if (input->pos < input->size) /* input not consumed : do not flush yet */ + endOp = ZSTD_e_continue; + + switch(endOp) + { + case ZSTD_e_flush: + return ZSTDMT_flushStream(mtctx, output); + case ZSTD_e_end: + return ZSTDMT_endStream(mtctx, output); + case ZSTD_e_continue: + return 1; + default: + return ERROR(GENERIC); /* invalid endDirective */ + } +} + + +size_t ZSTDMT_compressStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input) +{ + CHECK_F( ZSTDMT_compressStream_generic(zcs, output, input, ZSTD_e_continue) ); /* recommended next input size : fill current input buffer */ return zcs->inBuffSize - zcs->inBuff.filled; /* note : could be zero when input buffer is fully filled and no more availability to create new job */ @@ -726,26 +928,28 @@ static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* outp { size_t const srcSize = zcs->inBuff.filled - zcs->dictSize; - if (srcSize) DEBUGLOG(4, "flushing : %u bytes left to compress", (U32)srcSize); if ( ((srcSize > 0) || (endFrame && !zcs->frameEnded)) && (zcs->nextJobID <= zcs->doneJobID + zcs->jobIDMask) ) { CHECK_F( ZSTDMT_createCompressionJob(zcs, srcSize, endFrame) ); } /* check if there is any data available to flush */ - DEBUGLOG(5, "zcs->doneJobID : %u ; zcs->nextJobID : %u ", zcs->doneJobID, zcs->nextJobID); - return ZSTDMT_flushNextJob(zcs, output, 1); + return ZSTDMT_flushNextJob(zcs, output, 1 /* blockToFlush */); } size_t ZSTDMT_flushStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output) { - if (zcs->nbThreads==1) return ZSTD_flushStream(zcs->cstream, output); - return ZSTDMT_flushStream_internal(zcs, output, 0); + DEBUGLOG(5, "ZSTDMT_flushStream"); + if (zcs->nbThreads==1) + return ZSTD_flushStream(zcs->cctxPool->cctx[0], output); + return ZSTDMT_flushStream_internal(zcs, output, 0 /* endFrame */); } size_t ZSTDMT_endStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output) { - if (zcs->nbThreads==1) return ZSTD_endStream(zcs->cstream, output); - return ZSTDMT_flushStream_internal(zcs, output, 1); + DEBUGLOG(4, "ZSTDMT_endStream"); + if (zcs->nbThreads==1) + return ZSTD_endStream(zcs->cctxPool->cctx[0], output); + return ZSTDMT_flushStream_internal(zcs, output, 1 /* endFrame */); } diff --git a/thirdparty/zstd/compress/zstdmt_compress.h b/thirdparty/zstd/compress/zstdmt_compress.h index 27f78ee031..fad63b6d86 100644 --- a/thirdparty/zstd/compress/zstdmt_compress.h +++ b/thirdparty/zstd/compress/zstdmt_compress.h @@ -15,25 +15,34 @@ #endif -/* Note : All prototypes defined in this file shall be considered experimental. - * There is no guarantee of API continuity (yet) on any of these prototypes */ +/* Note : All prototypes defined in this file are labelled experimental. + * No guarantee of API continuity is provided on any of them. + * In fact, the expectation is that these prototypes will be replaced + * by ZSTD_compress_generic() API in the near future */ /* === Dependencies === */ -#include <stddef.h> /* size_t */ +#include <stddef.h> /* size_t */ #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters */ -#include "zstd.h" /* ZSTD_inBuffer, ZSTD_outBuffer, ZSTDLIB_API */ +#include "zstd.h" /* ZSTD_inBuffer, ZSTD_outBuffer, ZSTDLIB_API */ -/* === Simple one-pass functions === */ - +/* === Memory management === */ typedef struct ZSTDMT_CCtx_s ZSTDMT_CCtx; ZSTDLIB_API ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbThreads); -ZSTDLIB_API size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* cctx); +ZSTDLIB_API ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, + ZSTD_customMem cMem); +ZSTDLIB_API size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx); + +ZSTDLIB_API size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx); + + +/* === Simple buffer-to-butter one-pass function === */ + +ZSTDLIB_API size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + int compressionLevel); -ZSTDLIB_API size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - int compressionLevel); /* === Streaming functions === */ @@ -53,8 +62,22 @@ ZSTDLIB_API size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output); # define ZSTDMT_SECTION_SIZE_MIN (1U << 20) /* 1 MB - Minimum size of each compression job */ #endif -ZSTDLIB_API size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx, const void* dict, size_t dictSize, /**< dict can be released after init, a local copy is preserved within zcs */ - ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize is optional and can be zero == unknown */ +ZSTDLIB_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, + ZSTD_parameters const params, + unsigned overlapRLog); + +ZSTDLIB_API size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx, + const void* dict, size_t dictSize, /* dict can be released after init, a local copy is preserved within zcs */ + ZSTD_parameters params, + unsigned long long pledgedSrcSize); /* pledgedSrcSize is optional and can be zero == unknown */ + +ZSTDLIB_API size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fparams, + unsigned long long pledgedSrcSize); /* note : zero means empty */ /* ZSDTMT_parameter : * List of parameters that can be set using ZSTDMT_setMTCtxParameter() */ @@ -71,6 +94,19 @@ typedef enum { ZSTDLIB_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSDTMT_parameter parameter, unsigned value); +/*! ZSTDMT_compressStream_generic() : + * Combines ZSTDMT_compressStream() with ZSTDMT_flushStream() or ZSTDMT_endStream() + * depending on flush directive. + * @return : minimum amount of data still to be flushed + * 0 if fully flushed + * or an error code */ +ZSTDLIB_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input, + ZSTD_EndDirective endOp); + + + #if defined (__cplusplus) } #endif diff --git a/thirdparty/zstd/decompress/huf_decompress.c b/thirdparty/zstd/decompress/huf_decompress.c index ea35c36201..2a1b70ea5e 100644 --- a/thirdparty/zstd/decompress/huf_decompress.c +++ b/thirdparty/zstd/decompress/huf_decompress.c @@ -67,6 +67,12 @@ #define HUF_STATIC_ASSERT(c) { enum { HUF_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ +/* ************************************************************** +* Byte alignment for workSpace management +****************************************************************/ +#define HUF_ALIGN(x, a) HUF_ALIGN_MASK((x), (a) - 1) +#define HUF_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) + /*-***************************/ /* generic DTableDesc */ /*-***************************/ @@ -87,16 +93,28 @@ static DTableDesc HUF_getDTableDesc(const HUF_DTable* table) typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX2; /* single-symbol decoding */ -size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize) +size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize) { - BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; - U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */ U32 tableLog = 0; U32 nbSymbols = 0; size_t iSize; void* const dtPtr = DTable + 1; HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr; + U32* rankVal; + BYTE* huffWeight; + size_t spaceUsed32 = 0; + + rankVal = (U32 *)workSpace + spaceUsed32; + spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1; + huffWeight = (BYTE *)((U32 *)workSpace + spaceUsed32); + spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2; + + if ((spaceUsed32 << 2) > wkspSize) + return ERROR(tableLog_tooLarge); + workSpace = (U32 *)workSpace + spaceUsed32; + wkspSize -= (spaceUsed32 << 2); + HUF_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable)); /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ @@ -135,6 +153,13 @@ size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize) return iSize; } +size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_readDTableX2_wksp(DTable, src, srcSize, + workSpace, sizeof(workSpace)); +} + static BYTE HUF_decodeSymbolX2(BIT_DStream_t* Dstream, const HUF_DEltX2* dt, const U32 dtLog) { @@ -212,11 +237,13 @@ size_t HUF_decompress1X2_usingDTable( return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable); } -size_t HUF_decompress1X2_DCtx (HUF_DTable* DCtx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) { const BYTE* ip = (const BYTE*) cSrc; - size_t const hSize = HUF_readDTableX2 (DCtx, cSrc, cSrcSize); + size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, workSpace, wkspSize); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; @@ -224,6 +251,15 @@ size_t HUF_decompress1X2_DCtx (HUF_DTable* DCtx, void* dst, size_t dstSize, cons return HUF_decompress1X2_usingDTable_internal (dst, dstSize, ip, cSrcSize, DCtx); } + +size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) { HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); @@ -335,11 +371,14 @@ size_t HUF_decompress4X2_usingDTable( } -size_t HUF_decompress4X2_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) { const BYTE* ip = (const BYTE*) cSrc; - size_t const hSize = HUF_readDTableX2 (dctx, cSrc, cSrcSize); + size_t const hSize = HUF_readDTableX2_wksp (dctx, cSrc, cSrcSize, + workSpace, wkspSize); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; @@ -347,6 +386,13 @@ size_t HUF_decompress4X2_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, cons return HUF_decompress4X2_usingDTable_internal (dst, dstSize, ip, cSrcSize, dctx); } + +size_t HUF_decompress4X2_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) { HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); @@ -403,7 +449,8 @@ static void HUF_fillDTableX4Level2(HUF_DEltX4* DTable, U32 sizeLog, const U32 co } } } -typedef U32 rankVal_t[HUF_TABLELOG_MAX][HUF_TABLELOG_MAX + 1]; +typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1]; +typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX]; static void HUF_fillDTableX4(HUF_DEltX4* DTable, const U32 targetLog, const sortedSymbol_t* sortedList, const U32 sortedListSize, @@ -447,20 +494,43 @@ static void HUF_fillDTableX4(HUF_DEltX4* DTable, const U32 targetLog, } } -size_t HUF_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize) +size_t HUF_readDTableX4_wksp(HUF_DTable* DTable, const void* src, + size_t srcSize, void* workSpace, + size_t wkspSize) { - BYTE weightList[HUF_SYMBOLVALUE_MAX + 1]; - sortedSymbol_t sortedSymbol[HUF_SYMBOLVALUE_MAX + 1]; - U32 rankStats[HUF_TABLELOG_MAX + 1] = { 0 }; - U32 rankStart0[HUF_TABLELOG_MAX + 2] = { 0 }; - U32* const rankStart = rankStart0+1; - rankVal_t rankVal; U32 tableLog, maxW, sizeOfSort, nbSymbols; DTableDesc dtd = HUF_getDTableDesc(DTable); U32 const maxTableLog = dtd.maxTableLog; size_t iSize; void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */ HUF_DEltX4* const dt = (HUF_DEltX4*)dtPtr; + U32 *rankStart; + + rankValCol_t* rankVal; + U32* rankStats; + U32* rankStart0; + sortedSymbol_t* sortedSymbol; + BYTE* weightList; + size_t spaceUsed32 = 0; + + rankVal = (rankValCol_t *)((U32 *)workSpace + spaceUsed32); + spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2; + rankStats = (U32 *)workSpace + spaceUsed32; + spaceUsed32 += HUF_TABLELOG_MAX + 1; + rankStart0 = (U32 *)workSpace + spaceUsed32; + spaceUsed32 += HUF_TABLELOG_MAX + 2; + sortedSymbol = (sortedSymbol_t *)workSpace + (spaceUsed32 * sizeof(U32)) / sizeof(sortedSymbol_t); + spaceUsed32 += HUF_ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2; + weightList = (BYTE *)((U32 *)workSpace + spaceUsed32); + spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2; + + if ((spaceUsed32 << 2) > wkspSize) + return ERROR(tableLog_tooLarge); + workSpace = (U32 *)workSpace + spaceUsed32; + wkspSize -= (spaceUsed32 << 2); + + rankStart = rankStart0 + 1; + memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1)); HUF_STATIC_ASSERT(sizeof(HUF_DEltX4) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */ if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); @@ -527,6 +597,12 @@ size_t HUF_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize) return iSize; } +size_t HUF_readDTableX4(HUF_DTable* DTable, const void* src, size_t srcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_readDTableX4_wksp(DTable, src, srcSize, + workSpace, sizeof(workSpace)); +} static U32 HUF_decodeSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DEltX4* dt, const U32 dtLog) { @@ -545,7 +621,8 @@ static U32 HUF_decodeLastSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DE if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) { BIT_skipBits(DStream, dt[val].nbBits); if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8)) - DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */ + /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */ + DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); } } return 1; } @@ -626,11 +703,14 @@ size_t HUF_decompress1X4_usingDTable( return HUF_decompress1X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable); } -size_t HUF_decompress1X4_DCtx (HUF_DTable* DCtx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) { const BYTE* ip = (const BYTE*) cSrc; - size_t const hSize = HUF_readDTableX4 (DCtx, cSrc, cSrcSize); + size_t const hSize = HUF_readDTableX4_wksp(DCtx, cSrc, cSrcSize, + workSpace, wkspSize); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; @@ -638,6 +718,15 @@ size_t HUF_decompress1X4_DCtx (HUF_DTable* DCtx, void* dst, size_t dstSize, cons return HUF_decompress1X4_usingDTable_internal (dst, dstSize, ip, cSrcSize, DCtx); } + +size_t HUF_decompress1X4_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X4_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + size_t HUF_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) { HUF_CREATE_STATIC_DTABLEX4(DTable, HUF_TABLELOG_MAX); @@ -748,11 +837,14 @@ size_t HUF_decompress4X4_usingDTable( } -size_t HUF_decompress4X4_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) { const BYTE* ip = (const BYTE*) cSrc; - size_t hSize = HUF_readDTableX4 (dctx, cSrc, cSrcSize); + size_t hSize = HUF_readDTableX4_wksp(dctx, cSrc, cSrcSize, + workSpace, wkspSize); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; @@ -760,6 +852,15 @@ size_t HUF_decompress4X4_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, cons return HUF_decompress4X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx); } + +size_t HUF_decompress4X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + size_t HUF_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) { HUF_CREATE_STATIC_DTABLEX4(DTable, HUF_TABLELOG_MAX); @@ -861,19 +962,32 @@ size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const } } -size_t HUF_decompress4X_hufOnly (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + + +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, + size_t dstSize, const void* cSrc, + size_t cSrcSize, void* workSpace, + size_t wkspSize) { /* validation checks */ if (dstSize == 0) return ERROR(dstSize_tooSmall); if ((cSrcSize >= dstSize) || (cSrcSize <= 1)) return ERROR(corruption_detected); /* invalid */ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); - return algoNb ? HUF_decompress4X4_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) : - HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ; + return algoNb ? HUF_decompress4X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize): + HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); } } -size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) { /* validation checks */ if (dstSize == 0) return ERROR(dstSize_tooSmall); @@ -882,7 +996,17 @@ size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); - return algoNb ? HUF_decompress1X4_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) : - HUF_decompress1X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ; + return algoNb ? HUF_decompress1X4_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize): + HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize); } } + +size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} diff --git a/thirdparty/zstd/decompress/zstd_decompress.c b/thirdparty/zstd/decompress/zstd_decompress.c index 910f9ab783..465bcc20b5 100644 --- a/thirdparty/zstd/decompress/zstd_decompress.c +++ b/thirdparty/zstd/decompress/zstd_decompress.c @@ -53,8 +53,7 @@ # include "zstd_legacy.h" #endif - -#if defined(_MSC_VER) +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */ # include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ # define ZSTD_PREFETCH(ptr) _mm_prefetch((const char*)ptr, _MM_HINT_T0) #elif defined(__GNUC__) @@ -63,8 +62,9 @@ # define ZSTD_PREFETCH(ptr) /* disabled */ #endif + /*-************************************* -* Macros +* Errors ***************************************/ #define ZSTD_isError ERR_isError /* for inlining */ #define FSE_isError ERR_isError @@ -85,11 +85,15 @@ typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, ZSTDds_decompressLastBlock, ZSTDds_checkChecksum, ZSTDds_decodeSkippableHeader, ZSTDds_skipFrame } ZSTD_dStage; +typedef enum { zdss_init=0, zdss_loadHeader, + zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage; + typedef struct { FSE_DTable LLTable[FSE_DTABLE_SIZE_U32(LLFSELog)]; FSE_DTable OFTable[FSE_DTABLE_SIZE_U32(OffFSELog)]; FSE_DTable MLTable[FSE_DTABLE_SIZE_U32(MLFSELog)]; HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */ + U32 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; U32 rep[ZSTD_REP_NUM]; } ZSTD_entropyTables_t; @@ -105,7 +109,7 @@ struct ZSTD_DCtx_s const void* vBase; /* virtual start of previous segment if it was just before current one */ const void* dictEnd; /* end of previous segment */ size_t expected; - ZSTD_frameParams fParams; + ZSTD_frameHeader fParams; blockType_e bType; /* used in ZSTD_decompressContinue(), to transfer blockType between header decoding and block decoding stages */ ZSTD_dStage stage; U32 litEntropy; @@ -117,11 +121,39 @@ struct ZSTD_DCtx_s ZSTD_customMem customMem; size_t litSize; size_t rleSize; - BYTE litBuffer[ZSTD_BLOCKSIZE_ABSOLUTEMAX + WILDCOPY_OVERLENGTH]; + size_t staticSize; + + /* streaming */ + ZSTD_DDict* ddictLocal; + const ZSTD_DDict* ddict; + ZSTD_dStreamStage streamStage; + char* inBuff; + size_t inBuffSize; + size_t inPos; + size_t maxWindowSize; + char* outBuff; + size_t outBuffSize; + size_t outStart; + size_t outEnd; + size_t blockSize; + size_t lhSize; + void* legacyContext; + U32 previousLegacyVersion; + U32 legacyVersion; + U32 hostageByte; + + /* workspace */ + BYTE litBuffer[ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH]; BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; }; /* typedef'd to ZSTD_DCtx within "zstd.h" */ -size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx) { return (dctx==NULL) ? 0 : sizeof(ZSTD_DCtx); } +size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx) +{ + if (dctx==NULL) return 0; /* support sizeof NULL */ + return sizeof(*dctx) + + ZSTD_sizeof_DDict(dctx->ddictLocal) + + dctx->inBuffSize + dctx->outBuffSize; +} size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); } @@ -145,40 +177,76 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) return 0; } +static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) +{ + ZSTD_decompressBegin(dctx); /* cannot fail */ + dctx->staticSize = 0; + dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; + dctx->ddict = NULL; + dctx->ddictLocal = NULL; + dctx->inBuff = NULL; + dctx->inBuffSize = 0; + dctx->outBuffSize= 0; + dctx->streamStage = zdss_init; +} + ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) { - ZSTD_DCtx* dctx; + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem; - if (!customMem.customAlloc || !customMem.customFree) return NULL; + { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(*dctx), customMem); + if (!dctx) return NULL; + dctx->customMem = customMem; + dctx->legacyContext = NULL; + dctx->previousLegacyVersion = 0; + ZSTD_initDCtx_internal(dctx); + return dctx; + } +} - dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(ZSTD_DCtx), customMem); - if (!dctx) return NULL; - memcpy(&dctx->customMem, &customMem, sizeof(customMem)); - ZSTD_decompressBegin(dctx); +ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize) +{ + ZSTD_DCtx* dctx = (ZSTD_DCtx*) workspace; + + if ((size_t)workspace & 7) return NULL; /* 8-aligned */ + if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */ + + ZSTD_initDCtx_internal(dctx); + dctx->staticSize = workspaceSize; + dctx->inBuff = (char*)(dctx+1); return dctx; } ZSTD_DCtx* ZSTD_createDCtx(void) { - return ZSTD_createDCtx_advanced(defaultCustomMem); + return ZSTD_createDCtx_advanced(ZSTD_defaultCMem); } size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) { if (dctx==NULL) return 0; /* support free on NULL */ - ZSTD_free(dctx, dctx->customMem); - return 0; /* reserved as a potential error code in the future */ + if (dctx->staticSize) return ERROR(memory_allocation); /* not compatible with static DCtx */ + { ZSTD_customMem const cMem = dctx->customMem; + ZSTD_freeDDict(dctx->ddictLocal); + dctx->ddictLocal = NULL; + ZSTD_free(dctx->inBuff, cMem); + dctx->inBuff = NULL; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (dctx->legacyContext) + ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion); +#endif + ZSTD_free(dctx, cMem); + return 0; + } } +/* no longer useful */ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) { - size_t const workSpaceSize = (ZSTD_BLOCKSIZE_ABSOLUTEMAX+WILDCOPY_OVERLENGTH) + ZSTD_frameHeaderSize_max; - memcpy(dstDCtx, srcDCtx, sizeof(ZSTD_DCtx) - workSpaceSize); /* no need to copy workspace */ + size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx); + memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */ } -static void ZSTD_refDDict(ZSTD_DCtx* dstDCtx, const ZSTD_DDict* ddict); - /*-************************************************************* * Decompression section @@ -206,7 +274,7 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size) /** ZSTD_frameHeaderSize() : * srcSize must be >= ZSTD_frameHeaderSize_prefix. * @return : size of the Frame Header */ -static size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) +size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) { if (srcSize < ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong); { BYTE const fhd = ((const BYTE*)src)[4]; @@ -219,22 +287,24 @@ static size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) } -/** ZSTD_getFrameParams() : +/** ZSTD_getFrameHeader() : * decode Frame Header, or require larger `srcSize`. -* @return : 0, `fparamsPtr` is correctly filled, +* @return : 0, `zfhPtr` is correctly filled, * >0, `srcSize` is too small, result is expected `srcSize`, * or an error code, which can be tested using ZSTD_isError() */ -size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize) +size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize) { const BYTE* ip = (const BYTE*)src; - if (srcSize < ZSTD_frameHeaderSize_prefix) return ZSTD_frameHeaderSize_prefix; + if (MEM_readLE32(src) != ZSTD_MAGICNUMBER) { if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { - if (srcSize < ZSTD_skippableHeaderSize) return ZSTD_skippableHeaderSize; /* magic number + skippable frame length */ - memset(fparamsPtr, 0, sizeof(*fparamsPtr)); - fparamsPtr->frameContentSize = MEM_readLE32((const char *)src + 4); - fparamsPtr->windowSize = 0; /* windowSize==0 means a frame is skippable */ + /* skippable frame */ + if (srcSize < ZSTD_skippableHeaderSize) + return ZSTD_skippableHeaderSize; /* magic number + frame length */ + memset(zfhPtr, 0, sizeof(*zfhPtr)); + zfhPtr->frameContentSize = MEM_readLE32((const char *)src + 4); + zfhPtr->windowSize = 0; /* windowSize==0 means a frame is skippable */ return 0; } return ERROR(prefix_unknown); @@ -254,11 +324,13 @@ size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t U32 windowSize = 0; U32 dictID = 0; U64 frameContentSize = 0; - if ((fhdByte & 0x08) != 0) return ERROR(frameParameter_unsupported); /* reserved bits, which must be zero */ + if ((fhdByte & 0x08) != 0) + return ERROR(frameParameter_unsupported); /* reserved bits, must be zero */ if (!singleSegment) { BYTE const wlByte = ip[pos++]; U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN; - if (windowLog > ZSTD_WINDOWLOG_MAX) return ERROR(frameParameter_windowTooLarge); /* avoids issue with 1 << windowLog */ + if (windowLog > ZSTD_WINDOWLOG_MAX) + return ERROR(frameParameter_windowTooLarge); windowSize = (1U << windowLog); windowSize += (windowSize >> 3) * (wlByte&7); } @@ -281,10 +353,10 @@ size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t } if (!windowSize) windowSize = (U32)frameContentSize; if (windowSize > windowSizeMax) return ERROR(frameParameter_windowTooLarge); - fparamsPtr->frameContentSize = frameContentSize; - fparamsPtr->windowSize = windowSize; - fparamsPtr->dictID = dictID; - fparamsPtr->checksumFlag = checksumFlag; + zfhPtr->frameContentSize = frameContentSize; + zfhPtr->windowSize = windowSize; + zfhPtr->dictID = dictID; + zfhPtr->checksumFlag = checksumFlag; } return 0; } @@ -302,9 +374,8 @@ unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize) return ret == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret; } #endif - { - ZSTD_frameParams fParams; - if (ZSTD_getFrameParams(&fParams, src, srcSize) != 0) return ZSTD_CONTENTSIZE_ERROR; + { ZSTD_frameHeader fParams; + if (ZSTD_getFrameHeader(&fParams, src, srcSize) != 0) return ZSTD_CONTENTSIZE_ERROR; if (fParams.windowSize == 0) { /* Either skippable or empty frame, size == 0 either way */ return 0; @@ -323,51 +394,48 @@ unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize) * @return : decompressed size of the frames contained */ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) { - { - unsigned long long totalDstSize = 0; - while (srcSize >= ZSTD_frameHeaderSize_prefix) { - const U32 magicNumber = MEM_readLE32(src); - - if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { - size_t skippableSize; - if (srcSize < ZSTD_skippableHeaderSize) - return ERROR(srcSize_wrong); - skippableSize = MEM_readLE32((const BYTE *)src + 4) + - ZSTD_skippableHeaderSize; - if (srcSize < skippableSize) { - return ZSTD_CONTENTSIZE_ERROR; - } + unsigned long long totalDstSize = 0; - src = (const BYTE *)src + skippableSize; - srcSize -= skippableSize; - continue; + while (srcSize >= ZSTD_frameHeaderSize_prefix) { + const U32 magicNumber = MEM_readLE32(src); + + if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { + size_t skippableSize; + if (srcSize < ZSTD_skippableHeaderSize) + return ERROR(srcSize_wrong); + skippableSize = MEM_readLE32((const BYTE *)src + 4) + + ZSTD_skippableHeaderSize; + if (srcSize < skippableSize) { + return ZSTD_CONTENTSIZE_ERROR; } - { - unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize); - if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret; + src = (const BYTE *)src + skippableSize; + srcSize -= skippableSize; + continue; + } - /* check for overflow */ - if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR; - totalDstSize += ret; - } - { - size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize); - if (ZSTD_isError(frameSrcSize)) { - return ZSTD_CONTENTSIZE_ERROR; - } + { unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize); + if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret; - src = (const BYTE *)src + frameSrcSize; - srcSize -= frameSrcSize; - } + /* check for overflow */ + if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR; + totalDstSize += ret; } + { size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize); + if (ZSTD_isError(frameSrcSize)) { + return ZSTD_CONTENTSIZE_ERROR; + } - if (srcSize) { - return ZSTD_CONTENTSIZE_ERROR; + src = (const BYTE *)src + frameSrcSize; + srcSize -= frameSrcSize; } + } - return totalDstSize; + if (srcSize) { + return ZSTD_CONTENTSIZE_ERROR; } + + return totalDstSize; } /** ZSTD_getDecompressedSize() : @@ -389,7 +457,7 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize) * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize) { - size_t const result = ZSTD_getFrameParams(&(dctx->fParams), src, headerSize); + size_t const result = ZSTD_getFrameHeader(&(dctx->fParams), src, headerSize); if (ZSTD_isError(result)) return result; /* invalid header */ if (result>0) return ERROR(srcSize_wrong); /* headerSize too small */ if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID)) return ERROR(dictionary_wrong); @@ -398,13 +466,6 @@ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t he } -typedef struct -{ - blockType_e blockType; - U32 lastBlock; - U32 origSize; -} blockProperties_t; - /*! ZSTD_getcBlockSize() : * Provides the size of compressed block from block header `src` */ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, @@ -485,7 +546,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, litCSize = (lhc >> 22) + (istart[4] << 10); break; } - if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX) return ERROR(corruption_detected); + if (litSize > ZSTD_BLOCKSIZE_MAX) return ERROR(corruption_detected); if (litCSize + lhSize > srcSize) return ERROR(corruption_detected); if (HUF_isError((litEncType==set_repeat) ? @@ -493,8 +554,10 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, HUF_decompress1X_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->HUFptr) : HUF_decompress4X_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->HUFptr) ) : ( singleStream ? - HUF_decompress1X2_DCtx(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize) : - HUF_decompress4X_hufOnly (dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize)) )) + HUF_decompress1X2_DCtx_wksp(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize, + dctx->entropy.workspace, sizeof(dctx->entropy.workspace)) : + HUF_decompress4X_hufOnly_wksp(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize, + dctx->entropy.workspace, sizeof(dctx->entropy.workspace))))) return ERROR(corruption_detected); dctx->litPtr = dctx->litBuffer; @@ -557,7 +620,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, if (srcSize<4) return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4 */ break; } - if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX) return ERROR(corruption_detected); + if (litSize > ZSTD_BLOCKSIZE_MAX) return ERROR(corruption_detected); memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH); dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; @@ -684,6 +747,7 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, const BYTE* const istart = (const BYTE* const)src; const BYTE* const iend = istart + srcSize; const BYTE* ip = istart; + DEBUGLOG(5, "ZSTD_decodeSeqHeaders"); /* check */ if (srcSize < MIN_SEQUENCES_SIZE) return ERROR(srcSize_wrong); @@ -864,12 +928,18 @@ static seq_t ZSTD_decodeSequence(seqState_t* seqState) seq.offset = offset; } - seq.matchLength = ML_base[mlCode] + ((mlCode>31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */ + seq.matchLength = ML_base[mlCode] + + ((mlCode>31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */ if (MEM_32bits() && (mlBits+llBits>24)) BIT_reloadDStream(&seqState->DStream); - seq.litLength = LL_base[llCode] + ((llCode>15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */ - if (MEM_32bits() || - (totalBits > 64 - 7 - (LLFSELog+MLFSELog+OffFSELog)) ) BIT_reloadDStream(&seqState->DStream); + seq.litLength = LL_base[llCode] + + ((llCode>15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */ + if ( MEM_32bits() + || (totalBits > 64 - 7 - (LLFSELog+MLFSELog+OffFSELog)) ) + BIT_reloadDStream(&seqState->DStream); + + DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); /* ANS state update */ FSE_updateState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */ @@ -909,7 +979,8 @@ size_t ZSTD_execSequence(BYTE* op, /* copy Match */ if (sequence.offset > (size_t)(oLitEnd - base)) { /* offset beyond prefix -> go into extDict */ - if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected); + if (sequence.offset > (size_t)(oLitEnd - vBase)) + return ERROR(corruption_detected); match = dictEnd + (match - base); if (match + sequence.matchLength <= dictEnd) { memmove(oLitEnd, match, sequence.matchLength); @@ -977,9 +1048,12 @@ static size_t ZSTD_decompressSequences( const BYTE* const vBase = (const BYTE*) (dctx->vBase); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); int nbSeq; + DEBUGLOG(5, "ZSTD_decompressSequences"); /* Build Decoding Tables */ { size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize); + DEBUGLOG(5, "ZSTD_decodeSeqHeaders: size=%u, nbSeq=%i", + (U32)seqHSize, nbSeq); if (ZSTD_isError(seqHSize)) return seqHSize; ip += seqHSize; } @@ -998,11 +1072,13 @@ static size_t ZSTD_decompressSequences( nbSeq--; { seq_t const sequence = ZSTD_decodeSequence(&seqState); size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd); + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); if (ZSTD_isError(oneSeqSize)) return oneSeqSize; op += oneSeqSize; } } /* check if reached exact end */ + DEBUGLOG(5, "after decode loop, remaining nbSeq : %i", nbSeq); if (nbSeq) return ERROR(corruption_detected); /* save reps for next block */ { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); } @@ -1216,7 +1292,7 @@ static size_t ZSTD_decompressSequencesLong( const BYTE* const base = (const BYTE*) (dctx->base); const BYTE* const vBase = (const BYTE*) (dctx->vBase); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); - unsigned const windowSize = dctx->fParams.windowSize; + unsigned const windowSize32 = (unsigned)dctx->fParams.windowSize; int nbSeq; /* Build Decoding Tables */ @@ -1246,13 +1322,13 @@ static size_t ZSTD_decompressSequencesLong( /* prepare in advance */ for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && seqNb<seqAdvance; seqNb++) { - sequences[seqNb] = ZSTD_decodeSequenceLong(&seqState, windowSize); + sequences[seqNb] = ZSTD_decodeSequenceLong(&seqState, windowSize32); } if (seqNb<seqAdvance) return ERROR(corruption_detected); /* decode and decompress */ for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && seqNb<nbSeq ; seqNb++) { - seq_t const sequence = ZSTD_decodeSequenceLong(&seqState, windowSize); + seq_t const sequence = ZSTD_decodeSequenceLong(&seqState, windowSize32); size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STOSEQ_MASK], &litPtr, litEnd, base, vBase, dictEnd); if (ZSTD_isError(oneSeqSize)) return oneSeqSize; ZSTD_PREFETCH(sequence.match); @@ -1289,11 +1365,13 @@ static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, const void* src, size_t srcSize) { /* blockType == blockCompressed */ const BYTE* ip = (const BYTE*)src; + DEBUGLOG(5, "ZSTD_decompressBlock_internal"); - if (srcSize >= ZSTD_BLOCKSIZE_ABSOLUTEMAX) return ERROR(srcSize_wrong); + if (srcSize >= ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* Decode literals section */ { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize); + DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : %u", (U32)litCSize); if (ZSTD_isError(litCSize)) return litCSize; ip += litCSize; srcSize -= litCSize; @@ -1364,13 +1442,13 @@ size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize) const BYTE* ip = (const BYTE*)src; const BYTE* const ipstart = ip; size_t remainingSize = srcSize; - ZSTD_frameParams fParams; + ZSTD_frameHeader fParams; size_t const headerSize = ZSTD_frameHeaderSize(ip, remainingSize); if (ZSTD_isError(headerSize)) return headerSize; /* Frame Header */ - { size_t const ret = ZSTD_getFrameParams(&fParams, ip, remainingSize); + { size_t const ret = ZSTD_getFrameHeader(&fParams, ip, remainingSize); if (ZSTD_isError(ret)) return ret; if (ret > 0) return ERROR(srcSize_wrong); } @@ -1505,6 +1583,8 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, size_t decodedSize; size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize); if (ZSTD_isError(frameSize)) return frameSize; + /* legacy support is incompatible with static dctx */ + if (dctx->staticSize) return ERROR(memory_allocation); decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize); @@ -1540,7 +1620,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, if (ddict) { /* we were called from ZSTD_decompress_usingDDict */ - ZSTD_refDDict(dctx, ddict); + CHECK_F(ZSTD_decompressBegin_usingDDict(dctx, ddict)); } else { /* this will initialize correctly with no dict if dict == NULL, so * use this in all cases but ddict */ @@ -1580,7 +1660,7 @@ size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { -#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE==1) +#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1) size_t regenSize; ZSTD_DCtx* const dctx = ZSTD_createDCtx(); if (dctx==NULL) return ERROR(memory_allocation); @@ -1604,6 +1684,7 @@ ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { switch(dctx->stage) { default: /* should not happen */ + assert(0); case ZSTDds_getFrameHeaderSize: case ZSTDds_decodeFrameHeader: return ZSTDnit_frameHeader; @@ -1621,21 +1702,24 @@ ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { } } -int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; } /* for zbuff */ +static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; } /** ZSTD_decompressContinue() : -* @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity) -* or an error code, which can be tested using ZSTD_isError() */ + * srcSize : must be the exact nb of bytes expected (see ZSTD_nextSrcSizeToDecompress()) + * @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity) + * or an error code, which can be tested using ZSTD_isError() */ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { + DEBUGLOG(5, "ZSTD_decompressContinue"); /* Sanity check */ - if (srcSize != dctx->expected) return ERROR(srcSize_wrong); + if (srcSize != dctx->expected) return ERROR(srcSize_wrong); /* unauthorized */ if (dstCapacity) ZSTD_checkContinuity(dctx, dst); switch (dctx->stage) { case ZSTDds_getFrameHeaderSize : - if (srcSize != ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong); /* impossible */ + if (srcSize != ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong); /* unauthorized */ + assert(src != NULL); if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix); dctx->expected = ZSTD_skippableHeaderSize - ZSTD_frameHeaderSize_prefix; /* magic number + skippable frame length */ @@ -1653,6 +1737,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c dctx->expected = 0; /* not necessary to copy more */ case ZSTDds_decodeFrameHeader: + assert(src != NULL); memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected); CHECK_F(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize)); dctx->expected = ZSTD_blockHeaderSize; @@ -1680,17 +1765,19 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c dctx->stage = ZSTDds_getFrameHeaderSize; } } else { - dctx->expected = 3; /* go directly to next header */ + dctx->expected = ZSTD_blockHeaderSize; /* jump to next header */ dctx->stage = ZSTDds_decodeBlockHeader; } return 0; } case ZSTDds_decompressLastBlock: case ZSTDds_decompressBlock: + DEBUGLOG(5, "case ZSTDds_decompressBlock"); { size_t rSize; switch(dctx->bType) { case bt_compressed: + DEBUGLOG(5, "case bt_compressed"); rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize); break; case bt_raw : @@ -1730,7 +1817,8 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c return 0; } case ZSTDds_decodeSkippableHeader: - { memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected); + { assert(src != NULL); + memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected); dctx->expected = MEM_readLE32(dctx->headerBuffer + 4); dctx->stage = ZSTDds_skipFrame; return 0; @@ -1767,7 +1855,9 @@ static size_t ZSTD_loadEntropy(ZSTD_entropyTables_t* entropy, const void* const dictPtr += 8; /* skip header = magic + dictID */ - { size_t const hSize = HUF_readDTableX4(entropy->hufTable, dictPtr, dictEnd-dictPtr); + { size_t const hSize = HUF_readDTableX4_wksp( + entropy->hufTable, dictPtr, dictEnd - dictPtr, + entropy->workspace, sizeof(entropy->workspace)); if (HUF_isError(hSize)) return ERROR(dictionary_corrupted); dictPtr += hSize; } @@ -1815,7 +1905,7 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict { if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize); { U32 const magic = MEM_readLE32(dict); - if (magic != ZSTD_DICT_MAGIC) { + if (magic != ZSTD_MAGIC_DICTIONARY) { return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */ } } dctx->dictID = MEM_readLE32((const char*)dict + 4); @@ -1862,10 +1952,10 @@ static size_t ZSTD_DDictDictSize(const ZSTD_DDict* ddict) return ddict->dictSize; } -static void ZSTD_refDDict(ZSTD_DCtx* dstDCtx, const ZSTD_DDict* ddict) +size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dstDCtx, const ZSTD_DDict* ddict) { - ZSTD_decompressBegin(dstDCtx); /* init */ - if (ddict) { /* support refDDict on NULL */ + CHECK_F(ZSTD_decompressBegin(dstDCtx)); + if (ddict) { /* support begin on NULL */ dstDCtx->dictID = ddict->dictID; dstDCtx->base = ddict->dictContent; dstDCtx->vBase = ddict->dictContent; @@ -1886,6 +1976,7 @@ static void ZSTD_refDDict(ZSTD_DCtx* dstDCtx, const ZSTD_DDict* ddict) dstDCtx->fseEntropy = 0; } } + return 0; } static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict* ddict) @@ -1894,7 +1985,7 @@ static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict* ddict) ddict->entropyPresent = 0; if (ddict->dictSize < 8) return 0; { U32 const magic = MEM_readLE32(ddict->dictContent); - if (magic != ZSTD_DICT_MAGIC) return 0; /* pure content mode */ + if (magic != ZSTD_MAGIC_DICTIONARY) return 0; /* pure content mode */ } ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + 4); @@ -1905,33 +1996,39 @@ static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict* ddict) } +static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, const void* dict, size_t dictSize, unsigned byReference) +{ + if ((byReference) || (!dict) || (!dictSize)) { + ddict->dictBuffer = NULL; + ddict->dictContent = dict; + } else { + void* const internalBuffer = ZSTD_malloc(dictSize, ddict->cMem); + ddict->dictBuffer = internalBuffer; + ddict->dictContent = internalBuffer; + if (!internalBuffer) return ERROR(memory_allocation); + memcpy(internalBuffer, dict, dictSize); + } + ddict->dictSize = dictSize; + ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ + + /* parse dictionary content */ + CHECK_F( ZSTD_loadEntropy_inDDict(ddict) ); + + return 0; +} + ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, unsigned byReference, ZSTD_customMem customMem) { - if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem; - if (!customMem.customAlloc || !customMem.customFree) return NULL; + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem); if (!ddict) return NULL; ddict->cMem = customMem; - if ((byReference) || (!dict) || (!dictSize)) { - ddict->dictBuffer = NULL; - ddict->dictContent = dict; - } else { - void* const internalBuffer = ZSTD_malloc(dictSize, customMem); - if (!internalBuffer) { ZSTD_freeDDict(ddict); return NULL; } - memcpy(internalBuffer, dict, dictSize); - ddict->dictBuffer = internalBuffer; - ddict->dictContent = internalBuffer; + if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, byReference) )) { + ZSTD_freeDDict(ddict); + return NULL; } - ddict->dictSize = dictSize; - ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ - /* parse dictionary content */ - { size_t const errorCode = ZSTD_loadEntropy_inDDict(ddict); - if (ZSTD_isError(errorCode)) { - ZSTD_freeDDict(ddict); - return NULL; - } } return ddict; } @@ -1947,7 +2044,6 @@ ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize) return ZSTD_createDDict_advanced(dict, dictSize, 0, allocator); } - /*! ZSTD_createDDict_byReference() : * Create a digested dictionary, to start decompression without startup delay. * Dictionary content is simply referenced, it will be accessed during decompression. @@ -1959,6 +2055,26 @@ ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize } +ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + unsigned byReference) +{ + size_t const neededSpace = sizeof(ZSTD_DDict) + (byReference ? 0 : dictSize); + ZSTD_DDict* const ddict = (ZSTD_DDict*)workspace; + assert(workspace != NULL); + assert(dict != NULL); + if ((size_t)workspace & 7) return NULL; /* 8-aligned */ + if (workspaceSize < neededSpace) return NULL; + if (!byReference) { + memcpy(ddict+1, dict, dictSize); /* local copy */ + dict = ddict+1; + } + if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, 1 /* byRef */) )) + return NULL; + return ddict; +} + + size_t ZSTD_freeDDict(ZSTD_DDict* ddict) { if (ddict==NULL) return 0; /* support free on NULL */ @@ -1969,6 +2085,14 @@ size_t ZSTD_freeDDict(ZSTD_DDict* ddict) } } +/*! ZSTD_estimateDDictSize() : + * Estimate amount of memory that will be needed to create a dictionary for decompression. + * Note : dictionary created "byReference" are smaller */ +size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference) +{ + return sizeof(ZSTD_DDict) + (byReference ? 0 : dictSize); +} + size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict) { if (ddict==NULL) return 0; /* support sizeof on NULL */ @@ -1982,7 +2106,7 @@ size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict) unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize) { if (dictSize < 8) return 0; - if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return 0; + if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0; return MEM_readLE32((const char*)dict + 4); } @@ -2008,11 +2132,11 @@ unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict) * Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`. * - This is not a Zstandard frame. * When identifying the exact failure cause, it's possible to use - * ZSTD_getFrameParams(), which will provide a more precise error code. */ + * ZSTD_getFrameHeader(), which will provide a more precise error code. */ unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize) { - ZSTD_frameParams zfp = { 0 , 0 , 0 , 0 }; - size_t const hError = ZSTD_getFrameParams(&zfp, src, srcSize); + ZSTD_frameHeader zfp = { 0 , 0 , 0 , 0 }; + size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize); if (ZSTD_isError(hError)) return 0; return zfp.dictID; } @@ -2037,88 +2161,35 @@ size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, * Streaming decompression *====================================*/ -typedef enum { zdss_init, zdss_loadHeader, - zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage; - -/* *** Resource management *** */ -struct ZSTD_DStream_s { - ZSTD_DCtx* dctx; - ZSTD_DDict* ddictLocal; - const ZSTD_DDict* ddict; - ZSTD_frameParams fParams; - ZSTD_dStreamStage stage; - char* inBuff; - size_t inBuffSize; - size_t inPos; - size_t maxWindowSize; - char* outBuff; - size_t outBuffSize; - size_t outStart; - size_t outEnd; - size_t blockSize; - BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; /* tmp buffer to store frame header */ - size_t lhSize; - ZSTD_customMem customMem; - void* legacyContext; - U32 previousLegacyVersion; - U32 legacyVersion; - U32 hostageByte; -}; /* typedef'd to ZSTD_DStream within "zstd.h" */ - - ZSTD_DStream* ZSTD_createDStream(void) { - return ZSTD_createDStream_advanced(defaultCustomMem); + return ZSTD_createDStream_advanced(ZSTD_defaultCMem); } -ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem) +ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize) { - ZSTD_DStream* zds; - - if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem; - if (!customMem.customAlloc || !customMem.customFree) return NULL; + return ZSTD_initStaticDCtx(workspace, workspaceSize); +} - zds = (ZSTD_DStream*) ZSTD_malloc(sizeof(ZSTD_DStream), customMem); - if (zds==NULL) return NULL; - memset(zds, 0, sizeof(ZSTD_DStream)); - memcpy(&zds->customMem, &customMem, sizeof(ZSTD_customMem)); - zds->dctx = ZSTD_createDCtx_advanced(customMem); - if (zds->dctx == NULL) { ZSTD_freeDStream(zds); return NULL; } - zds->stage = zdss_init; - zds->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; - return zds; +ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem) +{ + return ZSTD_createDCtx_advanced(customMem); } size_t ZSTD_freeDStream(ZSTD_DStream* zds) { - if (zds==NULL) return 0; /* support free on null */ - { ZSTD_customMem const cMem = zds->customMem; - ZSTD_freeDCtx(zds->dctx); - zds->dctx = NULL; - ZSTD_freeDDict(zds->ddictLocal); - zds->ddictLocal = NULL; - ZSTD_free(zds->inBuff, cMem); - zds->inBuff = NULL; - ZSTD_free(zds->outBuff, cMem); - zds->outBuff = NULL; -#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) - if (zds->legacyContext) - ZSTD_freeLegacyStreamContext(zds->legacyContext, zds->previousLegacyVersion); -#endif - ZSTD_free(zds, cMem); - return 0; - } + return ZSTD_freeDCtx(zds); } /* *** Initialization *** */ -size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX + ZSTD_blockHeaderSize; } -size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; } +size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; } +size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; } size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize) { - zds->stage = zdss_loadHeader; + zds->streamStage = zdss_loadHeader; zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; ZSTD_freeDDict(zds->ddictLocal); if (dict && dictSize >= 8) { @@ -2147,7 +2218,7 @@ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict) size_t ZSTD_resetDStream(ZSTD_DStream* zds) { - zds->stage = zdss_loadHeader; + zds->streamStage = zdss_loadHeader; zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; zds->legacyVersion = 0; zds->hostageByte = 0; @@ -2168,11 +2239,24 @@ size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds) { - if (zds==NULL) return 0; /* support sizeof NULL */ - return sizeof(*zds) - + ZSTD_sizeof_DCtx(zds->dctx) - + ZSTD_sizeof_DDict(zds->ddictLocal) - + zds->inBuffSize + zds->outBuffSize; + return ZSTD_sizeof_DCtx(zds); +} + +size_t ZSTD_estimateDStreamSize(size_t windowSize) +{ + size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX); + size_t const inBuffSize = blockSize; /* no block can be larger */ + size_t const outBuffSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2); + return sizeof(ZSTD_DStream) + ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize; +} + +ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize) +{ + ZSTD_frameHeader fh; + size_t const err = ZSTD_getFrameHeader(&fh, src, srcSize); + if (ZSTD_isError(err)) return err; + if (err>0) return ERROR(srcSize_wrong); + return ZSTD_estimateDStreamSize(fh.windowSize); } @@ -2196,44 +2280,55 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB char* op = ostart; U32 someMoreWork = 1; + DEBUGLOG(5, "ZSTD_decompressStream"); + DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos)); #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) - if (zds->legacyVersion) + if (zds->legacyVersion) { + /* legacy support is incompatible with static dctx */ + if (zds->staticSize) return ERROR(memory_allocation); return ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input); + } #endif while (someMoreWork) { - switch(zds->stage) + switch(zds->streamStage) { case zdss_init : ZSTD_resetDStream(zds); /* transparent reset on starting decoding a new frame */ /* fall-through */ case zdss_loadHeader : - { size_t const hSize = ZSTD_getFrameParams(&zds->fParams, zds->headerBuffer, zds->lhSize); - if (ZSTD_isError(hSize)) + { size_t const hSize = ZSTD_getFrameHeader(&zds->fParams, zds->headerBuffer, zds->lhSize); + if (ZSTD_isError(hSize)) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) - { U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart); + U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart); if (legacyVersion) { const void* const dict = zds->ddict ? zds->ddict->dictContent : NULL; size_t const dictSize = zds->ddict ? zds->ddict->dictSize : 0; + /* legacy support is incompatible with static dctx */ + if (zds->staticSize) return ERROR(memory_allocation); CHECK_F(ZSTD_initLegacyStream(&zds->legacyContext, zds->previousLegacyVersion, legacyVersion, dict, dictSize)); zds->legacyVersion = zds->previousLegacyVersion = legacyVersion; return ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input); } else { return hSize; /* error */ - } } + } #else - return hSize; + return hSize; #endif + } if (hSize != 0) { /* need more input */ size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */ if (toLoad > (size_t)(iend-ip)) { /* not enough input to load full header */ - memcpy(zds->headerBuffer + zds->lhSize, ip, iend-ip); - zds->lhSize += iend-ip; + if (iend-ip > 0) { + memcpy(zds->headerBuffer + zds->lhSize, ip, iend-ip); + zds->lhSize += iend-ip; + } input->pos = input->size; return (MAX(ZSTD_frameHeaderSize_min, hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ } + assert(ip != NULL); memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; break; } } @@ -2243,74 +2338,90 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) { size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart); if (cSize <= (size_t)(iend-istart)) { - size_t const decompressedSize = ZSTD_decompress_usingDDict(zds->dctx, op, oend-op, istart, cSize, zds->ddict); + size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, oend-op, istart, cSize, zds->ddict); if (ZSTD_isError(decompressedSize)) return decompressedSize; ip = istart + cSize; op += decompressedSize; - zds->dctx->expected = 0; - zds->stage = zdss_init; + zds->expected = 0; + zds->streamStage = zdss_init; someMoreWork = 0; break; } } - /* Consume header */ - ZSTD_refDDict(zds->dctx, zds->ddict); - { size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zds->dctx); /* == ZSTD_frameHeaderSize_prefix */ - CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer, h1Size)); - { size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zds->dctx); - CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer+h1Size, h2Size)); - } } + /* Consume header (see ZSTDds_decodeFrameHeader) */ + DEBUGLOG(4, "Consume header"); + CHECK_F(ZSTD_decompressBegin_usingDDict(zds, zds->ddict)); + + if ((MEM_readLE32(zds->headerBuffer) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ + zds->expected = MEM_readLE32(zds->headerBuffer + 4); + zds->stage = ZSTDds_skipFrame; + } else { + CHECK_F(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize)); + zds->expected = ZSTD_blockHeaderSize; + zds->stage = ZSTDds_decodeBlockHeader; + } + /* control buffer memory usage */ + DEBUGLOG(4, "Control max buffer memory usage"); zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN); if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge); /* Adapt buffer sizes to frame header instructions */ - { size_t const blockSize = MIN(zds->fParams.windowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX); + { size_t const blockSize = MIN(zds->fParams.windowSize, ZSTD_BLOCKSIZE_MAX); size_t const neededOutSize = zds->fParams.windowSize + blockSize + WILDCOPY_OVERLENGTH * 2; zds->blockSize = blockSize; - if (zds->inBuffSize < blockSize) { - ZSTD_free(zds->inBuff, zds->customMem); - zds->inBuffSize = 0; - zds->inBuff = (char*)ZSTD_malloc(blockSize, zds->customMem); - if (zds->inBuff == NULL) return ERROR(memory_allocation); + if ((zds->inBuffSize < blockSize) || (zds->outBuffSize < neededOutSize)) { + size_t const bufferSize = blockSize + neededOutSize; + DEBUGLOG(4, "inBuff : from %u to %u", + (U32)zds->inBuffSize, (U32)blockSize); + DEBUGLOG(4, "outBuff : from %u to %u", + (U32)zds->outBuffSize, (U32)neededOutSize); + if (zds->staticSize) { /* static DCtx */ + DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize); + assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */ + if (bufferSize > zds->staticSize - sizeof(ZSTD_DCtx)) + return ERROR(memory_allocation); + } else { + ZSTD_free(zds->inBuff, zds->customMem); + zds->inBuffSize = 0; + zds->outBuffSize = 0; + zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem); + if (zds->inBuff == NULL) return ERROR(memory_allocation); + } zds->inBuffSize = blockSize; - } - if (zds->outBuffSize < neededOutSize) { - ZSTD_free(zds->outBuff, zds->customMem); - zds->outBuffSize = 0; - zds->outBuff = (char*)ZSTD_malloc(neededOutSize, zds->customMem); - if (zds->outBuff == NULL) return ERROR(memory_allocation); + zds->outBuff = zds->inBuff + zds->inBuffSize; zds->outBuffSize = neededOutSize; } } - zds->stage = zdss_read; + zds->streamStage = zdss_read; /* pass-through */ case zdss_read: - { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx); + DEBUGLOG(5, "stage zdss_read"); + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds); + DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize); if (neededInSize==0) { /* end of frame */ - zds->stage = zdss_init; + zds->streamStage = zdss_init; someMoreWork = 0; break; } if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */ - const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx); - size_t const decodedSize = ZSTD_decompressContinue(zds->dctx, + int const isSkipFrame = ZSTD_isSkipFrame(zds); + size_t const decodedSize = ZSTD_decompressContinue(zds, zds->outBuff + zds->outStart, (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart), ip, neededInSize); if (ZSTD_isError(decodedSize)) return decodedSize; ip += neededInSize; if (!decodedSize && !isSkipFrame) break; /* this was just a header */ zds->outEnd = zds->outStart + decodedSize; - zds->stage = zdss_flush; + zds->streamStage = zdss_flush; break; - } - if (ip==iend) { someMoreWork = 0; break; } /* no more input */ - zds->stage = zdss_load; - /* pass-through */ - } + } } + if (ip==iend) { someMoreWork = 0; break; } /* no more input */ + zds->streamStage = zdss_load; + /* pass-through */ case zdss_load: - { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx); + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds); size_t const toLoad = neededInSize - zds->inPos; /* should always be <= remaining space within inBuff */ size_t loadedSize; if (toLoad > zds->inBuffSize - zds->inPos) return ERROR(corruption_detected); /* should never happen */ @@ -2320,17 +2431,17 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */ /* decode loaded input */ - { const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx); - size_t const decodedSize = ZSTD_decompressContinue(zds->dctx, + { const int isSkipFrame = ZSTD_isSkipFrame(zds); + size_t const decodedSize = ZSTD_decompressContinue(zds, zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart, zds->inBuff, neededInSize); if (ZSTD_isError(decodedSize)) return decodedSize; zds->inPos = 0; /* input is consumed */ - if (!decodedSize && !isSkipFrame) { zds->stage = zdss_read; break; } /* this was just a header */ + if (!decodedSize && !isSkipFrame) { zds->streamStage = zdss_read; break; } /* this was just a header */ zds->outEnd = zds->outStart + decodedSize; - zds->stage = zdss_flush; - /* pass-through */ } } + zds->streamStage = zdss_flush; + /* pass-through */ case zdss_flush: { size_t const toFlushSize = zds->outEnd - zds->outStart; @@ -2338,37 +2449,41 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB op += flushedSize; zds->outStart += flushedSize; if (flushedSize == toFlushSize) { /* flush completed */ - zds->stage = zdss_read; + zds->streamStage = zdss_read; if (zds->outStart + zds->blockSize > zds->outBuffSize) zds->outStart = zds->outEnd = 0; break; - } - /* cannot complete flush */ - someMoreWork = 0; - break; - } + } } + /* cannot complete flush */ + someMoreWork = 0; + break; + default: return ERROR(GENERIC); /* impossible */ } } /* result */ input->pos += (size_t)(ip-istart); output->pos += (size_t)(op-ostart); - { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds->dctx); + { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds); if (!nextSrcSizeHint) { /* frame fully decoded */ if (zds->outEnd == zds->outStart) { /* output fully flushed */ if (zds->hostageByte) { - if (input->pos >= input->size) { zds->stage = zdss_read; return 1; } /* can't release hostage (not present) */ + if (input->pos >= input->size) { + /* can't release hostage (not present) */ + zds->streamStage = zdss_read; + return 1; + } input->pos++; /* release hostage */ - } + } /* zds->hostageByte */ return 0; - } + } /* zds->outEnd == zds->outStart */ if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */ input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */ zds->hostageByte=1; } return 1; - } - nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds->dctx) == ZSTDnit_block); /* preload header of next block */ + } /* nextSrcSizeHint==0 */ + nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */ if (zds->inPos > nextSrcSizeHint) return ERROR(GENERIC); /* should never happen */ nextSrcSizeHint -= zds->inPos; /* already loaded*/ return nextSrcSizeHint; diff --git a/thirdparty/zstd/zstd.h b/thirdparty/zstd/zstd.h index f8050c1361..58e9a5606d 100644 --- a/thirdparty/zstd/zstd.h +++ b/thirdparty/zstd/zstd.h @@ -19,10 +19,12 @@ extern "C" { /* ===== ZSTDLIB_API : control library symbols visibility ===== */ -#if defined(__GNUC__) && (__GNUC__ >= 4) -# define ZSTDLIB_VISIBILITY __attribute__ ((visibility ("default"))) -#else -# define ZSTDLIB_VISIBILITY +#ifndef ZSTDLIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define ZSTDLIB_VISIBILITY __attribute__ ((visibility ("default"))) +# else +# define ZSTDLIB_VISIBILITY +# endif #endif #if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) # define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBILITY @@ -36,35 +38,37 @@ extern "C" { /******************************************************************************************************* Introduction - zstd, short for Zstandard, is a fast lossless compression algorithm, targeting real-time compression scenarios - at zlib-level and better compression ratios. The zstd compression library provides in-memory compression and - decompression functions. The library supports compression levels from 1 up to ZSTD_maxCLevel() which is 22. + zstd, short for Zstandard, is a fast lossless compression algorithm, + targeting real-time compression scenarios at zlib-level and better compression ratios. + The zstd compression library provides in-memory compression and decompression functions. + The library supports compression levels from 1 up to ZSTD_maxCLevel() which is currently 22. Levels >= 20, labeled `--ultra`, should be used with caution, as they require more memory. Compression can be done in: - a single step (described as Simple API) - a single step, reusing a context (described as Explicit memory management) - unbounded multiple steps (described as Streaming compression) - The compression ratio achievable on small data can be highly improved using compression with a dictionary in: + The compression ratio achievable on small data can be highly improved using a dictionary in: - a single step (described as Simple dictionary API) - a single step, reusing a dictionary (described as Fast dictionary API) Advanced experimental functions can be accessed using #define ZSTD_STATIC_LINKING_ONLY before including zstd.h. - These APIs shall never be used with a dynamic library. + Advanced experimental APIs shall never be used with a dynamic library. They are not "stable", their definition may change in the future. Only static linking is allowed. *********************************************************************************************************/ /*------ Version ------*/ #define ZSTD_VERSION_MAJOR 1 -#define ZSTD_VERSION_MINOR 2 +#define ZSTD_VERSION_MINOR 3 #define ZSTD_VERSION_RELEASE 0 +#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) +ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< useful to check dll version */ + #define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE #define ZSTD_QUOTE(str) #str #define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str) #define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION) - -#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) -ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< library version number; to be used when checking dll version */ +ZSTDLIB_API const char* ZSTD_versionString(void); /* v1.3.0 */ /*************************************** @@ -81,38 +85,48 @@ ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity, /*! ZSTD_decompress() : * `compressedSize` : must be the _exact_ size of some number of compressed and/or skippable frames. - * `dstCapacity` is an upper bound of originalSize. + * `dstCapacity` is an upper bound of originalSize to regenerate. * If user cannot imply a maximum upper bound, it's better to use streaming mode to decompress data. * @return : the number of bytes decompressed into `dst` (<= `dstCapacity`), * or an errorCode if it fails (which can be tested using ZSTD_isError()). */ ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity, const void* src, size_t compressedSize); -/*! ZSTD_getDecompressedSize() : - * NOTE: This function is planned to be obsolete, in favour of ZSTD_getFrameContentSize. - * ZSTD_getFrameContentSize functions the same way, returning the decompressed size of a single - * frame, but distinguishes empty frames from frames with an unknown size, or errors. - * - * Additionally, ZSTD_findDecompressedSize can be used instead. It can handle multiple - * concatenated frames in one buffer, and so is more general. - * As a result however, it requires more computation and entire frames to be passed to it, - * as opposed to ZSTD_getFrameContentSize which requires only a single frame's header. - * - * 'src' is the start of a zstd compressed frame. - * @return : content size to be decompressed, as a 64-bits value _if known_, 0 otherwise. - * note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode. - * When `return==0`, data to decompress could be any size. +/*! ZSTD_getFrameContentSize() : v1.3.0 + * `src` should point to the start of a ZSTD encoded frame. + * `srcSize` must be at least as large as the frame header. + * hint : any size >= `ZSTD_frameHeaderSize_max` is large enough. + * @return : - decompressed size of the frame in `src`, if known + * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined + * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) + * note 1 : a 0 return value means the frame is valid but "empty". + * note 2 : decompressed size is an optional field, it may not be present, typically in streaming mode. + * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. * In which case, it's necessary to use streaming mode to decompress data. - * Optionally, application can still use ZSTD_decompress() while relying on implied limits. - * (For example, data may be necessarily cut into blocks <= 16 KB). - * note 2 : decompressed size is always present when compression is done with ZSTD_compress() - * note 3 : decompressed size can be very large (64-bits value), + * Optionally, application can rely on some implicit limit, + * as ZSTD_decompress() only needs an upper bound of decompressed size. + * (For example, data could be necessarily cut into blocks <= 16 KB). + * note 3 : decompressed size is always present when compression is done with ZSTD_compress() + * note 4 : decompressed size can be very large (64-bits value), * potentially larger than what local system can handle as a single memory segment. * In which case, it's necessary to use streaming mode to decompress data. - * note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified. - * Always ensure result fits within application's authorized limits. + * note 5 : If source is untrusted, decompressed size could be wrong or intentionally modified. + * Always ensure return value fits within application's authorized limits. * Each application can set its own limits. - * note 5 : when `return==0`, if precise failure cause is needed, use ZSTD_getFrameParams() to know more. */ + * note 6 : This function replaces ZSTD_getDecompressedSize() */ +#define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1) +#define ZSTD_CONTENTSIZE_ERROR (0ULL - 2) +ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize); + +/*! ZSTD_getDecompressedSize() : + * NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize(). + * Both functions work the same way, + * but ZSTD_getDecompressedSize() blends + * "empty", "unknown" and "error" results in the same return value (0), + * while ZSTD_getFrameContentSize() distinguishes them. + * + * 'src' is the start of a zstd compressed frame. + * @return : content size to be decompressed, as a 64-bits value _if known and not empty_, 0 otherwise. */ ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize); @@ -137,29 +151,35 @@ ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); /*! ZSTD_compressCCtx() : * Same as ZSTD_compress(), requires an allocated ZSTD_CCtx (see ZSTD_createCCtx()). */ -ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel); +ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* ctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + int compressionLevel); /*= Decompression context * When decompressing many times, - * it is recommended to allocate a context just once, and re-use it for each successive compression operation. + * it is recommended to allocate a context only once, + * and re-use it for each successive compression operation. * This will make workload friendlier for system's memory. - * Use one context per thread for parallel execution in multi-threaded environments. */ + * Use one context per thread for parallel execution. */ typedef struct ZSTD_DCtx_s ZSTD_DCtx; ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void); ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); /*! ZSTD_decompressDCtx() : - * Same as ZSTD_decompress(), requires an allocated ZSTD_DCtx (see ZSTD_createDCtx()). */ -ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + * Same as ZSTD_decompress(), requires an allocated ZSTD_DCtx (see ZSTD_createDCtx()) */ +ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* ctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize); /************************** * Simple dictionary API ***************************/ /*! ZSTD_compress_usingDict() : -* Compression using a predefined Dictionary (see dictBuilder/zdict.h). -* Note : This function loads the dictionary, resulting in significant startup delay. -* Note : When `dict == NULL || dictSize < 8` no dictionary is used. */ + * Compression using a predefined Dictionary (see dictBuilder/zdict.h). + * Note : This function loads the dictionary, resulting in significant startup delay. + * Note : When `dict == NULL || dictSize < 8` no dictionary is used. */ ZSTDLIB_API size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, @@ -167,30 +187,31 @@ ZSTDLIB_API size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, int compressionLevel); /*! ZSTD_decompress_usingDict() : -* Decompression using a predefined Dictionary (see dictBuilder/zdict.h). -* Dictionary must be identical to the one used during compression. -* Note : This function loads the dictionary, resulting in significant startup delay. -* Note : When `dict == NULL || dictSize < 8` no dictionary is used. */ + * Decompression using a predefined Dictionary (see dictBuilder/zdict.h). + * Dictionary must be identical to the one used during compression. + * Note : This function loads the dictionary, resulting in significant startup delay. + * Note : When `dict == NULL || dictSize < 8` no dictionary is used. */ ZSTDLIB_API size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict,size_t dictSize); -/**************************** -* Fast dictionary API -****************************/ +/********************************** + * Bulk processing dictionary API + *********************************/ typedef struct ZSTD_CDict_s ZSTD_CDict; /*! ZSTD_createCDict() : -* When compressing multiple messages / blocks with the same dictionary, it's recommended to load it just once. -* ZSTD_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay. -* ZSTD_CDict can be created once and used by multiple threads concurrently, as its usage is read-only. -* `dictBuffer` can be released after ZSTD_CDict creation, as its content is copied within CDict */ -ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize, int compressionLevel); + * When compressing multiple messages / blocks with the same dictionary, it's recommended to load it just once. + * ZSTD_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay. + * ZSTD_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only. + * `dictBuffer` can be released after ZSTD_CDict creation, since its content is copied within CDict */ +ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize, + int compressionLevel); /*! ZSTD_freeCDict() : -* Function frees memory allocated by ZSTD_createCDict(). */ + * Function frees memory allocated by ZSTD_createCDict(). */ ZSTDLIB_API size_t ZSTD_freeCDict(ZSTD_CDict* CDict); /*! ZSTD_compress_usingCDict() : @@ -207,17 +228,17 @@ ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, typedef struct ZSTD_DDict_s ZSTD_DDict; /*! ZSTD_createDDict() : -* Create a digested dictionary, ready to start decompression operation without startup delay. -* dictBuffer can be released after DDict creation, as its content is copied inside DDict */ + * Create a digested dictionary, ready to start decompression operation without startup delay. + * dictBuffer can be released after DDict creation, as its content is copied inside DDict */ ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize); /*! ZSTD_freeDDict() : -* Function frees memory allocated with ZSTD_createDDict() */ + * Function frees memory allocated with ZSTD_createDDict() */ ZSTDLIB_API size_t ZSTD_freeDDict(ZSTD_DDict* ddict); /*! ZSTD_decompress_usingDDict() : -* Decompression using a digested Dictionary. -* Faster startup than ZSTD_decompress_usingDict(), recommended when same dictionary is used multiple times. */ + * Decompression using a digested Dictionary. + * Faster startup than ZSTD_decompress_usingDict(), recommended when same dictionary is used multiple times. */ ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, @@ -274,14 +295,17 @@ typedef struct ZSTD_outBuffer_s { * ZSTD_endStream() instructs to finish a frame. * It will perform a flush and write frame epilogue. * The epilogue is required for decoders to consider a frame completed. -* Similar to ZSTD_flushStream(), it may not be able to flush the full content if `output->size` is too small. +* ZSTD_endStream() may not be able to flush full data if `output->size` is too small. * In which case, call again ZSTD_endStream() to complete the flush. -* @return : nb of bytes still present within internal buffer (0 if it's empty, hence compression completed) +* @return : 0 if frame fully completed and fully flushed, + or >0 if some data is still present within internal buffer + (value is minimum size estimation for remaining data to flush, but it could be more) * or an error code, which can be tested using ZSTD_isError(). * * *******************************************************************/ -typedef struct ZSTD_CStream_s ZSTD_CStream; +typedef ZSTD_CCtx ZSTD_CStream; /**< CCtx and CStream are now effectively same object (>= v1.3.0) */ + /* Continue to distinguish them for compatibility with versions <= v1.2.0 */ /*===== ZSTD_CStream management functions =====*/ ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void); ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); @@ -319,7 +343,8 @@ ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output * The return value is a suggested next input size (a hint to improve latency) that will never load more than the current frame. * *******************************************************************************/ -typedef struct ZSTD_DStream_s ZSTD_DStream; +typedef ZSTD_DCtx ZSTD_DStream; /**< DCtx and DStream are now effectively same object (>= v1.3.0) */ + /* Continue to distinguish them for compatibility with versions <= v1.2.0 */ /*===== ZSTD_DStream management functions =====*/ ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void); ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); @@ -334,23 +359,22 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output #endif /* ZSTD_H_235446 */ -#if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY) -#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY /**************************************************************************************** * START OF ADVANCED AND EXPERIMENTAL FUNCTIONS * The definitions in this section are considered experimental. - * They should never be used with a dynamic library, as they may change in the future. - * They are provided for advanced usages. + * They should never be used with a dynamic library, as prototypes may change in the future. + * They are provided for advanced scenarios. * Use them only in association with static linking. * ***************************************************************************************/ +#if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY) +#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY + /* --- Constants ---*/ #define ZSTD_MAGICNUMBER 0xFD2FB528 /* >= v0.8.0 */ #define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50U - -#define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1) -#define ZSTD_CONTENTSIZE_ERROR (0ULL - 2) +#define ZSTD_MAGIC_DICTIONARY 0xEC30A437 /* v0.7+ */ #define ZSTD_WINDOWLOG_MAX_32 27 #define ZSTD_WINDOWLOG_MAX_64 27 @@ -370,14 +394,15 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output #define ZSTD_FRAMEHEADERSIZE_MAX 18 /* for static allocation */ #define ZSTD_FRAMEHEADERSIZE_MIN 6 -static const size_t ZSTD_frameHeaderSize_prefix = 5; -static const size_t ZSTD_frameHeaderSize_min = ZSTD_FRAMEHEADERSIZE_MIN; +static const size_t ZSTD_frameHeaderSize_prefix = 5; /* minimum input size to know frame header size */ static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX; +static const size_t ZSTD_frameHeaderSize_min = ZSTD_FRAMEHEADERSIZE_MIN; static const size_t ZSTD_skippableHeaderSize = 8; /* magic number + skippable frame length */ /*--- Advanced types ---*/ -typedef enum { ZSTD_fast, ZSTD_dfast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2, ZSTD_btopt, ZSTD_btopt2 } ZSTD_strategy; /* from faster to stronger */ +typedef enum { ZSTD_fast=1, ZSTD_dfast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, + ZSTD_btlazy2, ZSTD_btopt, ZSTD_btultra } ZSTD_strategy; /* from faster to stronger */ typedef struct { unsigned windowLog; /**< largest match distance : larger == more compression, more memory needed during decompression */ @@ -400,76 +425,141 @@ typedef struct { ZSTD_frameParameters fParams; } ZSTD_parameters; +typedef struct { + unsigned long long frameContentSize; + size_t windowSize; + unsigned dictID; + unsigned checksumFlag; +} ZSTD_frameHeader; + /*= Custom memory allocation functions */ typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size); typedef void (*ZSTD_freeFunction) (void* opaque, void* address); typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem; +/* use this constant to defer to stdlib's functions */ +static const ZSTD_customMem ZSTD_defaultCMem = { NULL, NULL, NULL }; + /*************************************** -* Compressed size functions +* Frame size functions ***************************************/ /*! ZSTD_findFrameCompressedSize() : * `src` should point to the start of a ZSTD encoded frame or skippable frame * `srcSize` must be at least as large as the frame - * @return : the compressed size of the frame pointed to by `src`, suitable to pass to - * `ZSTD_decompress` or similar, or an error code if given invalid input. */ + * @return : the compressed size of the first frame starting at `src`, + * suitable to pass to `ZSTD_decompress` or similar, + * or an error code if input is invalid */ ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize); +/*! ZSTD_findDecompressedSize() : + * `src` should point the start of a series of ZSTD encoded and/or skippable frames + * `srcSize` must be the _exact_ size of this series + * (i.e. there should be a frame boundary exactly at `srcSize` bytes after `src`) + * @return : - decompressed size of all data in all successive frames + * - if the decompressed size cannot be determined: ZSTD_CONTENTSIZE_UNKNOWN + * - if an error occurred: ZSTD_CONTENTSIZE_ERROR + * + * note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode. + * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. + * In which case, it's necessary to use streaming mode to decompress data. + * note 2 : decompressed size is always present when compression is done with ZSTD_compress() + * note 3 : decompressed size can be very large (64-bits value), + * potentially larger than what local system can handle as a single memory segment. + * In which case, it's necessary to use streaming mode to decompress data. + * note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified. + * Always ensure result fits within application's authorized limits. + * Each application can set its own limits. + * note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to + * read each contained frame header. This is fast as most of the data is skipped, + * however it does mean that all frame data must be present and valid. */ +ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); + +/*! ZSTD_frameHeaderSize() : +* `src` should point to the start of a ZSTD frame +* `srcSize` must be >= ZSTD_frameHeaderSize_prefix. +* @return : size of the Frame Header */ +ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize); + + /*************************************** -* Decompressed size functions +* Context memory usage ***************************************/ -/*! ZSTD_getFrameContentSize() : -* `src` should point to the start of a ZSTD encoded frame -* `srcSize` must be at least as large as the frame header. A value greater than or equal -* to `ZSTD_frameHeaderSize_max` is guaranteed to be large enough in all cases. -* @return : decompressed size of the frame pointed to be `src` if known, otherwise -* - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined -* - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */ -ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize); -/*! ZSTD_findDecompressedSize() : -* `src` should point the start of a series of ZSTD encoded and/or skippable frames -* `srcSize` must be the _exact_ size of this series -* (i.e. there should be a frame boundary exactly `srcSize` bytes after `src`) -* @return : the decompressed size of all data in the contained frames, as a 64-bit value _if known_ -* - if the decompressed size cannot be determined: ZSTD_CONTENTSIZE_UNKNOWN -* - if an error occurred: ZSTD_CONTENTSIZE_ERROR -* -* note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode. -* When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. -* In which case, it's necessary to use streaming mode to decompress data. -* Optionally, application can still use ZSTD_decompress() while relying on implied limits. -* (For example, data may be necessarily cut into blocks <= 16 KB). -* note 2 : decompressed size is always present when compression is done with ZSTD_compress() -* note 3 : decompressed size can be very large (64-bits value), -* potentially larger than what local system can handle as a single memory segment. -* In which case, it's necessary to use streaming mode to decompress data. -* note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified. -* Always ensure result fits within application's authorized limits. -* Each application can set its own limits. -* note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to -* read each contained frame header. This is efficient as most of the data is skipped, -* however it does mean that all frame data must be present and valid. */ -ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); +/*! ZSTD_sizeof_*() : + * These functions give the current memory usage of selected object. + * Object memory usage can evolve if it's re-used multiple times. */ +ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx); +ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx); +ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs); +ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds); +ZSTDLIB_API size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict); +ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); + +/*! ZSTD_estimate*() : + * These functions make it possible to estimate memory usage + * of a future {D,C}Ctx, before its creation. + * ZSTD_estimateCCtxSize() will provide a budget large enough for any compression level up to selected one. + * It will also consider src size to be arbitrarily "large", which is worst case. + * If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced() can provide a tighter estimation. + * ZSTD_estimateCCtxSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + * Note : CCtx estimation is only correct for single-threaded compression */ +ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel); +ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced(ZSTD_compressionParameters cParams); +ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); + +/*! ZSTD_estimate?StreamSize() : + * ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one. + * It will also consider src size to be arbitrarily "large", which is worst case. + * If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced() can provide a tighter estimation. + * ZSTD_estimateCStreamSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + * Note : CStream estimation is only correct for single-threaded compression. + * ZSTD_DStream memory budget depends on window Size. + * This information can be passed manually, using ZSTD_estimateDStreamSize, + * or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame(); + * Note : if streaming is init with function ZSTD_init?Stream_usingDict(), + * an internal ?Dict will be created, which additional size is not estimated here. + * In this case, get total size by adding ZSTD_estimate?DictSize */ +ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel); +ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced(ZSTD_compressionParameters cParams); +ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize); +ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); + +/*! ZSTD_estimate?DictSize() : + * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). + * ZSTD_estimateCStreamSize_advanced() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced(). + * Note : dictionary created "byReference" are smaller */ +ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); +ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference); +ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference); /*************************************** * Advanced compression functions ***************************************/ -/*! ZSTD_estimateCCtxSize() : - * Gives the amount of memory allocated for a ZSTD_CCtx given a set of compression parameters. - * `frameContentSize` is an optional parameter, provide `0` if unknown */ -ZSTDLIB_API size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams); - /*! ZSTD_createCCtx_advanced() : * Create a ZSTD compression context using external alloc and free functions */ ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); -/*! ZSTD_sizeofCCtx() : - * Gives the amount of memory used by a given ZSTD_CCtx */ -ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx); +/*! ZSTD_initStaticCCtx() : initialize a fixed-size zstd compression context + * workspace: The memory area to emplace the context into. + * Provided pointer must 8-bytes aligned. + * It must outlive context usage. + * workspaceSize: Use ZSTD_estimateCCtxSize() or ZSTD_estimateCStreamSize() + * to determine how large workspace must be to support scenario. + * @return : pointer to ZSTD_CCtx*, or NULL if error (size too small) + * Note : zstd will never resize nor malloc() when using a static cctx. + * If it needs more memory than available, it will simply error out. + * Note 2 : there is no corresponding "free" function. + * Since workspace was allocated externally, it must be freed externally too. + * Limitation 1 : currently not compatible with internal CDict creation, such as + * ZSTD_CCtx_loadDictionary() or ZSTD_initCStream_usingDict(). + * Limitation 2 : currently not compatible with multi-threading + */ +ZSTDLIB_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize); + +/* !!! To be deprecated !!! */ typedef enum { ZSTD_p_forceWindow, /* Force back-references to remain < windowSize, even when referencing Dictionary content (default:0) */ ZSTD_p_forceRawDict /* Force loading dictionary in "content-only" mode (no header analysis) */ @@ -479,20 +569,43 @@ typedef enum { * @result : 0, or an error code (which can be tested with ZSTD_isError()) */ ZSTDLIB_API size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value); + /*! ZSTD_createCDict_byReference() : * Create a digested dictionary for compression * Dictionary content is simply referenced, and therefore stays in dictBuffer. * It is important that dictBuffer outlives CDict, it must remain read accessible throughout the lifetime of CDict */ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel); + +typedef enum { ZSTD_dm_auto=0, /* dictionary is "full" if it starts with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */ + ZSTD_dm_rawContent, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */ + ZSTD_dm_fullDict /* refuses to load a dictionary if it does not respect Zstandard's specification */ +} ZSTD_dictMode_e; /*! ZSTD_createCDict_advanced() : * Create a ZSTD_CDict using external alloc and free, and customized compression parameters */ -ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, unsigned byReference, - ZSTD_compressionParameters cParams, ZSTD_customMem customMem); - -/*! ZSTD_sizeof_CDict() : - * Gives the amount of memory used by a given ZSTD_sizeof_CDict */ -ZSTDLIB_API size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict); +ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, + unsigned byReference, ZSTD_dictMode_e dictMode, + ZSTD_compressionParameters cParams, + ZSTD_customMem customMem); + +/*! ZSTD_initStaticCDict_advanced() : + * Generate a digested dictionary in provided memory area. + * workspace: The memory area to emplace the dictionary into. + * Provided pointer must 8-bytes aligned. + * It must outlive dictionary usage. + * workspaceSize: Use ZSTD_estimateCDictSize() + * to determine how large workspace must be. + * cParams : use ZSTD_getCParams() to transform a compression level + * into its relevants cParams. + * @return : pointer to ZSTD_CDict*, or NULL if error (size too small) + * Note : there is no corresponding "free" function. + * Since workspace was allocated externally, it must be freed externally. + */ +ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict( + void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + unsigned byReference, ZSTD_dictMode_e dictMode, + ZSTD_compressionParameters cParams); /*! ZSTD_getCParams() : * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. @@ -509,8 +622,8 @@ ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long l ZSTDLIB_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); /*! ZSTD_adjustCParams() : -* optimize params for a given `srcSize` and `dictSize`. -* both values are optional, select `0` if unknown. */ + * optimize params for a given `srcSize` and `dictSize`. + * both values are optional, select `0` if unknown. */ ZSTDLIB_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize); /*! ZSTD_compress_advanced() : @@ -538,22 +651,32 @@ ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, * Note 3 : Skippable Frame Identifiers are considered valid. */ ZSTDLIB_API unsigned ZSTD_isFrame(const void* buffer, size_t size); -/*! ZSTD_estimateDCtxSize() : - * Gives the potential amount of memory allocated to create a ZSTD_DCtx */ -ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); - /*! ZSTD_createDCtx_advanced() : * Create a ZSTD decompression context using external alloc and free functions */ ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); -/*! ZSTD_sizeof_DCtx() : - * Gives the amount of memory used by a given ZSTD_DCtx */ -ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx); +/*! ZSTD_initStaticDCtx() : initialize a fixed-size zstd decompression context + * workspace: The memory area to emplace the context into. + * Provided pointer must 8-bytes aligned. + * It must outlive context usage. + * workspaceSize: Use ZSTD_estimateDCtxSize() or ZSTD_estimateDStreamSize() + * to determine how large workspace must be to support scenario. + * @return : pointer to ZSTD_DCtx*, or NULL if error (size too small) + * Note : zstd will never resize nor malloc() when using a static dctx. + * If it needs more memory than available, it will simply error out. + * Note 2 : static dctx is incompatible with legacy support + * Note 3 : there is no corresponding "free" function. + * Since workspace was allocated externally, it must be freed externally. + * Limitation : currently not compatible with internal DDict creation, + * such as ZSTD_initDStream_usingDict(). + */ +ZSTDLIB_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize); /*! ZSTD_createDDict_byReference() : * Create a digested dictionary, ready to start decompression operation without startup delay. - * Dictionary content is simply referenced, and therefore stays in dictBuffer. - * It is important that dictBuffer outlives DDict, it must remain read accessible throughout the lifetime of DDict */ + * Dictionary content is referenced, and therefore stays in dictBuffer. + * It is important that dictBuffer outlives DDict, + * it must remain read accessible throughout the lifetime of DDict */ ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize); /*! ZSTD_createDDict_advanced() : @@ -561,9 +684,20 @@ ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, siz ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, unsigned byReference, ZSTD_customMem customMem); -/*! ZSTD_sizeof_DDict() : - * Gives the amount of memory used by a given ZSTD_DDict */ -ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); +/*! ZSTD_initStaticDDict() : + * Generate a digested dictionary in provided memory area. + * workspace: The memory area to emplace the dictionary into. + * Provided pointer must 8-bytes aligned. + * It must outlive dictionary usage. + * workspaceSize: Use ZSTD_estimateDDictSize() + * to determine how large workspace must be. + * @return : pointer to ZSTD_DDict*, or NULL if error (size too small) + * Note : there is no corresponding "free" function. + * Since workspace was allocated externally, it must be freed externally. + */ +ZSTDLIB_API ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + unsigned byReference); /*! ZSTD_getDictID_fromDict() : * Provides the dictID stored within dictionary. @@ -586,7 +720,7 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict); * Note : this use case also happens when using a non-conformant dictionary. * - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`). * - This is not a Zstandard frame. - * When identifying the exact failure cause, it's possible to use ZSTD_getFrameParams(), which will provide a more precise error code. */ + * When identifying the exact failure cause, it's possible to use ZSTD_getFrameHeader(), which will provide a more precise error code. */ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); @@ -596,13 +730,13 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); /*===== Advanced Streaming compression functions =====*/ ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); -ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs); /**< size of CStream is variable, depending primarily on compression level */ +ZSTDLIB_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ ZSTDLIB_API size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); /**< pledgedSrcSize must be correct, a size of 0 means unknown. for a frame size of 0 use initCStream_advanced */ -ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< note: a dict will not be used if dict == NULL or dictSize < 8 */ +ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. */ ZSTDLIB_API size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0 */ ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); /**< note : cdict will just be referenced, and must outlive compression session */ -ZSTDLIB_API size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize, ZSTD_frameParameters fParams); /**< same as ZSTD_initCStream_usingCDict(), with control over frame parameters */ +ZSTDLIB_API size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize); /**< same as ZSTD_initCStream_usingCDict(), with control over frame parameters */ /*! ZSTD_resetCStream() : * start a new compression job, using same parameters from previous job. @@ -617,11 +751,11 @@ ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledg /*===== Advanced Streaming decompression functions =====*/ typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e; ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); -ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: a dict will not be used if dict == NULL or dictSize < 8 */ +ZSTDLIB_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */ ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue); +ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: a dict will not be used if dict == NULL or dictSize < 8 */ ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); /**< note : ddict will just be referenced, and must outlive decompression session */ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompression parameters from previous init; saves dictionary loading */ -ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds); /********************************************************************* @@ -683,21 +817,24 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapaci Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. A ZSTD_DCtx object can be re-used multiple times. - First typical operation is to retrieve frame parameters, using ZSTD_getFrameParams(). - It fills a ZSTD_frameParams structure which provide important information to correctly decode the frame, - such as the minimum rolling buffer size to allocate to decompress data (`windowSize`), - and the dictionary ID used. + First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader(). + It fills a ZSTD_frameHeader structure with important information to correctly decode the frame, + such as minimum rolling buffer size to allocate to decompress data (`windowSize`), + and the dictionary ID in use. (Note : content size is optional, it may not be present. 0 means : content size unknown). Note that these values could be wrong, either because of data malformation, or because an attacker is spoofing deliberate false information. As a consequence, check that values remain within valid application range, especially `windowSize`, before allocation. - Each application can set its own limit, depending on local restrictions. For extended interoperability, it is recommended to support at least 8 MB. - Frame parameters are extracted from the beginning of the compressed frame. - Data fragment must be large enough to ensure successful decoding, typically `ZSTD_frameHeaderSize_max` bytes. - @result : 0 : successful decoding, the `ZSTD_frameParams` structure is correctly filled. + Each application can set its own limit, depending on local restrictions. + For extended interoperability, it is recommended to support windowSize of at least 8 MB. + Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough. + Data fragment must be large enough to ensure successful decoding. + `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough. + @result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled. >0 : `srcSize` is too small, please provide at least @result bytes on next attempt. errorCode, which can be tested using ZSTD_isError(). - Start decompression, with ZSTD_decompressBegin() or ZSTD_decompressBegin_usingDict(). + Start decompression, with ZSTD_decompressBegin(). + If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict(). Alternatively, you can copy a prepared context, using ZSTD_copyDCtx(). Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. @@ -729,30 +866,233 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapaci b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits c) Frame Content - any content (User Data) of length equal to Frame Size For skippable frames ZSTD_decompressContinue() always returns 0. - For skippable frames ZSTD_getFrameParams() returns fparamsPtr->windowLog==0 what means that a frame is skippable. + For skippable frames ZSTD_getFrameHeader() returns fparamsPtr->windowLog==0 what means that a frame is skippable. Note : If fparamsPtr->frameContentSize==0, it is ambiguous: the frame might actually be a Zstd encoded frame with no content. For purposes of decompression, it is valid in both cases to skip the frame using ZSTD_findFrameCompressedSize to find its size in bytes. It also returns Frame Size as fparamsPtr->frameContentSize. */ -typedef struct { - unsigned long long frameContentSize; - unsigned windowSize; - unsigned dictID; - unsigned checksumFlag; -} ZSTD_frameParams; - /*===== Buffer-less streaming decompression functions =====*/ -ZSTDLIB_API size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize); /**< doesn't consume input, see details below */ +ZSTDLIB_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIB_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); + ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e; ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); + + +/*=== New advanced API (experimental, and compression only) ===*/ + +/* notes on API design : + * In this proposal, parameters are pushed one by one into an existing CCtx, + * and then applied on all subsequent compression jobs. + * When no parameter is ever provided, CCtx is created with compression level ZSTD_CLEVEL_DEFAULT. + * + * This API is intended to replace all others experimental API. + * It can basically do all other use cases, and even new ones. + * It stands a good chance to become "stable", + * after a reasonable testing period. + */ + +/* note on naming convention : + * Initially, the API favored names like ZSTD_setCCtxParameter() . + * In this proposal, convention is changed towards ZSTD_CCtx_setParameter() . + * The main driver is that it identifies more clearly the target object type. + * It feels clearer in light of potential variants : + * ZSTD_CDict_setParameter() (rather than ZSTD_setCDictParameter()) + * ZSTD_DCtx_setParameter() (rather than ZSTD_setDCtxParameter() ) + * Left variant feels easier to distinguish. + */ + +/* note on enum design : + * All enum will be manually set to explicit values before reaching "stable API" status */ + +typedef enum { + /* compression parameters */ + ZSTD_p_compressionLevel=100, /* Update all compression parameters according to pre-defined cLevel table + * Default level is ZSTD_CLEVEL_DEFAULT==3. + * Special: value 0 means "do not change cLevel". */ + ZSTD_p_windowLog, /* Maximum allowed back-reference distance, expressed as power of 2. + * Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX. + * Special: value 0 means "do not change windowLog". */ + ZSTD_p_hashLog, /* Size of the probe table, as a power of 2. + * Resulting table size is (1 << (hashLog+2)). + * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX. + * Larger tables improve compression ratio of strategies <= dFast, + * and improve speed of strategies > dFast. + * Special: value 0 means "do not change hashLog". */ + ZSTD_p_chainLog, /* Size of the full-search table, as a power of 2. + * Resulting table size is (1 << (chainLog+2)). + * Larger tables result in better and slower compression. + * This parameter is useless when using "fast" strategy. + * Special: value 0 means "do not change chainLog". */ + ZSTD_p_searchLog, /* Number of search attempts, as a power of 2. + * More attempts result in better and slower compression. + * This parameter is useless when using "fast" and "dFast" strategies. + * Special: value 0 means "do not change searchLog". */ + ZSTD_p_minMatch, /* Minimum size of searched matches (note : repCode matches can be smaller). + * Larger values make faster compression and decompression, but decrease ratio. + * Must be clamped between ZSTD_SEARCHLENGTH_MIN and ZSTD_SEARCHLENGTH_MAX. + * Note that currently, for all strategies < btopt, effective minimum is 4. + * Note that currently, for all strategies > fast, effective maximum is 6. + * Special: value 0 means "do not change minMatchLength". */ + ZSTD_p_targetLength, /* Only useful for strategies >= btopt. + * Length of Match considered "good enough" to stop search. + * Larger values make compression stronger and slower. + * Special: value 0 means "do not change targetLength". */ + ZSTD_p_compressionStrategy, /* See ZSTD_strategy enum definition. + * Cast selected strategy as unsigned for ZSTD_CCtx_setParameter() compatibility. + * The higher the value of selected strategy, the more complex it is, + * resulting in stronger and slower compression. + * Special: value 0 means "do not change strategy". */ + + /* frame parameters */ + ZSTD_p_contentSizeFlag=200, /* Content size is written into frame header _whenever known_ (default:1) */ + ZSTD_p_checksumFlag, /* A 32-bits checksum of content is written at end of frame (default:0) */ + ZSTD_p_dictIDFlag, /* When applicable, dictID of dictionary is provided in frame header (default:1) */ + + /* dictionary parameters (must be set before ZSTD_CCtx_loadDictionary) */ + ZSTD_p_dictMode=300, /* Select how dictionary content must be interpreted. Value must be from type ZSTD_dictMode_e. + * default : 0==auto : dictionary will be "full" if it respects specification, otherwise it will be "rawContent" */ + ZSTD_p_refDictContent, /* Dictionary content will be referenced, instead of copied (default:0==byCopy). + * It requires that dictionary buffer outlives its users */ + + /* multi-threading parameters */ + ZSTD_p_nbThreads=400, /* Select how many threads a compression job can spawn (default:1) + * More threads improve speed, but also increase memory usage. + * Can only receive a value > 1 if ZSTD_MULTITHREAD is enabled. + * Special: value 0 means "do not change nbThreads" */ + ZSTD_p_jobSize, /* Size of a compression job. Each compression job is completed in parallel. + * 0 means default, which is dynamically determined based on compression parameters. + * Job size must be a minimum of overlapSize, or 1 KB, whichever is largest + * The minimum size is automatically and transparently enforced */ + ZSTD_p_overlapSizeLog, /* Size of previous input reloaded at the beginning of each job. + * 0 => no overlap, 6(default) => use 1/8th of windowSize, >=9 => use full windowSize */ + + /* advanced parameters - may not remain available after API update */ + ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize, + * even when referencing into Dictionary content (default:0) */ + +} ZSTD_cParameter; + + +/*! ZSTD_CCtx_setParameter() : + * Set one compression parameter, selected by enum ZSTD_cParameter. + * Note : when `value` is an enum, cast it to unsigned for proper type checking. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). */ +ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value); + +/*! ZSTD_CCtx_setPledgedSrcSize() : + * Total input data size to be compressed as a single frame. + * This value will be controlled at the end, and result in error if not respected. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Note 1 : 0 means zero, empty. + * In order to mean "unknown content size", pass constant ZSTD_CONTENTSIZE_UNKNOWN. + * Note that ZSTD_CONTENTSIZE_UNKNOWN is default value for new compression jobs. + * Note 2 : If all data is provided and consumed in a single round, + * this value is overriden by srcSize instead. */ +ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize); + +/*! ZSTD_CCtx_loadDictionary() : + * Create an internal CDict from dict buffer. + * Decompression will have to use same buffer. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary, + * meaning "return to no-dictionary mode". + * Note 1 : `dict` content will be copied internally, + * except if ZSTD_p_refDictContent is set before loading. + * Note 2 : Loading a dictionary involves building tables, which are dependent on compression parameters. + * For this reason, compression parameters cannot be changed anymore after loading a dictionary. + * It's also a CPU-heavy operation, with non-negligible impact on latency. + * Note 3 : Dictionary will be used for all future compression jobs. + * To return to "no-dictionary" situation, load a NULL dictionary */ +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); + +/*! ZSTD_CCtx_refCDict() : + * Reference a prepared dictionary, to be used for all next compression jobs. + * Note that compression parameters are enforced from within CDict, + * and supercede any compression parameter previously set within CCtx. + * The dictionary will remain valid for future compression jobs using same CCtx. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special : adding a NULL CDict means "return to no-dictionary mode". + * Note 1 : Currently, only one dictionary can be managed. + * Adding a new dictionary effectively "discards" any previous one. + * Note 2 : CDict is just referenced, its lifetime must outlive CCtx. + */ +ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); + +/*! ZSTD_CCtx_refPrefix() : + * Reference a prefix (single-usage dictionary) for next compression job. + * Decompression need same prefix to properly regenerate data. + * Prefix is **only used once**. Tables are discarded at end of compression job. + * Subsequent compression jobs will be done without prefix (if none is explicitly referenced). + * If there is a need to use same prefix multiple times, consider embedding it into a ZSTD_CDict instead. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special : Adding any prefix (including NULL) invalidates any previous prefix or dictionary + * Note 1 : Prefix buffer is referenced. It must outlive compression job. + * Note 2 : Referencing a prefix involves building tables, which are dependent on compression parameters. + * It's a CPU-heavy operation, with non-negligible impact on latency. + * Note 3 : it's possible to alter ZSTD_p_dictMode using ZSTD_CCtx_setParameter() */ +ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize); + + + +typedef enum { + ZSTD_e_continue=0, /* collect more data, encoder transparently decides when to output result, for optimal conditions */ + ZSTD_e_flush, /* flush any data provided so far - frame will continue, future data can still reference previous data for better compression */ + ZSTD_e_end /* flush any remaining data and ends current frame. Any future compression starts a new frame. */ +} ZSTD_EndDirective; + +/*! ZSTD_compress_generic() : + * Behave about the same as ZSTD_compressStream. To note : + * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_setParameter() + * - Compression parameters cannot be changed once compression is started. + * - *dstPos must be <= dstCapacity, *srcPos must be <= srcSize + * - *dspPos and *srcPos will be updated. They are guaranteed to remain below their respective limit. + * - @return provides the minimum amount of data still to flush from internal buffers + * or an error code, which can be tested using ZSTD_isError(). + * if @return != 0, flush is not fully completed, there is some data left within internal buffers. + * - after a ZSTD_e_end directive, if internal buffer is not fully flushed, + * only ZSTD_e_end or ZSTD_e_flush operations are allowed. + * It is necessary to fully flush internal buffers + * before starting a new compression job, or changing compression parameters. + */ +ZSTDLIB_API size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input, + ZSTD_EndDirective endOp); + +/*! ZSTD_CCtx_reset() : + * Return a CCtx to clean state. + * Useful after an error, or to interrupt an ongoing compression job and start a new one. + * Any internal data not yet flushed is cancelled. + * Dictionary (if any) is dropped. + * It's possible to modify compression parameters after a reset. + */ +ZSTDLIB_API void ZSTD_CCtx_reset(ZSTD_CCtx* cctx); /* Not ready yet ! */ + + +/*! ZSTD_compress_generic_simpleArgs() : + * Same as ZSTD_compress_generic(), + * but using only integral types as arguments. + * Argument list is larger and less expressive than ZSTD_{in,out}Buffer, + * but can be helpful for binders from dynamic languages + * which have troubles handling structures containing memory pointers. + */ +size_t ZSTD_compress_generic_simpleArgs ( + ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos, + ZSTD_EndDirective endOp); + + + /** Block functions @@ -767,7 +1107,7 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); + compression : any ZSTD_compressBegin*() variant, including with dictionary + decompression : any ZSTD_decompressBegin*() variant, including with dictionary + copyCCtx() and copyDCtx() can be used too - - Block size is limited, it must be <= ZSTD_getBlockSizeMax() <= ZSTD_BLOCKSIZE_ABSOLUTEMAX + - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX + If input is larger than a block size, it's necessary to split input data into multiple blocks + For inputs larger than a single block size, consider using the regular ZSTD_compress() instead. Frame metadata is not that costly, and quickly becomes negligible as source size grows larger. @@ -780,9 +1120,10 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); Use ZSTD_insertBlock() for such a case. */ -#define ZSTD_BLOCKSIZE_ABSOLUTEMAX (128 * 1024) /* define, for static allocation */ +#define ZSTD_BLOCKSIZELOG_MAX 17 +#define ZSTD_BLOCKSIZE_MAX (1<<ZSTD_BLOCKSIZELOG_MAX) /* define, for static allocation */ /*===== Raw zstd block functions =====*/ -ZSTDLIB_API size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx); +ZSTDLIB_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx); ZSTDLIB_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); ZSTDLIB_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); ZSTDLIB_API size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert block into `dctx` history. Useful for uncompressed blocks */ |