diff options
259 files changed, 5253 insertions, 2400 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..69d0ba7851 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); }; @@ -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/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..57acb6c754 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "resource_loader.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_import.h" #include "os/file_access.h" #include "os/os.h" @@ -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/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/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..1a0a50a10f 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,8 @@ 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_featores=\"" + p_custom_features + "\"\n"); for (Map<String, List<String> >::Element *E = props.front(); E; E = E->next()) { @@ -565,12 +634,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 +655,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 +695,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 +761,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 +787,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 +816,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 +835,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 +860,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 +868,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 +1011,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 +1032,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/safe_refcount.cpp b/core/safe_refcount.cpp index 1bd16f9e4f..d18c90adfa 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; 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/doc/base/classes.xml b/doc/base/classes.xml index a137f9be7d..fa93d7ece7 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -741,7 +741,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 @@ -17682,7 +17682,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> 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..0cb7aa8745 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -31,7 +31,7 @@ #include "rasterizer_gles2.h" #include "gl_context/context_gl.h" -#include "global_config.h" +#include "project_settings.h" #include "os/os.h" #include "servers/visual/particle_system_sw.h" #include "servers/visual/shader_language.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..42d4572b7f 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "rasterizer_canvas_gles3.h" -#include "global_config.h" +#include "project_settings.h" #include "os/os.h" #include "rasterizer_scene_gles3.h" #include "servers/visual/visual_server_raster.h" 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..56bd3ca2ef 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]); @@ -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..263b0cc641 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); @@ -6140,7 +6168,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 +6197,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 +6210,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 +6225,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 +6238,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 +6884,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 +6893,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 +6909,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 +6916,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 +7041,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 +7055,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..ff3128d476 100644 --- a/drivers/png/resource_saver_png.cpp +++ b/drivers/png/resource_saver_png.cpp @@ -30,7 +30,7 @@ #include "resource_saver_png.h" #include "core/image.h" -#include "global_config.h" +#include "project_settings.h" #include "os/file_access.h" #include "scene/resources/texture.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..4dee796060 100644 --- a/drivers/rtaudio/audio_driver_rtaudio.cpp +++ b/drivers/rtaudio/audio_driver_rtaudio.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "audio_driver_rtaudio.h" -#include "global_config.h" +#include "project_settings.h" #include "os/os.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..da6de79592 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.cpp +++ b/drivers/xaudio2/audio_driver_xaudio2.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "audio_driver_xaudio2.h" -#include "global_config.h" +#include "project_settings.h" #include "os/os.h" const char *AudioDriverXAudio2::get_name() const { 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_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..f0f84416bf 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; @@ -1335,7 +1335,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_node.cpp b/editor/editor_node.cpp index f6a7aeff06..990628d6af 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -39,7 +39,6 @@ #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" @@ -52,12 +51,14 @@ #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" #include "servers/physics_2d_server.h" #include "translation.h" #include "version.h" +#include "version_hash.gen.h" #include <stdio.h> // plugins #include "asset_library_editor_plugin.h" @@ -163,7 +164,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 +273,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 +520,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 +871,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 +951,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 +1030,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 +1133,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 +1576,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); @@ -1797,7 +1803,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 +2270,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); @@ -2865,6 +2871,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); @@ -2934,9 +2945,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(); @@ -3277,7 +3288,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://")) { @@ -3565,7 +3576,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://", ""); @@ -3582,7 +3593,7 @@ 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()); @@ -3625,13 +3636,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++) { @@ -3746,6 +3757,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>(); @@ -5408,7 +5420,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 )) ); @@ -5937,7 +5949,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); @@ -5975,14 +5987,18 @@ EditorNode::EditorNode() { logo->set_texture(gui_base->get_icon("Logo", "EditorIcons")); 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 + String::utf8("\n\u00A9 2007-2017 Juan Linietsky, Ariel Manzur.\n\u00A9 2014-2017 ") + + 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(600, 240) * EDSCALE); + tc->set_custom_minimum_size(Size2(630, 240) * EDSCALE); tc->set_v_size_flags(Control::SIZE_EXPAND_FILL); vbc->add_child(tc); @@ -6010,14 +6026,14 @@ EditorNode::EditorNode() { dev_vbc->add_child(lbl); ItemList *il = memnew(ItemList); - il->set_max_columns(32); + il->set_max_columns(16); 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); + 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); - il->set_fixed_column_width(240 * EDSCALE); HSeparator *hs = memnew(HSeparator); hs->set_modulate(Color(0, 0, 0, 0)); @@ -6264,7 +6280,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; @@ -6277,7 +6293,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); @@ -6285,7 +6301,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(); } @@ -6366,8 +6382,8 @@ EditorNode::EditorNode() { _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 228fbe7196..e5a4cf654a 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -64,7 +64,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" @@ -310,7 +310,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; 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..e653502c0e 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -30,7 +30,7 @@ #include "editor_settings.h" #include "editor_node.h" -#include "global_config.h" +#include "project_settings.h" #include "io/compression.h" #include "io/config_file.h" #include "io/file_access_memory.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(); 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 c82c599139..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" @@ -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; } 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_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/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 c8936c8c35..4f07fdba2b 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -35,7 +35,7 @@ #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 "project_settings.h" #include "os/input.h" #include "os/keyboard.h" #include "print_string.h" @@ -2007,7 +2007,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 +2323,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)); @@ -3697,7 +3697,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/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/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..c90d66f914 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -32,7 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor/script_editor_debugger.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "os/file_access.h" @@ -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,7 +512,7 @@ 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()); @@ -777,6 +779,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 +1154,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) @@ -1568,8 +1603,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 +1697,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 +2074,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 +2103,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 +2211,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..8e6e92d48b 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -36,7 +36,7 @@ #include "editor/editor_settings.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/spatial_editor_gizmos.h" -#include "global_config.h" +#include "project_settings.h" #include "os/keyboard.h" #include "print_string.h" #include "scene/3d/camera.h" @@ -1717,11 +1717,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 +1731,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 +1834,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 a9c3fc17f0..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); } 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 c2e54ebd69..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" 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/api_generator.cpp b/modules/gdnative/api_generator.cpp index d5f22ee7a3..47162bfc49 100644 --- a/modules/gdnative/api_generator.cpp +++ b/modules/gdnative/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/gdnative.cpp b/modules/gdnative/gdnative.cpp index dad9a54df6..214164ef89 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -29,11 +29,11 @@ /*************************************************************************/ #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" @@ -481,8 +481,8 @@ void GDNativeScript::set_script_name(StringName p_script_name) { } 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_library:GDNativeLibrary"), &GDNativeScript::get_library); + ClassDB::bind_method(D_METHOD("set_library", "library:GDNativeLibrary"), &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); @@ -573,7 +573,7 @@ Error GDNativeLibrary::_initialize() { } ERR_FAIL_COND_V(platform_file == "", ERR_DOES_NOT_EXIST); - StringName path = GlobalConfig::get_singleton()->globalize_path(platform_file); + StringName path = ProjectSettings::get_singleton()->globalize_path(platform_file); GDNativeLibrary::currently_initialized_library = this; @@ -847,6 +847,16 @@ bool GDNativeInstance::set(const StringName &p_name, const Variant &p_value) { 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; } + + Map<StringName, GDNativeScriptData::Method>::Element *E = script->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; + } + return false; } @@ -856,14 +866,69 @@ bool GDNativeInstance::get(const StringName &p_name, Variant &r_ret) const { 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; + godot_variant_destroy(&value); return true; } + + Map<StringName, GDNativeScriptData::Method>::Element *E = script->script_data->methods.find("_get"); + if (E) { + Variant name = p_name; + const Variant *args[1] = { &name }; + + godot_variant result = E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, 1, (godot_variant **)args); + if (((Variant *)&result)->get_type() != Variant::NIL) { + r_ret = *(Variant *)&result; + godot_variant_destroy(&result); + return true; + } + godot_variant_destroy(&result); + } + return false; } void GDNativeInstance::get_property_list(List<PropertyInfo> *p_properties) const { script->get_script_property_list(p_properties); // TODO: dynamic properties + + Map<StringName, GDNativeScriptData::Method>::Element *E = script->script_data->methods.find("_get_property_list"); + if (E) { + godot_variant result = E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, 0, NULL); + Variant ret = *(Variant *)&result; + godot_variant_destroy(&result); + + if (ret.get_type() != Variant::ARRAY) { + ERR_EXPLAIN("Wrong type for _get_property_list, must be an array of dictionaries."); + ERR_FAIL(); + } + + Array arr = ret; + for (int i = 0; i < arr.size(); i++) { + Dictionary d = arr[i]; + ERR_CONTINUE(!d.has("name")) + ERR_CONTINUE(!d.has("type")) + + PropertyInfo pinfo; + + pinfo.type = Variant::Type(d["type"].operator int()); + ERR_CONTINUE(pinfo.type < 0 || pinfo.type >= Variant::VARIANT_MAX); + + pinfo.name = d["name"]; + ERR_CONTINUE(pinfo.name == ""); + + if (d.has("hint")) { + pinfo.hint = PropertyHint(d["hint"].operator int()); + } + if (d.has("hint_string")) { + pinfo.hint_string = d["hint_string"]; + } + if (d.has("usage")) { + pinfo.usage = d["usage"]; + } + + p_properties->push_back(pinfo); + } + } } Variant::Type GDNativeInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { @@ -1021,7 +1086,7 @@ 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); + ProjectSettings::get_singleton()->set_custom_property_info("gdnative/default_gdnativelibrary", prop_info); // generate bindings #if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) diff --git a/modules/gdnative/godot.cpp b/modules/gdnative/godot.cpp index 4dbb72bba1..764ce7c3ea 100644 --- a/modules/gdnative/godot.cpp +++ b/modules/gdnative/godot.cpp @@ -32,8 +32,8 @@ #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 @@ -93,7 +93,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 diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index adf3c8edc4..f1b4828a3e 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -30,7 +30,7 @@ #include "editor/editor_settings.h" #include "gd_compiler.h" #include "gd_script.h" -#include "global_config.h" +#include "project_settings.h" #include "os/file_access.h" #ifdef TOOLS_ENABLED #include "editor/editor_file_system.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()); @@ -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_script.cpp b/modules/gdscript/gd_script.cpp index 0afb6ac179..ca62122342 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "gd_script.h" #include "gd_compiler.h" -#include "global_config.h" +#include "project_settings.h" #include "global_constants.h" #include "io/file_access_encrypted.h" #include "os/file_access.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/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..10e02202aa 100644 --- a/modules/openssl/stream_peer_openssl.h +++ b/modules/openssl/stream_peer_openssl.h @@ -30,7 +30,7 @@ #ifndef STREAM_PEER_OPEN_SSL_H #define STREAM_PEER_OPEN_SSL_H -#include "global_config.h" +#include "project_settings.h" #include "io/stream_peer_ssl.h" #include "os/file_access.h" diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index d895f60280..f4af5026de 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "video_stream_theora.h" -#include "global_config.h" +#include "project_settings.h" #include "os/os.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..619ed8f6c0 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "visual_script.h" -#include "global_config.h" +#include "project_settings.h" #include "os/os.h" #include "scene/main/node.h" #include "visual_script_nodes.h" diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index b53a21c53b..7074ac76c7 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "visual_script_flow_control.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" #include "os/keyboard.h" @@ -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..c42e784fbc 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "visual_script_func_nodes.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" #include "os/os.h" #include "scene/main/node.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..9cbadde521 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "visual_script_nodes.h" -#include "global_config.h" +#include "project_settings.h" #include "global_constants.h" #include "os/input.h" #include "os/os.h" @@ -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 @@ -3466,7 +3466,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/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp index eaf4215302..ff0bca0fc5 100644 --- a/modules/webm/video_stream_webm.cpp +++ b/modules/webm/video_stream_webm.cpp @@ -34,7 +34,7 @@ #include "mkvparser/mkvparser.h" -#include "global_config.h" +#include "project_settings.h" #include "os/file_access.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..cf1ea169b3 100644 --- a/platform/android/audio_driver_jandroid.cpp +++ b/platform/android/audio_driver_jandroid.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "audio_driver_jandroid.h" -#include "global_config.h" +#include "project_settings.h" #include "os/os.h" #include "thread_jandroid.h" diff --git a/platform/android/detect.py b/platform/android/detect.py index 7508c9ed0e..55b7052393 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' 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..4e4fd8074c 100644 --- a/platform/android/godot_android.cpp +++ b/platform/android/godot_android.cpp @@ -36,7 +36,7 @@ #include <GLES2/gl2.h> #include "file_access_android.h" -#include "global_config.h" +#include "project_settings.h" #include "main/main.h" #include "os_android.h" #include <android/log.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..bd234fa4a2 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -36,7 +36,7 @@ #include "dir_access_jandroid.h" #include "file_access_android.h" #include "file_access_jandroid.h" -#include "global_config.h" +#include "project_settings.h" #include "java_class_wrapper.h" #include "main/input_default.h" #include "main/main.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/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/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 9df26f1471..7dbc178c60 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" @@ -487,7 +487,7 @@ void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, i #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(); @@ -828,7 +828,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 +911,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/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..9f9c785a2a 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1726,3 +1726,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/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..3143f30f77 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -1947,6 +1947,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/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_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..9de46fd937 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -444,7 +444,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:Node2D"), &Node2D::get_relative_transform_to_parent); ADD_GROUP("Transform", ""); ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position"); 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/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/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/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..159d81eb09 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "label.h" -#include "global_config.h" +#include "project_settings.h" #include "print_string.h" #include "translation.h" 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/range.cpp b/scene/gui/range.cpp index 7158592bb1..68afe8150a 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -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/text_edit.cpp b/scene/gui/text_edit.cpp index ffa23ce771..c32dafc809 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -33,7 +33,7 @@ #include "os/keyboard.h" #include "os/os.h" -#include "global_config.h" +#include "project_settings.h" #include "message_queue.h" #include "scene/main/viewport.h" diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 44f71a2c4e..8527ead01f 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()); @@ -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..26d1deadf9 100755 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1258,7 +1258,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 +2712,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 +2786,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 +2890,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/scene_tree.cpp b/scene/main/scene_tree.cpp index 65c7c1a36f..8f0467afc3 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(); } @@ -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..ce7950285d 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() { 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..3668dda604 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -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..805385ccaf 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"; } @@ -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_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/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 f108809c83..e0a9de6062 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -482,7 +482,7 @@ void StyleBoxLine::_bind_methods() { 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", "get_vertical"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical"); } float StyleBoxLine::get_style_margin(Margin p_margin) const { return thickness; 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/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..e20990cdce 100644 --- a/servers/audio/audio_driver_dummy.cpp +++ b/servers/audio/audio_driver_dummy.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "audio_driver_dummy.h" -#include "global_config.h" +#include "project_settings.h" #include "os/os.h" Error AudioDriverDummy::init() { diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 43f1175c79..253bf6e2ee 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "audio_server.h" -#include "global_config.h" +#include "project_settings.h" #include "io/resource_loader.h" #include "os/file_access.h" #include "os/os.h" @@ -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..9e84fce000 100644 --- a/servers/physics/space_sw.cpp +++ b/servers/physics/space_sw.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "space_sw.h" #include "collision_solver_sw.h" -#include "global_config.h" +#include "project_settings.h" #include "physics_server_sw.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..6c6c433230 100644 --- a/servers/physics/space_sw.h +++ b/servers/physics/space_sw.h @@ -36,7 +36,7 @@ #include "body_sw.h" #include "broad_phase_sw.h" #include "collision_object_sw.h" -#include "global_config.h" +#include "project_settings.h" #include "hash_map.h" #include "typedefs.h" 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..6eb1106de8 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -31,7 +31,7 @@ #include "broad_phase_2d_basic.h" #include "broad_phase_2d_hash_grid.h" #include "collision_solver_2d_sw.h" -#include "global_config.h" +#include "project_settings.h" #include "os/os.h" #include "script_language.h" @@ -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..5b00416b61 100644 --- a/servers/physics_2d/physics_2d_server_wrap_mt.h +++ b/servers/physics_2d/physics_2d_server_wrap_mt.h @@ -31,7 +31,7 @@ #define PHYSICS2DSERVERWRAPMT_H #include "command_queue_mt.h" -#include "global_config.h" +#include "project_settings.h" #include "os/thread.h" #include "servers/physics_2d_server.h" diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index a28233a4a6..c5bdfa3323 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -36,7 +36,7 @@ #include "body_pair_2d_sw.h" #include "broad_phase_2d_sw.h" #include "collision_object_2d_sw.h" -#include "global_config.h" +#include "project_settings.h" #include "hash_map.h" #include "typedefs.h" 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..da6174cd5c 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "visual_server_raster.h" #include "default_mouse_cursor.xpm" -#include "global_config.h" +#include "project_settings.h" #include "io/marshalls.h" #include "os/os.h" #include "sort.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..bdd41b0a57 100644 --- a/servers/visual/visual_server_wrap_mt.cpp +++ b/servers/visual/visual_server_wrap_mt.cpp @@ -27,7 +27,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "visual_server_wrap_mt.h" -#include "global_config.h" +#include "project_settings.h" #include "os/os.h" void VisualServerWrapMT::thread_exit() { diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 1e217649ba..277b401d49 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; @@ -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..f2c4e6249f 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,26 @@ 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); + + #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..003d703a5e 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_IA64) /* _mm_prefetch() is not defined for ia64 */ # 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); + unsigned long long totalDstSize = 0; - 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; - } - - 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); @@ -485,7 +553,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 +561,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 +627,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 +754,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 +935,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 +986,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 +1055,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 +1079,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 +1299,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 +1329,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 +1372,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 +1449,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 +1590,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 +1627,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 +1667,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 +1691,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 +1709,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 +1744,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 +1772,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 +1824,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 +1862,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 +1912,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 +1959,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 +1983,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 +1992,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 +2003,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 +2051,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 +2062,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 +2092,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 +2113,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 +2139,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 +2168,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 +2225,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 +2246,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 +2287,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 +2345,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 +2438,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 +2456,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 */ |