diff options
365 files changed, 10475 insertions, 7741 deletions
diff --git a/.editorconfig b/.editorconfig index f335026e1e..49517a5104 100644 --- a/.editorconfig +++ b/.editorconfig @@ -20,3 +20,7 @@ indent_size = 4 [.travis.yml] indent_style = space indent_size = 2 + +[*.{csproj,props,targets,nuspec}] +indent_style = space +indent_size = 2 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 7e8c5fd740..bc56cba21b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -6,8 +6,8 @@ labels: '' assignees: '' --- -<!-- Please search existing issues for potential duplicates before filing yours: -https://github.com/godotengine/godot/issues?q=is%3Aissue +<!-- Please search existing issues for potential duplicates before filing yours: +https://github.com/godotengine/godot/issues?q=is%3Aissue --> **Godot version:** diff --git a/.github/workflows/ios_builds.yml b/.github/workflows/ios_builds.yml new file mode 100644 index 0000000000..0657a6cb18 --- /dev/null +++ b/.github/workflows/ios_builds.yml @@ -0,0 +1,50 @@ +name: iOS Builds +on: [push, pull_request] + +# Global Cache Settings +env: + GODOT_BASE_BRANCH: master + SCONS_CACHE_LIMIT: 4096 + +jobs: + ios-template: + runs-on: "macos-latest" + name: Template (target=release, tools=no) + + steps: + - uses: actions/checkout@v2 + + # Upload cache on completion and check it out now + - name: Load .scons_cache directory + id: ios-template-cache + uses: actions/cache@v2 + with: + path: ${{github.workspace}}/.scons_cache/ + key: ${{github.job}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}} + restore-keys: | + ${{github.job}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}} + ${{github.job}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}} + ${{github.job}}-${{env.GODOT_BASE_BRANCH}} + + # Use python 3.x release (works cross platform) + - name: Set up Python 3.x + uses: actions/setup-python@v2 + with: + # Semantic version range syntax or exact version of a Python version + python-version: '3.x' + # Optional - x64 or x86 architecture, defaults to x64 + architecture: 'x64' + + # You can test your matrix by printing the current Python version + - name: Configuring Python packages + run: | + python -c "import sys; print(sys.version)" + python -m pip install scons + python --version + scons --version + + - name: Compilation + env: + SCONS_CACHE: ${{github.workspace}}/.scons_cache/ + run: | + scons -j2 verbose=yes warnings=all werror=yes platform=iphone target=release tools=no diff --git a/.github/workflows/javascript_builds.yml b/.github/workflows/javascript_builds.yml index 8167a48eae..421906c77f 100644 --- a/.github/workflows/javascript_builds.yml +++ b/.github/workflows/javascript_builds.yml @@ -5,7 +5,7 @@ on: [push, pull_request] env: GODOT_BASE_BRANCH: master SCONS_CACHE_LIMIT: 4096 - EM_VERSION: latest + EM_VERSION: 1.39.20 EM_CACHE_FOLDER: 'emsdk-cache' jobs: diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index be7737593a..198727b30e 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -9,7 +9,7 @@ env: jobs: linux-editor: runs-on: "ubuntu-20.04" - name: Editor w/ Mono (target=release_debug, tools=yes) + name: Editor w/ Mono (target=release_debug, tools=yes, tests=yes) steps: - uses: actions/checkout@v2 @@ -60,7 +60,7 @@ jobs: env: SCONS_CACHE: ${{github.workspace}}/.scons_cache/ run: | - scons -j2 verbose=yes warnings=all werror=yes platform=linuxbsd tools=yes target=release_debug module_mono_enabled=yes mono_glue=no + scons -j2 verbose=yes warnings=all werror=yes platform=linuxbsd tools=yes tests=yes target=release_debug module_mono_enabled=yes mono_glue=no # Execute unit tests for the editor - name: Unit Tests diff --git a/.github/workflows/macos_builds.yml b/.github/workflows/macos_builds.yml index 4a9fa910d0..bd3340111e 100644 --- a/.github/workflows/macos_builds.yml +++ b/.github/workflows/macos_builds.yml @@ -1,4 +1,4 @@ -name: MacOS Builds +name: macOS Builds on: [push, pull_request] # Global Cache Settings @@ -10,7 +10,7 @@ jobs: macos-editor: runs-on: "macos-latest" - name: Editor (target=release_debug, tools=yes) + name: Editor (target=release_debug, tools=yes, tests=yes) steps: - uses: actions/checkout@v2 @@ -49,7 +49,7 @@ jobs: env: SCONS_CACHE: ${{github.workspace}}/.scons_cache/ run: | - scons -j2 verbose=yes warnings=all werror=yes platform=osx tools=yes target=release_debug + scons -j2 verbose=yes warnings=all werror=yes platform=osx tools=yes tests=yes target=release_debug # Execute unit tests for the editor - name: Unit Tests diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index 87339da776..2a7a4e6625 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -13,7 +13,7 @@ jobs: run: | sudo apt-get update -qq sudo apt-get install -qq dos2unix recode clang-format - sudo pip3 install black pygments + sudo pip3 install git+https://github.com/psf/black@master pygments - name: File formatting checks (file_format.sh) run: | diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml index c58bae8275..0d3c78b45d 100644 --- a/.github/workflows/windows_builds.yml +++ b/.github/workflows/windows_builds.yml @@ -14,7 +14,7 @@ jobs: runs-on: "windows-latest" # Windows Editor - checkout with the plugin - name: Editor (target=release_debug, tools=yes) + name: Editor (target=release_debug, tools=yes, tests=yes) steps: - uses: actions/checkout@v2 @@ -54,7 +54,7 @@ jobs: env: SCONS_CACHE: /.scons_cache/ run: | - scons -j2 verbose=yes warnings=all werror=yes platform=windows tools=yes target=release_debug + scons -j2 verbose=yes warnings=all werror=yes platform=windows tools=yes tests=yes target=release_debug # Execute unit tests for the editor - name: Unit Tests @@ -66,9 +66,7 @@ There are also a number of other learning resources provided by the community, such as text and video tutorials, demos, etc. Consult the [community channels](https://godotengine.org/community) for more info. -[![Travis Build Status](https://travis-ci.org/godotengine/godot.svg?branch=master)](https://travis-ci.org/godotengine/godot) [![Actions Build Status](https://github.com/godotengine/godot/workflows/Godot/badge.svg?branch=master)](https://github.com/godotengine/godot/actions) -[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/bfiihqq6byxsjxxh/branch/master?svg=true)](https://ci.appveyor.com/project/akien-mga/godot) [![Code Triagers Badge](https://www.codetriage.com/godotengine/godot/badges/users.svg)](https://www.codetriage.com/godotengine/godot) [![Translate on Weblate](https://hosted.weblate.org/widgets/godot-engine/-/godot/svg-badge.svg)](https://hosted.weblate.org/engage/godot-engine/?utm_source=widget) [![Total alerts on LGTM](https://img.shields.io/lgtm/alerts/g/godotengine/godot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/godotengine/godot/alerts) diff --git a/SConstruct b/SConstruct index e23aa1cdbc..96d2f1abe7 100644 --- a/SConstruct +++ b/SConstruct @@ -84,6 +84,7 @@ env_base.__class__.add_shared_library = methods.add_shared_library env_base.__class__.add_library = methods.add_library env_base.__class__.add_program = methods.add_program env_base.__class__.CommandNoCache = methods.CommandNoCache +env_base.__class__.Run = methods.Run env_base.__class__.disable_warnings = methods.disable_warnings env_base.__class__.module_check_dependencies = methods.module_check_dependencies @@ -115,6 +116,7 @@ opts.Add(EnumVariable("target", "Compilation target", "debug", ("debug", "releas opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size"))) opts.Add(BoolVariable("tools", "Build the tools (a.k.a. the Godot editor)", True)) +opts.Add(BoolVariable("tests", "Build the unit tests", False)) opts.Add(BoolVariable("use_lto", "Use link-time optimization", False)) opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise epsilon (debug option)", False)) @@ -249,6 +251,10 @@ if env_base["target"] == "debug": # http://scons.org/doc/production/HTML/scons-user/ch06s04.html env_base.SetOption("implicit_cache", 1) +if not env_base["tools"]: + # Export templates can't run unit test tool. + env_base["tests"] = False + if env_base["no_editor_splash"]: env_base.Append(CPPDEFINES=["NO_EDITOR_SPLASH"]) @@ -312,6 +318,8 @@ if selected_platform in platform_list: env["verbose"] = True env["warnings"] = "extra" env["werror"] = True + if env["tools"]: + env["tests"] = True if env["vsproj"]: env.vs_incs = [] @@ -610,8 +618,9 @@ if selected_platform in platform_list: editor_module_list = ["regex"] if env["tools"] and not env.module_check_dependencies("tools", editor_module_list): print( - "Build option 'module_" + x + "_enabled=no' cannot be used with 'tools=yes' (editor), " - "only with 'tools=no' (export template)." + "Build option 'module_" + + x + + "_enabled=no' cannot be used with 'tools=yes' (editor), only with 'tools=no' (export template)." ) Exit(255) @@ -619,30 +628,24 @@ if selected_platform in platform_list: methods.no_verbose(sys, env) if not env["platform"] == "server": - env.Append( - BUILDERS={ - "GLES2_GLSL": env.Builder( - action=run_in_subprocess(gles_builders.build_gles2_headers), suffix="glsl.gen.h", src_suffix=".glsl" - ) - } - ) - env.Append( - BUILDERS={ - "RD_GLSL": env.Builder( - action=run_in_subprocess(gles_builders.build_rd_headers), suffix="glsl.gen.h", src_suffix=".glsl" - ) - } - ) - env.Append( - BUILDERS={ - "GLSL_HEADER": env.Builder( - action=run_in_subprocess(gles_builders.build_raw_headers), suffix="glsl.gen.h", src_suffix=".glsl" - ) - } - ) - - # enable test framework globally and inform it of configuration method - env.Append(CPPDEFINES=["DOCTEST_CONFIG_IMPLEMENT"]) + GLSL_BUILDERS = { + "GLES2_GLSL": env.Builder( + action=env.Run(gles_builders.build_gles2_headers, 'Building GLES2_GLSL header: "$TARGET"'), + suffix="glsl.gen.h", + src_suffix=".glsl", + ), + "RD_GLSL": env.Builder( + action=env.Run(gles_builders.build_rd_headers, 'Building RD_GLSL header: "$TARGET"'), + suffix="glsl.gen.h", + src_suffix=".glsl", + ), + "GLSL_HEADER": env.Builder( + action=env.Run(gles_builders.build_raw_headers, 'Building GLSL header: "$TARGET"'), + suffix="glsl.gen.h", + src_suffix=".glsl", + ), + } + env.Append(BUILDERS=GLSL_BUILDERS) scons_cache_path = os.environ.get("SCONS_CACHE") if scons_cache_path != None: @@ -651,8 +654,7 @@ if selected_platform in platform_list: Export("env") - # build subdirs, the build order is dependent on link order. - + # Build subdirs, the build order is dependent on link order. SConscript("core/SCsub") SConscript("servers/SCsub") SConscript("scene/SCsub") @@ -661,9 +663,11 @@ if selected_platform in platform_list: SConscript("platform/SCsub") SConscript("modules/SCsub") + if env["tests"]: + SConscript("tests/SCsub") SConscript("main/SCsub") - SConscript("platform/" + selected_platform + "/SCsub") # build selected platform + SConscript("platform/" + selected_platform + "/SCsub") # Build selected platform. # Microsoft Visual Studio Project Generation if env["vsproj"]: diff --git a/core/SCsub b/core/SCsub index 80a5f6b623..d08f17c60a 100644 --- a/core/SCsub +++ b/core/SCsub @@ -149,28 +149,34 @@ env.Depends( env.CommandNoCache( "#core/io/certs_compressed.gen.h", "#thirdparty/certs/ca-certificates.crt", - run_in_subprocess(core_builders.make_certs_header), + env.Run(core_builders.make_certs_header, "Building ca-certificates header."), ) # Make binders env.CommandNoCache( ["method_bind.gen.inc", "method_bind_ext.gen.inc", "method_bind_free_func.gen.inc"], "make_binders.py", - run_in_subprocess(make_binders.run), + env.Run(make_binders.run, "Generating method binders."), ) # Authors env.Depends("#core/authors.gen.h", "../AUTHORS.md") -env.CommandNoCache("#core/authors.gen.h", "../AUTHORS.md", run_in_subprocess(core_builders.make_authors_header)) +env.CommandNoCache( + "#core/authors.gen.h", "../AUTHORS.md", env.Run(core_builders.make_authors_header, "Generating authors header."), +) # Donors env.Depends("#core/donors.gen.h", "../DONORS.md") -env.CommandNoCache("#core/donors.gen.h", "../DONORS.md", run_in_subprocess(core_builders.make_donors_header)) +env.CommandNoCache( + "#core/donors.gen.h", "../DONORS.md", env.Run(core_builders.make_donors_header, "Generating donors header."), +) # License env.Depends("#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"]) env.CommandNoCache( - "#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"], run_in_subprocess(core_builders.make_license_header) + "#core/license.gen.h", + ["../COPYRIGHT.txt", "../LICENSE.txt"], + env.Run(core_builders.make_license_header, "Generating license header."), ) # Chain load SCsubs diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 2f8b11652b..045d7d5872 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -781,6 +781,7 @@ void _OS::_bind_methods() { // Those default values need to be specified for the docs generator, // to avoid using values from the documentation writer's own OS instance. + ADD_PROPERTY_DEFAULT("tablet_driver", ""); ADD_PROPERTY_DEFAULT("exit_code", 0); ADD_PROPERTY_DEFAULT("low_processor_usage_mode", false); ADD_PROPERTY_DEFAULT("low_processor_usage_mode_sleep_usec", 6900); diff --git a/core/callable_method_pointer.h b/core/callable_method_pointer.h index 22db7d1c82..1bb89e53e1 100644 --- a/core/callable_method_pointer.h +++ b/core/callable_method_pointer.h @@ -131,7 +131,7 @@ void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), con #ifdef DEBUG_METHODS_ENABLED (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...); #else - (p_instance->*p_method)(VariantCaster<P>::cast(p_args[Is])...); + (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...); #endif } @@ -228,7 +228,7 @@ void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), co #ifdef DEBUG_METHODS_ENABLED r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...); #else - (p_instance->*p_method)(VariantCaster<P>::cast(p_args[Is])...); + (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...); #endif } diff --git a/core/global_constants.cpp b/core/global_constants.cpp index 6281e56395..b30685539a 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -38,6 +38,7 @@ struct _GlobalConstant { #ifdef DEBUG_METHODS_ENABLED StringName enum_name; + bool ignore_value_in_docs; #endif const char *name; int value; @@ -45,8 +46,9 @@ struct _GlobalConstant { _GlobalConstant() {} #ifdef DEBUG_METHODS_ENABLED - _GlobalConstant(const StringName &p_enum_name, const char *p_name, int p_value) : + _GlobalConstant(const StringName &p_enum_name, const char *p_name, int p_value, bool p_ignore_value_in_docs = false) : enum_name(p_enum_name), + ignore_value_in_docs(p_ignore_value_in_docs), name(p_name), value(p_value) { } @@ -71,6 +73,15 @@ static Vector<_GlobalConstant> _global_constants; #define BIND_GLOBAL_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \ _global_constants.push_back(_GlobalConstant(__constant_get_enum_name(m_constant, #m_constant), m_custom_name, m_constant)); +#define BIND_GLOBAL_CONSTANT_NO_VAL(m_constant) \ + _global_constants.push_back(_GlobalConstant(StringName(), #m_constant, m_constant, true)); + +#define BIND_GLOBAL_ENUM_CONSTANT_NO_VAL(m_constant) \ + _global_constants.push_back(_GlobalConstant(__constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant, true)); + +#define BIND_GLOBAL_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \ + _global_constants.push_back(_GlobalConstant(__constant_get_enum_name(m_constant, #m_constant), m_custom_name, m_constant, true)); + #else #define BIND_GLOBAL_CONSTANT(m_constant) \ @@ -82,6 +93,15 @@ static Vector<_GlobalConstant> _global_constants; #define BIND_GLOBAL_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \ _global_constants.push_back(_GlobalConstant(m_custom_name, m_constant)); +#define BIND_GLOBAL_CONSTANT_NO_VAL(m_constant) \ + _global_constants.push_back(_GlobalConstant(#m_constant, m_constant)); + +#define BIND_GLOBAL_ENUM_CONSTANT_NO_VAL(m_constant) \ + _global_constants.push_back(_GlobalConstant(#m_constant, m_constant)); + +#define BIND_GLOBAL_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \ + _global_constants.push_back(_GlobalConstant(m_custom_name, m_constant)); + #endif VARIANT_ENUM_CAST(KeyList); @@ -368,7 +388,7 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_ALT); BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_META); BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_CTRL); - BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_CMD); + BIND_GLOBAL_ENUM_CONSTANT_NO_VAL(KEY_MASK_CMD); BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_KPAD); BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_GROUP_SWITCH); @@ -648,10 +668,18 @@ int GlobalConstants::get_global_constant_count() { StringName GlobalConstants::get_global_constant_enum(int p_idx) { return _global_constants[p_idx].enum_name; } + +bool GlobalConstants::get_ignore_value_in_docs(int p_idx) { + return _global_constants[p_idx].ignore_value_in_docs; +} #else StringName GlobalConstants::get_global_constant_enum(int p_idx) { return StringName(); } + +bool GlobalConstants::get_ignore_value_in_docs(int p_idx) { + return false; +} #endif const char *GlobalConstants::get_global_constant_name(int p_idx) { diff --git a/core/global_constants.h b/core/global_constants.h index a20b5ecd9a..989633a6fa 100644 --- a/core/global_constants.h +++ b/core/global_constants.h @@ -37,6 +37,7 @@ class GlobalConstants { public: static int get_global_constant_count(); static StringName get_global_constant_enum(int p_idx); + static bool get_ignore_value_in_docs(int p_idx); static const char *get_global_constant_name(int p_idx); static int get_global_constant_value(int p_idx); }; diff --git a/core/input/SCsub b/core/input/SCsub index c641819698..f40978911b 100644 --- a/core/input/SCsub +++ b/core/input/SCsub @@ -16,7 +16,7 @@ env.Depends("#core/input/default_controller_mappings.gen.cpp", controller_databa env.CommandNoCache( "#core/input/default_controller_mappings.gen.cpp", controller_databases, - run_in_subprocess(input_builders.make_default_controller_mappings), + env.Run(input_builders.make_default_controller_mappings, "Generating default controller mappings."), ) env.add_source_files(env.core_sources, "*.cpp") diff --git a/core/io/json.cpp b/core/io/json.cpp index b90841a5ef..8bdd6385cb 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -265,7 +265,7 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to if (p_str[index] == '-' || (p_str[index] >= '0' && p_str[index] <= '9')) { //a number const CharType *rptr; - double number = String::to_double(&p_str[index], &rptr); + double number = String::to_float(&p_str[index], &rptr); index += (rptr - &p_str[index]); r_token.type = TK_NUMBER; r_token.value = number; diff --git a/core/local_vector.h b/core/local_vector.h index d97f3330dc..b0dbd22b29 100644 --- a/core/local_vector.h +++ b/core/local_vector.h @@ -73,10 +73,10 @@ public: void remove(U p_index) { ERR_FAIL_UNSIGNED_INDEX(p_index, count); + count--; for (U i = p_index; i < count; i++) { data[i] = data[i + 1]; } - count--; if (!__has_trivial_destructor(T) && !force_trivial) { data[count].~T(); } diff --git a/core/math/expression.cpp b/core/math/expression.cpp index 13a49feb6b..735a30f6cc 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -1062,7 +1062,7 @@ Error Expression::_get_token(Token &r_token) { r_token.type = TK_CONSTANT; if (is_float) { - r_token.value = num.to_double(); + r_token.value = num.to_float(); } else { r_token.value = num.to_int(); } diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 7a9fd60e23..9f8d4da5b3 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -231,19 +231,19 @@ public: static _ALWAYS_INLINE_ double range_lerp(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); } static _ALWAYS_INLINE_ float range_lerp(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); } - static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_weight) { + static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_s) { if (is_equal_approx(p_from, p_to)) { return p_from; } - double x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0, 1.0); - return x * x * (3.0 - 2.0 * x); + double s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0, 1.0); + return s * s * (3.0 - 2.0 * s); } - static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_weight) { + static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_s) { if (is_equal_approx(p_from, p_to)) { return p_from; } - float x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0f, 1.0f); - return x * x * (3.0f - 2.0f * x); + float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f); + return s * s * (3.0f - 2.0f * s); } static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SGN(p_to - p_from) * p_delta; } static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SGN(p_to - p_from) * p_delta; } diff --git a/core/object.cpp b/core/object.cpp index 8abea9ca7e..ff6d4a666f 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -675,89 +675,11 @@ Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Call StringName method = *p_args[0]; - MessageQueue::get_singleton()->push_call(get_instance_id(), method, &p_args[1], p_argcount - 1); + MessageQueue::get_singleton()->push_call(get_instance_id(), method, &p_args[1], p_argcount - 1, true); return Variant(); } -#ifdef DEBUG_ENABLED -static void _test_call_error(const StringName &p_func, const Callable::CallError &error) { - switch (error.error) { - case Callable::CallError::CALL_OK: - case Callable::CallError::CALL_ERROR_INVALID_METHOD: - break; - case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: { - ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Invalid type for argument " + itos(error.argument) + ", expected " + Variant::get_type_name(Variant::Type(error.expected)) + "."); - break; - } - case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { - ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too many arguments, expected " + itos(error.argument) + "."); - break; - } - case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: { - ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too few arguments, expected " + itos(error.argument) + "."); - break; - } - case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: - break; - } -} -#else - -#define _test_call_error(m_str, m_err) - -#endif - -void Object::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - if (p_method == CoreStringNames::get_singleton()->_free) { -#ifdef DEBUG_ENABLED - ERR_FAIL_COND_MSG(Object::cast_to<Reference>(this), "Can't 'free' a reference."); - - ERR_FAIL_COND_MSG(_lock_index.get() > 1, "Object is locked and can't be freed."); -#endif - - //must be here, must be before everything, - memdelete(this); - return; - } - - //Variant ret; - OBJ_DEBUG_LOCK - - Callable::CallError error; - - if (script_instance) { - script_instance->call_multilevel(p_method, p_args, p_argcount); - //_test_call_error(p_method,error); - } - - MethodBind *method = ClassDB::get_method(get_class_name(), p_method); - - if (method) { - method->call(this, p_args, p_argcount, error); - _test_call_error(p_method, error); - } -} - -void Object::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - MethodBind *method = ClassDB::get_method(get_class_name(), p_method); - - Callable::CallError error; - OBJ_DEBUG_LOCK - - if (method) { - method->call(this, p_args, p_argcount, error); - _test_call_error(p_method, error); - } - - //Variant ret; - - if (script_instance) { - script_instance->call_multilevel_reversed(p_method, p_args, p_argcount); - //_test_call_error(p_method,error); - } -} - bool Object::has_method(const StringName &p_method) const { if (p_method == CoreStringNames::get_singleton()->_free) { return true; @@ -820,21 +742,6 @@ Variant Object::call(const StringName &p_name, VARIANT_ARG_DECLARE) { return ret; } -void Object::call_multilevel(const StringName &p_name, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - - int argc = 0; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - //Callable::CallError error; - call_multilevel(p_name, argptr, argc); -} - Variant Object::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { r_error.error = Callable::CallError::CALL_OK; diff --git a/core/object.h b/core/object.h index 954be5304c..d9847d10aa 100644 --- a/core/object.h +++ b/core/object.h @@ -655,10 +655,7 @@ public: void get_method_list(List<MethodInfo> *p_list) const; Variant callv(const StringName &p_method, const Array &p_args); virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); - virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); Variant call(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper - void call_multilevel(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper void notification(int p_notification, bool p_reversed = false); String to_string(); diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 638987bb2f..e08a44d0c1 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -122,6 +122,22 @@ void ProjectSettings::set_restart_if_changed(const String &p_name, bool p_restar props[p_name].restart_if_changed = p_restart; } +void ProjectSettings::set_ignore_value_in_docs(const String &p_name, bool p_ignore) { + ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + "."); +#ifdef DEBUG_METHODS_ENABLED + props[p_name].ignore_value_in_docs = p_ignore; +#endif +} + +bool ProjectSettings::get_ignore_value_in_docs(const String &p_name) const { + ERR_FAIL_COND_V_MSG(!props.has(p_name), false, "Request for nonexistent project setting: " + p_name + "."); +#ifdef DEBUG_METHODS_ENABLED + return props[p_name].ignore_value_in_docs; +#else + return false; +#endif +} + String ProjectSettings::globalize_path(const String &p_path) const { if (p_path.begins_with("res://")) { if (resource_path != "") { @@ -876,7 +892,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust } } -Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed) { +Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed, bool p_ignore_value_in_docs) { Variant ret; if (!ProjectSettings::get_singleton()->has_setting(p_var)) { ProjectSettings::get_singleton()->set(p_var, p_default); @@ -886,6 +902,7 @@ Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restar ProjectSettings::get_singleton()->set_initial_value(p_var, p_default); ProjectSettings::get_singleton()->set_builtin_order(p_var); ProjectSettings::get_singleton()->set_restart_if_changed(p_var, p_restart_if_changed); + ProjectSettings::get_singleton()->set_ignore_value_in_docs(p_var, p_ignore_value_in_docs); return ret; } diff --git a/core/project_settings.h b/core/project_settings.h index 4aceafe3c0..659ee402b3 100644 --- a/core/project_settings.h +++ b/core/project_settings.h @@ -62,6 +62,9 @@ protected: bool hide_from_editor = false; bool overridden = false; bool restart_if_changed = false; +#ifdef DEBUG_METHODS_ENABLED + bool ignore_value_in_docs = false; +#endif VariantContainer() {} @@ -125,6 +128,9 @@ public: void set_initial_value(const String &p_name, const Variant &p_value); void set_restart_if_changed(const String &p_name, bool p_restart); + void set_ignore_value_in_docs(const String &p_name, bool p_ignore); + bool get_ignore_value_in_docs(const String &p_name) const; + bool property_can_revert(const String &p_name); Variant property_get_revert(const String &p_name); @@ -167,9 +173,11 @@ public: }; //not a macro any longer -Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false); +Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false); #define GLOBAL_DEF(m_var, m_value) _GLOBAL_DEF(m_var, m_value) #define GLOBAL_DEF_RST(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true) +#define GLOBAL_DEF_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true) +#define GLOBAL_DEF_RST_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true) #define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var) #endif // PROJECT_SETTINGS_H diff --git a/core/script_language.cpp b/core/script_language.cpp index 420a560782..5176882662 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -33,6 +33,7 @@ #include "core/core_string_names.h" #include "core/debugger/engine_debugger.h" #include "core/debugger/script_debugger.h" +#include "core/os/file_access.h" #include "core/project_settings.h" #include <stdint.h> @@ -162,7 +163,7 @@ void ScriptServer::init_languages() { for (int i = 0; i < script_classes.size(); i++) { Dictionary c = script_classes[i]; - if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base")) { + if (!c.has("class") || !c.has("language") || !c.has("path") || !FileAccess::exists(c["path"]) || !c.has("base")) { continue; } add_global_class(c["class"], c["base"], c["language"], c["path"]); @@ -308,16 +309,6 @@ Variant ScriptInstance::call(const StringName &p_method, VARIANT_ARG_DECLARE) { return call(p_method, argptr, argc, error); } -void ScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - Callable::CallError ce; - call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls -} - -void ScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - Callable::CallError ce; - call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls -} - void ScriptInstance::property_set_fallback(const StringName &, const Variant &, bool *r_valid) { if (r_valid) { *r_valid = false; @@ -331,19 +322,6 @@ Variant ScriptInstance::property_get_fallback(const StringName &, bool *r_valid) return Variant(); } -void ScriptInstance::call_multilevel(const StringName &p_method, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - int argc = 0; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - call_multilevel(p_method, argptr, argc); -} - ScriptInstance::~ScriptInstance() { } diff --git a/core/script_language.h b/core/script_language.h index 6ba38399a1..aa7014ed3e 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -199,9 +199,6 @@ public: virtual bool has_method(const StringName &p_method) const = 0; virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST); virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0; - virtual void call_multilevel(const StringName &p_method, VARIANT_ARG_LIST); - virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); - virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); virtual void notification(int p_notification) = 0; virtual String to_string(bool *r_valid) { if (r_valid) { @@ -428,8 +425,6 @@ public: r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; return Variant(); } - //virtual void call_multilevel(const StringName& p_method,VARIANT_ARG_LIST) { return Variant(); } - //virtual void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount,Callable::CallError &r_error) { return Variant(); } virtual void notification(int p_notification) {} virtual Ref<Script> get_script() const { return script; } diff --git a/core/string_buffer.h b/core/string_buffer.h index 956a6333d9..f9cf31075a 100644 --- a/core/string_buffer.h +++ b/core/string_buffer.h @@ -150,7 +150,7 @@ String StringBuffer<SHORT_BUFFER_SIZE>::as_string() { template <int SHORT_BUFFER_SIZE> double StringBuffer<SHORT_BUFFER_SIZE>::as_double() { current_buffer_ptr()[string_length] = '\0'; - return String::to_double(current_buffer_ptr()); + return String::to_float(current_buffer_ptr()); } template <int SHORT_BUFFER_SIZE> diff --git a/core/ustring.cpp b/core/ustring.cpp index 5d3cf5f1a4..957caf1015 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -851,7 +851,7 @@ Vector<float> String::split_floats(const String &p_splitter, bool p_allow_empty) end = len; } if (p_allow_empty || (end > from)) { - ret.push_back(String::to_double(&c_str()[from])); + ret.push_back(String::to_float(&c_str()[from])); } if (end == len) { @@ -880,7 +880,7 @@ Vector<float> String::split_floats_mk(const Vector<String> &p_splitters, bool p_ } if (p_allow_empty || (end > from)) { - ret.push_back(String::to_double(&c_str()[from])); + ret.push_back(String::to_float(&c_str()[from])); } if (end == len) { @@ -1025,6 +1025,9 @@ String String::chr(CharType p_char) { } String String::num(double p_num, int p_decimals) { + if (Math::is_nan(p_num)) { + return "nan"; + } #ifndef NO_USE_STDLIB if (p_decimals > 16) { @@ -1313,6 +1316,9 @@ String String::num_real(double p_num) { } String String::num_scientific(double p_num) { + if (Math::is_nan(p_num)) { + return "nan"; + } #ifndef NO_USE_STDLIB char buf[256]; @@ -2000,7 +2006,7 @@ done: #define READING_EXP 3 #define READING_DONE 4 -double String::to_double(const char *p_str) { +double String::to_float(const char *p_str) { #ifndef NO_USE_STDLIB return built_in_strtod<char>(p_str); //return atof(p_str); DOES NOT WORK ON ANDROID(??) @@ -2009,11 +2015,7 @@ double String::to_double(const char *p_str) { #endif } -float String::to_float() const { - return to_double(); -} - -double String::to_double(const CharType *p_str, const CharType **r_end) { +double String::to_float(const CharType *p_str, const CharType **r_end) { return built_in_strtod<CharType>(p_str, (CharType **)r_end); } @@ -2081,7 +2083,7 @@ int64_t String::to_int(const CharType *p_str, int p_len, bool p_clamp) { return sign * integer; } -double String::to_double() const { +double String::to_float() const { if (empty()) { return 0; } diff --git a/core/ustring.h b/core/ustring.h index e745475f11..d37346fbd6 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -242,15 +242,14 @@ public: static String md5(const uint8_t *p_md5); static String hex_encode_buffer(const uint8_t *p_buffer, int p_len); bool is_numeric() const; - double to_double() const; - float to_float() const; + double to_float() const; int64_t hex_to_int(bool p_with_prefix = true) const; int64_t bin_to_int(bool p_with_prefix = true) const; int64_t to_int() const; static int64_t to_int(const char *p_str, int p_len = -1); - static double to_double(const char *p_str); - static double to_double(const CharType *p_str, const CharType **r_end = nullptr); + static double to_float(const char *p_str); + static double to_float(const CharType *p_str, const CharType **r_end = nullptr); static int64_t to_int(const CharType *p_str, int p_len = -1, bool p_clamp = false); String capitalize() const; String camelcase_to_underscore(bool lowercase = true) const; diff --git a/core/variant.cpp b/core/variant.cpp index f6b7e2821a..c19ce79e64 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -1454,7 +1454,7 @@ Variant::operator signed long() const { case INT: return _data._int; case FLOAT: - return _data._real; + return _data._float; case STRING: return operator String().to_int(); default: { @@ -1474,7 +1474,7 @@ Variant::operator unsigned long() const { case INT: return _data._int; case FLOAT: - return _data._real; + return _data._float; case STRING: return operator String().to_int(); default: { @@ -1573,7 +1573,7 @@ Variant::operator float() const { case FLOAT: return _data._float; case STRING: - return operator String().to_double(); + return operator String().to_float(); default: { return 0; } @@ -1591,7 +1591,7 @@ Variant::operator double() const { case FLOAT: return _data._float; case STRING: - return operator String().to_double(); + return operator String().to_float(); default: { return 0; } diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 8afa24e63d..b96fd0c103 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -1405,7 +1405,7 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i return (int64_t(*p_args[0])); } case FLOAT: { - return real_t(*p_args[0]); + return double(*p_args[0]); } case STRING: { return String(*p_args[0]); diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 9a28a0d085..7f7df33471 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -898,7 +898,7 @@ <constant name="KEY_MASK_CTRL" value="268435456" enum="KeyModifierMask"> Ctrl key mask. </constant> - <constant name="KEY_MASK_CMD" value="268435456" enum="KeyModifierMask"> + <constant name="KEY_MASK_CMD" value="platform-dependent" enum="KeyModifierMask"> Command key mask. On macOS, this is equivalent to [constant KEY_MASK_META]. On other platforms, this is equivalent to [constant KEY_MASK_CTRL]. This mask should be preferred to [constant KEY_MASK_META] or [constant KEY_MASK_CTRL] for system shortcuts as it handles all platforms correctly. </constant> <constant name="KEY_MASK_KPAD" value="536870912" enum="KeyModifierMask"> diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index 09811d5617..68f0a630ef 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -7,10 +7,10 @@ An Animation resource contains data used to animate everything in the engine. Animations are divided into tracks, and each track must be linked to a node. The state of that node can be changed through time, by adding timed keys (events) to the track. [codeblock] # This creates an animation that makes the node "Enemy" move to the right by - # 100 pixels in 1 second. + # 100 pixels in 0.5 seconds. var animation = Animation.new() var track_index = animation.add_track(Animation.TYPE_VALUE) - animation.track_set_path(track_index, "Enemy:position.x") + animation.track_set_path(track_index, "Enemy:position:x") animation.track_insert_key(track_index, 0.0, 0) animation.track_insert_key(track_index, 0.5, 100) [/codeblock] diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml index 675441d842..de05cfcd13 100644 --- a/doc/classes/Button.xml +++ b/doc/classes/Button.xml @@ -5,6 +5,18 @@ </brief_description> <description> Button is the standard themed button. It can contain text and an icon, and will display them according to the current [Theme]. + [b]Example of creating a button and assigning an action when pressed by code:[/b] + [codeblock] + func _ready(): + var button = Button.new() + button.text = "Click me" + button.connect("pressed", self, "_button_pressed") + add_child(button) + + func _button_pressed(): + print("Hello world!") + [/codeblock] + Buttons (like all Control nodes) can also be created in the editor, but some situations may require creating them from code. </description> <tutorials> </tutorials> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index be361f93f3..899988022f 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -316,7 +316,16 @@ <argument index="4" name="clip_w" type="int" default="-1"> </argument> <description> - Draws a string using a custom font. + Draws [code]text[/code] using the specified [code]font[/code] at the [code]position[/code] (top-left corner). The text will have its color multiplied by [code]modulate[/code]. If [code]clip_w[/code] is greater than or equal to 0, the text will be clipped if it exceeds the specified width. + [b]Example using the default project font:[/b] + [codeblock] + # If using this method in a script that redraws constantly, move the + # `default_font` declaration to a member variable assigned in `_ready()` + # so the Control is only created once. + var default_font = Control.new().get_font("font") + draw_string(default_font, Vector2(64, 64), "Hello world") + [/codeblock] + See also [method Font.draw]. </description> </method> <method name="draw_style_box"> @@ -525,7 +534,7 @@ <return type="bool"> </return> <description> - Returns [code]true[/code] if the node is present in the [SceneTree], its [member visible] property is [code]true[/code] and its inherited visibility is also [code]true[/code]. + Returns [code]true[/code] if the node is present in the [SceneTree], its [member visible] property is [code]true[/code] and all its antecedents are also visible. If any antecedent is hidden, this node will not be visible in the scene tree. </description> </method> <method name="make_canvas_position_local" qualifiers="const"> @@ -617,7 +626,8 @@ If [code]true[/code], the parent [CanvasItem]'s [member material] property is used as this one's material. </member> <member name="visible" type="bool" setter="set_visible" getter="is_visible" default="true"> - If [code]true[/code], this [CanvasItem] is drawn. For controls that inherit [Popup], the correct way to make them visible is to call one of the multiple [code]popup*()[/code] functions instead. + If [code]true[/code], this [CanvasItem] is drawn. The node is only visible if all of its antecedents are visible as well (in other words, [method is_visible_in_tree] must return [code]true[/code]). + [b]Note:[/b] For controls that inherit [Popup], the correct way to make them visible is to call one of the multiple [code]popup*()[/code] functions instead. </member> </members> <signals> diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml index bf82e921fb..e8f7a59e4c 100644 --- a/doc/classes/CollisionObject2D.xml +++ b/doc/classes/CollisionObject2D.xml @@ -217,7 +217,7 @@ </methods> <members> <member name="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" default="true"> - If [code]true[/code], this object is pickable. A pickable object can detect the mouse pointer entering/leaving, and if the mouse is inside it, report input events. + If [code]true[/code], this object is pickable. A pickable object can detect the mouse pointer entering/leaving, and if the mouse is inside it, report input events. Requires at least one [code]collision_layer[/code] bit to be set. </member> </members> <signals> @@ -229,17 +229,17 @@ <argument index="2" name="shape_idx" type="int"> </argument> <description> - Emitted when an input event occurs and [code]input_pickable[/code] is [code]true[/code]. See [method _input_event] for details. + Emitted when an input event occurs. Requires [member input_pickable] to be [code]true[/code] and at least one [code]collision_layer[/code] bit to be set. See [method _input_event] for details. </description> </signal> <signal name="mouse_entered"> <description> - Emitted when the mouse pointer enters any of this object's shapes. + Emitted when the mouse pointer enters any of this object's shapes. Requires [member input_pickable] to be [code]true[/code] and at least one [code]collision_layer[/code] bit to be set. </description> </signal> <signal name="mouse_exited"> <description> - Emitted when the mouse pointer exits all this object's shapes. + Emitted when the mouse pointer exits all this object's shapes. Requires [member input_pickable] to be [code]true[/code] and at least one [code]collision_layer[/code] bit to be set. </description> </signal> </signals> diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 49af8d7de2..814c232668 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -627,12 +627,14 @@ <return type="int"> </return> <description> + Returns the on-screen keyboard's height in pixels. Returns 0 if there is no keyboard or if it is currently hidden. </description> </method> <method name="virtual_keyboard_hide"> <return type="void"> </return> <description> + Hides the virtual keyboard if it is shown, does nothing otherwise. </description> </method> <method name="virtual_keyboard_show"> @@ -642,13 +644,23 @@ </argument> <argument index="1" name="position" type="Rect2" default="Rect2i( 0, 0, 0, 0 )"> </argument> - <argument index="2" name="max_length" type="int" default="-1"> + <argument index="2" name="multiline" type="bool" default="false"> </argument> - <argument index="3" name="cursor_start" type="int" default="-1"> + <argument index="3" name="max_length" type="int" default="-1"> </argument> - <argument index="4" name="cursor_end" type="int" default="-1"> + <argument index="4" name="cursor_start" type="int" default="-1"> + </argument> + <argument index="5" name="cursor_end" type="int" default="-1"> </argument> <description> + Shows the virtual keyboard if the platform has one. + [code]existing_text[/code] parameter is useful for implementing your own [LineEdit] or [TextEdit], as it tells the virtual keyboard what text has already been typed (the virtual keyboard uses it for auto-correct and predictions). + [code]position[/code] parameter is the screen space [Rect2] of the edited text. + [code]multiline[/code] parameter needs to be set to [code]true[/code] to be able to enter multiple lines of text, as in [TextEdit]. + [code]max_length[/code] limits the number of characters that can be entered if different from [code]-1[/code]. + [code]cursor_start[/code] can optionally define the current text cursor position if [code]cursor_end[/code] is not set. + [code]cursor_start[/code] and [code]cursor_end[/code] can optionally define the current text selection. + [b]Note:[/b] This method is implemented on Android, iOS and UWP. </description> </method> <method name="vsync_is_enabled" qualifiers="const"> diff --git a/doc/classes/EditorInspector.xml b/doc/classes/EditorInspector.xml index 5fbe427f67..6f03165a97 100644 --- a/doc/classes/EditorInspector.xml +++ b/doc/classes/EditorInspector.xml @@ -20,9 +20,7 @@ </method> </methods> <members> - <member name="scroll_horizontal_enabled" type="bool" setter="set_enable_h_scroll" getter="is_h_scroll_enabled" override="true" default="false"> - If [code]true[/code], horizontal scrolling is enabled. An horizontal scroll bar will display at the bottom of the inspector. - </member> + <member name="scroll_horizontal_enabled" type="bool" setter="set_enable_h_scroll" getter="is_h_scroll_enabled" override="true" default="false" /> </members> <signals> <signal name="object_id_selected"> diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml index 8b2b9c9350..9da36b51f9 100644 --- a/doc/classes/EditorInterface.xml +++ b/doc/classes/EditorInterface.xml @@ -51,8 +51,8 @@ <return type="Control"> </return> <description> - Returns the editor's [Viewport] instance. - [b]Note:[/b] This returns the main editor viewport containing the whole editor, not the 2D or 3D viewports specifically. + Returns the main editor control. Use this as a parent for main screens. + [b]Note:[/b] This returns the main editor control containing the whole editor, not the 2D or 3D viewports specifically. </description> </method> <method name="get_file_system_dock"> diff --git a/doc/classes/EditorTranslationParserPlugin.xml b/doc/classes/EditorTranslationParserPlugin.xml index a40ef45916..d40fc558de 100644 --- a/doc/classes/EditorTranslationParserPlugin.xml +++ b/doc/classes/EditorTranslationParserPlugin.xml @@ -35,7 +35,7 @@ func get_recognized_extensions(): - return ["gd"] + return ["gd"] [/codeblock] </description> <tutorials> diff --git a/doc/classes/File.xml b/doc/classes/File.xml index 20bc39ef1f..d91203d91f 100644 --- a/doc/classes/File.xml +++ b/doc/classes/File.xml @@ -257,6 +257,7 @@ </argument> <description> Opens an encrypted file in write or read mode. You need to pass a binary key to encrypt/decrypt it. + [b]Note:[/b] The provided key must be 32 bytes long. </description> </method> <method name="open_encrypted_with_pass"> diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml index 30b8c1fe76..ce6a25e191 100644 --- a/doc/classes/Font.xml +++ b/doc/classes/Font.xml @@ -26,6 +26,7 @@ </argument> <description> Draw [code]string[/code] into a canvas item using the font at a given position, with [code]modulate[/code] color, and optionally clipping the width. [code]position[/code] specifies the baseline, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis. + See also [method CanvasItem.draw_string]. </description> </method> <method name="draw_char" qualifiers="const"> diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml index 7bd2edcb1c..2e837dea1d 100644 --- a/doc/classes/JSON.xml +++ b/doc/classes/JSON.xml @@ -15,7 +15,7 @@ <argument index="0" name="json" type="String"> </argument> <description> - Parses a JSON encoded string and returns a [JSONParseResult] containing the result. + Parses a JSON-encoded string and returns a [JSONParseResult] containing the result. </description> </method> <method name="print"> @@ -29,6 +29,7 @@ </argument> <description> Converts a [Variant] var to JSON text and returns the result. Useful for serializing data to store or send over the network. + [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, converting a Variant to JSON text will convert all numerical values to [float] types. </description> </method> </methods> diff --git a/doc/classes/JSONParseResult.xml b/doc/classes/JSONParseResult.xml index 4444e08593..4dbceb35e9 100644 --- a/doc/classes/JSONParseResult.xml +++ b/doc/classes/JSONParseResult.xml @@ -15,21 +15,21 @@ The error type if the JSON source was not successfully parsed. See the [enum Error] constants. </member> <member name="error_line" type="int" setter="set_error_line" getter="get_error_line" default="-1"> - The line number where the error occurred if JSON source was not successfully parsed. + The line number where the error occurred if the JSON source was not successfully parsed. </member> <member name="error_string" type="String" setter="set_error_string" getter="get_error_string" default=""""> - The error message if JSON source was not successfully parsed. See the [enum Error] constants. + The error message if the JSON source was not successfully parsed. See the [enum Error] constants. </member> <member name="result" type="Variant" setter="set_result" getter="get_result"> - A [Variant] containing the parsed JSON. Use [method @GDScript.typeof] or the [code]is[/code] keyword to check if it is what you expect. For example, if the JSON source starts with curly braces ([code]{}[/code]), a [Dictionary] will be returned. If the JSON source starts with braces ([code][][/code]), an [Array] will be returned. - [b]Note:[/b] The JSON specification does not define integer or float types, but only a number type. Therefore, parsing a JSON text will convert all numerical values to float types. + A [Variant] containing the parsed JSON. Use [method @GDScript.typeof] or the [code]is[/code] keyword to check if it is what you expect. For example, if the JSON source starts with curly braces ([code]{}[/code]), a [Dictionary] will be returned. If the JSON source starts with brackets ([code][][/code]), an [Array] will be returned. + [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, parsing a JSON text will convert all numerical values to [float] types. [b]Note:[/b] JSON objects do not preserve key order like Godot dictionaries, thus, you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements: [codeblock] var p = JSON.parse('["hello", "world", "!"]') if typeof(p.result) == TYPE_ARRAY: print(p.result[0]) # Prints "hello" else: - print("unexpected results") + push_error("Unexpected results.") [/codeblock] </member> </members> diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index feac483fc4..f08a15d873 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -122,6 +122,8 @@ <member name="caret_blink_speed" type="float" setter="cursor_set_blink_speed" getter="cursor_get_blink_speed" default="0.65"> Duration (in seconds) of a caret's blinking cycle. </member> + <member name="caret_force_displayed" type="bool" setter="cursor_set_force_displayed" getter="cursor_get_force_displayed" default="false"> + </member> <member name="caret_position" type="int" setter="set_cursor_position" getter="get_cursor_position" default="0"> The cursor's position inside the [LineEdit]. When set, the text may scroll to accommodate it. </member> diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml index 05d00b9f31..02b319fb5a 100644 --- a/doc/classes/Node3D.xml +++ b/doc/classes/Node3D.xml @@ -101,7 +101,7 @@ <return type="bool"> </return> <description> - Returns whether the node is visible, taking into consideration that its parents visibility. + Returns [code]true[/code] if the node is present in the [SceneTree], its [member visible] property is [code]true[/code] and all its antecedents are also visible. If any antecedent is hidden, this node will not be visible in the scene tree. </description> </method> <method name="look_at"> @@ -323,7 +323,7 @@ Local translation of this node. </member> <member name="visible" type="bool" setter="set_visible" getter="is_visible" default="true"> - If [code]true[/code], this node is drawn. + If [code]true[/code], this node is drawn. The node is only visible if all of its antecedents are visible as well (in other words, [method is_visible_in_tree] must return [code]true[/code]). </member> </members> <signals> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 5b4b5d02fb..26110df335 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -120,7 +120,7 @@ [codeblock] var arguments = {} for argument in OS.get_cmdline_args(): - if argument.find("=") > -1: + if argument.find("=") > -1: var key_value = argument.split("=") arguments[key_value[0].lstrip("--")] = key_value[1] [/codeblock] diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index 3d8c2c5eb0..ca6b624359 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -17,8 +17,10 @@ [/codeblock] The [code]in[/code] operator will evaluate to [code]true[/code] as long as the key exists, even if the value is [code]null[/code]. Objects also receive notifications. Notifications are a simple way to notify the object about different events, so they can all be handled together. See [method _notification]. + [b]Note:[/b] Unlike references to a [Reference], references to an Object stored in a variable can become invalid without warning. Therefore, it's recommended to use [Reference] for data classes instead of [Object]. </description> <tutorials> + <link title="When and how to avoid using nodes for everything">https://docs.godotengine.org/en/latest/getting_started/workflow/best_practices/node_alternatives.html</link> </tutorials> <methods> <method name="_get" qualifiers="virtual"> @@ -518,7 +520,7 @@ One-shot connections disconnect themselves after emission. </constant> <constant name="CONNECT_REFERENCE_COUNTED" value="8" enum="ConnectFlags"> - Connect a signal as reference counted. This means that a given signal can be connected several times to the same target, and will only be fully disconnected once no references are left. + Connect a signal as reference-counted. This means that a given signal can be connected several times to the same target, and will only be fully disconnected once no references are left. </constant> </constants> </class> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index e255ce2e1a..f13dbbae76 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -244,7 +244,7 @@ <member name="audio/default_bus_layout" type="String" setter="" getter="" default=""res://default_bus_layout.tres""> Default [AudioBusLayout] resource file to use in the project, unless overridden by the scene. </member> - <member name="audio/driver" type="String" setter="" getter="" default=""PulseAudio""> + <member name="audio/driver" type="String" setter="" getter=""> Specifies the audio driver to use. This setting is platform-dependent as each platform supports different audio drivers. If left empty, the default audio driver will be used. </member> <member name="audio/enable_audio_input" type="bool" setter="" getter="" default="false"> @@ -280,6 +280,10 @@ <member name="debug/gdscript/completion/autocomplete_setters_and_getters" type="bool" setter="" getter="" default="false"> If [code]true[/code], displays getters and setters in autocompletion results in the script editor. This setting is meant to be used when porting old projects (Godot 2), as using member variables is the preferred style from Godot 3 onwards. </member> + <member name="debug/gdscript/warnings/assert_always_false" type="bool" setter="" getter="" default="true"> + </member> + <member name="debug/gdscript/warnings/assert_always_true" type="bool" setter="" getter="" default="true"> + </member> <member name="debug/gdscript/warnings/constant_used_as_function" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables warnings when a constant is used as a function. </member> @@ -292,15 +296,6 @@ <member name="debug/gdscript/warnings/exclude_addons" type="bool" setter="" getter="" default="true"> If [code]true[/code], scripts in the [code]res://addons[/code] folder will not generate warnings. </member> - <member name="debug/gdscript/warnings/function_conflicts_constant" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when a function is declared with the same name as a constant. - </member> - <member name="debug/gdscript/warnings/function_conflicts_variable" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when a function is declared with the same name as a variable. This will turn into an error in a future version when first-class functions become supported in GDScript. - </member> - <member name="debug/gdscript/warnings/function_may_yield" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when a function assigned to a variable may yield and return a function state instead of a value. - </member> <member name="debug/gdscript/warnings/function_used_as_property" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables warnings when using a function as if it was a property. </member> @@ -316,12 +311,16 @@ <member name="debug/gdscript/warnings/property_used_as_function" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables warnings when using a property as if it was a function. </member> + <member name="debug/gdscript/warnings/redundant_await" type="bool" setter="" getter="" default="true"> + </member> <member name="debug/gdscript/warnings/return_value_discarded" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables warnings when calling a function without using its return value (by assigning it to a variable or using it as a function argument). Such return values are sometimes used to denote possible errors using the [enum Error] enum. </member> <member name="debug/gdscript/warnings/shadowed_variable" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables warnings when defining a local or subclass member variable that would shadow a variable at an upper level (such as a member variable). </member> + <member name="debug/gdscript/warnings/shadowed_variable_base_class" type="bool" setter="" getter="" default="true"> + </member> <member name="debug/gdscript/warnings/standalone_expression" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables warnings when calling an expression that has no effect on the surrounding code, such as writing [code]2 + 2[/code] as a statement. </member> @@ -340,6 +339,8 @@ <member name="debug/gdscript/warnings/unreachable_code" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables warnings when unreachable code is detected (such as after a [code]return[/code] statement that will always be executed). </member> + <member name="debug/gdscript/warnings/unreachable_pattern" type="bool" setter="" getter="" default="true"> + </member> <member name="debug/gdscript/warnings/unsafe_call_argument" type="bool" setter="" getter="" default="false"> If [code]true[/code], enables warnings when using an expression whose type may not be compatible with the function parameter expected. </member> @@ -352,11 +353,11 @@ <member name="debug/gdscript/warnings/unsafe_property_access" type="bool" setter="" getter="" default="false"> If [code]true[/code], enables warnings when accessing a property whose presence is not guaranteed at compile-time in the class. </member> - <member name="debug/gdscript/warnings/unused_argument" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when a function parameter is unused. + <member name="debug/gdscript/warnings/unused_local_constant" type="bool" setter="" getter="" default="true"> </member> - <member name="debug/gdscript/warnings/unused_class_variable" type="bool" setter="" getter="" default="false"> - If [code]true[/code], enables warnings when a member variable is unused. + <member name="debug/gdscript/warnings/unused_parameter" type="bool" setter="" getter="" default="true"> + </member> + <member name="debug/gdscript/warnings/unused_private_class_variable" type="bool" setter="" getter="" default="true"> </member> <member name="debug/gdscript/warnings/unused_signal" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables warnings when a signal is unused. @@ -364,9 +365,6 @@ <member name="debug/gdscript/warnings/unused_variable" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables warnings when a local variable is unused. </member> - <member name="debug/gdscript/warnings/variable_conflicts_function" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when a variable is declared with the same name as a function. This will turn into an error in a future version when first-class functions become supported in GDScript. - </member> <member name="debug/gdscript/warnings/void_assignment" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables warnings when assigning the result of a function that returns [code]void[/code] to a variable. </member> @@ -453,7 +451,7 @@ <member name="display/window/size/width" type="int" setter="" getter="" default="1024"> Sets the game's main viewport width. On desktop platforms, this is the default window size. Stretch mode settings also use this as a reference when enabled. </member> - <member name="display/window/tablet_driver" type="String" setter="" getter="" default=""""> + <member name="display/window/tablet_driver" type="String" setter="" getter=""> Specifies the tablet driver to use. If left empty, the default driver will be used. </member> <member name="display/window/vsync/use_vsync" type="bool" setter="" getter="" default="true"> @@ -472,7 +470,7 @@ <member name="gui/common/default_scroll_deadzone" type="int" setter="" getter="" default="0"> Default value for [member ScrollContainer.scroll_deadzone], which will be used for all [ScrollContainer]s unless overridden. </member> - <member name="gui/common/swap_cancel_ok" type="bool" setter="" getter="" default="false"> + <member name="gui/common/swap_cancel_ok" type="bool" setter="" getter=""> If [code]true[/code], swaps Cancel and OK buttons in dialogs on Windows and UWP to follow interface conventions. </member> <member name="gui/common/text_edit_undo_stack_max_size" type="int" setter="" getter="" default="1024"> diff --git a/doc/classes/Reference.xml b/doc/classes/Reference.xml index 860a47798c..9c3d1d5d9d 100644 --- a/doc/classes/Reference.xml +++ b/doc/classes/Reference.xml @@ -5,10 +5,11 @@ </brief_description> <description> Base class for any object that keeps a reference count. [Resource] and many other helper objects inherit this class. - References keep an internal reference counter so that they are automatically released when no longer in use, and only then. References therefore do not need to be freed manually with [method Object.free]. + Unlike [Object]s, References keep an internal reference counter so that they are automatically released when no longer in use, and only then. References therefore do not need to be freed manually with [method Object.free]. In the vast majority of use cases, instantiating and using [Reference]-derived types is all you need to do. The methods provided in this class are only for advanced users, and can cause issues if misused. </description> <tutorials> + <link title="When and how to avoid using nodes for everything">https://docs.godotengine.org/en/latest/getting_started/workflow/best_practices/node_alternatives.html</link> </tutorials> <methods> <method name="init_ref"> diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml index 0aa40dffb3..e79a2e0ea9 100644 --- a/doc/classes/Resource.xml +++ b/doc/classes/Resource.xml @@ -4,10 +4,11 @@ Base class for all resources. </brief_description> <description> - Resource is the base class for all Godot-specific resource types, serving primarily as data containers. They are reference counted and freed when no longer in use. They are also cached once loaded from disk, so that any further attempts to load a resource from a given path will return the same reference (all this in contrast to a [Node], which is not reference counted and can be instanced from disk as many times as desired). Resources can be saved externally on disk or bundled into another object, such as a [Node] or another resource. + Resource is the base class for all Godot-specific resource types, serving primarily as data containers. Unlike [Object]s, they are reference-counted and freed when no longer in use. They are also cached once loaded from disk, so that any further attempts to load a resource from a given path will return the same reference (all this in contrast to a [Node], which is not reference-counted and can be instanced from disk as many times as desired). Resources can be saved externally on disk or bundled into another object, such as a [Node] or another resource. </description> <tutorials> - <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/resources.html</link> + <link title="Resources">https://docs.godotengine.org/en/latest/getting_started/step_by_step/resources.html</link> + <link title="When and how to avoid using nodes for everything">https://docs.godotengine.org/en/latest/getting_started/workflow/best_practices/node_alternatives.html</link> </tutorials> <methods> <method name="_setup_local_to_scene" qualifiers="virtual"> diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml index d56dc1e17c..a7efba518c 100644 --- a/doc/classes/RigidBody2D.xml +++ b/doc/classes/RigidBody2D.xml @@ -84,7 +84,7 @@ <return type="Node2D[]"> </return> <description> - Returns a list of the bodies colliding with this one. Use [member contacts_reported] to set the maximum number reported. You must also set [member contact_monitor] to [code]true[/code]. + Returns a list of the bodies colliding with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of collisions is updated once per frame and before the physics step. Consider using signals instead. </description> </method> @@ -133,7 +133,8 @@ If [code]true[/code], the body will emit signals when it collides with another RigidBody2D. See also [member contacts_reported]. </member> <member name="contacts_reported" type="int" setter="set_max_contacts_reported" getter="get_max_contacts_reported" default="0"> - The maximum number of contacts to report. + The maximum number of contacts that will be recorded. Requires [member contact_monitor] to be set to [code]true[/code]. + [b]Note:[/b] The number of contacts is different from the number of collisions. Collisions between parallel edges will result in two contacts (one at each end), and collisions between parallel faces will result in four contacts (one at each corner). </member> <member name="continuous_cd" type="int" setter="set_continuous_collision_detection_mode" getter="get_continuous_collision_detection_mode" enum="RigidBody2D.CCDMode" default="0"> Continuous collision detection mode. @@ -176,14 +177,14 @@ <argument index="0" name="body" type="Node"> </argument> <description> - Emitted when a body enters into contact with this one. [member contact_monitor] must be [code]true[/code] and [member contacts_reported] greater than [code]0[/code]. + Emitted when a body enters into contact with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. </description> </signal> <signal name="body_exited"> <argument index="0" name="body" type="Node"> </argument> <description> - Emitted when a body exits contact with this one. [member contact_monitor] must be [code]true[/code] and [member contacts_reported] greater than [code]0[/code]. + Emitted when a body exits contact with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. </description> </signal> <signal name="body_shape_entered"> @@ -196,7 +197,7 @@ <argument index="3" name="local_shape" type="int"> </argument> <description> - Emitted when a body enters into contact with this one. Reports colliding shape information. See [CollisionObject2D] for shape index information. [member contact_monitor] must be [code]true[/code] and [member contacts_reported] greater than [code]0[/code]. + Emitted when a body enters into contact with this one. Reports colliding shape information. See [CollisionObject2D] for shape index information. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. </description> </signal> <signal name="body_shape_exited"> @@ -209,7 +210,7 @@ <argument index="3" name="local_shape" type="int"> </argument> <description> - Emitted when a body shape exits contact with this one. Reports colliding shape information. See [CollisionObject2D] for shape index information. [member contact_monitor] must be [code]true[/code] and [member contacts_reported] greater than [code]0[/code]. + Emitted when a body shape exits contact with this one. Reports colliding shape information. See [CollisionObject2D] for shape index information. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. </description> </signal> <signal name="sleeping_state_changed"> diff --git a/doc/classes/RigidBody3D.xml b/doc/classes/RigidBody3D.xml index 370e6bd19c..933885ba77 100644 --- a/doc/classes/RigidBody3D.xml +++ b/doc/classes/RigidBody3D.xml @@ -96,7 +96,7 @@ <return type="Array"> </return> <description> - Returns a list of the bodies colliding with this one. By default, number of max contacts reported is at 0, see the [member contacts_reported] property to increase it. + Returns a list of the bodies colliding with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of collisions is updated once per frame and before the physics step. Consider using signals instead. </description> </method> @@ -157,10 +157,11 @@ If [code]true[/code], the body can enter sleep mode when there is no movement. See [member sleeping]. </member> <member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false"> - If [code]true[/code], the RigidBody3D will emit signals when it collides with another RigidBody3D. + If [code]true[/code], the RigidBody3D will emit signals when it collides with another RigidBody3D. See also [member contacts_reported]. </member> <member name="contacts_reported" type="int" setter="set_max_contacts_reported" getter="get_max_contacts_reported" default="0"> - The maximum contacts to report. Bodies can keep a log of the contacts with other bodies, this is enabled by setting the maximum amount of contacts reported to a number greater than 0. + The maximum number of contacts that will be recorded. Requires [member contact_monitor] to be set to [code]true[/code]. + [b]Note:[/b] The number of contacts is different from the number of collisions. Collisions between parallel edges will result in two contacts (one at each end), and collisions between parallel faces will result in four contacts (one at each corner). </member> <member name="continuous_cd" type="bool" setter="set_use_continuous_collision_detection" getter="is_using_continuous_collision_detection" default="false"> If [code]true[/code], continuous collision detection is used. @@ -200,14 +201,14 @@ <argument index="0" name="body" type="Node"> </argument> <description> - Emitted when a body enters into contact with this one. Contact monitor and contacts reported must be enabled for this to work. + Emitted when a body enters into contact with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. </description> </signal> <signal name="body_exited"> <argument index="0" name="body" type="Node"> </argument> <description> - Emitted when a body shape exits contact with this one. Contact monitor and contacts reported must be enabled for this to work. + Emitted when a body shape exits contact with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. </description> </signal> <signal name="body_shape_entered"> @@ -220,7 +221,7 @@ <argument index="3" name="local_shape" type="int"> </argument> <description> - Emitted when a body enters into contact with this one. Contact monitor and contacts reported must be enabled for this to work. + Emitted when a body enters into contact with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. This signal not only receives the body that collided with this one, but also its [RID] ([code]body_id[/code]), the shape index from the colliding body ([code]body_shape[/code]), and the shape index from this body ([code]local_shape[/code]) the other body collided with. </description> </signal> @@ -234,7 +235,7 @@ <argument index="3" name="local_shape" type="int"> </argument> <description> - Emitted when a body shape exits contact with this one. Contact monitor and contacts reported must be enabled for this to work. + Emitted when a body shape exits contact with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. This signal not only receives the body that stopped colliding with this one, but also its [RID] ([code]body_id[/code]), the shape index from the colliding body ([code]body_shape[/code]), and the shape index from this body ([code]local_shape[/code]) the other body stopped colliding with. </description> </signal> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 71db03e84f..ded64761d0 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -4,7 +4,7 @@ Built-in string class. </brief_description> <description> - This is the built-in string class (and the one used by GDScript). It supports Unicode and provides all necessary means for string handling. Strings are reference counted and use a copy-on-write approach, so passing them around is cheap in resources. + This is the built-in string class (and the one used by GDScript). It supports Unicode and provides all necessary means for string handling. Strings are reference-counted and use a copy-on-write approach, so passing them around is cheap in resources. </description> <tutorials> <link>https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/gdscript_format_string.html</link> @@ -895,8 +895,8 @@ <argument index="2" name="maxsplit" type="int" default="0"> </argument> <description> - Splits the string by a [code]delimiter[/code] string and returns an array of the substrings. - If [code]maxsplit[/code] is specified, it defines the number of splits to do from the left up to [code]maxsplit[/code]. The default value of 0 means that all items are split. + Splits the string by a [code]delimiter[/code] string and returns an array of the substrings. The [code]delimiter[/code] can be of any length. + If [code]maxsplit[/code] is specified, it defines the number of splits to do from the left up to [code]maxsplit[/code]. The default value of [code]0[/code] means that all items are split. Example: [codeblock] var some_string = "One,Two,Three,Four" @@ -905,6 +905,7 @@ print(some_array[0]) # Prints "One" print(some_array[1]) # Prints "Two,Three,Four" [/codeblock] + If you need to split strings with more complex rules, use the [RegEx] class instead. </description> </method> <method name="split_floats"> diff --git a/doc/classes/Thread.xml b/doc/classes/Thread.xml index 4d6e89fa6f..5c63d01322 100644 --- a/doc/classes/Thread.xml +++ b/doc/classes/Thread.xml @@ -7,7 +7,8 @@ A unit of execution in a process. Can run methods on [Object]s simultaneously. The use of synchronization via [Mutex] or [Semaphore] is advised if working with shared objects. </description> <tutorials> - <link>https://docs.godotengine.org/en/latest/tutorials/threads/using_multiple_threads.html</link> + <link title="Using multiple threads">https://docs.godotengine.org/en/latest/tutorials/threads/using_multiple_threads.html</link> + <link title="Thread-safe APIs">https://docs.godotengine.org/en/latest/tutorials/threads/thread_safe_apis.html</link> </tutorials> <methods> <method name="get_id" qualifiers="const"> diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml index 9a78e45d46..4991a1e58b 100644 --- a/doc/classes/TileSet.xml +++ b/doc/classes/TileSet.xml @@ -478,7 +478,17 @@ <argument index="0" name="id" type="int"> </argument> <description> - Returns an array of the tile's shapes. + Returns an array of dictionaries describing the tile's shapes. + [b]Dictionary structure in the array returned by this method:[/b] + [codeblock] + { + "autotile_coord": Vector2, + "one_way": bool, + "one_way_margin": int, + "shape": CollisionShape2D, + "shape_transform": Transform2D, + } + [/codeblock] </description> </method> <method name="tile_get_texture" qualifiers="const"> diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index 126d6b4180..22e643a51d 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -118,7 +118,7 @@ <return type="TreeItem"> </return> <description> - Returns the TreeItem's child items. + Returns the TreeItem's first child item or a null object if there is none. </description> </method> <method name="get_custom_bg_color" qualifiers="const"> @@ -196,7 +196,7 @@ <return type="TreeItem"> </return> <description> - Returns the next TreeItem in the tree. + Returns the next TreeItem in the tree or a null object if there is none. </description> </method> <method name="get_next_visible"> @@ -205,7 +205,7 @@ <argument index="0" name="wrap" type="bool" default="false"> </argument> <description> - Returns the next visible TreeItem in the tree. + Returns the next visible TreeItem in the tree or a null object if there is none. If [code]wrap[/code] is enabled, the method will wrap around to the first visible element in the tree when called on the last visible element, otherwise it returns [code]null[/code]. </description> </method> @@ -213,14 +213,14 @@ <return type="TreeItem"> </return> <description> - Returns the parent TreeItem. + Returns the parent TreeItem or a null object if there is none. </description> </method> <method name="get_prev"> <return type="TreeItem"> </return> <description> - Returns the previous TreeItem in the tree. + Returns the previous TreeItem in the tree or a null object if there is none. </description> </method> <method name="get_prev_visible"> @@ -229,7 +229,7 @@ <argument index="0" name="wrap" type="bool" default="false"> </argument> <description> - Returns the previous visible TreeItem in the tree. + Returns the previous visible TreeItem in the tree or a null object if there is none. If [code]wrap[/code] is enabled, the method will wrap around to the last visible element in the tree when called on the first visible element, otherwise it returns [code]null[/code]. </description> </method> diff --git a/doc/classes/VisualShaderNodeBooleanUniform.xml b/doc/classes/VisualShaderNodeBooleanUniform.xml index 8313a8256e..7d72f13f9d 100644 --- a/doc/classes/VisualShaderNodeBooleanUniform.xml +++ b/doc/classes/VisualShaderNodeBooleanUniform.xml @@ -10,6 +10,14 @@ </tutorials> <methods> </methods> + <members> + <member name="default_value" type="bool" setter="set_default_value" getter="get_default_value" default="false"> + A default value to be assigned within the shader. + </member> + <member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false"> + Enables usage of the [member default_value]. + </member> + </members> <constants> </constants> </class> diff --git a/doc/classes/VisualShaderNodeColorUniform.xml b/doc/classes/VisualShaderNodeColorUniform.xml index 6972ccefd9..90ef381b76 100644 --- a/doc/classes/VisualShaderNodeColorUniform.xml +++ b/doc/classes/VisualShaderNodeColorUniform.xml @@ -10,6 +10,14 @@ </tutorials> <methods> </methods> + <members> + <member name="default_value" type="Color" setter="set_default_value" getter="get_default_value" default="Color( 1, 1, 1, 1 )"> + A default value to be assigned within the shader. + </member> + <member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false"> + Enables usage of the [member default_value]. + </member> + </members> <constants> </constants> </class> diff --git a/doc/classes/VisualShaderNodeFloatUniform.xml b/doc/classes/VisualShaderNodeFloatUniform.xml index 33ece8ac1b..705d5e8796 100644 --- a/doc/classes/VisualShaderNodeFloatUniform.xml +++ b/doc/classes/VisualShaderNodeFloatUniform.xml @@ -11,6 +11,12 @@ <methods> </methods> <members> + <member name="default_value" type="float" setter="set_default_value" getter="get_default_value" default="0.0"> + A default value to be assigned within the shader. + </member> + <member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false"> + Enables usage of the [member default_value]. + </member> <member name="hint" type="int" setter="set_hint" getter="get_hint" enum="VisualShaderNodeFloatUniform.Hint" default="0"> A hint applied to the uniform, which controls the values it can take when set through the inspector. </member> diff --git a/doc/classes/VisualShaderNodeIntUniform.xml b/doc/classes/VisualShaderNodeIntUniform.xml index 8c7c288177..e39eba865b 100644 --- a/doc/classes/VisualShaderNodeIntUniform.xml +++ b/doc/classes/VisualShaderNodeIntUniform.xml @@ -11,6 +11,12 @@ <methods> </methods> <members> + <member name="default_value" type="int" setter="set_default_value" getter="get_default_value" default="0"> + A default value to be assigned within the shader. + </member> + <member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false"> + Enables usage of the [member default_value]. + </member> <member name="hint" type="int" setter="set_hint" getter="get_hint" enum="VisualShaderNodeIntUniform.Hint" default="0"> A hint applied to the uniform, which controls the values it can take when set through the inspector. </member> diff --git a/doc/classes/VisualShaderNodeTransformUniform.xml b/doc/classes/VisualShaderNodeTransformUniform.xml index 43696c8226..ff6246618d 100644 --- a/doc/classes/VisualShaderNodeTransformUniform.xml +++ b/doc/classes/VisualShaderNodeTransformUniform.xml @@ -10,6 +10,14 @@ </tutorials> <methods> </methods> + <members> + <member name="default_value" type="Transform" setter="set_default_value" getter="get_default_value" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> + A default value to be assigned within the shader. + </member> + <member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false"> + Enables usage of the [member default_value]. + </member> + </members> <constants> </constants> </class> diff --git a/doc/classes/VisualShaderNodeUniformRef.xml b/doc/classes/VisualShaderNodeUniformRef.xml new file mode 100644 index 0000000000..db02e398ab --- /dev/null +++ b/doc/classes/VisualShaderNodeUniformRef.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeUniformRef" inherits="VisualShaderNode" version="4.0"> + <brief_description> + A reference to an existing [VisualShaderNodeUniform]. + </brief_description> + <description> + Creating a reference to a [VisualShaderNodeUniform] allows you to reuse this uniform in different shaders or shader stages easily. + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="uniform_name" type="String" setter="set_uniform_name" getter="get_uniform_name" default=""[None]""> + The name of the uniform which this reference points to. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVec3Uniform.xml b/doc/classes/VisualShaderNodeVec3Uniform.xml index c8b44fdc8d..cd1500f5a1 100644 --- a/doc/classes/VisualShaderNodeVec3Uniform.xml +++ b/doc/classes/VisualShaderNodeVec3Uniform.xml @@ -10,6 +10,14 @@ </tutorials> <methods> </methods> + <members> + <member name="default_value" type="Vector3" setter="set_default_value" getter="get_default_value" default="Vector3( 0, 0, 0 )"> + A default value to be assigned within the shader. + </member> + <member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false"> + Enables usage of the [member default_value]. + </member> + </members> <constants> </constants> </class> diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py index c0bba38799..b594f652b3 100755 --- a/doc/tools/makerst.py +++ b/doc/tools/makerst.py @@ -565,6 +565,8 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S index += 1 + f.write(make_footer()) + def escape_rst(text, until_pos=-1): # type: (str) -> str # Escape \ character, otherwise it ends up as an escape character in rst @@ -600,6 +602,43 @@ def escape_rst(text, until_pos=-1): # type: (str) -> str return text +def format_codeblock(code_type, post_text, indent_level, state): # types: str, str, int, state + end_pos = post_text.find("[/" + code_type + "]") + if end_pos == -1: + print_error("[" + code_type + "] without a closing tag, file: {}".format(state.current_class), state) + return None + + code_text = post_text[len("[" + code_type + "]") : end_pos] + post_text = post_text[end_pos:] + + # Remove extraneous tabs + code_pos = 0 + while True: + code_pos = code_text.find("\n", code_pos) + if code_pos == -1: + break + + to_skip = 0 + while code_pos + to_skip + 1 < len(code_text) and code_text[code_pos + to_skip + 1] == "\t": + to_skip += 1 + + if to_skip > indent_level: + print_error( + "Four spaces should be used for indentation within [" + + code_type + + "], file: {}".format(state.current_class), + state, + ) + + if len(code_text[code_pos + to_skip + 1 :]) == 0: + code_text = code_text[:code_pos] + "\n" + code_pos += 1 + else: + code_text = code_text[:code_pos] + "\n " + code_text[code_pos + to_skip + 1 :] + code_pos += 5 - to_skip + return ["\n[" + code_type + "]" + code_text + post_text, len("\n[" + code_type + "]" + code_text)] + + def rstize_text(text, state): # type: (str, State) -> str # Linebreak + tabs in the XML should become two line breaks unless in a "codeblock" pos = 0 @@ -616,43 +655,17 @@ def rstize_text(text, state): # type: (str, State) -> str post_text = text[pos + 1 :] # Handle codeblocks - if post_text.startswith("[codeblock]"): - end_pos = post_text.find("[/codeblock]") - if end_pos == -1: - print_error("[codeblock] without a closing tag, file: {}".format(state.current_class), state) + if ( + post_text.startswith("[codeblock]") + or post_text.startswith("[gdscript]") + or post_text.startswith("[csharp]") + ): + block_type = post_text[1:].split("]")[0] + result = format_codeblock(block_type, post_text, indent_level, state) + if result is None: return "" - - code_text = post_text[len("[codeblock]") : end_pos] - post_text = post_text[end_pos:] - - # Remove extraneous tabs - code_pos = 0 - while True: - code_pos = code_text.find("\n", code_pos) - if code_pos == -1: - break - - to_skip = 0 - while code_pos + to_skip + 1 < len(code_text) and code_text[code_pos + to_skip + 1] == "\t": - to_skip += 1 - - if to_skip > indent_level: - print_error( - "Four spaces should be used for indentation within [codeblock], file: {}".format( - state.current_class - ), - state, - ) - - if len(code_text[code_pos + to_skip + 1 :]) == 0: - code_text = code_text[:code_pos] + "\n" - code_pos += 1 - else: - code_text = code_text[:code_pos] + "\n " + code_text[code_pos + to_skip + 1 :] - code_pos += 5 - to_skip - - text = pre_text + "\n[codeblock]" + code_text + post_text - pos += len("\n[codeblock]" + code_text) + text = pre_text + result[0] + pos += result[1] # Handle normal text else: @@ -697,7 +710,7 @@ def rstize_text(text, state): # type: (str, State) -> str else: # command cmd = tag_text space_pos = tag_text.find(" ") - if cmd == "/codeblock": + if cmd == "/codeblock" or cmd == "/gdscript" or cmd == "/csharp": tag_text = "" tag_depth -= 1 inside_code = False @@ -813,6 +826,20 @@ def rstize_text(text, state): # type: (str, State) -> str tag_depth += 1 tag_text = "\n::\n" inside_code = True + elif cmd == "gdscript": + tag_depth += 1 + tag_text = "\n .. code-tab:: gdscript GDScript\n" + inside_code = True + elif cmd == "csharp": + tag_depth += 1 + tag_text = "\n .. code-tab:: csharp\n" + inside_code = True + elif cmd == "codeblocks": + tag_depth += 1 + tag_text = "\n.. tabs::" + elif cmd == "/codeblocks": + tag_depth -= 1 + tag_text = "" elif cmd == "br": # Make a new paragraph instead of a linebreak, rst is not so linebreak friendly tag_text = "\n\n" @@ -995,7 +1022,10 @@ def make_method_signature( out += " **)**" if isinstance(method_def, MethodDef) and method_def.qualifiers is not None: - out += " " + method_def.qualifiers + # Use substitutions for abbreviations. This is used to display tooltips on hover. + # See `make_footer()` for descriptions. + for qualifier in method_def.qualifiers.split(): + out += " |" + qualifier + "|" return ret_type, out @@ -1004,6 +1034,18 @@ def make_heading(title, underline): # type: (str, str) -> str return title + "\n" + (underline * len(title)) + "\n\n" +def make_footer(): # type: () -> str + # Generate reusable abbreviation substitutions. + # This way, we avoid bloating the generated rST with duplicate abbreviations. + # fmt: off + return ( + ".. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)`\n" + ".. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)`\n" + ".. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)`" + ) + # fmt: on + + def make_url(link): # type: (str) -> str match = GODOT_DOCS_PATTERN.search(link) if match: diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub index 91d0e42f80..61d91711da 100644 --- a/drivers/vulkan/SCsub +++ b/drivers/vulkan/SCsub @@ -4,6 +4,7 @@ Import("env") env.add_source_files(env.drivers_sources, "*.cpp") +# FIXME: Refactor all this to reduce code duplication. if env["platform"] == "android": # Use NDK Vulkan headers thirdparty_dir = env["ANDROID_NDK_ROOT"] + "/sources/third_party/vulkan/src" @@ -22,6 +23,17 @@ if env["platform"] == "android": thirdparty_dir = "#thirdparty/vulkan" vma_sources = [thirdparty_dir + "/android/vk_mem_alloc.cpp"] env_thirdparty.add_source_files(env.drivers_sources, vma_sources) +elif env["platform"] == "iphone": + # Use bundled Vulkan headers + thirdparty_dir = "#thirdparty/vulkan" + env.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "/include", thirdparty_dir + "/loader"]) + + # Build Vulkan memory allocator + env_thirdparty = env.Clone() + env_thirdparty.disable_warnings() + + vma_sources = [thirdparty_dir + "/vk_mem_alloc.cpp"] + env_thirdparty.add_source_files(env.drivers_sources, vma_sources) elif env["builtin_vulkan"]: # Use bundled Vulkan headers thirdparty_dir = "#thirdparty/vulkan" @@ -70,16 +82,6 @@ elif env["builtin_vulkan"]: 'FALLBACK_CONFIG_DIRS=\\"%s\\"' % "/etc/xdg", ] ) - elif env["platform"] == "iphone": - env_thirdparty.AppendUnique( - CPPDEFINES=[ - "VK_USE_PLATFORM_IOS_MVK", - "VULKAN_NON_CMAKE_BUILD", - 'SYSCONFDIR=\\"%s\\"' % "/etc", - 'FALLBACK_DATA_DIRS=\\"%s\\"' % "/usr/local/share:/usr/share", - 'FALLBACK_CONFIG_DIRS=\\"%s\\"' % "/etc/xdg", - ] - ) elif env["platform"] == "linuxbsd": env_thirdparty.AppendUnique( CPPDEFINES=[ @@ -99,3 +101,13 @@ elif env["builtin_vulkan"]: loader_sources = [thirdparty_dir + "/loader/" + file for file in loader_sources] env_thirdparty.add_source_files(env.drivers_sources, loader_sources) env_thirdparty.add_source_files(env.drivers_sources, vma_sources) +else: # Always build VMA. + thirdparty_dir = "#thirdparty/vulkan" + env.Prepend(CPPPATH=[thirdparty_dir]) + + # Build Vulkan loader library + env_thirdparty = env.Clone() + env_thirdparty.disable_warnings() + vma_sources = [thirdparty_dir + "/vk_mem_alloc.cpp"] + + env_thirdparty.add_source_files(env.drivers_sources, vma_sources) diff --git a/editor/SCsub b/editor/SCsub index 651dd5fffd..a976c4ed12 100644 --- a/editor/SCsub +++ b/editor/SCsub @@ -7,7 +7,6 @@ env.editor_sources = [] import os import os.path import glob -from platform_methods import run_in_subprocess import editor_builders @@ -61,7 +60,11 @@ if env["tools"]: docs = sorted(docs) env.Depends("#editor/doc_data_compressed.gen.h", docs) - env.CommandNoCache("#editor/doc_data_compressed.gen.h", docs, run_in_subprocess(editor_builders.make_doc_header)) + env.CommandNoCache( + "#editor/doc_data_compressed.gen.h", + docs, + env.Run(editor_builders.make_doc_header, "Generating documentation header."), + ) path = env.Dir(".").abspath @@ -69,14 +72,18 @@ if env["tools"]: tlist = glob.glob(path + "/translations/*.po") env.Depends("#editor/editor_translations.gen.h", tlist) env.CommandNoCache( - "#editor/editor_translations.gen.h", tlist, run_in_subprocess(editor_builders.make_editor_translations_header) + "#editor/editor_translations.gen.h", + tlist, + env.Run(editor_builders.make_editor_translations_header, "Generating editor translations header."), ) # Documentation translations tlist = glob.glob(env.Dir("#doc").abspath + "/translations/*.po") env.Depends("#editor/doc_translations.gen.h", tlist) env.CommandNoCache( - "#editor/doc_translations.gen.h", tlist, run_in_subprocess(editor_builders.make_doc_translations_header) + "#editor/doc_translations.gen.h", + tlist, + env.Run(editor_builders.make_doc_translations_header, "Generating translations header."), ) # Fonts @@ -84,7 +91,11 @@ if env["tools"]: flist.extend(glob.glob(path + "/../thirdparty/fonts/*.otf")) flist.sort() env.Depends("#editor/builtin_fonts.gen.h", flist) - env.CommandNoCache("#editor/builtin_fonts.gen.h", flist, run_in_subprocess(editor_builders.make_fonts_header)) + env.CommandNoCache( + "#editor/builtin_fonts.gen.h", + flist, + env.Run(editor_builders.make_fonts_header, "Generating builtin fonts header."), + ) env.add_source_files(env.editor_sources, "*.cpp") diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 9a87d6d38c..37db3ba780 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1456,8 +1456,6 @@ void CodeTextEditor::set_edit_state(const Variant &p_state) { text_editor->set_line_as_bookmark(bookmarks[i], true); } } - - text_editor->grab_focus(); } void CodeTextEditor::set_error(const String &p_error) { diff --git a/editor/doc_data.cpp b/editor/doc_data.cpp index 54acbe9559..75b16b4510 100644 --- a/editor/doc_data.cpp +++ b/editor/doc_data.cpp @@ -321,12 +321,13 @@ void DocData::generate(bool p_basic_types) { continue; } if (E->get().usage & PROPERTY_USAGE_EDITOR) { - default_value = ProjectSettings::get_singleton()->property_get_revert(E->get().name); - default_value_valid = true; + if (!ProjectSettings::get_singleton()->get_ignore_value_in_docs(E->get().name)) { + default_value = ProjectSettings::get_singleton()->property_get_revert(E->get().name); + default_value_valid = true; + } } } else { default_value = get_documentation_default_value(name, E->get().name, default_value_valid); - if (inherited) { bool base_default_value_valid = false; Variant base_default_value = get_documentation_default_value(ClassDB::get_parent_class(name), E->get().name, base_default_value_valid); @@ -478,6 +479,7 @@ void DocData::generate(bool p_basic_types) { ConstantDoc constant; constant.name = E->get(); constant.value = itos(ClassDB::get_integer_constant(name, E->get())); + constant.is_value_valid = true; constant.enumeration = ClassDB::get_integer_constant_enum(name, E->get()); c.constants.push_back(constant); } @@ -620,6 +622,7 @@ void DocData::generate(bool p_basic_types) { constant.name = E->get(); Variant value = Variant::get_constant_value(Variant::Type(i), E->get()); constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string(); + constant.is_value_valid = true; c.constants.push_back(constant); } } @@ -635,7 +638,12 @@ void DocData::generate(bool p_basic_types) { for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) { ConstantDoc cd; cd.name = GlobalConstants::get_global_constant_name(i); - cd.value = itos(GlobalConstants::get_global_constant_value(i)); + if (!GlobalConstants::get_ignore_value_in_docs(i)) { + cd.value = itos(GlobalConstants::get_global_constant_value(i)); + cd.is_value_valid = true; + } else { + cd.is_value_valid = false; + } cd.enumeration = GlobalConstants::get_global_constant_enum(i); c.constants.push_back(cd); } @@ -715,6 +723,7 @@ void DocData::generate(bool p_basic_types) { ConstantDoc cd; cd.name = E->get().first; cd.value = E->get().second; + cd.is_value_valid = true; c.constants.push_back(cd); } @@ -989,6 +998,7 @@ Error DocData::_load(Ref<XMLParser> parser) { constant2.name = parser->get_attribute_value("name"); ERR_FAIL_COND_V(!parser->has_attribute("value"), ERR_FILE_CORRUPT); constant2.value = parser->get_attribute_value("value"); + constant2.is_value_valid = true; if (parser->has_attribute("enum")) { constant2.enumeration = parser->get_attribute_value("enum"); } @@ -1178,10 +1188,18 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri for (int i = 0; i < c.constants.size(); i++) { const ConstantDoc &k = c.constants[i]; - if (k.enumeration != String()) { - _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\">"); + if (k.is_value_valid) { + if (k.enumeration != String()) { + _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\">"); + } else { + _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\">"); + } } else { - _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\">"); + if (k.enumeration != String()) { + _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"platform-dependent\" enum=\"" + k.enumeration + "\">"); + } else { + _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"platform-dependent\">"); + } } _write_string(f, 3, k.description.strip_edges().xml_escape()); _write_string(f, 2, "</constant>"); diff --git a/editor/doc_data.h b/editor/doc_data.h index 1880be81ed..a35cfb59c7 100644 --- a/editor/doc_data.h +++ b/editor/doc_data.h @@ -62,6 +62,7 @@ public: struct ConstantDoc { String name; String value; + bool is_value_valid; String enumeration; String description; bool operator<(const ConstantDoc &p_const) const { diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 94887fb848..5d101ff2c2 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -688,12 +688,12 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_ const String &path = p_path; if (!FileAccess::exists(path)) { - EditorNode::get_singleton()->show_warning(TTR("Can't add autoload:") + "\n" + TTR(vformat("%s is an invalid path. File does not exist.", path))); + EditorNode::get_singleton()->show_warning(TTR("Can't add autoload:") + "\n" + vformat(TTR("%s is an invalid path. File does not exist."), path)); return false; } if (!path.begins_with("res://")) { - EditorNode::get_singleton()->show_warning(TTR("Can't add autoload:") + "\n" + TTR(vformat("%s is an invalid path. Not in resource path (res://).", path))); + EditorNode::get_singleton()->show_warning(TTR("Can't add autoload:") + "\n" + vformat(TTR("%s is an invalid path. Not in resource path (res://)."), path)); return false; } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 2a59aadd61..bce34db740 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -1252,6 +1252,55 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { String bbcode = p_bbcode.dedent().replace("\t", "").replace("\r", "").strip_edges(); + // Select the correct code examples + switch ((int)EDITOR_GET("text_editor/help/class_reference_examples")) { + case 0: // GDScript + bbcode = bbcode.replace("[gdscript]", "[codeblock]"); + bbcode = bbcode.replace("[/gdscript]", "[/codeblock]"); + + for (int pos = bbcode.find("[csharp]"); pos != -1; pos = bbcode.find("[csharp]")) { + if (bbcode.find("[/csharp]") == -1) { + WARN_PRINT("Unclosed [csharp] block or parse fail in code (search for tag errors)"); + break; + } + + bbcode.erase(pos, bbcode.find("[/csharp]") + 9 - pos); + while (bbcode[pos] == '\n') { + bbcode.erase(pos, 1); + } + } + break; + case 1: // C# + bbcode = bbcode.replace("[csharp]", "[codeblock]"); + bbcode = bbcode.replace("[/csharp]", "[/codeblock]"); + + for (int pos = bbcode.find("[gdscript]"); pos != -1; pos = bbcode.find("[gdscript]")) { + if (bbcode.find("[/gdscript]") == -1) { + WARN_PRINT("Unclosed [gdscript] block or parse fail in code (search for tag errors)"); + break; + } + + bbcode.erase(pos, bbcode.find("[/gdscript]") + 11 - pos); + while (bbcode[pos] == '\n') { + bbcode.erase(pos, 1); + } + } + break; + case 2: // GDScript and C# + bbcode = bbcode.replace("[csharp]", "[b]C#:[/b]\n[codeblock]"); + bbcode = bbcode.replace("[gdscript]", "[b]GDScript:[/b]\n[codeblock]"); + + bbcode = bbcode.replace("[/csharp]", "[/codeblock]"); + bbcode = bbcode.replace("[/gdscript]", "[/codeblock]"); + break; + } + + // Remove codeblocks (they would be printed otherwise) + bbcode = bbcode.replace("[codeblocks]\n", ""); + bbcode = bbcode.replace("\n[/codeblocks]", ""); + bbcode = bbcode.replace("[codeblocks]", ""); + bbcode = bbcode.replace("[/codeblocks]", ""); + // remove extra new lines around code blocks bbcode = bbcode.replace("[codeblock]\n", "[codeblock]"); bbcode = bbcode.replace("\n[/codeblock]", "[/codeblock]"); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 263ed9040a..ce131e6a05 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1236,7 +1236,10 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) { img.instance(); img->create(1, 1, 0, Image::FORMAT_RGB8); } else if (c3d < c2d) { - img = scene_root->get_texture()->get_data(); + Ref<ViewportTexture> viewport_texture = scene_root->get_texture(); + if (viewport_texture->get_width() > 0 && viewport_texture->get_height() > 0) { + img = viewport_texture->get_data(); + } } else { // The 3D editor may be disabled as a feature, but scenes can still be opened. // This check prevents the preview from regenerating in case those scenes are then saved. @@ -1246,7 +1249,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) { } } - if (img.is_valid()) { + if (img.is_valid() && img->get_width() > 0 && img->get_height() > 0) { img = img->duplicate(); save.step(TTR("Creating Thumbnail"), 2); @@ -6796,6 +6799,7 @@ EditorNode::EditorNode() { EditorNode::~EditorNode() { EditorInspector::cleanup_plugins(); + EditorTranslationParser::get_singleton()->clean_parsers(); remove_print_handler(&print_handler); memdelete(EditorHelp::get_doc_data()); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 2d50d25ff5..daafe095ce 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -3275,10 +3275,10 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ if ((p_hint == PROPERTY_HINT_RANGE || p_hint == PROPERTY_HINT_EXP_RANGE) && p_hint_text.get_slice_count(",") >= 2) { greater = false; //if using ranged, assume false by default lesser = false; - min = p_hint_text.get_slice(",", 0).to_double(); - max = p_hint_text.get_slice(",", 1).to_double(); + min = p_hint_text.get_slice(",", 0).to_float(); + max = p_hint_text.get_slice(",", 1).to_float(); if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_double(); + step = p_hint_text.get_slice(",", 2).to_float(); } hide_slider = false; exp_range = p_hint == PROPERTY_HINT_EXP_RANGE; @@ -3378,10 +3378,10 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ bool hide_slider = true; if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_double(); - max = p_hint_text.get_slice(",", 1).to_double(); + min = p_hint_text.get_slice(",", 0).to_float(); + max = p_hint_text.get_slice(",", 1).to_float(); if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_double(); + step = p_hint_text.get_slice(",", 2).to_float(); } hide_slider = false; } @@ -3396,8 +3396,8 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ bool hide_slider = true; if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_double(); - max = p_hint_text.get_slice(",", 1).to_double(); + min = p_hint_text.get_slice(",", 0).to_float(); + max = p_hint_text.get_slice(",", 1).to_float(); hide_slider = false; } @@ -3411,10 +3411,10 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ bool hide_slider = true; if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_double(); - max = p_hint_text.get_slice(",", 1).to_double(); + min = p_hint_text.get_slice(",", 0).to_float(); + max = p_hint_text.get_slice(",", 1).to_float(); if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_double(); + step = p_hint_text.get_slice(",", 2).to_float(); } hide_slider = false; } @@ -3428,8 +3428,8 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ bool hide_slider = true; if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_double(); - max = p_hint_text.get_slice(",", 1).to_double(); + min = p_hint_text.get_slice(",", 0).to_float(); + max = p_hint_text.get_slice(",", 1).to_float(); hide_slider = false; } @@ -3442,10 +3442,10 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ bool hide_slider = true; if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_double(); - max = p_hint_text.get_slice(",", 1).to_double(); + min = p_hint_text.get_slice(",", 0).to_float(); + max = p_hint_text.get_slice(",", 1).to_float(); if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_double(); + step = p_hint_text.get_slice(",", 2).to_float(); } hide_slider = false; } @@ -3460,8 +3460,8 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ bool hide_slider = true; if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_double(); - max = p_hint_text.get_slice(",", 1).to_double(); + min = p_hint_text.get_slice(",", 0).to_float(); + max = p_hint_text.get_slice(",", 1).to_float(); hide_slider = false; } @@ -3476,10 +3476,10 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ bool hide_slider = true; if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_double(); - max = p_hint_text.get_slice(",", 1).to_double(); + min = p_hint_text.get_slice(",", 0).to_float(); + max = p_hint_text.get_slice(",", 1).to_float(); if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_double(); + step = p_hint_text.get_slice(",", 2).to_float(); } hide_slider = false; } @@ -3494,10 +3494,10 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ bool hide_slider = true; if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_double(); - max = p_hint_text.get_slice(",", 1).to_double(); + min = p_hint_text.get_slice(",", 0).to_float(); + max = p_hint_text.get_slice(",", 1).to_float(); if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_double(); + step = p_hint_text.get_slice(",", 2).to_float(); } hide_slider = false; } @@ -3511,10 +3511,10 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ bool hide_slider = true; if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_double(); - max = p_hint_text.get_slice(",", 1).to_double(); + min = p_hint_text.get_slice(",", 0).to_float(); + max = p_hint_text.get_slice(",", 1).to_float(); if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_double(); + step = p_hint_text.get_slice(",", 2).to_float(); } hide_slider = false; } @@ -3528,10 +3528,10 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ bool hide_slider = true; if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_double(); - max = p_hint_text.get_slice(",", 1).to_double(); + min = p_hint_text.get_slice(",", 0).to_float(); + max = p_hint_text.get_slice(",", 1).to_float(); if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_double(); + step = p_hint_text.get_slice(",", 2).to_float(); } hide_slider = false; } @@ -3545,10 +3545,10 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ bool hide_slider = true; if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_double(); - max = p_hint_text.get_slice(",", 1).to_double(); + min = p_hint_text.get_slice(",", 0).to_float(); + max = p_hint_text.get_slice(",", 1).to_float(); if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_double(); + step = p_hint_text.get_slice(",", 2).to_float(); } hide_slider = false; } @@ -3562,10 +3562,10 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ bool hide_slider = true; if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_double(); - max = p_hint_text.get_slice(",", 1).to_double(); + min = p_hint_text.get_slice(",", 0).to_float(); + max = p_hint_text.get_slice(",", 1).to_float(); if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_double(); + step = p_hint_text.get_slice(",", 2).to_float(); } hide_slider = false; } diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 3a1a0d5b01..a3438b3601 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -495,6 +495,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { hints["text_editor/help/help_source_font_size"] = PropertyInfo(Variant::INT, "text_editor/help/help_source_font_size", PROPERTY_HINT_RANGE, "8,48,1"); _initial_set("text_editor/help/help_title_font_size", 23); hints["text_editor/help/help_title_font_size"] = PropertyInfo(Variant::INT, "text_editor/help/help_title_font_size", PROPERTY_HINT_RANGE, "8,48,1"); + _initial_set("text_editor/help/class_reference_examples", 0); + hints["text_editor/help/class_reference_examples"] = PropertyInfo(Variant::INT, "text_editor/help/class_reference_examples", PROPERTY_HINT_ENUM, "GDScript,C#,GDScript and C#"); /* Editors */ diff --git a/editor/editor_translation_parser.cpp b/editor/editor_translation_parser.cpp index 3f4864ad1e..da191fbc92 100644 --- a/editor/editor_translation_parser.cpp +++ b/editor/editor_translation_parser.cpp @@ -147,6 +147,11 @@ void EditorTranslationParser::remove_parser(const Ref<EditorTranslationParserPlu } } +void EditorTranslationParser::clean_parsers() { + standard_parsers.clear(); + custom_parsers.clear(); +} + EditorTranslationParser *EditorTranslationParser::get_singleton() { if (!singleton) { singleton = memnew(EditorTranslationParser); diff --git a/editor/editor_translation_parser.h b/editor/editor_translation_parser.h index 6d00bedfa4..fb8aa6ec9b 100644 --- a/editor/editor_translation_parser.h +++ b/editor/editor_translation_parser.h @@ -64,6 +64,7 @@ public: Ref<EditorTranslationParserPlugin> get_parser(const String &p_extension) const; void add_parser(const Ref<EditorTranslationParserPlugin> &p_parser, ParserType p_type); void remove_parser(const Ref<EditorTranslationParserPlugin> &p_parser, ParserType p_type); + void clean_parsers(); EditorTranslationParser(); ~EditorTranslationParser(); diff --git a/editor/icons/SCsub b/editor/icons/SCsub index e143276259..dd4243d750 100644 --- a/editor/icons/SCsub +++ b/editor/icons/SCsub @@ -4,14 +4,14 @@ Import("env") import os -from platform_methods import run_in_subprocess import editor_icons_builders -make_editor_icons_builder = Builder( - action=run_in_subprocess(editor_icons_builders.make_editor_icons_action), suffix=".h", src_suffix=".svg" -) -env["BUILDERS"]["MakeEditorIconsBuilder"] = make_editor_icons_builder +env["BUILDERS"]["MakeEditorIconsBuilder"] = Builder( + action=env.Run(editor_icons_builders.make_editor_icons_action, "Generating editor icons header."), + suffix=".h", + src_suffix=".svg", +) # Editor's own icons icon_sources = Glob("*.svg") diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp index 41e71248a9..8eb68ecdcf 100644 --- a/editor/import/collada.cpp +++ b/editor/import/collada.cpp @@ -262,7 +262,7 @@ void Collada::_parse_asset(XMLParser &parser) { COLLADA_PRINT("up axis: " + parser.get_node_data()); } else if (name == "unit") { - state.unit_scale = parser.get_attribute_value("meter").to_double(); + state.unit_scale = parser.get_attribute_value("meter").to_float(); COLLADA_PRINT("unit scale: " + rtos(state.unit_scale)); } @@ -433,7 +433,7 @@ Transform Collada::_read_transform(XMLParser &parser) { Vector<float> farr; farr.resize(16); for (int i = 0; i < 16; i++) { - farr.write[i] = array[i].to_double(); + farr.write[i] = array[i].to_float(); } return _read_transform_from_array(farr); @@ -469,7 +469,7 @@ Variant Collada::_parse_param(XMLParser &parser) { if (parser.get_node_name() == "float") { parser.read(); if (parser.get_node_type() == XMLParser::NODE_TEXT) { - data = parser.get_node_data().to_double(); + data = parser.get_node_data().to_float(); } } else if (parser.get_node_name() == "float2") { Vector<float> v2 = _read_float_array(parser); @@ -735,29 +735,29 @@ void Collada::_parse_camera(XMLParser &parser) { camera.mode = CameraData::MODE_ORTHOGONAL; } else if (name == "xfov") { parser.read(); - camera.perspective.x_fov = parser.get_node_data().to_double(); + camera.perspective.x_fov = parser.get_node_data().to_float(); } else if (name == "yfov") { parser.read(); - camera.perspective.y_fov = parser.get_node_data().to_double(); + camera.perspective.y_fov = parser.get_node_data().to_float(); } else if (name == "xmag") { parser.read(); - camera.orthogonal.x_mag = parser.get_node_data().to_double(); + camera.orthogonal.x_mag = parser.get_node_data().to_float(); } else if (name == "ymag") { parser.read(); - camera.orthogonal.y_mag = parser.get_node_data().to_double(); + camera.orthogonal.y_mag = parser.get_node_data().to_float(); } else if (name == "aspect_ratio") { parser.read(); - camera.aspect = parser.get_node_data().to_double(); + camera.aspect = parser.get_node_data().to_float(); } else if (name == "znear") { parser.read(); - camera.z_near = parser.get_node_data().to_double(); + camera.z_near = parser.get_node_data().to_float(); } else if (name == "zfar") { parser.read(); - camera.z_far = parser.get_node_data().to_double(); + camera.z_far = parser.get_node_data().to_float(); } } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "camera") { @@ -806,20 +806,20 @@ void Collada::_parse_light(XMLParser &parser) { } else if (name == "constant_attenuation") { parser.read(); - light.constant_att = parser.get_node_data().to_double(); + light.constant_att = parser.get_node_data().to_float(); } else if (name == "linear_attenuation") { parser.read(); - light.linear_att = parser.get_node_data().to_double(); + light.linear_att = parser.get_node_data().to_float(); } else if (name == "quadratic_attenuation") { parser.read(); - light.quad_att = parser.get_node_data().to_double(); + light.quad_att = parser.get_node_data().to_float(); } else if (name == "falloff_angle") { parser.read(); - light.spot_angle = parser.get_node_data().to_double(); + light.spot_angle = parser.get_node_data().to_float(); } else if (name == "falloff_exponent") { parser.read(); - light.spot_exp = parser.get_node_data().to_double(); + light.spot_exp = parser.get_node_data().to_float(); } } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "light") { @@ -1877,10 +1877,10 @@ void Collada::_parse_animation_clip(XMLParser &parser) { clip.name = parser.get_attribute_value("id"); } if (parser.has_attribute("start")) { - clip.begin = parser.get_attribute_value("start").to_double(); + clip.begin = parser.get_attribute_value("start").to_float(); } if (parser.has_attribute("end")) { - clip.end = parser.get_attribute_value("end").to_double(); + clip.end = parser.get_attribute_value("end").to_float(); } while (parser.read() == OK) { diff --git a/editor/input_map_editor.cpp b/editor/input_map_editor.cpp index 70c354e55a..52cf9c1869 100644 --- a/editor/input_map_editor.cpp +++ b/editor/input_map_editor.cpp @@ -36,44 +36,44 @@ #include "editor/editor_scale.h" static const char *_button_descriptions[JOY_SDL_BUTTONS] = { - "Face Bottom, DualShock Cross, Xbox A, Nintendo B", - "Face Right, DualShock Circle, Xbox B, Nintendo A", - "Face Left, DualShock Square, Xbox X, Nintendo Y", - "Face Top, DualShock Triangle, Xbox Y, Nintendo X", - "DualShock Select, Xbox Back, Nintendo -", - "Home, DualShock PS, Guide", - "Start, Nintendo +", - "Left Stick, DualShock L3, Xbox L/LS", - "Right Stick, DualShock R3, Xbox R/RS", - "Left Shoulder, DualShock L1, Xbox LB", - "Right Shoulder, DualShock R1, Xbox RB", - "D-Pad Up", - "D-Pad Down", - "D-Pad Left", - "D-Pad Right" + TTRC("Face Bottom, DualShock Cross, Xbox A, Nintendo B"), + TTRC("Face Right, DualShock Circle, Xbox B, Nintendo A"), + TTRC("Face Left, DualShock Square, Xbox X, Nintendo Y"), + TTRC("Face Top, DualShock Triangle, Xbox Y, Nintendo X"), + TTRC("DualShock Select, Xbox Back, Nintendo -"), + TTRC("Home, DualShock PS, Guide"), + TTRC("Start, Nintendo +"), + TTRC("Left Stick, DualShock L3, Xbox L/LS"), + TTRC("Right Stick, DualShock R3, Xbox R/RS"), + TTRC("Left Shoulder, DualShock L1, Xbox LB"), + TTRC("Right Shoulder, DualShock R1, Xbox RB"), + TTRC("D-Pad Up"), + TTRC("D-Pad Down"), + TTRC("D-Pad Left"), + TTRC("D-Pad Right") }; static const char *_axis_descriptions[JOY_AXIS_MAX * 2] = { - "Left Stick Left", - "Left Stick Right", - "Left Stick Up", - "Left Stick Down", - "Right Stick Left", - "Right Stick Right", - "Right Stick Up", - "Right Stick Down", - "Joystick 2 Left", - "Joystick 2 Right, Left Trigger, L2, LT", - "Joystick 2 Up", - "Joystick 2 Down, Right Trigger, R2, RT", - "Joystick 3 Left", - "Joystick 3 Right", - "Joystick 3 Up", - "Joystick 3 Down", - "Joystick 4 Left", - "Joystick 4 Right", - "Joystick 4 Up", - "Joystick 4 Down", + TTRC("Left Stick Left"), + TTRC("Left Stick Right"), + TTRC("Left Stick Up"), + TTRC("Left Stick Down"), + TTRC("Right Stick Left"), + TTRC("Right Stick Right"), + TTRC("Right Stick Up"), + TTRC("Right Stick Down"), + TTRC("Joystick 2 Left"), + TTRC("Joystick 2 Right, Left Trigger, L2, LT"), + TTRC("Joystick 2 Up"), + TTRC("Joystick 2 Down, Right Trigger, R2, RT"), + TTRC("Joystick 3 Left"), + TTRC("Joystick 3 Right"), + TTRC("Joystick 3 Up"), + TTRC("Joystick 3 Down"), + TTRC("Joystick 4 Left"), + TTRC("Joystick 4 Right"), + TTRC("Joystick 4 Up"), + TTRC("Joystick 4 Down"), }; void InputMapEditor::_notification(int p_what) { diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index e2f35e29d8..6e4a39d3f0 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -411,7 +411,7 @@ void AnimationPlayerEditor::_animation_remove() { String current = animation->get_item_text(animation->get_selected()); - delete_dialog->set_text(TTR("Delete Animation '" + current + "'?")); + delete_dialog->set_text(vformat(TTR("Delete Animation '%s'?"), current)); delete_dialog->popup_centered(); } @@ -744,7 +744,7 @@ void AnimationPlayerEditor::_dialog_action(String p_path) { } void AnimationPlayerEditor::_scale_changed(const String &p_scale) { - player->set_speed_scale(p_scale.to_double()); + player->set_speed_scale(p_scale.to_float()); } void AnimationPlayerEditor::_update_animation() { diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index ced0b9f984..b4b81cc7f0 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -4689,9 +4689,9 @@ void Node3DEditor::edit(Node3D *p_spatial) { } void Node3DEditor::_snap_changed() { - snap_translate_value = snap_translate->get_text().to_double(); - snap_rotate_value = snap_rotate->get_text().to_double(); - snap_scale_value = snap_scale->get_text().to_double(); + snap_translate_value = snap_translate->get_text().to_float(); + snap_rotate_value = snap_rotate->get_text().to_float(); + snap_scale_value = snap_scale->get_text().to_float(); } void Node3DEditor::_snap_update() { @@ -4708,9 +4708,9 @@ void Node3DEditor::_xform_dialog_action() { Vector3 translate; for (int i = 0; i < 3; i++) { - translate[i] = xform_translate[i]->get_text().to_double(); - rotate[i] = Math::deg2rad(xform_rotate[i]->get_text().to_double()); - scale[i] = xform_scale[i]->get_text().to_double(); + translate[i] = xform_translate[i]->get_text().to_float(); + rotate[i] = Math::deg2rad(xform_rotate[i]->get_text().to_float()); + scale[i] = xform_scale[i]->get_text().to_float(); } t.basis.scale(scale); @@ -5407,7 +5407,7 @@ void Node3DEditor::_update_gizmos_menu() { } String plugin_name = gizmo_plugins_by_name[i]->get_name(); const int plugin_state = gizmo_plugins_by_name[i]->get_state(); - gizmos_menu->add_multistate_item(TTR(plugin_name), 3, plugin_state, i); + gizmos_menu->add_multistate_item(plugin_name, 3, plugin_state, i); const int idx = gizmos_menu->get_item_index(i); gizmos_menu->set_item_tooltip( idx, @@ -6432,9 +6432,9 @@ Vector3 Node3DEditor::snap_point(Vector3 p_target, Vector3 p_start) const { float Node3DEditor::get_translate_snap() const { float snap_value; if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { - snap_value = snap_translate->get_text().to_double() / 10.0; + snap_value = snap_translate->get_text().to_float() / 10.0; } else { - snap_value = snap_translate->get_text().to_double(); + snap_value = snap_translate->get_text().to_float(); } return snap_value; @@ -6443,9 +6443,9 @@ float Node3DEditor::get_translate_snap() const { float Node3DEditor::get_rotate_snap() const { float snap_value; if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { - snap_value = snap_rotate->get_text().to_double() / 3.0; + snap_value = snap_rotate->get_text().to_float() / 3.0; } else { - snap_value = snap_rotate->get_text().to_double(); + snap_value = snap_rotate->get_text().to_float(); } return snap_value; @@ -6454,9 +6454,9 @@ float Node3DEditor::get_rotate_snap() const { float Node3DEditor::get_scale_snap() const { float snap_value; if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { - snap_value = snap_scale->get_text().to_double() / 2.0; + snap_value = snap_scale->get_text().to_float() / 2.0; } else { - snap_value = snap_scale->get_text().to_double(); + snap_value = snap_scale->get_text().to_float(); } return snap_value; diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 71830d0464..20eef1cebd 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -696,18 +696,21 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { Node *tselected = tab_container->get_child(selected); - ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected)); + ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tselected); if (current) { Ref<Script> script = current->get_edited_resource(); - if (p_save) { - // Do not try to save internal scripts - if (!script.is_valid() || !(script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1)) { + if (p_save && script.is_valid()) { + // Do not try to save internal scripts, but prompt to save in-memory + // scripts which are not saved to disk yet (have empty path). + if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) { _menu_option(FILE_SAVE); } } - - if (script != nullptr) { - previous_scripts.push_back(script->get_path()); + if (script.is_valid()) { + if (!script->get_path().empty()) { + // Only saved scripts can be restored. + previous_scripts.push_back(script->get_path()); + } notify_script_close(script); } } @@ -779,8 +782,10 @@ void ScriptEditor::_close_docs_tab() { void ScriptEditor::_copy_script_path() { ScriptEditorBase *se = _get_current_editor(); - RES script = se->get_edited_resource(); - DisplayServer::get_singleton()->clipboard_set(script->get_path()); + if (se) { + RES script = se->get_edited_resource(); + DisplayServer::get_singleton()->clipboard_set(script->get_path()); + } } void ScriptEditor::_close_other_tabs() { @@ -1038,17 +1043,19 @@ void ScriptEditor::_file_dialog_action(String p_file) { } break; case FILE_SAVE_AS: { ScriptEditorBase *current = _get_current_editor(); + if (current) { + RES resource = current->get_edited_resource(); + String path = ProjectSettings::get_singleton()->localize_path(p_file); + Error err = _save_text_file(resource, path); - String path = ProjectSettings::get_singleton()->localize_path(p_file); - Error err = _save_text_file(current->get_edited_resource(), path); + if (err != OK) { + editor->show_accept(TTR("Error saving file!"), TTR("OK")); + return; + } - if (err != OK) { - editor->show_accept(TTR("Error saving file!"), TTR("OK")); - return; + resource->set_path(path); + _update_script_names(); } - - ((Resource *)current->get_edited_resource().ptr())->set_path(path); - _update_script_names(); } break; case THEME_SAVE_AS: { if (!EditorSettings::get_singleton()->save_text_editor_theme_as(p_file)) { @@ -1240,13 +1247,14 @@ void ScriptEditor::_menu_option(int p_option) { } } - Ref<TextFile> text_file = current->get_edited_resource(); + RES resource = current->get_edited_resource(); + Ref<TextFile> text_file = resource; if (text_file != nullptr) { current->apply_code(); _save_text_file(text_file, text_file->get_path()); break; } - editor->save_resource(current->get_edited_resource()); + editor->save_resource(resource); } break; case FILE_SAVE_AS: { @@ -1264,7 +1272,8 @@ void ScriptEditor::_menu_option(int p_option) { } } - Ref<TextFile> text_file = current->get_edited_resource(); + RES resource = current->get_edited_resource(); + Ref<TextFile> text_file = resource; if (text_file != nullptr) { file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); @@ -1280,8 +1289,8 @@ void ScriptEditor::_menu_option(int p_option) { break; } - editor->push_item(Object::cast_to<Object>(current->get_edited_resource().ptr())); - editor->save_resource_as(current->get_edited_resource()); + editor->push_item(resource.ptr()); + editor->save_resource_as(resource); } break; @@ -1465,6 +1474,7 @@ void ScriptEditor::_notification(int p_what) { editor->connect("stop_pressed", callable_mp(this, &ScriptEditor::_editor_stop)); editor->connect("script_add_function_request", callable_mp(this, &ScriptEditor::_add_callback)); editor->connect("resource_saved", callable_mp(this, &ScriptEditor::_res_saved_callback)); + editor->get_filesystem_dock()->connect("file_removed", callable_mp(this, &ScriptEditor::_file_removed)); script_list->connect("item_selected", callable_mp(this, &ScriptEditor::_script_selected)); members_overview->connect("item_selected", callable_mp(this, &ScriptEditor::_members_overview_selected)); @@ -1472,6 +1482,7 @@ void ScriptEditor::_notification(int p_what) { script_split->connect("dragged", callable_mp(this, &ScriptEditor::_script_split_dragged)); EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &ScriptEditor::_editor_settings_changed)); + EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &ScriptEditor::_filesystem_changed)); [[fallthrough]]; } case NOTIFICATION_THEME_CHANGED: { @@ -1577,7 +1588,9 @@ void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) { List<int> bpoints; se->get_breakpoints(&bpoints); String base = script->get_path(); - ERR_CONTINUE(base.begins_with("local://") || base == ""); + if (base.begins_with("local://") || base == "") { + continue; + } for (List<int>::Element *E = bpoints.front(); E; E = E->next()) { p_breakpoints->push_back(base + ":" + itos(E->get() + 1)); @@ -1630,6 +1643,8 @@ void ScriptEditor::ensure_select_current() { if (tab_container->get_child_count() && tab_container->get_current_tab() >= 0) { ScriptEditorBase *se = _get_current_editor(); if (se) { + se->enable_editor(); + if (!grab_focus_block && is_visible_in_tree()) { se->ensure_focus(); } @@ -1840,6 +1855,12 @@ void ScriptEditor::_update_script_names() { if (se) { Ref<Texture2D> icon = se->get_theme_icon(); String path = se->get_edited_resource()->get_path(); + bool saved = !path.empty(); + if (saved) { + // The script might be deleted, moved, or renamed, so make sure + // to update original path to previously edited resource. + se->set_meta("_edit_res_path", path); + } bool built_in = !path.is_resource_file(); String name; @@ -1858,7 +1879,7 @@ void ScriptEditor::_update_script_names() { _ScriptEditorItemData sd; sd.icon = icon; sd.name = name; - sd.tooltip = path; + sd.tooltip = saved ? path : TTR("Unsaved file."); sd.index = i; sd.used = used.has(se->get_edited_resource()); sd.category = 0; @@ -1891,6 +1912,9 @@ void ScriptEditor::_update_script_names() { sd.name = path; } break; } + if (!saved) { + sd.name = se->get_name(); + } sedata.push_back(sd); } @@ -1898,14 +1922,18 @@ void ScriptEditor::_update_script_names() { Vector<String> disambiguated_script_names; Vector<String> full_script_paths; for (int j = 0; j < sedata.size(); j++) { - disambiguated_script_names.append(sedata[j].name); + disambiguated_script_names.append(sedata[j].name.replace("(*)", "")); full_script_paths.append(sedata[j].tooltip); } EditorNode::disambiguate_filenames(full_script_paths, disambiguated_script_names); for (int j = 0; j < sedata.size(); j++) { - sedata.write[j].name = disambiguated_script_names[j]; + if (sedata[j].name.ends_with("(*)")) { + sedata.write[j].name = disambiguated_script_names[j] + "(*)"; + } else { + sedata.write[j].name = disambiguated_script_names[j]; + } } EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i)); @@ -1974,6 +2002,11 @@ void ScriptEditor::_update_script_names() { script_list->select(index); script_name_label->set_text(sedata_filtered[i].name); script_icon->set_texture(sedata_filtered[i].icon); + ScriptEditorBase *se = _get_current_editor(); + if (se) { + se->enable_editor(); + _update_selected_editor_menu(); + } } } @@ -2062,15 +2095,15 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra Ref<Script> script = p_resource; - // refuse to open built-in if scene is not loaded - - // see if already has it + // Don't open dominant script if using an external editor. + const bool use_external_editor = + EditorSettings::get_singleton()->get("text_editor/external/use_external_editor") || + (script.is_valid() && script->get_language()->overrides_external_editor()); + const bool open_dominant = EditorSettings::get_singleton()->get("text_editor/files/open_dominant_script_on_scene_change"); - bool open_dominant = EditorSettings::get_singleton()->get("text_editor/files/open_dominant_script_on_scene_change"); + const bool should_open = (open_dominant && !use_external_editor) || !EditorNode::get_singleton()->is_changing_scene(); - const bool should_open = open_dominant || !EditorNode::get_singleton()->is_changing_scene(); - - if (script != nullptr && script->get_language()->overrides_external_editor()) { + if (script.is_valid() && script->get_language()->overrides_external_editor()) { if (should_open) { Error err = script->get_language()->open_in_external_editor(script, p_line >= 0 ? p_line : 0, p_col); if (err != OK) { @@ -2080,10 +2113,10 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra return false; } - if ((EditorDebuggerNode::get_singleton()->get_dump_stack_script() != p_resource || EditorDebuggerNode::get_singleton()->get_debug_with_external_editor()) && + if (use_external_editor && + (EditorDebuggerNode::get_singleton()->get_dump_stack_script() != p_resource || EditorDebuggerNode::get_singleton()->get_debug_with_external_editor()) && p_resource->get_path().is_resource_file() && - p_resource->get_class_name() != StringName("VisualScript") && - bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) { + p_resource->get_class_name() != StringName("VisualScript")) { String path = EditorSettings::get_singleton()->get("text_editor/external/exec_path"); String flags = EditorSettings::get_singleton()->get("text_editor/external/exec_flags"); @@ -2148,6 +2181,8 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra if ((script != nullptr && se->get_edited_resource() == p_resource) || se->get_edited_resource()->get_path() == p_resource->get_path()) { if (should_open) { + se->enable_editor(); + if (tab_container->get_current_tab() != i) { _go_to_tab(i); _update_script_names(); @@ -2178,6 +2213,8 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra } ERR_FAIL_COND_V(!se, false); + se->set_edited_resource(p_resource); + if (p_resource->get_class_name() != StringName("VisualScript")) { bool highlighter_set = false; for (int i = 0; i < syntax_highlighters.size(); i++) { @@ -2198,7 +2235,14 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra } tab_container->add_child(se); - se->set_edited_resource(p_resource); + + if (p_grab_focus) { + se->enable_editor(); + } + + // If we delete a script within the filesystem, the original resource path + // is lost, so keep it as metadata to figure out the exact tab to delete. + se->set_meta("_edit_res_path", p_resource->get_path()); se->set_tooltip_request_func("_get_debug_tooltip", this); if (se->get_edit_menu()) { se->get_edit_menu()->hide(); @@ -2208,6 +2252,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra if (p_grab_focus) { _go_to_tab(tab_container->get_tab_count() - 1); + _add_recent_script(p_resource->get_path()); } _sort_list_on_update = true; @@ -2232,7 +2277,6 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra } notify_script_changed(p_resource); - _add_recent_script(p_resource->get_path()); return true; } @@ -2373,6 +2417,23 @@ void ScriptEditor::_editor_settings_changed() { ScriptServer::set_reload_scripts_on_save(EDITOR_DEF("text_editor/files/auto_reload_and_parse_scripts_on_save", true)); } +void ScriptEditor::_filesystem_changed() { + _update_script_names(); +} + +void ScriptEditor::_file_removed(const String &p_removed_file) { + for (int i = 0; i < tab_container->get_child_count(); i++) { + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); + if (!se) { + continue; + } + if (se->get_meta("_edit_res_path") == p_removed_file) { + // The script is deleted with no undo, so just close the tab. + _close_tab(i, false, false); + } + } +} + void ScriptEditor::_autosave_scripts() { save_all_scripts(); } @@ -2704,7 +2765,7 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { if (!scr.is_valid()) { continue; } - if (!edit(scr)) { + if (!edit(scr, false)) { continue; } } else { @@ -2713,7 +2774,7 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { if (error != OK || !text_file.is_valid()) { continue; } - if (!edit(text_file)) { + if (!edit(text_file, false)) { continue; } } @@ -2945,13 +3006,13 @@ Array ScriptEditor::_get_open_script_editors() const { } 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"); - - if (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) { - return; - } + // Don't open dominant script if using an external editor. + const bool use_external_editor = + EditorSettings::get_singleton()->get("text_editor/external/use_external_editor") || + (p_script.is_valid() && p_script->get_language()->overrides_external_editor()); + const bool open_dominant = EditorSettings::get_singleton()->get("text_editor/files/open_dominant_script_on_scene_change"); - if (open_dominant && p_script.is_valid()) { + if (open_dominant && !use_external_editor && p_script.is_valid()) { edit(p_script); } } diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 3891af4091..1234ebd267 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -134,6 +134,7 @@ public: virtual RES get_edited_resource() const = 0; virtual Vector<String> get_functions() = 0; virtual void set_edited_resource(const RES &p_res) = 0; + virtual void enable_editor() = 0; virtual void reload_text() = 0; virtual String get_name() = 0; virtual Ref<Texture2D> get_theme_icon() = 0; @@ -370,6 +371,8 @@ class ScriptEditor : public PanelContainer { void _save_layout(); void _editor_settings_changed(); + void _filesystem_changed(); + void _file_removed(const String &p_file); void _autosave_scripts(); void _update_autosave_timer(); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index f4fdf8ccb0..4b89ca1216 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -140,10 +140,10 @@ RES ScriptTextEditor::get_edited_resource() const { } void ScriptTextEditor::set_edited_resource(const RES &p_res) { - ERR_FAIL_COND(!script.is_null()); + ERR_FAIL_COND(script.is_valid()); + ERR_FAIL_COND(p_res.is_null()); script = p_res; - _set_theme_for_script(); code_editor->get_text_edit()->set_text(script->get_source_code()); code_editor->get_text_edit()->clear_undo_history(); @@ -151,6 +151,17 @@ void ScriptTextEditor::set_edited_resource(const RES &p_res) { emit_signal("name_changed"); code_editor->update_line_and_column(); +} + +void ScriptTextEditor::enable_editor() { + if (editor_enabled) { + return; + } + + editor_enabled = true; + + _enable_code_editor(); + _set_theme_for_script(); _validate_script(); } @@ -301,14 +312,6 @@ void ScriptTextEditor::reload_text() { code_editor->update_line_and_column(); } -void ScriptTextEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_READY: - _load_theme_settings(); - break; - } -} - void ScriptTextEditor::add_callback(const String &p_function, PackedStringArray p_args) { String code = code_editor->get_text_edit()->get_text(); int pos = script->get_language()->find_function(p_function, code); @@ -335,7 +338,10 @@ void ScriptTextEditor::update_settings() { } bool ScriptTextEditor::is_unsaved() { - return code_editor->get_text_edit()->get_version() != code_editor->get_text_edit()->get_saved_version(); + const bool unsaved = + code_editor->get_text_edit()->get_version() != code_editor->get_text_edit()->get_saved_version() || + script->get_path().empty(); // In memory. + return unsaved; } Variant ScriptTextEditor::get_edit_state() { @@ -352,6 +358,10 @@ void ScriptTextEditor::set_edit_state(const Variant &p_state) { _change_syntax_highlighter(idx); } } + + if (editor_enabled) { + ensure_focus(); + } } void ScriptTextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) { @@ -408,6 +418,9 @@ String ScriptTextEditor::get_name() { if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) { name = script->get_path().get_file(); if (is_unsaved()) { + if (script->get_path().empty()) { + name = TTR("[unsaved]"); + } name += "(*)"; } } else if (script->get_name() != "") { @@ -1274,23 +1287,28 @@ void ScriptTextEditor::_edit_option_toggle_inline_comment() { } void ScriptTextEditor::add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { + ERR_FAIL_COND(p_highlighter.is_null()); + highlighters[p_highlighter->_get_name()] = p_highlighter; highlighter_menu->add_radio_check_item(p_highlighter->_get_name()); } void ScriptTextEditor::set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { + ERR_FAIL_COND(p_highlighter.is_null()); + + Map<String, Ref<EditorSyntaxHighlighter>>::Element *el = highlighters.front(); + while (el != nullptr) { + int highlighter_index = highlighter_menu->get_item_idx_from_text(el->key()); + highlighter_menu->set_item_checked(highlighter_index, el->value() == p_highlighter); + el = el->next(); + } + TextEdit *te = code_editor->get_text_edit(); p_highlighter->_set_edited_resource(script); te->set_syntax_highlighter(p_highlighter); - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(p_highlighter->_get_name()), true); } void ScriptTextEditor::_change_syntax_highlighter(int p_idx) { - Map<String, Ref<EditorSyntaxHighlighter>>::Element *el = highlighters.front(); - while (el != nullptr) { - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(el->key()), false); - el = el->next(); - } set_syntax_highlighter(highlighters[highlighter_menu->get_item_text(p_idx)]); } @@ -1606,64 +1624,41 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p context_menu->popup(); } -ScriptTextEditor::ScriptTextEditor() { - theme_loaded = false; - script_is_valid = false; +void ScriptTextEditor::_enable_code_editor() { + ERR_FAIL_COND(code_editor->get_parent()); VSplitContainer *editor_box = memnew(VSplitContainer); add_child(editor_box); editor_box->set_anchors_and_margins_preset(Control::PRESET_WIDE); editor_box->set_v_size_flags(SIZE_EXPAND_FILL); - code_editor = memnew(CodeTextEditor); editor_box->add_child(code_editor); - code_editor->add_theme_constant_override("separation", 2); - code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); + code_editor->connect("show_warnings_panel", callable_mp(this, &ScriptTextEditor::_show_warnings_panel)); code_editor->connect("validate_script", callable_mp(this, &ScriptTextEditor::_validate_script)); code_editor->connect("load_theme_settings", callable_mp(this, &ScriptTextEditor::_load_theme_settings)); - code_editor->set_code_complete_func(_code_complete_scripts, this); code_editor->get_text_edit()->connect("breakpoint_toggled", callable_mp(this, &ScriptTextEditor::_breakpoint_toggled)); code_editor->get_text_edit()->connect("symbol_lookup", callable_mp(this, &ScriptTextEditor::_lookup_symbol)); code_editor->get_text_edit()->connect("symbol_validate", callable_mp(this, &ScriptTextEditor::_validate_symbol)); code_editor->get_text_edit()->connect("info_clicked", callable_mp(this, &ScriptTextEditor::_lookup_connections)); - code_editor->set_v_size_flags(SIZE_EXPAND_FILL); + code_editor->get_text_edit()->connect("gui_input", callable_mp(this, &ScriptTextEditor::_text_edit_gui_input)); code_editor->show_toggle_scripts_button(); - warnings_panel = memnew(RichTextLabel); editor_box->add_child(warnings_panel); warnings_panel->add_theme_font_override( "normal_font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("main", "EditorFonts")); - warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); - warnings_panel->set_h_size_flags(SIZE_EXPAND_FILL); - warnings_panel->set_meta_underline(true); - warnings_panel->set_selection_enabled(true); - warnings_panel->set_focus_mode(FOCUS_CLICK); - warnings_panel->hide(); - - code_editor->connect("show_warnings_panel", callable_mp(this, &ScriptTextEditor::_show_warnings_panel)); warnings_panel->connect("meta_clicked", callable_mp(this, &ScriptTextEditor::_warning_clicked)); - update_settings(); - - code_editor->get_text_edit()->set_callhint_settings( - EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"), - EditorSettings::get_singleton()->get("text_editor/completion/callhint_tooltip_offset")); - - code_editor->get_text_edit()->set_select_identifiers_on_hover(true); - code_editor->get_text_edit()->set_context_menu_enabled(false); - code_editor->get_text_edit()->connect("gui_input", callable_mp(this, &ScriptTextEditor::_text_edit_gui_input)); - - context_menu = memnew(PopupMenu); add_child(context_menu); context_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); - color_panel = memnew(PopupPanel); add_child(color_panel); + color_picker = memnew(ColorPicker); color_picker->set_deferred_mode(true); - color_panel->add_child(color_picker); color_picker->connect("color_changed", callable_mp(this, &ScriptTextEditor::_color_changed)); + color_panel->add_child(color_picker); + // get default color picker mode from editor settings int default_color_mode = EDITOR_GET("interface/inspector/default_color_picker_mode"); if (default_color_mode == 1) { @@ -1672,12 +1667,27 @@ ScriptTextEditor::ScriptTextEditor() { color_picker->set_raw_mode(true); } - edit_hb = memnew(HBoxContainer); + quick_open = memnew(ScriptEditorQuickOpen); + quick_open->connect("goto_line", callable_mp(this, &ScriptTextEditor::_goto_line)); + add_child(quick_open); - edit_menu = memnew(MenuButton); - edit_menu->set_text(TTR("Edit")); - edit_menu->set_switch_on_hover(true); + goto_line_dialog = memnew(GotoLineDialog); + add_child(goto_line_dialog); + + add_child(connection_info_dialog); + edit_hb->add_child(search_menu); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); + search_menu->get_popup()->add_separator(); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES); + search_menu->get_popup()->add_separator(); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL); + search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); + + edit_hb->add_child(edit_menu); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); edit_menu->get_popup()->add_separator(); @@ -1707,8 +1717,6 @@ ScriptTextEditor::ScriptTextEditor() { edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); edit_menu->get_popup()->add_separator(); - PopupMenu *convert_case = memnew(PopupMenu); - convert_case->set_name("convert_case"); edit_menu->get_popup()->add_child(convert_case); edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "convert_case"); convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KEY_MASK_SHIFT | KEY_F4), EDIT_TO_UPPERCASE); @@ -1716,12 +1724,73 @@ ScriptTextEditor::ScriptTextEditor() { convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KEY_MASK_SHIFT | KEY_F6), EDIT_CAPITALIZE); convert_case->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); - highlighter_menu = memnew(PopupMenu); - highlighter_menu->set_name("highlighter_menu"); edit_menu->get_popup()->add_child(highlighter_menu); edit_menu->get_popup()->add_submenu_item(TTR("Syntax Highlighter"), "highlighter_menu"); highlighter_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_change_syntax_highlighter)); + _load_theme_settings(); + + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES); + edit_hb->add_child(goto_menu); + goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_function"), SEARCH_LOCATE_FUNCTION); + goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); + goto_menu->get_popup()->add_separator(); + + goto_menu->get_popup()->add_child(bookmarks_menu); + goto_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "Bookmarks"); + _update_bookmark_list(); + bookmarks_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_update_bookmark_list)); + bookmarks_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_bookmark_item_pressed)); + + goto_menu->get_popup()->add_child(breakpoints_menu); + goto_menu->get_popup()->add_submenu_item(TTR("Breakpoints"), "Breakpoints"); + _update_breakpoint_list(); + breakpoints_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_update_breakpoint_list)); + breakpoints_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_breakpoint_item_pressed)); + + goto_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); +} + +ScriptTextEditor::ScriptTextEditor() { + code_editor = memnew(CodeTextEditor); + code_editor->add_theme_constant_override("separation", 2); + code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); + code_editor->set_code_complete_func(_code_complete_scripts, this); + code_editor->set_v_size_flags(SIZE_EXPAND_FILL); + + warnings_panel = memnew(RichTextLabel); + warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); + warnings_panel->set_h_size_flags(SIZE_EXPAND_FILL); + warnings_panel->set_meta_underline(true); + warnings_panel->set_selection_enabled(true); + warnings_panel->set_focus_mode(FOCUS_CLICK); + warnings_panel->hide(); + + update_settings(); + + code_editor->get_text_edit()->set_callhint_settings( + EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"), + EditorSettings::get_singleton()->get("text_editor/completion/callhint_tooltip_offset")); + + code_editor->get_text_edit()->set_select_identifiers_on_hover(true); + code_editor->get_text_edit()->set_context_menu_enabled(false); + + context_menu = memnew(PopupMenu); + + color_panel = memnew(PopupPanel); + + edit_hb = memnew(HBoxContainer); + + edit_menu = memnew(MenuButton); + edit_menu->set_text(TTR("Edit")); + edit_menu->set_switch_on_hover(true); + + convert_case = memnew(PopupMenu); + convert_case->set_name("convert_case"); + + highlighter_menu = memnew(PopupMenu); + highlighter_menu->set_name("highlighter_menu"); + Ref<EditorPlainTextSyntaxHighlighter> plain_highlighter; plain_highlighter.instance(); add_syntax_highlighter(plain_highlighter); @@ -1732,64 +1801,42 @@ ScriptTextEditor::ScriptTextEditor() { set_syntax_highlighter(highlighter); search_menu = memnew(MenuButton); - edit_hb->add_child(search_menu); search_menu->set_text(TTR("Search")); search_menu->set_switch_on_hover(true); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); - search_menu->get_popup()->add_separator(); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES); - search_menu->get_popup()->add_separator(); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL); - search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); - - edit_hb->add_child(edit_menu); - - MenuButton *goto_menu = memnew(MenuButton); - edit_hb->add_child(goto_menu); + goto_menu = memnew(MenuButton); goto_menu->set_text(TTR("Go To")); goto_menu->set_switch_on_hover(true); - goto_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); - - goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_function"), SEARCH_LOCATE_FUNCTION); - goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); - goto_menu->get_popup()->add_separator(); bookmarks_menu = memnew(PopupMenu); bookmarks_menu->set_name("Bookmarks"); - goto_menu->get_popup()->add_child(bookmarks_menu); - goto_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "Bookmarks"); - _update_bookmark_list(); - bookmarks_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_update_bookmark_list)); - bookmarks_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_bookmark_item_pressed)); breakpoints_menu = memnew(PopupMenu); breakpoints_menu->set_name("Breakpoints"); - goto_menu->get_popup()->add_child(breakpoints_menu); - goto_menu->get_popup()->add_submenu_item(TTR("Breakpoints"), "Breakpoints"); - _update_breakpoint_list(); - breakpoints_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_update_breakpoint_list)); - breakpoints_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_breakpoint_item_pressed)); - - quick_open = memnew(ScriptEditorQuickOpen); - add_child(quick_open); - quick_open->connect("goto_line", callable_mp(this, &ScriptTextEditor::_goto_line)); - - goto_line_dialog = memnew(GotoLineDialog); - add_child(goto_line_dialog); connection_info_dialog = memnew(ConnectionInfoDialog); - add_child(connection_info_dialog); code_editor->get_text_edit()->set_drag_forwarding(this); } ScriptTextEditor::~ScriptTextEditor() { highlighters.clear(); + + if (!editor_enabled) { + memdelete(code_editor); + memdelete(warnings_panel); + memdelete(context_menu); + memdelete(color_panel); + memdelete(edit_hb); + memdelete(edit_menu); + memdelete(convert_case); + memdelete(highlighter_menu); + memdelete(search_menu); + memdelete(goto_menu); + memdelete(bookmarks_menu); + memdelete(breakpoints_menu); + memdelete(connection_info_dialog); + } } static ScriptEditorBase *create_editor(const RES &p_resource) { diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 6d7f84d746..e931c9fdc6 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -39,8 +39,8 @@ class ConnectionInfoDialog : public AcceptDialog { GDCLASS(ConnectionInfoDialog, AcceptDialog); - Label *method; - Tree *tree; + Label *method = nullptr; + Tree *tree = nullptr; virtual void ok_pressed() override; @@ -53,11 +53,12 @@ public: class ScriptTextEditor : public ScriptEditorBase { GDCLASS(ScriptTextEditor, ScriptEditorBase); - CodeTextEditor *code_editor; - RichTextLabel *warnings_panel; + CodeTextEditor *code_editor = nullptr; + RichTextLabel *warnings_panel = nullptr; Ref<Script> script; - bool script_is_valid; + bool script_is_valid = false; + bool editor_enabled = false; Vector<String> functions; @@ -65,25 +66,27 @@ class ScriptTextEditor : public ScriptEditorBase { Vector<String> member_keywords; - HBoxContainer *edit_hb; + HBoxContainer *edit_hb = nullptr; - MenuButton *edit_menu; - MenuButton *search_menu; - PopupMenu *bookmarks_menu; - PopupMenu *breakpoints_menu; - PopupMenu *highlighter_menu; - PopupMenu *context_menu; + MenuButton *edit_menu = nullptr; + MenuButton *search_menu = nullptr; + MenuButton *goto_menu = nullptr; + PopupMenu *bookmarks_menu = nullptr; + PopupMenu *breakpoints_menu = nullptr; + PopupMenu *highlighter_menu = nullptr; + PopupMenu *context_menu = nullptr; + PopupMenu *convert_case = nullptr; - GotoLineDialog *goto_line_dialog; - ScriptEditorQuickOpen *quick_open; - ConnectionInfoDialog *connection_info_dialog; + GotoLineDialog *goto_line_dialog = nullptr; + ScriptEditorQuickOpen *quick_open = nullptr; + ConnectionInfoDialog *connection_info_dialog = nullptr; - PopupPanel *color_panel; - ColorPicker *color_picker; + PopupPanel *color_panel = nullptr; + ColorPicker *color_picker = nullptr; Vector2 color_position; String color_args; - bool theme_loaded; + bool theme_loaded = false; enum { EDIT_UNDO, @@ -132,6 +135,8 @@ class ScriptTextEditor : public ScriptEditorBase { LOOKUP_SYMBOL, }; + void _enable_code_editor(); + protected: void _update_breakpoint_list(); void _breakpoint_item_pressed(int p_idx); @@ -149,7 +154,6 @@ protected: void _show_warnings_panel(bool p_show); void _warning_clicked(Variant p_line); - void _notification(int p_what); static void _bind_methods(); Map<String, Ref<EditorSyntaxHighlighter>> highlighters; @@ -185,6 +189,7 @@ public: virtual void apply_code() override; virtual RES get_edited_resource() const override; virtual void set_edited_resource(const RES &p_res) override; + virtual void enable_editor() override; virtual Vector<String> get_functions() override; virtual void reload_text() override; virtual String get_name() override; diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 60ba3802fb..2a7f3f0656 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -136,32 +136,43 @@ void ShaderTextEditor::_load_theme_settings() { syntax_highlighter->set_function_color(EDITOR_GET("text_editor/highlighting/function_color")); syntax_highlighter->set_member_variable_color(EDITOR_GET("text_editor/highlighting/member_variable_color")); + syntax_highlighter->clear_keyword_colors(); + List<String> keywords; ShaderLanguage::get_keyword_list(&keywords); + const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); + + for (List<String>::Element *E = keywords.front(); E; E = E->next()) { + syntax_highlighter->add_keyword_color(E->get(), keyword_color); + } + // Colorize built-ins like `COLOR` differently to make them easier + // to distinguish from keywords at a quick glance. + + List<String> built_ins; if (shader.is_valid()) { for (const Map<StringName, ShaderLanguage::FunctionInfo>::Element *E = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())).front(); E; E = E->next()) { for (const Map<StringName, ShaderLanguage::BuiltInInfo>::Element *F = E->get().built_ins.front(); F; F = F->next()) { - keywords.push_back(F->key()); + built_ins.push_back(F->key()); } } for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())).size(); i++) { - keywords.push_back(ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()))[i]); + built_ins.push_back(ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()))[i]); } } - const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); - syntax_highlighter->clear_keyword_colors(); - for (List<String>::Element *E = keywords.front(); E; E = E->next()) { - syntax_highlighter->add_keyword_color(E->get(), keyword_color); + const Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); + + for (List<String>::Element *E = built_ins.front(); E; E = E->next()) { + syntax_highlighter->add_keyword_color(E->get(), member_variable_color); } - //colorize comments + // Colorize comments. const Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); syntax_highlighter->clear_color_regions(); syntax_highlighter->add_color_region("/*", "*/", comment_color, false); - syntax_highlighter->add_color_region("//", "", comment_color, false); + syntax_highlighter->add_color_region("//", "", comment_color, true); } void ShaderTextEditor::_check_shader_mode() { diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 516c14329c..1073da7d8c 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -458,7 +458,7 @@ void SpriteFramesEditor::_animation_select() { } if (frames->has_animation(edited_anim)) { - double value = anim_speed->get_line_edit()->get_text().to_double(); + double value = anim_speed->get_line_edit()->get_text().to_float(); if (!Math::is_equal_approx(value, frames->get_animation_speed(edited_anim))) { _animation_fps_changed(value); } diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index d602d152fe..82e231e396 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -34,22 +34,27 @@ #include "editor/editor_node.h" void TextEditor::add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { + ERR_FAIL_COND(p_highlighter.is_null()); + highlighters[p_highlighter->_get_name()] = p_highlighter; highlighter_menu->add_radio_check_item(p_highlighter->_get_name()); } void TextEditor::set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { - TextEdit *te = code_editor->get_text_edit(); - te->set_syntax_highlighter(p_highlighter); - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(p_highlighter->_get_name()), true); -} + ERR_FAIL_COND(p_highlighter.is_null()); -void TextEditor::_change_syntax_highlighter(int p_idx) { Map<String, Ref<EditorSyntaxHighlighter>>::Element *el = highlighters.front(); while (el != nullptr) { - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(el->key()), false); + int highlighter_index = highlighter_menu->get_item_idx_from_text(el->key()); + highlighter_menu->set_item_checked(highlighter_index, el->value() == p_highlighter); el = el->next(); } + + TextEdit *te = code_editor->get_text_edit(); + te->set_syntax_highlighter(p_highlighter); +} + +void TextEditor::_change_syntax_highlighter(int p_idx) { set_syntax_highlighter(highlighters[highlighter_menu->get_item_text(p_idx)]); } @@ -114,6 +119,9 @@ String TextEditor::get_name() { if (text_file->get_path().find("local://") == -1 && text_file->get_path().find("::") == -1) { name = text_file->get_path().get_file(); if (is_unsaved()) { + if (text_file->get_path().empty()) { + name = TTR("[unsaved]"); + } name += "(*)"; } } else if (text_file->get_name() != "") { @@ -126,7 +134,7 @@ String TextEditor::get_name() { } Ref<Texture2D> TextEditor::get_theme_icon() { - return EditorNode::get_singleton()->get_object_icon(text_file.operator->(), ""); + return EditorNode::get_singleton()->get_object_icon(text_file.ptr(), ""); } RES TextEditor::get_edited_resource() const { @@ -134,7 +142,8 @@ RES TextEditor::get_edited_resource() const { } void TextEditor::set_edited_resource(const RES &p_res) { - ERR_FAIL_COND(!text_file.is_null()); + ERR_FAIL_COND(text_file.is_valid()); + ERR_FAIL_COND(p_res.is_null()); text_file = p_res; @@ -146,6 +155,16 @@ void TextEditor::set_edited_resource(const RES &p_res) { code_editor->update_line_and_column(); } +void TextEditor::enable_editor() { + if (editor_enabled) { + return; + } + + editor_enabled = true; + + _load_theme_settings(); +} + void TextEditor::add_callback(const String &p_function, PackedStringArray p_args) { } @@ -220,7 +239,10 @@ void TextEditor::apply_code() { } bool TextEditor::is_unsaved() { - return code_editor->get_text_edit()->get_version() != code_editor->get_text_edit()->get_saved_version(); + const bool unsaved = + code_editor->get_text_edit()->get_version() != code_editor->get_text_edit()->get_saved_version() || + text_file->get_path().empty(); // In memory. + return unsaved; } Variant TextEditor::get_edit_state() { @@ -237,6 +259,8 @@ void TextEditor::set_edit_state(const Variant &p_state) { _change_syntax_highlighter(idx); } } + + ensure_focus(); } void TextEditor::trim_trailing_whitespace() { @@ -303,14 +327,6 @@ void TextEditor::clear_edit_menu() { memdelete(edit_hb); } -void TextEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_READY: - _load_theme_settings(); - break; - } -} - void TextEditor::_edit_option(int p_op) { TextEdit *tx = code_editor->get_text_edit(); diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 5299776b56..f3e9e599cf 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -37,18 +37,19 @@ class TextEditor : public ScriptEditorBase { GDCLASS(TextEditor, ScriptEditorBase); private: - CodeTextEditor *code_editor; + CodeTextEditor *code_editor = nullptr; Ref<TextFile> text_file; + bool editor_enabled = false; - HBoxContainer *edit_hb; - MenuButton *edit_menu; - PopupMenu *highlighter_menu; - MenuButton *search_menu; - PopupMenu *bookmarks_menu; - PopupMenu *context_menu; + HBoxContainer *edit_hb = nullptr; + MenuButton *edit_menu = nullptr; + PopupMenu *highlighter_menu = nullptr; + MenuButton *search_menu = nullptr; + PopupMenu *bookmarks_menu = nullptr; + PopupMenu *context_menu = nullptr; - GotoLineDialog *goto_line_dialog; + GotoLineDialog *goto_line_dialog = nullptr; enum { EDIT_UNDO, @@ -88,8 +89,6 @@ private: protected: static void _bind_methods(); - void _notification(int p_what); - void _edit_option(int p_op); void _make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded, Vector2 p_position); void _text_edit_gui_input(const Ref<InputEvent> &ev); @@ -113,7 +112,7 @@ public: virtual Ref<Texture2D> get_theme_icon() override; virtual RES get_edited_resource() const override; virtual void set_edited_resource(const RES &p_res) override; - void set_edited_file(const Ref<TextFile> &p_file); + virtual void enable_editor() override; virtual void reload_text() override; virtual void apply_code() override; virtual bool is_unsaved() override; diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 7fb751e3ed..a613174ed9 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -698,7 +698,7 @@ void TileSetEditor::_on_tileset_toolbar_confirm() { List<int> ids; tileset->get_tile_list(&ids); - undo_redo->create_action(TTR(option == TOOL_TILESET_MERGE_SCENE ? "Merge Tileset from Scene" : "Create Tileset from Scene")); + undo_redo->create_action(option == TOOL_TILESET_MERGE_SCENE ? TTR("Merge Tileset from Scene") : TTR("Create Tileset from Scene")); undo_redo->add_do_method(this, "_undo_redo_import_scene", scene, option == TOOL_TILESET_MERGE_SCENE); undo_redo->add_undo_method(tileset.ptr(), "clear"); for (List<int>::Element *E = ids.front(); E; E = E->next()) { diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index d987f6f7c0..53bd1150ec 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -489,6 +489,45 @@ void VisualShaderEditor::_update_graph() { Vector<int> nodes = visual_shader->get_node_list(type); + VisualShaderNodeUniformRef::clear_uniforms(); + + // scan for all uniforms + + for (int t = 0; t < VisualShader::TYPE_MAX; t++) { + Vector<int> tnodes = visual_shader->get_node_list((VisualShader::Type)t); + for (int i = 0; i < tnodes.size(); i++) { + Ref<VisualShaderNode> vsnode = visual_shader->get_node((VisualShader::Type)t, tnodes[i]); + Ref<VisualShaderNodeUniform> uniform = vsnode; + + if (uniform.is_valid()) { + Ref<VisualShaderNodeFloatUniform> float_uniform = vsnode; + Ref<VisualShaderNodeIntUniform> int_uniform = vsnode; + Ref<VisualShaderNodeVec3Uniform> vec3_uniform = vsnode; + Ref<VisualShaderNodeColorUniform> color_uniform = vsnode; + Ref<VisualShaderNodeBooleanUniform> bool_uniform = vsnode; + Ref<VisualShaderNodeTransformUniform> transform_uniform = vsnode; + + VisualShaderNodeUniformRef::UniformType uniform_type; + if (float_uniform.is_valid()) { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_FLOAT; + } else if (int_uniform.is_valid()) { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_INT; + } else if (bool_uniform.is_valid()) { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_BOOLEAN; + } else if (vec3_uniform.is_valid()) { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_VECTOR; + } else if (transform_uniform.is_valid()) { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_TRANSFORM; + } else if (color_uniform.is_valid()) { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_COLOR; + } else { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_SAMPLER; + } + VisualShaderNodeUniformRef::add_uniform(uniform->get_uniform_name(), uniform_type); + } + } + } + Control *offset; for (int n_i = 0; n_i < nodes.size(); n_i++) { @@ -834,6 +873,9 @@ void VisualShaderEditor::_update_graph() { Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); + Color function_color = EDITOR_GET("text_editor/highlighting/function_color"); + Color number_color = EDITOR_GET("text_editor/highlighting/number_color"); + Color members_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); expression_box->set_syntax_highlighter(expression_syntax_highlighter); expression_box->add_theme_color_override("background_color", background_color); @@ -844,9 +886,12 @@ void VisualShaderEditor::_update_graph() { expression_box->add_theme_font_override("font", get_theme_font("expression", "EditorFonts")); expression_box->add_theme_color_override("font_color", text_color); + expression_syntax_highlighter->set_number_color(number_color); expression_syntax_highlighter->set_symbol_color(symbol_color); + expression_syntax_highlighter->set_function_color(function_color); + expression_syntax_highlighter->set_member_variable_color(members_color); expression_syntax_highlighter->add_color_region("/*", "*/", comment_color, false); - expression_syntax_highlighter->add_color_region("//", "", comment_color, false); + expression_syntax_highlighter->add_color_region("//", "", comment_color, true); expression_box->set_text(expression); expression_box->set_context_menu_enabled(false); @@ -1701,6 +1746,9 @@ void VisualShaderEditor::_notification(int p_what) { Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); + Color function_color = EDITOR_GET("text_editor/highlighting/function_color"); + Color number_color = EDITOR_GET("text_editor/highlighting/number_color"); + Color members_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); preview_text->add_theme_color_override("background_color", background_color); @@ -1710,10 +1758,13 @@ void VisualShaderEditor::_notification(int p_what) { preview_text->add_theme_font_override("font", get_theme_font("expression", "EditorFonts")); preview_text->add_theme_color_override("font_color", text_color); + syntax_highlighter->set_number_color(number_color); syntax_highlighter->set_symbol_color(symbol_color); + syntax_highlighter->set_function_color(function_color); + syntax_highlighter->set_member_variable_color(members_color); syntax_highlighter->clear_color_regions(); syntax_highlighter->add_color_region("/*", "*/", comment_color, false); - syntax_highlighter->add_color_region("//", "", comment_color, false); + syntax_highlighter->add_color_region("//", "", comment_color, true); error_text->add_theme_font_override("font", get_theme_font("status_source", "EditorFonts")); error_text->add_theme_color_override("font_color", get_theme_color("error_color", "Editor")); @@ -2035,6 +2086,41 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> input, St undo_redo->commit_action(); } +void VisualShaderEditor::_uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform_ref, String p_name) { + String prev_name = p_uniform_ref->get_uniform_name(); + + if (p_name == prev_name) { + return; + } + + bool type_changed = p_uniform_ref->get_uniform_type_by_name(p_name) != p_uniform_ref->get_uniform_type_by_name(prev_name); + + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo->create_action(TTR("UniformRef Name Changed")); + + undo_redo->add_do_method(p_uniform_ref.ptr(), "set_uniform_name", p_name); + undo_redo->add_undo_method(p_uniform_ref.ptr(), "set_uniform_name", prev_name); + + if (type_changed) { + //restore connections if type changed + VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + int id = visual_shader->find_node_id(type, p_uniform_ref); + List<VisualShader::Connection> conns; + visual_shader->get_node_connections(type, &conns); + for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { + if (E->get().from_node == id) { + undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + } + } + } + + undo_redo->add_do_method(VisualShaderEditor::get_singleton(), "_update_graph"); + undo_redo->add_undo_method(VisualShaderEditor::get_singleton(), "_update_graph"); + + undo_redo->commit_action(); +} + void VisualShaderEditor::_member_filter_changed(const String &p_text) { _update_options_menu(); } @@ -2260,6 +2346,7 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_add_node", &VisualShaderEditor::_add_node); ClassDB::bind_method("_node_changed", &VisualShaderEditor::_node_changed); ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item); + ClassDB::bind_method("_uniform_select_item", &VisualShaderEditor::_uniform_select_item); ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size); ClassDB::bind_method("_clear_buffer", &VisualShaderEditor::_clear_buffer); @@ -2862,6 +2949,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Expression", "Special", "", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside."))); add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which is placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants."))); + add_options.push_back(AddOption("UniformRef", "Special", "", "VisualShaderNodeUniformRef", TTR("A reference to an existing uniform."))); add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); @@ -2980,6 +3068,54 @@ public: } }; +//////////////// + +class VisualShaderNodePluginUniformRefEditor : public OptionButton { + GDCLASS(VisualShaderNodePluginUniformRefEditor, OptionButton); + + Ref<VisualShaderNodeUniformRef> uniform_ref; + +public: + void _notification(int p_what) { + if (p_what == NOTIFICATION_READY) { + connect("item_selected", callable_mp(this, &VisualShaderNodePluginUniformRefEditor::_item_selected)); + } + } + + void _item_selected(int p_item) { + VisualShaderEditor::get_singleton()->call_deferred("_uniform_select_item", uniform_ref, get_item_text(p_item)); + } + + void setup(const Ref<VisualShaderNodeUniformRef> &p_uniform_ref) { + uniform_ref = p_uniform_ref; + + Ref<Texture2D> type_icon[7] = { + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("float", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("int", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("bool", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Vector3", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Color", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons"), + }; + + add_item("[None]"); + int to_select = -1; + for (int i = 0; i < p_uniform_ref->get_uniforms_count(); i++) { + if (p_uniform_ref->get_uniform_name() == p_uniform_ref->get_uniform_name_by_index(i)) { + to_select = i + 1; + } + add_icon_item(type_icon[p_uniform_ref->get_uniform_type_by_index(i)], p_uniform_ref->get_uniform_name_by_index(i)); + } + + if (to_select >= 0) { + select(to_select); + } + } +}; + +//////////////// + class VisualShaderNodePluginDefaultEditor : public VBoxContainer { GDCLASS(VisualShaderNodePluginDefaultEditor, VBoxContainer); Ref<Resource> parent_resource; @@ -3095,6 +3231,13 @@ public: }; Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) { + if (p_node->is_class("VisualShaderNodeUniformRef")) { + //create input + VisualShaderNodePluginUniformRefEditor *uniform_editor = memnew(VisualShaderNodePluginUniformRefEditor); + uniform_editor->setup(p_node); + return uniform_editor; + } + if (p_node->is_class("VisualShaderNodeInput")) { //create input VisualShaderNodePluginInputEditor *input_editor = memnew(VisualShaderNodePluginInputEditor); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 0601b35131..9b80488b22 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -232,6 +232,7 @@ class VisualShaderEditor : public VBoxContainer { void _rebuild(); void _input_select_item(Ref<VisualShaderNodeInput> input, String name); + void _uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform, String p_name); void _add_input_port(int p_node, int p_port, int p_port_type, const String &p_name); void _remove_input_port(int p_node, int p_port); diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index c9115fb870..cb56358ae6 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -368,18 +368,18 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: float min = 0, max = 100, step = type == Variant::FLOAT ? .01 : 1; if (c >= 1) { if (!hint_text.get_slice(",", 0).empty()) { - min = hint_text.get_slice(",", 0).to_double(); + min = hint_text.get_slice(",", 0).to_float(); } } if (c >= 2) { if (!hint_text.get_slice(",", 1).empty()) { - max = hint_text.get_slice(",", 1).to_double(); + max = hint_text.get_slice(",", 1).to_float(); } } if (c >= 3) { if (!hint_text.get_slice(",", 2).empty()) { - step = hint_text.get_slice(",", 2).to_double(); + step = hint_text.get_slice(",", 2).to_float(); } } @@ -1590,7 +1590,7 @@ real_t CustomPropertyEditor::_parse_real_expression(String text) { Error err = expr->parse(text); real_t out; if (err != OK) { - out = value_editor[0]->get_text().to_double(); + out = value_editor[0]->get_text().to_float(); } else { out = expr->execute(Array(), nullptr, false); } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 108e44f294..ce869feddd 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -2718,7 +2718,7 @@ void SceneTreeDock::_update_create_root_dialog() { if (l != String()) { Button *button = memnew(Button); favorite_nodes->add_child(button); - button->set_text(TTR(l)); + button->set_text(l); String name = l.get_slicec(' ', 0); if (ScriptServer::is_global_class(name)) { name = ScriptServer::get_global_class_native_base(name); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index ffdf8208b8..628475bbc0 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -603,7 +603,7 @@ void ScriptCreateDialog::_path_entered(const String &p_path) { } void ScriptCreateDialog::_msg_script_valid(bool valid, const String &p_msg) { - error_label->set_text("- " + TTR(p_msg)); + error_label->set_text("- " + p_msg); if (valid) { error_label->add_theme_color_override("font_color", gc->get_theme_color("success_color", "Editor")); } else { @@ -612,7 +612,7 @@ void ScriptCreateDialog::_msg_script_valid(bool valid, const String &p_msg) { } void ScriptCreateDialog::_msg_path_valid(bool valid, const String &p_msg) { - path_error_label->set_text("- " + TTR(p_msg)); + path_error_label->set_text("- " + p_msg); if (valid) { path_error_label->add_theme_color_override("font_color", gc->get_theme_color("success_color", "Editor")); } else { diff --git a/editor/translations/af.po b/editor/translations/af.po index daa0737106..90dca850de 100644 --- a/editor/translations/af.po +++ b/editor/translations/af.po @@ -2403,10 +2403,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10565,6 +10561,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Skrap" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Skrap" @@ -12232,6 +12233,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/ar.po b/editor/translations/ar.po index 5a0b6d1e17..45ac317d99 100644 --- a/editor/translations/ar.po +++ b/editor/translations/ar.po @@ -41,12 +41,14 @@ # Anas <anas.ghamdi61@gmail.com>, 2020. # R-K <raouf9005@gmail.com>, 2020. # HeroFight dev <abdkafi2002@gmail.com>, 2020. +# Ø£Øمد مصطÙÙ‰ الطبراني <eltabaraniahmed@gmail.com>, 2020. +# ChemicalInk <aladdinalkhafaji@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-25 08:40+0000\n" -"Last-Translator: Airbus5717 <Abdussamadf350@gmail.com>\n" +"PO-Revision-Date: 2020-07-21 13:41+0000\n" +"Last-Translator: ChemicalInk <aladdinalkhafaji@gmail.com>\n" "Language-Team: Arabic <https://hosted.weblate.org/projects/godot-engine/" "godot/ar/>\n" "Language: ar\n" @@ -2342,10 +2344,6 @@ msgid "There is no defined scene to run." msgstr "ليس هناك مشهد Ù…Øدد ليتم تشغيله." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "المشهد الØالي لم يتم ØÙظه. الرجاء ØÙظ المشهد قبل تشغيله Ùˆ اختباره." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "لا يمكن بدء عملية جانبية!" @@ -4722,17 +4720,16 @@ msgstr "" #: editor/plugins/animation_state_machine_editor.cpp msgid "Transition: " -msgstr "التØريك " +msgstr "الانتقال: " #: editor/plugins/animation_state_machine_editor.cpp -#, fuzzy msgid "Play Mode:" -msgstr "وضع السØب" +msgstr "وضع اللعب:" #: editor/plugins/animation_tree_editor_plugin.cpp #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "AnimationTree" -msgstr "مسارات التØريك" +msgstr "شجرة التØريك" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "New name:" @@ -4899,14 +4896,12 @@ msgid "Request failed, return code:" msgstr "Ùشل إتمام الطلب٫ الرمز الذي تم إرجاعه:" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Request failed." msgstr "Ùشل الطلب." #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Cannot save response to:" -msgstr "لا يمكن المسØ:" +msgstr "لا يمكن الØÙظ بسبب:" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Write error." @@ -4917,19 +4912,16 @@ msgid "Request failed, too many redirects" msgstr "Ùشل الطلب٫ السبب هو اعادة التØويل مرات اكثر من اللازم" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Redirect loop." msgstr "اعادة توجيه Øلقة التكرار." #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Request failed, timeout" -msgstr "Ùشل إتمام الطلب٫ الرمز الذي تم إرجاعه:" +msgstr "Ùشل الطلب ØŒ انتهت المهلة" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Timeout." -msgstr "الوقت" +msgstr "إنتهى الوقت" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Bad download hash, assuming file has been tampered with." @@ -4952,14 +4944,12 @@ msgid "Asset Download Error:" msgstr "خطأ ÙÙŠ تنزيل الأصول:" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Downloading (%s / %s)..." -msgstr "جاري التنزيل" +msgstr "جاري التنزيل (%s / %s)..." #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Downloading..." -msgstr "جاري التنزيل" +msgstr "‫جاري التنزيل..." #: editor/plugins/asset_library_editor_plugin.cpp msgid "Resolving..." @@ -4974,9 +4964,8 @@ msgid "Idle" msgstr "عاطل" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Install..." -msgstr "تثبيت" +msgstr "تثبيت..." #: editor/plugins/asset_library_editor_plugin.cpp msgid "Retry" @@ -5007,24 +4996,20 @@ msgid "Name (Z-A)" msgstr "الاسم (ترتيب أل٠بائي معكوس)" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "License (A-Z)" -msgstr "الرخصة" +msgstr "الرخصة (Ø£-ÙŠ)" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "License (Z-A)" -msgstr "الرخصة" +msgstr "الرخصة (ÙŠ-Ø£)" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "First" msgstr "الأول" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Previous" -msgstr "التبويب السابق" +msgstr "السابق" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Next" @@ -5043,14 +5028,12 @@ msgid "No results for \"%s\"." msgstr "لا نتائج من أجل \"%s\"." #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Import..." -msgstr "إستيراد" +msgstr "استيراد..." #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Plugins..." -msgstr "إضاÙات" +msgstr "إضاÙات..." #: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp msgid "Sort:" @@ -5066,9 +5049,8 @@ msgid "Site:" msgstr "الموقع:" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Support" -msgstr "الدعم..." +msgstr "الدعم" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Official" @@ -5079,9 +5061,8 @@ msgid "Testing" msgstr "أختبار" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Loading..." -msgstr "تØميل" +msgstr "جاري التØميل..." #: editor/plugins/asset_library_editor_plugin.cpp msgid "Assets ZIP File" @@ -5594,9 +5575,8 @@ msgid "Scale mask for inserting keys." msgstr "قناع التØجيم لأجل إدخال المÙاتيØ." #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Insert keys (based on mask)." -msgstr "أدخل Ù…ÙØªØ§Ø (مسارات موجودة بالÙعل)" +msgstr "أدخل المÙØ§ØªÙŠØ (على أساس القناع)." #: editor/plugins/canvas_item_editor_plugin.cpp msgid "" @@ -5666,9 +5646,8 @@ msgid "Error instancing scene from %s" msgstr "خطأ ÙÙŠ ØªÙˆØ¶ÙŠØ Ø§Ù„Ù…Ø´Ù‡Ø¯ من %s" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Change Default Type" -msgstr "غير النوع الإÙتراضي" +msgstr "تغير النوع الإÙتراضي" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "" @@ -5753,9 +5732,8 @@ msgid "Emission Colors" msgstr "الوان الإنبعاث" #: editor/plugins/cpu_particles_editor_plugin.cpp -#, fuzzy msgid "CPUParticles" -msgstr "جسيمات" +msgstr "جزيئات ÙˆØدة المعالجة المركزية" #: editor/plugins/cpu_particles_editor_plugin.cpp #: editor/plugins/particles_editor_plugin.cpp @@ -5816,9 +5794,8 @@ msgid "Right Linear" msgstr "الخط اليميني" #: editor/plugins/curve_editor_plugin.cpp -#, fuzzy msgid "Load Preset" -msgstr "تØميل الإعداد المعد مسبقاً" +msgstr "تØميل إعداد مسبق" #: editor/plugins/curve_editor_plugin.cpp msgid "Remove Curve Point" @@ -5974,9 +5951,8 @@ msgstr "" "هذا هو الخيار الأكثر دقة (لكنه الأبطئ) لأجل للكش٠عن وقوع التصادم." #: editor/plugins/mesh_instance_editor_plugin.cpp -#, fuzzy msgid "Create Single Convex Collision Sibling" -msgstr "إنشاء متصادم Ù…Øدب قريب" +msgstr "إنشاء شقيق تصادم Ù…Øدب Ù…Ùرد" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "" @@ -6051,9 +6027,8 @@ msgid "" msgstr "تØديث من المشهد" #: editor/plugins/mesh_library_editor_plugin.cpp -#, fuzzy msgid "Mesh Library" -msgstr "مكتبة الميش..." +msgstr "مكتبة المجسم" #: editor/plugins/mesh_library_editor_plugin.cpp #: editor/plugins/theme_editor_plugin.cpp @@ -10617,6 +10592,11 @@ msgstr "ØÙظ المشهد" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Øذ٠العÙقدة \"%s\" مع جميع أبنائها؟" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "إنشاء عقدة" @@ -12372,6 +12352,12 @@ msgstr "" "يجب تزويد ال CollisionShape2D بإØدى الأشكال (من نوع Shape2D) لتعمل بالشكل " "المطلوب. الرجاء تكوين Ùˆ ضبط الشكل لها اولا!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12851,6 +12837,9 @@ msgstr "يمكن تعيين المتغيرات Ùقط ÙÙŠ الذروة ." msgid "Constants cannot be modified." msgstr "لا يمكن تعديل الثوابت." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "المشهد الØالي لم يتم ØÙظه. الرجاء ØÙظ المشهد قبل تشغيله Ùˆ اختباره." + #~ msgid "Not in resource path." #~ msgstr "ليس ÙÙŠ مسار الموارد." diff --git a/editor/translations/bg.po b/editor/translations/bg.po index c9f38d518a..b0378d612c 100644 --- a/editor/translations/bg.po +++ b/editor/translations/bg.po @@ -2262,11 +2262,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"Текущата Ñцена никога не е била запазена. МолÑ, запазете Ñ Ð¿Ñ€ÐµÐ´Ð¸ изпълнение." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10293,6 +10288,11 @@ msgid "Make node as Root" msgstr "Превръщане на възела в корен" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Изтриване на %d възела?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "Изтриване на %d възела?" @@ -11996,6 +11996,12 @@ msgstr "" "За да работи CollisionShape2D, е нужно да му Ñе даде форма. МолÑ, Ñъздайте " "му Shape2D реÑурÑ." +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12484,6 +12490,11 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "Текущата Ñцена никога не е била запазена. МолÑ, запазете Ñ Ð¿Ñ€ÐµÐ´Ð¸ " +#~ "изпълнение." + #~ msgid "Not in resource path." #~ msgstr "Ðе е в Ð¿ÑŠÑ‚Ñ Ð½Ð° реÑурÑите." diff --git a/editor/translations/bn.po b/editor/translations/bn.po index c438934246..5fdcfb385b 100644 --- a/editor/translations/bn.po +++ b/editor/translations/bn.po @@ -2490,11 +2490,6 @@ msgid "There is no defined scene to run." msgstr "চালানোর জনà§à¦¯ কোনো দৃশà§à¦¯ নিরà§à¦¦à¦¿à¦·à§à¦Ÿ করা নেই।" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"বরà§à¦¤à¦®à¦¾à¦¨ দৃশà§à¦¯à¦Ÿà¦¿ কখনোই সংরকà§à¦·à¦£ করা হয় নি, অনà§à¦—à§à¦°à¦¹ করে চালানোর পূরà§à¦¬à§‡ à¦à¦Ÿà¦¿ সংরকà§à¦·à¦£ করà§à¦¨à¥¤" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "উপ-পà§à¦°à¦•à§à¦°à¦¿à¦¯à¦¼à¦¾à¦•à§‡ শà§à¦°à§ করা সমà§à¦à¦¬ হয়নি!" @@ -11217,6 +11212,11 @@ msgstr "অরà§à¦¥à¦ªà§‚রà§à¦¨!" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "নোড(সমূহ) অপসারণ করà§à¦¨" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "নোড(সমূহ) অপসারণ করà§à¦¨" @@ -13032,6 +13032,12 @@ msgstr "" "সফলà§à¦à¦¾à¦¬à§‡ কাজ করতে CollisionShape2D à¦à¦° à¦à¦•à¦Ÿà¦¿ আকৃতি পà§à¦°à§Ÿà§‹à¦œà¦¨à¥¤ অনà§à¦—à§à¦°à¦¹ করে তার জনà§à¦¯ " "à¦à¦•à¦Ÿà¦¿ আকৃতি তৈরি করà§à¦¨!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -13552,6 +13558,11 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "বরà§à¦¤à¦®à¦¾à¦¨ দৃশà§à¦¯à¦Ÿà¦¿ কখনোই সংরকà§à¦·à¦£ করা হয় নি, অনà§à¦—à§à¦°à¦¹ করে চালানোর পূরà§à¦¬à§‡ à¦à¦Ÿà¦¿ সংরকà§à¦·à¦£ " +#~ "করà§à¦¨à¥¤" + #~ msgid "Not in resource path." #~ msgstr "রিসোরà§à¦¸à§‡à¦° পথে নয়।" diff --git a/editor/translations/ca.po b/editor/translations/ca.po index 5fb91db7b4..359aea8184 100644 --- a/editor/translations/ca.po +++ b/editor/translations/ca.po @@ -2338,11 +2338,6 @@ msgid "There is no defined scene to run." msgstr "No s'ha definit cap escena per executar." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"L'escena actual no s'ha desat encara. Desa l'escena abans d'executar-la." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "No s'ha pogut començar el subprocés!" @@ -10818,6 +10813,11 @@ msgid "Make node as Root" msgstr "Convertir node en arrel" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Voleu suprimir el node \"%s\" i els seus fills?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "Suprimir %d nodes?" @@ -12585,6 +12585,12 @@ msgstr "" "S'ha de proporcionar una forma perquè *CollisionShape2D pugui funcionar. " "Creeu-li un recurs de forma (shape)!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -13161,6 +13167,10 @@ msgstr "" msgid "Constants cannot be modified." msgstr "Les constants no es poden modificar." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "L'escena actual no s'ha desat encara. Desa l'escena abans d'executar-la." + #~ msgid "Not in resource path." #~ msgstr "Fora del camà dels recursos." diff --git a/editor/translations/cs.po b/editor/translations/cs.po index 722fa52d92..e629fbc2ff 100644 --- a/editor/translations/cs.po +++ b/editor/translations/cs.po @@ -24,7 +24,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-25 08:40+0000\n" +"PO-Revision-Date: 2020-07-28 09:51+0000\n" "Last-Translator: ZbynÄ›k <zbynek.fiala@gmail.com>\n" "Language-Team: Czech <https://hosted.weblate.org/projects/godot-engine/godot/" "cs/>\n" @@ -773,9 +773,8 @@ msgid "Method in target node must be specified." msgstr "Je nutné zadat metodu v cÃlovém uzlu." #: editor/connections_dialog.cpp -#, fuzzy msgid "Method name must be a valid identifier." -msgstr "Jméno nenà platný identifikátor:" +msgstr "Jméno metody musà být platný identifikátor." #: editor/connections_dialog.cpp msgid "" @@ -828,7 +827,7 @@ msgstr "DalÅ¡Ã argumenty volánÃ:" #: editor/connections_dialog.cpp msgid "Receiver Method:" -msgstr "Metoda pÅ™ijÃmaÄe:" +msgstr "Metoda pÅ™Ãjemce:" #: editor/connections_dialog.cpp msgid "Advanced" @@ -1296,7 +1295,7 @@ msgstr "PÅ™etaženÃm uspořádejte." #: editor/editor_audio_buses.cpp msgid "Solo" -msgstr "Solo" +msgstr "Sólo" #: editor/editor_audio_buses.cpp msgid "Mute" @@ -1496,7 +1495,7 @@ msgstr "Název" #: editor/editor_autoload_settings.cpp msgid "Singleton" -msgstr "Singleton" +msgstr "Singleton (jedináÄek)" #: editor/editor_data.cpp editor/inspector_dock.cpp msgid "Paste Params" @@ -1961,9 +1960,8 @@ msgid "Properties" msgstr "Vlastnosti" #: editor/editor_help.cpp -#, fuzzy msgid "override:" -msgstr "PÅ™epsat" +msgstr "pÅ™epsat:" #: editor/editor_help.cpp msgid "default:" @@ -2339,10 +2337,6 @@ msgid "There is no defined scene to run." msgstr "Neexistuje žádná scéna pro spuÅ¡tÄ›nÃ." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "Aktuálnà scéna nebyla nikdy uložena, prosÃm uložte jà pÅ™ed spuÅ¡tÄ›nÃm." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Nelze spustit podproces!" @@ -2427,9 +2421,8 @@ msgid "Can't reload a scene that was never saved." msgstr "Nelze naÄÃst scénu, která nebyla nikdy uložena." #: editor/editor_node.cpp -#, fuzzy msgid "Reload Saved Scene" -msgstr "Uložit scénu" +msgstr "ZnovunaÄÃst uloženou scénu" #: editor/editor_node.cpp msgid "" @@ -2929,9 +2922,8 @@ msgid "Q&A" msgstr "Otázky a odpovÄ›di" #: editor/editor_node.cpp -#, fuzzy msgid "Report a Bug" -msgstr "Znovu importovat" +msgstr "Nahlásit chybu" #: editor/editor_node.cpp msgid "Send Docs Feedback" @@ -3662,7 +3654,7 @@ msgstr "OtevÅ™Ãt scény" #: editor/filesystem_dock.cpp msgid "Instance" -msgstr "Instance" +msgstr "Instance:" #: editor/filesystem_dock.cpp msgid "Add to Favorites" @@ -5731,7 +5723,7 @@ msgstr "" #: editor/plugins/cpu_particles_editor_plugin.cpp msgid "CPUParticles" -msgstr "CPUParticles" +msgstr "CPUParticles (Äástice)" #: editor/plugins/cpu_particles_editor_plugin.cpp #: editor/plugins/particles_editor_plugin.cpp @@ -6589,7 +6581,7 @@ msgstr "Vložit zdroj" #: editor/plugins/resource_preloader_editor_plugin.cpp #: editor/scene_tree_editor.cpp msgid "Instance:" -msgstr "Instance:" +msgstr "Instance" #: editor/plugins/resource_preloader_editor_plugin.cpp #: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp @@ -7091,13 +7083,12 @@ msgid "Go to Previous Breakpoint" msgstr "PÅ™ejÃt na pÅ™edchozà breakpoint" #: editor/plugins/shader_editor_plugin.cpp -#, fuzzy msgid "" "This shader has been modified on on disk.\n" "What action should be taken?" msgstr "" -"NásledujÃcà soubory majà novÄ›jÅ¡Ã verzi na disku.\n" -"Jaká akce se má vykonat?:" +"Tento shader byl na disku upraven.\n" +"Jaká akce se má vykonat?" #: editor/plugins/shader_editor_plugin.cpp msgid "Shader" @@ -7118,7 +7109,7 @@ msgstr "" #: editor/plugins/skeleton_2d_editor_plugin.cpp msgid "Skeleton2D" -msgstr "Skeleton2D" +msgstr "Skeleton2D (Kostra 2D)" #: editor/plugins/skeleton_2d_editor_plugin.cpp msgid "Make Rest Pose (From Bones)" @@ -7857,7 +7848,7 @@ msgstr "" #: editor/plugins/texture_region_editor_plugin.cpp msgid "Offset:" -msgstr "Offset:" +msgstr "Offset(Posun):" #: editor/plugins/texture_region_editor_plugin.cpp msgid "Step:" @@ -8464,7 +8455,7 @@ msgstr "Tato vlastnost nemůže být zmÄ›nÄ›na." #: editor/plugins/tile_set_editor_plugin.cpp msgid "TileSet" -msgstr "TileSet" +msgstr "TileSet (Sada dlaždic)" #: editor/plugins/version_control_editor_plugin.cpp #, fuzzy @@ -9855,11 +9846,12 @@ msgid "" msgstr "Odstranit projekt ze seznamu? (Obsah složky zůstane nedotÄen)" #: editor/project_manager.cpp -#, fuzzy msgid "" "Remove this project from the list?\n" "The project folder's contents won't be modified." -msgstr "Odstranit projekt ze seznamu? (Obsah složky zůstane nedotÄen)" +msgstr "" +"Odstranit projekt ze seznamu?\n" +"Obsah složky zůstane nedotÄen." #: editor/project_manager.cpp #, fuzzy @@ -9960,9 +9952,8 @@ msgstr "" "nebo '\"'" #: editor/project_settings_editor.cpp -#, fuzzy msgid "An action with the name '%s' already exists." -msgstr "Akce '%s' již existuje!" +msgstr "Akce s názvem \"%s\" již existuje." #: editor/project_settings_editor.cpp msgid "Rename Input Action Event" @@ -10549,8 +10540,12 @@ msgstr "Dává smysl!" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Smazat %d uzlů?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" -msgstr "Smazat uzel" +msgstr "Smazat %d uzlů?" #: editor/scene_tree_dock.cpp msgid "Delete the root node \"%s\"?" @@ -10561,9 +10556,8 @@ msgid "Delete node \"%s\" and its children?" msgstr "" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "Delete node \"%s\"?" -msgstr "Smazat uzel" +msgstr "Smazat uzel \"%s\"?" #: editor/scene_tree_dock.cpp msgid "Can not perform with the root node." @@ -12234,6 +12228,12 @@ msgid "" "shape resource for it!" msgstr "CollisionShape2D musà obsahovat tvar. ProsÃm vytvoÅ™te zdrojový tvar." +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12761,6 +12761,10 @@ msgstr "" msgid "Constants cannot be modified." msgstr "Konstanty nenà možné upravovat." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "Aktuálnà scéna nebyla nikdy uložena, prosÃm uložte jà pÅ™ed spuÅ¡tÄ›nÃm." + #~ msgid "Not in resource path." #~ msgstr "Nenà v cestÄ› ke zdroji." diff --git a/editor/translations/da.po b/editor/translations/da.po index 70b05c08ff..da54615917 100644 --- a/editor/translations/da.po +++ b/editor/translations/da.po @@ -2426,10 +2426,6 @@ msgid "There is no defined scene to run." msgstr "Der er ingen defineret scene at køre." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "Den nuværende scene er aldrig gemt, venligst gem før du kører den." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Kunne ikke starte underproces!" @@ -10784,6 +10780,11 @@ msgstr "Gem Scene" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Vælg Node" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Vælg Node" @@ -12512,6 +12513,12 @@ msgstr "" "En figur skal gives CollisionShape2D for at det fungerer. Opret venligst en " "figur ressource for den!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -13030,6 +13037,9 @@ msgstr "" msgid "Constants cannot be modified." msgstr "Konstanter kan ikke ændres." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "Den nuværende scene er aldrig gemt, venligst gem før du kører den." + #~ msgid "Not in resource path." #~ msgstr "Ikke i stien for ressource." diff --git a/editor/translations/de.po b/editor/translations/de.po index eb533ff15e..4b8252173e 100644 --- a/editor/translations/de.po +++ b/editor/translations/de.po @@ -52,12 +52,14 @@ # artism90 <artism90@googlemail.com>, 2020. # Jaigskim <filzstift112@gmail.com>, 2020. # Jacqueline Ulken <Jacqueline.Ulken@protonmail.com>, 2020. +# Günther Bohn <ciscouser@gmx.de>, 2020. +# Tom Wor <mail@tomwor.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-25 08:40+0000\n" -"Last-Translator: So Wieso <sowieso@dukun.de>\n" +"PO-Revision-Date: 2020-07-28 09:51+0000\n" +"Last-Translator: Tom Wor <mail@tomwor.com>\n" "Language-Team: German <https://hosted.weblate.org/projects/godot-engine/" "godot/de/>\n" "Language: de\n" @@ -775,7 +777,7 @@ msgstr "Standard" #: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp msgid "Toggle Scripts Panel" -msgstr "Seitenleiste umschalten" +msgstr "Skript-Panel umschalten" #: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/texture_region_editor_plugin.cpp @@ -2382,12 +2384,6 @@ msgid "There is no defined scene to run." msgstr "Es ist keine abzuspielende Szene definiert." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"Die aktuelle Szene wurde noch nicht gespeichert, bitte vor dem Abspielen " -"sichern." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Unterprozess konnte nicht gestartet werden!" @@ -5438,7 +5434,7 @@ msgstr "" #: editor/plugins/texture_region_editor_plugin.cpp #: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp msgid "Zoom Reset" -msgstr "Zoom Zurücksetzen" +msgstr "Zoom zurücksetzen" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -10153,7 +10149,7 @@ msgstr "Ereignis hinzufügen" #: editor/project_settings_editor.cpp msgid "Button" -msgstr "\"Button\"" +msgstr "Schaltfläche (Button)" #: editor/project_settings_editor.cpp msgid "Left Button." @@ -10641,6 +10637,11 @@ msgid "Make node as Root" msgstr "Node zur Szenenwurzel machen" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Node „%s“ und Unterobjekte löschen?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "%d Nodes löschen?" @@ -10759,7 +10760,7 @@ msgstr "Leere Vererbung" #: editor/scene_tree_dock.cpp msgid "Editable Children" -msgstr "bearbeitbare Unterobjekte" +msgstr "Bearbeitbare Unterobjekte" #: editor/scene_tree_dock.cpp msgid "Load As Placeholder" @@ -12340,6 +12341,12 @@ msgstr "" "Damit CollisionShape2D funktionieren kann, muss eine Form angegeben werden. " "Bitte erzeuge eine Shape-Ressource dafür!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12939,6 +12946,11 @@ msgstr "Varyings können nur in Vertex-Funktion zugewiesen werden." msgid "Constants cannot be modified." msgstr "Konstanten können nicht verändert werden." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "Die aktuelle Szene wurde noch nicht gespeichert, bitte vor dem Abspielen " +#~ "sichern." + #~ msgid "Not in resource path." #~ msgstr "Nicht im Ressourcen-Pfad." diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot index 01121a8156..87dca17afd 100644 --- a/editor/translations/editor.pot +++ b/editor/translations/editor.pot @@ -2245,10 +2245,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10109,6 +10105,10 @@ msgid "Make node as Root" msgstr "" #: editor/scene_tree_dock.cpp +msgid "Delete %d nodes and any children?" +msgstr "" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "" @@ -11710,6 +11710,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/el.po b/editor/translations/el.po index 8ff5881a9e..dff4eaafb0 100644 --- a/editor/translations/el.po +++ b/editor/translations/el.po @@ -8,12 +8,13 @@ # Eternal Death <eternaldeath0001@gmail.com>, 2019. # Overloaded @ Orama Interactive http://orama-interactive.com/ <manoschool@yahoo.gr>, 2020. # pandektis <pandektis@gmail.com>, 2020. +# KostasMSC <kargyris@athtech.gr>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-25 08:40+0000\n" -"Last-Translator: pandektis <pandektis@gmail.com>\n" +"PO-Revision-Date: 2020-07-11 01:21+0000\n" +"Last-Translator: KostasMSC <kargyris@athtech.gr>\n" "Language-Team: Greek <https://hosted.weblate.org/projects/godot-engine/godot/" "el/>\n" "Language: el\n" @@ -1785,7 +1786,7 @@ msgstr "ÎÎος φάκελος..." #: editor/editor_file_dialog.cpp editor/find_in_files.cpp #: editor/plugins/version_control_editor_plugin.cpp msgid "Refresh" -msgstr "Αναναίωση" +msgstr "ΑνανÎωση" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "All Recognized" @@ -2336,12 +2337,6 @@ msgid "There is no defined scene to run." msgstr "Δεν υπάÏχει καθοÏισμÎνη σκηνή για εκτελÎση." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"Η Ï„ÏÎχουσα σκηνή δεν Îχει αποθηκευτεί, αποθηκεÏστε Ï€Ïιν να Ï„ÏÎξετε το " -"Ï€ÏόγÏαμμα." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "ΑδÏνατη η εκκίνηση της υπό-εÏγασίας!" @@ -2703,7 +2698,7 @@ msgstr "Άνοιγμα Ï€Ïόσφατων" #: editor/editor_node.cpp msgid "Save Scene" -msgstr "ΑποθηκεÏσετε σκηνής" +msgstr "ΑποθηκεÏση σκηνής" #: editor/editor_node.cpp msgid "Save All Scenes" @@ -5581,7 +5576,7 @@ msgstr "Εμφάνιση ΧαÏάκων" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Show Guides" -msgstr "Εμφάνιση Οδηγών" +msgstr "Εμφάνιση Οδηγιών" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Show Origin" @@ -10582,6 +10577,11 @@ msgid "Make node as Root" msgstr "Κάνε κόμβο Ïίζα" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "ΔιαγÏαφή κόμβου \"%s\" και των παιδιών του;" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "ΔιαγÏαφή %d κόμβων;" @@ -12286,6 +12286,12 @@ msgstr "" "Ένα σχήμα Ï€ÏÎπει να δοθεί στο CollisionShape2D για να λειτουÏγήσει. " "ΔημιουÏγήστε Îνα πόÏο σχήματος για αυτό!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12870,6 +12876,11 @@ msgstr "Τα «varying» μποÏοÏν να ανατεθοÏν μόνο στηΠmsgid "Constants cannot be modified." msgstr "Οι σταθεÏÎÏ‚ δεν μποÏοÏν να Ï„ÏοποποιηθοÏν." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "Η Ï„ÏÎχουσα σκηνή δεν Îχει αποθηκευτεί, αποθηκεÏστε Ï€Ïιν να Ï„ÏÎξετε το " +#~ "Ï€ÏόγÏαμμα." + #~ msgid "Not in resource path." #~ msgstr "Δεν υπάÏχει στην διαδÏομή πόÏων." diff --git a/editor/translations/eo.po b/editor/translations/eo.po index f98f043118..e740ea7d7a 100644 --- a/editor/translations/eo.po +++ b/editor/translations/eo.po @@ -2309,10 +2309,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10261,6 +10257,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Forigi Åœlosilo(j)n" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Forigi Åœlosilo(j)n" @@ -11882,6 +11883,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/es.po b/editor/translations/es.po index a200653685..e32797440e 100644 --- a/editor/translations/es.po +++ b/editor/translations/es.po @@ -49,11 +49,12 @@ # Serk Lintur <serk.lintur@gmail.com>, 2020. # Pedro J. Estébanez <pedrojrulez@gmail.com>, 2020. # paco <pacosoftfree@protonmail.com>, 2020. +# Jonatan <arandajonatan94@tuta.io>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-25 08:40+0000\n" +"PO-Revision-Date: 2020-07-28 09:51+0000\n" "Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n" "Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/" "godot/es/>\n" @@ -84,7 +85,7 @@ msgstr "" #: core/math/expression.cpp msgid "Invalid input %i (not passed) in expression" -msgstr "Entrada inválida %i (no se pasó) en la expresión" +msgstr "Entrada inválida %i (no aprobada) en la expresión" #: core/math/expression.cpp msgid "self can't be used because instance is null (not passed)" @@ -853,7 +854,7 @@ msgstr "Eliminar" #: editor/connections_dialog.cpp msgid "Add Extra Call Argument:" -msgstr "Añadir Argumento de Llamada Extra:" +msgstr "Añadir Argumento Extra de Llamada:" #: editor/connections_dialog.cpp msgid "Extra Call Arguments:" @@ -2383,11 +2384,6 @@ msgid "There is no defined scene to run." msgstr "No hay escena definida para ejecutar." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"La escena actual nunca se guardó. Por favor, guárdela antes de ejecutar." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "¡No se pudo comenzar el subproceso!" @@ -4369,7 +4365,7 @@ msgstr "No hay ningún triángulo, asà que no se puede hacer blending." #: editor/plugins/animation_blend_space_2d_editor.cpp msgid "Toggle Auto Triangles" -msgstr "Act./Desact. Auto Triángulos" +msgstr "Act./Desact. Triángulos Automáticos" #: editor/plugins/animation_blend_space_2d_editor.cpp msgid "Create triangles by connecting points." @@ -4381,7 +4377,8 @@ msgstr "Borrar puntos y triángulos." #: editor/plugins/animation_blend_space_2d_editor.cpp msgid "Generate blend triangles automatically (instead of manually)" -msgstr "Generar triángulos de blending automáticamente (en vez de manualmente)" +msgstr "" +"Generar triángulos combinados automáticamente (en lugar de manualmente)" #: editor/plugins/animation_blend_space_2d_editor.cpp #: editor/plugins/animation_tree_player_editor_plugin.cpp @@ -8947,7 +8944,7 @@ msgstr "Devuelve el valor absoluto del parámetro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the arc-cosine of the parameter." -msgstr "Devuelve el arcocoseno del parámetro." +msgstr "Devuelve el arco-coseno del parámetro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the inverse hyperbolic cosine of the parameter." @@ -8955,7 +8952,7 @@ msgstr "Devuelve el coseno hiperbólico inverso del parámetro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the arc-sine of the parameter." -msgstr "Devuelve el arcoseno del parámetro." +msgstr "Devuelve el arco-seno del parámetro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the inverse hyperbolic sine of the parameter." @@ -8963,11 +8960,11 @@ msgstr "Devuelve el seno hiperbólico inverso del parámetro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the arc-tangent of the parameter." -msgstr "Devuelve el arcotangente del parámetro." +msgstr "Devuelve el arco-tangente del parámetro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the arc-tangent of the parameters." -msgstr "Devuelve el arcotangente de los parámetros." +msgstr "Devuelve el arco-tangente de los parámetros." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the inverse hyperbolic tangent of the parameter." @@ -8996,11 +8993,11 @@ msgstr "Convierte una cantidad en radianes a grados." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Base-e Exponential." -msgstr "Exponencial en base e." +msgstr "Exponencial con Base-e." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Base-2 Exponential." -msgstr "Exponencial en base 2." +msgstr "Exponencial con base 2." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Finds the nearest integer less than or equal to the parameter." @@ -9020,7 +9017,7 @@ msgstr "Logaritmo natural." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Base-2 logarithm." -msgstr "Logaritmo de la base 2." +msgstr "Logaritmo Base-2." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the greater of two values." @@ -10630,6 +10627,11 @@ msgid "Make node as Root" msgstr "Convertir nodo como RaÃz" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "¿Eliminar el nodo \"%s\" y sus hijos?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "¿Eliminar %d nodos?" @@ -12345,6 +12347,12 @@ msgstr "" "Para que funcione CollisionShape2D se debe proporcionar una forma. Por " "favor, ¡crea un recurso de forma para ello!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12927,6 +12935,10 @@ msgstr "Solo se pueden asignar variaciones en funciones de vértice." msgid "Constants cannot be modified." msgstr "Las constantes no pueden modificarse." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "La escena actual nunca se guardó. Por favor, guárdela antes de ejecutar." + #~ msgid "Not in resource path." #~ msgstr "No está en la ruta de recursos." diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po index ca9f5a7a49..92e6e7d511 100644 --- a/editor/translations/es_AR.po +++ b/editor/translations/es_AR.po @@ -2345,11 +2345,6 @@ msgid "There is no defined scene to run." msgstr "No hay escena definida para ejecutar." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"La escena actual nunca se guardó. Favor de guardarla antes de ejecutar." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "No se pudo comenzar el subproceso!" @@ -10583,6 +10578,11 @@ msgid "Make node as Root" msgstr "Convertir nodo en RaÃz" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "¿Eliminar el nodo \"%s\" y sus hijos?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "¿Eliminar %d nodos?" @@ -12293,6 +12293,12 @@ msgstr "" "Se debe proveer un shape para que CollisionShape2D funcione. Creale un " "recurso shape!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12870,6 +12876,10 @@ msgstr "Solo se pueden asignar variaciones en funciones de vértice." msgid "Constants cannot be modified." msgstr "Las constantes no pueden modificarse." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "La escena actual nunca se guardó. Favor de guardarla antes de ejecutar." + #~ msgid "Not in resource path." #~ msgstr "No está en la ruta de recursos." diff --git a/editor/translations/et.po b/editor/translations/et.po index 5fd61347e1..ae27129ab6 100644 --- a/editor/translations/et.po +++ b/editor/translations/et.po @@ -9,15 +9,15 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2020-05-31 12:39+0000\n" -"Last-Translator: René <renepiik@gmail.com>\n" +"PO-Revision-Date: 2020-07-26 15:42+0000\n" +"Last-Translator: StReef <streef.gtx@gmail.com>\n" "Language-Team: Estonian <https://hosted.weblate.org/projects/godot-engine/" "godot/et/>\n" "Language: et\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.1-dev\n" +"X-Generator: Weblate 4.2-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -409,8 +409,7 @@ msgstr "Animatsiooni rajad võivad osutada ainult AnimationPlayer sõlmedele." #: editor/animation_track_editor.cpp msgid "An animation player can't animate itself, only other players." -msgstr "" -"Animatsiooni mängija ei saa animeerida iseennast, ainult teisi mängijaid." +msgstr "AnimationPlayer ei saa animeerida iseennast, ainult teisi mängijaid." #: editor/animation_track_editor.cpp msgid "Not possible to add a new track without a root" @@ -492,7 +491,7 @@ msgstr "" #: editor/animation_track_editor.cpp msgid "Select an AnimationPlayer node to create and edit animations." -msgstr "" +msgstr "Vali AnimationPlayer sõlm, et luua ja redigeerida animatsioone." #: editor/animation_track_editor.cpp msgid "Only show tracks from nodes selected in tree." @@ -503,12 +502,13 @@ msgid "Group tracks by node or display them as plain list." msgstr "" #: editor/animation_track_editor.cpp +#, fuzzy msgid "Snap:" -msgstr "" +msgstr "Intervall:" #: editor/animation_track_editor.cpp msgid "Animation step value." -msgstr "" +msgstr "Animatsiooni sammu väärtus." #: editor/animation_track_editor.cpp msgid "Seconds" @@ -516,7 +516,7 @@ msgstr "Sekundid" #: editor/animation_track_editor.cpp msgid "FPS" -msgstr "Kaadrit/Sekundis" +msgstr "K/S" #: editor/animation_track_editor.cpp editor/editor_properties.cpp #: editor/plugins/polygon_2d_editor_plugin.cpp @@ -530,7 +530,7 @@ msgstr "Muuda" #: editor/animation_track_editor.cpp msgid "Animation properties." -msgstr "" +msgstr "Animatsiooni atribuudid." #: editor/animation_track_editor.cpp msgid "Copy Tracks" @@ -773,7 +773,7 @@ msgstr "" #: editor/groups_editor.cpp editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp msgid "Add" -msgstr "" +msgstr "Lisa" #: editor/connections_dialog.cpp editor/dependency_editor.cpp #: editor/editor_feature_profile.cpp editor/groups_editor.cpp @@ -784,7 +784,7 @@ msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp #: editor/project_settings_editor.cpp msgid "Remove" -msgstr "" +msgstr "Eemalda" #: editor/connections_dialog.cpp msgid "Add Extra Call Argument:" @@ -835,7 +835,7 @@ msgstr "" #: editor/run_settings_dialog.cpp editor/settings_config_dialog.cpp #: modules/visual_script/visual_script_editor.cpp msgid "Close" -msgstr "" +msgstr "Sulge" #: editor/connections_dialog.cpp msgid "Connect" @@ -880,7 +880,7 @@ msgstr "" #: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp msgid "Signals" -msgstr "" +msgstr "Signaalid" #: editor/connections_dialog.cpp msgid "Are you sure you want to remove all connections from this signal?" @@ -997,7 +997,7 @@ msgstr "" #: modules/visual_script/visual_script_property_selector.cpp #: scene/gui/file_dialog.cpp msgid "Open" -msgstr "" +msgstr "Ava" #: editor/dependency_editor.cpp msgid "Owners Of:" @@ -1080,67 +1080,67 @@ msgstr "" #: editor/editor_about.cpp msgid "Thanks from the Godot community!" -msgstr "" +msgstr "Tänu Godot kogukonnale!" #: editor/editor_about.cpp msgid "Godot Engine contributors" -msgstr "" +msgstr "Godot mängumootori panustajad" #: editor/editor_about.cpp msgid "Project Founders" -msgstr "" +msgstr "Projekti asutajad" #: editor/editor_about.cpp msgid "Lead Developer" -msgstr "" +msgstr "Juhtiv arendaja" #: editor/editor_about.cpp msgid "Project Manager " -msgstr "" +msgstr "Projekti juht " #: editor/editor_about.cpp msgid "Developers" -msgstr "" +msgstr "Arendajad" #: editor/editor_about.cpp msgid "Authors" -msgstr "" +msgstr "Autorid" #: editor/editor_about.cpp msgid "Platinum Sponsors" -msgstr "" +msgstr "Plaatinumsponsorid" #: editor/editor_about.cpp msgid "Gold Sponsors" -msgstr "" +msgstr "Kuldsponsorid" #: editor/editor_about.cpp msgid "Mini Sponsors" -msgstr "" +msgstr "Väikesponsorid" #: editor/editor_about.cpp msgid "Gold Donors" -msgstr "" +msgstr "Kuldannetajad" #: editor/editor_about.cpp msgid "Silver Donors" -msgstr "" +msgstr "Hõbennetajad" #: editor/editor_about.cpp msgid "Bronze Donors" -msgstr "" +msgstr "Pronksannetajad" #: editor/editor_about.cpp msgid "Donors" -msgstr "" +msgstr "Annetajad" #: editor/editor_about.cpp msgid "License" -msgstr "" +msgstr "Litsents" #: editor/editor_about.cpp msgid "Third-party Licenses" -msgstr "" +msgstr "Kolmanda osapoole litsents" #: editor/editor_about.cpp msgid "" @@ -1160,7 +1160,7 @@ msgstr "" #: editor/editor_about.cpp msgid "Licenses" -msgstr "" +msgstr "Litsensid" #: editor/editor_asset_installer.cpp editor/project_manager.cpp msgid "Error opening package file, not in ZIP format." @@ -1209,7 +1209,7 @@ msgstr "" #: editor/editor_audio_buses.cpp msgid "Add Effect" -msgstr "" +msgstr "Lisa efekt" #: editor/editor_audio_buses.cpp msgid "Rename Audio Bus" @@ -1237,7 +1237,7 @@ msgstr "" #: editor/editor_audio_buses.cpp msgid "Add Audio Bus Effect" -msgstr "" +msgstr "Lisa helisiini efekt" #: editor/editor_audio_buses.cpp msgid "Move Bus Effect" @@ -1571,7 +1571,7 @@ msgstr "" #: editor/editor_feature_profile.cpp msgid "3D Editor" -msgstr "3D-redigeerija" +msgstr "3D-redaktor" #: editor/editor_feature_profile.cpp msgid "Script Editor" @@ -1715,7 +1715,7 @@ msgstr "Ekspordi profiil" #: editor/editor_feature_profile.cpp msgid "Manage Editor Feature Profiles" -msgstr "Halda redigeerija funktsioonide profiile" +msgstr "Halda redaktori funktsioonide profiile" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Select Current Folder" @@ -2073,9 +2073,8 @@ msgstr "Puhasta väljund" #: editor/editor_network_profiler.cpp editor/editor_node.cpp #: editor/editor_profiler.cpp -#, fuzzy msgid "Stop" -msgstr "Peatu/Stopp" +msgstr "Lõpeta" #: editor/editor_network_profiler.cpp editor/editor_profiler.cpp #: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp @@ -2281,16 +2280,12 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" #: editor/editor_node.cpp editor/filesystem_dock.cpp msgid "Open Scene" -msgstr "" +msgstr "Ava stseen" #: editor/editor_node.cpp msgid "Open Base Scene" @@ -2326,7 +2321,7 @@ msgstr "" #: editor/editor_node.cpp msgid "Save Scene As..." -msgstr "" +msgstr "Salvesta stseen kui..." #: editor/editor_node.cpp msgid "No" @@ -2385,19 +2380,19 @@ msgstr "" #: editor/editor_node.cpp msgid "Quit" -msgstr "" +msgstr "Välju" #: editor/editor_node.cpp msgid "Exit the editor?" -msgstr "" +msgstr "Välju redaktorist?" #: editor/editor_node.cpp msgid "Open Project Manager?" -msgstr "" +msgstr "Ava projekti juht?" #: editor/editor_node.cpp msgid "Save & Quit" -msgstr "" +msgstr "Salvesta ja välju" #: editor/editor_node.cpp msgid "Save changes to the following scene(s) before quitting?" @@ -2419,11 +2414,11 @@ msgstr "" #: editor/editor_node.cpp msgid "Close Scene" -msgstr "" +msgstr "Sule stseen" #: editor/editor_node.cpp msgid "Reopen Closed Scene" -msgstr "" +msgstr "Taasava suletud stseen" #: editor/editor_node.cpp msgid "Unable to enable addon plugin at: '%s' parsing of config failed." @@ -2504,7 +2499,7 @@ msgstr "" #: editor/editor_node.cpp editor/import_dock.cpp #: editor/script_create_dialog.cpp msgid "Default" -msgstr "" +msgstr "Vaikimisi" #: editor/editor_node.cpp editor/editor_properties.cpp #: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp @@ -2513,7 +2508,7 @@ msgstr "" #: editor/editor_node.cpp msgid "Play This Scene" -msgstr "" +msgstr "Mängi seda stseeni" #: editor/editor_node.cpp msgid "Close Tab" @@ -2553,7 +2548,7 @@ msgstr "" #: editor/editor_node.cpp msgid "Dock Position" -msgstr "" +msgstr "Doki asukoht" #: editor/editor_node.cpp msgid "Distraction Free Mode" @@ -2565,11 +2560,11 @@ msgstr "" #: editor/editor_node.cpp msgid "Add a new scene." -msgstr "" +msgstr "Lisa uus stseen." #: editor/editor_node.cpp msgid "Scene" -msgstr "" +msgstr "Stseen" #: editor/editor_node.cpp msgid "Go to previously opened scene." @@ -2598,27 +2593,27 @@ msgstr "" #: editor/editor_node.cpp msgid "New Scene" -msgstr "" +msgstr "Uus stseen" #: editor/editor_node.cpp msgid "New Inherited Scene..." -msgstr "" +msgstr "Uus päritud stseen..." #: editor/editor_node.cpp msgid "Open Scene..." -msgstr "" +msgstr "Ava stseen..." #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp msgid "Open Recent" -msgstr "" +msgstr "Hiljuti avatud" #: editor/editor_node.cpp msgid "Save Scene" -msgstr "" +msgstr "Salvesta stseen" #: editor/editor_node.cpp msgid "Save All Scenes" -msgstr "" +msgstr "Salvesta kõik stseenid" #: editor/editor_node.cpp msgid "Convert To..." @@ -2635,12 +2630,12 @@ msgstr "" #: editor/editor_node.cpp editor/plugins/script_text_editor.cpp #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp msgid "Undo" -msgstr "" +msgstr "Võta tagasi" #: editor/editor_node.cpp editor/plugins/script_text_editor.cpp #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp msgid "Redo" -msgstr "" +msgstr "Tee uuesti" #: editor/editor_node.cpp msgid "Miscellaneous project or scene-wide tools." @@ -2649,11 +2644,11 @@ msgstr "" #: editor/editor_node.cpp editor/project_manager.cpp #: editor/script_create_dialog.cpp msgid "Project" -msgstr "" +msgstr "Projekt" #: editor/editor_node.cpp msgid "Project Settings..." -msgstr "" +msgstr "Projekti sätted..." #: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp msgid "Version Control" @@ -2669,7 +2664,7 @@ msgstr "" #: editor/editor_node.cpp msgid "Export..." -msgstr "" +msgstr "Ekspordi..." #: editor/editor_node.cpp msgid "Install Android Build Template..." @@ -2681,7 +2676,7 @@ msgstr "" #: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp msgid "Tools" -msgstr "" +msgstr "Tööriistad" #: editor/editor_node.cpp msgid "Orphan Resource Explorer..." @@ -2694,7 +2689,7 @@ msgstr "" #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp #: editor/project_export.cpp msgid "Debug" -msgstr "" +msgstr "Silumine" #: editor/editor_node.cpp msgid "Deploy with Remote Debug" @@ -2766,19 +2761,19 @@ msgstr "" #: editor/editor_node.cpp editor/script_create_dialog.cpp msgid "Editor" -msgstr "" +msgstr "Redaktor" #: editor/editor_node.cpp msgid "Editor Settings..." -msgstr "" +msgstr "Redaktori sätted..." #: editor/editor_node.cpp msgid "Editor Layout" -msgstr "" +msgstr "Redaktori paigutus" #: editor/editor_node.cpp msgid "Take Screenshot" -msgstr "" +msgstr "Tee ekraanipilt" #: editor/editor_node.cpp msgid "Screenshots are stored in the Editor Data/Settings Folder." @@ -2814,7 +2809,7 @@ msgstr "" #: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp msgid "Help" -msgstr "" +msgstr "Abi" #: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp #: editor/plugins/script_editor_plugin.cpp @@ -2823,68 +2818,68 @@ msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp #: editor/project_settings_editor.cpp editor/rename_dialog.cpp msgid "Search" -msgstr "" +msgstr "Otsi" #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp #: editor/plugins/shader_editor_plugin.cpp msgid "Online Docs" -msgstr "" +msgstr "Veebidokumentatsioonid" #: editor/editor_node.cpp msgid "Q&A" -msgstr "" +msgstr "Küsimused & vastused" #: editor/editor_node.cpp msgid "Report a Bug" -msgstr "" +msgstr "Teavita veast" #: editor/editor_node.cpp msgid "Send Docs Feedback" -msgstr "" +msgstr "Saada dokumentatsioonide tagasisede" #: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp msgid "Community" -msgstr "" +msgstr "Kogukond" #: editor/editor_node.cpp msgid "About" -msgstr "" +msgstr "Teave" #: editor/editor_node.cpp msgid "Play the project." -msgstr "" +msgstr "Mängi projekti." #: editor/editor_node.cpp msgid "Play" -msgstr "" +msgstr "Mängi" #: editor/editor_node.cpp msgid "Pause the scene execution for debugging." -msgstr "" +msgstr "Peata stseeni töö selle silumiseks." #: editor/editor_node.cpp msgid "Pause Scene" -msgstr "" +msgstr "Peata stseen" #: editor/editor_node.cpp msgid "Stop the scene." -msgstr "" +msgstr "Lõpeta stseen." #: editor/editor_node.cpp msgid "Play the edited scene." -msgstr "" +msgstr "Mängi redigeeritud stseeni." #: editor/editor_node.cpp msgid "Play Scene" -msgstr "" +msgstr "Mängi stseeni" #: editor/editor_node.cpp msgid "Play custom scene" -msgstr "" +msgstr "Mängi kohandatud stseeni" #: editor/editor_node.cpp msgid "Play Custom Scene" -msgstr "" +msgstr "Mängi kohandatud stseeni" #: editor/editor_node.cpp msgid "Changing the video driver requires restarting the editor." @@ -2913,19 +2908,19 @@ msgstr "" #: editor/editor_node.cpp msgid "FileSystem" -msgstr "" +msgstr "Failikuvaja" #: editor/editor_node.cpp msgid "Inspector" -msgstr "" +msgstr "Ãœlevaataja" #: editor/editor_node.cpp msgid "Expand Bottom Panel" -msgstr "" +msgstr "Laienda alumist paneeli" #: editor/editor_node.cpp msgid "Output" -msgstr "" +msgstr "Väljund" #: editor/editor_node.cpp msgid "Don't Save" @@ -3016,7 +3011,7 @@ msgstr "" #: editor/editor_node.h msgid "Warning!" -msgstr "" +msgstr "Hoiatus!" #: editor/editor_path.cpp msgid "No sub-resources found." @@ -3606,7 +3601,7 @@ msgstr "" #: editor/project_manager.cpp editor/rename_dialog.cpp #: editor/scene_tree_dock.cpp msgid "Rename" -msgstr "" +msgstr "Nimeta ümber" #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3626,7 +3621,7 @@ msgstr "" #: editor/filesystem_dock.cpp msgid "Search files" -msgstr "" +msgstr "Otsi faile" #: editor/filesystem_dock.cpp msgid "" @@ -3688,7 +3683,7 @@ msgstr "" #: editor/find_in_files.cpp editor/progress_dialog.cpp scene/gui/dialogs.cpp msgid "Cancel" -msgstr "" +msgstr "Tühista" #: editor/find_in_files.cpp msgid "Find: " @@ -3704,7 +3699,7 @@ msgstr "" #: editor/find_in_files.cpp msgid "Searching..." -msgstr "" +msgstr "Otsin..." #: editor/find_in_files.cpp msgid "Search complete" @@ -3736,7 +3731,7 @@ msgstr "" #: editor/groups_editor.cpp editor/node_dock.cpp msgid "Groups" -msgstr "" +msgstr "Rühmad" #: editor/groups_editor.cpp msgid "Nodes Not in Group" @@ -3745,7 +3740,7 @@ msgstr "" #: editor/groups_editor.cpp editor/scene_tree_dock.cpp #: editor/scene_tree_editor.cpp msgid "Filter nodes" -msgstr "" +msgstr "Filtreeri sõlmed" #: editor/groups_editor.cpp msgid "Nodes in Group" @@ -3761,7 +3756,7 @@ msgstr "" #: editor/groups_editor.cpp msgid "Manage Groups" -msgstr "" +msgstr "Halda gruppe" #: editor/import/resource_importer_scene.cpp msgid "Import as Single Scene" @@ -3858,15 +3853,15 @@ msgstr "" #: editor/import_dock.cpp msgid "Import As:" -msgstr "" +msgstr "Impordi kui:" #: editor/import_dock.cpp msgid "Preset" -msgstr "" +msgstr "Eelseadistus" #: editor/import_dock.cpp msgid "Reimport" -msgstr "" +msgstr "Taasimpordi" #: editor/import_dock.cpp msgid "Save Scenes, Re-Import, and Restart" @@ -3932,7 +3927,7 @@ msgstr "" #: editor/inspector_dock.cpp msgid "Save the currently edited resource." -msgstr "" +msgstr "Salvesta käesolevalt muudetud ressurss." #: editor/inspector_dock.cpp msgid "Go to the previous edited object in history." @@ -3944,15 +3939,15 @@ msgstr "" #: editor/inspector_dock.cpp msgid "History of recently edited objects." -msgstr "" +msgstr "Hiljuti muudetud objektide ajalugu." #: editor/inspector_dock.cpp msgid "Object properties." -msgstr "" +msgstr "Objekti atribuudid." #: editor/inspector_dock.cpp msgid "Filter properties" -msgstr "" +msgstr "Filtreeri atribuudid" #: editor/inspector_dock.cpp msgid "Changes may be lost!" @@ -4306,16 +4301,16 @@ msgstr "" #: editor/plugins/animation_player_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Delete Animation?" -msgstr "" +msgstr "Kustuta animatsioon?" #: editor/plugins/animation_player_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Remove Animation" -msgstr "" +msgstr "Eemalda animatioon" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Invalid animation name!" -msgstr "" +msgstr "Vigane animatsiooni nimi!" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Animation name already exists!" @@ -4392,7 +4387,7 @@ msgstr "" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Animation Tools" -msgstr "" +msgstr "Animatsiooni tööriistad" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Animation" @@ -4404,7 +4399,7 @@ msgstr "" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Open in Inspector" -msgstr "" +msgstr "Ava ülevaatajas" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Display list of animations in player." @@ -4841,11 +4836,11 @@ msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Recently Updated" -msgstr "" +msgstr "Hiljuti uuendatud" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Least Recently Updated" -msgstr "" +msgstr "Vanim uuendus" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Name (A-Z)" @@ -4857,11 +4852,11 @@ msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp msgid "License (A-Z)" -msgstr "" +msgstr "Litsents (A-Z)" #: editor/plugins/asset_library_editor_plugin.cpp msgid "License (Z-A)" -msgstr "" +msgstr "Litsents (Z-A)" #: editor/plugins/asset_library_editor_plugin.cpp msgid "First" @@ -4897,28 +4892,28 @@ msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp msgid "Sort:" -msgstr "" +msgstr "Sordi:" #: editor/plugins/asset_library_editor_plugin.cpp #: editor/project_settings_editor.cpp msgid "Category:" -msgstr "" +msgstr "Kategooria:" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Site:" -msgstr "" +msgstr "Veebisait:" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Support" -msgstr "" +msgstr "Toetus" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Official" -msgstr "" +msgstr "Ametlik" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Testing" -msgstr "" +msgstr "Testimine" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Loading..." @@ -6625,7 +6620,7 @@ msgstr "" #: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp msgid "Run" -msgstr "" +msgstr "Käivita" #: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp msgid "Step Into" @@ -6690,7 +6685,7 @@ msgstr "" #: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp msgid "Debugger" -msgstr "" +msgstr "Siluja" #: editor/plugins/script_editor_plugin.cpp msgid "Search Results" @@ -6853,7 +6848,7 @@ msgstr "" #: editor/plugins/script_text_editor.cpp msgid "Contextual Help" -msgstr "" +msgstr "Kontekstuaalne abi" #: editor/plugins/script_text_editor.cpp msgid "Toggle Bookmark" @@ -6952,7 +6947,7 @@ msgstr "" #: editor/plugins/spatial_editor_plugin.cpp msgid "Perspective" -msgstr "" +msgstr "Perspektiiv" #: editor/plugins/spatial_editor_plugin.cpp msgid "Transform Aborted." @@ -6996,35 +6991,35 @@ msgstr "" #: editor/plugins/spatial_editor_plugin.cpp msgid "Pitch" -msgstr "" +msgstr "Frontaal" #: editor/plugins/spatial_editor_plugin.cpp msgid "Yaw" -msgstr "" +msgstr "Sagitaal" #: editor/plugins/spatial_editor_plugin.cpp msgid "Objects Drawn" -msgstr "" +msgstr "Objekte kuvatud" #: editor/plugins/spatial_editor_plugin.cpp msgid "Material Changes" -msgstr "" +msgstr "Materjali muutused" #: editor/plugins/spatial_editor_plugin.cpp msgid "Shader Changes" -msgstr "" +msgstr "Varjutaja muutused" #: editor/plugins/spatial_editor_plugin.cpp msgid "Surface Changes" -msgstr "" +msgstr "Pinna muutused" #: editor/plugins/spatial_editor_plugin.cpp msgid "Draw Calls" -msgstr "" +msgstr "Kuvamise kutsungid" #: editor/plugins/spatial_editor_plugin.cpp msgid "Vertices" -msgstr "" +msgstr "Tipud" #: editor/plugins/spatial_editor_plugin.cpp msgid "Top View." @@ -7112,7 +7107,7 @@ msgstr "" #: editor/plugins/spatial_editor_plugin.cpp msgid "View Environment" -msgstr "" +msgstr "Kuva keskkond" #: editor/plugins/spatial_editor_plugin.cpp msgid "View Gizmos" @@ -7120,7 +7115,7 @@ msgstr "" #: editor/plugins/spatial_editor_plugin.cpp msgid "View Information" -msgstr "" +msgstr "Kuva informatsioon" #: editor/plugins/spatial_editor_plugin.cpp msgid "View FPS" @@ -7128,7 +7123,7 @@ msgstr "" #: editor/plugins/spatial_editor_plugin.cpp msgid "Half Resolution" -msgstr "" +msgstr "Poolresolutioon" #: editor/plugins/spatial_editor_plugin.cpp msgid "Audio Listener" @@ -7140,7 +7135,7 @@ msgstr "" #: editor/plugins/spatial_editor_plugin.cpp msgid "Cinematic Preview" -msgstr "" +msgstr "Kinemaatiline eelvaade" #: editor/plugins/spatial_editor_plugin.cpp msgid "Not available when using the GLES2 renderer." @@ -7226,27 +7221,27 @@ msgstr "" #: editor/plugins/spatial_editor_plugin.cpp msgid "Bottom View" -msgstr "" +msgstr "Altvaade" #: editor/plugins/spatial_editor_plugin.cpp msgid "Top View" -msgstr "" +msgstr "Ãœlavaade" #: editor/plugins/spatial_editor_plugin.cpp msgid "Rear View" -msgstr "" +msgstr "Tagavaade" #: editor/plugins/spatial_editor_plugin.cpp msgid "Front View" -msgstr "" +msgstr "Eesvaade" #: editor/plugins/spatial_editor_plugin.cpp msgid "Left View" -msgstr "" +msgstr "Vasakvaade" #: editor/plugins/spatial_editor_plugin.cpp msgid "Right View" -msgstr "" +msgstr "Paremvaade" #: editor/plugins/spatial_editor_plugin.cpp msgid "Switch Perspective/Orthogonal View" @@ -7258,11 +7253,11 @@ msgstr "" #: editor/plugins/spatial_editor_plugin.cpp msgid "Focus Origin" -msgstr "" +msgstr "Fookuse alge" #: editor/plugins/spatial_editor_plugin.cpp msgid "Focus Selection" -msgstr "" +msgstr "Fookuse valik" #: editor/plugins/spatial_editor_plugin.cpp msgid "Toggle Freelook" @@ -7540,7 +7535,7 @@ msgstr "" #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Loop" -msgstr "" +msgstr "Kordus" #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Animation Frames:" @@ -9516,11 +9511,11 @@ msgstr "" #: editor/project_manager.cpp msgid "Project Manager" -msgstr "" +msgstr "projektihaldur" #: editor/project_manager.cpp msgid "Projects" -msgstr "" +msgstr "Projektid" #: editor/project_manager.cpp msgid "Last Modified" @@ -9528,7 +9523,7 @@ msgstr "" #: editor/project_manager.cpp msgid "Scan" -msgstr "" +msgstr "Otsi" #: editor/project_manager.cpp msgid "Select a Folder to Scan" @@ -9536,7 +9531,7 @@ msgstr "" #: editor/project_manager.cpp msgid "New Project" -msgstr "" +msgstr "Uus projekt" #: editor/project_manager.cpp msgid "Remove Missing" @@ -9544,7 +9539,7 @@ msgstr "" #: editor/project_manager.cpp msgid "Templates" -msgstr "" +msgstr "Mallid" #: editor/project_manager.cpp msgid "Restart Now" @@ -9789,11 +9784,11 @@ msgstr "" #: editor/project_settings_editor.cpp msgid "Project Settings (project.godot)" -msgstr "" +msgstr "Projekti sätted (project.godot)" #: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp msgid "General" -msgstr "" +msgstr "Ãœldine" #: editor/project_settings_editor.cpp msgid "Override For..." @@ -10159,6 +10154,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Kustuta Võti (Võtmed)" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Kustuta Võti (Võtmed)" @@ -10221,7 +10221,7 @@ msgstr "" #: editor/scene_tree_dock.cpp msgid "User Interface" -msgstr "" +msgstr "Kasutajaliides" #: editor/scene_tree_dock.cpp msgid "Other Node" @@ -10290,7 +10290,7 @@ msgstr "" #: editor/scene_tree_dock.cpp msgid "Add Child Node" -msgstr "" +msgstr "Lisa alamsõlm" #: editor/scene_tree_dock.cpp msgid "Expand/Collapse All" @@ -10326,7 +10326,7 @@ msgstr "" #: editor/scene_tree_dock.cpp msgid "Add/Create a New Node." -msgstr "" +msgstr "Lisa/loo uus sõlm." #: editor/scene_tree_dock.cpp msgid "" @@ -10336,7 +10336,7 @@ msgstr "" #: editor/scene_tree_dock.cpp msgid "Attach a new or existing script to the selected node." -msgstr "" +msgstr "Kinnita uus või olemasolev skript valitud sõlmele." #: editor/scene_tree_dock.cpp msgid "Detach the script from the selected node." @@ -10723,15 +10723,15 @@ msgstr "" #: editor/settings_config_dialog.cpp msgid "Editor Settings" -msgstr "" +msgstr "Redaktori sätted" #: editor/settings_config_dialog.cpp msgid "Shortcuts" -msgstr "" +msgstr "Kiirklahvid" #: editor/settings_config_dialog.cpp msgid "Binding" -msgstr "" +msgstr "Kombinatsioon" #: editor/spatial_editor_gizmos.cpp msgid "Change Light Radius" @@ -11767,6 +11767,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12160,7 +12166,7 @@ msgstr "" #: scene/gui/dialogs.cpp msgid "Please Confirm..." -msgstr "" +msgstr "Palun kinnita..." #: scene/gui/popup.cpp msgid "" diff --git a/editor/translations/eu.po b/editor/translations/eu.po index e461c0f1ec..906a258f32 100644 --- a/editor/translations/eu.po +++ b/editor/translations/eu.po @@ -2255,10 +2255,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10132,6 +10128,10 @@ msgid "Make node as Root" msgstr "" #: editor/scene_tree_dock.cpp +msgid "Delete %d nodes and any children?" +msgstr "" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "" @@ -11735,6 +11735,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/fa.po b/editor/translations/fa.po index 428b69062a..dc7ae9ec69 100644 --- a/editor/translations/fa.po +++ b/editor/translations/fa.po @@ -13,12 +13,13 @@ # hpn33 <hamed.hpn332@gmail.com>, 2019, 2020. # Focus <saeeddashticlash@gmail.com>, 2019, 2020. # mohamad por <mohamad24xx@gmail.com>, 2020. +# Tetra Homer <tetrahomer@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-04-23 20:21+0000\n" -"Last-Translator: Focus <saeeddashticlash@gmail.com>\n" +"PO-Revision-Date: 2020-07-21 13:41+0000\n" +"Last-Translator: Tetra Homer <tetrahomer@gmail.com>\n" "Language-Team: Persian <https://hosted.weblate.org/projects/godot-engine/" "godot/fa/>\n" "Language: fa\n" @@ -26,14 +27,12 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.0.2-dev\n" +"X-Generator: Weblate 4.2-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Invalid type argument to convert(), use TYPE_* constants." -msgstr "" -"نوع ورودی برای متد ()convert ‌ نامعتبر است ،‌ از ثابت های *_TYPE‌ استÙاده " -"کنید ." +msgstr "نوع ورودی برای ()convert نامعتبر است, ثوابت *_TYPE‌ بکار گیرید ." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." @@ -53,61 +52,59 @@ msgstr "ورودی نامعتبر i% (تایید نشده) در عبارت" #: core/math/expression.cpp msgid "self can't be used because instance is null (not passed)" -msgstr "نمی توان از self استÙاده کرد چون instance = null هست (تایید نشده)" +msgstr "نمی توان self را بکار گرÙت چون instance = null هست (تایید نشده)" #: core/math/expression.cpp -#, fuzzy msgid "Invalid operands to operator %s, %s and %s." -msgstr "نام دارایی ایندکس نامعتبر 's%' در گره s%." +msgstr "عملگر های نامعتبر به عملگر %s, %s Ùˆ %s." #: core/math/expression.cpp -#, fuzzy msgid "Invalid index of type %s for base type %s" -msgstr "نام دارایی ایندکس نامعتبر 's%' در گره s%." +msgstr "نوع ایندکس %s برای نوع اصلی %s نامعتبر است" #: core/math/expression.cpp msgid "Invalid named index '%s' for base type %s" -msgstr "شاخص نامگذاری شده \"Ùª s\" برای نوع پایه٪ s نامعتبر است" +msgstr "ایندکس اسمی '%s' برای نوع اصلی %s نامعتبر است" #: core/math/expression.cpp msgid "Invalid arguments to construct '%s'" -msgstr ": آرگومان نوع نامعتبر آرگومان های نامعتبر برای ساخت 'Ùª s'" +msgstr "آرگومان های نامعتبر برای ساخت '%s'" #: core/math/expression.cpp msgid "On call to '%s':" -msgstr "در تماس با 'Ùª s':" +msgstr "به هنگام Ùراخوان تابع'%s':" #: core/ustring.cpp msgid "B" -msgstr "" +msgstr "بایت" #: core/ustring.cpp msgid "KiB" -msgstr "" +msgstr "کیلوبایت" #: core/ustring.cpp msgid "MiB" -msgstr "" +msgstr "مگابایت" #: core/ustring.cpp msgid "GiB" -msgstr "" +msgstr "گیگابایت" #: core/ustring.cpp msgid "TiB" -msgstr "" +msgstr "ترابایت" #: core/ustring.cpp msgid "PiB" -msgstr "" +msgstr "پتابایت" #: core/ustring.cpp msgid "EiB" -msgstr "" +msgstr "اگزابایت" #: editor/animation_bezier_editor.cpp msgid "Free" -msgstr "ازاد کردن" +msgstr "آزاد کردن" #: editor/animation_bezier_editor.cpp msgid "Balanced" @@ -123,90 +120,84 @@ msgstr "زمان:" #: editor/animation_bezier_editor.cpp msgid "Value:" -msgstr "ارزش:" +msgstr "مقدار:" #: editor/animation_bezier_editor.cpp msgid "Insert Key Here" -msgstr "کلید را اینجا وارد Ú©Ù†" +msgstr "کلید را اینجا وارد کنید" #: editor/animation_bezier_editor.cpp msgid "Duplicate Selected Key(s)" -msgstr "کلیدهای انتخاب شده تکراری درست Ú©Ù†" +msgstr "تکرار کلید(های) منتخب" #: editor/animation_bezier_editor.cpp msgid "Delete Selected Key(s)" -msgstr "کلید‌های انخاب شده را پاک Ú©Ù†" +msgstr "Øذ٠کلید(های) منتخب" #: editor/animation_bezier_editor.cpp msgid "Add Bezier Point" -msgstr "Bezier Point را اضاÙÙ‡ Ú©Ù†" +msgstr "اÙزودن نقطه بÙزیÙر" #: editor/animation_bezier_editor.cpp msgid "Move Bezier Points" -msgstr "Bezier Points را جابجا Ú©Ù†" +msgstr "انتقال نقاط بÙزیÙر" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Duplicate Keys" -msgstr "تکرار کلید‌های انیمیشن" +msgstr "تکرار کلید ‌های متØرک" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Delete Keys" -msgstr "کلیدها را در انیمیشن ØØ°Ù Ú©Ù†" +msgstr "Øذ٠کلید های متØرک" #: editor/animation_track_editor.cpp msgid "Anim Change Keyframe Time" -msgstr "تغییر زمان Ùریم کلید در انیمیشن" +msgstr "تغییر زمان Ù„Øظه‌کلید٠متØرک" #: editor/animation_track_editor.cpp msgid "Anim Change Transition" -msgstr "انتقال را در انیمیشن تغییر بده" +msgstr "تغییر انتقالی متØرک" #: editor/animation_track_editor.cpp msgid "Anim Change Transform" -msgstr "انتقال را در انیمیشن تغییر بده" +msgstr "تغییر دگرشکل متØرک" #: editor/animation_track_editor.cpp msgid "Anim Change Keyframe Value" -msgstr "تغییر مقدار Ùریم کلید در انیمیشن" +msgstr "تغییر مقدار Ù„Øظه‌کلید متØرک" #: editor/animation_track_editor.cpp msgid "Anim Change Call" -msgstr "Ùراخوانی را در انیمیشن تغییر بده" +msgstr "تغییر Ùراخوان متØرک" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Keyframe Time" -msgstr "تغییر زمان Ùریم کلید در انیمیشن" +msgstr "تغییرات زمان Ù„Øظه‌کلید متØرک" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Transition" -msgstr "انتقال را در انیمیشن تغییر بده" +msgstr "تغییرات انتقالی متØرک" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Transform" -msgstr "انتقال را در انیمیشن تغییر بده" +msgstr "تغییرات دگرشکل متØرک" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Keyframe Value" -msgstr "تغییر مقدار Ùریم کلید در انیمیشن" +msgstr "تغییرات مقدار Ù„Øظه‌کلید متØرک" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Call" -msgstr "Ùراخوانی را در انیمیشن تغییر بده" +msgstr "تغییرات Ùراخوان متØرک" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Change Animation Length" -msgstr "طول انیمیشن را تغییر بده" +msgstr "تغییر طول انیمیشن" #: editor/animation_track_editor.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Change Animation Loop" -msgstr "Øلقه(loop) انیمیشن را تغییر دهید" +msgstr "تغییر Øلقه(loop) انیمیشن" #: editor/animation_track_editor.cpp msgid "Property Track" @@ -214,15 +205,15 @@ msgstr "ویژگی مسیر" #: editor/animation_track_editor.cpp msgid "3D Transform Track" -msgstr "مسیر 3D Transform" +msgstr "مسیر دگرشکل 3D" #: editor/animation_track_editor.cpp msgid "Call Method Track" -msgstr "صدا زدن Method Track" +msgstr "Ùراخوان تابع مسیر" #: editor/animation_track_editor.cpp msgid "Bezier Curve Track" -msgstr "" +msgstr "مسیر منØÙ†ÛŒ بÙزیÙر" #: editor/animation_track_editor.cpp msgid "Audio Playback Track" @@ -267,7 +258,7 @@ msgstr "تغییرمیسر path" #: editor/animation_track_editor.cpp msgid "Toggle this track on/off." -msgstr "روشن / خاموش کردن این Track." +msgstr "دÙگرØالت٠روشن/خاموش این قطعه." #: editor/animation_track_editor.cpp msgid "Update Mode (How this property is set)" @@ -336,9 +327,8 @@ msgid "Insert Key" msgstr "درج کلید" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Duplicate Key(s)" -msgstr "نسخه همانند (Duplicate ) کلید(key)" +msgstr "تکرار کلید(ها)" #: editor/animation_track_editor.cpp msgid "Delete Key(s)" @@ -366,7 +356,7 @@ msgstr "یک ترک جدید برای s% بساز Ùˆ کلید را درج کن؟ #: editor/animation_track_editor.cpp msgid "Create %d NEW tracks and insert keys?" -msgstr "ساختن تعداد d% ترک جدید، ودرج کلیدها؟" +msgstr "ساختن %d قطعه جدید Ùˆ درج کلیدها؟" #: editor/animation_track_editor.cpp editor/create_dialog.cpp #: editor/editor_audio_buses.cpp editor/editor_feature_profile.cpp @@ -430,7 +420,7 @@ msgstr "" #: editor/animation_track_editor.cpp msgid "An animation player can't animate itself, only other players." -msgstr "" +msgstr "یک مجری انیمیشن نمی تواند خود را Ù…Øرک کند، Ùقط سایر مجریان." #: editor/animation_track_editor.cpp msgid "Not possible to add a new track without a root" @@ -438,66 +428,60 @@ msgstr "بدون ریشه اضاÙÙ‡ کردن مسیر امکان پذیر Ù†ÛŒØ #: editor/animation_track_editor.cpp msgid "Invalid track for Bezier (no suitable sub-properties)" -msgstr "" +msgstr "مسیر نامعتبر برای بÙزیÙر( زیر-خواص نامناسب)" #: editor/animation_track_editor.cpp msgid "Add Bezier Track" -msgstr "ترک Bezier را اضاÙÙ‡ Ú©Ù†" +msgstr "اÙزودن مسیر بÙزیÙر" #: editor/animation_track_editor.cpp msgid "Track path is invalid, so can't add a key." -msgstr "" +msgstr "مسیر قطعه نامعتبر، پس نمی‌توان یک کلید به آن اÙزود." #: editor/animation_track_editor.cpp msgid "Track is not of type Spatial, can't insert key" msgstr "" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Add Transform Track Key" -msgstr "درج ترک Ùˆ کلید در انیمیشن" +msgstr "اÙزودن کلید مسیر دگرشکل" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Add Track Key" -msgstr "ترک را اضاÙÙ‡ Ú©Ù†" +msgstr "اÙزودن کلید مسیر" #: editor/animation_track_editor.cpp msgid "Track path is invalid, so can't add a method key." msgstr "" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Add Method Track Key" -msgstr "درج ترک Ùˆ کلید در انیمیشن" +msgstr "اÙزودن تابع کلید میسر" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Method not found in object: " -msgstr "VariableGet در اسکریپت پیدا نشد: " +msgstr "تابع در شئ یاÙت نشد: " #: editor/animation_track_editor.cpp msgid "Anim Move Keys" msgstr "کلیدها را در انیمیشن جابجا Ú©Ù†" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Clipboard is empty" -msgstr "ØاÙظه پنهان خالی است!" +msgstr "ØاÙظه پنهان خالی است" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Paste Tracks" -msgstr "مسیر به سمت گره:" +msgstr "جاگذاری مسیر ها" #: editor/animation_track_editor.cpp msgid "Anim Scale Keys" -msgstr "کلیدها را در انیمیشن تغییر مقیاس بده" +msgstr "اندازه کلید های متØرک" #: editor/animation_track_editor.cpp msgid "" "This option does not work for Bezier editing, as it's only a single track." -msgstr "" +msgstr "این گزینه برای Ø§ØµÙ„Ø§Ø Ø¨ÙزیÙر کار نمی کند, چون تنها یک مسیر واØد است." #: editor/animation_track_editor.cpp msgid "" @@ -511,42 +495,47 @@ msgid "" "Alternatively, use an import preset that imports animations to separate " "files." msgstr "" +"این انیمیشن متعلق به یک صØنه ورودی است, بنابراین تغییرات در مسیرهای ورودی " +"ذخیره نشده‌اند.\n" +"\n" +"برای امکان اضاÙÙ‡ کردن مسیر های سÙارشی, به تنظیمات ورودی صØنه بروید Ùˆ\n" +"\"انیمیشن > ذخیره‌سازی\" به \"پرونده ها\", \"انیمیشن > Ù†Ú¯Ù‡ داشتن مسیر های " +"سÙارشی\" را تنظیم Ùˆ Ùعال کنید، سپس ازنو-وارد کنید.\n" +"با وارد کردن از «پیش تعیین شده»ای Ú©Ù‡ انیمیشن ها را به صورت پرونده‌های جداگانه " +"وارد Ù…ÛŒ کند، می‌توانید این روش جایگزین را بکار گیرید." #: editor/animation_track_editor.cpp msgid "Warning: Editing imported animation" -msgstr "" +msgstr "هشدار: در Øال ویرایش انیمیشن وارد شده" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Select an AnimationPlayer node to create and edit animations." -msgstr "" -"یک AnimationPlayer از درخت صØنه انتخاب کنید تا انیمیشن‌ها را ویرایش کنید." +msgstr "یک گره AnimationPlayer را برای ایجاد Ùˆ ویرایش انیمیشن ها برگزینید." #: editor/animation_track_editor.cpp msgid "Only show tracks from nodes selected in tree." -msgstr "" +msgstr "Ùقط مسیرهای از گره های انتخاب شده در درخت نشان داده شود." #: editor/animation_track_editor.cpp msgid "Group tracks by node or display them as plain list." msgstr "" +"مسیرها را بر اساس گره گروه‌بندی کنید یا آن‌ها را به عنوان لیست ساده نمایش دهید." #: editor/animation_track_editor.cpp -#, fuzzy msgid "Snap:" -msgstr "گام(ها):" +msgstr "Ú†Ùت:" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Animation step value." -msgstr "گره انیمیشن" +msgstr "مقدار مرØله انیمیشن." #: editor/animation_track_editor.cpp msgid "Seconds" -msgstr "" +msgstr "ثانیه ها" #: editor/animation_track_editor.cpp msgid "FPS" -msgstr "" +msgstr "Ù„Øظه بر ثانیه" #: editor/animation_track_editor.cpp editor/editor_properties.cpp #: editor/plugins/polygon_2d_editor_plugin.cpp @@ -559,9 +548,8 @@ msgid "Edit" msgstr "ویرایش" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Animation properties." -msgstr "گره انیمیشن" +msgstr "خصوصیات انیمیشن." #: editor/animation_track_editor.cpp msgid "Copy Tracks" @@ -577,26 +565,23 @@ msgstr "از مکان‌نما تغییر مقیاس بده" #: editor/animation_track_editor.cpp modules/gridmap/grid_map_editor_plugin.cpp msgid "Duplicate Selection" -msgstr "انتخاب شده را به دو تا تکثیر Ú©Ù†" +msgstr "تکثیر برگزیده" #: editor/animation_track_editor.cpp msgid "Duplicate Transposed" -msgstr "ترانهاده را به دو تا تکثیر Ú©Ù†" +msgstr "تکثیر جابجایی" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Delete Selection" -msgstr "انتخاب شده را ØØ°Ù Ú©Ù†" +msgstr "Øذ٠برگزیده" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Go to Next Step" -msgstr "به گام بعدی برو" +msgstr "برو به گام بعد" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Go to Previous Step" -msgstr "به گام قبلی برو" +msgstr "برو به گام پیشین" #: editor/animation_track_editor.cpp msgid "Optimize Animation" @@ -612,7 +597,7 @@ msgstr "" #: editor/animation_track_editor.cpp msgid "Use Bezier Curves" -msgstr "" +msgstr "بکارگیری منØÙ†ÛŒ بÙزیÙر" #: editor/animation_track_editor.cpp msgid "Anim. Optimizer" @@ -659,9 +644,8 @@ msgid "Scale Ratio:" msgstr "نسبت تغییر مقیاس:" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Select Tracks to Copy" -msgstr "دارایی Setter را اضاÙÙ‡ Ú©Ù†" +msgstr "انتخاب میسرها جهت تکثیر" #: editor/animation_track_editor.cpp editor/editor_log.cpp #: editor/editor_properties.cpp @@ -670,17 +654,15 @@ msgstr "دارایی Setter را اضاÙÙ‡ Ú©Ù†" #: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp msgid "Copy" -msgstr "Ú©Ù¾ÛŒ کردن" +msgstr "Ú©Ù¾ÛŒ" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Select All/None" -msgstr "گره انتخاب" +msgstr "انتخاب همه/هیچ" #: editor/animation_track_editor_plugins.cpp -#, fuzzy msgid "Add Audio Track Clip" -msgstr "ترک را اضاÙÙ‡ Ú©Ù†" +msgstr "اÙزودن کلیپ آهنگ صوتی" #: editor/animation_track_editor_plugins.cpp msgid "Change Audio Track Clip Start Offset" @@ -711,18 +693,16 @@ msgid "Line Number:" msgstr "شماره خط:" #: editor/code_editor.cpp -#, fuzzy msgid "%d replaced." -msgstr "جایگزینی" +msgstr "%d جایگزین شده." #: editor/code_editor.cpp editor/editor_help.cpp msgid "%d match." -msgstr "" +msgstr "%d منطبق." #: editor/code_editor.cpp editor/editor_help.cpp -#, fuzzy msgid "%d matches." -msgstr "تطبیقی ندارد" +msgstr "%d هم‌خوانی." #: editor/code_editor.cpp editor/find_in_files.cpp msgid "Match Case" @@ -747,7 +727,7 @@ msgstr "تنها در قسمت انتخاب شده" #: editor/code_editor.cpp editor/plugins/script_text_editor.cpp #: editor/plugins/text_editor.cpp msgid "Standard" -msgstr "" +msgstr "استاندارد" #: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp msgid "Toggle Scripts Panel" @@ -757,17 +737,17 @@ msgstr "" #: editor/plugins/texture_region_editor_plugin.cpp #: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp msgid "Zoom In" -msgstr "بزرگنمایی بیشتر" +msgstr "بزرگنمایی" #: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/texture_region_editor_plugin.cpp #: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp msgid "Zoom Out" -msgstr "بزرگنمایی کمتر" +msgstr "کوچکنمایی" #: editor/code_editor.cpp msgid "Reset Zoom" -msgstr "بازنشانی بزرگنمایی" +msgstr "باز‌نشانی مقیاس" #: editor/code_editor.cpp msgid "Warnings" @@ -778,38 +758,31 @@ msgid "Line and column numbers." msgstr "" #: editor/connections_dialog.cpp -#, fuzzy msgid "Method in target node must be specified." -msgstr "متد در گره مقصد باید مشخص شده باشد!" +msgstr "تابع در گره مقصد باید مشخص شده باشد." #: editor/connections_dialog.cpp -#, fuzzy msgid "Method name must be a valid identifier." -msgstr "نام یک شناسه‌ی معتبر نیست:" +msgstr "اسم تابع باید یک شناسه‌ی معتبر باشد." #: editor/connections_dialog.cpp -#, fuzzy msgid "" "Target method not found. Specify a valid method or attach a script to the " "target node." msgstr "" -"متد هد٠پیدا نشد! لطÙا یک متد صØÛŒØ Ù…Ø´Ø®Øµ کنید یا یک اسکریپت به گره هد٠الØاق " -"کنید." +"متد هد٠پیدا نشد. یک تابع معتبر تعیین کنید یا یک اسکریپت به گره هد٠وصل کنید." #: editor/connections_dialog.cpp -#, fuzzy msgid "Connect to Node:" msgstr "اتصال به گره:" #: editor/connections_dialog.cpp -#, fuzzy msgid "Connect to Script:" -msgstr "اتصال به گره:" +msgstr "اتصال به اسکریپت:" #: editor/connections_dialog.cpp -#, fuzzy msgid "From Signal:" -msgstr "سیگنال ها:" +msgstr "از سیگنال:" #: editor/connections_dialog.cpp msgid "Scene does not contain any script." @@ -841,14 +814,12 @@ msgid "Extra Call Arguments:" msgstr "آرگومان‌های اضاÙÛŒ Ùراخوانی:" #: editor/connections_dialog.cpp -#, fuzzy msgid "Receiver Method:" -msgstr "انتخاب Øالت" +msgstr "روش گیرنده:" #: editor/connections_dialog.cpp -#, fuzzy msgid "Advanced" -msgstr "متعادل شده" +msgstr "پیشرÙته" #: editor/connections_dialog.cpp msgid "Deferred" @@ -868,9 +839,8 @@ msgid "Disconnects the signal after its first emission." msgstr "" #: editor/connections_dialog.cpp -#, fuzzy msgid "Cannot connect signal" -msgstr "اتصال سیگنال:" +msgstr "نمی توان سیگنال را متصل کرد" #: editor/connections_dialog.cpp editor/dependency_editor.cpp #: editor/export_template_manager.cpp editor/groups_editor.cpp @@ -891,9 +861,8 @@ msgid "Connect" msgstr "اتصال" #: editor/connections_dialog.cpp -#, fuzzy msgid "Signal:" -msgstr "سیگنال ها:" +msgstr "سیگنال:" #: editor/connections_dialog.cpp msgid "Connect '%s' to '%s'" @@ -904,9 +873,8 @@ msgid "Disconnect '%s' from '%s'" msgstr "'s%' را از 's%' جدا Ú©Ù†" #: editor/connections_dialog.cpp -#, fuzzy msgid "Disconnect all from signal: '%s'" -msgstr "'s%' را از 's%' جدا Ú©Ù†" +msgstr "جدا کردن همه از سیگنال: '%s'" #: editor/connections_dialog.cpp msgid "Connect..." @@ -918,14 +886,12 @@ msgid "Disconnect" msgstr "عدم اتصال" #: editor/connections_dialog.cpp -#, fuzzy msgid "Connect a Signal to a Method" -msgstr "اتصال سیگنال:" +msgstr "وصل یک سیگنال به یک تابع" #: editor/connections_dialog.cpp -#, fuzzy msgid "Edit Connection:" -msgstr "خطای اتصال" +msgstr "ویرایش اتصال:" #: editor/connections_dialog.cpp msgid "Are you sure you want to remove all connections from the \"%s\" signal?" @@ -940,19 +906,16 @@ msgid "Are you sure you want to remove all connections from this signal?" msgstr "" #: editor/connections_dialog.cpp -#, fuzzy msgid "Disconnect All" -msgstr "عدم اتصال" +msgstr "جدا کردن همه" #: editor/connections_dialog.cpp -#, fuzzy msgid "Edit..." -msgstr "ویرایش" +msgstr "ویرایش..." #: editor/connections_dialog.cpp -#, fuzzy msgid "Go To Method" -msgstr "روش ها" +msgstr "برو به تابع" #: editor/create_dialog.cpp msgid "Change %s Type" @@ -1004,22 +967,20 @@ msgid "Dependencies For:" msgstr "بستگی‌ها برای:" #: editor/dependency_editor.cpp -#, fuzzy msgid "" "Scene '%s' is currently being edited.\n" "Changes will only take effect when reloaded." msgstr "" -"صØنه‌ی 's%' در Øال Øاضر ویرایش شده است.\n" -"تغییرات مؤثر نخواهد بود مگر با بارگذاری مجدد." +"ویرایش صØنه 's%' شروع شده است.\n" +"تغییرات تنها وقتی جلوه گرند Ú©Ù‡ از نو بارگیری شوند." #: editor/dependency_editor.cpp -#, fuzzy msgid "" "Resource '%s' is in use.\n" "Changes will only take effect when reloaded." msgstr "" -"منابع 's%' در Øال استÙاده است.\n" -"تغییرات با بارگذاری مجدد مؤثر خواهد بود." +"منابع 's%' بکار رÙته‌اند.\n" +"تغییرات تنها وقتی جلوه گرند Ú©Ù‡ از نو بارگیری شوند." #: editor/dependency_editor.cpp #: modules/gdnative/gdnative_library_editor_plugin.cpp @@ -1066,9 +1027,8 @@ msgid "Owners Of:" msgstr "مالکانÙ:" #: editor/dependency_editor.cpp -#, fuzzy msgid "Remove selected files from the project? (Can't be restored)" -msgstr "آیا پرونده‌های انتخاب شده از پروژه Øذ٠شوند؟ (بدون undo)" +msgstr "آیا پرونده‌های انتخاب شده از Ø·Ø±Ø Øذ٠شوند؟ (نمی‌توان بازیابی کرد)" #: editor/dependency_editor.cpp msgid "" @@ -1089,9 +1049,8 @@ msgid "Error loading:" msgstr "خطا در بارگذاری:" #: editor/dependency_editor.cpp -#, fuzzy msgid "Load failed due to missing dependencies:" -msgstr "خطا در بارگذاری صØنه به دلیل بستگی‌های Ù…Ùقود:" +msgstr "به دلیل Ù…Ùقود شدن وابستگی‌ها بارگیری انجام نشد:" #: editor/dependency_editor.cpp editor/editor_node.cpp msgid "Open Anyway" @@ -1114,9 +1073,8 @@ msgid "Permanently delete %d item(s)? (No undo!)" msgstr "به طور دائمی تعداد 'd%' آیتم را Øذ٠کند؟ (بدون undo !)" #: editor/dependency_editor.cpp -#, fuzzy msgid "Show Dependencies" -msgstr "بستگی‌ها" +msgstr "نمایش وابستگی‌ها" #: editor/dependency_editor.cpp msgid "Orphan Resource Explorer" @@ -1176,11 +1134,11 @@ msgstr "مؤلÙان" #: editor/editor_about.cpp msgid "Platinum Sponsors" -msgstr "اسپانسر‌های پلاتینیوم (درجه Û±)" +msgstr "Øامیان پلاتینیÙÙ… (درجه Û±)" #: editor/editor_about.cpp msgid "Gold Sponsors" -msgstr "اسپانسر‌های طلایی (درجه Û²)" +msgstr "Øامیان طلایی (درجه Û²)" #: editor/editor_about.cpp msgid "Mini Sponsors" @@ -1207,9 +1165,8 @@ msgid "License" msgstr "مجوز" #: editor/editor_about.cpp -#, fuzzy msgid "Third-party Licenses" -msgstr "مجوز‌های شخص ثالث" +msgstr "مجوز های شخص-ثالث" #: editor/editor_about.cpp msgid "" @@ -1218,6 +1175,9 @@ msgid "" "is an exhaustive list of all such third-party components with their " "respective copyright statements and license terms." msgstr "" +"Godot Engine به تعدادی از کتابخانه های منبع باز Ùˆ شخص-ثالث رایگان متکی است " +"Ú©Ù‡ همگی با شرایط مجوز MIT سازگار هستند. در زیر لیستی جامع از کلیه مؤلÙÙ‡ های " +"شخص ثالث با بیانیه های ØÙ‚ Ú©Ù¾ÛŒ برداری مربوطه Ùˆ شرایط مجوز آنها قرار دارد." #: editor/editor_about.cpp msgid "All Components" @@ -1233,29 +1193,27 @@ msgstr "گواهینامه" #: editor/editor_asset_installer.cpp editor/project_manager.cpp msgid "Error opening package file, not in ZIP format." -msgstr "" +msgstr "خطای گشودن بسته بندی پرونده، به Ø´Ú©Ù„ ZIP نیست." #: editor/editor_asset_installer.cpp -#, fuzzy msgid "%s (Already Exists)" -msgstr "پیش از این وجود داشته است" +msgstr "%s (موجود است)" #: editor/editor_asset_installer.cpp msgid "Uncompressing Assets" -msgstr "عست های غیر Ùشرده" +msgstr "Ùشرده نشدن اَسÙت ها" #: editor/editor_asset_installer.cpp editor/project_manager.cpp msgid "The following files failed extraction from package:" -msgstr "" +msgstr "استخراج پرونده های زیر از بسته بندی انجام نشد:" #: editor/editor_asset_installer.cpp -#, fuzzy msgid "And %s more files." -msgstr "نمی‌تواند یک پوشه ایجاد شود." +msgstr "Ùˆ %s بیش تر پرونده ها." #: editor/editor_asset_installer.cpp editor/project_manager.cpp msgid "Package installed successfully!" -msgstr "" +msgstr "بسته با موÙقیت نصب شد!" #: editor/editor_asset_installer.cpp #: editor/plugins/asset_library_editor_plugin.cpp @@ -1263,9 +1221,8 @@ msgid "Success!" msgstr "موÙقیت!" #: editor/editor_asset_installer.cpp -#, fuzzy msgid "Package Contents:" -msgstr "Ù…Øتواها:" +msgstr "درون مایه های بسته بندی:" #: editor/editor_asset_installer.cpp editor/editor_node.cpp msgid "Install" @@ -1277,52 +1234,51 @@ msgstr "نصب کننده پکیج ها" #: editor/editor_audio_buses.cpp msgid "Speakers" -msgstr "" +msgstr "بلندگوها" #: editor/editor_audio_buses.cpp msgid "Add Effect" -msgstr "" +msgstr "اÙزودن جلوه" #: editor/editor_audio_buses.cpp msgid "Rename Audio Bus" -msgstr "" +msgstr "تغییر نام صوت گذرا" #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Change Audio Bus Volume" -msgstr "مقدار آرایه را تغییر بده" +msgstr "تغییر مقدار صدای خطی" #: editor/editor_audio_buses.cpp msgid "Toggle Audio Bus Solo" -msgstr "" +msgstr "دÙگرØالت٠صدای تکی خطی" #: editor/editor_audio_buses.cpp msgid "Toggle Audio Bus Mute" -msgstr "" +msgstr "دÙگرØالت٠صدای سکوت خطی" #: editor/editor_audio_buses.cpp msgid "Toggle Audio Bus Bypass Effects" -msgstr "" +msgstr "دÙگرØالت٠صدای جلوه های میان بر خطی" #: editor/editor_audio_buses.cpp msgid "Select Audio Bus Send" -msgstr "" +msgstr "انتخاب صدای ارسال گذرا" #: editor/editor_audio_buses.cpp msgid "Add Audio Bus Effect" -msgstr "" +msgstr "اÙزودن صدای جلوه خطی" #: editor/editor_audio_buses.cpp msgid "Move Bus Effect" -msgstr "" +msgstr "انتقال جلوه خطی" #: editor/editor_audio_buses.cpp msgid "Delete Bus Effect" -msgstr "Øذ٠اثر گذرا" +msgstr "Øذ٠جلوه خطی" #: editor/editor_audio_buses.cpp msgid "Drag & drop to rearrange." -msgstr "" +msgstr "برای چینش مجدد، بکشید Ùˆ رها کنید." #: editor/editor_audio_buses.cpp msgid "Solo" @@ -1351,7 +1307,7 @@ msgstr "بازنشانی Øجم" #: editor/editor_audio_buses.cpp msgid "Delete Effect" -msgstr "Øذ٠اثر" +msgstr "Øذ٠جلوه" #: editor/editor_audio_buses.cpp msgid "Audio" @@ -1366,24 +1322,20 @@ msgid "Master bus can't be deleted!" msgstr "" #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Delete Audio Bus" -msgstr "انیمیشن را بهینه‌سازی Ú©Ù†" +msgstr "Øذ٠صدای خطی" #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Duplicate Audio Bus" -msgstr "انتخاب شده را به دو تا تکثیر Ú©Ù†" +msgstr "تکثیر صدای خطی" #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Reset Bus Volume" -msgstr "بازنشانی بزرگنمایی" +msgstr "باز‌نشانی مقدار خطی" #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Move Audio Bus" -msgstr "کلید Add را جابجا Ú©Ù†" +msgstr "انتقال صدای خطی" #: editor/editor_audio_buses.cpp msgid "Save Audio Bus Layout As..." @@ -1410,9 +1362,8 @@ msgid "Invalid file, not an audio bus layout." msgstr "" #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Error saving file: %s" -msgstr "خطا در بارگذاری:" +msgstr "خطای ذخیره کردن پرونده: %s" #: editor/editor_audio_buses.cpp msgid "Add Bus" @@ -1461,23 +1412,20 @@ msgid "Valid characters:" msgstr "کاراکترهای معتبر:" #: editor/editor_autoload_settings.cpp -#, fuzzy msgid "Must not collide with an existing engine class name." -msgstr "نام نامعتبر. نباید با یک نام کلاس موجود در موتور برخوردی داشته باشد." +msgstr "نباید با یک نام کلاس موتور موجود برخورد کند." #: editor/editor_autoload_settings.cpp -#, fuzzy msgid "Must not collide with an existing built-in type name." -msgstr "نام نامعتبر. نباید یا یک نام نوع توکار برخوردی داشته باشد." +msgstr "نباید با یک نام نوع درون-ساز موجود برخورد کند." #: editor/editor_autoload_settings.cpp -#, fuzzy msgid "Must not collide with an existing global constant name." -msgstr "نام نامعتبر. نباید با نام یک ثابت سراسری موجود برخوردی داشته باشد." +msgstr "نباید با نام یک ثابت سراسری موجود برخوردی کند." #: editor/editor_autoload_settings.cpp msgid "Keyword cannot be used as an autoload name." -msgstr "" +msgstr "کلمه کلیدی نمی تواند به عنوان یک نام خودبارگیر بکار برده شود." #: editor/editor_autoload_settings.cpp msgid "Autoload '%s' already exists!" @@ -1553,9 +1501,8 @@ msgid "Updating scene..." msgstr "" #: editor/editor_data.cpp editor/editor_properties.cpp -#, fuzzy msgid "[empty]" -msgstr "(خالی)" +msgstr "[پوچ]" #: editor/editor_data.cpp msgid "[unsaved]" @@ -1644,91 +1591,76 @@ msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB." msgstr "" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "3D Editor" -msgstr "ویرایشگر" +msgstr "ویرایشگر 3بعدی" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Script Editor" -msgstr "گشودن ویرایشگر اسکریپت" +msgstr "ویرایشگر اسکریپت" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Asset Library" -msgstr "گشودن کتابخانه عست" +msgstr "کتابخانه دارایی" #: editor/editor_feature_profile.cpp msgid "Scene Tree Editing" msgstr "" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Import Dock" -msgstr "وارد کردن" +msgstr "وارد کردن لنگرگاه" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Node Dock" -msgstr "نام گره:" +msgstr "لنگرگاه گره:" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "FileSystem and Import Docks" -msgstr "سامانه پرونده" +msgstr "Ùایل‌سیستم Ùˆ وارد‌کردن لنگرگاه" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Erase profile '%s'? (no undo)" -msgstr "جایگزینی همه" +msgstr "پاک‌کردن نمایه '%s'? (عدم بازگردانی)" #: editor/editor_feature_profile.cpp msgid "Profile must be a valid filename and must not contain '.'" msgstr "" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Profile with this name already exists." -msgstr "بارگذاری خودکار 's%' هم اکنون موجود است!" +msgstr "نمایه با این نام در Øال Øاضر وجود دارد." #: editor/editor_feature_profile.cpp msgid "(Editor Disabled, Properties Disabled)" msgstr "" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "(Properties Disabled)" -msgstr "ویژگی:" +msgstr "(خصوصیات غیرÙعال شده)" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "(Editor Disabled)" -msgstr "غیرÙعال شده" +msgstr "(ویرایشگر غیرÙعال شده)" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Class Options:" -msgstr "توضیØ:" +msgstr "گزینه‌های کلاس:" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Enable Contextual Editor" -msgstr "گشودن ویرایشگر متن" +msgstr "Ùعال کردن ویرایشگر متنی" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Enabled Properties:" -msgstr "صاÙÛŒ کردن گره‌ها" +msgstr "خصوصیات Ùعال شده:" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Enabled Features:" -msgstr "Ùهرست متدها:" +msgstr "ویژگی های Ùعال شده:" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Enabled Classes:" -msgstr "جستجوی کلاسها" +msgstr "کلاس های Ùعال شده:" #: editor/editor_feature_profile.cpp msgid "File '%s' format is invalid, import aborted." @@ -1741,23 +1673,20 @@ msgid "" msgstr "" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Error saving profile to path: '%s'." -msgstr "خطای بارگذاری قلم." +msgstr "خطای ذخیره نمایه در مسیر: '%s'." #: editor/editor_feature_profile.cpp msgid "Unset" msgstr "" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Current Profile:" -msgstr "نسخه اخیر:" +msgstr "نمایه موجود:" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Make Current" -msgstr "تابع را بساز" +msgstr "ساختن جریان" #: editor/editor_feature_profile.cpp #: editor/plugins/animation_player_editor_plugin.cpp @@ -1775,73 +1704,61 @@ msgid "Export" msgstr "صدور" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Available Profiles:" -msgstr "گره های موجود:" +msgstr "نمایه‌های موجود:" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Class Options" -msgstr "توضیØات" +msgstr "گزینه های کلاس" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "New profile name:" -msgstr "نام گره:" +msgstr "نام نمایه جدید:" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Erase Profile" -msgstr "Ú©Ùندی در آغاز" +msgstr "پاک کردن نمایه" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Godot Feature Profile" -msgstr "مدیریت صدور قالب ها" +msgstr "ویژگی نمایه Godot" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Import Profile(s)" -msgstr "پروژه واردشده" +msgstr "وارد کردن نمایه(ها)" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Export Profile" -msgstr "صدور پروژه" +msgstr "صادر کردن نمایه" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Manage Editor Feature Profiles" -msgstr "مدیریت صدور قالب ها" +msgstr "مدیریت ویژگی نمایه‌های ویرایشگر" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp -#, fuzzy msgid "Select Current Folder" -msgstr "ساختن پوشه" +msgstr "برگزیدن پوشه موجود" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "File Exists, Overwrite?" msgstr "Ùایل وجود دارد، آیا بازنویسی شود؟" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp -#, fuzzy msgid "Select This Folder" -msgstr "انتخاب Øالت" +msgstr "برگزیدن این پوشه" #: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp msgid "Copy Path" msgstr "" #: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp -#, fuzzy msgid "Open in File Manager" -msgstr "باز شدن مدیر پروژه؟" +msgstr "گشودن در مدیر پرونده" #: editor/editor_file_dialog.cpp editor/editor_node.cpp #: editor/filesystem_dock.cpp editor/project_manager.cpp -#, fuzzy msgid "Show in File Manager" -msgstr "باز شدن مدیر پروژه؟" +msgstr "نمایش در مدیر پرونده" #: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp msgid "New Folder..." @@ -1924,29 +1841,24 @@ msgid "Move Favorite Down" msgstr "" #: editor/editor_file_dialog.cpp -#, fuzzy msgid "Go to previous folder." -msgstr "رÙتن به پوشه والد" +msgstr "برو به پوشه پیشین." #: editor/editor_file_dialog.cpp -#, fuzzy msgid "Go to next folder." -msgstr "رÙتن به پوشه والد" +msgstr "برو به پوشه بعد." #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp -#, fuzzy msgid "Go to parent folder." -msgstr "رÙتن به پوشه والد" +msgstr "برو به پوشه والد." #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp -#, fuzzy msgid "Refresh files." -msgstr "جستجوی کلاسها" +msgstr "نوسازی پرونده‌ها." #: editor/editor_file_dialog.cpp -#, fuzzy msgid "(Un)favorite current folder." -msgstr "ناتوان در ساختن پوشه." +msgstr "پوشه موجود (غیر)Ù…Øبوب." #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Toggle the visibility of hidden files." @@ -1976,7 +1888,7 @@ msgstr "پرونده:" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Must use a valid extension." -msgstr "باید از یک پسوند معتبر استÙاده شود." +msgstr "باید یک پسوند معتبر بکار گیرید." #: editor/editor_file_system.cpp msgid "ScanSources" @@ -2010,9 +1922,8 @@ msgid "Inherited by:" msgstr "به ارث رسیده به وسیله:" #: editor/editor_help.cpp -#, fuzzy msgid "Description" -msgstr "توضیØ:" +msgstr "توضیØ" #: editor/editor_help.cpp msgid "Online Tutorials" @@ -2020,25 +1931,23 @@ msgstr "" #: editor/editor_help.cpp msgid "Properties" -msgstr "" +msgstr "خصوصیات" #: editor/editor_help.cpp msgid "override:" msgstr "" #: editor/editor_help.cpp -#, fuzzy msgid "default:" -msgstr "پیشÙرض" +msgstr "پیش Ùرض:" #: editor/editor_help.cpp msgid "Methods" -msgstr "روش ها" +msgstr "توابع" #: editor/editor_help.cpp -#, fuzzy msgid "Theme Properties" -msgstr "صاÙÛŒ کردن گره‌ها" +msgstr "خصوصیات زمینه" #: editor/editor_help.cpp msgid "Enumerations" @@ -2046,17 +1955,15 @@ msgstr "شمارش ها" #: editor/editor_help.cpp msgid "Constants" -msgstr "ثابت ها" +msgstr "ثوابت" #: editor/editor_help.cpp -#, fuzzy msgid "Property Descriptions" -msgstr "توضیØات مشخصه:" +msgstr "توضیØات خصیصه" #: editor/editor_help.cpp -#, fuzzy msgid "(value)" -msgstr "ارزش:" +msgstr "(مقدار)" #: editor/editor_help.cpp msgid "" @@ -2065,9 +1972,8 @@ msgid "" msgstr "" #: editor/editor_help.cpp -#, fuzzy msgid "Method Descriptions" -msgstr "توضیØات" +msgstr "توضیØات تابع" #: editor/editor_help.cpp msgid "" @@ -2082,80 +1988,67 @@ msgstr "جستجوی راهنما" #: editor/editor_help_search.cpp msgid "Case Sensitive" -msgstr "Øساس به Øالت (Øرو٠لاتین)" +msgstr "Øساس به Øرو٠کوچک Ùˆ بزرگ" #: editor/editor_help_search.cpp -#, fuzzy msgid "Show Hierarchy" -msgstr "جستجو" +msgstr "نمایش سلسله‌مراتب" #: editor/editor_help_search.cpp -#, fuzzy msgid "Display All" -msgstr "جایگزینی همه" +msgstr "نشان دادن همه" #: editor/editor_help_search.cpp msgid "Classes Only" -msgstr "" +msgstr "تنها کلاس‌ها" #: editor/editor_help_search.cpp -#, fuzzy msgid "Methods Only" -msgstr "روش ها" +msgstr "تنها روش‌ها" #: editor/editor_help_search.cpp -#, fuzzy msgid "Signals Only" -msgstr "سیگنال‌ها" +msgstr "تنها سیگنال‌ها" #: editor/editor_help_search.cpp -#, fuzzy msgid "Constants Only" -msgstr "ثابت ها" +msgstr "تنها ثوابت" #: editor/editor_help_search.cpp -#, fuzzy msgid "Properties Only" -msgstr "ویژگی:" +msgstr "تنها خصوصیات" #: editor/editor_help_search.cpp -#, fuzzy msgid "Theme Properties Only" -msgstr "دارایی Setter را اضاÙÙ‡ Ú©Ù†" +msgstr "تنها خصوصیات زمینه" #: editor/editor_help_search.cpp -#, fuzzy msgid "Member Type" -msgstr "عضوها" +msgstr "نوع عضو" #: editor/editor_help_search.cpp -#, fuzzy msgid "Class" -msgstr "کلاس:" +msgstr "کلاس" #: editor/editor_help_search.cpp -#, fuzzy msgid "Method" -msgstr "روش ها" +msgstr "روش" #: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp -#, fuzzy msgid "Signal" -msgstr "سیگنال‌ها" +msgstr "سیگنال‌" #: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp msgid "Constant" msgstr "ثابت" #: editor/editor_help_search.cpp -#, fuzzy msgid "Property" -msgstr "ویژگی:" +msgstr "خصیصه" #: editor/editor_help_search.cpp -#, fuzzy msgid "Theme Property" -msgstr "صاÙÛŒ کردن گره‌ها" +msgstr "ویژگی زمینه" #: editor/editor_inspector.cpp editor/project_settings_editor.cpp msgid "Property:" @@ -2163,20 +2056,19 @@ msgstr "ویژگی:" #: editor/editor_inspector.cpp msgid "Set" -msgstr "" +msgstr "تعیین" #: editor/editor_inspector.cpp msgid "Set Multiple:" -msgstr "" +msgstr "تعیین چندگانه:" #: editor/editor_log.cpp msgid "Output:" msgstr "خروجی:" #: editor/editor_log.cpp editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Copy Selection" -msgstr "برداشتن انتخاب شده" +msgstr "Ú©Ù¾ÛŒ برگزیده" #: editor/editor_log.cpp editor/editor_network_profiler.cpp #: editor/editor_profiler.cpp editor/editor_properties.cpp @@ -2189,31 +2081,30 @@ msgid "Clear" msgstr "پاک کردن" #: editor/editor_log.cpp -#, fuzzy msgid "Clear Output" -msgstr "خروجی" +msgstr "پاک کردن خروجی" #: editor/editor_network_profiler.cpp editor/editor_node.cpp #: editor/editor_profiler.cpp msgid "Stop" -msgstr "" +msgstr "توقÙ" #: editor/editor_network_profiler.cpp editor/editor_profiler.cpp #: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp msgid "Start" -msgstr "" +msgstr "شروع" #: editor/editor_network_profiler.cpp msgid "%s/s" -msgstr "" +msgstr "%s/ثانیه" #: editor/editor_network_profiler.cpp msgid "Down" -msgstr "" +msgstr "پایین" #: editor/editor_network_profiler.cpp msgid "Up" -msgstr "" +msgstr "بالا" #: editor/editor_network_profiler.cpp editor/editor_node.cpp msgid "Node" @@ -2237,7 +2128,7 @@ msgstr "" #: editor/editor_node.cpp editor/project_manager.cpp msgid "New Window" -msgstr "" +msgstr "چارچوب جدید" #: editor/editor_node.cpp msgid "Imported resources can't be saved." @@ -2246,11 +2137,11 @@ msgstr "" #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp #: scene/gui/dialogs.cpp msgid "OK" -msgstr "مواÙقت" +msgstr "قبول" #: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp msgid "Error saving resource!" -msgstr "" +msgstr "خطای ذخیره سازی منبع!" #: editor/editor_node.cpp msgid "" @@ -2279,9 +2170,8 @@ msgid "Can't open '%s'. The file could have been moved or deleted." msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "Error while parsing '%s'." -msgstr "خطای بارگذاری قلم." +msgstr "خطا هنگام تجزیه '%s'." #: editor/editor_node.cpp msgid "Unexpected end of file '%s'." @@ -2292,9 +2182,8 @@ msgid "Missing '%s' or its dependencies." msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "Error while loading '%s'." -msgstr "خطای بارگذاری قلم." +msgstr "خطا هنگام تجزیه '%s'." #: editor/editor_node.cpp msgid "Saving Scene" @@ -2399,33 +2288,28 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" #: editor/editor_node.cpp editor/filesystem_dock.cpp msgid "Open Scene" -msgstr "باز کردن صØنه" +msgstr "گشودن صØنه" #: editor/editor_node.cpp msgid "Open Base Scene" -msgstr "" +msgstr "گشودن صØنه اصلی" #: editor/editor_node.cpp -#, fuzzy msgid "Quick Open..." -msgstr "باز Ú©Ù†" +msgstr "گشودن Ùوری..." #: editor/editor_node.cpp msgid "Quick Open Scene..." -msgstr "" +msgstr "گشودن Ùوری صØنه..." #: editor/editor_node.cpp msgid "Quick Open Script..." -msgstr "" +msgstr "گشودن سریع اسکریپت..." #: editor/editor_node.cpp msgid "Save & Close" @@ -2449,27 +2333,27 @@ msgstr "ذخیره صØنه در ..." #: editor/editor_node.cpp msgid "No" -msgstr "" +msgstr "نه" #: editor/editor_node.cpp msgid "Yes" -msgstr "تایید" +msgstr "بله" #: editor/editor_node.cpp msgid "This scene has never been saved. Save before running?" -msgstr "" +msgstr "این صØنه هرگز ذخیره نشده است. ذخیره قبل از اجرا؟" #: editor/editor_node.cpp editor/scene_tree_dock.cpp msgid "This operation can't be done without a scene." -msgstr "" +msgstr "این عملیات بدون یک صØنه انجام نمی شود." #: editor/editor_node.cpp msgid "Export Mesh Library" -msgstr "" +msgstr "صادر کردن کتابخانه شبکه مش" #: editor/editor_node.cpp msgid "This operation can't be done without a root node." -msgstr "" +msgstr "این عملیات بدون یک گره ریشه ای انجام نمی شود." #: editor/editor_node.cpp msgid "Export Tile Set" @@ -2488,9 +2372,8 @@ msgid "Can't reload a scene that was never saved." msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "Reload Saved Scene" -msgstr "باز کردن صØنه" +msgstr "بازیابی صØنه ذخیره شده" #: editor/editor_node.cpp msgid "" @@ -2500,7 +2383,7 @@ msgstr "" #: editor/editor_node.cpp msgid "Quick Run Scene..." -msgstr "" +msgstr "اجرا Ùوری صØنه…" #: editor/editor_node.cpp msgid "Quit" @@ -2508,7 +2391,7 @@ msgstr "خروج" #: editor/editor_node.cpp msgid "Exit the editor?" -msgstr "از ویرایشگر خارج Ù…ÛŒ شوید؟" +msgstr "خروج از ویرایشگر؟" #: editor/editor_node.cpp msgid "Open Project Manager?" @@ -2538,12 +2421,11 @@ msgstr "" #: editor/editor_node.cpp msgid "Close Scene" -msgstr "" +msgstr "بستن صØنه" #: editor/editor_node.cpp -#, fuzzy msgid "Reopen Closed Scene" -msgstr "باز کردن صØنه" +msgstr "بازگشودن صØنه بسته شده" #: editor/editor_node.cpp msgid "Unable to enable addon plugin at: '%s' parsing of config failed." @@ -2554,9 +2436,8 @@ msgid "Unable to find script field for addon plugin at: 'res://addons/%s'." msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "Unable to load addon script from path: '%s'." -msgstr "خطای بارگذاری قلم." +msgstr "امکان بارگیری اسکریپت اÙزونه از مسیر وجود ندارد: '%s'." #: editor/editor_node.cpp msgid "" @@ -2616,7 +2497,7 @@ msgstr "" #: editor/editor_node.cpp msgid "Save Layout" -msgstr "" +msgstr "ذخیره لایه" #: editor/editor_node.cpp msgid "Delete Layout" @@ -2629,50 +2510,44 @@ msgstr "پیشÙرض" #: editor/editor_node.cpp editor/editor_properties.cpp #: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp -#, fuzzy msgid "Show in FileSystem" -msgstr "سامانه پرونده" +msgstr "نمایش در Ùایل‌سیستم" #: editor/editor_node.cpp -#, fuzzy msgid "Play This Scene" -msgstr "پخش صØنه" +msgstr "اجرای این صØنه" #: editor/editor_node.cpp -#, fuzzy msgid "Close Tab" -msgstr "بستن" +msgstr "بستن زبانه" #: editor/editor_node.cpp -#, fuzzy msgid "Undo Close Tab" -msgstr "بستن" +msgstr "برگرداندن زبانه" #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp msgid "Close Other Tabs" -msgstr "" +msgstr "بستن زبانه های دیگر" #: editor/editor_node.cpp msgid "Close Tabs to the Right" -msgstr "" +msgstr "بستن زبانه ها به طر٠راست" #: editor/editor_node.cpp -#, fuzzy msgid "Close All Tabs" -msgstr "بستن" +msgstr "بستن تمام زبانه ها" #: editor/editor_node.cpp msgid "Switch Scene Tab" -msgstr "" +msgstr "جاگرداندن زبانه صØنه" #: editor/editor_node.cpp msgid "%d more files or folders" msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "%d more folders" -msgstr "نمی‌تواند یک پوشه ایجاد شود." +msgstr "%d پوشه‌های بیش تر" #: editor/editor_node.cpp msgid "%d more files" @@ -2703,9 +2578,8 @@ msgid "Go to previously opened scene." msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "Copy Text" -msgstr "Ú©Ù¾ÛŒ کردن" +msgstr "Ú©Ù¾ÛŒ متن" #: editor/editor_node.cpp msgid "Next tab" @@ -2744,9 +2618,8 @@ msgid "Save Scene" msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "Save All Scenes" -msgstr "ذخیره صØنه در ..." +msgstr "ذخیره صØنه" #: editor/editor_node.cpp msgid "Convert To..." @@ -2763,12 +2636,12 @@ msgstr "" #: editor/editor_node.cpp editor/plugins/script_text_editor.cpp #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp msgid "Undo" -msgstr "خنثی کردن (Undo)" +msgstr "عقب‌گرد" #: editor/editor_node.cpp editor/plugins/script_text_editor.cpp #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp msgid "Redo" -msgstr "" +msgstr "جلوگرد" #: editor/editor_node.cpp msgid "Miscellaneous project or scene-wide tools." @@ -2780,14 +2653,12 @@ msgid "Project" msgstr "پروژه" #: editor/editor_node.cpp -#, fuzzy msgid "Project Settings..." -msgstr "ترجیØات پروژه" +msgstr "تنظیمات طرØ…" #: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp -#, fuzzy msgid "Version Control" -msgstr "نسخه:" +msgstr "مهار نسخه" #: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp msgid "Set Up Version Control" @@ -2798,27 +2669,24 @@ msgid "Shut Down Version Control" msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "Export..." -msgstr "صدور" +msgstr "صدور…" #: editor/editor_node.cpp msgid "Install Android Build Template..." msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "Open Project Data Folder" -msgstr "باز شدن مدیر پروژه؟" +msgstr "گشودن پوشه اطلاعات طرØ" #: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp msgid "Tools" msgstr "ابزارها" #: editor/editor_node.cpp -#, fuzzy msgid "Orphan Resource Explorer..." -msgstr "پوینده‌ی منبع جدا اÙتاده" +msgstr "پوینده‌ی منبع جااÙتاده" #: editor/editor_node.cpp msgid "Quit to Project List" @@ -2898,14 +2766,12 @@ msgid "" msgstr "" #: editor/editor_node.cpp editor/script_create_dialog.cpp -#, fuzzy msgid "Editor" msgstr "ویرایشگر" #: editor/editor_node.cpp -#, fuzzy msgid "Editor Settings..." -msgstr "ویرایشگر ترجیØات" +msgstr "تنظیمات ویرایشگر…" #: editor/editor_node.cpp msgid "Editor Layout" @@ -10070,9 +9936,8 @@ msgid "Project Manager" msgstr "مدیر پروژه" #: editor/project_manager.cpp -#, fuzzy msgid "Projects" -msgstr "پروژه" +msgstr "Ø·Ø±Ø Ù‡Ø§" #: editor/project_manager.cpp msgid "Last Modified" @@ -10112,6 +9977,8 @@ msgid "" "You currently don't have any projects.\n" "Would you like to explore official example projects in the Asset Library?" msgstr "" +"شما Ùعلا هیچ طرØÛŒ ندارید.\n" +"آیا Ù…ÛŒ خواهید Ø·Ø±Ø Ù‡Ø§ÛŒ نمونه رسمی را در کتابخانه دارایی کاوش کنید؟" #: editor/project_manager.cpp msgid "" @@ -10119,6 +9986,9 @@ msgid "" "To filter projects by name and full path, the query must contain at least " "one `/` character." msgstr "" +"کادر جستجو Ø·Ø±Ø Ù‡Ø§ را با نام Ùˆ مسیر اجزا گذشته تصÙیه Ù…ÛŒ کند.\n" +"برای تصÙیه کردن Ø·Ø±Ø Ù‡Ø§ با نام Ùˆ مسیر کامل، پرس Ùˆ جو باید Øداقل دارای یک `/" +"`کاراکتر باشد." #: editor/project_settings_editor.cpp msgid "Key " @@ -10363,7 +10233,7 @@ msgstr "" #: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp msgid "The editor must be restarted for changes to take effect." -msgstr "" +msgstr "باید ویرایشگر از نو شروع شود تا تغییرات جلوه کنند." #: editor/project_settings_editor.cpp msgid "Input Map" @@ -10739,6 +10609,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Øذ٠گره(ها)" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Øذ٠گره(ها)" @@ -12469,7 +12344,7 @@ msgstr "" #: scene/2d/collision_polygon_2d.cpp msgid "An empty CollisionPolygon2D has no effect on collision." -msgstr "یک CollisionPolygon2D خالی اثری بر برخورد ندارد." +msgstr "یک CollisionPolygon2D خالی جلوه بر برخورد ندارد." #: scene/2d/collision_shape_2d.cpp msgid "" @@ -12490,6 +12365,12 @@ msgstr "" "یک Ø´Ú©Ù„ باید برای CollisionShape2D Ùراهم شده باشد تا عمل کند. لطÙا یک Ø´Ú©Ù„ " "منبع برای آن ایجاد کنید!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12506,9 +12387,7 @@ msgstr "یک باÙت با Ø´Ú©Ù„ نور باید برای دارایی texture #: scene/2d/light_occluder_2d.cpp msgid "" "An occluder polygon must be set (or drawn) for this occluder to take effect." -msgstr "" -"یک چندضلعی مسدود باید برای این مسدودکننده (occluder) تنظیم (یا ترسیم) شود تا " -"تأثیرگذار باشد." +msgstr "یک چندضلعی انسدادی باید تنظیم (یا ترسیم) شود تا جلوه کننده باشد." #: scene/2d/light_occluder_2d.cpp #, fuzzy @@ -12680,7 +12559,7 @@ msgstr "" #: scene/3d/collision_polygon.cpp msgid "An empty CollisionPolygon has no effect on collision." -msgstr "یک CollisionPolygon خالی تأثیری بر برخورد ندارد." +msgstr "یک CollisionPolygon خالی جلوه بر برخورد ندارد." #: scene/3d/collision_shape.cpp msgid "" @@ -12825,6 +12704,8 @@ msgid "" "WorldEnvironment requires its \"Environment\" property to contain an " "Environment to have a visible effect." msgstr "" +"Ù…Øیط جهان نیاز به ویژگی \"Ù…Øیط\" خود دارد تا دارای یک Ù…Øیط باشد تا جلوه ای " +"قابل دیدن داشته باشد." #: scene/3d/world_environment.cpp msgid "" @@ -13009,7 +12890,7 @@ msgstr "" #: servers/visual/shader_language.cpp msgid "Constants cannot be modified." -msgstr "" +msgstr "ثوابت قابل تغییر نیستند." #~ msgid "Not in resource path." #~ msgstr "در مسیر٠منبع نیست." diff --git a/editor/translations/fi.po b/editor/translations/fi.po index 8ea9a940f0..67deaf06b3 100644 --- a/editor/translations/fi.po +++ b/editor/translations/fi.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-25 08:40+0000\n" +"PO-Revision-Date: 2020-06-26 06:11+0000\n" "Last-Translator: Tapani Niemi <tapani.niemi@kapsi.fi>\n" "Language-Team: Finnish <https://hosted.weblate.org/projects/godot-engine/" "godot/fi/>\n" @@ -2327,11 +2327,6 @@ msgid "There is no defined scene to run." msgstr "Suoritettavaa skeneä ei ole määritetty." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"Nykyistä skeneä ei ole vielä tallennettu. Tallenna se ennen suorittamista." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Aliprosessia ei voitu käynnistää!" @@ -8642,7 +8637,7 @@ msgstr "Muuntaa HSV-vektorin RGB-vastaavaksi." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Converts RGB vector to HSV equivalent." -msgstr "Muuntaa RGB-vektori HSV-vastaavaksi." +msgstr "Muuntaa RGB-vektorin HSV-vastaavaksi." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Sepia function." @@ -10530,6 +10525,11 @@ msgid "Make node as Root" msgstr "Tee solmusta juurisolmu" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Poista solmu \"%s\" ja sen alisolmut?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "Poista %d solmua?" @@ -12223,6 +12223,12 @@ msgstr "" "CollisionShape2D solmulla täytyy olla muoto, jotta se toimisi. Ole hyvä ja " "luo sille muotoresurssi!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12797,6 +12803,10 @@ msgstr "Varying tyypin voi sijoittaa vain vertex-funktiossa." msgid "Constants cannot be modified." msgstr "Vakioita ei voi muokata." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "Nykyistä skeneä ei ole vielä tallennettu. Tallenna se ennen suorittamista." + #~ msgid "Not in resource path." #~ msgstr "Ei löytynyt resurssipolusta." diff --git a/editor/translations/fil.po b/editor/translations/fil.po index ceda61c802..490d9d92ec 100644 --- a/editor/translations/fil.po +++ b/editor/translations/fil.po @@ -2259,10 +2259,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10133,6 +10129,10 @@ msgid "Make node as Root" msgstr "" #: editor/scene_tree_dock.cpp +msgid "Delete %d nodes and any children?" +msgstr "" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "" @@ -11739,6 +11739,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/fr.po b/editor/translations/fr.po index 9dd9b3e166..95e9d7a55c 100644 --- a/editor/translations/fr.po +++ b/editor/translations/fr.po @@ -35,7 +35,7 @@ # Rémi Verschelde <rverschelde@gmail.com>, 2016-2017. # Robin Arys <robinarys@hotmail.com>, 2017. # Roger BR <drai_kin@hotmail.com>, 2016. -# salty64 <cedric.arrabie@univ-pau.fr>, 2018. +# salty64 <cedric.arrabie@univ-pau.fr>, 2018, 2020. # Thomas Baijot <thomasbaijot@gmail.com>, 2016, 2019. # Tommy Melançon-Roy <tommel1234@hotmail.com>, 2017-2018. # Willow <theotimefd@aol.com>, 2018. @@ -79,7 +79,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-25 08:40+0000\n" +"PO-Revision-Date: 2020-07-26 15:41+0000\n" "Last-Translator: Nathan <bonnemainsnathan@gmail.com>\n" "Language-Team: French <https://hosted.weblate.org/projects/godot-engine/" "godot/fr/>\n" @@ -384,7 +384,7 @@ msgstr "Envelopper l’interp. de la boucle" #: editor/animation_track_editor.cpp #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Insert Key" -msgstr "Insérer clés" +msgstr "Insérer clé" #: editor/animation_track_editor.cpp msgid "Duplicate Key(s)" @@ -2409,12 +2409,6 @@ msgid "There is no defined scene to run." msgstr "Il n'y a pas de scène définie pour être lancée." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"La scène actuelle n'a jamais été sauvegardée, veuillez la sauvegarder avant " -"de la lancer." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Impossible de démarrer le sous-processus !" @@ -5543,7 +5537,7 @@ msgstr "Activer/Désactiver le magnétisme intelligent." #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Use Smart Snap" -msgstr "Utiliser le magnétisme intelligent" +msgstr "Utiliser l'aimantation intelligente" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Toggle grid snapping." @@ -7311,7 +7305,7 @@ msgstr "Échelle : " #: editor/plugins/spatial_editor_plugin.cpp msgid "Translating: " -msgstr "Traduction : " +msgstr "Translation : " #: editor/plugins/spatial_editor_plugin.cpp msgid "Rotating %s degrees." @@ -7567,7 +7561,7 @@ msgstr "Utiliser les coordonées locales" #: editor/plugins/spatial_editor_plugin.cpp msgid "Use Snap" -msgstr "Aligner avec la grille" +msgstr "Utiliser l’aimantation" #: editor/plugins/spatial_editor_plugin.cpp msgid "Bottom View" @@ -7599,11 +7593,11 @@ msgstr "Basculer entre la vue perspective et orthogonale" #: editor/plugins/spatial_editor_plugin.cpp msgid "Insert Animation Key" -msgstr "Insérer une clef d'animation" +msgstr "Insérer une clé d'animation" #: editor/plugins/spatial_editor_plugin.cpp msgid "Focus Origin" -msgstr "Focaliser sur l'origine" +msgstr "Focaliser l'origine" #: editor/plugins/spatial_editor_plugin.cpp msgid "Focus Selection" @@ -9026,8 +9020,7 @@ msgstr "Renvoie la tangente hyperbolique inverse du paramètre." msgid "" "Finds the nearest integer that is greater than or equal to the parameter." msgstr "" -"Recherche l'entier le plus proche qui est plus supérieur ou égal au " -"paramètre." +"Recherche l'entier le plus proche qui est supérieur ou égal au paramètre." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Constrains a value to lie between two further values." @@ -9043,7 +9036,7 @@ msgstr "Renvoie le cosinus hyperbolique du paramètre." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Converts a quantity in radians to degrees." -msgstr "Convertit une quantité de radians en degrés." +msgstr "Convertit une quantité en radians en degrés." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Base-e Exponential." @@ -9109,11 +9102,11 @@ msgstr "1.0 / scalaire" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Finds the nearest integer to the parameter." -msgstr "Renvoie l'entier le plus proche de celui du paramètre." +msgstr "Renvoie l'entier le plus proche du paramètre." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Finds the nearest even integer to the parameter." -msgstr "Renvoie l'entier pair le plus proche de celui du paramètre." +msgstr "Renvoie l'entier pair le plus proche du paramètre." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Clamps the value between 0.0 and 1.0." @@ -10686,6 +10679,10 @@ msgid "Make node as Root" msgstr "Choisir le nÅ“ud comme racine de scène" #: editor/scene_tree_dock.cpp +msgid "Delete %d nodes and any children?" +msgstr "Supprimer %d nÅ“uds et leurs enfants potentiels ?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "Supprimer %d nÅ“uds ?" @@ -11130,11 +11127,11 @@ msgstr "Erreur :" #: editor/script_editor_debugger.cpp msgid "C++ Error" -msgstr "Erreur C ++" +msgstr "Erreur C++" #: editor/script_editor_debugger.cpp msgid "C++ Error:" -msgstr "Erreur C ++ :" +msgstr "Erreur C++ :" #: editor/script_editor_debugger.cpp msgid "C++ Source" @@ -11223,7 +11220,7 @@ msgstr "Exporter la liste vers un fichier CSV" #: editor/script_editor_debugger.cpp msgid "Resource Path" -msgstr "Chemin de la ressource" +msgstr "Chemin de ressource" #: editor/script_editor_debugger.cpp msgid "Type" @@ -12404,6 +12401,15 @@ msgstr "" "Une forme doit être créée afin qu'une CollisionShape2D fonctionne. Veuillez " "créer une ressource de forme !" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" +"Les formes à base de polygones ne sont pas prévues pour être utilisées ou " +"éditées via le nÅ“ud CollisionShape2D. Veuillez utiliser le nÅ“ud " +"CollisionPolygon2D à la place." + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12984,7 +12990,7 @@ msgstr "Affectation à la fonction." #: servers/visual/shader_language.cpp msgid "Assignment to uniform." -msgstr "Affectation à l'uniforme." +msgstr "Affectation à la variable uniform." #: servers/visual/shader_language.cpp msgid "Varyings can only be assigned in vertex function." @@ -12994,6 +13000,11 @@ msgstr "Les variations ne peuvent être affectées que dans la fonction vertex." msgid "Constants cannot be modified." msgstr "Les constantes ne peuvent être modifiées." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "La scène actuelle n'a jamais été sauvegardée, veuillez la sauvegarder " +#~ "avant de la lancer." + #~ msgid "Not in resource path." #~ msgstr "Pas dans le chemin de la ressource." diff --git a/editor/translations/ga.po b/editor/translations/ga.po index 70dd5eada7..a496566c2e 100644 --- a/editor/translations/ga.po +++ b/editor/translations/ga.po @@ -2253,10 +2253,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10129,6 +10125,10 @@ msgid "Make node as Root" msgstr "" #: editor/scene_tree_dock.cpp +msgid "Delete %d nodes and any children?" +msgstr "" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "" @@ -11737,6 +11737,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/he.po b/editor/translations/he.po index 7895ae48fe..c3789f9804 100644 --- a/editor/translations/he.po +++ b/editor/translations/he.po @@ -2381,10 +2381,6 @@ msgid "There is no defined scene to run." msgstr "×ין ×¡×¦× ×” מוגדרת להרצה." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "×”×¡×¦× ×” ×”× ×•×›×—×™×ª ×ž×¢×•×œ× ×œ× × ×©×ž×¨×”, × × ×œ×©×ž×•×¨ ×ותה ×‘×˜×¨× ×”×”×¨×¦×”." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "×œ× × ×™×ª×Ÿ להפעיל תהליך ×ž×©× ×”!" @@ -10684,6 +10680,11 @@ msgstr "שמירת ×¡×¦× ×”" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "מחיקת שורה" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "מחיקת שורה" @@ -12367,6 +12368,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12842,6 +12849,9 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "×”×¡×¦× ×” ×”× ×•×›×—×™×ª ×ž×¢×•×œ× ×œ× × ×©×ž×¨×”, × × ×œ×©×ž×•×¨ ×ותה ×‘×˜×¨× ×”×”×¨×¦×”." + #~ msgid "Not in resource path." #~ msgstr "×œ× ×‘× ×ª×™×‘ המש×ב." diff --git a/editor/translations/hi.po b/editor/translations/hi.po index e3ae2aabe5..70d7a4d6b3 100644 --- a/editor/translations/hi.po +++ b/editor/translations/hi.po @@ -2311,10 +2311,6 @@ msgid "There is no defined scene to run." msgstr "चलाने के लिठकोई परिà¤à¤¾à¤·à¤¿à¤¤ दृशà¥à¤¯ नहीं है ।" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "वरà¥à¤¤à¤®à¤¾à¤¨ दृशà¥à¤¯ कà¤à¥€ नहीं बचाया गया था, कृपया इसे चलाने से पहले बचाने के लिठ।" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "उपपà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾ शà¥à¤°à¥‚ नहीं कर सका!" @@ -10329,6 +10325,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "को हटा दें" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "को हटा दें" @@ -11975,6 +11976,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12443,6 +12450,9 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "वरà¥à¤¤à¤®à¤¾à¤¨ दृशà¥à¤¯ कà¤à¥€ नहीं बचाया गया था, कृपया इसे चलाने से पहले बचाने के लिठ।" + #~ msgid "Not in resource path." #~ msgstr "रेसोरà¥à¤¸ पाथ में नहीं." diff --git a/editor/translations/hr.po b/editor/translations/hr.po index 5355ee1dc9..a515a912b0 100644 --- a/editor/translations/hr.po +++ b/editor/translations/hr.po @@ -2271,10 +2271,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10179,6 +10175,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "ObriÅ¡i kljuÄ(eve)" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "ObriÅ¡i kljuÄ(eve)" @@ -11798,6 +11799,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/hu.po b/editor/translations/hu.po index b57028a426..5661ed02cd 100644 --- a/editor/translations/hu.po +++ b/editor/translations/hu.po @@ -2441,11 +2441,6 @@ msgid "There is no defined scene to run." msgstr "Nincs meghatározva Scene a futtatáshoz." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"A jelenlegi Scene soha nem volt még mentve, mentse el a futtatás elÅ‘tt." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Az alprocesszt nem lehetett elindÃtani!" @@ -10894,6 +10889,11 @@ msgstr "Scene mentés" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Node létrehozás" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Node létrehozás" @@ -12589,6 +12589,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -13066,6 +13072,10 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "A jelenlegi Scene soha nem volt még mentve, mentse el a futtatás elÅ‘tt." + #~ msgid "Not in resource path." #~ msgstr "Nincs az erÅ‘forrás elérési útban." diff --git a/editor/translations/id.po b/editor/translations/id.po index 92c0c25da9..cf4bd738fa 100644 --- a/editor/translations/id.po +++ b/editor/translations/id.po @@ -26,12 +26,13 @@ # Ade Fikri Malihuddin <ade.fm97@gmail.com>, 2020. # zephyroths <ridho.hikaru@gmail.com>, 2020. # Richard Urban <redasuio1@gmail.com>, 2020. +# yusuf afandi <afandi.yusuf.04@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-03 20:09+0000\n" -"Last-Translator: Sofyan Sugianto <sofyanartem@gmail.com>\n" +"PO-Revision-Date: 2020-07-06 04:41+0000\n" +"Last-Translator: yusuf afandi <afandi.yusuf.04@gmail.com>\n" "Language-Team: Indonesian <https://hosted.weblate.org/projects/godot-engine/" "godot/id/>\n" "Language: id\n" @@ -39,7 +40,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.1-dev\n" +"X-Generator: Weblate 4.2-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -778,9 +779,8 @@ msgid "Method in target node must be specified." msgstr "Method dalam node target harus ditentukan." #: editor/connections_dialog.cpp -#, fuzzy msgid "Method name must be a valid identifier." -msgstr "Nama bukan sebuah pengidentifikasi yang sah:" +msgstr "Nama bukan sebuah pengidentifikasi yang sah." #: editor/connections_dialog.cpp msgid "" @@ -2346,12 +2346,6 @@ msgid "There is no defined scene to run." msgstr "Tidak ada skena yang didefinisikan untuk dijalankan." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"Skena saat ini belum pernah disimpan, harap simpan terlebih dahulu sebelum " -"menjalankannya." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Tidak dapat memulai subproses!" @@ -10553,6 +10547,11 @@ msgid "Make node as Root" msgstr "Jadikan node sebagai Dasar" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Hapus node \"%s\" dan anak-anaknya?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "Hapus %d node?" @@ -12240,6 +12239,12 @@ msgstr "" "Sebuah shape harus disediakan untuk CollisionShape2D supaya berfungsi. Mohon " "ciptakan resource shape untuknya!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12800,6 +12805,11 @@ msgstr "Variasi hanya bisa ditetapkan dalam fungsi vertex." msgid "Constants cannot be modified." msgstr "Konstanta tidak dapat dimodifikasi." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "Skena saat ini belum pernah disimpan, harap simpan terlebih dahulu " +#~ "sebelum menjalankannya." + #~ msgid "Not in resource path." #~ msgstr "Tidak dalam lokasi resource." diff --git a/editor/translations/is.po b/editor/translations/is.po index f0d93d1242..d53a9d609d 100644 --- a/editor/translations/is.po +++ b/editor/translations/is.po @@ -2291,10 +2291,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10240,6 +10236,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Anim DELETE-lyklar" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Anim DELETE-lyklar" @@ -11858,6 +11859,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/it.po b/editor/translations/it.po index 7c929b7779..93ca2a8f29 100644 --- a/editor/translations/it.po +++ b/editor/translations/it.po @@ -29,7 +29,7 @@ # Giuseppe Guerra <me@nyodev.xyz>, 2019. # RHC <rhc.throwaway@gmail.com>, 2019. # Antonio Giungato <antonio.giungato@gmail.com>, 2019. -# Marco Galli <mrcgll98@gmail.com>, 2019. +# Marco Galli <mrcgll98@gmail.com>, 2019, 2020. # MassiminoilTrace <omino.gis@gmail.com>, 2019, 2020. # MARCO BANFI <mbanfi@gmail.com>, 2019. # Marco <rodomar705@gmail.com>, 2019. @@ -37,7 +37,7 @@ # Stefano Merazzi <asso99@hotmail.com>, 2019. # Sinapse X <sinapsex13@gmail.com>, 2019. # Micila Micillotto <micillotto@gmail.com>, 2019, 2020. -# Mirko Soppelsa <miknsop@gmail.com>, 2019. +# Mirko Soppelsa <miknsop@gmail.com>, 2019, 2020. # No <kingofwizards.kw7@gmail.com>, 2019. # StarFang208 <polaritymanx@yahoo.it>, 2019. # Katia Piazza <gydey@ridiculousglitch.com>, 2019. @@ -52,12 +52,14 @@ # Anonymous <noreply@weblate.org>, 2020. # riccardo boffelli <riccardo.boffelli.96@gmail.com>, 2020. # Lorenzo Asolan <brixiumx@gmail.com>, 2020. +# Lorenzo Cerqua <lorenzocerqua@tutanota.com>, 2020. +# Federico Manzella <ferdiu.manzella@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-25 08:40+0000\n" -"Last-Translator: Lorenzo Asolan <brixiumx@gmail.com>\n" +"PO-Revision-Date: 2020-07-26 15:41+0000\n" +"Last-Translator: Mirko <miknsop@gmail.com>\n" "Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/" "godot/it/>\n" "Language: it\n" @@ -804,7 +806,6 @@ msgid "Method in target node must be specified." msgstr "Il metodo del nodo designato deve essere specificato." #: editor/connections_dialog.cpp -#, fuzzy msgid "Method name must be a valid identifier." msgstr "Il nome del metodo dev'essere un identificatore valido." @@ -2380,12 +2381,6 @@ msgid "There is no defined scene to run." msgstr "Non c'è nessuna scena definita da eseguire." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"La scena attuale non è mai stata salvata, si prega di salvarla prima di " -"eseguirla." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Impossibile avviare il sottoprocesso!" @@ -4029,10 +4024,9 @@ msgid "Error running post-import script:" msgstr "Errore di esecuzione dello script di post-import:" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Did you return a Node-derived object in the `post_import()` method?" msgstr "" -"Avete restituito un oggetto derivato da un Nodo nel metodo `post_import()`?" +"Hai restituito un oggetto derivato da un Nodo nel metodo `post_import()`?" #: editor/import/resource_importer_scene.cpp msgid "Saving..." @@ -8720,7 +8714,7 @@ msgstr "Crea Nodo Shader" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Color function." -msgstr "Colora funzione." +msgstr "Funzione colore." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Color operator." @@ -8728,15 +8722,15 @@ msgstr "Operatore colore." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Grayscale function." -msgstr "Funzione Grayscale." +msgstr "Funzione scala di grigi." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Converts HSV vector to RGB equivalent." -msgstr "Converti vettore HSV nell'equivalente RGB." +msgstr "Converte un vettore HSV nel suo equivalente RGB." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Converts RGB vector to HSV equivalent." -msgstr "Converti vettore RGB nell'equivalente HSV." +msgstr "Converte un vettore RGB nel suo equivalente HSV." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Sepia function." @@ -8744,31 +8738,31 @@ msgstr "Funzione seppia." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Burn operator." -msgstr "Operatore Burn." +msgstr "Operatore brucia." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Darken operator." -msgstr "Operatore Darken." +msgstr "Operatore scurisci." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Difference operator." -msgstr "Operatore \"differenza\"." +msgstr "Operatore differenza." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Dodge operator." -msgstr "Operatore schivata." +msgstr "Operatore scherma." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "HardLight operator." -msgstr "Operatore HardLight." +msgstr "Operatore luce dura." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Lighten operator." -msgstr "Operatore \"schiarischi\"." +msgstr "Operatore schiarisci." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Overlay operator." -msgstr "Operatore overlay." +msgstr "Operatore sovrapponi." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Screen operator." @@ -8776,7 +8770,7 @@ msgstr "Operatore schermo." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "SoftLight operator." -msgstr "Operatore SoftLight." +msgstr "Operatore luce morbida." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Color constant." @@ -8788,7 +8782,8 @@ msgstr "Uniforme di colore." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the boolean result of the %s comparison between two parameters." -msgstr "Ritorna il risultato booleano del confronto di %s tra due parametri." +msgstr "" +"Restituisce il risultato booleano del confronto di %s tra due parametri." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Equal (==)" @@ -8800,29 +8795,31 @@ msgstr "Maggiore Di (>)" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Greater Than or Equal (>=)" -msgstr "Maggiore o Uguale (>=)" +msgstr "Maggiore o uguale (>=)" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "" "Returns an associated vector if the provided scalars are equal, greater or " "less." msgstr "" -"Ritorna un vettore associato se gli scalari di quello fornito sono uguali, " -"maggiori o minori." +"Restituisce un vettore associato se gli scalari di quello fornito sono " +"uguali, maggiori o minori." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "" "Returns the boolean result of the comparison between INF and a scalar " "parameter." msgstr "" -"Ritorna il risultato booleano del confronto tra INF e un parametro scalare." +"Restituisce il risultato booleano del confronto tra INF e un parametro " +"scalare." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "" "Returns the boolean result of the comparison between NaN and a scalar " "parameter." msgstr "" -"Ritorna il risultato booleano del confronto tra NaN e un parametro scalare." +"Restituisce il risultato booleano del confronto tra NaN e un parametro " +"scalare." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Less Than (<)" @@ -8840,24 +8837,26 @@ msgstr "Non Uguale (!=)" msgid "" "Returns an associated vector if the provided boolean value is true or false." msgstr "" -"Ritorna un vettore associato se il valore booleano fornito è vero o falso." +"Restituisce un vettore associato se il valore booleano fornito è vero o " +"falso." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "" "Returns an associated scalar if the provided boolean value is true or false." -msgstr "Ritorna uno scalare associato se il booleano provvisto è vero o falso." +msgstr "" +"Restituisce uno scalare associato se il booleano fornito è vero o falso." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the boolean result of the comparison between two parameters." -msgstr "Ritorna il risultato booleano del confronto tra due parametri." +msgstr "Restituisce il risultato booleano del confronto tra due parametri." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "" "Returns the boolean result of the comparison between INF (or NaN) and a " "scalar parameter." msgstr "" -"Ritorna il risultato booleano del confronto tra INF (o NaN) e un parametro " -"scalare." +"Restituisce il risultato booleano del confronto tra INF (o NaN) e un " +"parametro scalare." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Boolean constant." @@ -8877,27 +8876,27 @@ msgstr "Parametro di input." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "'%s' input parameter for vertex and fragment shader modes." -msgstr "Parametro di input '%s' per le modalità shader vertex e fragment." +msgstr "Parametro di input '%s' per le modalità shader vertice e frammento." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "'%s' input parameter for fragment and light shader modes." -msgstr "Parametro di input '%s' per le modalità shader fragment e light." +msgstr "Parametro di input '%s' per le modalità shader frammento e luce." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "'%s' input parameter for fragment shader mode." -msgstr "Parametro di input '%s' per la modalità shader fragment." +msgstr "Parametro di input '%s' per la modalità shader frammento." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "'%s' input parameter for light shader mode." -msgstr "Parametro di input '%s' per la modalità shader light." +msgstr "Parametro di input '%s' per la modalità shader luce." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "'%s' input parameter for vertex shader mode." -msgstr "Parametro di input '%s' per la modalità shader vertex." +msgstr "Parametro di input '%s' per la modalità shader vertice." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "'%s' input parameter for vertex and fragment shader mode." -msgstr "Parametro di input '%s' per la modalità shader vertex e fragment." +msgstr "Parametro di input '%s' per la modalità shader vertice e frammento." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Scalar function." @@ -8941,35 +8940,35 @@ msgstr "La costante Sqrt2 (1.414214). La radice quadrata di 2." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the absolute value of the parameter." -msgstr "Ritorna il valore assoluto del parametro." +msgstr "Restituisce il valore assoluto del parametro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the arc-cosine of the parameter." -msgstr "Ritorna l'arco-coseno del parametro." +msgstr "Restituisce l'arco-coseno del parametro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the inverse hyperbolic cosine of the parameter." -msgstr "Ritorna l'inversa del coseno iperbolico del parametro." +msgstr "Restituisce l'inversa del coseno iperbolico del parametro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the arc-sine of the parameter." -msgstr "Ritorna l'arco-seno del parametro." +msgstr "Restituisce l'arco-seno del parametro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the inverse hyperbolic sine of the parameter." -msgstr "Ritorna l'inversa del seno iperbolico del parametro." +msgstr "Restituisce l'inversa del seno iperbolico del parametro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the arc-tangent of the parameter." -msgstr "Ritorna l'arco-tangente del parametro." +msgstr "Restituisce l'arco-tangente del parametro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the arc-tangent of the parameters." -msgstr "Ritorna l'arco-tangente dei parametri." +msgstr "Restituisce l'arco-tangente dei parametri." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the inverse hyperbolic tangent of the parameter." -msgstr "Ritorna l'inversa della tangente iperbolica del parametro." +msgstr "Restituisce l'inversa della tangente iperbolica del parametro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "" @@ -8983,11 +8982,11 @@ msgstr "Vincola un valore tra due altri valori." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the cosine of the parameter." -msgstr "Ritorna il coseno del parametro." +msgstr "Restituisce il coseno del parametro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the hyperbolic cosine of the parameter." -msgstr "Ritorna il coseno iperbolico del parametro." +msgstr "Restituisce il coseno iperbolico del parametro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Converts a quantity in radians to degrees." @@ -9024,11 +9023,11 @@ msgstr "Logaritmo in base 2." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the greater of two values." -msgstr "Ritorna il maggiore di due valori." +msgstr "Restituisce il maggiore di due valori." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the lesser of two values." -msgstr "Ritorna il minore di due valori." +msgstr "Restituisce il minore di due valori." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Linear interpolation between two scalars." @@ -9036,7 +9035,7 @@ msgstr "Interpolazione lineare tra due scalari." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the opposite value of the parameter." -msgstr "Ritorna il valore opposto del parametro." +msgstr "Restituisce il valore opposto del parametro." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "1.0 - scalar" @@ -9046,7 +9045,7 @@ msgstr "1.0 - scalare" msgid "" "Returns the value of the first parameter raised to the power of the second." msgstr "" -"Ritorna il valore del primo parametro elevato alla potenza del secondo." +"Restituisce il valore del primo parametro elevato alla potenza del secondo." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Converts a quantity in degrees to radians." @@ -10631,6 +10630,11 @@ msgid "Make node as Root" msgstr "Rendi il nodo come Radice" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Elimina il nodo \"%s\" e tutti i suoi figli?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "Elimina %d nodi?" @@ -10760,15 +10764,14 @@ msgid "Open Documentation" msgstr "Apri la documentazione" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "" "Cannot attach a script: there are no languages registered.\n" "This is probably because this editor was built with all language modules " "disabled." msgstr "" "Non è possibile allegare uno script: non ci sono linguaggi registrati.\n" -"Questo probabilmente perché questo editor è stato costruito con tutti i " -"moduli di lingua disabilitati." +"Probabilmente perché questo editor è stato costruito con tutti i moduli di " +"linguaggio disabilitati." #: editor/scene_tree_dock.cpp msgid "Add Child Node" @@ -12053,11 +12056,9 @@ msgstr "" "Debug keystore non configurato nelle Impostazioni dell'Editor né nel preset." #: platform/android/export/export.cpp -#, fuzzy msgid "Release keystore incorrectly configured in the export preset." msgstr "" -"Debug keystore non configurato correttamente nelle Impostazioni dell'Editor " -"né nel preset." +"Debug keystore non configurato correttamente nel preset di esportazione." #: platform/android/export/export.cpp msgid "Custom build requires a valid Android SDK path in Editor Settings." @@ -12088,12 +12089,11 @@ msgid "Invalid package name:" msgstr "Nome del pacchetto non valido:" #: platform/android/export/export.cpp -#, fuzzy msgid "" "Invalid \"GodotPaymentV3\" module included in the \"android/modules\" " "project setting (changed in Godot 3.2.2).\n" msgstr "" -"Modulo \"GodotPaymentV3\" non valido incluso nell'impostazione del progetto " +"Modulo \"GodotPaymentV3\" non valido incluso nelle impostazione del progetto " "\"android/moduli\" (modificato in Godot 3.2.2).\n" #: platform/android/export/export.cpp @@ -12101,13 +12101,12 @@ msgid "\"Use Custom Build\" must be enabled to use the plugins." msgstr "Per utilizzare i plugin \"Use Custom Build\" deve essere abilitato." #: platform/android/export/export.cpp -#, fuzzy msgid "" "\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR" "\"." msgstr "" -"\"Degrees Of Freedom\" è valido solo quando \"Xr Mode\" è \"Oculus Mobile VR" -"\"." +"\"Degrees Of Freedom\" è valido solamente quando \"Xr Mode\" è \"Oculus " +"Mobile VR\"." #: platform/android/export/export.cpp #, fuzzy @@ -12346,6 +12345,12 @@ msgstr "" "Perché CollisionShape2D funzioni deve essere fornita una forma. Si prega di " "creare una risorsa forma (shape)!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12924,6 +12929,11 @@ msgstr "Varyings può essere assegnato soltanto nella funzione del vertice." msgid "Constants cannot be modified." msgstr "Le constanti non possono essere modificate." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "La scena attuale non è mai stata salvata, si prega di salvarla prima di " +#~ "eseguirla." + #~ msgid "Not in resource path." #~ msgstr "Non è nel percorso risorse." diff --git a/editor/translations/ja.po b/editor/translations/ja.po index 35e590d629..d3b2771793 100644 --- a/editor/translations/ja.po +++ b/editor/translations/ja.po @@ -36,7 +36,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-25 08:40+0000\n" +"PO-Revision-Date: 2020-07-28 09:51+0000\n" "Last-Translator: Wataru Onuki <bettawat@yahoo.co.jp>\n" "Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/" "godot/ja/>\n" @@ -331,11 +331,11 @@ msgstr "ã‚ュービック" #: editor/animation_track_editor.cpp msgid "Clamp Loop Interp" -msgstr "ループインタプリタを抑ãˆè¾¼ã¿(clamp)" +msgstr "ループ補間をクランプ" #: editor/animation_track_editor.cpp msgid "Wrap Loop Interp" -msgstr "ループインタプリタをラップ(wrap)" +msgstr "ループ補間をラップ" #: editor/animation_track_editor.cpp #: editor/plugins/canvas_item_editor_plugin.cpp @@ -840,7 +840,7 @@ msgstr "è¿½åŠ ã®å‘¼å‡ºã—引数:" #: editor/connections_dialog.cpp msgid "Receiver Method:" -msgstr "メソッドã®é¸æŠž:" +msgstr "å—ä¿¡å´ãƒ¡ã‚½ãƒƒãƒ‰:" #: editor/connections_dialog.cpp msgid "Advanced" @@ -1482,7 +1482,7 @@ msgstr "自動èªè¾¼ã¿ã®ä¸¦ã¹æ›¿ãˆ" #: editor/editor_autoload_settings.cpp msgid "Can't add autoload:" -msgstr "" +msgstr "自動èªã¿è¾¼ã¿ã‚’è¿½åŠ å‡ºæ¥ã¾ã›ã‚“:" #: editor/editor_autoload_settings.cpp msgid "Add AutoLoad" @@ -2353,10 +2353,6 @@ msgid "There is no defined scene to run." msgstr "実行ã™ã‚‹ã‚·ãƒ¼ãƒ³ãŒå®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“。" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "ç¾åœ¨ã®ã‚·ãƒ¼ãƒ³ã¯ä¿å˜ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸã€‚実行ã™ã‚‹å‰ã«ä¿å˜ã—ã¦ãã ã•ã„。" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "サブプãƒã‚»ã‚¹ã‚’開始ã§ãã¾ã›ã‚“ã§ã—ãŸ!" @@ -2442,13 +2438,15 @@ msgstr "ä¿å˜ã•ã‚Œã¦ã„ãªã„シーンをèªã¿è¾¼ã‚€ã“ã¨ã¯ã§ãã¾ã›ã‚“ #: editor/editor_node.cpp msgid "Reload Saved Scene" -msgstr "ä¿å˜æ¸ˆã¿ã®ã‚·ãƒ¼ãƒ³ã‚’リãƒãƒ¼ãƒ‰" +msgstr "ä¿å˜æ¸ˆã¿ã‚·ãƒ¼ãƒ³ã‚’リãƒãƒ¼ãƒ‰" #: editor/editor_node.cpp msgid "" "The current scene has unsaved changes.\n" "Reload the saved scene anyway? This action cannot be undone." msgstr "" +"ç¾åœ¨ã®ã‚·ãƒ¼ãƒ³ã«ã¯æœªä¿å˜ã®å¤‰æ›´ãŒã‚ã‚Šã¾ã™ã€‚\n" +"ãã‚Œã§ã‚‚ä¿å˜æ¸ˆã¿ã‚·ãƒ¼ãƒ³ã‚’リãƒãƒ¼ãƒ‰ã—ã¾ã™ã‹ï¼Ÿ ã“ã®å‹•ä½œã¯å–り消ã›ã¾ã›ã‚“。" #: editor/editor_node.cpp msgid "Quick Run Scene..." @@ -2905,7 +2903,7 @@ msgstr "システムコンソールã®æœ‰åŠ¹åŒ– / 無効化" #: editor/editor_node.cpp msgid "Open Editor Data/Settings Folder" -msgstr "エディタã®ãƒ‡ãƒ¼ã‚¿ãƒ»è¨å®šãƒ•ã‚©ãƒ«ãƒ€ã‚’é–‹ã" +msgstr "エディタã®ãƒ‡ãƒ¼ã‚¿ / è¨å®šãƒ•ã‚©ãƒ«ãƒ€ã‚’é–‹ã" #: editor/editor_node.cpp msgid "Open Editor Data Folder" @@ -3062,13 +3060,13 @@ msgid "" "the \"Use Custom Build\" option should be enabled in the Android export " "preset." msgstr "" -"ã“ã®æ“作㯠\"res://android/build\" ã«ã‚½ãƒ¼ã‚¹ãƒ†ãƒ³ãƒ—レートをインストールã—アンド" -"ãƒã‚¤ãƒ‰ã®ã‚«ã‚¹ã‚¿ãƒ ビルドをè¨å®šã—ã¾ã™ã€‚\n" -"後ã‹ã‚‰è¨å®šã«å¤‰æ›´ã‚’åŠ ãˆãŸã‚Šã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆæ™‚ã«ã‚«ã‚¹ã‚¿ãƒ APKをビルドã§ãã¾ã™ã€‚(モ" -"ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’è¿½åŠ ã™ã‚‹ã€AndroidManifest.xmlを変更ã™ã‚‹ç‰)\n" +"ã“ã®æ“作㯠\"res://android/build\" ã«ã‚½ãƒ¼ã‚¹ãƒ†ãƒ³ãƒ—レートをインストールã—ã€ã‚¢ãƒ³" +"ドãƒã‚¤ãƒ‰ã®ã‚«ã‚¹ã‚¿ãƒ ビルドをè¨å®šã—ã¾ã™ã€‚\n" +"後ã‹ã‚‰è¨å®šã«å¤‰æ›´ã‚’åŠ ãˆãŸã‚Šã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆæ™‚ã«ã‚«ã‚¹ã‚¿ãƒ APKをビルドã§ãã¾ã™ (モ" +"ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’è¿½åŠ ã™ã‚‹ã€AndroidManifest.xmlを変更ã™ã‚‹ç‰)。\n" "APKビルドã®åˆæœŸè¨å®šã®ä»£ã‚ã‚Šã«ã‚«ã‚¹ã‚¿ãƒ ビルドè¨å®šã‚’使ã†ãŸã‚ã«ã¯ã€ã‚¢ãƒ³ãƒ‰ãƒã‚¤ãƒ‰ã®" -"エクスãƒãƒ¼ãƒˆè¨å®šã®ã€Œã‚«ã‚¹ã‚¿ãƒ ビルドを使用ã™ã‚‹ã€ã®ã‚ªãƒ—ションãŒæœ‰åŠ¹åŒ–ã•ã‚Œã¦ã„ã‚‹" -"å¿…è¦ãŒã‚ã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。" +"エクスãƒãƒ¼ãƒˆè¨å®šã®ã€ŒUse Custom Build (カスタムビルドを使用ã™ã‚‹)ã€ã®ã‚ªãƒ—ション" +"ãŒæœ‰åŠ¹åŒ–ã•ã‚Œã¦ã„ã‚‹å¿…è¦ãŒã‚ã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。" #: editor/editor_node.cpp msgid "" @@ -3980,6 +3978,7 @@ msgstr "インãƒãƒ¼ãƒˆæ¸ˆã‚¹ã‚¯ãƒªãƒ—トã®å®Ÿè¡Œä¸ã«ã‚¨ãƒ©ãƒ¼:" #: editor/import/resource_importer_scene.cpp msgid "Did you return a Node-derived object in the `post_import()` method?" msgstr "" +"`post_import()` メソッド内ã§ã€Nodeを継承ã—ãŸã‚ªãƒ–ジェクトを返ã—ã¾ã—ãŸã‹ï¼Ÿ" #: editor/import/resource_importer_scene.cpp msgid "Saving..." @@ -4742,7 +4741,7 @@ msgstr "プレイモード:" #: editor/plugins/animation_tree_editor_plugin.cpp #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "AnimationTree" -msgstr "AnimationTree(アニメーションツリー)" +msgstr "アニメーションツリー" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "New name:" @@ -7412,6 +7411,11 @@ msgid "" "Closed eye: Gizmo is hidden.\n" "Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")." msgstr "" +"クリックã§å¯è¦–状態ã®ã‚ªãƒ³ / オフ。\n" +"\n" +"é–‹ã„ãŸç›®: ギズモã¯å¯è¦–。\n" +"é–‰ã˜ãŸç›®: ギズモã¯éžå¯è¦–。\n" +"åŠé–‹ãã®ç›®: ギズモã¯éžé€æ˜Žãªé¢ã‚’通ã—ã¦ã‚‚å¯è¦– (「Xç·šã€)。" #: editor/plugins/spatial_editor_plugin.cpp msgid "Snap Nodes To Floor" @@ -7571,7 +7575,7 @@ msgstr "Z-Farを表示:" #: editor/plugins/spatial_editor_plugin.cpp msgid "Transform Change" -msgstr "変æ›ã®å¤‰æ›´" +msgstr "トランスフォームã®å¤‰æ›´" #: editor/plugins/spatial_editor_plugin.cpp msgid "Translate:" @@ -8646,11 +8650,11 @@ msgstr "グレースケール関数。" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Converts HSV vector to RGB equivalent." -msgstr "HSVベクトルをRGBベクトルã«å¤‰æ›ã—ã¾ã™ã€‚" +msgstr "HSVベクトルをRGBベクトルã«å¤‰æ›ã€‚" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Converts RGB vector to HSV equivalent." -msgstr "RGBベクトルをHSVベクトルã«å¤‰æ›ã—ã¾ã™ã€‚" +msgstr "RGBベクトルをHSVベクトルã«å¤‰æ›ã€‚" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Sepia function." @@ -8984,7 +8988,7 @@ msgstr "パラメータã®ç¬¦å·ã‚’抽出ã—ã¾ã™ã€‚" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the sine of the parameter." -msgstr "パラメータã®ç¬¦å·ã‚’è¿”ã—ã¾ã™ã€‚" +msgstr "パラメータã®ã‚µã‚¤ãƒ³ã‚’è¿”ã—ã¾ã™ã€‚" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the hyperbolic sine of the parameter." @@ -9044,7 +9048,7 @@ msgstr "スカラーをスカラーã§ä¹—ç®—ã—ã¾ã™ã€‚" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the remainder of the two scalars." -msgstr "2ã¤ã®ã‚¹ã‚«ãƒ©ãƒ¼ã®æ®‹ã‚Šã‚’è¿”ã—ã¾ã™ã€‚" +msgstr "2ã¤ã®ã‚¹ã‚«ãƒ©ãƒ¼ã®å‰°ä½™ã‚’è¿”ã—ã¾ã™ã€‚" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Subtracts scalar from scalar." @@ -9272,7 +9276,7 @@ msgstr "ベクトルã§ãƒ™ã‚¯ãƒˆãƒ«ã‚’ä¹—ç®—ã—ã¾ã™ã€‚" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the remainder of the two vectors." -msgstr "2ã¤ã®ãƒ™ã‚¯ãƒˆãƒ«ã®æ®‹ã‚Šã‚’è¿”ã—ã¾ã™ã€‚" +msgstr "2ã¤ã®ãƒ™ã‚¯ãƒˆãƒ«ã®å‰°ä½™ã‚’è¿”ã—ã¾ã™ã€‚" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Subtracts vector from vector." @@ -10531,6 +10535,11 @@ msgid "Make node as Root" msgstr "ノードをルートã«ã™ã‚‹" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "\"%s\" ノードã¨ãã®åノードを削除ã—ã¾ã™ã‹ï¼Ÿ" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "%d ノードを削除ã—ã¾ã™ã‹ï¼Ÿ" @@ -10664,6 +10673,9 @@ msgid "" "This is probably because this editor was built with all language modules " "disabled." msgstr "" +"スクリプトをアタッãƒã§ãã¾ã›ã‚“: 言語ãŒã²ã¨ã¤ã‚‚登録ã•ã‚Œã¦ã„ã¾ã›ã‚“。\n" +"ãŠãらãã“ã®ã‚¨ãƒ‡ã‚£ã‚¿ã¯ã€ã™ã¹ã¦ã®è¨€èªžãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’無効化ã—ã¦ãƒ“ルドã•ã‚Œã¦ã„ã¾" +"ã™ã€‚" #: editor/scene_tree_dock.cpp msgid "Add Child Node" @@ -11977,26 +11989,36 @@ msgid "" "Invalid \"GodotPaymentV3\" module included in the \"android/modules\" " "project setting (changed in Godot 3.2.2).\n" msgstr "" +"「android/modulesã€ã«å«ã¾ã‚Œã‚‹ã€ŒGodotPaymentV3ã€ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã®ãƒ—ãƒã‚¸ã‚§ã‚¯ãƒˆè¨å®šãŒ" +"無効ã§ã™ (Godot 3.2.2 ã«ã¦å¤‰æ›´)。\n" #: platform/android/export/export.cpp msgid "\"Use Custom Build\" must be enabled to use the plugins." msgstr "" +"プラグインを利用ã™ã‚‹ã«ã¯ã€ŒUse Custom Build (カスタムビルドを使用ã™ã‚‹)ã€ãŒæœ‰åŠ¹" +"ã«ãªã£ã¦ã„ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚" #: platform/android/export/export.cpp msgid "" "\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR" "\"." msgstr "" +"\"Degrees Of Freedom\" 㯠\"Xr Mode\" ㌠\"Oculus Mobile VR\" ã®å ´åˆã«ã®ã¿æœ‰" +"効ã«ãªã‚Šã¾ã™ã€‚" #: platform/android/export/export.cpp msgid "" "\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"." msgstr "" +"\"Hand Tracking\" 㯠\"Xr Mode\" ㌠\"Oculus Mobile VR\" ã®å ´åˆã«ã®ã¿æœ‰åŠ¹ã«ãª" +"ã‚Šã¾ã™ã€‚" #: platform/android/export/export.cpp msgid "" "\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"." msgstr "" +"\"Focus Awareness\" 㯠\"Xr Mode\" ㌠\"Oculus Mobile VR\" ã®å ´åˆã«ã®ã¿æœ‰åŠ¹ã«" +"ãªã‚Šã¾ã™ã€‚" #: platform/android/export/export.cpp msgid "" @@ -12208,6 +12230,12 @@ msgstr "" "関数ã«å¯¾ã—㦠CollisionShape2D ã®å½¢çŠ¶(シェイプ)を指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ãã®" "ãŸã‚ã®ã‚·ã‚§ã‚¤ãƒ—リソースを作æˆã—ã¦ãã ã•ã„!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12780,6 +12808,9 @@ msgstr "Varying変数ã¯é ‚点関数ã«ã®ã¿å‰²ã‚Šå½“ã¦ã‚‹ã“ã¨ãŒã§ãã¾ã msgid "Constants cannot be modified." msgstr "定数ã¯å¤‰æ›´ã§ãã¾ã›ã‚“。" +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "ç¾åœ¨ã®ã‚·ãƒ¼ãƒ³ã¯ä¿å˜ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸã€‚実行ã™ã‚‹å‰ã«ä¿å˜ã—ã¦ãã ã•ã„。" + #~ msgid "Not in resource path." #~ msgstr "リソースパスã«ã‚ã‚Šã¾ã›ã‚“。" diff --git a/editor/translations/ka.po b/editor/translations/ka.po index af03b1af9e..1bfd23080b 100644 --- a/editor/translations/ka.po +++ b/editor/translations/ka.po @@ -2365,10 +2365,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10441,6 +10437,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "წáƒáƒ¨áƒšáƒ" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "წáƒáƒ¨áƒšáƒ" @@ -12092,6 +12093,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/ko.po b/editor/translations/ko.po index 462c59d319..23a9e4dded 100644 --- a/editor/translations/ko.po +++ b/editor/translations/ko.po @@ -22,7 +22,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-25 08:40+0000\n" +"PO-Revision-Date: 2020-06-29 15:26+0000\n" "Last-Translator: Ch. <ccwpc@hanmail.net>\n" "Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/" "godot/ko/>\n" @@ -2329,10 +2329,6 @@ msgid "There is no defined scene to run." msgstr "ì‹¤í–‰í• ì”¬ì´ ì„¤ì •ë˜ì§€ 않았습니다." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "현재 ì”¬ì´ ì•„ì§ ì €ìž¥ë˜ì§€ 않았습니다. 실행하기 ì „ì— ì €ìž¥í•´ì£¼ì„¸ìš”." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "하위 프로세스를 ì‹œìž‘í• ìˆ˜ 없습니다!" @@ -4518,7 +4514,7 @@ msgstr "ì• ë‹ˆë©”ì´ì…˜ ë„구" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Animation" -msgstr "ì• ë‹ˆë©”ì´ì…˜(Animation)" +msgstr "ì• ë‹ˆë©”ì´ì…˜" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Edit Transitions..." @@ -7896,7 +7892,7 @@ msgstr "ì²´í¬ëœ ë¼ë””오 í•ëª©" #: editor/plugins/theme_editor_plugin.cpp msgid "Named Sep." -msgstr "ì´ë¦„있는 분기." +msgstr "ì´ë¦„있는 구분ìž." #: editor/plugins/theme_editor_plugin.cpp msgid "Submenu" @@ -10420,7 +10416,7 @@ msgstr "씬 ì¸ìŠ¤í„´ìŠ¤í™”" #: editor/scene_tree_dock.cpp msgid "Replace with Branch Scene" -msgstr "분기 씬으로 êµì²´" +msgstr "가지 씬으로 êµì²´" #: editor/scene_tree_dock.cpp msgid "Instance Child Scene" @@ -10465,6 +10461,11 @@ msgid "Make node as Root" msgstr "노드를 루트로 만들기" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "노드 \"%s\"와(ê³¼) ìžì‹ì„ ì‚ì œí• ê¹Œìš”?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "%dê°œì˜ ë…¸ë“œë¥¼ ì‚ì œí• ê¹Œìš”?" @@ -10625,7 +10626,7 @@ msgstr "다른 씬ì—ì„œ 병합하기" #: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp msgid "Save Branch as Scene" -msgstr "분기를 씬으로 ì €ìž¥" +msgstr "가지를 씬으로 ì €ìž¥" #: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp msgid "Copy Node Path" @@ -12135,6 +12136,12 @@ msgstr "" "CollisionShape2Dê°€ ìž‘ë™í•˜ë ¤ë©´ 반드시 Shapeê°€ 있어야 합니다. Shape 리소스를 만" "들어주세요!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12692,6 +12699,9 @@ msgstr "Varyingì€ ê¼ì§“ì 함수ì—만 ì§€ì •í• ìˆ˜ 있습니다." msgid "Constants cannot be modified." msgstr "ìƒìˆ˜ëŠ” ìˆ˜ì •í• ìˆ˜ 없습니다." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "현재 ì”¬ì´ ì•„ì§ ì €ìž¥ë˜ì§€ 않았습니다. 실행하기 ì „ì— ì €ìž¥í•´ì£¼ì„¸ìš”." + #~ msgid "Not in resource path." #~ msgstr "리소스 ê²½ë¡œì— ì—†ìŠµë‹ˆë‹¤." diff --git a/editor/translations/lt.po b/editor/translations/lt.po index fdf9ef15ae..4d3884d5f8 100644 --- a/editor/translations/lt.po +++ b/editor/translations/lt.po @@ -4,12 +4,13 @@ # This file is distributed under the same license as the Godot source code. # Ignas Kiela <ignaskiela@super.lt>, 2017. # Kornelijus <kornelijus.github@gmail.com>, 2017, 2018. +# Ignotas Gražys <ignotas.gr@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2018-12-13 14:41+0100\n" -"Last-Translator: Kornelijus <kornelijus.github@gmail.com>\n" +"PO-Revision-Date: 2020-07-06 04:41+0000\n" +"Last-Translator: Ignotas Gražys <ignotas.gr@gmail.com>\n" "Language-Team: Lithuanian <https://hosted.weblate.org/projects/godot-engine/" "godot/lt/>\n" "Language: lt\n" @@ -18,34 +19,34 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=n==1 ? 0 : n%10>=2 && (n%100<10 || n" "%100>=20) ? 1 : n%10==0 || (n%100>10 && n%100<20) ? 2 : 3;\n" -"X-Generator: Poedit 2.2\n" +"X-Generator: Weblate 4.2-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Invalid type argument to convert(), use TYPE_* constants." -msgstr "" +msgstr "Netinkamo tipo argumentas į convert(), naudoti TYPE_* konstantas." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." -msgstr "" +msgstr "TikÄ—tasi 1 (simbolio) ilgio eilutÄ—s." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/mono/glue/gd_glue.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Not enough bytes for decoding bytes, or invalid format." -msgstr "" +msgstr "Nepakanka baitų iÅ¡Å¡ifruoti baitams, arba netinkamas formatas." #: core/math/expression.cpp msgid "Invalid input %i (not passed) in expression" -msgstr "" +msgstr "Netinkama įvestis iÅ¡raiÅ¡koje %i (nepraleista)" #: core/math/expression.cpp msgid "self can't be used because instance is null (not passed)" -msgstr "" +msgstr "self nenaudojamas, nes atvejis yra null (nepraleistas)" #: core/math/expression.cpp msgid "Invalid operands to operator %s, %s and %s." -msgstr "" +msgstr "Netinkami operatoriaus operandai %s, %s ir %s." #: core/math/expression.cpp msgid "Invalid index of type %s for base type %s" @@ -57,7 +58,7 @@ msgstr "" #: core/math/expression.cpp msgid "Invalid arguments to construct '%s'" -msgstr "" +msgstr "Netinkami argumentai sukurti '%s'" #: core/math/expression.cpp msgid "On call to '%s':" @@ -65,31 +66,31 @@ msgstr "" #: core/ustring.cpp msgid "B" -msgstr "" +msgstr "B" #: core/ustring.cpp msgid "KiB" -msgstr "" +msgstr "KiB" #: core/ustring.cpp msgid "MiB" -msgstr "" +msgstr "MiB" #: core/ustring.cpp msgid "GiB" -msgstr "" +msgstr "GiB" #: core/ustring.cpp msgid "TiB" -msgstr "" +msgstr "TiB" #: core/ustring.cpp msgid "PiB" -msgstr "" +msgstr "PiB" #: core/ustring.cpp msgid "EiB" -msgstr "" +msgstr "EiB" #: editor/animation_bezier_editor.cpp msgid "Free" @@ -97,40 +98,40 @@ msgstr "Nemokama" #: editor/animation_bezier_editor.cpp msgid "Balanced" -msgstr "" +msgstr "Subalansuotas" #: editor/animation_bezier_editor.cpp msgid "Mirror" -msgstr "" +msgstr "AtspindÄ—ti" #: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp +#, fuzzy msgid "Time:" msgstr "TrukmÄ—:" #: editor/animation_bezier_editor.cpp -#, fuzzy msgid "Value:" -msgstr "Naujas pavadinimas:" +msgstr "ReikÅ¡mÄ—:" #: editor/animation_bezier_editor.cpp msgid "Insert Key Here" -msgstr "" +msgstr "Ä®raÅ¡yti raktažodį Äia" #: editor/animation_bezier_editor.cpp msgid "Duplicate Selected Key(s)" -msgstr "" +msgstr "Kopijuoti pasirinktÄ… (-us) raktažodį (-žius)" #: editor/animation_bezier_editor.cpp msgid "Delete Selected Key(s)" -msgstr "" +msgstr "IÅ¡trinti pasirinktus raktažodžius" #: editor/animation_bezier_editor.cpp msgid "Add Bezier Point" -msgstr "" +msgstr "PridÄ—ti BezjÄ— taÅ¡kÄ…" #: editor/animation_bezier_editor.cpp msgid "Move Bezier Points" -msgstr "" +msgstr "Judinti BezjÄ— taÅ¡kus" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Duplicate Keys" @@ -188,22 +189,21 @@ msgid "Anim Multi Change Call" msgstr "Animacija: Pakeisti IÅ¡kvietimÄ…" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Change Animation Length" -msgstr "Animacijos Nodas" +msgstr "Pakeisti animacijos ilgį" #: editor/animation_track_editor.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Change Animation Loop" -msgstr "" +msgstr "Pakeisti animacijos ciklÄ…" #: editor/animation_track_editor.cpp msgid "Property Track" -msgstr "" +msgstr "YpatybÄ—s seklys" #: editor/animation_track_editor.cpp msgid "3D Transform Track" -msgstr "" +msgstr "3D transformacijų seklys" #: editor/animation_track_editor.cpp msgid "Call Method Track" @@ -211,7 +211,7 @@ msgstr "" #: editor/animation_track_editor.cpp msgid "Bezier Curve Track" -msgstr "" +msgstr "BezjÄ— kreivÄ—s seklys" #: editor/animation_track_editor.cpp msgid "Audio Playback Track" @@ -227,32 +227,29 @@ msgid "Animation length (frames)" msgstr "Animacija" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Animation length (seconds)" -msgstr "Animacijos Nodas" +msgstr "Animacijos ilgis (sekundÄ—mis)" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Add Track" -msgstr "Animacija: PridÄ—ti Takelį" +msgstr "PridÄ—ti įraÅ¡Ä…" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Animation Looping" -msgstr "Animacijos Nodas" +msgstr "Animacijos ciklas" #: editor/animation_track_editor.cpp #: modules/visual_script/visual_script_editor.cpp msgid "Functions:" -msgstr "" +msgstr "Funkcijos:" #: editor/animation_track_editor.cpp msgid "Audio Clips:" -msgstr "" +msgstr "Garso įraÅ¡ai:" #: editor/animation_track_editor.cpp msgid "Anim Clips:" -msgstr "" +msgstr "Animacijų įraÅ¡ai:" #: editor/animation_track_editor.cpp msgid "Change Track Path" @@ -260,38 +257,35 @@ msgstr "" #: editor/animation_track_editor.cpp msgid "Toggle this track on/off." -msgstr "" +msgstr "Ä®raÅ¡o koregavimas: įjungtas/ iÅ¡jungtas." #: editor/animation_track_editor.cpp msgid "Update Mode (How this property is set)" msgstr "" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Interpolation Mode" -msgstr "Animacijos Nodas" +msgstr "Interpoliacijos režimas" #: editor/animation_track_editor.cpp msgid "Loop Wrap Mode (Interpolate end with beginning on loop)" msgstr "" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Remove this track." -msgstr "Animacija: Panaikinti Takelį" +msgstr "Panaikinti šį įraÅ¡Ä…." #: editor/animation_track_editor.cpp -#, fuzzy msgid "Time (s): " -msgstr "TrukmÄ—:" +msgstr "Laikas (-ai): " #: editor/animation_track_editor.cpp msgid "Toggle Track Enabled" -msgstr "" +msgstr "Koreguoti įraÅ¡Ä… į įjungtas" #: editor/animation_track_editor.cpp msgid "Continuous" -msgstr "" +msgstr "TÄ™stinis" #: editor/animation_track_editor.cpp msgid "Discrete" @@ -299,24 +293,24 @@ msgstr "Diskretus" #: editor/animation_track_editor.cpp msgid "Trigger" -msgstr "" +msgstr "Gaidukas" #: editor/animation_track_editor.cpp msgid "Capture" -msgstr "" +msgstr "Fiksuoti" #: editor/animation_track_editor.cpp msgid "Nearest" -msgstr "" +msgstr "Artimiausias" #: editor/animation_track_editor.cpp editor/plugins/curve_editor_plugin.cpp #: editor/property_editor.cpp msgid "Linear" -msgstr "" +msgstr "Linijinis" #: editor/animation_track_editor.cpp msgid "Cubic" -msgstr "" +msgstr "Kubinis" #: editor/animation_track_editor.cpp msgid "Clamp Loop Interp" @@ -329,36 +323,31 @@ msgstr "" #: editor/animation_track_editor.cpp #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Insert Key" -msgstr "" +msgstr "Ä®terpti raktažodį" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Duplicate Key(s)" -msgstr "Duplikuoti" +msgstr "Kopijuoti raktažodį (-ius)" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Delete Key(s)" -msgstr "IÅ¡trinti EfektÄ…" +msgstr "IÅ¡trinti raktažodį (-ius)" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Change Animation Update Mode" -msgstr "Animacijos Nodas" +msgstr "Keisti animacijos atnaujinimo režimÄ…" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Change Animation Interpolation Mode" -msgstr "Animacijos Nodas" +msgstr "Keisti animacijos interpoliacijos režimÄ…" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Change Animation Loop Mode" -msgstr "Animacijos Nodas" +msgstr "Keiskite animacijos ciklo režimÄ…" #: editor/animation_track_editor.cpp msgid "Remove Anim Track" -msgstr "Animacija: Panaikinti Takelį" +msgstr "Animacija: panaikinti įraÅ¡Ä…" #: editor/animation_track_editor.cpp msgid "Create NEW track for %s and insert key?" @@ -382,7 +371,7 @@ msgstr "Sukurti" #: editor/animation_track_editor.cpp msgid "Anim Insert" -msgstr "" +msgstr "Animacija: įterpti" #: editor/animation_track_editor.cpp msgid "AnimationPlayer can't animate itself, only other players." @@ -401,13 +390,12 @@ msgid "Anim Insert Key" msgstr "" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Change Animation Step" -msgstr "Animacijos Nodas" +msgstr "Keisti animacijos žingsnį" #: editor/animation_track_editor.cpp msgid "Rearrange Tracks" -msgstr "" +msgstr "Naujai sudÄ—lioti įraÅ¡us" #: editor/animation_track_editor.cpp msgid "Transform tracks only apply to Spatial-based nodes." @@ -420,31 +408,34 @@ msgid "" "-AudioStreamPlayer2D\n" "-AudioStreamPlayer3D" msgstr "" +"Garso įraÅ¡ai gali nurodyti tik į Å¡iuos tipinius mazgus:\n" +"-GarsoSrautogrotuvas\n" +"-GarsoSrautogrotuvas2D\n" +"-GarsoSrautogrotuvas3D" #: editor/animation_track_editor.cpp msgid "Animation tracks can only point to AnimationPlayer nodes." -msgstr "" +msgstr "Animacijos įraÅ¡ai gali nurodyti į AnimacijosGrotuvo mazgus." #: editor/animation_track_editor.cpp msgid "An animation player can't animate itself, only other players." -msgstr "" +msgstr "Animacijos grotuvas negali animuoti savÄ™s, tik kitus grotuvus." #: editor/animation_track_editor.cpp msgid "Not possible to add a new track without a root" -msgstr "" +msgstr "NÄ—ra galimybÄ—s pridÄ—ti naujÄ… įraÅ¡Ä… be root" #: editor/animation_track_editor.cpp msgid "Invalid track for Bezier (no suitable sub-properties)" -msgstr "" +msgstr "Netinkamas BezjÄ— traktas (nÄ—ra tinkamų antrinių savybių)" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Add Bezier Track" -msgstr "Animacija: PridÄ—ti Takelį" +msgstr "PridÄ—ti BezjÄ— traktÄ…" #: editor/animation_track_editor.cpp msgid "Track path is invalid, so can't add a key." -msgstr "" +msgstr "Trakto kelias yra negalimas, negalima pridÄ—ti raktažodžio." #: editor/animation_track_editor.cpp msgid "Track is not of type Spatial, can't insert key" @@ -2330,10 +2321,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10427,6 +10414,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "IÅ¡trinti EfektÄ…" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "IÅ¡trinti EfektÄ…" @@ -12077,6 +12069,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/lv.po b/editor/translations/lv.po index 8417a6b650..2612b441c6 100644 --- a/editor/translations/lv.po +++ b/editor/translations/lv.po @@ -2290,10 +2290,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10229,6 +10225,11 @@ msgid "Make node as Root" msgstr "" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "IzdzÄ“st %d mezglus?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "IzdzÄ“st %d mezglus?" @@ -11858,6 +11859,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/mi.po b/editor/translations/mi.po index ab68a71ee2..07a3bdae3c 100644 --- a/editor/translations/mi.po +++ b/editor/translations/mi.po @@ -2243,10 +2243,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10107,6 +10103,10 @@ msgid "Make node as Root" msgstr "" #: editor/scene_tree_dock.cpp +msgid "Delete %d nodes and any children?" +msgstr "" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "" @@ -11708,6 +11708,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/ml.po b/editor/translations/ml.po index db5f5638f3..aa7844d7ab 100644 --- a/editor/translations/ml.po +++ b/editor/translations/ml.po @@ -2255,10 +2255,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10123,6 +10119,10 @@ msgid "Make node as Root" msgstr "" #: editor/scene_tree_dock.cpp +msgid "Delete %d nodes and any children?" +msgstr "" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "" @@ -11725,6 +11725,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/mr.po b/editor/translations/mr.po index 1700bcb138..043d7e643e 100644 --- a/editor/translations/mr.po +++ b/editor/translations/mr.po @@ -2250,10 +2250,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10114,6 +10110,10 @@ msgid "Make node as Root" msgstr "" #: editor/scene_tree_dock.cpp +msgid "Delete %d nodes and any children?" +msgstr "" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "" @@ -11715,6 +11715,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/ms.po b/editor/translations/ms.po index 160fa6e69f..ad70f291ca 100644 --- a/editor/translations/ms.po +++ b/editor/translations/ms.po @@ -2275,10 +2275,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10182,6 +10178,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Semua Pilihan" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Semua Pilihan" @@ -11795,6 +11796,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/nb.po b/editor/translations/nb.po index 4e7ca2dce1..dbad564d9a 100644 --- a/editor/translations/nb.po +++ b/editor/translations/nb.po @@ -2461,10 +2461,6 @@ msgid "There is no defined scene to run." msgstr "Det er ingen definert scene Ã¥ kjøre." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "Gjeldende scene ble aldri lagret, vennligst lagre før kjøring." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Kunne ikke starta subprosess!" @@ -10978,6 +10974,11 @@ msgstr "Lagre Scene" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Kutt Noder" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Kutt Noder" @@ -12703,6 +12704,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -13173,6 +13180,9 @@ msgstr "" msgid "Constants cannot be modified." msgstr "Konstanter kan ikke endres." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "Gjeldende scene ble aldri lagret, vennligst lagre før kjøring." + #~ msgid "Not in resource path." #~ msgstr "Ikke i resource path." diff --git a/editor/translations/nl.po b/editor/translations/nl.po index 3d560d3d6d..7f111ad901 100644 --- a/editor/translations/nl.po +++ b/editor/translations/nl.po @@ -40,12 +40,15 @@ # Tirrin <lensenjoe@gmail.com>, 2019. # Filip Van Raemdonck <arrawn@gmail.com>, 2019. # Julian <jdhoogvorst@gmail.com>, 2019, 2020. +# kitfka <philipthuijs@gmail.com>, 2020. +# Mike van Leeuwen <mkvanleeuwen@gmail.com>, 2020. +# marnicq van loon <marnicqvanloon@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-22 06:40+0000\n" -"Last-Translator: Stijn Hinlopen <f.a.hinlopen@gmail.com>\n" +"PO-Revision-Date: 2020-07-04 08:58+0000\n" +"Last-Translator: marnicq van loon <marnicqvanloon@gmail.com>\n" "Language-Team: Dutch <https://hosted.weblate.org/projects/godot-engine/godot/" "nl/>\n" "Language: nl\n" @@ -58,17 +61,17 @@ msgstr "" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Invalid type argument to convert(), use TYPE_* constants." -msgstr "Ongeldig argumenttype voor convert(), gebruik TYPE_* constanten." +msgstr "Ongeldig type argument voor convert(), gebruik TYPE_* constanten." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." -msgstr "Tekenreeks met lengte 1 verwacht (één karakter)." +msgstr "Verwachtte een tekenreeks van lengte 1 (één karakter)." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/mono/glue/gd_glue.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Not enough bytes for decoding bytes, or invalid format." -msgstr "Niet genoeg bytes om te decoderen, of ongeldig formaat." +msgstr "Niet genoeg bytes voor het decoderen van bytes, of ongeldig formaat." #: core/math/expression.cpp msgid "Invalid input %i (not passed) in expression" @@ -525,10 +528,12 @@ msgid "" msgstr "" "Deze animatie behoort tot een geïmporteerde scène, dus veranderingen aan " "geïmporteerde tracks zullen niet worden opgeslagen.\n" +"\n" "Om aangepaste tracks toe te kunnen voegen, moet in de importinstellingen van " "de scène en de \"Animation→Storage\" naar \"Files\" zetten en " "\"Animation→Keep Custom Tracks\" inschakelen. Importeer de scène dan " "opnieuw.\n" +"\n" "Anders kan je een importvoorinstelling gebruiken die animaties importeert en " "in verschillende bestanden opslaat." @@ -775,7 +780,7 @@ msgstr "Uitzoomen" #: editor/code_editor.cpp msgid "Reset Zoom" -msgstr "Initialiseer Zoom" +msgstr "Herstel Zoom" #: editor/code_editor.cpp msgid "Warnings" @@ -790,9 +795,8 @@ msgid "Method in target node must be specified." msgstr "Methode in doelknoop moet gespecificeerd worden." #: editor/connections_dialog.cpp -#, fuzzy msgid "Method name must be a valid identifier." -msgstr "Naam is geen geldige identifier:" +msgstr "Methodenaam is geen geldige naam." #: editor/connections_dialog.cpp msgid "" @@ -1494,7 +1498,7 @@ msgstr "Autoloads opnieuw ordenen" #: editor/editor_autoload_settings.cpp msgid "Can't add autoload:" -msgstr "Autoload kon niet toevoegd worden:" +msgstr "Autoload kan niet toevoegd worden:" #: editor/editor_autoload_settings.cpp msgid "Add AutoLoad" @@ -1865,11 +1869,11 @@ msgstr "Ga Omhoog" #: editor/editor_file_dialog.cpp msgid "Toggle Hidden Files" -msgstr "Toggle Verborgen Bestanden" +msgstr "Verborgen Bestanden Omschakelen" #: editor/editor_file_dialog.cpp msgid "Toggle Favorite" -msgstr "Toggle Favoriet" +msgstr "Favoriet Omschakelen" #: editor/editor_file_dialog.cpp msgid "Toggle Mode" @@ -2365,10 +2369,6 @@ msgid "There is no defined scene to run." msgstr "Er is geen startscène ingesteld." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "De huidige scène is nooit opgeslagen, sla het op voor het uitvoeren." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Kon het subproces niet opstarten!" @@ -10596,6 +10596,11 @@ msgid "Make node as Root" msgstr "Knoop tot wortelknoop maken" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Verwijder knoop \"%s\" en zijn kinderen?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "Verwijder %d knopen?" @@ -12288,6 +12293,12 @@ msgid "" "shape resource for it!" msgstr "Een CollisionShape2D heeft een vorm nodig in de Shape-eigenschap!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12862,6 +12873,10 @@ msgstr "Varyings kunnen alleen worden toegewezenin vertex functies." msgid "Constants cannot be modified." msgstr "Constanten kunnen niet worden aangepast." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "De huidige scène is nooit opgeslagen, sla het op voor het uitvoeren." + #~ msgid "Not in resource path." #~ msgstr "Niet in bronpad." diff --git a/editor/translations/or.po b/editor/translations/or.po index d6678c2819..5859fe6b0a 100644 --- a/editor/translations/or.po +++ b/editor/translations/or.po @@ -2249,10 +2249,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10113,6 +10109,10 @@ msgid "Make node as Root" msgstr "" #: editor/scene_tree_dock.cpp +msgid "Delete %d nodes and any children?" +msgstr "" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "" @@ -11714,6 +11714,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/pl.po b/editor/translations/pl.po index ed53a98bed..2a09acd7c5 100644 --- a/editor/translations/pl.po +++ b/editor/translations/pl.po @@ -40,12 +40,13 @@ # Cezary Stasiak <cezary.p.stasiak@gmail.com>, 2019. # Jan LigudziÅ„ski <jan.ligudzinski@gmail.com>, 2020. # Adam Jagoda <kontakt@lukasz.xyz>, 2020. +# Filip Glura <mcmr.slendy@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-25 08:40+0000\n" -"Last-Translator: Adam Jagoda <kontakt@lukasz.xyz>\n" +"PO-Revision-Date: 2020-07-21 13:41+0000\n" +"Last-Translator: Filip Glura <mcmr.slendy@gmail.com>\n" "Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/" "godot/pl/>\n" "Language: pl\n" @@ -69,8 +70,7 @@ msgstr "Oczekiwano ciÄ…gu znaków o dÅ‚ugoÅ›ci 1 (znaku)." #: modules/mono/glue/gd_glue.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Not enough bytes for decoding bytes, or invalid format." -msgstr "" -"NiewystarczajÄ…ca ilość bajtów dla bajtów dekodujÄ…cych, albo zÅ‚y format." +msgstr "NiewystarczajÄ…ca ilość bajtów dla bajtów dekodujÄ…cych lub zÅ‚y format." #: core/math/expression.cpp msgid "Invalid input %i (not passed) in expression" @@ -79,7 +79,7 @@ msgstr "NiewÅ‚aÅ›ciwe dane %i (nie przekazane) w wyrażeniu" #: core/math/expression.cpp msgid "self can't be used because instance is null (not passed)" msgstr "" -"self nie może być użyte ponieważ instancja jest równa zeru (nie przekazano)" +"self nie może być użyte, ponieważ instancja jest nullem (nie przekazano)" #: core/math/expression.cpp msgid "Invalid operands to operator %s, %s and %s." @@ -2355,12 +2355,6 @@ msgid "There is no defined scene to run." msgstr "Nie ma zdefiniowanej sceny do uruchomienia." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"Aktualna scena nie zostaÅ‚a zapisana, proszÄ™ zapisać scenÄ™ przed " -"uruchomieniem." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Nie można byÅ‚o uruchomić podprocesu!" @@ -10566,6 +10560,11 @@ msgid "Make node as Root" msgstr "ZmieÅ„ wÄ™zeÅ‚ na KorzeÅ„" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Usunąć wÄ™zeÅ‚ \"%s\" oraz jego wÄ™zÅ‚y potomne?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "Usunąć %d wÄ™złów?" @@ -12262,6 +12261,12 @@ msgstr "" "KsztaÅ‚t jest niezbÄ™dny do dziaÅ‚ania CollisionShape2D. ProszÄ™ utworzyć zasób " "Shape!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12834,6 +12839,11 @@ msgstr "Varying może być przypisane tylko w funkcji wierzchoÅ‚ków." msgid "Constants cannot be modified." msgstr "StaÅ‚e nie mogÄ… być modyfikowane." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "Aktualna scena nie zostaÅ‚a zapisana, proszÄ™ zapisać scenÄ™ przed " +#~ "uruchomieniem." + #~ msgid "Not in resource path." #~ msgstr "Nie znaleziono w Å›cieżce zasobów." diff --git a/editor/translations/pr.po b/editor/translations/pr.po index bfa3d0b52c..bf2d3ef0ad 100644 --- a/editor/translations/pr.po +++ b/editor/translations/pr.po @@ -2327,10 +2327,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10451,6 +10447,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Slit th' Node" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Slit th' Node" @@ -12146,6 +12147,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po index 70878acad2..e2e19c99ce 100644 --- a/editor/translations/pt_BR.po +++ b/editor/translations/pt_BR.po @@ -94,12 +94,16 @@ # Kleyton Luiz de Sousa Vieira <kleytonluizdesouzavieira@gmail.com>, 2020. # Felipe Jesus Macedo <fmacedo746@gmail.com>, 2020. # José Paulo <jose.paulo1919@gmail.com>, 2020. +# Necco <necco@outlook.com>, 2020. +# Marcelo Silveira Hayden <mshayden.1998@gmail.com>, 2020. +# GUILHERME SOUZA REIS DE MELO LOPES <guilhermesrml@unipam.edu.br>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: 2016-05-30\n" -"PO-Revision-Date: 2020-06-25 08:40+0000\n" -"Last-Translator: José Paulo <jose.paulo1919@gmail.com>\n" +"PO-Revision-Date: 2020-07-26 15:41+0000\n" +"Last-Translator: GUILHERME SOUZA REIS DE MELO LOPES <guilhermesrml@unipam." +"edu.br>\n" "Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/" "godot-engine/godot/pt_BR/>\n" "Language: pt_BR\n" @@ -182,7 +186,7 @@ msgstr "EiB" #: editor/animation_bezier_editor.cpp msgid "Free" -msgstr "Livre" +msgstr "Gratuito" #: editor/animation_bezier_editor.cpp msgid "Balanced" @@ -1557,7 +1561,7 @@ msgstr "Caminho:" #: editor/editor_autoload_settings.cpp msgid "Node Name:" -msgstr "Nome do nó:" +msgstr "Nome do Nó:" #: editor/editor_autoload_settings.cpp editor/editor_help_search.cpp #: editor/editor_profiler.cpp editor/project_manager.cpp @@ -1705,7 +1709,7 @@ msgstr "Importar Dock" #: editor/editor_feature_profile.cpp msgid "Node Dock" -msgstr "Dock de Nós" +msgstr "Painel de Nós" #: editor/editor_feature_profile.cpp msgid "FileSystem and Import Docks" @@ -2410,10 +2414,6 @@ msgid "There is no defined scene to run." msgstr "Não há cena definida para rodar." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "A cena atual nunca foi salva. Por favor salve antes de rodá-la." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Não se pôde iniciar sub-processo!" @@ -3954,7 +3954,7 @@ msgstr "Grupos" #: editor/groups_editor.cpp msgid "Nodes Not in Group" -msgstr "Nodes fora do Grupo" +msgstr "Nós fora do Grupo" #: editor/groups_editor.cpp editor/scene_tree_dock.cpp #: editor/scene_tree_editor.cpp @@ -4052,7 +4052,7 @@ msgstr "Erro ao rodar script pós-importação:" #: editor/import/resource_importer_scene.cpp msgid "Did you return a Node-derived object in the `post_import()` method?" -msgstr "Você retornou um objeto derivado de nó no método `post import ()`?" +msgstr "Você retornou um objeto derivado de Nó no método `post_import()`?" #: editor/import/resource_importer_scene.cpp msgid "Saving..." @@ -4481,7 +4481,7 @@ msgid "" "Animation player has no valid root node path, so unable to retrieve track " "names." msgstr "" -"O reprodutor de animações não tem caminho de nó raiz válido, então não é " +"O reprodutor de animações não tem um caminho de nó raiz válido, então não é " "possÃvel obter os nomes das trilhas." #: editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -4504,7 +4504,7 @@ msgstr "Nó Renomeado" #: editor/plugins/animation_blend_tree_editor_plugin.cpp #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Add Node..." -msgstr "Adicionar nó..." +msgstr "Adicionar Nó..." #: editor/plugins/animation_blend_tree_editor_plugin.cpp #: editor/plugins/root_motion_editor_plugin.cpp @@ -4763,7 +4763,7 @@ msgstr "Viagem" #: editor/plugins/animation_state_machine_editor.cpp msgid "Start and end nodes are needed for a sub-transition." -msgstr "Nós inicial e final são necessários para uma sub-transição." +msgstr "Nó inicial e final são necessários para uma sub-transição." #: editor/plugins/animation_state_machine_editor.cpp msgid "No playback resource set at path: %s." @@ -5290,15 +5290,14 @@ msgstr "" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Presets for the anchors and margins values of a Control node." -msgstr "" -"Predefinições para os valores de âncoras e margens de um nó de controle." +msgstr "Predefinições para os valores de âncoras e margens de um nó Control." #: editor/plugins/canvas_item_editor_plugin.cpp msgid "" "When active, moving Control nodes changes their anchors instead of their " "margins." msgstr "" -"Quando ativo, os nós de Controle móveis mudam suas âncoras em vez de suas " +"Quando ativo, os nós Control móveis mudam suas âncoras em vez de suas " "margens." #: editor/plugins/canvas_item_editor_plugin.cpp @@ -7527,7 +7526,7 @@ msgstr "Usar Espaço Local" #: editor/plugins/spatial_editor_plugin.cpp msgid "Use Snap" -msgstr "Use Snap" +msgstr "Use Encaixar" #: editor/plugins/spatial_editor_plugin.cpp msgid "Bottom View" @@ -8997,11 +8996,11 @@ msgstr "Converte um valor em radianos para graus." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Base-e Exponential." -msgstr "Exponencial de Base e." +msgstr "Exponencial de base e." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Base-2 Exponential." -msgstr "Exponencial na base 2." +msgstr "Exponencial de base 2." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Finds the nearest integer less than or equal to the parameter." @@ -9021,7 +9020,7 @@ msgstr "Logaritmo natural." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Base-2 logarithm." -msgstr "Logaritmo de base-2." +msgstr "Logaritmo de base 2." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the greater of two values." @@ -9395,8 +9394,8 @@ msgid "" "Returns falloff based on the dot product of surface normal and view " "direction of camera (pass associated inputs to it)." msgstr "" -"Retorna decaimento com base no produto escalar da normal da superfÃcie com o " -"a direção de visão da câmera (passe as entradas associadas a ele)." +"Retorna decaimento com base no produto escalar da normal da superfÃcie com a " +"direção de visão da câmera (passe as entradas associadas a ele)." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "" @@ -10628,6 +10627,11 @@ msgid "Make node as Root" msgstr "Tornar Raiz o Nó" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Deletar nó \"%s\" e seus filhos?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "Excluir %d nós?" @@ -11915,11 +11919,11 @@ msgstr "Localizar Tipo de Nó" #: modules/visual_script/visual_script_editor.cpp msgid "Copy Nodes" -msgstr "Copiar Nodes" +msgstr "Copiar Nós" #: modules/visual_script/visual_script_editor.cpp msgid "Cut Nodes" -msgstr "Recortar Nodes" +msgstr "Recortar Nós" #: modules/visual_script/visual_script_editor.cpp msgid "Make Function" @@ -11951,7 +11955,7 @@ msgstr "Nome da propriedade de Ãndice inválido." #: modules/visual_script/visual_script_func_nodes.cpp msgid "Base object is not a Node!" -msgstr "Objeto base não é um nó!" +msgstr "Objeto base não é um Nó!" #: modules/visual_script/visual_script_func_nodes.cpp msgid "Path does not lead Node!" @@ -12049,10 +12053,9 @@ msgstr "" "na predefinição." #: platform/android/export/export.cpp -#, fuzzy msgid "Release keystore incorrectly configured in the export preset." msgstr "" -"Keystore de liberação icorretamente configurada na predefinição de " +"Keystore de liberação incorretamente configurada na predefinição de " "exportação." #: platform/android/export/export.cpp @@ -12097,21 +12100,18 @@ msgstr "" "\"Use Custom Build\" precisa estar ativo para ser possÃvel utilizar plugins." #: platform/android/export/export.cpp -#, fuzzy msgid "" "\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR" "\"." msgstr "" -"\"Degrees Of Freedom\" só é válido quando o \"Oculus Mobile VR\" está no " -"\"Mode Xr\"." +"\"Degrees Of Freedom\" só é válido quando o \"Xr Mode\" é \"Oculus Mobile VR" +"\"." #: platform/android/export/export.cpp -#, fuzzy msgid "" "\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"." msgstr "" -"\"Hand Tracking\" só é válido quando o\"Oculus Mobile VR\" está no \"Xr Mode" -"\"." +"\"Hand Tracking\" só é válido quando o \"Xr Mode\" é \"Oculus Mobile VR\"." #: platform/android/export/export.cpp msgid "" @@ -12327,6 +12327,12 @@ msgstr "" "Uma forma deve ser fornecida para que o nó CollisionShape2D funcione. Por " "favor, crie um recurso de forma para ele!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12807,7 +12813,7 @@ msgid "" "The Hint Tooltip won't be displayed as the control's Mouse Filter is set to " "\"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"." msgstr "" -"A sugestão de dica não será exibida quando o Filtro do Mouse do controle " +"A Sugestão de Dica não será exibida quando o Filtro do Mouse do controle " "estiver definido como \"Ignorar\". Para resolver isto, defina o Filtro do " "Mouse como \"Parar\" ou \"Passar\"." @@ -12840,8 +12846,8 @@ msgid "" "Use a container as child (VBox, HBox, etc.), or a Control and set the custom " "minimum size manually." msgstr "" -"Um ScrollContainer foi feito para trabalhar com um componente filho único.\n" -"Use um container como filho (VBox, HBox, etc.) ou um Control e defina o " +"Um ScrollContainer foi feito para trabalhar com um único componente filho.\n" +"Use um contêiner como filho (VBox, HBox, etc.) ou um Control e defina o " "tamanho mÃnimo manualmente." #: scene/gui/tree.cpp @@ -12871,7 +12877,7 @@ msgstr "" #: scene/main/viewport.cpp msgid "Viewport size must be greater than 0 to render anything." msgstr "" -"O tamanho da viewport deve ser maior do que 0 para renderizar qualquer coisa." +"O tamanho da Viewport deve ser maior do que 0 para renderizar qualquer coisa." #: scene/resources/visual_shader_nodes.cpp msgid "Invalid source for preview." @@ -12901,6 +12907,9 @@ msgstr "Variáveis só podem ser atribuÃdas na função de vértice." msgid "Constants cannot be modified." msgstr "Constantes não podem serem modificadas." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "A cena atual nunca foi salva. Por favor salve antes de rodá-la." + #~ msgid "Not in resource path." #~ msgstr "Não está no caminho de recursos." diff --git a/editor/translations/pt_PT.po b/editor/translations/pt_PT.po index 54accb0d6f..ba1f5b31d5 100644 --- a/editor/translations/pt_PT.po +++ b/editor/translations/pt_PT.po @@ -20,7 +20,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-15 12:01+0000\n" +"PO-Revision-Date: 2020-06-26 06:11+0000\n" "Last-Translator: João Lopes <linux-man@hotmail.com>\n" "Language-Team: Portuguese (Portugal) <https://hosted.weblate.org/projects/" "godot-engine/godot/pt_PT/>\n" @@ -29,7 +29,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.1\n" +"X-Generator: Weblate 4.2-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -768,9 +768,8 @@ msgid "Method in target node must be specified." msgstr "Método no nó alvo deve ser especificado." #: editor/connections_dialog.cpp -#, fuzzy msgid "Method name must be a valid identifier." -msgstr "O nome não é um identificador válido:" +msgstr "O nome do método tem de ser um identificador válido." #: editor/connections_dialog.cpp msgid "" @@ -2339,10 +2338,6 @@ msgid "There is no defined scene to run." msgstr "Não existe cena definida para execução." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "A cena atual nunca foi guardada, por favor guarde-a antes de executar." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Não consegui iniciar o subprocesso!" @@ -10530,6 +10525,11 @@ msgid "Make node as Root" msgstr "Tornar Nó Raiz" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Apagar nó \"%s\" e filhos?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "Apagar %d nós?" @@ -12227,6 +12227,12 @@ msgstr "" "Uma forma tem de ser fornecida para CollisionShape2D funcionar. Crie um " "recurso forma!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12794,6 +12800,10 @@ msgstr "Variações só podem ser atribuÃdas na função vértice." msgid "Constants cannot be modified." msgstr "Constantes não podem ser modificadas." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "A cena atual nunca foi guardada, por favor guarde-a antes de executar." + #~ msgid "Not in resource path." #~ msgstr "Não está no caminho do recurso." diff --git a/editor/translations/ro.po b/editor/translations/ro.po index cbf6a8f0a0..ba5fbcf11a 100644 --- a/editor/translations/ro.po +++ b/editor/translations/ro.po @@ -8,15 +8,17 @@ # TigerxWood <TigerxWood@gmail.com>, 2018. # Grigore Antoniuc <grisa181@gmail.com>, 2018. # Boby Ilea <boby.ilea@gmail.com>, 2019. -# EVOKZH <avip.ady@gmail.com>, 2019. +# EVOKZH <avip.ady@gmail.com>, 2019, 2020. # Marincia Catalin <catalinmarincia@gmail.com>, 2020. # Marincia Cătălin <catalinmarincia@gmail.com>, 2020. +# Teodor <teo.virghi@yahoo.ro>, 2020. +# f0roots <f0rootss@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-01-23 15:05+0000\n" -"Last-Translator: Marincia Cătălin <catalinmarincia@gmail.com>\n" +"PO-Revision-Date: 2020-07-19 01:27+0000\n" +"Last-Translator: f0roots <f0rootss@gmail.com>\n" "Language-Team: Romanian <https://hosted.weblate.org/projects/godot-engine/" "godot/ro/>\n" "Language: ro\n" @@ -25,7 +27,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " "20)) ? 1 : 2;\n" -"X-Generator: Weblate 3.11-dev\n" +"X-Generator: Weblate 4.2-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -56,7 +58,7 @@ msgstr "Operanzi invalizi la operatorii %s, %s È™i %s." #: core/math/expression.cpp msgid "Invalid index of type %s for base type %s" -msgstr "Indice invalid de tip %s pentru tipul de bază %s" +msgstr "Index invalid de tip %s pentru tipul de bază %s" #: core/math/expression.cpp msgid "Invalid named index '%s' for base type %s" @@ -108,7 +110,7 @@ msgstr "Echilibrat" #: editor/animation_bezier_editor.cpp msgid "Mirror" -msgstr "Reflectează" +msgstr "Oglinda" #: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp msgid "Time:" @@ -120,7 +122,7 @@ msgstr "Valoare:" #: editor/animation_bezier_editor.cpp msgid "Insert Key Here" -msgstr "Inserează Cheie Aici" +msgstr "Inserează Cheia Aici" #: editor/animation_bezier_editor.cpp msgid "Duplicate Selected Key(s)" @@ -140,7 +142,7 @@ msgstr "Mută Punct Bezier" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Duplicate Keys" -msgstr "Anim Clonare Chei" +msgstr "Anim Chei duplicate" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Delete Keys" @@ -160,7 +162,7 @@ msgstr "Anim Schimbare transformare" #: editor/animation_track_editor.cpp msgid "Anim Change Keyframe Value" -msgstr "Anim Schimbare valoare cadre cheie" +msgstr "Anim Schimbare valoare Keyframe" #: editor/animation_track_editor.cpp msgid "Anim Change Call" @@ -267,6 +269,7 @@ msgstr "Mod Intercalare" #: editor/animation_track_editor.cpp msgid "Loop Wrap Mode (Interpolate end with beginning on loop)" msgstr "" +"Mod de înfășurare a buclei (Intercalează sfârÈ™itul cu începutul în buclă)" #: editor/animation_track_editor.cpp msgid "Remove this track." @@ -311,20 +314,20 @@ msgstr "Cubic" #: editor/animation_track_editor.cpp msgid "Clamp Loop Interp" -msgstr "" +msgstr "LimitaÈ›i intercalarea buclei" #: editor/animation_track_editor.cpp msgid "Wrap Loop Interp" -msgstr "" +msgstr "ÃŽnfășuraÈ›i intercalarea buclei" #: editor/animation_track_editor.cpp #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Insert Key" -msgstr "Inserează Notă" +msgstr "Inserare cheie" #: editor/animation_track_editor.cpp msgid "Duplicate Key(s)" -msgstr "Clonare Chei(s)" +msgstr "Clonare Chei" #: editor/animation_track_editor.cpp msgid "Delete Key(s)" @@ -405,6 +408,10 @@ msgid "" "-AudioStreamPlayer2D\n" "-AudioStreamPlayer3D" msgstr "" +"Track-urile audio pot sa fie folosite numai în noduri de tipul:\n" +"- AudioStreamPlayer\n" +"-AudioStreamPlayer2D\n" +"-AudioStreamPlayer3D" #: editor/animation_track_editor.cpp msgid "Animation tracks can only point to AnimationPlayer nodes." @@ -413,6 +420,8 @@ msgstr "Pistele de animaÈ›ie pot direcÈ›iona numai nodurilor AnimaÈ›ieJucător." #: editor/animation_track_editor.cpp msgid "An animation player can't animate itself, only other players." msgstr "" +"Un player de animatie nu se poate anima insusi, doar alti playeri de " +"animatie." #: editor/animation_track_editor.cpp msgid "Not possible to add a new track without a root" @@ -489,6 +498,15 @@ msgid "" "Alternatively, use an import preset that imports animations to separate " "files." msgstr "" +"Aceasta animaÈ›ie aparÈ›ine unei scene importante, schimbările de importare " +"ale Track-urilor nu vor fi salvate.\n" +"\n" +"Pentru a activa opÈ›iunea de a adaugă Track-uri, navigaÈ›i la setările de " +"import ale scenei È™i setaÈ›i\n" +"\"AnimaÈ›ie > Depozitare\" către \"FiÈ™iere\", activaÈ›i \"AnimaÈ›ie > Păstrează " +"Track-uri personalizate\", după re-importaÈ›i.\n" +"Alternativ, folosiÈ›i un import presetat care importa animaÈ›iile către " +"fiÈ™iere separate." #: editor/animation_track_editor.cpp msgid "Warning: Editing imported animation" @@ -652,11 +670,11 @@ msgstr "Anim AdăugaÈ›i Pistă Audio" #: editor/animation_track_editor_plugins.cpp msgid "Change Audio Track Clip Start Offset" -msgstr "" +msgstr "SchimbaÈ›i decalajul de pornire a clipului audio" #: editor/animation_track_editor_plugins.cpp msgid "Change Audio Track Clip End Offset" -msgstr "" +msgstr "SchimbaÈ›i decalajul de oprire a clipului audio" #: editor/array_property_edit.cpp msgid "Resize Array" @@ -679,9 +697,8 @@ msgid "Line Number:" msgstr "Linia Numărul:" #: editor/code_editor.cpp -#, fuzzy msgid "%d replaced." -msgstr "ÃŽnlocuiÈ›i" +msgstr "%d ÃŽnlocuit" #: editor/code_editor.cpp editor/editor_help.cpp msgid "%d match." @@ -718,23 +735,23 @@ msgstr "Standard" #: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp msgid "Toggle Scripts Panel" -msgstr "" +msgstr "Porniti sau opriti panoul de scripturi" #: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/texture_region_editor_plugin.cpp #: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp msgid "Zoom In" -msgstr "Zoom-aÈ›i ÃŽn" +msgstr "Apropiere" #: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/texture_region_editor_plugin.cpp #: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp msgid "Zoom Out" -msgstr "Zoom-aÈ›i Afară" +msgstr "Departare" #: editor/code_editor.cpp msgid "Reset Zoom" -msgstr "ResetaÈ›i Zoom-area" +msgstr "ResetaÈ›i zoom-ul" #: editor/code_editor.cpp msgid "Warnings" @@ -749,9 +766,8 @@ msgid "Method in target node must be specified." msgstr "Metoda din nodul È›intă trebuie specificată." #: editor/connections_dialog.cpp -#, fuzzy msgid "Method name must be a valid identifier." -msgstr "Metoda din nodul È›intă trebuie specificată." +msgstr "Numele metodei trebuie să fie un identificator valid." #: editor/connections_dialog.cpp msgid "" @@ -818,6 +834,7 @@ msgstr "Amânat(ă)" msgid "" "Defers the signal, storing it in a queue and only firing it at idle time." msgstr "" +"Amână semnalul stocând-ul într-o coadă, dându-i drumul numai la timp inactiv." #: editor/connections_dialog.cpp msgid "Oneshot" @@ -1289,7 +1306,7 @@ msgstr "OpÈ›iuni Pistă Audio" #: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp #: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp msgid "Duplicate" -msgstr "DuplicaÈ›i" +msgstr "Duplicat" #: editor/editor_audio_buses.cpp msgid "Reset Volume" @@ -1419,7 +1436,7 @@ msgstr "" #: editor/editor_autoload_settings.cpp msgid "Keyword cannot be used as an autoload name." -msgstr "" +msgstr "Cuvântul cheie nu poate fi utilizat ca nume de încărcare automată." #: editor/editor_autoload_settings.cpp msgid "Autoload '%s' already exists!" @@ -1451,7 +1468,7 @@ msgstr "RearanjaÈ›i Autoload-urile" #: editor/editor_autoload_settings.cpp msgid "Can't add autoload:" -msgstr "" +msgstr "Nu pot adaugă încărcare automata:" #: editor/editor_autoload_settings.cpp msgid "Add AutoLoad" @@ -1514,7 +1531,7 @@ msgstr "AlegeÅ£i un Director" #: editor/filesystem_dock.cpp editor/project_manager.cpp #: scene/gui/file_dialog.cpp msgid "Create Folder" -msgstr "CreaÈ›i Director" +msgstr "Creare folder" #: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp #: editor/editor_plugin_settings.cpp editor/filesystem_dock.cpp @@ -1538,7 +1555,7 @@ msgstr "FiÅŸierul se Stochează:" #: editor/editor_export.cpp msgid "No export template found at the expected path:" -msgstr "" +msgstr "Nu a fost găsit niciun È™ablon de export pe calea aÈ™teptată:" #: editor/editor_export.cpp msgid "Packing" @@ -1549,12 +1566,16 @@ msgid "" "Target platform requires 'ETC' texture compression for GLES2. Enable 'Import " "Etc' in Project Settings." msgstr "" +"Platforma È›intă necesită textură compresată „ETC†pentru GLES2. ActivaÈ›i " +"„Import Etc†în Setările proiectului." #: editor/editor_export.cpp msgid "" "Target platform requires 'ETC2' texture compression for GLES3. Enable " "'Import Etc 2' in Project Settings." msgstr "" +"Platforma È›intă necesită textură compresata „ETC2†pentru GLES3. ActivaÈ›i " +"„Import Etc 2†în Setările proiectului." #: editor/editor_export.cpp msgid "" @@ -1563,6 +1584,10 @@ msgid "" "Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback " "Enabled'." msgstr "" +"Platforma È›intă necesită o textură compresată „ETC†pentru revenirea " +"driverului la GLES2.\n" +"ActivaÈ›i „Import Etc†în Setările de proiect sau dezactivaÈ›i „Driver " +"Fallback Enabledâ€." #: editor/editor_export.cpp platform/android/export/export.cpp #: platform/iphone/export/export.cpp platform/javascript/export/export.cpp @@ -1574,7 +1599,7 @@ msgstr "FiÈ™ierul È™ablon de depanare personalizat nu a fost găsit." #: platform/iphone/export/export.cpp platform/javascript/export/export.cpp #: platform/osx/export/export.cpp platform/uwp/export/export.cpp msgid "Custom release template not found." -msgstr "" +msgstr "Șablonul personalizat de lansare nu a fost găsit." #: editor/editor_export.cpp platform/javascript/export/export.cpp msgid "Template file not found:" @@ -1583,6 +1608,7 @@ msgstr "FiÈ™ierul È™ablon nu a fost găsit:" #: editor/editor_export.cpp msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB." msgstr "" +"La exporturile pe 32 de biÈ›i PCK-ul încorporat nu poate fi mai mare de 4 GiB." #: editor/editor_feature_profile.cpp msgid "3D Editor" @@ -1590,7 +1616,7 @@ msgstr "Editor 3D" #: editor/editor_feature_profile.cpp msgid "Script Editor" -msgstr "Editorul de Scripturi" +msgstr "Editor de scripturi" #: editor/editor_feature_profile.cpp msgid "Asset Library" @@ -1619,6 +1645,7 @@ msgstr "ȘtergeÈ›i profilul '%s'?(ireversibil)" #: editor/editor_feature_profile.cpp msgid "Profile must be a valid filename and must not contain '.'" msgstr "" +"Profilul trebuie sa fie un nume valid de fisier si nu trebuie sa contina '.'" #: editor/editor_feature_profile.cpp msgid "Profile with this name already exists." @@ -1626,7 +1653,7 @@ msgstr "Un profil cu acest nume există deja." #: editor/editor_feature_profile.cpp msgid "(Editor Disabled, Properties Disabled)" -msgstr "" +msgstr "(Editorul Dezactivat, Proprietatile Dezactivate)" #: editor/editor_feature_profile.cpp msgid "(Properties Disabled)" @@ -1650,7 +1677,7 @@ msgstr "Proprietăți Activate:" #: editor/editor_feature_profile.cpp msgid "Enabled Features:" -msgstr "" +msgstr "Caracteristici active:" #: editor/editor_feature_profile.cpp msgid "Enabled Classes:" @@ -1658,13 +1685,15 @@ msgstr "Clase Activate:" #: editor/editor_feature_profile.cpp msgid "File '%s' format is invalid, import aborted." -msgstr "" +msgstr "Formatul fiÈ™ierului '%s' este invalid, importarea este anulată." #: editor/editor_feature_profile.cpp msgid "" "Profile '%s' already exists. Remove it first before importing, import " "aborted." msgstr "" +"Profilul '%s' este deja existent. Elimină-l inainte de a-l importa, " +"importara este anulata." #: editor/editor_feature_profile.cpp msgid "Error saving profile to path: '%s'." @@ -1672,7 +1701,7 @@ msgstr "Eroare la salvarea profilului la calea: '%s'." #: editor/editor_feature_profile.cpp msgid "Unset" -msgstr "" +msgstr "Nesetat(ă)" #: editor/editor_feature_profile.cpp msgid "Current Profile:" @@ -1686,7 +1715,7 @@ msgstr "FaceÈ›i Curent" #: editor/plugins/animation_player_editor_plugin.cpp #: editor/plugins/version_control_editor_plugin.cpp msgid "New" -msgstr "" +msgstr "Nou" #: editor/editor_feature_profile.cpp editor/editor_node.cpp #: editor/project_manager.cpp @@ -1743,7 +1772,7 @@ msgstr "SelectaÅ£i directorul curent" #: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp msgid "Copy Path" -msgstr "CopiaÅ£i Calea" +msgstr "Copiere cale" #: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp msgid "Open in File Manager" @@ -1761,7 +1790,7 @@ msgstr "Director Nou..." #: editor/editor_file_dialog.cpp editor/find_in_files.cpp #: editor/plugins/version_control_editor_plugin.cpp msgid "Refresh" -msgstr "ReîmprospătaÈ›i" +msgstr "Reîmprospătare" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "All Recognized" @@ -1820,19 +1849,19 @@ msgstr "ComutaÈ›i Favorite" #: editor/editor_file_dialog.cpp msgid "Toggle Mode" -msgstr "Modul de Comutare" +msgstr "Comutare mod" #: editor/editor_file_dialog.cpp msgid "Focus Path" -msgstr "Calea Focală" +msgstr "Cale focalizare" #: editor/editor_file_dialog.cpp msgid "Move Favorite Up" -msgstr "DeplasaÈ›i Favorit Sus" +msgstr "Mutare favorită în sus" #: editor/editor_file_dialog.cpp msgid "Move Favorite Down" -msgstr "DeplasaÈ›i Favorit Jos" +msgstr "Mutare favorită în jos" #: editor/editor_file_dialog.cpp msgid "Go to previous folder." @@ -1893,6 +1922,8 @@ msgid "" "There are multiple importers for different types pointing to file %s, import " "aborted" msgstr "" +"Există importatori multiplii pentru tipuri diferite care trimit spre " +"fiÈ™ierul %s, importarea este anulată" #: editor/editor_file_system.cpp msgid "(Re)Importing Assets" @@ -1929,7 +1960,7 @@ msgstr "Proprietăți" #: editor/editor_help.cpp msgid "override:" -msgstr "" +msgstr "extindere:" #: editor/editor_help.cpp msgid "default:" @@ -1953,7 +1984,7 @@ msgstr "Constante" #: editor/editor_help.cpp msgid "Property Descriptions" -msgstr "Descriere Proprietate" +msgstr "Descrieri Proprietate" #: editor/editor_help.cpp msgid "(value)" @@ -2051,15 +2082,15 @@ msgstr "Proprietate Temă" #: editor/editor_inspector.cpp editor/project_settings_editor.cpp msgid "Property:" -msgstr "" +msgstr "Proprietate:" #: editor/editor_inspector.cpp msgid "Set" -msgstr "" +msgstr "StabileÈ™te" #: editor/editor_inspector.cpp msgid "Set Multiple:" -msgstr "" +msgstr "Seteaza Multiple:" #: editor/editor_log.cpp msgid "Output:" @@ -2095,7 +2126,7 @@ msgstr "Start" #: editor/editor_network_profiler.cpp msgid "%s/s" -msgstr "" +msgstr "%s/s" #: editor/editor_network_profiler.cpp msgid "Down" @@ -2103,7 +2134,7 @@ msgstr "Descarcă" #: editor/editor_network_profiler.cpp msgid "Up" -msgstr "" +msgstr "Sus" #: editor/editor_network_profiler.cpp editor/editor_node.cpp msgid "Node" @@ -2127,16 +2158,16 @@ msgstr "" #: editor/editor_node.cpp editor/project_manager.cpp msgid "New Window" -msgstr "" +msgstr "Fereastra Noua" #: editor/editor_node.cpp msgid "Imported resources can't be saved." -msgstr "" +msgstr "Resursele importate nu pot fi salvate." #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp #: scene/gui/dialogs.cpp msgid "OK" -msgstr "" +msgstr "OK" #: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp msgid "Error saving resource!" @@ -2147,6 +2178,8 @@ msgid "" "This resource can't be saved because it does not belong to the edited scene. " "Make it unique first." msgstr "" +"Resursa aceasta nu poate fi salvată deoarece nu aparÈ›ine scenei editate. " +"Resursa trebuie să fie unică." #: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp msgid "Save Resource As..." @@ -2166,7 +2199,7 @@ msgstr "Eroare la salvare." #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp msgid "Can't open '%s'. The file could have been moved or deleted." -msgstr "" +msgstr "'%s' nu poate fi deschis. FiÈ™ierul ar putea fi modificat sau È™ters." #: editor/editor_node.cpp msgid "Error while parsing '%s'." @@ -2205,6 +2238,8 @@ msgid "" "This scene can't be saved because there is a cyclic instancing inclusion.\n" "Please resolve it and then attempt to save again." msgstr "" +"Această scenă nu poate fi salvată, deoarece există o includere ciclică.\n" +"RezolvaÈ›i-l È™i apoi încercaÈ›i să salvaÈ›i din nou." #: editor/editor_node.cpp msgid "" @@ -2262,7 +2297,6 @@ msgstr "" "înÅ£elege mai bine cum sa lucraÈ›i cu acestea." #: editor/editor_node.cpp -#, fuzzy msgid "" "This resource belongs to a scene that was instanced or inherited.\n" "Changes to it won't be kept when saving the current scene." @@ -2279,41 +2313,34 @@ msgstr "" "setările din panoul de import ÅŸi apoi reimportaÈ›i." #: editor/editor_node.cpp -#, fuzzy msgid "" "This scene was imported, so changes to it won't be kept.\n" "Instancing it or inheriting will allow making changes to it.\n" "Please read the documentation relevant to importing scenes to better " "understand this workflow." msgstr "" -"Această scenă a fost importată, astfel încât modificările la acesta nu vor " -"fi păstrate.\n" -"InstanÈ›area sau moÅŸtenirea vă permite efectuarea de modificări la acesta.\n" -"Vă rugăm să citiÅ£i documentaÅ£ia relevantă pentru importul scene pentru a " -"înÅ£elege mai bine acest mod de lucru." +"Această scenă a fost importată, astfel încât modificările acesteia nu vor fi " +"păstrate.\n" +"InstanÈ›area sau moÅŸtenirea vă permite efectuarea de modificări pentru ea.\n" +"Vă rugăm să citiÈ›i documentaÈ›ia relevantă pentru importarea scenei pentru a " +"înÈ›elege mai bine acest mod de lucru." #: editor/editor_node.cpp -#, fuzzy msgid "" "This is a remote object, so changes to it won't be kept.\n" "Please read the documentation relevant to debugging to better understand " "this workflow." msgstr "" -"Acesta este un obiect îndepărtat, astfel încât modificările la acesta nu vor " +"Acesta este un obiect îndepărtat, astfel încât modificările acesteia nu vor " "fi păstrate.\n" -"Vă rugăm să citiÅ£i documentaÅ£ia relevantă pentru depanare pentru a înÅ£elege " -"mai bine acest mod de lucru." +"Vă rugăm să citiÈ›i documentaÈ›ia relevantă depanării pentru a înÈ›elege mai " +"bine acest mod de lucru." #: editor/editor_node.cpp msgid "There is no defined scene to run." msgstr "Nu există nici o scenă definită pentru a execuÈ›ie." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"Scena curentă nu a fost salvată niciodată, salvaÈ›i-o înainte de rulare." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Nu s-a putut porni subprocesul!" @@ -2326,9 +2353,8 @@ msgid "Open Base Scene" msgstr "Deschide o scenă de bază" #: editor/editor_node.cpp -#, fuzzy msgid "Quick Open..." -msgstr "Deschide o scenă rapid..." +msgstr "Deschidere rapidă..." #: editor/editor_node.cpp msgid "Quick Open Scene..." @@ -2347,9 +2373,8 @@ msgid "Save changes to '%s' before closing?" msgstr "Salvează schimbările la ’%s’ înainte de ieÈ™ire?" #: editor/editor_node.cpp -#, fuzzy msgid "Saved %s modified resource(s)." -msgstr "ÃŽncărcarea resursei a eÈ™uat." +msgstr "Resurse modificate %s salvate." #: editor/editor_node.cpp msgid "A root node is required to save the scene." @@ -2400,9 +2425,8 @@ msgid "Can't reload a scene that was never saved." msgstr "Nu se poate reîncărca o scenă care nu a fost salvată niciodată." #: editor/editor_node.cpp -#, fuzzy msgid "Reload Saved Scene" -msgstr "Salvează Scena" +msgstr "Reîncărcare scenă salvată" #: editor/editor_node.cpp msgid "" @@ -2458,9 +2482,8 @@ msgid "Close Scene" msgstr "ÃŽnchide Scena" #: editor/editor_node.cpp -#, fuzzy msgid "Reopen Closed Scene" -msgstr "ÃŽnchide Scena" +msgstr "Redeschidere scenă închisă" #: editor/editor_node.cpp msgid "Unable to enable addon plugin at: '%s' parsing of config failed." @@ -2477,13 +2500,12 @@ msgid "Unable to load addon script from path: '%s'." msgstr "Nu a putut fi încărcat scriptul add-on din calea: '%s'." #: editor/editor_node.cpp -#, fuzzy msgid "" "Unable to load addon script from path: '%s' There seems to be an error in " "the code, please check the syntax." msgstr "" -"Nu a putut fi încărcat scriptul add-on din calea: '%s' Scriptul nu este în " -"modul unealtă." +"Imposibil de încărcat scriptul addon din cale: '%s' Se pare că există o " +"eroare în cod, verificaÈ›i sintaxa." #: editor/editor_node.cpp msgid "" @@ -2565,24 +2587,20 @@ msgstr "Implicit" #: editor/editor_node.cpp editor/editor_properties.cpp #: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp -#, fuzzy msgid "Show in FileSystem" -msgstr "Sistemul De FiÈ™iere" +msgstr "AfiÈ™are în FileSystem" #: editor/editor_node.cpp -#, fuzzy msgid "Play This Scene" -msgstr "Rulează Scena" +msgstr "Redare scenă" #: editor/editor_node.cpp -#, fuzzy msgid "Close Tab" -msgstr "Aproape" +msgstr "ÃŽnchidere filă" #: editor/editor_node.cpp -#, fuzzy msgid "Undo Close Tab" -msgstr "Aproape" +msgstr "Anulare fila ÃŽnchidere" #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp msgid "Close Other Tabs" @@ -2593,9 +2611,8 @@ msgid "Close Tabs to the Right" msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "Close All Tabs" -msgstr "Aproape" +msgstr "Inchide toate filele" #: editor/editor_node.cpp msgid "Switch Scene Tab" @@ -2638,9 +2655,8 @@ msgid "Go to previously opened scene." msgstr "Mergi la o scenă deschisă anterior." #: editor/editor_node.cpp -#, fuzzy msgid "Copy Text" -msgstr "CopiaÅ£i Calea" +msgstr "Copiază textul" #: editor/editor_node.cpp msgid "Next tab" @@ -2679,9 +2695,8 @@ msgid "Save Scene" msgstr "Salvează Scena" #: editor/editor_node.cpp -#, fuzzy msgid "Save All Scenes" -msgstr "Salvează toate Scenele" +msgstr "SalvaÈ›i toate scenele" #: editor/editor_node.cpp msgid "Convert To..." @@ -2715,14 +2730,12 @@ msgid "Project" msgstr "Proiect" #: editor/editor_node.cpp -#, fuzzy msgid "Project Settings..." -msgstr "Setări ale Proiectului" +msgstr "Setări proiect..." #: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp -#, fuzzy msgid "Version Control" -msgstr "Versiune:" +msgstr "Control versiune" #: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp msgid "Set Up Version Control" @@ -2733,27 +2746,24 @@ msgid "Shut Down Version Control" msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "Export..." -msgstr "Exportare" +msgstr "Export..." #: editor/editor_node.cpp msgid "Install Android Build Template..." msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "Open Project Data Folder" -msgstr "Deschizi Managerul de Proiect?" +msgstr "DeschideÈ›i folderul datelor proiectului" #: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp msgid "Tools" msgstr "Unelte" #: editor/editor_node.cpp -#, fuzzy msgid "Orphan Resource Explorer..." -msgstr "Explorator de Resurse Orfane" +msgstr "Explorator de resurse orfane ..." #: editor/editor_node.cpp msgid "Quit to Project List" @@ -2856,27 +2866,24 @@ msgid "Editor" msgstr "Editor" #: editor/editor_node.cpp -#, fuzzy msgid "Editor Settings..." -msgstr "Setări ale Editorului" +msgstr "Setările editorului..." #: editor/editor_node.cpp msgid "Editor Layout" msgstr "Schema Editorului" #: editor/editor_node.cpp -#, fuzzy msgid "Take Screenshot" -msgstr "Salvează Scena" +msgstr "Salvează captură de ecran" #: editor/editor_node.cpp -#, fuzzy msgid "Screenshots are stored in the Editor Data/Settings Folder." -msgstr "Setări ale Editorului" +msgstr "Capturile de ecran sunt stocate în folderul Date/Setări editor." #: editor/editor_node.cpp msgid "Toggle Fullscreen" -msgstr "Comută în Ecran Complet" +msgstr "Comutare ecran complet" #: editor/editor_node.cpp #, fuzzy @@ -2898,14 +2905,12 @@ msgid "Open Editor Settings Folder" msgstr "Setări ale Editorului" #: editor/editor_node.cpp -#, fuzzy msgid "Manage Editor Features..." -msgstr "Administrează Șabloanele de Export" +msgstr "Gestionare caracteristici editor..." #: editor/editor_node.cpp -#, fuzzy msgid "Manage Export Templates..." -msgstr "Administrează Șabloanele de Export" +msgstr "Gestionare È™abloane export..." #: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp msgid "Help" @@ -2960,7 +2965,7 @@ msgstr "" #: editor/editor_node.cpp msgid "Pause Scene" -msgstr "ÃŽntrerupere Scenă" +msgstr "Pauză scenă" #: editor/editor_node.cpp msgid "Stop the scene." @@ -2992,9 +2997,8 @@ msgid "Save & Restart" msgstr "Salvează È™i Restartează" #: editor/editor_node.cpp -#, fuzzy msgid "Spins when the editor window redraws." -msgstr "Se roteÈ™te când ferestra editorului se recolorează!" +msgstr "Se roteÈ™te când fereastra editorului se redeschide." #: editor/editor_node.cpp #, fuzzy @@ -3135,9 +3139,8 @@ msgid "Thumbnail..." msgstr "Miniatură..." #: editor/editor_plugin_settings.cpp -#, fuzzy msgid "Main Script:" -msgstr "Execută Scriptul" +msgstr "Script principal:" #: editor/editor_plugin_settings.cpp #, fuzzy @@ -3166,9 +3169,8 @@ msgid "Status:" msgstr "Stare:" #: editor/editor_plugin_settings.cpp -#, fuzzy msgid "Edit:" -msgstr "Modificare" +msgstr "Editare:" #: editor/editor_profiler.cpp msgid "Measure:" @@ -3211,9 +3213,8 @@ msgid "Calls" msgstr "Apeluri" #: editor/editor_properties.cpp -#, fuzzy msgid "Edit Text:" -msgstr "Membri" +msgstr "Editare text:" #: editor/editor_properties.cpp editor/script_create_dialog.cpp msgid "On" @@ -3236,9 +3237,8 @@ msgid "Assign..." msgstr "" #: editor/editor_properties.cpp -#, fuzzy msgid "Invalid RID" -msgstr "Nume nevalid." +msgstr "RID nevalid" #: editor/editor_properties.cpp msgid "" @@ -3506,9 +3506,8 @@ msgid "" msgstr "" #: editor/export_template_manager.cpp -#, fuzzy msgid "Error requesting URL:" -msgstr "Eroare la solicitarea URL: " +msgstr "Eroare la solicitarea URL:" #: editor/export_template_manager.cpp msgid "Connecting to Mirror..." @@ -3596,14 +3595,12 @@ msgid "Download Templates" msgstr "Descarcă Șabloane" #: editor/export_template_manager.cpp -#, fuzzy msgid "Select mirror from list: (Shift+Click: Open in Browser)" -msgstr "Selectează oglinda din listă: " +msgstr "Selectează oglinda din listă: (Shift+Click: Deschide in Browser)" #: editor/filesystem_dock.cpp -#, fuzzy msgid "Favorites" -msgstr "Favorite:" +msgstr "Favorite" #: editor/filesystem_dock.cpp msgid "Status: Import of file failed. Please fix file and reimport manually." @@ -3636,9 +3633,8 @@ msgid "No name provided." msgstr "Niciun nume furnizat." #: editor/filesystem_dock.cpp -#, fuzzy msgid "Provided name contains invalid characters." -msgstr "Numele furnizat conÈ›ine caractere nevalide" +msgstr "Numele furnizat conÈ›ine caractere nevalide." #: editor/filesystem_dock.cpp msgid "A file or folder with this name already exists." @@ -3665,9 +3661,8 @@ msgid "Duplicating folder:" msgstr "Duplicând directorul:" #: editor/filesystem_dock.cpp -#, fuzzy msgid "New Inherited Scene" -msgstr "Scenă Derivată Nouă..." +msgstr "Nouă scenă moÈ™tenită" #: editor/filesystem_dock.cpp #, fuzzy @@ -3684,9 +3679,8 @@ msgid "Instance" msgstr "Instanță" #: editor/filesystem_dock.cpp -#, fuzzy msgid "Add to Favorites" -msgstr "Favorite:" +msgstr "Adauga la Favorite" #: editor/filesystem_dock.cpp #, fuzzy @@ -3714,9 +3708,8 @@ msgid "Move To..." msgstr "Mută ÃŽn..." #: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." -msgstr "Scenă Nouă" +msgstr "Scenă nouă..." #: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp #, fuzzy @@ -3807,19 +3800,16 @@ msgid "Find in Files" msgstr "%d mai multe fiÈ™iere" #: editor/find_in_files.cpp -#, fuzzy msgid "Find:" -msgstr "GăsiÈ›i" +msgstr "GăsiÈ›i:" #: editor/find_in_files.cpp -#, fuzzy msgid "Folder:" -msgstr "CreaÈ›i Director" +msgstr "Folderul:" #: editor/find_in_files.cpp -#, fuzzy msgid "Filters:" -msgstr "Filtre..." +msgstr "Filtre:" #: editor/find_in_files.cpp msgid "" @@ -3841,14 +3831,12 @@ msgid "Cancel" msgstr "" #: editor/find_in_files.cpp -#, fuzzy msgid "Find: " -msgstr "GăsiÈ›i" +msgstr "GăsiÈ›i: " #: editor/find_in_files.cpp -#, fuzzy msgid "Replace: " -msgstr "ÃŽnlocuiÈ›i" +msgstr "ÃŽnlocuiÈ›i: " #: editor/find_in_files.cpp #, fuzzy @@ -3874,9 +3862,8 @@ msgid "Remove from Group" msgstr "Elimină din Grup" #: editor/groups_editor.cpp -#, fuzzy msgid "Group name already exists." -msgstr "EROARE: Numele animaÈ›iei există deja!" +msgstr "Numele grupului există deja." #: editor/groups_editor.cpp #, fuzzy @@ -4008,9 +3995,8 @@ msgid "Saving..." msgstr "Se Salvează..." #: editor/import_dock.cpp -#, fuzzy msgid "%d Files" -msgstr " FiÈ™iere" +msgstr "%d FiÈ™iere" #: editor/import_dock.cpp msgid "Set as Default for '%s'" @@ -4025,9 +4011,8 @@ msgid "Import As:" msgstr "Importă Ca:" #: editor/import_dock.cpp -#, fuzzy msgid "Preset" -msgstr "Presetare..." +msgstr "Presetare" #: editor/import_dock.cpp msgid "Reimport" @@ -4071,9 +4056,8 @@ msgid "Copy Params" msgstr "Copie Parametrii" #: editor/inspector_dock.cpp -#, fuzzy msgid "Edit Resource Clipboard" -msgstr "Clip-board de resurse gol !" +msgstr "Editare clipboard resursă" #: editor/inspector_dock.cpp msgid "Copy Resource" @@ -4120,9 +4104,8 @@ msgid "Object properties." msgstr "Proprietățile obiectului." #: editor/inspector_dock.cpp -#, fuzzy msgid "Filter properties" -msgstr "Proprietățile obiectului." +msgstr "Proprietăți filtrare" #: editor/inspector_dock.cpp msgid "Changes may be lost!" @@ -4148,9 +4131,8 @@ msgid "Create a Plugin" msgstr "Crează Poligon" #: editor/plugin_config_dialog.cpp -#, fuzzy msgid "Plugin Name:" -msgstr "Plugin-uri" +msgstr "Nume plugin:" #: editor/plugin_config_dialog.cpp msgid "Subfolder:" @@ -4177,21 +4159,18 @@ msgstr "Crează Poligon" #: editor/plugins/abstract_polygon_2d_editor.cpp #: editor/plugins/animation_blend_space_1d_editor.cpp #: editor/plugins/animation_blend_space_2d_editor.cpp -#, fuzzy msgid "Create points." -msgstr "Șterge puncte" +msgstr "CreaÈ›i puncte." #: editor/plugins/abstract_polygon_2d_editor.cpp -#, fuzzy msgid "" "Edit points.\n" "LMB: Move Point\n" "RMB: Erase Point" msgstr "" -"Editează poligon existent:\n" -"LMB: Mută Punct.\n" -"Ctrl+LMB: Despică Segment.\n" -"RMB: Șterge Punct." +"Editează puncte\n" +"LMB: Mută Punct\n" +"RMB: Șterge Punct" #: editor/plugins/abstract_polygon_2d_editor.cpp #: editor/plugins/animation_blend_space_1d_editor.cpp @@ -4230,9 +4209,8 @@ msgstr "Adaugă AnimaÈ›ia" #: editor/plugins/animation_blend_space_2d_editor.cpp #: editor/plugins/animation_blend_tree_editor_plugin.cpp #: editor/plugins/animation_state_machine_editor.cpp -#, fuzzy msgid "Load..." -msgstr "ÃŽncărcaÈ›i" +msgstr "ÃŽncărca..." #: editor/plugins/animation_blend_space_1d_editor.cpp #: editor/plugins/animation_blend_space_2d_editor.cpp @@ -4323,9 +4301,8 @@ msgid "Open Animation Node" msgstr "Nod de AnimaÈ›ie" #: editor/plugins/animation_blend_space_2d_editor.cpp -#, fuzzy msgid "Triangle already exists." -msgstr "EROARE: Numele animaÈ›iei există deja!" +msgstr "Triunghiul există deja." #: editor/plugins/animation_blend_space_2d_editor.cpp #, fuzzy @@ -4438,9 +4415,8 @@ msgid "Delete Node(s)" msgstr "" #: editor/plugins/animation_blend_tree_editor_plugin.cpp -#, fuzzy msgid "Toggle Filter On/Off" -msgstr "Comutează modul fără distrageri." +msgstr "Comutare filtru activat/dezactivat" #: editor/plugins/animation_blend_tree_editor_plugin.cpp #, fuzzy @@ -4477,9 +4453,8 @@ msgstr "FuncÈ›ii" #: editor/plugins/animation_blend_tree_editor_plugin.cpp #: editor/plugins/animation_state_machine_editor.cpp -#, fuzzy msgid "Node Renamed" -msgstr "Nume Nod:" +msgstr "Nod redenumit" #: editor/plugins/animation_blend_tree_editor_plugin.cpp #: editor/plugins/visual_shader_editor_plugin.cpp @@ -4488,9 +4463,8 @@ msgstr "" #: editor/plugins/animation_blend_tree_editor_plugin.cpp #: editor/plugins/root_motion_editor_plugin.cpp -#, fuzzy msgid "Edit Filtered Tracks:" -msgstr "Editează Filtrele" +msgstr "Editare piste filtrate:" #: editor/plugins/animation_blend_tree_editor_plugin.cpp #, fuzzy @@ -4614,9 +4588,8 @@ msgid "Animation" msgstr "AnimaÈ›ie" #: editor/plugins/animation_player_editor_plugin.cpp -#, fuzzy msgid "Edit Transitions..." -msgstr "TranziÈ›ii" +msgstr "Editare tranziÈ›ii..." #: editor/plugins/animation_player_editor_plugin.cpp #, fuzzy @@ -4718,9 +4691,8 @@ msgid "Move Node" msgstr "Mod Mutare" #: editor/plugins/animation_state_machine_editor.cpp -#, fuzzy msgid "Transition exists!" -msgstr "TranziÈ›ie" +msgstr "TranziÅ£ia există!" #: editor/plugins/animation_state_machine_editor.cpp #, fuzzy @@ -4783,14 +4755,12 @@ msgid "" msgstr "" #: editor/plugins/animation_state_machine_editor.cpp -#, fuzzy msgid "Create new nodes." -msgstr "CreaÈ›i %s Nou" +msgstr "CreaÈ›i noduri noi." #: editor/plugins/animation_state_machine_editor.cpp -#, fuzzy msgid "Connect nodes." -msgstr "ConectaÈ›i la Nod:" +msgstr "ConectaÈ›i nodurile." #: editor/plugins/animation_state_machine_editor.cpp #, fuzzy @@ -4806,14 +4776,12 @@ msgid "Set the end animation. This is useful for sub-transitions." msgstr "" #: editor/plugins/animation_state_machine_editor.cpp -#, fuzzy msgid "Transition: " -msgstr "TranziÈ›ie" +msgstr "TranziÈ›ie: " #: editor/plugins/animation_state_machine_editor.cpp -#, fuzzy msgid "Play Mode:" -msgstr "Mod ÃŽn Jur" +msgstr "Mod redare:" #: editor/plugins/animation_tree_editor_plugin.cpp #: editor/plugins/animation_tree_player_editor_plugin.cpp @@ -5008,14 +4976,12 @@ msgid "Redirect loop." msgstr "Buclă de RedirecÈ›ionare." #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Request failed, timeout" -msgstr "Cerere eÈ™uată, cod returnat:" +msgstr "Solicitare nereuÈ™ită, expirare" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Timeout." -msgstr "Timp" +msgstr "Pauză." #: editor/plugins/asset_library_editor_plugin.cpp msgid "Bad download hash, assuming file has been tampered with." @@ -5038,14 +5004,12 @@ msgid "Asset Download Error:" msgstr "Eroare la Descărcarea Asset-ului:" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Downloading (%s / %s)..." -msgstr "Se Descarcă" +msgstr "Se descarcă (%s / %s)..." #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Downloading..." -msgstr "Se Descarcă" +msgstr "Descărcare..." #: editor/plugins/asset_library_editor_plugin.cpp msgid "Resolving..." @@ -5060,9 +5024,8 @@ msgid "Idle" msgstr "Inactiv" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Install..." -msgstr "InstalaÈ›i" +msgstr "Instalare..." #: editor/plugins/asset_library_editor_plugin.cpp msgid "Retry" @@ -5130,14 +5093,12 @@ msgid "No results for \"%s\"." msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Import..." -msgstr "Importă" +msgstr "Import..." #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Plugins..." -msgstr "Plugin-uri" +msgstr "Plugin-uri..." #: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp msgid "Sort:" @@ -5153,9 +5114,8 @@ msgid "Site:" msgstr "Site:" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Support" -msgstr "Suport..." +msgstr "Suport" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Official" @@ -5166,9 +5126,8 @@ msgid "Testing" msgstr "Se Testează" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Loading..." -msgstr "ÃŽncărcaÈ›i" +msgstr "ÃŽncărcare..." #: editor/plugins/asset_library_editor_plugin.cpp msgid "Assets ZIP File" @@ -5397,9 +5356,8 @@ msgid "Full Rect" msgstr "" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Keep Ratio" -msgstr "ProporÈ›ie Scalare:" +msgstr "Păstrare raport" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Anchors only" @@ -5486,14 +5444,13 @@ msgstr "" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/texture_region_editor_plugin.cpp #: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp -#, fuzzy msgid "Zoom Reset" -msgstr "Zoom-aÈ›i Afară" +msgstr "Resetare zoom" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Select Mode" -msgstr "Mod Selectare" +msgstr "Selectare mod" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Drag: Rotate" @@ -5547,14 +5504,12 @@ msgid "Pan Mode" msgstr "Mod ÃŽn Jur" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Ruler Mode" -msgstr "Modul de ExecuÈ›ie:" +msgstr "Mod riglă" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Toggle smart snapping." -msgstr "Comutare snapping" +msgstr "ComutaÈ›i fixarea inteligentă." #: editor/plugins/canvas_item_editor_plugin.cpp #, fuzzy @@ -5562,9 +5517,8 @@ msgid "Use Smart Snap" msgstr "Utilizează Snap" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Toggle grid snapping." -msgstr "Comutare snapping" +msgstr "Comutare grilă fixare." #: editor/plugins/canvas_item_editor_plugin.cpp #, fuzzy @@ -5683,7 +5637,7 @@ msgstr "Arată Grila" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Show Helpers" -msgstr "Arată AsistenÈ›ii" +msgstr "AfiÈ™are ajutoare" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Show Rulers" @@ -5691,7 +5645,7 @@ msgstr "Arată Riglele" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Show Guides" -msgstr "Arată Ghizii" +msgstr "AfiÈ™are ghiduri" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Show Origin" @@ -5730,9 +5684,8 @@ msgid "Scale mask for inserting keys." msgstr "" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Insert keys (based on mask)." -msgstr "Inserează Notă (Melodii existente)" +msgstr "Introduce cheile (bazat pe masca)." #: editor/plugins/canvas_item_editor_plugin.cpp msgid "" @@ -5754,7 +5707,7 @@ msgstr "Lungime AnimaÈ›ie (în secunde)" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Insert Key (Existing Tracks)" -msgstr "Inserează Notă (Melodii existente)" +msgstr "Inserează Cheie (Track-uri existente)" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Copy Pose" @@ -5838,9 +5791,8 @@ msgstr "ÃŽncărcare Mască de Emisie" #: editor/plugins/cpu_particles_editor_plugin.cpp #: editor/plugins/particles_2d_editor_plugin.cpp #: editor/plugins/particles_editor_plugin.cpp -#, fuzzy msgid "Restart" -msgstr "Restartare (s):" +msgstr "Restart" #: editor/plugins/cpu_particles_2d_editor_plugin.cpp #: editor/plugins/particles_2d_editor_plugin.cpp @@ -5875,9 +5827,8 @@ msgstr "" #: editor/plugins/cpu_particles_2d_editor_plugin.cpp #: editor/plugins/particles_2d_editor_plugin.cpp -#, fuzzy msgid "Directed Border Pixels" -msgstr "Directoare È™i FiÅŸiere:" +msgstr "Pixeli borduri direcÈ›ionaÈ›i" #: editor/plugins/cpu_particles_2d_editor_plugin.cpp #: editor/plugins/particles_2d_editor_plugin.cpp @@ -6009,9 +5960,8 @@ msgid "Mesh is empty!" msgstr "Mesh-ul este gol!" #: editor/plugins/mesh_instance_editor_plugin.cpp -#, fuzzy msgid "Couldn't create a Trimesh collision shape." -msgstr "Creează un Frate de Coliziune Trimesh" +msgstr "Nu a putut crea o formă de coliziune Trimesh." #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Create Static Trimesh Body" @@ -6044,9 +5994,8 @@ msgid "Can't create multiple convex collision shapes for the scene root." msgstr "" #: editor/plugins/mesh_instance_editor_plugin.cpp -#, fuzzy msgid "Couldn't create any collision shapes." -msgstr "Nu s-a putut creea un contur!" +msgstr "Nu a putut crea nici o formă de coliziune." #: editor/plugins/mesh_instance_editor_plugin.cpp #, fuzzy @@ -6181,16 +6130,16 @@ msgid "Remove item %d?" msgstr "Elimini obiectul %d?" #: editor/plugins/mesh_library_editor_plugin.cpp -#, fuzzy msgid "" "Update from existing scene?:\n" "%s" -msgstr "Actualizează din Scenă" +msgstr "" +"Actualizează din Scenă existenta?:\n" +"%s" #: editor/plugins/mesh_library_editor_plugin.cpp -#, fuzzy msgid "Mesh Library" -msgstr "Librărie_de_Structuri..." +msgstr "Bibliotecă meshuri" #: editor/plugins/mesh_library_editor_plugin.cpp #: editor/plugins/theme_editor_plugin.cpp @@ -6598,9 +6547,8 @@ msgid "Paint Bone Weights" msgstr "" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Open Polygon 2D UV editor." -msgstr "Editor UV de poligoane 2D" +msgstr "DeschideÈ›i editorul UV Poligon 2D." #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Polygon 2D UV Editor" @@ -6710,9 +6658,8 @@ msgid "Show Grid" msgstr "Arată Grila" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Configure Grid:" -msgstr "Configurare Snap" +msgstr "Configurare grilă:" #: editor/plugins/polygon_2d_editor_plugin.cpp #, fuzzy @@ -6794,9 +6741,8 @@ msgid "AnimationTree has no path set to an AnimationPlayer" msgstr "" #: editor/plugins/root_motion_editor_plugin.cpp -#, fuzzy msgid "Path to AnimationPlayer is invalid" -msgstr "Arborele AnimaÈ›iei este nevalid." +msgstr "Calea către AnimationPlayer nu este validă" #: editor/plugins/script_editor_plugin.cpp msgid "Clear Recent Files" @@ -6807,14 +6753,12 @@ msgid "Close and save changes?" msgstr "" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Error writing TextFile:" -msgstr "Eroare la salvarea TileSet!" +msgstr "Eroare la scrierea TextFile:" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Could not load file at:" -msgstr "Directorul nu a putut fi creat." +msgstr "Nu s-a putut încărca fiÈ™ierul la:" #: editor/plugins/script_editor_plugin.cpp #, fuzzy @@ -6827,19 +6771,16 @@ msgid "Error while saving theme." msgstr "Eroare la salvare." #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Error Saving" -msgstr "Eroare mutând:" +msgstr "Eroare La Salvarea" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Error importing theme." -msgstr "Eroare mutând:" +msgstr "Eroare la importarea temei." #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Error Importing" -msgstr "Eroare mutând:" +msgstr "Eroare la importare" #: editor/plugins/script_editor_plugin.cpp #, fuzzy @@ -6904,18 +6845,16 @@ msgid "Find Previous" msgstr "" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Filter scripts" -msgstr "Proprietățile obiectului." +msgstr "Filtrare scripturi" #: editor/plugins/script_editor_plugin.cpp msgid "Toggle alphabetical sorting of the method list." msgstr "" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Filter methods" -msgstr "Proprietățile obiectului." +msgstr "Metode de filtrare" #: editor/plugins/script_editor_plugin.cpp msgid "Sort" @@ -6946,9 +6885,8 @@ msgid "File" msgstr "" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Open..." -msgstr "Deschide" +msgstr "Deschide..." #: editor/plugins/script_editor_plugin.cpp #, fuzzy @@ -7033,9 +6971,8 @@ msgid "Debug with External Editor" msgstr "Deschide Editorul următor" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Open Godot online documentation." -msgstr "Deschide Recente" +msgstr "DeschideÈ›i documentaÈ›ia online Godot." #: editor/plugins/script_editor_plugin.cpp msgid "Search the reference documentation." @@ -7098,19 +7035,19 @@ msgid "Target" msgstr "" #: editor/plugins/script_text_editor.cpp -#, fuzzy msgid "" "Missing connected method '%s' for signal '%s' from node '%s' to node '%s'." -msgstr "DeconectaÈ›i '%s' de la '%s'" +msgstr "" +"LipseÈ™te metoda conectată '%s' pentru semnalul '%s' de la nodul '%s' la " +"nodul '%s'." #: editor/plugins/script_text_editor.cpp msgid "[Ignore]" msgstr "" #: editor/plugins/script_text_editor.cpp -#, fuzzy msgid "Line" -msgstr "Linie:" +msgstr "Linie" #: editor/plugins/script_text_editor.cpp #, fuzzy @@ -7266,14 +7203,12 @@ msgid "Remove All Bookmarks" msgstr "EliminaÈ›i Autoload" #: editor/plugins/script_text_editor.cpp -#, fuzzy msgid "Go to Function..." -msgstr "FaceÈ›i FuncÈ›ia" +msgstr "Salt la funcÈ›ie..." #: editor/plugins/script_text_editor.cpp -#, fuzzy msgid "Go to Line..." -msgstr "DuceÈ›i-vă la Linie" +msgstr "Salt la linie..." #: editor/plugins/script_text_editor.cpp #: modules/visual_script/visual_script_editor.cpp @@ -7727,9 +7662,8 @@ msgstr "" #: editor/plugins/spatial_editor_plugin.cpp #: modules/gridmap/grid_map_editor_plugin.cpp -#, fuzzy msgid "Settings..." -msgstr "Setări Snap" +msgstr "Setări ..." #: editor/plugins/spatial_editor_plugin.cpp msgid "Snap Settings" @@ -7848,9 +7782,8 @@ msgid "Invalid geometry, can't replace by mesh." msgstr "" #: editor/plugins/sprite_editor_plugin.cpp -#, fuzzy msgid "Convert to Mesh2D" -msgstr "ConverteÈ™te ÃŽn..." +msgstr "Conversie în Mesh2D" #: editor/plugins/sprite_editor_plugin.cpp msgid "Invalid geometry, can't create polygon." @@ -7901,9 +7834,8 @@ msgid "Update Preview" msgstr "Previzualizare" #: editor/plugins/sprite_editor_plugin.cpp -#, fuzzy msgid "Settings:" -msgstr "Setări Snap" +msgstr "Setări:" #: editor/plugins/sprite_frames_editor_plugin.cpp #, fuzzy @@ -7919,9 +7851,8 @@ msgid "Add Frame" msgstr "" #: editor/plugins/sprite_frames_editor_plugin.cpp -#, fuzzy msgid "Unable to load images" -msgstr "ÃŽncărcarea resursei a eÈ™uat." +msgstr "Imposibil de încărcat imaginile" #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "ERROR: Couldn't load frame resource!" @@ -7953,9 +7884,8 @@ msgid "Move Frame" msgstr "Mod Mutare" #: editor/plugins/sprite_frames_editor_plugin.cpp -#, fuzzy msgid "Animations:" -msgstr "AnimaÈ›ie" +msgstr "AnimaÅ£ii:" #: editor/plugins/sprite_frames_editor_plugin.cpp #, fuzzy @@ -8238,9 +8168,8 @@ msgid "Erase Selection" msgstr "" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Fix Invalid Tiles" -msgstr "Nume nevalid." +msgstr "Remediere Tiles nevalide" #: editor/plugins/tile_map_editor_plugin.cpp #: modules/gridmap/grid_map_editor_plugin.cpp @@ -8287,9 +8216,8 @@ msgid "Enable Priority" msgstr "Editează Filtrele" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Filter tiles" -msgstr "Filtrează fiÈ™ierele..." +msgstr "Filtrare Tiles" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Give a TileSet resource to this TileMap to use its tiles." @@ -8337,9 +8265,8 @@ msgid "Add Texture(s) to TileSet." msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Remove selected Texture from TileSet." -msgstr "Elimină Obiectul Selectat" +msgstr "EliminaÈ›i textura selectată din TileSet." #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create from Scene" @@ -8380,9 +8307,8 @@ msgid "Select the previous shape, subtile, or Tile." msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Region" -msgstr "Modul de ExecuÈ›ie:" +msgstr "Regiunea" #: editor/plugins/tile_set_editor_plugin.cpp #, fuzzy @@ -8415,9 +8341,8 @@ msgid "Z Index" msgstr "Mod ÃŽn Jur" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Region Mode" -msgstr "Modul de ExecuÈ›ie:" +msgstr "Mod regiune" #: editor/plugins/tile_set_editor_plugin.cpp #, fuzzy @@ -8459,9 +8384,8 @@ msgid "Copy bitmask." msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Paste bitmask." -msgstr "LipeÈ™te AnimaÈ›ie" +msgstr "LipiÈ›i bitmask." #: editor/plugins/tile_set_editor_plugin.cpp #, fuzzy @@ -8469,9 +8393,8 @@ msgid "Erase bitmask." msgstr "RMB: Șterge Punctul." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Create a new rectangle." -msgstr "CreaÈ›i %s Nou" +msgstr "CreaÈ›i un dreptunghi nou." #: editor/plugins/tile_set_editor_plugin.cpp #, fuzzy @@ -8496,9 +8419,10 @@ msgid "" msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Remove selected texture? This will remove all tiles which use it." -msgstr "Elimină Obiectul Selectat" +msgstr "" +"EliminaÈ›i textura selectată? Acest lucru va elimina toate tiles care îl " +"utilizează." #: editor/plugins/tile_set_editor_plugin.cpp msgid "You haven't selected a texture to remove." @@ -8528,9 +8452,8 @@ msgid "" msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete selected Rect." -msgstr "ÅžtergeÈ›i fiÅŸierele selectate?" +msgstr "ȘtergeÈ›i Rectul selectat." #: editor/plugins/tile_set_editor_plugin.cpp msgid "" @@ -8539,9 +8462,8 @@ msgid "" msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete polygon." -msgstr "Șterge puncte" +msgstr "ȘtergeÈ›i poligonul." #: editor/plugins/tile_set_editor_plugin.cpp msgid "" @@ -8589,9 +8511,8 @@ msgid "Edit Tile Bitmask" msgstr "Editează Filtrele" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Edit Collision Polygon" -msgstr "Editează poligonul existent:" +msgstr "Editează coliziunea poligonului" #: editor/plugins/tile_set_editor_plugin.cpp #, fuzzy @@ -8677,9 +8598,8 @@ msgid "This property can't be changed." msgstr "Această operaÈ›ie nu se poate face fără o scenă." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "TileSet" -msgstr "Set_de_Plăci..." +msgstr "Set de dale" #: editor/plugins/version_control_editor_plugin.cpp msgid "No VCS addons are available." @@ -8794,9 +8714,8 @@ msgid "Add Output" msgstr "Adaugă Intrare(Input)" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Scalar" -msgstr "Dimensiune:" +msgstr "Scalar" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Vector" @@ -8830,9 +8749,8 @@ msgid "Change output port type" msgstr "Schimbă tipul implicit" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Change input port name" -msgstr "Schimbă Numele AnimaÈ›iei:" +msgstr "Modificarea numelui portului de intrare" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Change output port name" @@ -8849,9 +8767,8 @@ msgid "Remove output port" msgstr "Elimină punct" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Set expression" -msgstr "Versiune Curentă:" +msgstr "Setare expresie" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Resize VisualShader node" @@ -8902,9 +8819,8 @@ msgid "Light" msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Show resulted shader code." -msgstr "Creează Nod" +msgstr "AfiÈ™ează codul shader rezultat." #: editor/plugins/visual_shader_editor_plugin.cpp #, fuzzy @@ -8912,18 +8828,16 @@ msgid "Create Shader Node" msgstr "Creează Nod" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Color function." -msgstr "FaceÈ›i FuncÈ›ia" +msgstr "FuncÈ›ia de culoare." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Color operator." msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Grayscale function." -msgstr "FaceÈ›i FuncÈ›ia" +msgstr "FuncÈ›ia tonuri de gri." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Converts HSV vector to RGB equivalent." @@ -8934,9 +8848,8 @@ msgid "Converts RGB vector to HSV equivalent." msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Sepia function." -msgstr "FaceÈ›i FuncÈ›ia" +msgstr "FuncÈ›ia sepia." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Burn operator." @@ -8947,18 +8860,16 @@ msgid "Darken operator." msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Difference operator." -msgstr "Doar DiferenÈ›e" +msgstr "Operator de diferență." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Dodge operator." msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "HardLight operator." -msgstr "Dimensiune (raport):" +msgstr "Operator HardLight." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Lighten operator." @@ -8977,14 +8888,12 @@ msgid "SoftLight operator." msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Color constant." -msgstr "Permanent" +msgstr "Constantă de culoare." #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Color uniform." -msgstr "Anim Schimbare transformare" +msgstr "Culoare uniformă." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the boolean result of the %s comparison between two parameters." @@ -9065,9 +8974,8 @@ msgid "'%s' input parameter for all shader modes." msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Input parameter." -msgstr "Snap către părinte" +msgstr "Parametru de intrare." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "'%s' input parameter for vertex and fragment shader modes." @@ -9094,14 +9002,12 @@ msgid "'%s' input parameter for vertex and fragment shader mode." msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Scalar function." -msgstr "ScalaÈ›i SelecÈ›ia" +msgstr "FuncÈ›ie scalară." #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Scalar operator." -msgstr "Dimensiune (raport):" +msgstr "Operator scalar." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "E constant (2.718282). Represents the base of the natural logarithm." @@ -9330,9 +9236,8 @@ msgid "Scalar constant." msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Scalar uniform." -msgstr "Anim Schimbare transformare" +msgstr "Scalare uniformă." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Perform the cubic texture lookup." @@ -9355,9 +9260,8 @@ msgid "2D texture uniform lookup with triplanar." msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Transform function." -msgstr "Crează Poligon" +msgstr "FuncÈ›ie de transformare." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "" @@ -9399,19 +9303,16 @@ msgid "Multiplies vector by transform." msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Transform constant." -msgstr "Crează Poligon" +msgstr "Transformare constantă." #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Transform uniform." -msgstr "Crează Poligon" +msgstr "Transformare uniformă." #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Vector function." -msgstr "FaceÈ›i FuncÈ›ia" +msgstr "FuncÈ›ie vectorială." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Vector operator." @@ -9622,9 +9523,8 @@ msgid "Runnable" msgstr "" #: editor/project_export.cpp -#, fuzzy msgid "Add initial export..." -msgstr "Adaugă Intrare(Input)" +msgstr "Adăugare export iniÈ›ial..." #: editor/project_export.cpp msgid "Add previous patches..." @@ -9734,7 +9634,7 @@ msgstr "" #: editor/project_export.cpp #, fuzzy msgid "Pack File" -msgstr " FiÈ™iere" +msgstr "Pachet FiÈ™ier" #: editor/project_export.cpp msgid "Features" @@ -9754,9 +9654,8 @@ msgid "Script" msgstr "Execută Scriptul" #: editor/project_export.cpp -#, fuzzy msgid "Script Export Mode:" -msgstr "Exportă Proiectul" +msgstr "Mod export script:" #: editor/project_export.cpp msgid "Text" @@ -9787,9 +9686,8 @@ msgid "Export Project" msgstr "Exportă Proiectul" #: editor/project_export.cpp -#, fuzzy msgid "Export mode?" -msgstr "Exportă Proiectul" +msgstr "Exportă Proiectul?" #: editor/project_export.cpp #, fuzzy @@ -9797,9 +9695,8 @@ msgid "Export All" msgstr "Exportare" #: editor/project_export.cpp editor/project_manager.cpp -#, fuzzy msgid "ZIP File" -msgstr " FiÈ™iere" +msgstr "FiÈ™iere ZIP" #: editor/project_export.cpp msgid "Godot Game Pack" @@ -10147,18 +10044,16 @@ msgid "" msgstr "" #: editor/project_settings_editor.cpp -#, fuzzy msgid "An action with the name '%s' already exists." -msgstr "EROARE: Numele animaÈ›iei există deja!" +msgstr "Există deja o acÈ›iune cu numele '%s'." #: editor/project_settings_editor.cpp msgid "Rename Input Action Event" msgstr "" #: editor/project_settings_editor.cpp -#, fuzzy msgid "Change Action deadzone" -msgstr "Schimbă Numele AnimaÈ›iei:" +msgstr "Modificare acÈ›iune deadzone" #: editor/project_settings_editor.cpp msgid "Add Input Action Event" @@ -10515,9 +10410,8 @@ msgid "Suffix" msgstr "" #: editor/rename_dialog.cpp -#, fuzzy msgid "Use Regular Expressions" -msgstr "Versiune Curentă:" +msgstr "FolosiÈ›i expresii regulate" #: editor/rename_dialog.cpp #, fuzzy @@ -10529,23 +10423,20 @@ msgid "Substitute" msgstr "" #: editor/rename_dialog.cpp -#, fuzzy msgid "Node name" -msgstr "Nume Nod:" +msgstr "Nume nod" #: editor/rename_dialog.cpp msgid "Node's parent name, if available" msgstr "" #: editor/rename_dialog.cpp -#, fuzzy msgid "Node type" -msgstr "Nume Nod:" +msgstr "Tip nod" #: editor/rename_dialog.cpp -#, fuzzy msgid "Current scene name" -msgstr "Scena curentă nu este salvată. Deschizi oricum?" +msgstr "Numele scenei curente" #: editor/rename_dialog.cpp #, fuzzy @@ -10571,9 +10462,8 @@ msgid "Initial value for the counter" msgstr "" #: editor/rename_dialog.cpp -#, fuzzy msgid "Step" -msgstr "Pas (s):" +msgstr "Pas" #: editor/rename_dialog.cpp msgid "Amount by which counter is incremented for each node" @@ -10627,9 +10517,8 @@ msgid "Regular Expression Error" msgstr "" #: editor/rename_dialog.cpp -#, fuzzy msgid "At character %s" -msgstr "Caractere valide:" +msgstr "La caracterul %s" #: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp msgid "Reparent Node" @@ -10733,8 +10622,12 @@ msgstr "Salvează Scena" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "ȘtergeÈ›i %d noduri?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" -msgstr "Creează Nod" +msgstr "ȘtergeÈ›i %d noduri?" #: editor/scene_tree_dock.cpp msgid "Delete the root node \"%s\"?" @@ -10745,9 +10638,8 @@ msgid "Delete node \"%s\" and its children?" msgstr "" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "Delete node \"%s\"?" -msgstr "Creează Nod" +msgstr "ȘtergeÈ›i nodul \"%s\"?" #: editor/scene_tree_dock.cpp msgid "Can not perform with the root node." @@ -10784,9 +10676,8 @@ msgid "New Scene Root" msgstr "Salvează Scena" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "Create Root Node:" -msgstr "Creează Nod" +msgstr "Creare nod rădăcină:" #: editor/scene_tree_dock.cpp #, fuzzy @@ -10910,9 +10801,8 @@ msgid "Delete (No Confirm)" msgstr "" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "Add/Create a New Node." -msgstr "CreaÈ›i %s Nou" +msgstr "Adaugă/Creează un Nod nou." #: editor/scene_tree_dock.cpp msgid "" @@ -10985,9 +10875,8 @@ msgid "" msgstr "" #: editor/scene_tree_editor.cpp -#, fuzzy msgid "Open Script:" -msgstr "Execută Scriptul" +msgstr "Deschide scriptul:" #: editor/scene_tree_editor.cpp msgid "" @@ -11032,14 +10921,12 @@ msgid "Select a Node" msgstr "" #: editor/script_create_dialog.cpp -#, fuzzy msgid "Path is empty." -msgstr "Mesh-ul este gol!" +msgstr "Calea este goală." #: editor/script_create_dialog.cpp -#, fuzzy msgid "Filename is empty." -msgstr "Mesh-ul este gol!" +msgstr "Numele fiÈ™ierului este gol." #: editor/script_create_dialog.cpp msgid "Path is not local." @@ -11130,9 +11017,8 @@ msgid "Built-in script (into scene file)." msgstr "OperaÈ›iuni cu fiÈ™iere tip scenă." #: editor/script_create_dialog.cpp -#, fuzzy msgid "Will create a new script file." -msgstr "CreaÈ›i %s Nou" +msgstr "Va crea un nou fiÈ™ier script." #: editor/script_create_dialog.cpp #, fuzzy @@ -11140,9 +11026,8 @@ msgid "Will load an existing script file." msgstr "ÃŽncărcaÅ£i o Schemă de Pistă Audio existentă." #: editor/script_create_dialog.cpp -#, fuzzy msgid "Script file already exists." -msgstr "AutoLoad '%s' există deja!" +msgstr "FiÈ™ierul script există deja." #: editor/script_create_dialog.cpp msgid "" @@ -11156,14 +11041,12 @@ msgid "Class Name:" msgstr "Clasă:" #: editor/script_create_dialog.cpp -#, fuzzy msgid "Template:" -msgstr "Elimină Șablon" +msgstr "Åžablon:" #: editor/script_create_dialog.cpp -#, fuzzy msgid "Built-in Script:" -msgstr "Execută Scriptul" +msgstr "Script încorporat:" #: editor/script_create_dialog.cpp msgid "Attach Node Script" @@ -11182,19 +11065,16 @@ msgid "Warning:" msgstr "" #: editor/script_editor_debugger.cpp -#, fuzzy msgid "Error:" -msgstr "Eroare!" +msgstr "Eroare:" #: editor/script_editor_debugger.cpp -#, fuzzy msgid "C++ Error" -msgstr "Eroare!" +msgstr "Eroare C++" #: editor/script_editor_debugger.cpp -#, fuzzy msgid "C++ Error:" -msgstr "Eroare!" +msgstr "Eroare C++:" #: editor/script_editor_debugger.cpp #, fuzzy @@ -11202,14 +11082,12 @@ msgid "C++ Source" msgstr "Resursă" #: editor/script_editor_debugger.cpp -#, fuzzy msgid "Source:" -msgstr "Resursă" +msgstr "Sursă:" #: editor/script_editor_debugger.cpp -#, fuzzy msgid "C++ Source:" -msgstr "Resursă" +msgstr "Sursă C++:" #: editor/script_editor_debugger.cpp msgid "Stack Trace" @@ -11220,9 +11098,8 @@ msgid "Errors" msgstr "" #: editor/script_editor_debugger.cpp -#, fuzzy msgid "Child process connected." -msgstr "Deconectat" +msgstr "Procesul copilului conectat." #: editor/script_editor_debugger.cpp msgid "Copy Error" @@ -11645,9 +11522,8 @@ msgid "Pick Distance:" msgstr "" #: modules/gridmap/grid_map_editor_plugin.cpp -#, fuzzy msgid "Filter meshes" -msgstr "Proprietățile obiectului." +msgstr "Filtru meshuri" #: modules/gridmap/grid_map_editor_plugin.cpp msgid "Give a MeshLibrary resource to this GridMap to use its meshes." @@ -11789,18 +11665,16 @@ msgstr "" "motor tip." #: modules/visual_script/visual_script_editor.cpp -#, fuzzy msgid "Create a new function." -msgstr "CreaÈ›i %s Nou" +msgstr "CreaÈ›i o nouă funcÈ›ie." #: modules/visual_script/visual_script_editor.cpp msgid "Variables:" msgstr "" #: modules/visual_script/visual_script_editor.cpp -#, fuzzy msgid "Create a new variable." -msgstr "CreaÈ›i %s Nou" +msgstr "CreaÈ›i o nouă variabilă." #: modules/visual_script/visual_script_editor.cpp msgid "Signals:" @@ -11938,14 +11812,12 @@ msgid "Disconnect Nodes" msgstr "Deconectat" #: modules/visual_script/visual_script_editor.cpp -#, fuzzy msgid "Connect Node Data" -msgstr "ConectaÈ›i la Nod:" +msgstr "Conectare date nod" #: modules/visual_script/visual_script_editor.cpp -#, fuzzy msgid "Connect Node Sequence" -msgstr "ConectaÈ›i la Nod:" +msgstr "Conectare secvență nod" #: modules/visual_script/visual_script_editor.cpp msgid "Script already has function '%s'" @@ -12014,18 +11886,16 @@ msgid "Editing Signal:" msgstr "" #: modules/visual_script/visual_script_editor.cpp -#, fuzzy msgid "Make Tool:" -msgstr "Creează Oase" +msgstr "Creare Unealta:" #: modules/visual_script/visual_script_editor.cpp msgid "Members:" msgstr "Membri:" #: modules/visual_script/visual_script_editor.cpp -#, fuzzy msgid "Change Base Type:" -msgstr "SchimbaÈ›i Tipul %s" +msgstr "Modificare tip bază:" #: modules/visual_script/visual_script_editor.cpp #, fuzzy @@ -12033,9 +11903,8 @@ msgid "Add Nodes..." msgstr "Se adaugă %s..." #: modules/visual_script/visual_script_editor.cpp -#, fuzzy msgid "Add Function..." -msgstr "FaceÈ›i FuncÈ›ia" +msgstr "Adăugare funcÈ›ie..." #: modules/visual_script/visual_script_editor.cpp msgid "function_name" @@ -12206,9 +12075,8 @@ msgid "Invalid public key for APK expansion." msgstr "" #: platform/android/export/export.cpp -#, fuzzy msgid "Invalid package name:" -msgstr "Nume nevalid." +msgstr "Nume pachet nevalid:" #: platform/android/export/export.cpp msgid "" @@ -12277,9 +12145,8 @@ msgid "App Store Team ID not specified - cannot configure the project." msgstr "" #: platform/iphone/export/export.cpp -#, fuzzy msgid "Invalid Identifier:" -msgstr "Nume nevalid." +msgstr "Identificator nevalid:" #: platform/iphone/export/export.cpp msgid "Required icon is not specified in the preset." @@ -12422,6 +12289,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12743,14 +12616,12 @@ msgid "In node '%s', invalid animation: '%s'." msgstr "" #: scene/animation/animation_tree.cpp -#, fuzzy msgid "Invalid animation: '%s'." -msgstr "EROARE: Nume animaÈ›ie nevalid!" +msgstr "AnimaÈ›ie nevalidă: '%s'." #: scene/animation/animation_tree.cpp -#, fuzzy msgid "Nothing connected to input '%s' of node '%s'." -msgstr "DeconectaÈ›i '%s' de la '%s'" +msgstr "Nimic conectat la intrarea '%s' a nodului '%s'." #: scene/animation/animation_tree.cpp msgid "No root AnimationNode for the graph is set." @@ -12890,6 +12761,10 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "Scena curentă nu a fost salvată niciodată, salvaÈ›i-o înainte de rulare." + #~ msgid "Not in resource path." #~ msgstr "Nu în calea de resurse." diff --git a/editor/translations/ru.po b/editor/translations/ru.po index a2e562446d..16be6345f0 100644 --- a/editor/translations/ru.po +++ b/editor/translations/ru.po @@ -9,7 +9,7 @@ # DimOkGamer <dimokgamer@gmail.com>, 2016-2017. # Forest Swamp <sample1989@mail.ru>, 2018. # Igor S <scorched@bk.ru>, 2017. -# ijet <my-ijet@mail.ru>, 2017-2018. +# ijet <my-ijet@mail.ru>, 2017-2018, 2020. # Maxim Kim <habamax@gmail.com>, 2016. # Maxim toby3d Lebedev <mail@toby3d.ru>, 2016. # outbools <drag4e@yandex.ru>, 2017. @@ -78,12 +78,16 @@ # Alex Tern <ternvein@gmail.com>, 2020. # Varion Drakon Neonovich <variondrakon@gmail.com>, 2020. # d2cyb <dmitrydpb@gmail.com>, 2020. +# ÐлекÑей Смирнов <tir74@mail.ru>, 2020. +# Calamander <Calamander@yandex.ru>, 2020. +# Terminator <fresh-ter@yandex.com>, 2020. +# Anatoly Kuznetsov <muffinnorth@yandex.ru>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-22 06:40+0000\n" -"Last-Translator: ÐлекÑандр <ol-vin@mail.ru>\n" +"PO-Revision-Date: 2020-07-23 02:44+0000\n" +"Last-Translator: Anatoly Kuznetsov <muffinnorth@yandex.ru>\n" "Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/" "godot/ru/>\n" "Language: ru\n" @@ -97,7 +101,7 @@ msgstr "" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Invalid type argument to convert(), use TYPE_* constants." -msgstr "Ðеверный тип аргумента Ð´Ð»Ñ convert(), иÑпользуйте конÑтанты TYPE_*." +msgstr "Ðеверный параметр типа Ð´Ð»Ñ convert(), иÑпользуйте конÑтанты TYPE_*." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." @@ -830,9 +834,8 @@ msgid "Method in target node must be specified." msgstr "Метод в целевом узле должен быть указан." #: editor/connections_dialog.cpp -#, fuzzy msgid "Method name must be a valid identifier." -msgstr "Ð˜Ð¼Ñ Ð½Ðµ ÑвлÑетÑÑ Ð´Ð¾Ð¿ÑƒÑтимым идентификатором:" +msgstr "Ð˜Ð¼Ñ Ð½Ðµ ÑвлÑетÑÑ Ð´Ð¾Ð¿ÑƒÑтимым идентификатором." #: editor/connections_dialog.cpp msgid "" @@ -1893,23 +1896,23 @@ msgstr "Ðазад" #: editor/editor_file_dialog.cpp msgid "Go Forward" -msgstr "Вперёд" +msgstr "Перейти вперёд" #: editor/editor_file_dialog.cpp msgid "Go Up" -msgstr "Вверх" +msgstr "ПоднÑÑ‚ÑŒÑÑ" #: editor/editor_file_dialog.cpp msgid "Toggle Hidden Files" -msgstr "Скрыть файлы" +msgstr "Переключение Ñкрытых файлов" #: editor/editor_file_dialog.cpp msgid "Toggle Favorite" -msgstr "Переключить избранное" +msgstr "Избранное" #: editor/editor_file_dialog.cpp msgid "Toggle Mode" -msgstr "Переключить режим отображениÑ" +msgstr "Режим отображениÑ" #: editor/editor_file_dialog.cpp msgid "Focus Path" @@ -1917,11 +1920,11 @@ msgstr "Ð¤Ð¾ÐºÑƒÑ Ð½Ð° пути" #: editor/editor_file_dialog.cpp msgid "Move Favorite Up" -msgstr "ПеремеÑтить избранное вверх" +msgstr "ПоднÑÑ‚ÑŒ избранное" #: editor/editor_file_dialog.cpp msgid "Move Favorite Down" -msgstr "ПеремеÑтить избранное вниз" +msgstr "ОпуÑтить избранное" #: editor/editor_file_dialog.cpp msgid "Go to previous folder." @@ -2400,10 +2403,6 @@ msgid "There is no defined scene to run." msgstr "Ðет открытой Ñцены Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑка." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "Ð¢ÐµÐºÑƒÑ‰Ð°Ñ Ñцена никогда не была Ñохранена, Ñохраните её перед запуÑком." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Ðе удаётÑÑ Ð·Ð°Ð¿ÑƒÑтить подпроцеÑÑ!" @@ -2829,7 +2828,7 @@ msgstr "Обзор реÑурÑов-Ñирот..." #: editor/editor_node.cpp msgid "Quit to Project List" -msgstr "Выйти в ÑпиÑок проектов" +msgstr "Выйти к ÑпиÑку проектов" #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp #: editor/project_export.cpp @@ -2945,7 +2944,7 @@ msgstr "Снимки Ñкрана хранÑÑ‚ÑÑ Ð² папке данных/н #: editor/editor_node.cpp msgid "Toggle Fullscreen" -msgstr "Переключить полноÑкранный режим" +msgstr "Включить полноÑкранный режим" #: editor/editor_node.cpp msgid "Toggle System Console" @@ -3015,7 +3014,7 @@ msgstr "ЗапуÑтить проект." #: editor/editor_node.cpp msgid "Play" -msgstr "ВоÑпроизвеÑти" +msgstr "ЗапуÑтить" #: editor/editor_node.cpp msgid "Pause the scene execution for debugging." @@ -3080,7 +3079,7 @@ msgstr "ИнÑпектор" #: editor/editor_node.cpp msgid "Expand Bottom Panel" -msgstr "Развернуть нижнюю панель" +msgstr "РаÑширить боковую панель" #: editor/editor_node.cpp msgid "Output" @@ -5459,7 +5458,7 @@ msgstr "Режим перемещениÑ" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Rotate Mode" -msgstr "Режим поворота" +msgstr "Режим вращениÑ" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -5485,7 +5484,7 @@ msgstr "Режим оÑмотра" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Ruler Mode" -msgstr "Режим линейки" +msgstr "Режим измерениÑ" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Toggle smart snapping." @@ -5599,11 +5598,11 @@ msgstr "Обзор" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Always Show Grid" -msgstr "Ð’Ñегда показывать Ñетку" +msgstr "Ð’Ñегда отображать Ñетку" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Show Helpers" -msgstr "Показывать помощники" +msgstr "Показывать помощников" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Show Rulers" @@ -5611,7 +5610,7 @@ msgstr "Показывать линейки" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Show Guides" -msgstr "Показывать направлÑющие" +msgstr "Отображение направлÑющих" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Show Origin" @@ -5635,7 +5634,7 @@ msgstr "Кадрировать выбранное" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Preview Canvas Scale" -msgstr "МаÑштаб при проÑмотре холÑта" +msgstr "ПроÑмотреть Canvas Scale" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Translation mask for inserting keys." @@ -5676,7 +5675,7 @@ msgstr "Опции анимационных ключей и поз" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Insert Key (Existing Tracks)" -msgstr "Ð’Ñтавить ключ (ÑущеÑтвующие треки)" +msgstr "Ð’Ñтавить ключ (ÑущеÑтвующие дорожки)" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Copy Pose" @@ -5696,7 +5695,7 @@ msgstr "Разделить шаг Ñетки на 2" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Pan View" -msgstr "Панорама" +msgstr "Панорамировать вид" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Add %s" @@ -6786,7 +6785,7 @@ msgstr "Ðайти Ñледующее" #: editor/plugins/script_editor_plugin.cpp #: editor/plugins/script_text_editor.cpp msgid "Find Previous" -msgstr "Ðайти предыдущее" +msgstr "Ðайти предыдущий" #: editor/plugins/script_editor_plugin.cpp msgid "Filter scripts" @@ -6808,13 +6807,13 @@ msgstr "Сортировать" #: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp #: modules/gdnative/gdnative_library_editor_plugin.cpp msgid "Move Up" -msgstr "ПеремеÑтить вверх" +msgstr "ДвигатьÑÑ Ð²Ð²ÐµÑ€Ñ…" #: editor/plugins/script_editor_plugin.cpp #: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp #: modules/gdnative/gdnative_library_editor_plugin.cpp msgid "Move Down" -msgstr "ПеремеÑтить вниз" +msgstr "ДвигатьÑÑ Ð²Ð½Ð¸Ð·" #: editor/plugins/script_editor_plugin.cpp msgid "Next script" @@ -6834,7 +6833,7 @@ msgstr "Открыть..." #: editor/plugins/script_editor_plugin.cpp msgid "Reopen Closed Script" -msgstr "Открыть ранее закрытый Ñкрипт" +msgstr "Переоткрыть закрытый Ñкрипт" #: editor/plugins/script_editor_plugin.cpp msgid "Save All" @@ -6842,7 +6841,7 @@ msgstr "Сохранить вÑÑ‘" #: editor/plugins/script_editor_plugin.cpp msgid "Soft Reload Script" -msgstr "ÐœÑгко перезагрузить Ñкрипт" +msgstr "ÐœÑÐ³ÐºÐ°Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ° Ñкрипта" #: editor/plugins/script_editor_plugin.cpp msgid "Copy Script Path" @@ -7023,7 +7022,7 @@ msgstr "нижний региÑÑ‚Ñ€" #: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp msgid "Capitalize" -msgstr "ПропиÑные" +msgstr "Ð—Ð°Ð³Ð»Ð°Ð²Ð½Ð°Ñ Ð±ÑƒÐºÐ²Ð°" #: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp msgid "Syntax Highlighter" @@ -7051,7 +7050,7 @@ msgstr "Вырезать" #: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp #: scene/gui/text_edit.cpp msgid "Select All" -msgstr "Выбрать вÑе" +msgstr "Выделить вÑÑ‘" #: editor/plugins/script_text_editor.cpp msgid "Delete Line" @@ -7083,11 +7082,11 @@ msgstr "Развернуть вÑе Ñтроки" #: editor/plugins/script_text_editor.cpp msgid "Clone Down" -msgstr "Копировать вниз" +msgstr "Продублировать вниз" #: editor/plugins/script_text_editor.cpp msgid "Complete Symbol" -msgstr "СпиÑок автозавершениÑ" +msgstr "Завершить Ñимвол" #: editor/plugins/script_text_editor.cpp msgid "Evaluate Selection" @@ -7095,7 +7094,7 @@ msgstr "ВычиÑлить выделенное" #: editor/plugins/script_text_editor.cpp msgid "Trim Trailing Whitespace" -msgstr "Удаление пробелов в конце Ñтрок" +msgstr "Обрезать замыкающие пробелы" #: editor/plugins/script_text_editor.cpp msgid "Convert Indent to Spaces" @@ -7103,11 +7102,11 @@ msgstr "Преобразовать отÑтуп в пробелы" #: editor/plugins/script_text_editor.cpp msgid "Convert Indent to Tabs" -msgstr "Преобразовать отÑтуп в табулÑцию" +msgstr "Преобразовать отÑтупы в табулÑторы" #: editor/plugins/script_text_editor.cpp msgid "Auto Indent" -msgstr "ÐвтоотÑтуп" +msgstr "Ðвто-отÑтуп" #: editor/plugins/script_text_editor.cpp msgid "Find in Files..." @@ -7123,11 +7122,11 @@ msgstr "Переключить закладку" #: editor/plugins/script_text_editor.cpp msgid "Go to Next Bookmark" -msgstr "Перейти к Ñледующей закладке" +msgstr "Переход к Ñледующей закладке" #: editor/plugins/script_text_editor.cpp msgid "Go to Previous Bookmark" -msgstr "Перейти к предыдущей закладке" +msgstr "Переход к предыдущей закладке" #: editor/plugins/script_text_editor.cpp msgid "Remove All Bookmarks" @@ -7148,11 +7147,11 @@ msgstr "Точка оÑтановки" #: editor/plugins/script_text_editor.cpp msgid "Remove All Breakpoints" -msgstr "Удалить вÑе точки оÑтановок" +msgstr "Удалить вÑе точки оÑтанова" #: editor/plugins/script_text_editor.cpp msgid "Go to Next Breakpoint" -msgstr "Перейти к Ñледующей точке оÑтановки" +msgstr "Переход к Ñледующей точке оÑтанова" #: editor/plugins/script_text_editor.cpp msgid "Go to Previous Breakpoint" @@ -7336,7 +7335,7 @@ msgstr "Зад" #: editor/plugins/spatial_editor_plugin.cpp msgid "Align Transform with View" -msgstr "ВыравнÑÑ‚ÑŒ преобразование Ñ Ð¾Ð±Ð»Ð°Ñтью проÑмотра" +msgstr "ВыровнÑÑ‚ÑŒ транÑформации Ñ Ð²Ð¸Ð´Ð¾Ð¼" #: editor/plugins/spatial_editor_plugin.cpp msgid "Align Rotation with View" @@ -7360,7 +7359,7 @@ msgstr "Блокировать вращение камеры" #: editor/plugins/spatial_editor_plugin.cpp msgid "Display Normal" -msgstr "Режим нормалей" +msgstr "Ðормальный режим" #: editor/plugins/spatial_editor_plugin.cpp msgid "Display Wireframe" @@ -7412,35 +7411,35 @@ msgstr "ÐедоÑтупно при иÑпользовании рендерерР#: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Left" -msgstr "Обзор налево" +msgstr "Свободный вид, лево" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Right" -msgstr "Обзор направо" +msgstr "Свободный вид, право" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Forward" -msgstr "Обзор вперёд" +msgstr "Freelook Forward" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Backwards" -msgstr "Обзор назад" +msgstr "Свободный вид, назад" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Up" -msgstr "Обзор вверх" +msgstr "Свободный вид, вверх" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Down" -msgstr "Обзор вниз" +msgstr "Свободный вид, вниз" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Speed Modifier" -msgstr "Обзор модификатор ÑкороÑти" +msgstr "Модификатор ÑкороÑти Ñвободного вида" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Slow Modifier" -msgstr "Медленный модификатор Ñвободного проÑмотра" +msgstr "Модификатор Ð·Ð°Ð¼ÐµÐ´Ð»ÐµÐ½Ð¸Ñ Ñвободного вида" #: editor/plugins/spatial_editor_plugin.cpp msgid "View Rotation Locked" @@ -7498,7 +7497,7 @@ msgstr "ИÑпользовать локальное проÑтранÑтво" #: editor/plugins/spatial_editor_plugin.cpp msgid "Use Snap" -msgstr "ИÑпользовать привÑзку" +msgstr "ИÑпользовать привÑзки" #: editor/plugins/spatial_editor_plugin.cpp msgid "Bottom View" @@ -7526,7 +7525,7 @@ msgstr "Вид Ñправа" #: editor/plugins/spatial_editor_plugin.cpp msgid "Switch Perspective/Orthogonal View" -msgstr "Переключить перÑпективный/ортогональный вид" +msgstr "Переключение перÑпективного/ортогонального вида" #: editor/plugins/spatial_editor_plugin.cpp msgid "Insert Animation Key" @@ -7534,7 +7533,7 @@ msgstr "Ð’Ñтавить ключ анимации" #: editor/plugins/spatial_editor_plugin.cpp msgid "Focus Origin" -msgstr "Ð¤Ð¾ÐºÑƒÑ Ð½Ð° центре" +msgstr "СфокуÑироватьÑÑ Ð½Ð° начале координат" #: editor/plugins/spatial_editor_plugin.cpp msgid "Focus Selection" @@ -7542,7 +7541,7 @@ msgstr "Показать выбранное" #: editor/plugins/spatial_editor_plugin.cpp msgid "Toggle Freelook" -msgstr "Переключить Ñвободный обзор" +msgstr "Включить Ñвободный вид" #: editor/plugins/spatial_editor_plugin.cpp #: editor/plugins/visual_shader_editor_plugin.cpp @@ -7551,7 +7550,7 @@ msgstr "Преобразование" #: editor/plugins/spatial_editor_plugin.cpp msgid "Snap Object to Floor" -msgstr "ПривÑзать объект к полу" +msgstr "ПривÑзка объекта к полу" #: editor/plugins/spatial_editor_plugin.cpp msgid "Transform Dialog..." @@ -8105,7 +8104,7 @@ msgstr "ОчиÑтить карту тайлов" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Find Tile" -msgstr "Ðайти плитку" +msgstr "Ðайти тайл" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Transpose" @@ -8129,7 +8128,7 @@ msgstr "Задайте TileSet реÑÑƒÑ€Ñ Ñтому Tilemap чтобы иÑп #: editor/plugins/tile_map_editor_plugin.cpp msgid "Paint Tile" -msgstr "РиÑовать тайл" +msgstr "ПокраÑить тайл" #: editor/plugins/tile_map_editor_plugin.cpp msgid "" @@ -8153,11 +8152,11 @@ msgstr "Повернуть вправо" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Flip Horizontally" -msgstr "Отразить по горизонтали" +msgstr "Перевернуть по горизонтали" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Flip Vertically" -msgstr "Отразить по вертикали" +msgstr "Перевернуть по вертикали" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Clear Transform" @@ -10373,7 +10372,7 @@ msgstr "Выбрать метод" #: editor/rename_dialog.cpp editor/scene_tree_dock.cpp msgid "Batch Rename" -msgstr "Пакетное переименование" +msgstr "Групповое переименование" #: editor/rename_dialog.cpp msgid "Prefix" @@ -10563,7 +10562,7 @@ msgstr "Добавить дочернюю Ñцену" #: editor/scene_tree_dock.cpp msgid "Detach Script" -msgstr "Прикрепить Ñкрипт" +msgstr "Открепить Ñкрипт" #: editor/scene_tree_dock.cpp msgid "This operation can't be done on the tree root." @@ -10600,6 +10599,11 @@ msgid "Make node as Root" msgstr "Сделать узел корневым" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Удалить узел «%s» и его дочерние Ñлементы?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "Удалить %d узлов?" @@ -10768,7 +10772,7 @@ msgstr "Сохранить ветку, как Ñцену" #: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp msgid "Copy Node Path" -msgstr "Копировать путь" +msgstr "Копировать путь ноды" #: editor/scene_tree_dock.cpp msgid "Delete (No Confirm)" @@ -11885,7 +11889,7 @@ msgstr "Удалить выделенное" #: modules/visual_script/visual_script_editor.cpp msgid "Find Node Type" -msgstr "Ðайти тип узла" +msgstr "Ðайти тип нода" #: modules/visual_script/visual_script_editor.cpp msgid "Copy Nodes" @@ -11901,7 +11905,7 @@ msgstr "Сделать функцию" #: modules/visual_script/visual_script_editor.cpp msgid "Refresh Graph" -msgstr "Обновить граф" +msgstr "Обновить график" #: modules/visual_script/visual_script_editor.cpp msgid "Edit Member" @@ -12291,6 +12295,12 @@ msgstr "" "Shape должен быть предуÑмотрен Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¹ CollisionShape2D. ПожалуйÑта, " "Ñоздайте shape-реÑÑƒÑ€Ñ Ð´Ð»Ñ Ñтого!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12863,6 +12873,10 @@ msgstr "Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ быть назначены только Ð msgid "Constants cannot be modified." msgstr "КонÑтанты не могут быть изменены." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "Ð¢ÐµÐºÑƒÑ‰Ð°Ñ Ñцена никогда не была Ñохранена, Ñохраните её перед запуÑком." + #~ msgid "Not in resource path." #~ msgstr "Ðе в пути реÑурÑов." diff --git a/editor/translations/si.po b/editor/translations/si.po index 141696c00a..c8b0a57cbe 100644 --- a/editor/translations/si.po +++ b/editor/translations/si.po @@ -2273,10 +2273,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10191,6 +10187,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "යà¶à·”රු මක෠දමන්න" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "යà¶à·”රු මක෠දමන්න" @@ -11807,6 +11808,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/sk.po b/editor/translations/sk.po index 0920487af3..59cd8da671 100644 --- a/editor/translations/sk.po +++ b/editor/translations/sk.po @@ -2321,10 +2321,6 @@ msgid "There is no defined scene to run." msgstr "Nieje definovaná žiadna scéna na spustenie." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "Aktuálna scéna sa nikdy neuložila, prosÃm uložte ju pred spustenÃm." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Subprocess sa nedá spustiÅ¥!" @@ -10493,6 +10489,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "VÅ¡etky vybrané" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "VÅ¡etky vybrané" @@ -12171,6 +12172,12 @@ msgstr "" "MusÃte nastaviÅ¥ tvar objektu CollisionShape2D aby fungoval. ProsÃm, vytvorte " "preň tvarový objekt!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12648,6 +12655,9 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "Aktuálna scéna sa nikdy neuložila, prosÃm uložte ju pred spustenÃm." + #~ msgid "Not in resource path." #~ msgstr "Nieje v resource path." diff --git a/editor/translations/sl.po b/editor/translations/sl.po index 114dce1e63..c40bc3b40f 100644 --- a/editor/translations/sl.po +++ b/editor/translations/sl.po @@ -11,12 +11,13 @@ # Andrej Poženel <andrej.pozenel@outlook.com>, 2019. # Arnold Marko <arnold.marko@gmail.com>, 2019. # Alex <alexrixhardson@gmail.com>, 2019. +# Andrew Poženel <andrej.pozenel@outlook.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2019-10-26 03:53+0000\n" -"Last-Translator: Alex <alexrixhardson@gmail.com>\n" +"PO-Revision-Date: 2020-07-15 02:42+0000\n" +"Last-Translator: Andrew Poženel <andrej.pozenel@outlook.com>\n" "Language-Team: Slovenian <https://hosted.weblate.org/projects/godot-engine/" "godot/sl/>\n" "Language: sl\n" @@ -25,22 +26,22 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" "%100==4 ? 2 : 3;\n" -"X-Generator: Weblate 3.9.1-dev\n" +"X-Generator: Weblate 4.2-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Invalid type argument to convert(), use TYPE_* constants." -msgstr "Neveljavna vrsta argumenta za convert(), uporabite TYPE_* konstanto." +msgstr "Neveljavna vrsta argumenta za convert(), uporabite TYPE_* konstante." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." -msgstr "" +msgstr "PriÄakovan niz dolžine 1 (znak)." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/mono/glue/gd_glue.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Not enough bytes for decoding bytes, or invalid format." -msgstr "Ni dovolj bajtov za dekodiranje, ali pa format ni ustrezen." +msgstr "Ni dovolj bajtov za dekodiranje, ali pa je neveljaven format." #: core/math/expression.cpp msgid "Invalid input %i (not passed) in expression" @@ -48,7 +49,7 @@ msgstr "NapaÄen vnos %i(ni podan) v izrazu" #: core/math/expression.cpp msgid "self can't be used because instance is null (not passed)" -msgstr "self ne more biti uporabljen, ker instanca ni null (ni podano)" +msgstr "self ne more biti uporabljen, ker je instanca null (ni podano)" #: core/math/expression.cpp msgid "Invalid operands to operator %s, %s and %s." @@ -115,9 +116,8 @@ msgid "Time:" msgstr "ÄŒas:" #: editor/animation_bezier_editor.cpp -#, fuzzy msgid "Value:" -msgstr "Novo ime:" +msgstr "Vrednost:" #: editor/animation_bezier_editor.cpp msgid "Insert Key Here" @@ -132,14 +132,12 @@ msgid "Delete Selected Key(s)" msgstr "IzbriÅ¡i Izbran/e KljuÄ/e" #: editor/animation_bezier_editor.cpp -#, fuzzy msgid "Add Bezier Point" -msgstr "Dodaj toÄko" +msgstr "Dodaj Bezierjevo toÄko" #: editor/animation_bezier_editor.cpp -#, fuzzy msgid "Move Bezier Points" -msgstr "Odstrani toÄko" +msgstr "Premakni Bezierjevo toÄko" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Duplicate Keys" @@ -195,35 +193,33 @@ msgid "Anim Multi Change Call" msgstr "Animacija Spremeni klic" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Change Animation Length" -msgstr "Spremeni Ime Animacije:" +msgstr "Spremeni dolžino animacije" #: editor/animation_track_editor.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Change Animation Loop" -msgstr "" +msgstr "Spremeni ponavljanje animacije" #: editor/animation_track_editor.cpp msgid "Property Track" -msgstr "" +msgstr "Sled atributa" #: editor/animation_track_editor.cpp -#, fuzzy msgid "3D Transform Track" -msgstr "Preoblikovanje" +msgstr "Sled 3D preoblikovanja" #: editor/animation_track_editor.cpp msgid "Call Method Track" -msgstr "" +msgstr "Sled klica funkcije" #: editor/animation_track_editor.cpp msgid "Bezier Curve Track" -msgstr "" +msgstr "Sled Bezierjeve Krivulje" #: editor/animation_track_editor.cpp msgid "Audio Playback Track" -msgstr "" +msgstr "ZvoÄna Sled" #: editor/animation_track_editor.cpp #, fuzzy @@ -2443,10 +2439,6 @@ msgid "There is no defined scene to run." msgstr "Ni doloÄene scene za zagon." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "Trenutna scena ni bila shranjena, shranite jo pred zagonom." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Nemorem zaÄeti podprocesa!" @@ -10840,6 +10832,11 @@ msgstr "Shrani Prizor" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Izberi Gradnik" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Izberi Gradnik" @@ -12555,6 +12552,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -13039,6 +13042,9 @@ msgstr "" msgid "Constants cannot be modified." msgstr "Konstante ni možno spreminjati." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "Trenutna scena ni bila shranjena, shranite jo pred zagonom." + #~ msgid "Not in resource path." #~ msgstr "Ni na poti virov." diff --git a/editor/translations/sq.po b/editor/translations/sq.po index 32d08c7bc9..2df44bdd5b 100644 --- a/editor/translations/sq.po +++ b/editor/translations/sq.po @@ -2372,11 +2372,6 @@ msgid "There is no defined scene to run." msgstr "Nuk ka një skenë të përcaktuar për të filluar." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"Skena aktuale nuk është ruajtur më parë, ju lutem ruajeni para se të filloni." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Nuk mund të fillojë subprocess-in!" @@ -10473,6 +10468,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Fshi Nyjen" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Fshi Nyjen" @@ -12127,6 +12127,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12590,6 +12596,11 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "Skena aktuale nuk është ruajtur më parë, ju lutem ruajeni para se të " +#~ "filloni." + #~ msgid "Not in resource path." #~ msgstr "Jo në rrugën e resurseve." diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po index 01d8c4ca91..0bb67647f8 100644 --- a/editor/translations/sr_Cyrl.po +++ b/editor/translations/sr_Cyrl.po @@ -2549,10 +2549,6 @@ msgid "There is no defined scene to run." msgstr "Ðе поÑтоји дефиниÑана Ñцена за покретање." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "Тренутна Ñцена није Ñачувана, молим Ñачувајте је пре покретања." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Ðе могу покренути подпроцеÑ!" @@ -11811,6 +11807,11 @@ msgstr "Ðаправи Корен од чвора" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Обриши чвор \"%s\" и његову децу?" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Обриши %d чворове?" @@ -13785,6 +13786,12 @@ msgstr "" "Облик мора бити Ñнабдевен за СударниОблик2Д да би радио. Молимо креирај " "облик реÑÑƒÑ€Ñ Ð·Ð° њега!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp #, fuzzy msgid "" @@ -14435,6 +14442,9 @@ msgstr "Варијације могу Ñамо бити одређене у фу msgid "Constants cannot be modified." msgstr "КонÑтанте није могуће мењати." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "Тренутна Ñцена није Ñачувана, молим Ñачувајте је пре покретања." + #~ msgid "Not in resource path." #~ msgstr "Ðије на пут реÑурÑа." diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po index fe13877f42..4dece6c33c 100644 --- a/editor/translations/sr_Latn.po +++ b/editor/translations/sr_Latn.po @@ -2287,10 +2287,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10270,6 +10266,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Animacija ObriÅ¡i KljuÄeve" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "Animacija ObriÅ¡i KljuÄeve" @@ -11895,6 +11896,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/sv.po b/editor/translations/sv.po index ddd0188d5d..d3cda1a61a 100644 --- a/editor/translations/sv.po +++ b/editor/translations/sv.po @@ -5,7 +5,7 @@ # bergmarklund <davemcgroin@gmail.com>, 2017, 2018. # Christoffer Sundbom <christoffer_karlsson@live.se>, 2017. # Jakob Sinclair <sinclair.jakob@mailbox.org>, 2018. -# . <grenoscar@gmail.com>, 2018. +# . <grenoscar@gmail.com>, 2018, 2020. # Kristoffer Grundström <kristoffer.grundstrom1983@gmail.com>, 2018. # Magnus Helander <helander@fastmail.net>, 2018. # Daniel K <danielkimblad@hotmail.com>, 2018. @@ -15,12 +15,14 @@ # Anonymous <noreply@weblate.org>, 2020. # Joakim Lundberg <joakim@joakimlundberg.com>, 2020. # Kristoffer Grundström <swedishsailfishosuser@tutanota.com>, 2020. +# Jonas Robertsson <jonas.robertsson@posteo.net>, 2020. +# André Andersson <andre.eric.andersson@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-03 20:09+0000\n" -"Last-Translator: Kristoffer Grundström <swedishsailfishosuser@tutanota.com>\n" +"PO-Revision-Date: 2020-07-15 02:42+0000\n" +"Last-Translator: Jonas Robertsson <jonas.robertsson@posteo.net>\n" "Language-Team: Swedish <https://hosted.weblate.org/projects/godot-engine/" "godot/sv/>\n" "Language: sv\n" @@ -28,7 +30,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.1-dev\n" +"X-Generator: Weblate 4.2-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -37,14 +39,13 @@ msgstr "Ogiltligt typargument till convert(), använd TYPE_* konstanter." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." -msgstr "Förväntade en sträng med längden 1 (en karaktär)." +msgstr "Förväntas en string av längden 1 (en karaktär)." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/mono/glue/gd_glue.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Not enough bytes for decoding bytes, or invalid format." -msgstr "" -"Inte tillräckligt antal bytes eller ogiltigt format för avkodning av bytes." +msgstr "Inte tillräckligt med bytes för avkodning byte, eller ogiltigt format." #: core/math/expression.cpp msgid "Invalid input %i (not passed) in expression" @@ -152,7 +153,7 @@ msgstr "Anim Ta Bort Nycklar" #: editor/animation_track_editor.cpp msgid "Anim Change Keyframe Time" -msgstr "Anim Ändra Tid för Nyckebild" +msgstr "Anim Ändra Nyckelbildstid" #: editor/animation_track_editor.cpp msgid "Anim Change Transition" @@ -164,7 +165,7 @@ msgstr "Anim Ändra Transformation" #: editor/animation_track_editor.cpp msgid "Anim Change Keyframe Value" -msgstr "Anim Ändra Värde PÃ¥ Nyckelbild" +msgstr "Anim Ändra Värdet PÃ¥ Tidsnyckeln" #: editor/animation_track_editor.cpp msgid "Anim Change Call" @@ -172,7 +173,7 @@ msgstr "Anim Ändra Anrop" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Keyframe Time" -msgstr "Anim multi-ändring nyckelbildstid" +msgstr "Anim Fler-Ändra Nyckelbildstid" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Transition" @@ -188,7 +189,7 @@ msgstr "Anim Fler-Ändra Nyckelbildsvärde" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Call" -msgstr "Anim Fler-Ändra Anrop" +msgstr "Anim Ändra Anrop" #: editor/animation_track_editor.cpp msgid "Change Animation Length" @@ -229,7 +230,7 @@ msgstr "Animation längd (bildrutor)" #: editor/animation_track_editor.cpp msgid "Animation length (seconds)" -msgstr "Animationslängd (i sekunder)" +msgstr "Animationens längd (sekunder)" #: editor/animation_track_editor.cpp msgid "Add Track" @@ -294,7 +295,7 @@ msgstr "Diskret" #: editor/animation_track_editor.cpp msgid "Trigger" -msgstr "Utlös" +msgstr "Avtryckare" #: editor/animation_track_editor.cpp msgid "Capture" @@ -499,6 +500,15 @@ msgid "" "Alternatively, use an import preset that imports animations to separate " "files." msgstr "" +"Denna animationen tillhör en importerad scen, sÃ¥ ändringar i de importerade " +"spÃ¥ren kommer inte sparas.\n" +"\n" +"För att aktivera förmÃ¥gan att lägga till anpassade spÃ¥r, navigera till " +"scenens importinställningar och ställ in\n" +"\"Animation > Lagring\" till \"Filer\", aktivera \"Animation > BehÃ¥ll " +"Anpassade SpÃ¥r\", sedan importera om.\n" +"Alternativt, använd en importförinställning som importerar animationer till " +"separata filer." #: editor/animation_track_editor.cpp msgid "Warning: Editing imported animation" @@ -514,17 +524,15 @@ msgstr "Visa enbart spÃ¥r frÃ¥n valda noder i trädet." #: editor/animation_track_editor.cpp msgid "Group tracks by node or display them as plain list." -msgstr "" +msgstr "Gruppera spÃ¥r efter noder eller visa dem som enkel lista." #: editor/animation_track_editor.cpp -#, fuzzy msgid "Snap:" -msgstr "Steg (s):" +msgstr "Fäst:" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Animation step value." -msgstr "Animation" +msgstr "Animationens stegvärde." #: editor/animation_track_editor.cpp msgid "Seconds" @@ -545,14 +553,12 @@ msgid "Edit" msgstr "Redigera" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Animation properties." -msgstr "Animation" +msgstr "Animationens egenskaper." #: editor/animation_track_editor.cpp -#, fuzzy msgid "Copy Tracks" -msgstr "Kopiera Params" +msgstr "Kopiera SpÃ¥r" #: editor/animation_track_editor.cpp msgid "Scale Selection" @@ -571,19 +577,16 @@ msgid "Duplicate Transposed" msgstr "Fördubbla Transponerade" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Delete Selection" -msgstr "Duplicera urval" +msgstr "Radera Markering" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Go to Next Step" -msgstr "GÃ¥ Till Nästa Steg" +msgstr "GÃ¥ till Nästa Steg" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Go to Previous Step" -msgstr "Ge Till FöregÃ¥ende Steg" +msgstr "GÃ¥ till FöregÃ¥ende Steg" #: editor/animation_track_editor.cpp msgid "Optimize Animation" @@ -591,7 +594,7 @@ msgstr "Optimera Animation" #: editor/animation_track_editor.cpp msgid "Clean-Up Animation" -msgstr "Städa upp Animation" +msgstr "Rensa Animation" #: editor/animation_track_editor.cpp msgid "Pick the node that will be animated:" @@ -646,9 +649,8 @@ msgid "Scale Ratio:" msgstr "Skalnings förhÃ¥llande:" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Select Tracks to Copy" -msgstr "Ange övergÃ¥ngar:" +msgstr "Välj SpÃ¥r att Kopiera" #: editor/animation_track_editor.cpp editor/editor_log.cpp #: editor/editor_properties.cpp @@ -660,22 +662,20 @@ msgid "Copy" msgstr "Kopiera" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Select All/None" -msgstr "Välj Node" +msgstr "Välj Alla/Inga" #: editor/animation_track_editor_plugins.cpp -#, fuzzy msgid "Add Audio Track Clip" -msgstr "Ljud-Lyssnare" +msgstr "Lägg till LjudspÃ¥rsklipp" #: editor/animation_track_editor_plugins.cpp msgid "Change Audio Track Clip Start Offset" -msgstr "" +msgstr "Byt LjudspÃ¥rsklippets Startförskjutning" #: editor/animation_track_editor_plugins.cpp msgid "Change Audio Track Clip End Offset" -msgstr "" +msgstr "Byt LjudspÃ¥rsklippets Slutförskjutning" #: editor/array_property_edit.cpp msgid "Resize Array" @@ -698,18 +698,16 @@ msgid "Line Number:" msgstr "Radnummer:" #: editor/code_editor.cpp -#, fuzzy msgid "%d replaced." -msgstr "Ersätt..." +msgstr "%d ersatt." #: editor/code_editor.cpp editor/editor_help.cpp msgid "%d match." -msgstr "" +msgstr "%d matcha." #: editor/code_editor.cpp editor/editor_help.cpp -#, fuzzy msgid "%d matches." -msgstr "Inga matchningar" +msgstr "%d matchningar." #: editor/code_editor.cpp editor/find_in_files.cpp msgid "Match Case" @@ -734,11 +732,11 @@ msgstr "Endast Urval" #: editor/code_editor.cpp editor/plugins/script_text_editor.cpp #: editor/plugins/text_editor.cpp msgid "Standard" -msgstr "" +msgstr "Standard" #: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp msgid "Toggle Scripts Panel" -msgstr "" +msgstr "Växla Skriptpanel" #: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/texture_region_editor_plugin.cpp @@ -757,51 +755,44 @@ msgid "Reset Zoom" msgstr "Ã…terställ Zoom" #: editor/code_editor.cpp -#, fuzzy msgid "Warnings" -msgstr "Varning" +msgstr "Varningar" #: editor/code_editor.cpp msgid "Line and column numbers." -msgstr "" +msgstr "Rad- och Kolumnnummer." #: editor/connections_dialog.cpp -#, fuzzy msgid "Method in target node must be specified." -msgstr "Metod i MÃ¥l-Node mÃ¥ste specificeras!" +msgstr "Metod i mÃ¥lnod mÃ¥ste specificeras." #: editor/connections_dialog.cpp -#, fuzzy msgid "Method name must be a valid identifier." -msgstr "Metod i MÃ¥l-Node mÃ¥ste specificeras!" +msgstr "Metodnamn mÃ¥ste vara en giltig identifierare." #: editor/connections_dialog.cpp -#, fuzzy msgid "" "Target method not found. Specify a valid method or attach a script to the " "target node." msgstr "" -"MÃ¥lmetod hittades inte! Specificera en giltig metod eller koppla ett skript " -"till MÃ¥l-Node." +"MÃ¥lmetod hittades inte. Specificera en giltig metod eller koppla ett skript " +"till mÃ¥lnoden." #: editor/connections_dialog.cpp -#, fuzzy msgid "Connect to Node:" -msgstr "Anslut Till Node:" +msgstr "Anslut till Nod:" #: editor/connections_dialog.cpp -#, fuzzy msgid "Connect to Script:" -msgstr "Anslut Till Node:" +msgstr "Anslut till Skript:" #: editor/connections_dialog.cpp -#, fuzzy msgid "From Signal:" -msgstr "Signaler:" +msgstr "FrÃ¥n Signal:" #: editor/connections_dialog.cpp msgid "Scene does not contain any script." -msgstr "" +msgstr "Scenen innehÃ¥ller inte nÃ¥got skript." #: editor/connections_dialog.cpp editor/editor_autoload_settings.cpp #: editor/groups_editor.cpp editor/plugins/item_list_editor_plugin.cpp @@ -829,14 +820,12 @@ msgid "Extra Call Arguments:" msgstr "Extra Call Argument:" #: editor/connections_dialog.cpp -#, fuzzy msgid "Receiver Method:" -msgstr "Filtrera noder" +msgstr "Mottagarmetod:" #: editor/connections_dialog.cpp -#, fuzzy msgid "Advanced" -msgstr "Balanserad" +msgstr "Avancerad" #: editor/connections_dialog.cpp msgid "Deferred" @@ -846,6 +835,8 @@ msgstr "Uppskjuten" msgid "" "Defers the signal, storing it in a queue and only firing it at idle time." msgstr "" +"Skjuter upp signalen och sparar den i en kö och avfyrar den endast under " +"vilotid." #: editor/connections_dialog.cpp msgid "Oneshot" @@ -853,12 +844,11 @@ msgstr "Oneshot" #: editor/connections_dialog.cpp msgid "Disconnects the signal after its first emission." -msgstr "" +msgstr "Kopplar av signalen efter sitt första utsläpp." #: editor/connections_dialog.cpp -#, fuzzy msgid "Cannot connect signal" -msgstr "Ansluter Signal:" +msgstr "Kan ej ansluta signal" #: editor/connections_dialog.cpp editor/dependency_editor.cpp #: editor/export_template_manager.cpp editor/groups_editor.cpp @@ -879,23 +869,20 @@ msgid "Connect" msgstr "Anslut" #: editor/connections_dialog.cpp -#, fuzzy msgid "Signal:" -msgstr "Signaler:" +msgstr "Signal:" #: editor/connections_dialog.cpp msgid "Connect '%s' to '%s'" msgstr "Anslut '%s' till '%s'" #: editor/connections_dialog.cpp -#, fuzzy msgid "Disconnect '%s' from '%s'" -msgstr "Anslut '%s' till '%s'" +msgstr "Koppla av '%s' frÃ¥n '%s'" #: editor/connections_dialog.cpp -#, fuzzy msgid "Disconnect all from signal: '%s'" -msgstr "Anslut '%s' till '%s'" +msgstr "Koppla av alla frÃ¥n signal: '%s'" #: editor/connections_dialog.cpp msgid "Connect..." @@ -907,18 +894,16 @@ msgid "Disconnect" msgstr "Koppla frÃ¥n" #: editor/connections_dialog.cpp -#, fuzzy msgid "Connect a Signal to a Method" -msgstr "Ansluter Signal:" +msgstr "Anslut en Signal till en Metod" #: editor/connections_dialog.cpp -#, fuzzy msgid "Edit Connection:" -msgstr "Anslutningsfel" +msgstr "Redigera Koppling:" #: editor/connections_dialog.cpp msgid "Are you sure you want to remove all connections from the \"%s\" signal?" -msgstr "" +msgstr "Är du säker att du vill ta bort alla kopplingar frÃ¥n \"%s\" signalen?" #: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp msgid "Signals" @@ -926,36 +911,31 @@ msgstr "Signaler" #: editor/connections_dialog.cpp msgid "Are you sure you want to remove all connections from this signal?" -msgstr "" +msgstr "Är du säker att du vill ta bort alla kopplingar frÃ¥n denna signal?" #: editor/connections_dialog.cpp -#, fuzzy msgid "Disconnect All" -msgstr "Koppla frÃ¥n" +msgstr "Koppla av alla" #: editor/connections_dialog.cpp -#, fuzzy msgid "Edit..." -msgstr "Redigera" +msgstr "Ändra..." #: editor/connections_dialog.cpp -#, fuzzy msgid "Go To Method" -msgstr "Metoder" +msgstr "GÃ¥ Till Metod" #: editor/create_dialog.cpp -#, fuzzy msgid "Change %s Type" -msgstr "Ändra Typ" +msgstr "Ändra %s Typ" #: editor/create_dialog.cpp editor/project_settings_editor.cpp msgid "Change" msgstr "Ändra" #: editor/create_dialog.cpp -#, fuzzy msgid "Create New %s" -msgstr "Skapa Ny" +msgstr "Skapa Ny %s" #: editor/create_dialog.cpp editor/editor_file_dialog.cpp #: editor/filesystem_dock.cpp @@ -995,22 +975,20 @@ msgid "Dependencies For:" msgstr "Beroenden För:" #: editor/dependency_editor.cpp -#, fuzzy msgid "" "Scene '%s' is currently being edited.\n" "Changes will only take effect when reloaded." msgstr "" "Scen '%s' hÃ¥ller pÃ¥ att redigeras.\n" -"Ändringarna börjar inte gälla förrän omladdning." +"Ändringar börjar inte gälla förrän omladdning." #: editor/dependency_editor.cpp -#, fuzzy msgid "" "Resource '%s' is in use.\n" "Changes will only take effect when reloaded." msgstr "" "Resurs '%s' är i användning.\n" -"Ändringarna börjar gälla när den laddas om." +"Ändringar börjar endast gälla efter omladdning." #: editor/dependency_editor.cpp #: modules/gdnative/gdnative_library_editor_plugin.cpp @@ -1057,9 +1035,8 @@ msgid "Owners Of:" msgstr "Ägare av:" #: editor/dependency_editor.cpp -#, fuzzy msgid "Remove selected files from the project? (Can't be restored)" -msgstr "Ta bort valda filer frÃ¥n projektet? (gÃ¥r inte Ã¥ngra)" +msgstr "Ta bort valda filer frÃ¥n projektet? (Kan ej Ã¥terställas)" #: editor/dependency_editor.cpp msgid "" @@ -1071,9 +1048,8 @@ msgstr "" "Ta bort dem ändÃ¥? (gÃ¥r inte Ã¥ngra)" #: editor/dependency_editor.cpp -#, fuzzy msgid "Cannot remove:" -msgstr "Kan inte ta bort:\n" +msgstr "Kan inte ta bort:" #: editor/dependency_editor.cpp msgid "Error loading:" @@ -1154,9 +1130,8 @@ msgid "Lead Developer" msgstr "Ledande utvecklare" #: editor/editor_about.cpp -#, fuzzy msgid "Project Manager " -msgstr "Projektledare" +msgstr "Projekthanterare " #: editor/editor_about.cpp msgid "Developers" @@ -1199,12 +1174,10 @@ msgid "License" msgstr "Licens" #: editor/editor_about.cpp -#, fuzzy msgid "Third-party Licenses" msgstr "Tredje parts Licens" #: editor/editor_about.cpp -#, fuzzy msgid "" "Godot Engine relies on a number of third-party free and open source " "libraries, all compatible with the terms of its MIT license. The following " @@ -1229,14 +1202,12 @@ msgid "Licenses" msgstr "Licenser" #: editor/editor_asset_installer.cpp editor/project_manager.cpp -#, fuzzy msgid "Error opening package file, not in ZIP format." -msgstr "Fel vid öppning av paketetfil, inte i zip-format." +msgstr "Fel vid öppning av paketfil, är inte ZIP-format." #: editor/editor_asset_installer.cpp -#, fuzzy msgid "%s (Already Exists)" -msgstr "Autoload '%s' finns redan!" +msgstr "%s (Existerar Redan)" #: editor/editor_asset_installer.cpp msgid "Uncompressing Assets" @@ -1244,15 +1215,13 @@ msgstr "Dekomprimerar TillgÃ¥ngar" #: editor/editor_asset_installer.cpp editor/project_manager.cpp msgid "The following files failed extraction from package:" -msgstr "" +msgstr "Följande filer gick inte att packa upp frÃ¥n tillägget:" #: editor/editor_asset_installer.cpp -#, fuzzy msgid "And %s more files." -msgstr "%d fler filer" +msgstr "%d fler filer." #: editor/editor_asset_installer.cpp editor/project_manager.cpp -#, fuzzy msgid "Package installed successfully!" msgstr "Paketet installerades!" @@ -1397,7 +1366,7 @@ msgstr "Öppna Ljud-Buss Layout" #: editor/editor_audio_buses.cpp msgid "There is no '%s' file." -msgstr "" +msgstr "Det finns ingen '%s' fil." #: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp msgid "Layout" @@ -1408,9 +1377,8 @@ msgid "Invalid file, not an audio bus layout." msgstr "Ogiltig fil, inte en Ljud-Buss Layout." #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Error saving file: %s" -msgstr "Fel vid sparande av TileSet!" +msgstr "Fel vid sparande av fil: %s" #: editor/editor_audio_buses.cpp msgid "Add Bus" @@ -1478,7 +1446,7 @@ msgstr "" #: editor/editor_autoload_settings.cpp msgid "Keyword cannot be used as an autoload name." -msgstr "" +msgstr "Nyckelord kan inte användas som ett autoladdningsnamn." #: editor/editor_autoload_settings.cpp msgid "Autoload '%s' already exists!" @@ -1510,7 +1478,7 @@ msgstr "Ändra ordning pÃ¥ Autoloads" #: editor/editor_autoload_settings.cpp msgid "Can't add autoload:" -msgstr "" +msgstr "Kunde inte lägga till autoladdning:" #: editor/editor_autoload_settings.cpp msgid "Add AutoLoad" @@ -1561,7 +1529,7 @@ msgstr "(tom)" #: editor/editor_data.cpp msgid "[unsaved]" -msgstr "[osparad]" +msgstr "[inte sparad]" #: editor/editor_dir_dialog.cpp #, fuzzy @@ -1600,7 +1568,7 @@ msgstr "Lagrar Fil:" #: editor/editor_export.cpp msgid "No export template found at the expected path:" -msgstr "" +msgstr "Ingen exportmall hittades vid den förväntade sökvägen:" #: editor/editor_export.cpp msgid "Packing" @@ -1611,12 +1579,16 @@ msgid "" "Target platform requires 'ETC' texture compression for GLES2. Enable 'Import " "Etc' in Project Settings." msgstr "" +"MÃ¥lplattformen kräver 'ETC' texturkomprimering för GLES2. Aktivera 'Import " +"Etc' i Projektinställningarna." #: editor/editor_export.cpp msgid "" "Target platform requires 'ETC2' texture compression for GLES3. Enable " "'Import Etc 2' in Project Settings." msgstr "" +"MÃ¥lplattformen kräver 'ETC2' texturkomprimering för GLES3. Aktivera 'Import " +"Etc 2' i Projektinställningarna." #: editor/editor_export.cpp msgid "" @@ -1629,9 +1601,8 @@ msgstr "" #: editor/editor_export.cpp platform/android/export/export.cpp #: platform/iphone/export/export.cpp platform/javascript/export/export.cpp #: platform/osx/export/export.cpp platform/uwp/export/export.cpp -#, fuzzy msgid "Custom debug template not found." -msgstr "Mallfil hittades inte:\n" +msgstr "Mallfil hittades inte:" #: editor/editor_export.cpp platform/android/export/export.cpp #: platform/iphone/export/export.cpp platform/javascript/export/export.cpp @@ -1640,9 +1611,8 @@ msgid "Custom release template not found." msgstr "" #: editor/editor_export.cpp platform/javascript/export/export.cpp -#, fuzzy msgid "Template file not found:" -msgstr "Mallfil hittades inte:\n" +msgstr "Mallfil hittades inte:" #: editor/editor_export.cpp msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB." @@ -2425,10 +2395,6 @@ msgid "There is no defined scene to run." msgstr "Det finns ingen definierad scen att köra." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "Nuvarande scen har aldrig sparats, vänligen spara den innan körning." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Kunde inte starta underprocess!" @@ -2805,9 +2771,8 @@ msgid "Convert To..." msgstr "Konvertera Till..." #: editor/editor_node.cpp -#, fuzzy msgid "MeshLibrary..." -msgstr "MeshLibrary..." +msgstr "MeshBibliotek..." #: editor/editor_node.cpp #, fuzzy @@ -2965,9 +2930,8 @@ msgid "Editor Layout" msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "Take Screenshot" -msgstr "Vettigt!" +msgstr "Ta Skärmdump" #: editor/editor_node.cpp msgid "Screenshots are stored in the Editor Data/Settings Folder." @@ -3213,9 +3177,8 @@ msgid "Open the previous Editor" msgstr "" #: editor/editor_node.h -#, fuzzy msgid "Warning!" -msgstr "Varning" +msgstr "Varning!" #: editor/editor_path.cpp #, fuzzy @@ -3942,14 +3905,12 @@ msgid "Cancel" msgstr "Avbryt" #: editor/find_in_files.cpp -#, fuzzy msgid "Find: " -msgstr "Hitta" +msgstr "Hitta:" #: editor/find_in_files.cpp -#, fuzzy msgid "Replace: " -msgstr "Ersätt" +msgstr "Ersätt:" #: editor/find_in_files.cpp #, fuzzy @@ -3975,9 +3936,8 @@ msgid "Remove from Group" msgstr "Ta bort frÃ¥n Grupp" #: editor/groups_editor.cpp -#, fuzzy msgid "Group name already exists." -msgstr "ERROR: Animationsnamn finns redan!" +msgstr "Gruppnamn existerar redan." #: editor/groups_editor.cpp #, fuzzy @@ -4417,9 +4377,8 @@ msgid "Open Animation Node" msgstr "Animations-Node" #: editor/plugins/animation_blend_space_2d_editor.cpp -#, fuzzy msgid "Triangle already exists." -msgstr "ERROR: Animationsnamn finns redan!" +msgstr "Triangel existerar redan." #: editor/plugins/animation_blend_space_2d_editor.cpp #, fuzzy @@ -4650,14 +4609,12 @@ msgid "Duplicate Animation" msgstr "Duplicera Animation" #: editor/plugins/animation_player_editor_plugin.cpp -#, fuzzy msgid "No animation to copy!" -msgstr "Animation zoom." +msgstr "Ingen animation finns att kopiera!" #: editor/plugins/animation_player_editor_plugin.cpp -#, fuzzy msgid "No animation resource on clipboard!" -msgstr "Inte i resursens sökväg." +msgstr "Ingen animationsresurs i urklipp!" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Pasted Animation" @@ -4668,9 +4625,8 @@ msgid "Paste Animation" msgstr "Klistra in Animation" #: editor/plugins/animation_player_editor_plugin.cpp -#, fuzzy msgid "No animation to edit!" -msgstr "Animations-Node" +msgstr "Ingen animation finns att redigera!" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Play selected animation backwards from current pos. (A)" @@ -4706,7 +4662,7 @@ msgstr "Animeringsverktyg" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Animation" -msgstr "Animering" +msgstr "Animation" #: editor/plugins/animation_player_editor_plugin.cpp #, fuzzy @@ -4815,9 +4771,8 @@ msgid "Move Node" msgstr "Flytta Nod(er)" #: editor/plugins/animation_state_machine_editor.cpp -#, fuzzy msgid "Transition exists!" -msgstr "ÖvergÃ¥ng" +msgstr "ÖvergÃ¥ng existerar!" #: editor/plugins/animation_state_machine_editor.cpp #, fuzzy @@ -4903,9 +4858,8 @@ msgid "Set the end animation. This is useful for sub-transitions." msgstr "" #: editor/plugins/animation_state_machine_editor.cpp -#, fuzzy msgid "Transition: " -msgstr "ÖvergÃ¥ng" +msgstr "ÖvergÃ¥ng:" #: editor/plugins/animation_state_machine_editor.cpp #, fuzzy @@ -7881,9 +7835,8 @@ msgid "LightOccluder2D Preview" msgstr "Skapa Mapp" #: editor/plugins/sprite_editor_plugin.cpp -#, fuzzy msgid "Sprite is empty!" -msgstr "Sökvägen är tom" +msgstr "Spriten är tom!" #: editor/plugins/sprite_editor_plugin.cpp msgid "Can't convert a sprite using animation frames to mesh." @@ -10184,9 +10137,8 @@ msgid "" msgstr "" #: editor/project_settings_editor.cpp -#, fuzzy msgid "An action with the name '%s' already exists." -msgstr "ERROR: Animationsnamn finns redan!" +msgstr "En process med namnet '%s' existerar redan." #: editor/project_settings_editor.cpp msgid "Rename Input Action Event" @@ -10768,9 +10720,13 @@ msgid "Instantiated scenes can't become root" msgstr "" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "Make node as Root" -msgstr "Vettigt!" +msgstr "Gör nod som Rot" + +#: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Ta bort Nod(er)" #: editor/scene_tree_dock.cpp #, fuzzy @@ -10821,9 +10777,8 @@ msgid "Make Local" msgstr "Gör Patch" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "New Scene Root" -msgstr "Vettigt!" +msgstr "Ny Scenrot" #: editor/scene_tree_dock.cpp #, fuzzy @@ -10932,9 +10887,8 @@ msgid "Reparent to New Node" msgstr "Byt Förälder-Node" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "Make Scene Root" -msgstr "Vettigt!" +msgstr "Skapa Scenrot" #: editor/scene_tree_dock.cpp msgid "Merge From Scene" @@ -11188,9 +11142,8 @@ msgid "Will load an existing script file." msgstr "Ladda in befintlig Skript-fil" #: editor/script_create_dialog.cpp -#, fuzzy msgid "Script file already exists." -msgstr "Autoload '%s' finns redan!" +msgstr "Skriptfil existerar redan." #: editor/script_create_dialog.cpp msgid "" @@ -12349,9 +12302,8 @@ msgid "Run exported HTML in the system's default browser." msgstr "Kör exporterad HTML i systemets standardwebbläsare." #: platform/javascript/export/export.cpp -#, fuzzy msgid "Could not write file:" -msgstr "Kunde inte skriva till filen:\n" +msgstr "Kunde inte skriva till filen:" #: platform/javascript/export/export.cpp #, fuzzy @@ -12367,9 +12319,8 @@ msgid "Could not read custom HTML shell:" msgstr "" #: platform/javascript/export/export.cpp -#, fuzzy msgid "Could not read boot splash image file:" -msgstr "Kunde inte skriva till filen:\n" +msgstr "Kunde inte skriva till filen:" #: platform/javascript/export/export.cpp msgid "Using default boot splash image." @@ -12482,6 +12433,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12824,9 +12781,8 @@ msgid "In node '%s', invalid animation: '%s'." msgstr "" #: scene/animation/animation_tree.cpp -#, fuzzy msgid "Invalid animation: '%s'." -msgstr "ERROR: Ogiltigt animationsnamn!" +msgstr "Ogiltig animation: '%s'." #: scene/animation/animation_tree.cpp #, fuzzy @@ -12974,6 +12930,10 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "Nuvarande scen har aldrig sparats, vänligen spara den innan körning." + #~ msgid "Not in resource path." #~ msgstr "Inte i resursens sökväg." diff --git a/editor/translations/ta.po b/editor/translations/ta.po index 8f161acfc9..01cbcc1881 100644 --- a/editor/translations/ta.po +++ b/editor/translations/ta.po @@ -2275,10 +2275,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10187,6 +10183,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "அனைதà¯à®¤à¯ தேரà¯à®µà¯à®•à®³à¯" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "அனைதà¯à®¤à¯ தேரà¯à®µà¯à®•à®³à¯" @@ -11801,6 +11802,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/te.po b/editor/translations/te.po index 87fb947dd0..3523306b0d 100644 --- a/editor/translations/te.po +++ b/editor/translations/te.po @@ -2251,10 +2251,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10116,6 +10112,10 @@ msgid "Make node as Root" msgstr "" #: editor/scene_tree_dock.cpp +msgid "Delete %d nodes and any children?" +msgstr "" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "" @@ -11717,6 +11717,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/th.po b/editor/translations/th.po index 3af6fde5a0..279f8c08ba 100644 --- a/editor/translations/th.po +++ b/editor/translations/th.po @@ -2290,10 +2290,6 @@ msgid "There is no defined scene to run." msgstr "ยังไม่ได้เลืà¸à¸à¸‰à¸²à¸à¸—ี่จะเล่น" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "ฉาà¸à¸›à¸±à¸ˆà¸ˆà¸¸à¸šà¸±à¸™à¸¢à¸±à¸‡à¹„ม่ได้บันทึภà¸à¸£à¸¸à¸“าบันทึà¸à¸à¹ˆà¸à¸™à¹€à¸£à¸´à¹ˆà¸¡à¹‚ปรà¹à¸à¸£à¸¡" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "ไม่สามารถเริ่มขั้นตà¸à¸™à¸¢à¹ˆà¸à¸¢!" @@ -10508,6 +10504,11 @@ msgid "Make node as Root" msgstr "ทำโหนดให้เป็นโหนดà¹à¸¡à¹ˆ" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "ลบโหนด \"%s\" à¹à¸¥à¸°à¹‚หนดลูà¸?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "ลบโหนด %d ?" @@ -12168,6 +12169,12 @@ msgid "" "shape resource for it!" msgstr "ต้à¸à¸‡à¸¡à¸µà¸£à¸¹à¸›à¸—รงเพื่à¸à¹ƒà¸«à¹‰ CollisionShape2D ทำงานได้ à¸à¸£à¸¸à¸“าสร้างรูปทรง!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12689,6 +12696,9 @@ msgstr "" msgid "Constants cannot be modified." msgstr "ค่าคงที่ไม่สามารถà¹à¸à¹‰à¹„ขได้" +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "ฉาà¸à¸›à¸±à¸ˆà¸ˆà¸¸à¸šà¸±à¸™à¸¢à¸±à¸‡à¹„ม่ได้บันทึภà¸à¸£à¸¸à¸“าบันทึà¸à¸à¹ˆà¸à¸™à¹€à¸£à¸´à¹ˆà¸¡à¹‚ปรà¹à¸à¸£à¸¡" + #~ msgid "Not in resource path." #~ msgstr "ไม่à¸à¸¢à¸¹à¹ˆà¹ƒà¸™à¹‚ฟลเดà¸à¸£à¹Œà¸£à¸µà¸‹à¸à¸£à¹Œà¸ª" diff --git a/editor/translations/tr.po b/editor/translations/tr.po index 27886e1d4d..edc01421d2 100644 --- a/editor/translations/tr.po +++ b/editor/translations/tr.po @@ -47,12 +47,15 @@ # Anonymous <noreply@weblate.org>, 2020. # GüneÅŸ Gümüş <gunes.gumus.001@gmail.com>, 2020. # OÄŸuz Ersen <oguzersen@protonmail.com>, 2020. +# Vedat Günel <gunel15@itu.edu.tr>, 2020. +# Ahmet Elgün <ahmetelgn@gmail.com>, 2020. +# Efruz Yıldırır <efruzyildirir@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-05-22 21:01+0000\n" -"Last-Translator: GüneÅŸ Gümüş <gunes.gumus.001@gmail.com>\n" +"PO-Revision-Date: 2020-07-06 04:41+0000\n" +"Last-Translator: Efruz Yıldırır <efruzyildirir@gmail.com>\n" "Language-Team: Turkish <https://hosted.weblate.org/projects/godot-engine/" "godot/tr/>\n" "Language: tr\n" @@ -60,7 +63,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.1-dev\n" +"X-Generator: Weblate 4.2-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -798,9 +801,8 @@ msgid "Method in target node must be specified." msgstr "Hedef düğümdeki metod tanımlanmalı." #: editor/connections_dialog.cpp -#, fuzzy msgid "Method name must be a valid identifier." -msgstr "Ad doÄŸru bir belirleyici deÄŸil:" +msgstr "Metod ismi geçerli bir tanımlayıcı deÄŸil." #: editor/connections_dialog.cpp msgid "" @@ -1497,7 +1499,7 @@ msgstr "KendindenYüklenme'leri Yeniden Sırala" #: editor/editor_autoload_settings.cpp msgid "Can't add autoload:" -msgstr "" +msgstr "Otomatik yükleme eklenemiyor:" #: editor/editor_autoload_settings.cpp msgid "Add AutoLoad" @@ -2364,10 +2366,6 @@ msgid "There is no defined scene to run." msgstr "Çalıştırmak için herhangi bir sahne seçilmedi." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "Åžimdiki sahne hiç kaydedilmedi, lütfen çalıştırmadan önce kaydediniz." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Alt iÅŸlem baÅŸlatılamadı!" @@ -2452,15 +2450,16 @@ msgid "Can't reload a scene that was never saved." msgstr "Hiç kaydedilmemiÅŸ bir sahne yeniden yüklenemiyor." #: editor/editor_node.cpp -#, fuzzy msgid "Reload Saved Scene" -msgstr "Sahne Kaydet" +msgstr "KaydedilmiÅŸ Sahneyi Yeniden Yükle" #: editor/editor_node.cpp msgid "" "The current scene has unsaved changes.\n" "Reload the saved scene anyway? This action cannot be undone." msgstr "" +"Mevcut sahnede kaydedilmemiÅŸ deÄŸiÅŸiklikler var.\n" +"Sahne yine de yeniden yüklensin mi? Bu iÅŸlem geri alınamaz." #: editor/editor_node.cpp msgid "Quick Run Scene..." @@ -3395,11 +3394,10 @@ msgid "Did you forget the '_run' method?" msgstr "'_run()' metodunu unuttunuz mu?" #: editor/editor_spin_slider.cpp -#, fuzzy msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes." msgstr "" -"Alıcı bırakmak için Ctrl'e basılı tutun. Genel imza bırakmak için Shift'e " -"basılı tutun." +"Tamsayılara yuvarlamak için Ctrl tuÅŸunu basılı tutun. Hassas deÄŸiÅŸiklikler " +"için Shift tuÅŸunu basılı tutun." #: editor/editor_sub_scene.cpp msgid "Select Node(s) to Import" @@ -4000,7 +3998,7 @@ msgstr "sonradan-içe aktarılmış betik çalıştırılırken hata:" #: editor/import/resource_importer_scene.cpp msgid "Did you return a Node-derived object in the `post_import()` method?" -msgstr "" +msgstr "`Post_import ()` yönteminde Node türevi bir nesne döndürdünüz mü?" #: editor/import/resource_importer_scene.cpp msgid "Saving..." @@ -4024,7 +4022,7 @@ msgstr "Åžu Åžekilde İçe Aktar:" #: editor/import_dock.cpp msgid "Preset" -msgstr "Önayar" +msgstr "Ön ayar" #: editor/import_dock.cpp msgid "Reimport" @@ -4037,7 +4035,7 @@ msgstr "Sahneleri kaydet, tekrar içe aktar ve baÅŸtan baÅŸlat" #: editor/import_dock.cpp msgid "Changing the type of an imported file requires editor restart." msgstr "" -"İçe aktarılmış dosyanın tipini deÄŸiÅŸtirmek editörü baÅŸtan baÅŸlatılmasını " +"İçe aktarılmış dosyanın tipini deÄŸiÅŸtirmek editörü yeniden baÅŸlatmanı " "gerektiriyor." #: editor/import_dock.cpp @@ -6947,9 +6945,8 @@ msgstr "" "'%s' düğümünden '%s' düğümüne, '%s' sinyali için '%s' baÄŸlantı metodu eksik." #: editor/plugins/script_text_editor.cpp -#, fuzzy msgid "[Ignore]" -msgstr "(gözardı et)" +msgstr "[Gözardı et]" #: editor/plugins/script_text_editor.cpp msgid "Line" @@ -10558,6 +10555,11 @@ msgid "Make node as Root" msgstr "Düğümü Kök düğüm yap" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "\"%s\" düğümü ve alt düğümleri silinsin mi?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "%d düğümleri silelim mi?" @@ -12009,6 +12011,7 @@ msgstr "" #: platform/android/export/export.cpp msgid "\"Use Custom Build\" must be enabled to use the plugins." msgstr "" +"Eklentileri kullanabilmek için \"Özel Derleme Kullan\" seçeneÄŸi aktif olmalı." #: platform/android/export/export.cpp msgid "" @@ -12234,6 +12237,12 @@ msgstr "" "CollisionShape2D'nin iÅŸlevini yerine getirmesi için ona bir ÅŸekil saÄŸlanması " "gerekmektedir. Lütfen onun için bir ÅŸekil kaynağı oluÅŸturun!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12808,6 +12817,10 @@ msgstr "varyings yalnızca vertex iÅŸlevinde atanabilir." msgid "Constants cannot be modified." msgstr "Sabit deÄŸerler deÄŸiÅŸtirilemez." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "Åžimdiki sahne hiç kaydedilmedi, lütfen çalıştırmadan önce kaydediniz." + #~ msgid "Not in resource path." #~ msgstr "Kaynak yolunda deÄŸil." diff --git a/editor/translations/uk.po b/editor/translations/uk.po index 03990a655e..edab41c9b6 100644 --- a/editor/translations/uk.po +++ b/editor/translations/uk.po @@ -2342,11 +2342,6 @@ msgid "There is no defined scene to run." msgstr "Ðемає визначеної Ñцени Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" -"Поточна Ñцена ніколи не була збережена, будь лаÑка, збережіть Ñ—Ñ— до запуÑку." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Ðе вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити підпроцеÑ!" @@ -10569,6 +10564,11 @@ msgid "Make node as Root" msgstr "Зробити вузол кореневим" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Вилучити вузол «%s» Ñ– його дочірні запиÑи?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "Вилучити %d вузлів?" @@ -12275,6 +12275,12 @@ msgstr "" "Ð”Ð»Ñ Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ñ†ÐµÐ·Ð´Ð°Ñ‚Ð½Ð¾ÑÑ‚Ñ– CollisionShape2D Ñлід надати форму. Будь " "лаÑка, Ñтворіть реÑÑƒÑ€Ñ Ñ„Ð¾Ñ€Ð¼Ð¸ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ елемента!" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12854,6 +12860,11 @@ msgstr "Змінні величини можна пов'Ñзувати лише msgid "Constants cannot be modified." msgstr "Сталі не можна змінювати." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "" +#~ "Поточна Ñцена ніколи не була збережена, будь лаÑка, збережіть Ñ—Ñ— до " +#~ "запуÑку." + #~ msgid "Not in resource path." #~ msgstr "Ðе в реÑурÑному шлÑху." diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po index 6985cbdc39..4f4dccd8bb 100644 --- a/editor/translations/ur_PK.po +++ b/editor/translations/ur_PK.po @@ -2296,10 +2296,6 @@ msgid "There is no defined scene to run." msgstr "" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10359,6 +10355,11 @@ msgstr "" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr ".اینیمیشن Ú©ÛŒ کیز Ú©Ùˆ ڈیلیٹ کرو" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr ".اینیمیشن Ú©ÛŒ کیز Ú©Ùˆ ڈیلیٹ کرو" @@ -12011,6 +12012,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/vi.po b/editor/translations/vi.po index ff214a7091..8db07bf4b0 100644 --- a/editor/translations/vi.po +++ b/editor/translations/vi.po @@ -12,12 +12,13 @@ # Steve Dang <itsnguu@outlook.com>, 2019, 2020. # Peter Anh <peteranh3105@gmail.com>, 2019. # DÅ©ng Äinh <dqdthanhthanh@gmail.com>, 2019. +# Steve Dang <bynguu@outlook.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-02-02 08:51+0000\n" -"Last-Translator: Steve Dang <itsnguu@outlook.com>\n" +"PO-Revision-Date: 2020-07-28 09:51+0000\n" +"Last-Translator: Steve Dang <bynguu@outlook.com>\n" "Language-Team: Vietnamese <https://hosted.weblate.org/projects/godot-engine/" "godot/vi/>\n" "Language: vi\n" @@ -25,16 +26,16 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 3.11-dev\n" +"X-Generator: Weblate 4.2-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Invalid type argument to convert(), use TYPE_* constants." -msgstr "Hà m convert() có đối số không hợp lệ, sá» dụng các hằng TYPE_*." +msgstr "Hà m convert() có loại đối số không hợp lệ, sá» dụng các hằng TYPE_*." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." -msgstr "" +msgstr "Mong đợi má»™t chuá»—i có Ä‘á»™ dà i 01 ký tá»±." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/mono/glue/gd_glue.cpp @@ -1118,7 +1119,7 @@ msgstr "Äóng góp và o Godot Engine" #: editor/editor_about.cpp msgid "Project Founders" -msgstr "Sáng láºp dá»± án" +msgstr "Các đồng sáng láºp dá»± án" #: editor/editor_about.cpp msgid "Lead Developer" @@ -1126,7 +1127,7 @@ msgstr "Phát triển chÃnh" #: editor/editor_about.cpp msgid "Project Manager " -msgstr "Quản là dá»± án " +msgstr "Quản là Dá»± án " #: editor/editor_about.cpp msgid "Developers" @@ -1567,12 +1568,16 @@ msgid "" "Target platform requires 'ETC' texture compression for GLES2. Enable 'Import " "Etc' in Project Settings." msgstr "" +"Ná»n tảng yêu cầu dùng kiểu nén 'ETC' cho GLES2. Báºt 'Nháºp ETC' trong Cà i đặt " +"Dá»± án." #: editor/editor_export.cpp msgid "" "Target platform requires 'ETC2' texture compression for GLES3. Enable " "'Import Etc 2' in Project Settings." msgstr "" +"Ná»n tảng yêu cầu dùng kiểu nén 'ETC2' cho GLES3. Báºt 'Nháºp ETC2' trong Cà i " +"đặt Dá»± án." #: editor/editor_export.cpp msgid "" @@ -1581,6 +1586,9 @@ msgid "" "Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback " "Enabled'." msgstr "" +"Ná»n tảng yêu cầu kiểu nén 'ETC' cho trình Ä‘iá»u khiển dá»± phòng GLES2.\n" +"Chá»n kÃch hoạt 'Nháºp ETC' trong Cà i đặt Dá»± án, hoặc chá»n tắt 'KÃch hoạt " +"Trình Ä‘iá»u khiển Dá»± phòng'." #: editor/editor_export.cpp platform/android/export/export.cpp #: platform/iphone/export/export.cpp platform/javascript/export/export.cpp @@ -2340,10 +2348,6 @@ msgid "There is no defined scene to run." msgstr "Không có cảnh được xác định để chạy." #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "Cảnh hiện tại chÆ°a được lÆ°u, hãy lÆ°u nó trÆ°á»›c khi chạy." - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "Không thể bắt đầu quá trình nhá»!" @@ -2452,7 +2456,7 @@ msgstr "Thoát trình biên táºp?" #: editor/editor_node.cpp msgid "Open Project Manager?" -msgstr "Mở Quản lý dá»± án?" +msgstr "Mở Quản lý Dá»± án?" #: editor/editor_node.cpp msgid "Save & Quit" @@ -2464,7 +2468,7 @@ msgstr "LÆ°u thay đổi trong các scene sau trÆ°á»›c khi thoát?" #: editor/editor_node.cpp msgid "Save changes the following scene(s) before opening Project Manager?" -msgstr "LÆ°u thay đổi trong các scene sau trÆ°á»›c khi mở Project Manager?" +msgstr "LÆ°u thay đổi trong các cảnh sau trÆ°á»›c khi mở Quản là Dá»± án?" #: editor/editor_node.cpp msgid "" @@ -2527,7 +2531,7 @@ msgid "" "Error loading scene, it must be inside the project path. Use 'Import' to " "open the scene, then save it inside the project path." msgstr "" -"Lá»—i nạp cảnh, nó phải trong Ä‘Æ°á»ng dẫn dá»± án. Sá» dụng 'Nháºp và o' để mở cảnh, " +"Lá»—i nạp cảnh, nó phải trong Ä‘Æ°á»ng dẫn dá»± án. Sá» dụng 'Nháºp' để mở các cảnh, " "sau đó lÆ°u lại trong Ä‘Æ°á»ng dẫn dá»± án." #: editor/editor_node.cpp @@ -2554,7 +2558,7 @@ msgid "" "category." msgstr "" "Cảnh đã chá»n '%s' không tồn tại, chá»n má»™t cảnh hợp lệ?\n" -"Bạn có thể thay đổi nó sau trong \"Cà i đặt dá»± án\", nằm trong mục 'ứng dụng'." +"Bạn có thể thay đổi nó sau trong \"Cà i đặt Dá»± án\", nằm trong mục 'ứng dụng'." #: editor/editor_node.cpp msgid "" @@ -2562,8 +2566,8 @@ msgid "" "You can change it later in \"Project Settings\" under the 'application' " "category." msgstr "" -"Chá»n '%s' không phải má»™t tệp cảnh, chá»n tệp cảnh hợp lệ?\n" -"Bạn có thể thay đổi nó sau trong \"Cà i đặt dá»± án\", nằm trong mục 'ứng dụng'." +"'%s' không phải má»™t tệp phân cảnh, chá»n tệp phân cảnh hợp lệ?\n" +"Bạn có thể thay đổi nó sau trong \"Cà i đặt Dá»± án\", nằm trong mục 'ứng dụng'." #: editor/editor_node.cpp msgid "Save Layout" @@ -2717,17 +2721,16 @@ msgstr "Là m lại" #: editor/editor_node.cpp msgid "Miscellaneous project or scene-wide tools." -msgstr "" +msgstr "Linh tinh dá»± án hoặc công cụ toà n phân cảnh." #: editor/editor_node.cpp editor/project_manager.cpp #: editor/script_create_dialog.cpp msgid "Project" -msgstr "Dá»± án" +msgstr "Dá»± Ãn" #: editor/editor_node.cpp -#, fuzzy msgid "Project Settings..." -msgstr "List Project" +msgstr "Cà i đặt Dá»± Ãn" #: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp #, fuzzy @@ -2754,7 +2757,7 @@ msgstr "Cà i đặt mẫu xây dá»±ng Android" #: editor/editor_node.cpp msgid "Open Project Data Folder" -msgstr "Mở thÆ° mục dữ liệu dá»± án" +msgstr "Mở ThÆ° mục dữ liệu của Dá»± Ãn" #: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp msgid "Tools" @@ -2767,7 +2770,7 @@ msgstr "LÆ°u tà i nguyên thà nh ..." #: editor/editor_node.cpp msgid "Quit to Project List" -msgstr "Thoát danh sách dá»± án" +msgstr "Thoát khá»i Danh sách Dá»± án" #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp #: editor/project_export.cpp @@ -2799,6 +2802,11 @@ msgid "" "On Android, deploy will use the USB cable for faster performance. This " "option speeds up testing for games with a large footprint." msgstr "" +"Khi tuỳ chá»n nà y được báºt, lúc xuất hoặc triển khai sẽ tạo má»™t tệp thá»±c thi " +"tối giản nhất.\n" +"Hệ thống tệp tin sẽ được cung cấp từ dá»± án bởi trình soạn thảo qua mạng.\n" +"Trên ná»n tảng Android, triển khai sẽ sá» dụng cáp USB để có hiệu suất nhanh " +"hÆ¡n. Tuỳ chá»n nà y tăng tốc Ä‘á»™ khi thá» nghiệm cho các trò chÆ¡i nặng." #: editor/editor_node.cpp msgid "Visible Collision Shapes" @@ -2893,9 +2901,8 @@ msgid "Manage Editor Features..." msgstr "Quản lý tÃnh năng Trình biên táºp" #: editor/editor_node.cpp -#, fuzzy msgid "Manage Export Templates..." -msgstr "Quản lý mẫu Xuất ra" +msgstr "Quản lý Các Mẫu Xuất Bản ..." #: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp msgid "Help" @@ -3005,7 +3012,7 @@ msgstr "" #: editor/editor_node.cpp msgid "Inspector" -msgstr "Quản lý đối tượng" +msgstr "Quan Sát Viên" #: editor/editor_node.cpp msgid "Expand Bottom Panel" @@ -3022,10 +3029,11 @@ msgstr "Không LÆ°u" #: editor/editor_node.cpp msgid "Android build template is missing, please install relevant templates." msgstr "" +"Mẫu xuất bản cho Android bị thiếu, vui lòng cà i các mẫu xuất bản liên quan." #: editor/editor_node.cpp msgid "Manage Templates" -msgstr "Quản lý Mẫu" +msgstr "Quản lý Mẫu xuất bản" #: editor/editor_node.cpp msgid "" @@ -3037,6 +3045,12 @@ msgid "" "the \"Use Custom Build\" option should be enabled in the Android export " "preset." msgstr "" +"Äiá»u nà y sẽ thiết láºp dá»± án của bạn cho các bản dá»±ng Android tùy chỉnh bằng " +"cách cà i đặt nguồn mẫu thà nh \"res://android/build\".\n" +"Bạn có thể áp dụng các sá»a đổi và xây dá»±ng APK tùy chỉnh khi xuất (thêm các " +"mô-Ä‘un, thay đổi AndroidManifest.xml, ...).\n" +"LÆ°u ý rằng để tạo các bản dá»±ng tùy chỉnh, tùy chá»n \"Sá» dụng Bản dá»±ng Tùy " +"chỉnh\" phải được BẬT trong Cà i đặt xuất Android." #: editor/editor_node.cpp msgid "" @@ -3045,15 +3059,17 @@ msgid "" "Remove the \"res://android/build\" directory manually before attempting this " "operation again." msgstr "" +"Mẫu bản dá»±ng cho Android đã được cà i đặt trong dá»± án nà y sẽ không bị ghi " +"đè.\n" +"Xóa thủ công thÆ° mục \"res://android/build\" trÆ°á»›c khi thá» lại thao tác nà y." #: editor/editor_node.cpp msgid "Import Templates From ZIP File" -msgstr "Nháºp mẫu và o từ tệp nén ZIP" +msgstr "Nạp các mẫu xuất bản bằng tệp ZIP" #: editor/editor_node.cpp -#, fuzzy msgid "Template Package" -msgstr "Khung project" +msgstr "Gói Và Dụ" #: editor/editor_node.cpp msgid "Export Library" @@ -3382,7 +3398,7 @@ msgstr "Tải" #: editor/export_template_manager.cpp msgid "Official export templates aren't available for development builds." -msgstr "" +msgstr "Các mẫu xuất bản chÃnh thức không có sẵn cho các bản dá»±ng phát triển." #: editor/export_template_manager.cpp msgid "(Missing)" @@ -3402,23 +3418,23 @@ msgstr "Xóa template phiên bản '%s'?" #: editor/export_template_manager.cpp msgid "Can't open export templates zip." -msgstr "" +msgstr "Không thể mở tệp zip các mẫu xuất bản." #: editor/export_template_manager.cpp msgid "Invalid version.txt format inside templates: %s." -msgstr "" +msgstr "Äịnh dạng version.txt không hợp lệ bên trong các mẫu xuất bản: %s." #: editor/export_template_manager.cpp msgid "No version.txt found inside templates." -msgstr "Không thấy version.txt trong templates." +msgstr "Không thấy version.txt trong các mẫu xuất bản." #: editor/export_template_manager.cpp msgid "Error creating path for templates:" -msgstr "" +msgstr "Lá»—i tạo Ä‘Æ°á»ng dẫn đến các mẫu xuất bản:" #: editor/export_template_manager.cpp msgid "Extracting Export Templates" -msgstr "" +msgstr "TrÃch xuất các Mẫu xuất bản" #: editor/export_template_manager.cpp msgid "Importing:" @@ -3480,6 +3496,8 @@ msgid "" "Templates installation failed.\n" "The problematic templates archives can be found at '%s'." msgstr "" +"Cà i đặt các mẫu xuất bản thất bại.\n" +"Các lÆ°u trữ mẫu xuất bản có vấn Ä‘á» có thể được tìm thấy tại '%s'." #: editor/export_template_manager.cpp #, fuzzy @@ -3558,9 +3576,8 @@ msgid "Select Template File" msgstr "Chá»n file template" #: editor/export_template_manager.cpp -#, fuzzy msgid "Godot Export Templates" -msgstr "Quản lý mẫu Xuất ra" +msgstr "Các mẫu xuất bản Godot" #: editor/export_template_manager.cpp msgid "Export Template Manager" @@ -3568,7 +3585,7 @@ msgstr "" #: editor/export_template_manager.cpp msgid "Download Templates" -msgstr "Tải các Mẫu" +msgstr "Tải Xuống Các Mẫu Xuất Bản" #: editor/export_template_manager.cpp msgid "Select mirror from list: (Shift+Click: Open in Browser)" @@ -3780,8 +3797,8 @@ msgid "" "Include the files with the following extensions. Add or remove them in " "ProjectSettings." msgstr "" -"Bao gồm các tệp tin vá»›i các phần mở rá»™ng sau. Thêm hoặc loại bá» chúng trong " -"Cà i đặt Dá»± án." +"Bao gồm các tệp tin vá»›i các phần mở rá»™ng. Thêm hoặc loại bá» chúng trong Cà i " +"đặt Dá»± án." #: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp #: editor/plugins/script_text_editor.cpp @@ -9412,6 +9429,8 @@ msgid "" "Failed to export the project for platform '%s'.\n" "Export templates seem to be missing or invalid." msgstr "" +"Không thể xuất bản dá»± án cho ná»n tảng '%s'.\n" +"Mẫu xuất bản dÆ°á»ng nhÆ° bị thiếu hoặc không hợp lệ." #: editor/project_export.cpp msgid "" @@ -9419,6 +9438,9 @@ msgid "" "This might be due to a configuration issue in the export preset or your " "export settings." msgstr "" +"Không thể xuất dá»± án cho ná»n tảng '%s'.\n" +"Có thể là do vấn Ä‘á» cấu hình trong cà i đặt xuất bản hoặc cà i đặt xuất bản " +"của bạn." #: editor/project_export.cpp msgid "Release" @@ -9434,7 +9456,7 @@ msgstr "" #: editor/project_export.cpp msgid "Export templates for this platform are missing/corrupted:" -msgstr "" +msgstr "Các mẫu xuất bản cho ná»n tảng nà y bị thiếu/há»ng:" #: editor/project_export.cpp msgid "Presets" @@ -9461,7 +9483,7 @@ msgstr "" #: editor/project_export.cpp msgid "Export all resources in the project" -msgstr "" +msgstr "Xuất ra tất cả tà i nguyên dùng trong dá»± án" #: editor/project_export.cpp msgid "Export selected scenes (and dependencies)" @@ -9490,6 +9512,8 @@ msgid "" "Filters to exclude files/folders from project\n" "(comma-separated, e.g: *.json, *.txt, docs/*)" msgstr "" +"Bá»™ lá»c loại trừ các tệp tin/thÆ° mục khá»i từ dá»± án\n" +"(phân tách bằng dấu phẩy, và dụ: *.json, *.txt, docs/*)" #: editor/project_export.cpp msgid "Patches" @@ -9551,7 +9575,7 @@ msgstr "" #: editor/project_export.cpp msgid "Export Project" -msgstr "Xuất dá»± án ra" +msgstr "Xuất bản Dá»± án" #: editor/project_export.cpp msgid "Export mode?" @@ -9573,11 +9597,11 @@ msgstr "" #: editor/project_export.cpp msgid "Export templates for this platform are missing:" -msgstr "" +msgstr "Các mẫu xuất bản cho ná»n tảng nà y bị thiếu:" #: editor/project_export.cpp msgid "Manage Export Templates" -msgstr "Quản lý mẫu Xuất ra" +msgstr "Quản Lý Các Mẫu Xuất Bản" #: editor/project_export.cpp msgid "Export With Debug" @@ -9597,6 +9621,7 @@ msgstr "Lá»—i không thể mở gói, không phải dạng nén." msgid "" "Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file." msgstr "" +"Tệp dá»± án \".zip\" không hợp lệ; trong nó không chứa tệp \"project.godot\"." #: editor/project_manager.cpp msgid "Please choose an empty folder." @@ -9604,24 +9629,23 @@ msgstr "" #: editor/project_manager.cpp msgid "Please choose a \"project.godot\" or \".zip\" file." -msgstr "" +msgstr "Chá»n tệp \"project.godot\" hoặc tệp \".zip\"." #: editor/project_manager.cpp msgid "This directory already contains a Godot project." -msgstr "" +msgstr "ThÆ° mục nà y đã chứa má»™t dá»± án Godot." #: editor/project_manager.cpp msgid "New Game Project" -msgstr "" +msgstr "Dá»± án Trò chÆ¡i Má»›i" #: editor/project_manager.cpp msgid "Imported Project" -msgstr "" +msgstr "Äã nạp Dá»± án" #: editor/project_manager.cpp -#, fuzzy msgid "Invalid Project Name." -msgstr "KÃch thÆ°á»›c font không hợp lệ." +msgstr "Tên dá»± án không hợp lệ." #: editor/project_manager.cpp msgid "Couldn't create folder." @@ -9633,33 +9657,35 @@ msgstr "" #: editor/project_manager.cpp msgid "It would be a good idea to name your project." -msgstr "" +msgstr "Nó là má»™t ý tưởng tuyệt để đặt tên cho dá»± án của bạn." #: editor/project_manager.cpp msgid "Invalid project path (changed anything?)." -msgstr "" +msgstr "ÄÆ°á»ng dẫn dá»± án không hợp lệ (bạn có thay đổi Ä‘iá»u gì?)." #: editor/project_manager.cpp msgid "" "Couldn't load project.godot in project path (error %d). It may be missing or " "corrupted." msgstr "" +"Không thể nạp 'project.godot' trong Ä‘Æ°á»ng dẫn dá»± án (lá»—i %d). Nó có thể bị " +"thiếu hoặc đã há»ng." #: editor/project_manager.cpp msgid "Couldn't edit project.godot in project path." -msgstr "" +msgstr "Không thể chỉnh sá»a 'project.godot' trong Ä‘Æ°á»ng dẫn dá»± án." #: editor/project_manager.cpp msgid "Couldn't create project.godot in project path." -msgstr "" +msgstr "Không thể tạo 'project.godot' trong Ä‘Æ°á»ng dẫn dá»± án." #: editor/project_manager.cpp msgid "Rename Project" -msgstr "" +msgstr "Äổi tên Dá»± án" #: editor/project_manager.cpp msgid "Import Existing Project" -msgstr "" +msgstr "Nạp Dá»± án có sẵn" #: editor/project_manager.cpp msgid "Import & Edit" @@ -9667,7 +9693,7 @@ msgstr "" #: editor/project_manager.cpp msgid "Create New Project" -msgstr "" +msgstr "Tạo má»›i Dá»± án" #: editor/project_manager.cpp msgid "Create & Edit" @@ -9675,7 +9701,7 @@ msgstr "Tạo & Sá»a" #: editor/project_manager.cpp msgid "Install Project:" -msgstr "" +msgstr "Cà i đặt Dá»± án:" #: editor/project_manager.cpp msgid "Install & Edit" @@ -9683,15 +9709,15 @@ msgstr "" #: editor/project_manager.cpp msgid "Project Name:" -msgstr "" +msgstr "Tên Dá»± án:" #: editor/project_manager.cpp msgid "Project Path:" -msgstr "" +msgstr "ÄÆ°á»ng dẫn Dá»± án:" #: editor/project_manager.cpp msgid "Project Installation Path:" -msgstr "" +msgstr "ÄÆ°á»ng dẫn cà i đặt Dá»± án:" #: editor/project_manager.cpp msgid "Renderer:" @@ -9727,25 +9753,23 @@ msgstr "" #: editor/project_manager.cpp msgid "Unnamed Project" -msgstr "" +msgstr "Dá»± án không tên" #: editor/project_manager.cpp -#, fuzzy msgid "Missing Project" -msgstr "Dá»± án" +msgstr "Dá»± án bị lá»—i" #: editor/project_manager.cpp msgid "Error: Project is missing on the filesystem." -msgstr "" +msgstr "Lá»—i: Dá»± án bị thiếu trên hệ thống tệp tin." #: editor/project_manager.cpp -#, fuzzy msgid "Can't open project at '%s'." -msgstr "Không thể chạy project" +msgstr "Không thể mở dá»± án tại '%s'." #: editor/project_manager.cpp msgid "Are you sure to open more than one project?" -msgstr "" +msgstr "Bạn chắc chắn mở nhiá»u hÆ¡n má»™t dá»± án?" #: editor/project_manager.cpp msgid "" @@ -9759,6 +9783,13 @@ msgid "" "Warning: You won't be able to open the project with previous versions of the " "engine anymore." msgstr "" +"Tệp dá»± án không chỉ định phiên bản Godot mà nó được tạo.\n" +"\n" +"%s\n" +"\n" +"Nếu bạn vẫn tiến hà nh mở dá»± án, tệp dá»± án sẽ được chuyển đổi sang cấu hình " +"Godot hiện tại.\n" +"Cảnh báo: Bạn sẽ không thể mở dá»± án vá»›i các phiên bản cÅ© của Godot nữa." #: editor/project_manager.cpp msgid "" @@ -9771,12 +9802,21 @@ msgid "" "Warning: You won't be able to open the project with previous versions of the " "engine anymore." msgstr "" +"Tệp dá»± án được tạo bởi phiên bản Godot cÅ© và cần được chuyển đổi cho phiên " +"bản nà y:\n" +"\n" +"%s\n" +"\n" +"Bạn có muốn chuyển đổi nó?\n" +"Cảnh báo: Bạn sẽ không thể mở dá»± án vá»›i các phiên bản Godot cÅ© nữa." #: editor/project_manager.cpp msgid "" "The project settings were created by a newer engine version, whose settings " "are not compatible with this version." msgstr "" +"Các cà i đặt dá»± án đã được tạo bởi phiên bản Godot má»›i, có các cà i đặt không " +"tÆ°Æ¡ng thÃch vá»›i phiên bản nà y." #: editor/project_manager.cpp msgid "" @@ -9784,53 +9824,67 @@ msgid "" "Please edit the project and set the main scene in the Project Settings under " "the \"Application\" category." msgstr "" +"Không thể chạy dá»± án: chÆ°a chá»n phân cảnh chÃnh.\n" +"Äể chá»n phân cảnh chÃnh, mở \"Cà i đặt Dá»± án\" sau đó và o mục \"Ứng dụng\"." #: editor/project_manager.cpp msgid "" "Can't run project: Assets need to be imported.\n" "Please edit the project to trigger the initial import." msgstr "" +"Không thể chạy dá»± án: Các tà i sản chÆ°a được nạp.\n" +"Vui lòng thiết láºp dá»± án để kÃch hoạt nạp tà i sản ban đầu." #: editor/project_manager.cpp msgid "Are you sure to run %d projects at once?" -msgstr "" +msgstr "Bạn có chắc chắn chạy các dá»± án %d cùng lúc?" #: editor/project_manager.cpp msgid "" "Remove %d projects from the list?\n" "The project folders' contents won't be modified." msgstr "" +"Gỡ các dá»± án %d khá»i danh sách?\n" +"Ná»™i dung các thÆ° mục dá»± án sẽ không được sá»a đổi." #: editor/project_manager.cpp msgid "" "Remove this project from the list?\n" "The project folder's contents won't be modified." msgstr "" +"Gỡ dá»± án nà y khá»i danh sách?\n" +"Ná»™i dung của thÆ° mục dá»± án sẽ không được sá»a đổi." #: editor/project_manager.cpp msgid "" "Remove all missing projects from the list?\n" "The project folders' contents won't be modified." msgstr "" +"Gỡ tất cả dá»± án bị há»ng khá»i danh sách?\n" +"Ná»™i dung các thÆ° mục dá»± án sẽ không bị sá»a đổi." #: editor/project_manager.cpp msgid "" "Language changed.\n" "The interface will update after restarting the editor or project manager." msgstr "" +"Äã thay đổi ngôn ngữ.\n" +"Giao diện sẽ cáºp nháºt sau khi khởi Ä‘á»™ng lại trình biên táºp hoặc trình quản " +"là dá»± án." #: editor/project_manager.cpp msgid "" "Are you sure to scan %s folders for existing Godot projects?\n" "This could take a while." msgstr "" +"Bạn có chắc chắn quét các thÆ° mục %s để tìm các dá»± án Godot có sẵn?\n" +"Äiá»u nà y sẽ mất chút thá»i gian." #: editor/project_manager.cpp msgid "Project Manager" -msgstr "" +msgstr "Trình quản lý Dá»± án" #: editor/project_manager.cpp -#, fuzzy msgid "Projects" msgstr "Dá»± án" @@ -9848,7 +9902,7 @@ msgstr "Chá»n má»™t Folder để Quét" #: editor/project_manager.cpp msgid "New Project" -msgstr "Tạo Project" +msgstr "Tạo Dá»± Ãn" #: editor/project_manager.cpp #, fuzzy @@ -9857,7 +9911,7 @@ msgstr "Xóa Animation" #: editor/project_manager.cpp msgid "Templates" -msgstr "Khung project" +msgstr "ThÆ° Viện" #: editor/project_manager.cpp msgid "Restart Now" @@ -9865,16 +9919,15 @@ msgstr "Restart ngay" #: editor/project_manager.cpp msgid "Can't run project" -msgstr "Không thể chạy project" +msgstr "Không thể chạy dá»± án" #: editor/project_manager.cpp -#, fuzzy msgid "" "You currently don't have any projects.\n" "Would you like to explore official example projects in the Asset Library?" msgstr "" -"Hiện giá» bạn không có project nà o.\n" -"Bạn có muốn xem các project official và dụ trên Asset Library không?" +"Hiện tại bạn không có bất kỳ dá»± án nà o.\n" +"Bạn có muốn xem qua các dá»± án và dụ trên ThÆ° Viện không?" #: editor/project_manager.cpp msgid "" @@ -9882,6 +9935,9 @@ msgid "" "To filter projects by name and full path, the query must contain at least " "one `/` character." msgstr "" +"Há»™p tìm kiếm lá»c các dá»± án theo tên và phần cuối Ä‘Æ°á»ng dẫn.\n" +"Äể lá»c các dá»± án theo tên và đưá»ng dẫn đầy đủ, truy vấn phải chứa Ãt nhất " +"má»™t ký tá»± '/'." #: editor/project_settings_editor.cpp msgid "Key " @@ -10107,7 +10163,7 @@ msgstr "" #: editor/project_settings_editor.cpp msgid "Project Settings (project.godot)" -msgstr "" +msgstr "Cà i đặt Dá»± án (project.godot)" #: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp msgid "General" @@ -10488,6 +10544,11 @@ msgid "Make node as Root" msgstr "Gán nút là nút Gốc" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "Xoá nút \"%s\" và các nút con của nó?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "Xoá %d nút?" @@ -10906,9 +10967,8 @@ msgid "Class Name:" msgstr "Lá»›p:" #: editor/script_create_dialog.cpp -#, fuzzy msgid "Template:" -msgstr "Khung project" +msgstr "Bản mẫu:" #: editor/script_create_dialog.cpp #, fuzzy @@ -11941,6 +12001,8 @@ msgid "" "Android build template not installed in the project. Install it from the " "Project menu." msgstr "" +"Mẫu xuất bản cho Android chÆ°a được cà i đặt trong dá»± án. Cà i đặt nó từ menu " +"Dá»± Ãn." #: platform/android/export/export.cpp msgid "Invalid public key for APK expansion." @@ -11982,6 +12044,8 @@ msgid "" "Trying to build from a custom built template, but no version info for it " "exists. Please reinstall from the 'Project' menu." msgstr "" +"Cố gắng xây dá»±ng từ má»™t mẫu xuất bản tùy chỉnh, nhÆ°ng không có thông tin " +"phiên bản nà o tồn tại. Vui lòng cà i đặt lại từ menu 'Dá»± án'." #: platform/android/export/export.cpp msgid "" @@ -11990,16 +12054,22 @@ msgid "" " Godot Version: %s\n" "Please reinstall Android build template from 'Project' menu." msgstr "" +"Phiên bản xây dá»±ng Android không khá»›p:\n" +" Mẫu xuất bản được cà i đặt: %s\n" +" Phiên bản Godot sá» dụng: %s\n" +"Vui lòng cà i đặt lại mẫu xuất bản Android từ menu 'Dá»± Ãn'." #: platform/android/export/export.cpp msgid "Building Android Project (gradle)" -msgstr "" +msgstr "Äang dá»±ng dá»± án Android (gradle)" #: platform/android/export/export.cpp msgid "" "Building of Android project failed, check output for the error.\n" "Alternatively visit docs.godotengine.org for Android build documentation." msgstr "" +"Xây dá»±ng dá»± án Android không thà nh công, kiểm tra lá»—i đầu ra.\n" +"Hoặc truy cáºp 'docs.godotengine.org' xem tà i liệu xây dá»±ng Android." #: platform/android/export/export.cpp msgid "No build apk generated at: " @@ -12015,7 +12085,7 @@ msgstr "" #: platform/iphone/export/export.cpp msgid "App Store Team ID not specified - cannot configure the project." -msgstr "" +msgstr "App Store Team ID không được chỉ định - không thể cấu hình dá»± án." #: platform/iphone/export/export.cpp #, fuzzy @@ -12163,6 +12233,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12591,6 +12667,8 @@ msgid "" "Default Environment as specified in Project Settings (Rendering -> " "Environment -> Default Environment) could not be loaded." msgstr "" +"Environment mặc định được chỉ định trong Cà i đặt Dá»± án (Rendering -> " +"Environment -> Default Environment) không thể nạp được." #: scene/main/viewport.cpp msgid "" @@ -12633,6 +12711,9 @@ msgstr "" msgid "Constants cannot be modified." msgstr "Không thể chỉnh sá»a hằng số." +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "Cảnh hiện tại chÆ°a được lÆ°u, hãy lÆ°u nó trÆ°á»›c khi chạy." + #, fuzzy #~ msgid "Revert" #~ msgstr "Trở lại" diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po index f9dc64aea2..e344be12e9 100644 --- a/editor/translations/zh_CN.po +++ b/editor/translations/zh_CN.po @@ -3,7 +3,7 @@ # Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). # This file is distributed under the same license as the Godot source code. # 360119124 <360119124@qq.com>, 2018. -# æŸ æª¬æ€æ‰‹ <lemonkiller@gmail.com>, 2018. +# æŸ æª¬æ€æ‰‹ <lemonkiller@gmail.com>, 2018, 2020. # 纯æ´çš„å蛋 <tqj.zyy@gmail.com>, 2016. # å¤æœˆè“风 <trlanfeng@foxmail.com>, 2016. # å´äº®å¼Ÿ <wu@liangdi.me>, 2017. @@ -34,7 +34,7 @@ # 刘庆文 <liuqingwen@163.com>, 2018. # Haowen Liu <liu.haowen.andy@gmail.com>, 2018. # tangdou1 <1093505442@qq.com>, 2018, 2019. -# yzt <834950797@qq.com>, 2018, 2019. +# yzt <834950797@qq.com>, 2018, 2019, 2020. # DKLost <514dklost@gmail.com>, 2018. # thanksshu <hezihanshangyuan@gmail.com>, 2018. # Jsheng <yangea@outlook.com>, 2019. @@ -66,12 +66,14 @@ # Tim Bao <honiebao@gmail.com>, 2020. # UnluckyNinja <unluckyninja1994@gmail.com>, 2020. # æ— åŒæµ <1257678024@qq.com>, 2020. +# ZhangXinyu <zhang2xinyu@outlook.com>, 2020. +# Silence Tai <silence.m@hotmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Chinese (Simplified) (Godot Engine)\n" "POT-Creation-Date: 2018-01-20 12:15+0200\n" -"PO-Revision-Date: 2020-06-25 08:40+0000\n" -"Last-Translator: UnluckyNinja <unluckyninja1994@gmail.com>\n" +"PO-Revision-Date: 2020-07-26 15:41+0000\n" +"Last-Translator: yzt <834950797@qq.com>\n" "Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/" "godot-engine/godot/zh_Hans/>\n" "Language: zh_CN\n" @@ -84,7 +86,7 @@ msgstr "" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Invalid type argument to convert(), use TYPE_* constants." -msgstr "convert()çš„å‚æ•°ç±»åž‹æ— æ•ˆï¼Œè¯·ä½¿ç”¨TYPE_*常é‡ã€‚" +msgstr "convert() çš„å‚æ•°ç±»åž‹æ— æ•ˆï¼Œè¯·ä½¿ç”¨ TYPE_* 常é‡ã€‚" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." @@ -2008,7 +2010,7 @@ msgstr "属性说明" #: editor/editor_help.cpp msgid "(value)" -msgstr "(值)" +msgstr "(值)" #: editor/editor_help.cpp msgid "" @@ -2348,10 +2350,6 @@ msgid "There is no defined scene to run." msgstr "没有设置è¦æ‰§è¡Œçš„场景。" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "当å‰åœºæ™¯å°šæœªä¿å˜ï¼Œè¯·ä¿å˜åŽå†å°è¯•æ‰§è¡Œã€‚" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "æ— æ³•å¯åŠ¨å进程ï¼" @@ -2635,15 +2633,15 @@ msgstr "é¢æ¿ä½ç½®" #: editor/editor_node.cpp msgid "Distraction Free Mode" -msgstr "æ— å¹²æ‰°æ¨¡å¼" +msgstr "专注模å¼" #: editor/editor_node.cpp msgid "Toggle distraction-free mode." -msgstr "切æ¢æ— 干扰模å¼ã€‚" +msgstr "切æ¢ä¸“注模å¼ã€‚" #: editor/editor_node.cpp msgid "Add a new scene." -msgstr "æ·»åŠ æ–°åœºæ™¯ã€‚" +msgstr "æ·»åŠ åœºæ™¯ã€‚" #: editor/editor_node.cpp msgid "Scene" @@ -2659,11 +2657,11 @@ msgstr "å¤åˆ¶æ–‡æœ¬" #: editor/editor_node.cpp msgid "Next tab" -msgstr "ä¸‹ä¸€ä¸ªæ ‡ç¾é¡µ" +msgstr "ä¸‹ä¸€æ ‡ç¾" #: editor/editor_node.cpp msgid "Previous tab" -msgstr "ä¸Šä¸€ä¸ªæ ‡ç¾" +msgstr "ä¸Šä¸€æ ‡ç¾" #: editor/editor_node.cpp msgid "Filter Files..." @@ -6953,7 +6951,7 @@ msgstr "å–消折å 所有行" #: editor/plugins/script_text_editor.cpp msgid "Clone Down" -msgstr "æ‹·è´åˆ°ä¸‹ä¸€è¡Œ" +msgstr "å¤åˆ¶åˆ°ä¸‹ä¸€è¡Œ" #: editor/plugins/script_text_editor.cpp msgid "Complete Symbol" @@ -7370,7 +7368,7 @@ msgstr "使用å¸é™„" #: editor/plugins/spatial_editor_plugin.cpp msgid "Bottom View" -msgstr "仰视图。" +msgstr "仰视图" #: editor/plugins/spatial_editor_plugin.cpp msgid "Top View" @@ -9803,7 +9801,7 @@ msgid "" "one `/` character." msgstr "" "æœç´¢æ¡†æ ¹æ®å称和路径的末尾部分æ¥è¿‡æ»¤é¡¹ç›®ã€‚\n" -"如果è¦æ ¹æ®å称和完整路径过滤,æœç´¢å†…容应至少包å«ä¸€ä¸ªâ€œ/â€å—符。" +"如果è¦æ ¹æ®å称和完整路径过滤,æœç´¢å†…容应至少包å«ä¸€ä¸ª `/` å—符。" #: editor/project_settings_editor.cpp msgid "Key " @@ -10401,6 +10399,11 @@ msgid "Make node as Root" msgstr "å°†èŠ‚ç‚¹è®¾ç½®ä¸ºæ ¹èŠ‚ç‚¹" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "是å¦åˆ 除节点“%sâ€åŠå…¶å节点?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "是å¦åˆ 除%d个节点?" @@ -11677,7 +11680,7 @@ msgstr "生æˆå‡½æ•°" #: modules/visual_script/visual_script_editor.cpp msgid "Refresh Graph" -msgstr "刷新图" +msgstr "刷新节点" #: modules/visual_script/visual_script_editor.cpp msgid "Edit Member" @@ -12040,6 +12043,12 @@ msgid "" "shape resource for it!" msgstr "形状资æºå¿…须是通过CollisionShape2D节点的shape属性创建的ï¼" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12320,7 +12329,7 @@ msgid "" "PathFollow's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its " "parent Path's Curve resource." msgstr "" -"PathFollowçš„ROTATION_ORIENTEDè¦æ±‚在其父路径的Curve资æºä¸å¯ç”¨â€œå‘上矢é‡â€ã€‚" +"PathFollow çš„ ROTATION_ORIENTED è¦æ±‚在其父路径的 Curve 资æºä¸å¯ç”¨â€œå‘上矢é‡â€ã€‚" #: scene/3d/physics_body.cpp msgid "" @@ -12558,6 +12567,9 @@ msgstr "å˜é‡åªèƒ½åœ¨é¡¶ç‚¹å‡½æ•°ä¸æŒ‡å®šã€‚" msgid "Constants cannot be modified." msgstr "ä¸å…许修改常é‡ã€‚" +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "当å‰åœºæ™¯å°šæœªä¿å˜ï¼Œè¯·ä¿å˜åŽå†å°è¯•æ‰§è¡Œã€‚" + #~ msgid "Not in resource path." #~ msgstr "ä¸åœ¨èµ„æºè·¯å¾„下。" diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po index 90c85892f6..d4e1bf62dd 100644 --- a/editor/translations/zh_HK.po +++ b/editor/translations/zh_HK.po @@ -2406,10 +2406,6 @@ msgid "There is no defined scene to run." msgstr "沒有å¯ä»¥å·²å®šç¾©çš„å ´æ™¯å¯ä»¥é‹è¡Œã€‚" #: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "" - -#: editor/editor_node.cpp msgid "Could not start subprocess!" msgstr "" @@ -10813,6 +10809,11 @@ msgstr "儲å˜å ´æ™¯" #: editor/scene_tree_dock.cpp #, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "åˆ é™¤root node \"%s\"?" + +#: editor/scene_tree_dock.cpp +#, fuzzy msgid "Delete %d nodes?" msgstr "ä¸é¸" @@ -12533,6 +12534,12 @@ msgid "" "shape resource for it!" msgstr "" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po index 129a3fdad4..73b99ee161 100644 --- a/editor/translations/zh_TW.po +++ b/editor/translations/zh_TW.po @@ -28,7 +28,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-22 06:40+0000\n" +"PO-Revision-Date: 2020-07-07 15:56+0000\n" "Last-Translator: BinotaLIU <me@binota.org>\n" "Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/" "godot-engine/godot/zh_Hant/>\n" @@ -52,7 +52,7 @@ msgstr "應為一個長度為 1(一個å—元)的å—串。" #: modules/mono/glue/gd_glue.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Not enough bytes for decoding bytes, or invalid format." -msgstr "欲解碼的ä½å…ƒçµ„ä¸è¶³æˆ–æ ¼å¼ç„¡æ•ˆã€‚" +msgstr "ä½å…ƒçµ„長度ä¸è¶³ä»¥é€²è¡Œè§£ç¢¼æˆ–æˆ–æ ¼å¼ç„¡æ•ˆã€‚" #: core/math/expression.cpp msgid "Invalid input %i (not passed) in expression" @@ -196,7 +196,7 @@ msgstr "更改多個動畫的關éµç•«æ ¼æ•¸å€¼" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Call" -msgstr "更改多個動畫的回調" +msgstr "更改多個動畫的呼å«" #: editor/animation_track_editor.cpp msgid "Change Animation Length" @@ -302,7 +302,7 @@ msgstr "ä¸é€£çºŒ" #: editor/animation_track_editor.cpp msgid "Trigger" -msgstr "觸發器" +msgstr "觸發程åº" #: editor/animation_track_editor.cpp msgid "Capture" @@ -408,7 +408,7 @@ msgstr "é‡æ–°æŽ’列軌é“" #: editor/animation_track_editor.cpp msgid "Transform tracks only apply to Spatial-based nodes." -msgstr "變形軌åªèƒ½å¥—用至 Spatial 節點。" +msgstr "變形軌僅å¯å¥—用至 Spatial 節點。" #: editor/animation_track_editor.cpp msgid "" @@ -417,18 +417,18 @@ msgid "" "-AudioStreamPlayer2D\n" "-AudioStreamPlayer3D" msgstr "" -"音訊軌åªèƒ½æŒ‡å‘以下類型的節點:\n" +"音訊軌僅å¯æŒ‡å‘以下類型節點:\n" "-AudioStreamPlayer\n" "-AudioStreamPlayer2D\n" "-AudioStreamPlayer3D" #: editor/animation_track_editor.cpp msgid "Animation tracks can only point to AnimationPlayer nodes." -msgstr "動畫軌åªèƒ½æŒ‡å‘ AnimationPlayer 節點。" +msgstr "動畫軌僅å¯æŒ‡å‘ AnimationPlayer 節點。" #: editor/animation_track_editor.cpp msgid "An animation player can't animate itself, only other players." -msgstr "å‹•ç•« Player 無法æ’放自己,åªèƒ½æ’放其他 Player。" +msgstr "å‹•ç•« Player 無法æ’放自己,僅å¯æ’放其他 Player。" #: editor/animation_track_editor.cpp msgid "Not possible to add a new track without a root" @@ -460,7 +460,7 @@ msgstr "æ·»åŠ è»Œé“é—œéµç•«æ ¼" #: editor/animation_track_editor.cpp msgid "Track path is invalid, so can't add a method key." -msgstr "無效的軌é“路徑,無法新增方法關éµç•«æ ¼ã€‚" +msgstr "無效軌é“路徑,無法新增方法關éµç•«æ ¼ã€‚" #: editor/animation_track_editor.cpp msgid "Add Method Track Key" @@ -503,11 +503,12 @@ msgid "" "Alternatively, use an import preset that imports animations to separate " "files." msgstr "" -"é€™å€‹å‹•ç•«æ˜¯ç”±å¤–éƒ¨åŒ¯å…¥ä¹‹å ´æ™¯æ供,套用於匯入軌é“的修改將ä¸æœƒè¢«ä¿å˜ã€‚\n" +"è©²å‹•ç•«å±¬æ–¼å¤–éƒ¨åŒ¯å…¥ä¹‹å ´æ™¯ï¼Œå¥—ç”¨æ–¼åŒ¯å…¥è»Œé“的修改將ä¸æœƒè¢«ä¿å˜ã€‚\n" "\n" -"è‹¥è¦é–‹å•Ÿã€ŒåŠ 入客制軌ã€çš„åŠŸèƒ½ï¼Œè«‹åœ¨å ´æ™¯åœ¨åŒ¯å…¥è¨å®šä¸å°‡ã€Œå‹•ç•« -> 儲å˜ã€è¨å®šç‚º\n" -"「檔案ã€ï¼Œä¸¦å•Ÿç”¨ã€Œå‹•ç•« -> ä¿å˜å®¢åˆ¶è»Œã€ï¼Œç„¶å¾Œé‡æ–°åŒ¯å…¥ã€‚\n" -"或者也å¯ä½¿ç”¨æœƒå°‡å‹•ç•«åŒ¯å…¥ç¨ç«‹æª”案的匯入 Preset。" +"è‹¥è¦é–‹å•Ÿã€ŒåŠ 入客制軌ã€çš„åŠŸèƒ½ï¼Œè«‹åœ¨å ´æ™¯åœ¨åŒ¯å…¥è¨å®šä¸å°‡ [Animation] -> " +"[Storage] è¨å®šç‚º\n" +"[Files],並啟用 [Animation] -> [Keep Custom Tracks],然後é‡æ–°åŒ¯å…¥ã€‚\n" +"å¦å¯ä½¿ç”¨æœƒå°‡å‹•ç•«åŒ¯å…¥ç¨ç«‹æª”案的匯入é è¨è¨å®šã€‚" #: editor/animation_track_editor.cpp msgid "Warning: Editing imported animation" @@ -597,7 +598,7 @@ msgstr "清除動畫" #: editor/animation_track_editor.cpp msgid "Pick the node that will be animated:" -msgstr "é¸æ“‡è¦è¨å®šå‹•ç•«çš„節點:" +msgstr "é¸æ“‡æ¬²è¨å®šå‹•ç•«ä¹‹ç¯€é»žï¼š" #: editor/animation_track_editor.cpp msgid "Use Bezier Curves" @@ -698,7 +699,7 @@ msgstr "行號:" #: editor/code_editor.cpp msgid "%d replaced." -msgstr "å·²å–代了 %d 件。" +msgstr "å·²å–代 %d 件。" #: editor/code_editor.cpp editor/editor_help.cpp msgid "%d match." @@ -714,7 +715,7 @@ msgstr "å€åˆ†å¤§å°å¯«" #: editor/code_editor.cpp editor/find_in_files.cpp msgid "Whole Words" -msgstr "æœå°‹å®Œæ•´å–®å—" +msgstr "æœå°‹å®Œæ•´å–®è©ž" #: editor/code_editor.cpp editor/rename_dialog.cpp msgid "Replace" @@ -759,16 +760,15 @@ msgstr "è¦å‘Š" #: editor/code_editor.cpp msgid "Line and column numbers." -msgstr "行號和列號。" +msgstr "行號與列號。" #: editor/connections_dialog.cpp msgid "Method in target node must be specified." -msgstr "å¿…é ˆæŒ‡å®šç›®æ¨™ç¯€é»žçš„æ–¹æ³•ã€‚" +msgstr "å¿…é ˆæŒ‡å®šç›®æ¨™ç¯€é»žæ–¹æ³•ã€‚" #: editor/connections_dialog.cpp -#, fuzzy msgid "Method name must be a valid identifier." -msgstr "å稱ä¸æ˜¯ä¸€å€‹æœ‰æ•ˆçš„è˜åˆ¥ç¬¦ï¼š" +msgstr "方法åç¨±å¿…é ˆç‚ºæœ‰æ•ˆè˜åˆ¥ç¬¦ã€‚" #: editor/connections_dialog.cpp msgid "" @@ -790,7 +790,7 @@ msgstr "自訊號:" #: editor/connections_dialog.cpp msgid "Scene does not contain any script." -msgstr "å ´æ™¯ä¸ç„¡ä»»ä½•çš„腳本。" +msgstr "å ´æ™¯ä¸ç„¡ä»»ä½•è…³æœ¬ã€‚" #: editor/connections_dialog.cpp editor/editor_autoload_settings.cpp #: editor/groups_editor.cpp editor/plugins/item_list_editor_plugin.cpp @@ -819,7 +819,7 @@ msgstr "é¡å¤–呼å«å¼•æ•¸ï¼š" #: editor/connections_dialog.cpp msgid "Receiver Method:" -msgstr "Receiver 方法:" +msgstr "接收器方法:" #: editor/connections_dialog.cpp msgid "Advanced" @@ -1028,7 +1028,7 @@ msgstr "é–‹å•Ÿ" #: editor/dependency_editor.cpp msgid "Owners Of:" -msgstr "æ“有者:" +msgstr "為下列之æ“有者:" #: editor/dependency_editor.cpp msgid "Remove selected files from the project? (Can't be restored)" @@ -1101,7 +1101,7 @@ msgstr "沒有明確從屬關係的資æºï¼š" #: editor/dictionary_property_edit.cpp msgid "Change Dictionary Key" -msgstr "改變å—å…¸éµ" +msgstr "改變å—典索引éµ" #: editor/dictionary_property_edit.cpp msgid "Change Dictionary Value" @@ -1179,7 +1179,7 @@ msgid "" "respective copyright statements and license terms." msgstr "" "Godot Engine ä¾è³´æ•¸å€‹è‡ªç”±ä¸”開放原始碼的第三方函å¼åº«ï¼Œæ‰€æœ‰å‡½å¼åº«çš†ç›¸å®¹æ–¼ MIT " -"授權æ¢æ¬¾ã€‚以下是這些第三方元件的完整列表於其å„自之著作權宣告與授權æ¢æ¬¾ã€‚" +"授權æ¢æ¬¾ã€‚以下為這些第三方元件的完整列表與其著作權宣告åŠæŽˆæ¬Šæ¢æ¬¾ã€‚" #: editor/editor_about.cpp msgid "All Components" @@ -1244,39 +1244,39 @@ msgstr "新增效果" #: editor/editor_audio_buses.cpp msgid "Rename Audio Bus" -msgstr "é‡æ–°å‘½å音訊 Bus" +msgstr "é‡æ–°å‘½å音訊匯æµæŽ’" #: editor/editor_audio_buses.cpp msgid "Change Audio Bus Volume" -msgstr "更改音訊 Bus 音é‡" +msgstr "更改音訊匯æµæŽ’音é‡" #: editor/editor_audio_buses.cpp msgid "Toggle Audio Bus Solo" -msgstr "切æ›éŸ³è¨Š Bus çš„ Solo" +msgstr "切æ›éŸ³è¨ŠåŒ¯æµæŽ’ Solo" #: editor/editor_audio_buses.cpp msgid "Toggle Audio Bus Mute" -msgstr "éœéŸ³ï¼å–消éœéŸ³éŸ³è¨Š Bus" +msgstr "éœéŸ³ï¼å–消éœéŸ³éŸ³è¨ŠåŒ¯æµæŽ’" #: editor/editor_audio_buses.cpp msgid "Toggle Audio Bus Bypass Effects" -msgstr "忽略ï¼å–消忽略音訊 Bus 效果" +msgstr "忽略ï¼å–消忽略音訊匯æµæŽ’效果" #: editor/editor_audio_buses.cpp msgid "Select Audio Bus Send" -msgstr "é¸æ“‡ Bus 輸出地點" +msgstr "é¸æ“‡éŸ³è¨ŠåŒ¯æµæŽ’輸出ä½ç½®" #: editor/editor_audio_buses.cpp msgid "Add Audio Bus Effect" -msgstr "新增音效 Bus 效果" +msgstr "新增音效匯æµæŽ’效果" #: editor/editor_audio_buses.cpp msgid "Move Bus Effect" -msgstr "移動 Bus 效果" +msgstr "移動匯æµæŽ’效果" #: editor/editor_audio_buses.cpp msgid "Delete Bus Effect" -msgstr "刪除 Bus 效果" +msgstr "刪除匯æµæŽ’效果" #: editor/editor_audio_buses.cpp msgid "Drag & drop to rearrange." @@ -1296,7 +1296,7 @@ msgstr "忽略效果" #: editor/editor_audio_buses.cpp msgid "Bus options" -msgstr "Bus é¸é …" +msgstr "匯æµæŽ’é¸é …" #: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp #: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp @@ -1317,31 +1317,31 @@ msgstr "音訊" #: editor/editor_audio_buses.cpp msgid "Add Audio Bus" -msgstr "新增音訊 Bus" +msgstr "新增音訊匯æµæŽ’" #: editor/editor_audio_buses.cpp msgid "Master bus can't be deleted!" -msgstr "Master Bus ä¸å¯åˆªé™¤ï¼" +msgstr "ä¸å¯åˆªé™¤ä¸»åŒ¯æµæŽ’ï¼" #: editor/editor_audio_buses.cpp msgid "Delete Audio Bus" -msgstr "刪除音訊 Bus" +msgstr "刪除音訊匯æµæŽ’" #: editor/editor_audio_buses.cpp msgid "Duplicate Audio Bus" -msgstr "é‡è¤‡éŸ³è¨Š Bus" +msgstr "é‡è¤‡éŸ³è¨ŠåŒ¯æµæŽ’" #: editor/editor_audio_buses.cpp msgid "Reset Bus Volume" -msgstr "é‡è¨ Bus 音é‡" +msgstr "é‡è¨åŒ¯æµæŽ’音é‡" #: editor/editor_audio_buses.cpp msgid "Move Audio Bus" -msgstr "移動音訊 Bus" +msgstr "移動音訊匯æµæŽ’" #: editor/editor_audio_buses.cpp msgid "Save Audio Bus Layout As..." -msgstr "å¦å˜éŸ³è¨Š Bus é…置為..." +msgstr "將音訊匯æµæŽ’é…ç½®å¦å˜ç‚º..." #: editor/editor_audio_buses.cpp msgid "Location for New Layout..." @@ -1349,7 +1349,7 @@ msgstr "æ–°é…置的ä½ç½®..." #: editor/editor_audio_buses.cpp msgid "Open Audio Bus Layout" -msgstr "開啟音訊 Bus é…ç½®" +msgstr "開啟音訊匯æµæŽ’é…ç½®" #: editor/editor_audio_buses.cpp msgid "There is no '%s' file." @@ -1361,7 +1361,7 @@ msgstr "ç•«é¢é…ç½®" #: editor/editor_audio_buses.cpp msgid "Invalid file, not an audio bus layout." -msgstr "無效的檔案,或該檔案ä¸æ˜¯éŸ³è¨Š Bus é…置檔。" +msgstr "無效檔案或該檔案並éžéŸ³è¨ŠåŒ¯æµæŽ’é…置檔。" #: editor/editor_audio_buses.cpp msgid "Error saving file: %s" @@ -1369,11 +1369,11 @@ msgstr "無法ä¿å˜æª”案:%s" #: editor/editor_audio_buses.cpp msgid "Add Bus" -msgstr "新增 Bus" +msgstr "新增匯æµæŽ’" #: editor/editor_audio_buses.cpp msgid "Add a new Audio Bus to this layout." -msgstr "新增一個新的音訊 Bus 至該é…置。" +msgstr "新增一個新的音訊匯æµæŽ’至該é…置。" #: editor/editor_audio_buses.cpp editor/editor_properties.cpp #: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp @@ -1383,7 +1383,7 @@ msgstr "載入" #: editor/editor_audio_buses.cpp msgid "Load an existing Bus Layout." -msgstr "讀å–ç¾å˜çš„ Bus é…置。" +msgstr "讀å–ç¾æœ‰çš„匯æµæŽ’é…置。" #: editor/editor_audio_buses.cpp msgid "Save As" @@ -1391,7 +1391,7 @@ msgstr "å¦å˜æ–°æª”" #: editor/editor_audio_buses.cpp msgid "Save this Bus Layout to a file." -msgstr "將該 Bus é…ç½®ä¿å˜è‡³æª”案。" +msgstr "將該匯æµæŽ’é…ç½®ä¿å˜è‡³æª”案。" #: editor/editor_audio_buses.cpp editor/import_dock.cpp msgid "Load Default" @@ -1399,11 +1399,11 @@ msgstr "載入é è¨" #: editor/editor_audio_buses.cpp msgid "Load the default Bus Layout." -msgstr "載入é è¨çš„ Bus é…置。" +msgstr "載入é è¨åŒ¯æµæŽ’é…置。" #: editor/editor_audio_buses.cpp msgid "Create a new Bus Layout." -msgstr "建立新的 Bus é…置。" +msgstr "建立新匯æµæŽ’é…置。" #: editor/editor_autoload_settings.cpp msgid "Invalid name." @@ -1419,7 +1419,7 @@ msgstr "ä¸å¯èˆ‡ç¾å˜çš„引擎類別å稱è¡çªã€‚" #: editor/editor_autoload_settings.cpp msgid "Must not collide with an existing built-in type name." -msgstr "ä¸å¯èˆ‡å…§å»ºçš„列表å稱è¡çªã€‚" +msgstr "ä¸å¯èˆ‡å…§å»ºçš„類別å稱è¡çªã€‚" #: editor/editor_autoload_settings.cpp msgid "Must not collide with an existing global constant name." @@ -1484,7 +1484,7 @@ msgstr "å稱" #: editor/editor_autoload_settings.cpp msgid "Singleton" -msgstr "單例 (Singleton)" +msgstr "單例" #: editor/editor_data.cpp editor/inspector_dock.cpp msgid "Paste Params" @@ -1512,7 +1512,7 @@ msgstr "[未ä¿å˜]" #: editor/editor_dir_dialog.cpp msgid "Please select a base directory first." -msgstr "è«‹å…ˆé¸æ“‡ä¸€å€‹åŸºç¤Žçš„資料夾。" +msgstr "è«‹å…ˆé¸æ“‡åŸºç¤Žè³‡æ–™å¤¾ã€‚" #: editor/editor_dir_dialog.cpp msgid "Choose a Directory" @@ -1557,15 +1557,16 @@ msgid "" "Target platform requires 'ETC' texture compression for GLES2. Enable 'Import " "Etc' in Project Settings." msgstr "" -"目標平å°ä¸Šçš„ GLES2 å¿…é ˆä½¿ç”¨ã€ŒETCã€ç´‹ç†å£“縮。請在專案è¨å®šä¸å•Ÿç”¨ã€ŒåŒ¯å…¥ ETCã€ã€‚" +"目標平å°ä¸Šçš„ GLES2 å¿…é ˆä½¿ç”¨ã€ŒETCã€ç´‹ç†å£“縮。請在專案è¨å®šä¸å•Ÿç”¨ã€ŒImport " +"Etcã€ã€‚" #: editor/editor_export.cpp msgid "" "Target platform requires 'ETC2' texture compression for GLES3. Enable " "'Import Etc 2' in Project Settings." msgstr "" -"目標平å°ä¸Šçš„ GLES3 å¿…é ˆä½¿ç”¨ã€ŒETC2ã€ç´‹ç†å£“縮。請在專案è¨å®šä¸å•Ÿç”¨ã€ŒåŒ¯å…¥ " -"ETC2ã€ã€‚" +"目標平å°ä¸Šçš„ GLES3 å¿…é ˆä½¿ç”¨ã€ŒETC2ã€ç´‹ç†å£“縮。請在專案è¨å®šä¸å•Ÿç”¨ã€ŒImport Etc " +"2ã€ã€‚" #: editor/editor_export.cpp msgid "" @@ -1575,7 +1576,7 @@ msgid "" "Enabled'." msgstr "" "目標平å°ä¸Šçš„ GLES2 å›žé€€é©…å‹•å™¨åŠŸèƒ½å¿…é ˆä½¿ç”¨ã€ŒETCã€ç´‹ç†å£“縮。\n" -"請在專案è¨å®šä¸å•Ÿç”¨ã€ŒåŒ¯å…¥ ETCã€æˆ–是ç¦ç”¨ã€Œå•Ÿç”¨é©…動器回退ã€ã€‚" +"請在專案è¨å®šä¸å•Ÿç”¨ã€ŒImport Etcã€æˆ–是ç¦ç”¨ã€ŒDriver Fallback Enabledã€ã€‚" #: editor/editor_export.cpp platform/android/export/export.cpp #: platform/iphone/export/export.cpp platform/javascript/export/export.cpp @@ -1587,7 +1588,7 @@ msgstr "找ä¸åˆ°è‡ªå®šç¾©åµéŒ¯æ¨£æ¿ã€‚" #: platform/iphone/export/export.cpp platform/javascript/export/export.cpp #: platform/osx/export/export.cpp platform/uwp/export/export.cpp msgid "Custom release template not found." -msgstr "找ä¸åˆ°è‡ªå®šç¾©é‡‹å‡ºæ¨£æ¿ã€‚" +msgstr "找ä¸åˆ°è‡ªå®šç¾©ç™¼è¡Œæ¨£æ¿ã€‚" #: editor/editor_export.cpp platform/javascript/export/export.cpp msgid "Template file not found:" @@ -1595,7 +1596,7 @@ msgstr "找ä¸åˆ°æ¨£æ¿æª”案:" #: editor/editor_export.cpp msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB." -msgstr "匯出 32 ä½å…ƒæª”時,內嵌的 PCK 大å°ä¸å¾—è¶…éŽ 4 GB。" +msgstr "匯出 32 ä½å…ƒæª”時,內嵌 PCK 大å°ä¸å¾—è¶…éŽ 4 GB。" #: editor/editor_feature_profile.cpp msgid "3D Editor" @@ -1627,15 +1628,15 @@ msgstr "檔案系統與匯入 Dock" #: editor/editor_feature_profile.cpp msgid "Erase profile '%s'? (no undo)" -msgstr "確定è¦æ¸…除 Profile「%sã€å—Žï¼Ÿï¼ˆç„¡æ³•å¾©åŽŸï¼‰" +msgstr "確定è¦æ¸…除è¨å®šæª”「%sã€å—Žï¼Ÿï¼ˆç„¡æ³•å¾©åŽŸï¼‰" #: editor/editor_feature_profile.cpp msgid "Profile must be a valid filename and must not contain '.'" -msgstr "Profile å¿…é ˆç‚ºä¸€å€‹æœ‰æ•ˆçš„æª”æ¡ˆå稱,並且ä¸åŒ…å«ã€Œ.ã€" +msgstr "è¨å®šæª”å¿…é ˆç‚ºæœ‰æ•ˆæª”å,且ä¸å¯åŒ…å«ã€Œ.ã€" #: editor/editor_feature_profile.cpp msgid "Profile with this name already exists." -msgstr "已有相åŒå稱的 Profile å˜åœ¨ã€‚" +msgstr "已有相åŒå稱的è¨å®šæª”å˜åœ¨ã€‚" #: editor/editor_feature_profile.cpp msgid "(Editor Disabled, Properties Disabled)" @@ -1677,11 +1678,11 @@ msgstr "檔案「%sã€çš„æ ¼å¼ç„¡æ•ˆï¼Œå·²ä¸æ¢åŒ¯å…¥ã€‚" msgid "" "Profile '%s' already exists. Remove it first before importing, import " "aborted." -msgstr "Profile「%sã€å·²ç¶“å˜åœ¨ã€‚匯入å‰è«‹å…ˆå°‡å…¶ç§»é™¤ã€‚å·²ä¸æ¢åŒ¯å…¥ã€‚" +msgstr "è¨å®šæª”「%sã€å·²å˜åœ¨ã€‚匯入å‰è«‹å…ˆå°‡å…¶ç§»é™¤ã€‚å·²ä¸æ¢åŒ¯å…¥ã€‚" #: editor/editor_feature_profile.cpp msgid "Error saving profile to path: '%s'." -msgstr "ä¿å˜ Profile 至路徑「%sã€æ™‚發生錯誤。" +msgstr "在下列路徑ä¿å˜è¨å®šæª”時發生錯誤:%s。" #: editor/editor_feature_profile.cpp msgid "Unset" @@ -1689,7 +1690,7 @@ msgstr "未è¨å®š" #: editor/editor_feature_profile.cpp msgid "Current Profile:" -msgstr "ç›®å‰ç‰ˆæœ¬ï¼š" +msgstr "ç›®å‰è¨å®šæª”:" #: editor/editor_feature_profile.cpp msgid "Make Current" @@ -1712,7 +1713,7 @@ msgstr "匯出" #: editor/editor_feature_profile.cpp msgid "Available Profiles:" -msgstr "å¯ç”¨çš„ Profile:" +msgstr "å¯ç”¨è¨å®šæª”:" #: editor/editor_feature_profile.cpp msgid "Class Options" @@ -1720,31 +1721,31 @@ msgstr "類別é¸é …" #: editor/editor_feature_profile.cpp msgid "New profile name:" -msgstr "新增 Profile å稱:" +msgstr "新增è¨å®šæª”å稱:" #: editor/editor_feature_profile.cpp msgid "Erase Profile" -msgstr "清除 Profile" +msgstr "清除è¨å®šæª”" #: editor/editor_feature_profile.cpp msgid "Godot Feature Profile" -msgstr "Godot 功能 Profile" +msgstr "Godot 功能è¨å®šæª”" #: editor/editor_feature_profile.cpp msgid "Import Profile(s)" -msgstr "匯入 Profile" +msgstr "匯入è¨å®šæª”" #: editor/editor_feature_profile.cpp msgid "Export Profile" -msgstr "匯出 Profile" +msgstr "匯出è¨å®šæª”" #: editor/editor_feature_profile.cpp msgid "Manage Editor Feature Profiles" -msgstr "管ç†ç·¨è¼¯å™¨åŠŸèƒ½ Profile" +msgstr "管ç†ç·¨è¼¯å™¨åŠŸèƒ½è¨å®šæª”" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Select Current Folder" -msgstr "é¸æ“‡ç›®å‰çš„資料夾" +msgstr "é¸æ“‡ç›®å‰è³‡æ–™å¤¾" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "File Exists, Overwrite?" @@ -1865,7 +1866,7 @@ msgstr "é‡æ–°æ•´ç†æª”案。" #: editor/editor_file_dialog.cpp msgid "(Un)favorite current folder." -msgstr "將目å‰çš„資料夾新增或移除我的最愛。" +msgstr "將目å‰è³‡æ–™å¤¾æ–°å¢žæˆ–移除至我的最愛。" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Toggle the visibility of hidden files." @@ -1913,7 +1914,7 @@ msgstr "(é‡æ–°ï¼‰åŒ¯å…¥ç´ æ" #: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp msgid "Top" -msgstr "上" +msgstr "é ‚ç«¯" #: editor/editor_help.cpp msgid "Class:" @@ -2009,27 +2010,27 @@ msgstr "全部顯示" #: editor/editor_help_search.cpp msgid "Classes Only" -msgstr "僅é™é¡žåˆ¥" +msgstr "僅顯示類別" #: editor/editor_help_search.cpp msgid "Methods Only" -msgstr "僅é™æ–¹æ³•" +msgstr "僅顯示方法" #: editor/editor_help_search.cpp msgid "Signals Only" -msgstr "僅é™ä¿¡è™Ÿ" +msgstr "僅顯示訊號" #: editor/editor_help_search.cpp msgid "Constants Only" -msgstr "僅é™å¸¸æ•¸" +msgstr "僅顯示常數" #: editor/editor_help_search.cpp msgid "Properties Only" -msgstr "僅é™å±¬æ€§" +msgstr "僅顯示屬性" #: editor/editor_help_search.cpp msgid "Theme Properties Only" -msgstr "僅é™ä¸»é¡Œå±¬æ€§" +msgstr "僅顯示主題屬性" #: editor/editor_help_search.cpp msgid "Member Type" @@ -2156,7 +2157,7 @@ msgstr "ä¿å˜è³‡æºéŒ¯èª¤ï¼" msgid "" "This resource can't be saved because it does not belong to the edited scene. " "Make it unique first." -msgstr "由於該資æºä¸å±¬æ–¼å·²ç·¨è¼¯çš„å ´æ™¯ï¼Œç„¡æ³•ä¿å˜è©²è³‡æºã€‚請先確ä¿å…¶ç¨ç«‹ã€‚" +msgstr "由於該資æºä¸å±¬æ–¼å·²ç·¨è¼¯çš„å ´æ™¯ï¼Œç„¡æ³•ä¿å˜è©²è³‡æºã€‚請先使其ç¨ç«‹åŒ–。" #: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp msgid "Save Resource As..." @@ -2305,11 +2306,7 @@ msgstr "" #: editor/editor_node.cpp msgid "There is no defined scene to run." -msgstr "æ²’æœ‰å·²å®šç¾©çš„å ´æ™¯å¯åŸ·è¡Œã€‚" - -#: editor/editor_node.cpp -msgid "Current scene was never saved, please save it prior to running." -msgstr "ç›®å‰çš„å ´æ™¯å¾žæœªè¢«ä¿å˜ï¼Œè«‹å…ˆä¿å˜ä»¥åŸ·è¡Œã€‚" +msgstr "æœªå®šç¾©æ¬²åŸ·è¡Œä¹‹å ´æ™¯ã€‚" #: editor/editor_node.cpp msgid "Could not start subprocess!" @@ -2365,7 +2362,7 @@ msgstr "是" #: editor/editor_node.cpp msgid "This scene has never been saved. Save before running?" -msgstr "æ¤å ´æ™¯å¾žæœªè¢«ä¿å˜ã€‚是å¦è¦åœ¨åŸ·è¡Œå‰å…ˆä¿å˜ï¼Ÿ" +msgstr "æ¤å ´æ™¯å¾žæœªè¢«ä¿å˜ã€‚是å¦æ–¼åŸ·è¡Œå‰å…ˆä¿å˜ï¼Ÿ" #: editor/editor_node.cpp editor/scene_tree_dock.cpp msgid "This operation can't be done without a scene." @@ -2381,15 +2378,15 @@ msgstr "該æ“ä½œå¿…é ˆè¦æœ‰è·Ÿç¯€é»žæ‰å¯å®Œæˆã€‚" #: editor/editor_node.cpp msgid "Export Tile Set" -msgstr "匯出 Tile Set" +msgstr "匯出圖塊集" #: editor/editor_node.cpp msgid "This operation can't be done without a selected node." -msgstr "該æ“ä½œå¿…é ˆè¦æœ‰å·²é¸æ“‡çš„節點æ‰å¯å®Œæˆã€‚" +msgstr "è«‹å…ˆé¸æ“‡ç¯€é»žä»¥åŸ·è¡Œè©²æ“作。" #: editor/editor_node.cpp msgid "Current scene not saved. Open anyway?" -msgstr "ç›®å‰çš„å ´æ™¯å°šæœªä¿å˜ã€‚ä»ç„¶è¦é–‹å•Ÿå—Žï¼Ÿ" +msgstr "尚未ä¿å˜ç›®å‰å ´æ™¯ã€‚ä»ç„¶è¦é–‹å•Ÿå—Žï¼Ÿ" #: editor/editor_node.cpp msgid "Can't reload a scene that was never saved." @@ -2404,8 +2401,8 @@ msgid "" "The current scene has unsaved changes.\n" "Reload the saved scene anyway? This action cannot be undone." msgstr "" -"ç›®å‰çš„å ´æ™¯æœ‰æœªä¿å˜çš„改動。\n" -"ä»ç„¶è¦é‡æ–°è¼‰å…¥å ´æ™¯å—Žï¼Ÿé€™å€‹æ“作將無法復原。" +"ç›®å‰å ´æ™¯æœ‰æœªä¿å˜çš„改動。\n" +"ä»è¦é‡æ–°è¼‰å…¥å ´æ™¯å—Žï¼Ÿæ¤æ“作將無法復原。" #: editor/editor_node.cpp msgid "Quick Run Scene..." @@ -2439,9 +2436,7 @@ msgstr "開啟專案管ç†å“¡å‰è¦å…ˆä¿å˜ä»¥ä¸‹å ´æ™¯å—Žï¼Ÿ" msgid "" "This option is deprecated. Situations where refresh must be forced are now " "considered a bug. Please report." -msgstr "" -"該é¸é …å·²åœæ¢ç¶è·ã€‚é‡åˆ°éœ€è¦å¼·åˆ¶é‡æ–°æ•´ç†çš„ç‹€æ³ç¾åœ¨å·²è¢«è¦–為程å¼éŒ¯èª¤ã€‚è«‹å›žå ±è©²å•" -"題。" +msgstr "該é¸é …å·²åœæ¢ç¶è·ã€‚ç›®å‰å·²å°‡éœ€å¼·åˆ¶é‡æ–°æ•´ç†ä¹‹ç‹€æ³è¦–為 Bugï¼Œè«‹å›žå ±è©²å•é¡Œã€‚" #: editor/editor_node.cpp msgid "Pick a Main Scene" @@ -2471,12 +2466,12 @@ msgstr "無法自路徑「%sã€è¼‰å…¥æ“´å……腳本。" msgid "" "Unable to load addon script from path: '%s' There seems to be an error in " "the code, please check the syntax." -msgstr "無法從路徑「%sã€è¼‰å…¥æ“´å……腳本。看樣å是程å¼ç¢¼ä¸æœ‰éŒ¯èª¤ï¼Œè«‹æª¢æŸ¥èªžæ³•ã€‚" +msgstr "無法自路徑「%sã€è¼‰å…¥æ“´å……腳本。å¯èƒ½ç‚ºç¨‹å¼ç¢¼ä¸æœ‰éŒ¯èª¤ï¼Œè«‹æª¢æŸ¥èªžæ³•ã€‚" #: editor/editor_node.cpp msgid "" "Unable to load addon script from path: '%s' Base type is not EditorPlugin." -msgstr "無法自路徑「%sã€è¼‰å…¥æ“´å……腳本,基礎型別ä¸æ˜¯ EditorPlugin。" +msgstr "無法自路徑「%sã€è¼‰å…¥æ“´å……è…³æœ¬ï¼ŒåŸºç¤Žåž‹åˆ¥éž EditorPlugin。" #: editor/editor_node.cpp msgid "Unable to load addon script from path: '%s' Script is not in tool mode." @@ -2495,7 +2490,7 @@ msgid "" "Error loading scene, it must be inside the project path. Use 'Import' to " "open the scene, then save it inside the project path." msgstr "" -"è¼‰å…¥å ´æ™¯æ™‚ç™¼ç”ŸéŒ¯èª¤ï¼Œå ´æ™¯å¿…é ˆç½®æ–¼å°ˆæ¡ˆè·¯å¾‘å…§ã€‚è«‹ä½¿ç”¨ã€ŒåŒ¯å…¥ã€ä¾†é–‹å•Ÿè©²å ´æ™¯ï¼Œä¸¦å°‡" +"è¼‰å…¥å ´æ™¯æ™‚ç™¼ç”ŸéŒ¯èª¤ï¼Œå ´æ™¯å¿…é ˆç½®æ–¼å°ˆæ¡ˆè·¯å¾‘å…§ã€‚è«‹ä½¿ç”¨ [匯入] ä¾†é–‹å•Ÿè©²å ´æ™¯ï¼Œä¸¦å°‡" "å…¶ä¿å˜æ–¼å°ˆæ¡ˆè·¯å¾‘內。" #: editor/editor_node.cpp @@ -2513,7 +2508,7 @@ msgid "" "category." msgstr "" "å°šæœªå®šç¾©ä¸»å ´æ™¯ã€‚è¦é¸æ“‡ä¸€å€‹å ´æ™¯å—Žï¼Ÿ\n" -"ç¨å¾Œå¯åœ¨ã€Œæ‡‰ç”¨ç¨‹å¼ã€åˆ†é¡žä¸çš„「專案è¨å®šã€ä¿®æ”¹ã€‚" +"ç¨å¾Œå¯åœ¨ã€Œå°ˆæ¡ˆè¨å®šã€çš„ [Application] 分類ä¸ä¿®æ”¹ã€‚" #: editor/editor_node.cpp msgid "" @@ -2522,7 +2517,7 @@ msgid "" "category." msgstr "" "所é¸çš„å ´æ™¯ã€Œ%sã€ä¸å˜åœ¨ï¼Œæ˜¯å¦è¦é¸æ“‡ä¸€å€‹æœ‰æ•ˆçš„å ´æ™¯ï¼Ÿ\n" -"ç¨å¾Œå¯åœ¨ã€Œæ‡‰ç”¨ç¨‹å¼ã€åˆ†é¡žä¸çš„「專案è¨å®šã€ä¸ä¿®æ”¹ã€‚" +"ç¨å¾Œå¯åœ¨ã€Œå°ˆæ¡ˆè¨å®šã€çš„ [Application] 分類ä¸ä¿®æ”¹ã€‚" #: editor/editor_node.cpp msgid "" @@ -2530,8 +2525,8 @@ msgid "" "You can change it later in \"Project Settings\" under the 'application' " "category." msgstr "" -"所é¸çš„å ´æ™¯ã€Œ%sã€ä¸æ˜¯å ´æ™¯æª”案,是å¦è¦é¸æ“‡å¦ä¸€å€‹æœ‰æ•ˆçš„å ´æ™¯ï¼Ÿ\n" -"ç¨å¾Œå¯åœ¨ã€Œæ‡‰ç”¨ç¨‹å¼ã€åˆ†é¡žä¸çš„「專案è¨å®šã€ä¸ä¿®æ”¹ã€‚" +"所é¸çš„å ´æ™¯ã€Œ%sã€ä¸¦éžå ´æ™¯æª”案,是å¦è¦é¸æ“‡å¦ä¸€å€‹æœ‰æ•ˆçš„å ´æ™¯ï¼Ÿ\n" +"ç¨å¾Œå¯åœ¨ã€Œå°ˆæ¡ˆè¨å®šã€ä¸çš„ [Application] ä¸ä¿®æ”¹ã€‚" #: editor/editor_node.cpp msgid "Save Layout" @@ -2589,7 +2584,7 @@ msgstr "還有 %d 個資料夾" #: editor/editor_node.cpp msgid "%d more files" -msgstr "還有 %d 個檔案" +msgstr "其他 %d 個檔案" #: editor/editor_node.cpp msgid "Dock Position" @@ -2759,10 +2754,10 @@ msgid "" "On Android, deploy will use the USB cable for faster performance. This " "option speeds up testing for games with a large footprint." msgstr "" -"當該é¸é …啟用後,匯出或部署將會產生最å°åŒ–çš„å¯åŸ·è¡Œæª”。\n" -"檔案系統將由這個編輯器在網路上æ供。\n" -"Android å¹³å°ä¸Šï¼Œéƒ¨ç½²éœ€è¦ä½¿ç”¨ USB 線以ç²å¾—更快速的效能。該é¸é …å°æ–¼å¤§åž‹éŠæˆ²èƒ½åŠ " -"速測試。" +"啟用該é¸é …後,匯出或部署是會產生最å°å¯åŸ·è¡Œæª”。\n" +"專案之檔案系統將由本編輯器以網路æ供。\n" +"部署至 Android å¹³å°éœ€ä½¿ç”¨ USB 線以ç²å¾—更快速的效能。該é¸é …å°æ–¼å¤§åž‹éŠæˆ²èƒ½åŠ 速" +"測試。" #: editor/editor_node.cpp msgid "Visible Collision Shapes" @@ -2772,7 +2767,7 @@ msgstr "顯示碰撞å€åŸŸ" msgid "" "Collision shapes and raycast nodes (for 2D and 3D) will be visible on the " "running game if this option is turned on." -msgstr "該é¸é …開啟後,執行éŠæˆ²æ™‚å°‡å¯çœ‹è¦‹ç¢°æ’žå€åŸŸèˆ‡ï¼ˆ2D 或 3D 的)射線節點。" +msgstr "é–‹å•Ÿé¸é …後,執行éŠæˆ²æ™‚å°‡å¯çœ‹è¦‹ç¢°æ’žå€åŸŸèˆ‡ï¼ˆ2D 或 3D 的)射線節點。" #: editor/editor_node.cpp msgid "Visible Navigation" @@ -2782,7 +2777,7 @@ msgstr "顯示導航" msgid "" "Navigation meshes and polygons will be visible on the running game if this " "option is turned on." -msgstr "該é¸é …開啟後,執行éŠæˆ²æ™‚å°‡å¯çœ‹è¦‹å°Žèˆªç¶²æ ¼ (mesh) 與多邊形。" +msgstr "開啟該é¸é …後,執行éŠæˆ²æ™‚å°‡å¯çœ‹è¦‹å°Žèˆªç¶²æ ¼ (mesh) 與多邊形。" #: editor/editor_node.cpp msgid "Sync Scene Changes" @@ -2809,7 +2804,7 @@ msgid "" "When used remotely on a device, this is more efficient with network " "filesystem." msgstr "" -"當開啟該é¸é …後,ä¿å˜çš„腳本都將在執行ä¸çš„éŠæˆ²é‡æ–°è¼‰å…¥ã€‚\n" +"開啟該é¸é …後,ä¿å˜ä¹‹è…³æœ¬éƒ½å°‡æ–¼åŸ·è¡Œä¸çš„éŠæˆ²é‡æ–°è¼‰å…¥ã€‚\n" "若在é 端è£ç½®ä¸Šä½¿ç”¨ï¼Œå¯ä½¿ç”¨ç¶²è·¯æª”案系統 NFS 以ç²å¾—最佳效能。" #: editor/editor_node.cpp editor/script_create_dialog.cpp @@ -2842,7 +2837,7 @@ msgstr "é–‹å•Ÿï¼é—œé–‰ç³»çµ±ä¸»æŽ§å°" #: editor/editor_node.cpp msgid "Open Editor Data/Settings Folder" -msgstr "開啟「編輯器資料ï¼ç·¨è¼¯å™¨è¨å®šã€è³‡æ–™å¤¾" +msgstr "é–‹å•Ÿ 編輯器資料ï¼ç·¨è¼¯å™¨è¨å®š 資料夾" #: editor/editor_node.cpp msgid "Open Editor Data Folder" @@ -2997,12 +2992,12 @@ msgid "" "the \"Use Custom Build\" option should be enabled in the Android export " "preset." msgstr "" -"將通éŽåœ¨ã€Œres://android/buildã€ä¸å®‰è£åŽŸå§‹æ¨£æ¿ä»¥ç‚ºè©²é …ç›®è¨å®šè‡ªå®š Android 建構" -"樣æ¿ã€‚\n" -"輸出時å¯ä»¥å¥—用修改並建構自定 APK(如新增模組ã€ä¿®æ”¹ AndroidManifest.xml …" +"將於「res://android/buildã€å®‰è£åŽŸå§‹æ¨£æ¿ä»¥ç‚ºè©²é …ç›®è¨å®šè‡ªå®š Android 建構樣" +"æ¿ã€‚\n" +"輸出時å¯å¥—用修改並建構自定 APK(如新增模組ã€ä¿®æ”¹ AndroidManifest.xml …" "ç‰ï¼‰ã€‚\n" -"請注æ„,若è¦ä½¿ç”¨è‡ªå®šå»ºæ§‹è€Œéžä½¿ç”¨é 先建構好的 APK,請啟用 Android 匯出 Preset " -"ä¸çš„「使用自定建構ã€é¸é …。" +"請注æ„,若è¦ä½¿ç”¨è‡ªå®šå»ºæ§‹è€Œéžä½¿ç”¨é 先建構之 APK,請啟用 Android 匯出é è¨è¨å®šä¸" +"çš„ [Use Custom Build] é¸é …。" #: editor/editor_node.cpp msgid "" @@ -3145,7 +3140,7 @@ msgstr "全部" #: editor/editor_profiler.cpp msgid "Self" -msgstr "僅自己" +msgstr "自身" #: editor/editor_profiler.cpp msgid "Frame #:" @@ -3198,7 +3193,7 @@ msgid "" "Can't create a ViewportTexture on resources saved as a file.\n" "Resource needs to belong to a scene." msgstr "" -"無法為è¦ä¿å˜ç‚ºæª”案的資æºå»ºç«‹æª¢è¦–å€ç´‹ç† (ViewportTexture)。\n" +"無法為欲ä¿å˜ç‚ºæª”案之資æºå»ºç«‹ ViewportTexture。\n" "資æºå¿…é ˆå±¬æ–¼ä¸€å€‹å ´æ™¯ã€‚" #: editor/editor_properties.cpp @@ -3209,11 +3204,11 @@ msgid "" "containing it up to a node)." msgstr "" "無法為該資æºå»ºç«‹æª¢è¦–å€ç´‹ç† (ViewportTexture)ï¼Œå› å…¶æœªè¨å®šå°æ‡‰çš„æœ¬åœ°å ´æ™¯ã€‚\n" -"請開啟其(與其至節點的所有資æºï¼‰çš„ã€Œæœ¬åœ°åŒ–å ´æ™¯ã€å±¬æ€§ã€‚" +"請開啟其(與其至節點的所有資æºï¼‰ã€ŒLocal to Sceneã€å±¬æ€§ã€‚" #: editor/editor_properties.cpp editor/property_editor.cpp msgid "Pick a Viewport" -msgstr "é¸æ“‡æª¢è¦–å€" +msgstr "é¸æ“‡ Viewport" #: editor/editor_properties.cpp editor/property_editor.cpp msgid "New Script" @@ -3247,11 +3242,11 @@ msgstr "貼上" #: editor/editor_properties.cpp editor/property_editor.cpp msgid "Convert To %s" -msgstr "轉æ›æˆ %s" +msgstr "轉æ›ç‚º %s" #: editor/editor_properties.cpp editor/property_editor.cpp msgid "Selected node is not a Viewport!" -msgstr "所é¸ç¯€é»žä¸æ˜¯æª¢è¦–å€ (Viewport)ï¼" +msgstr "所é¸ç¯€é»žä¸¦éž Viewportï¼" #: editor/editor_properties_array_dict.cpp msgid "Size: " @@ -3268,7 +3263,7 @@ msgstr "ç§»é™¤é …ç›®" #: editor/editor_properties_array_dict.cpp msgid "New Key:" -msgstr "新增éµå€¼ï¼š" +msgstr "新增索引éµï¼š" #: editor/editor_properties_array_dict.cpp msgid "New Value:" @@ -3276,15 +3271,15 @@ msgstr "新增數值:" #: editor/editor_properties_array_dict.cpp msgid "Add Key/Value Pair" -msgstr "新增éµï¼å€¼é…å°" +msgstr "新增索引éµï¼å€¼çµ„" #: editor/editor_run_native.cpp msgid "" "No runnable export preset found for this platform.\n" "Please add a runnable preset in the export menu." msgstr "" -"該平å°æ²’有å¯åŸ·è¡Œçš„匯出 Preset。\n" -"請在匯出é¸å–®ä¸æ–°å¢žä¸€å€‹å¯åŸ·è¡Œçš„ Preset。" +"該平å°æ²’有å¯åŸ·è¡Œçš„匯出é è¨è¨å®šã€‚\n" +"請在匯出é¸å–®ä¸æ–°å¢žä¸€å€‹å¯åŸ·è¡Œçš„é è¨è¨å®šã€‚" #: editor/editor_run_script.cpp msgid "Write your logic in the _run() method." @@ -3300,7 +3295,7 @@ msgstr "無法實體化腳本:" #: editor/editor_run_script.cpp msgid "Did you forget the 'tool' keyword?" -msgstr "是å¦éºæ¼ã€Œtoolã€é—œéµå—?" +msgstr "是å¦æœªåŠ 上「toolã€é—œéµå—?" #: editor/editor_run_script.cpp msgid "Couldn't run script:" @@ -3308,7 +3303,7 @@ msgstr "無法執行腳本:" #: editor/editor_run_script.cpp msgid "Did you forget the '_run' method?" -msgstr "是å¦éºæ¼äº†ã€Œ_runã€æ–¹æ³•ï¼Ÿ" +msgstr "是å¦æœªæ–°å¢žã€Œ_runã€æ–¹æ³•ï¼Ÿ" #: editor/editor_spin_slider.cpp msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes." @@ -3403,7 +3398,7 @@ msgstr "解æžé¡åƒåˆ—表的 JSON æ™‚ç™¼ç”ŸéŒ¯èª¤ã€‚è«‹å›žå ±æ¤å•é¡Œï¼" msgid "" "No download links found for this version. Direct download is only available " "for official releases." -msgstr "為找到該版本的下載éˆæŽ¥ã€‚直接下載僅é©ç”¨æ–¼æ£å¼ç‰ˆæœ¬ã€‚" +msgstr "未找到該版本的下載éˆæŽ¥ã€‚直接下載僅é©ç”¨æ–¼æ£å¼ç™¼è¡Œç‰ˆæœ¬ã€‚" #: editor/export_template_manager.cpp #: editor/plugins/asset_library_editor_plugin.cpp @@ -3446,8 +3441,8 @@ msgid "" "Templates installation failed.\n" "The problematic templates archives can be found at '%s'." msgstr "" -"未找到樣æ¿å®‰è£ã€‚\n" -"有å•é¡Œçš„樣æ¿æª”案å˜æ”¾æ–¼ã€Œ%sã€ã€‚" +"樣æ¿å®‰è£å¤±æ•—。\n" +"發生å•é¡Œä¹‹æ¨£æ¿æª”案å˜æ”¾æ–¼ã€Œ%sã€ã€‚" #: editor/export_template_manager.cpp msgid "Error requesting URL:" @@ -3573,7 +3568,7 @@ msgstr "未æä¾›å稱。" #: editor/filesystem_dock.cpp msgid "Provided name contains invalid characters." -msgstr "æ供的å稱包å«äº†ç„¡æ•ˆçš„å—元。" +msgstr "æ供的å稱包å«ç„¡æ•ˆå—元。" #: editor/filesystem_dock.cpp msgid "A file or folder with this name already exists." @@ -3581,7 +3576,7 @@ msgstr "已有相åŒå稱的檔案或資料夾å˜åœ¨ã€‚" #: editor/filesystem_dock.cpp msgid "Name contains invalid characters." -msgstr "å稱包å«äº†ç„¡æ•ˆçš„å—元。" +msgstr "å稱包å«ç„¡æ•ˆå—元。" #: editor/filesystem_dock.cpp msgid "Renaming file:" @@ -3891,7 +3886,7 @@ msgstr "æ£åœ¨åŸ·è¡Œè‡ªå®šè…³æœ¬..." #: editor/import/resource_importer_scene.cpp msgid "Couldn't load post-import script:" -msgstr "無法載入匯入後腳本:" +msgstr "無法載入 Post-Import 腳本:" #: editor/import/resource_importer_scene.cpp msgid "Invalid/broken script for post-import (check console):" @@ -3903,7 +3898,7 @@ msgstr "執行匯入後腳本時發生錯誤:" #: editor/import/resource_importer_scene.cpp msgid "Did you return a Node-derived object in the `post_import()` method?" -msgstr "是å¦æœ‰åœ¨ `post_import()` 方法內回傳 Node è¡ç”Ÿä¹‹ç‰©ä»¶ï¼Ÿ" +msgstr "是å¦æœ‰åœ¨ `post_import()` 方法內回傳繼承 Node 之物件?" #: editor/import/resource_importer_scene.cpp msgid "Saving..." @@ -3927,7 +3922,7 @@ msgstr "匯入為:" #: editor/import_dock.cpp msgid "Preset" -msgstr "Preset" +msgstr "é è¨è¨å®š" #: editor/import_dock.cpp msgid "Reimport" @@ -3944,7 +3939,7 @@ msgstr "修改匯入檔案的型別需è¦é‡æ–°å•Ÿå‹•ç·¨è¼¯å™¨ã€‚" #: editor/import_dock.cpp msgid "" "WARNING: Assets exist that use this resource, they may stop loading properly." -msgstr "è¦å‘Šï¼šæœ‰ç´ æ使用該資æºï¼Œå°‡æœƒç„¡æ³•æ£ç¢ºåŠ 載。" +msgstr "è¦å‘Šï¼šæœ‰ç´ æ使用該資æºï¼Œå°‡ç„¡æ³•æ£ç¢ºåŠ 載。" #: editor/inspector_dock.cpp msgid "Failed to load resource." @@ -3989,7 +3984,7 @@ msgstr "在說明ä¸é–‹å•Ÿ" #: editor/inspector_dock.cpp msgid "Create a new resource in memory and edit it." -msgstr "在記憶體ä¸å»ºç«‹ä¸€å€‹æ–°çš„資æºå編輯。" +msgstr "在記憶體ä¸å»ºç«‹æ–°è³‡æºä¸¦ç·¨è¼¯ã€‚" #: editor/inspector_dock.cpp msgid "Load an existing resource from disk and edit it." @@ -4001,11 +3996,11 @@ msgstr "ä¿å˜ç›®å‰ç·¨è¼¯çš„資æºã€‚" #: editor/inspector_dock.cpp msgid "Go to the previous edited object in history." -msgstr "在æ·å²è¨˜éŒ„ä¸è·³è‡³ä¸Šä¸€å€‹ç·¨è¼¯çš„物件。" +msgstr "跳至æ·å²è¨˜éŒ„ä¸ä¸Šä¸€å€‹ç·¨è¼¯çš„物件。" #: editor/inspector_dock.cpp msgid "Go to the next edited object in history." -msgstr "在æ·å²è¨˜éŒ„ä¸è·³è‡³ä¸‹ä¸€å€‹ç·¨è¼¯çš„物件。" +msgstr "跳至æ·å²è¨˜éŒ„ä¸ä¸‹ä¸€å€‹ç·¨è¼¯çš„物件。" #: editor/inspector_dock.cpp msgid "History of recently edited objects." @@ -4017,7 +4012,7 @@ msgstr "物件屬性。" #: editor/inspector_dock.cpp msgid "Filter properties" -msgstr "éŽæ¿¾å±¬æ€§" +msgstr "篩é¸å±¬æ€§" #: editor/inspector_dock.cpp msgid "Changes may be lost!" @@ -4207,23 +4202,23 @@ msgstr "新增三角形" #: editor/plugins/animation_blend_space_2d_editor.cpp msgid "Change BlendSpace2D Limits" -msgstr "修改混åˆç©ºé–“ 2D é™åˆ¶" +msgstr "修改 BlendSpace2D é™åˆ¶" #: editor/plugins/animation_blend_space_2d_editor.cpp msgid "Change BlendSpace2D Labels" -msgstr "修改混åˆç©ºé–“ 2D 標籤" +msgstr "修改 BlendSpace2D 標籤" #: editor/plugins/animation_blend_space_2d_editor.cpp msgid "Remove BlendSpace2D Point" -msgstr "移除混åˆç©ºé–“ 2D é ‚é»ž" +msgstr "移除 BlendSpace2D é ‚é»ž" #: editor/plugins/animation_blend_space_2d_editor.cpp msgid "Remove BlendSpace2D Triangle" -msgstr "移除混åˆç©ºé–“ 2D 三角形" +msgstr "移除 BlendSpace2D 三角形" #: editor/plugins/animation_blend_space_2d_editor.cpp msgid "BlendSpace2D does not belong to an AnimationTree node." -msgstr "æ··åˆç©ºé–“ 2D ä¸å±¬æ–¼ä»»ä½•å‹•ç•«æ¨¹ç¯€é»žã€‚" +msgstr "BlendSpace2D ä¸å±¬æ–¼ä»»ä½• AnimationTree 節點。" #: editor/plugins/animation_blend_space_2d_editor.cpp msgid "No triangles exist, so no blending can take place." @@ -4257,11 +4252,11 @@ msgstr "已更改åƒæ•¸" #: editor/plugins/animation_blend_tree_editor_plugin.cpp #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "Edit Filters" -msgstr "編輯篩é¸" +msgstr "編輯篩é¸æ¢ä»¶" #: editor/plugins/animation_blend_tree_editor_plugin.cpp msgid "Output node can't be added to the blend tree." -msgstr "輸出節點無法被新增到混åˆæ¨¹ã€‚" +msgstr "輸出節點無法被新增至混åˆæ¨¹ã€‚" #: editor/plugins/animation_blend_tree_editor_plugin.cpp msgid "Add Node to BlendTree" @@ -4302,11 +4297,11 @@ msgstr "刪除節點" #: editor/plugins/animation_blend_tree_editor_plugin.cpp msgid "Toggle Filter On/Off" -msgstr "é–‹å•Ÿï¼é—œé–‰éŽæ¿¾" +msgstr "é–‹å•Ÿï¼é—œé–‰ç¯©é¸" #: editor/plugins/animation_blend_tree_editor_plugin.cpp msgid "Change Filter" -msgstr "更改éŽæ¿¾" +msgstr "更改篩é¸æ¢ä»¶" #: editor/plugins/animation_blend_tree_editor_plugin.cpp msgid "No animation player set, so unable to retrieve track names." @@ -4352,7 +4347,7 @@ msgstr "編輯已篩é¸çš„軌é“:" #: editor/plugins/animation_blend_tree_editor_plugin.cpp msgid "Enable Filtering" -msgstr "啟用篩é¸" +msgstr "啟用æ¢ä»¶ç¯©é¸" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Toggle Autoplay" @@ -4415,7 +4410,7 @@ msgstr "ç„¡å‹•ç•«å¯è¤‡è£½ï¼" #: editor/plugins/animation_player_editor_plugin.cpp msgid "No animation resource on clipboard!" -msgstr "剪貼簿ä¸æ²’有動畫資æºï¼" +msgstr "剪貼簿ä¸ç„¡å‹•ç•«è³‡æºï¼" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Pasted Animation" @@ -4483,11 +4478,11 @@ msgstr "載入後自動æ’放" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Enable Onion Skinning" -msgstr "啟用洋蔥皮化 (Onion Skinning)" +msgstr "啟用æ圖紙" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Onion Skinning Options" -msgstr "洋蔥皮化é¸é …" +msgstr "æ圖紙é¸é …" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Directions" @@ -4531,7 +4526,7 @@ msgstr "åŒ…å« Gizmo (3D)" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Pin AnimationPlayer" -msgstr "固定動畫æ’放器" +msgstr "固定 AnimationPlayer" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Create New Animation" @@ -4641,7 +4636,7 @@ msgstr "移除所é¸çš„ç¯€é»žæˆ–è½‰å ´ã€‚" #: editor/plugins/animation_state_machine_editor.cpp msgid "Toggle autoplay this animation on start, restart or seek to zero." -msgstr "é–‹å•Ÿï¼é—œé–‰è©²å‹•ç•«åœ¨é–‹å§‹ã€é‡æ–°å•Ÿå‹•æˆ–尋覓至 0 時的自動æ’放。" +msgstr "é–‹å•Ÿï¼é—œé–‰è‡ªå‹•æ’放動畫於開始ã€é‡æ–°å•Ÿå‹•æˆ–æœå°‹è‡³ 0 時。" #: editor/plugins/animation_state_machine_editor.cpp msgid "Set the end animation. This is useful for sub-transitions." @@ -4716,7 +4711,7 @@ msgstr "æ··åˆ 1:" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "X-Fade Time (s):" -msgstr "交å‰æ·¡åŒ– (X-Fade) 時間(秒):" +msgstr "淡入與淡出時間(秒):" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "Current:" @@ -4750,39 +4745,39 @@ msgstr "無效的動畫樹。" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "Animation Node" -msgstr "動畫節點" +msgstr "Animation 節點" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "OneShot Node" -msgstr "å–®é …ç¯€é»ž" +msgstr "OneShot 節點" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "Mix Node" -msgstr "æ··åˆç¯€é»ž" +msgstr "Mix 節點" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "Blend2 Node" -msgstr "æ··åˆ 2 節點" +msgstr "Blend2 節點" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "Blend3 Node" -msgstr "æ··åˆ 3 節點" +msgstr "Blend3 節點" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "Blend4 Node" -msgstr "æ··åˆ 4 節點" +msgstr "Blend4 節點" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "TimeScale Node" -msgstr "時間縮放節點" +msgstr "TimeScale 節點" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "TimeSeek Node" -msgstr "時間尋覓節點" +msgstr "TimeSeek 節點" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "Transition Node" -msgstr "è½‰å ´ç¯€é»ž" +msgstr "Transition 節點" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "Import Animations..." @@ -4790,11 +4785,11 @@ msgstr "匯入動畫…" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "Edit Node Filters" -msgstr "編輯節點éŽæ¿¾" +msgstr "編輯節點篩é¸æ¢ä»¶" #: editor/plugins/animation_tree_player_editor_plugin.cpp msgid "Filters..." -msgstr "éŽæ¿¾..." +msgstr "篩é¸..." #: editor/plugins/asset_library_editor_plugin.cpp msgid "Contents:" @@ -4858,7 +4853,7 @@ msgstr "下載雜湊錯誤,檔案å¯èƒ½è¢«ç¯¡æ”¹ã€‚" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Expected:" -msgstr "é 計:" +msgstr "應為:" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Got:" @@ -5011,7 +5006,8 @@ msgstr "" msgid "" "No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake " "Light' flag is on." -msgstr "æ²’æœ‰å¯ Bake çš„ç¶²æ ¼ã€‚è«‹ç¢ºä¿ç¶²æ ¼åŒ…å« UV2 通é“並已開啟「Bake 光照ã€æ——標。" +msgstr "" +"ç„¡å¯è£½ä½œä¹‹ç¶²æ ¼ã€‚請確ä¿é€™äº›ç¶²æ ¼åŒ…å« UV2 通é“並已開啟「Bake Lightã€æ——標。" #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "Failed creating lightmap images, make sure path is writable." @@ -5019,7 +5015,7 @@ msgstr "建立光照圖失敗,請確ä¿è©²è·¯å¾‘å¯å¯«å…¥ã€‚" #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "Bake Lightmaps" -msgstr "Bake 光照圖" +msgstr "建立光照圖" #: editor/plugins/camera_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp editor/rename_dialog.cpp @@ -5092,7 +5088,7 @@ msgstr "移動軸心" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Rotate CanvasItem" -msgstr "æ—‹è½‰ç•«å¸ƒé …ç›®" +msgstr "旋轉 CanvasItem" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Move anchor" @@ -5100,31 +5096,31 @@ msgstr "移動錨點" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Resize CanvasItem" -msgstr "èª¿æ•´ç•«å¸ƒé …ç›®å¤§å°" +msgstr "調整 CanvasItem 大å°" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Scale CanvasItem" -msgstr "ç¸®æ”¾ç•«å¸ƒé …ç›®" +msgstr "縮放 CanvasItem" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Move CanvasItem" -msgstr "ç§»å‹•ç•«å¸ƒé …ç›®" +msgstr "移動 CanvasItem" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "" "Children of containers have their anchors and margins values overridden by " "their parent." -msgstr "容器åé …ç›®çš„éŒ¨é»žèˆ‡å¤–é‚Šè· (margin) 值被其æ¯é …目複寫。" +msgstr "容器åé …ç›®çš„éŒ¨é»žèˆ‡å¤–é‚Šè·å€¼éå…¶æ¯é …目複寫。" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Presets for the anchors and margins values of a Control node." -msgstr "控制節點的錨點與外邊è·çš„ Preset。" +msgstr "控制節點的錨點與外邊è·ä¹‹é è¨è¨å®šã€‚" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "" "When active, moving Control nodes changes their anchors instead of their " "margins." -msgstr "啟用時,移動控制節點將修改錨點而éžå¤–é‚Šè·ã€‚" +msgstr "啟用後,移動控制節點將修改錨點而éžå¤–é‚Šè·ã€‚" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Top Left" @@ -5164,27 +5160,27 @@ msgstr "ä¸å¤®" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Left Wide" -msgstr "左延長" +msgstr "左延展" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Top Wide" -msgstr "上延長" +msgstr "上延展" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Right Wide" -msgstr "å³å»¶é•·" +msgstr "å³å»¶å±•" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Bottom Wide" -msgstr "下延長" +msgstr "下延展" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "VCenter Wide" -msgstr "åž‚ç›´ä¸å¤®å»¶é•·" +msgstr "åž‚ç›´ä¸å¤®å»¶å±•" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "HCenter Wide" -msgstr "æ°´å¹³ä¸å¤®å»¶é•·" +msgstr "æ°´å¹³ä¸å¤®å»¶å±•" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Full Rect" @@ -5212,7 +5208,7 @@ msgid "" "Game Camera Override\n" "Overrides game camera with editor viewport camera." msgstr "" -"éŠæˆ²ç›¸æ©Ÿè¦†è“‹\n" +"éŠæˆ²ç›¸æ©Ÿè¤‡å¯«\n" "以檢視å€ç›¸æ©Ÿå–代éŠæˆ²ç›¸æ©Ÿã€‚" #: editor/plugins/canvas_item_editor_plugin.cpp @@ -5221,7 +5217,7 @@ msgid "" "Game Camera Override\n" "No game instance running." msgstr "" -"éŠæˆ²ç›¸æ©Ÿè¦†è“‹\n" +"éŠæˆ²ç›¸æ©Ÿè¤‡å¯«\n" "ç„¡æ£åœ¨åŸ·è¡Œçš„éŠæˆ²å¯¦é«”。" #: editor/plugins/canvas_item_editor_plugin.cpp @@ -5254,7 +5250,7 @@ msgstr "清除åƒè€ƒç·š" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Create Custom Bone(s) from Node(s)" -msgstr "å節點建立自定骨骼" +msgstr "自節點建立自定骨骼" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Clear Bones" @@ -5272,7 +5268,7 @@ msgstr "清除 IK éˆ" msgid "" "Warning: Children of a container get their position and size determined only " "by their parent." -msgstr "è¦å‘Šï¼šå®¹å™¨çš„åé …ç›®çš„ä½ç½®èˆ‡å¤§å°æœ‰å…¶æ¯é …目決定。" +msgstr "è¦å‘Šï¼šå®¹å™¨åé …ç›®ä¹‹ä½ç½®èˆ‡å¤§å°ç”±å…¶æ¯é …目決定。" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/texture_region_editor_plugin.cpp @@ -5510,8 +5506,8 @@ msgid "" "Keys are only added to existing tracks, no new tracks will be created.\n" "Keys must be inserted manually for the first time." msgstr "" -"檔物件被轉æ›ã€æ—‹è½‰ã€æˆ–(基於é®ç½©ï¼‰ç¸®æ”¾æ™‚自動æ’入關éµå½±æ ¼ã€‚\n" -"é—œéµå½±æ ¼åªæœƒè¢«æ–°å¢žè‡³ç¾å˜çš„軌é“,將ä¸æœƒå»ºç«‹æ–°çš„軌é“。\n" +"當物件被轉æ›ã€æ—‹è½‰ 或(基於é®ç½©ï¼‰ç¸®æ”¾æ™‚自動æ’入關éµå½±æ ¼ã€‚\n" +"é—œéµå½±æ ¼åªæœƒè¢«æ–°å¢žè‡³ç¾æœ‰è»Œé“,ä¸æœƒå»ºç«‹æ–°è»Œé“。\n" "ç¬¬ä¸€æ¬¡å¿…é ˆå…ˆæ‰‹å‹•æ’入關éµå½±æ ¼ã€‚" #: editor/plugins/canvas_item_editor_plugin.cpp @@ -5524,7 +5520,7 @@ msgstr "å‹•ç•«é—œéµå½±æ ¼èˆ‡å§¿å‹¢é¸é …" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Insert Key (Existing Tracks)" -msgstr "æ’入關éµå½±æ ¼ï¼ˆåœ¨ç¾æœ‰è»Œé“)" +msgstr "æ’入關éµå½±æ ¼ï¼ˆæ–¼ç¾æœ‰è»Œé“)" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Copy Pose" @@ -5582,7 +5578,7 @@ msgstr "" #: editor/plugins/collision_polygon_editor_plugin.cpp msgid "Create Polygon3D" -msgstr "建立多邊形 3D" +msgstr "建立 Polygon3D" #: editor/plugins/collision_polygon_editor_plugin.cpp msgid "Edit Poly" @@ -5678,11 +5674,11 @@ msgstr "Flat 1" #: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp msgid "Ease In" -msgstr "ç·©å…¥" +msgstr "緩慢移入" #: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp msgid "Ease Out" -msgstr "緩出" +msgstr "緩慢移出" #: editor/plugins/curve_editor_plugin.cpp msgid "Smoothstep" @@ -5698,7 +5694,7 @@ msgstr "修改曲線切線" #: editor/plugins/curve_editor_plugin.cpp msgid "Load Curve Preset" -msgstr "åŠ è¼‰æ›²ç·š Preset" +msgstr "åŠ è¼‰æ›²ç·šé è¨è¨å®š" #: editor/plugins/curve_editor_plugin.cpp msgid "Add Point" @@ -5718,7 +5714,7 @@ msgstr "å³ç·šæ€§" #: editor/plugins/curve_editor_plugin.cpp msgid "Load Preset" -msgstr "載入 Preset" +msgstr "載入é è¨è¨å®š" #: editor/plugins/curve_editor_plugin.cpp msgid "Remove Curve Point" @@ -5738,7 +5734,7 @@ msgstr "å³éµé»žæ“Šä»¥æ–°å¢žæŽ§åˆ¶é»ž" #: editor/plugins/gi_probe_editor_plugin.cpp msgid "Bake GI Probe" -msgstr "Bake GI 探é‡" +msgstr "製作 GI 探查" #: editor/plugins/gradient_editor_plugin.cpp msgid "Gradient Edited" @@ -5810,7 +5806,7 @@ msgstr "å»ºç«‹å°Žèˆªç¶²æ ¼" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Contained Mesh is not of type ArrayMesh." -msgstr "包å«çš„ç¶²æ ¼çš„åž‹åˆ¥ä¸æ˜¯é™£åˆ—ç¶²æ ¼ (ArrayMesh)。" +msgstr "包å«ä¹‹ Mesh ä¸¦éž ArrayMesh 型別。" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "UV Unwrap failed, mesh may not be manifold?" @@ -5818,7 +5814,7 @@ msgstr "UV å±•é–‹å¤±æ•—ï¼Œè©²ç¶²æ ¼å¯èƒ½ä¸¦éžæµå½¢ï¼Ÿ" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "No mesh to debug." -msgstr "沒有å¯é™¤éŒ¯çš„ç¶²æ ¼ã€‚" +msgstr "沒有å¯é€²è¡ŒåµéŒ¯ä¹‹ç¶²æ ¼ã€‚" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Model has no UV in this layer" @@ -5826,15 +5822,15 @@ msgstr "模型在該圖層上無 UV" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "MeshInstance lacks a Mesh!" -msgstr "ç¶²æ ¼å¯¦é«” (MeshInstance) 缺ä¹ç¶²æ ¼ï¼" +msgstr "MeshInstance æœªåŒ…å« Meshï¼" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Mesh has not surface to create outlines from!" -msgstr "ç¶²æ ¼æœªåŒ…å«å¯å»ºç«‹è¼ªå»“的表é¢ï¼" +msgstr "Mesh 未包å«å¯å»ºç«‹è¼ªå»“的表é¢ï¼" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Mesh primitive type is not PRIMITIVE_TRIANGLES!" -msgstr "ç¶²æ ¼çš„åŽŸå§‹é¡žåž‹ä¸æ˜¯ PRIMITIVE_TRIANGLESï¼" +msgstr "Mesh çš„åŽŸå§‹é¡žåž‹ä¸¦éž PRIMITIVE_TRIANGLESï¼" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Could not create outline!" @@ -5858,8 +5854,8 @@ msgid "" "automatically.\n" "This is the most accurate (but slowest) option for collision detection." msgstr "" -"建立éœæ…‹å½¢é«” (StaticBody) 並自動指派一個基於多邊形的碰撞形體。\n" -"å°æ–¼ç¢°æ’žåµæ¸¬ï¼Œé€™æ˜¯æœ€ç²¾ç¢ºï¼ˆä½†æœ€æ…¢ï¼‰çš„é¸é …。" +"建立 StaticBody 並自動指派一個基於多邊形的碰撞形體。\n" +"å°æ–¼ç¢°æ’žåµæ¸¬ï¼Œè©²é¸é …為最精確(但最慢)的é¸é …。" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Create Trimesh Collision Sibling" @@ -5871,7 +5867,7 @@ msgid "" "This is the most accurate (but slowest) option for collision detection." msgstr "" "建立基於多邊形的碰撞形狀。\n" -"å°æ–¼ç¢°æ’žåµæ¸¬ï¼Œé€™æ˜¯æœ€ç²¾ç¢ºï¼ˆä½†æœ€æ…¢ï¼‰çš„é¸é …。" +"å°æ–¼ç¢°æ’žåµæ¸¬ï¼Œè©²é¸é …為最精確(但最慢)的é¸é …。" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Create Single Convex Collision Sibling" @@ -5883,7 +5879,7 @@ msgid "" "This is the fastest (but least accurate) option for collision detection." msgstr "" "建立單一凸é¢ç¢°æ’žå½¢ç‹€ã€‚\n" -"å°æ–¼ç¢°æ’žåµæ¸¬ï¼Œé€™æ˜¯æœ€å¿«ï¼ˆä½†æœ€ä¸ç²¾ç¢ºï¼‰çš„é¸é …。" +"å°æ–¼ç¢°æ’žåµæ¸¬ï¼Œè©²é¸é …為最快(但最ä¸ç²¾ç¢ºï¼‰çš„é¸é …。" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Create Multiple Convex Collision Siblings" @@ -5949,7 +5945,7 @@ msgstr "" #: editor/plugins/mesh_library_editor_plugin.cpp msgid "Mesh Library" -msgstr "ç¶²æ ¼åº« (Mesh Library)" +msgstr "ç¶²æ ¼åº«" #: editor/plugins/mesh_library_editor_plugin.cpp #: editor/plugins/theme_editor_plugin.cpp @@ -5970,11 +5966,11 @@ msgstr "è‡ªå ´æ™¯æ›´æ–°" #: editor/plugins/multimesh_editor_plugin.cpp msgid "No mesh source specified (and no MultiMesh set in node)." -msgstr "æœªæŒ‡å®šç¶²æ ¼ä¾†æºï¼ˆä¸”節點ä¸æ²’æœ‰å¤šç¶²æ ¼é›† (MultiMesh Set))。" +msgstr "æœªæŒ‡å®šç¶²æ ¼ä¾†æºï¼ˆä¸”節點ä¸æ²’有 MultiMesh 集)。" #: editor/plugins/multimesh_editor_plugin.cpp msgid "No mesh source specified (and MultiMesh contains no Mesh)." -msgstr "æœªæŒ‡å®šç¶²æ ¼ä¾†æºï¼ˆä¸”å¤šç¶²æ ¼ (MultiMesh) 未包å«ç¶²æ ¼ (Mesh))。" +msgstr "æœªæŒ‡å®šç¶²æ ¼ä¾†æºï¼ˆä¸” MultiMesh æœªåŒ…å« Mesh)。" #: editor/plugins/multimesh_editor_plugin.cpp msgid "Mesh source is invalid (invalid path)." @@ -5982,11 +5978,11 @@ msgstr "ç¶²æ ¼ä¾†æºç„¡æ•ˆï¼ˆç„¡æ•ˆçš„路徑)。" #: editor/plugins/multimesh_editor_plugin.cpp msgid "Mesh source is invalid (not a MeshInstance)." -msgstr "ç¶²æ ¼ä¾†æºç„¡æ•ˆï¼ˆä¸æ˜¯ç¶²æ ¼å¯¦é«” (MeshInstance))。" +msgstr "ç¶²æ ¼ä¾†æºç„¡æ•ˆï¼ˆéž MeshInstance)。" #: editor/plugins/multimesh_editor_plugin.cpp msgid "Mesh source is invalid (contains no Mesh resource)." -msgstr "ç¶²æ ¼ä¾†æºç„¡æ•ˆï¼ˆæœªåŒ…å«ç¶²æ ¼ (Mesh) 資æºï¼‰ã€‚" +msgstr "ç¶²æ ¼ä¾†æºç„¡æ•ˆï¼ˆæœªåŒ…å« Mesh 資æºï¼‰ã€‚" #: editor/plugins/multimesh_editor_plugin.cpp msgid "No surface source specified." @@ -6010,7 +6006,7 @@ msgstr "é¸æ“‡ä¾†æºç¶²æ ¼ï¼š" #: editor/plugins/multimesh_editor_plugin.cpp msgid "Select a Target Surface:" -msgstr "é¸æ“‡ç›®æ¨™ç¶²æ ¼ï¼š" +msgstr "é¸æ“‡ç›®æ¨™è¡¨é¢ï¼š" #: editor/plugins/multimesh_editor_plugin.cpp msgid "Populate Surface" @@ -6018,7 +6014,7 @@ msgstr "填充表é¢" #: editor/plugins/multimesh_editor_plugin.cpp msgid "Populate MultiMesh" -msgstr "å¡«å……å¤šç¶²æ ¼ (MultiMesh)" +msgstr "å¡«å…… MultiMesh" #: editor/plugins/multimesh_editor_plugin.cpp msgid "Target Surface:" @@ -6080,7 +6076,7 @@ msgstr "產生矩形å¯è¦‹æ€§" #: editor/plugins/particles_2d_editor_plugin.cpp msgid "Can only set point into a ParticlesMaterial process material" -msgstr "僅é™æŒ‡å‘ç²’åæ料的處ç†ææ–™ (ParticlesMaterial Process Material)" +msgstr "僅å¯å°‡ç‚º ParticlesMaterial 處ç†ææ–™è¨å®šé»ž" #: editor/plugins/particles_2d_editor_plugin.cpp #: editor/plugins/particles_editor_plugin.cpp @@ -6097,7 +6093,7 @@ msgstr "幾何體未包å«ä»»ä½•é¢ã€‚" #: editor/plugins/particles_editor_plugin.cpp msgid "\"%s\" doesn't inherit from Spatial." -msgstr "「%sã€éžè‡ª Spatial 繼承。" +msgstr "「%sã€éžç¹¼æ‰¿è‡ª Spatial。" #: editor/plugins/particles_editor_plugin.cpp msgid "\"%s\" doesn't contain geometry." @@ -6133,7 +6129,7 @@ msgstr "發射æºï¼š " #: editor/plugins/particles_editor_plugin.cpp msgid "A processor material of type 'ParticlesMaterial' is required." -msgstr "需è¦ã€Œç²’åææ–™ (ParticlesMaterial)ã€åž‹åˆ¥çš„處ç†å™¨æ料。" +msgstr "需「ParticlesMaterialã€åž‹åˆ¥çš„處ç†å™¨æ料。" #: editor/plugins/particles_editor_plugin.cpp msgid "Generating AABB" @@ -6232,12 +6228,12 @@ msgstr "é¸é …" #: editor/plugins/path_2d_editor_plugin.cpp #: editor/plugins/path_editor_plugin.cpp msgid "Mirror Handle Angles" -msgstr "é¡åƒæ‰‹æŸ„角度" +msgstr "é¡åƒæŽ§é»žè§’度" #: editor/plugins/path_2d_editor_plugin.cpp #: editor/plugins/path_editor_plugin.cpp msgid "Mirror Handle Lengths" -msgstr "é¡åƒæ‰‹æŸ„長度" +msgstr "é¡åƒæŽ§é»žé•·åº¦" #: editor/plugins/path_editor_plugin.cpp msgid "Curve Point #" @@ -6245,15 +6241,15 @@ msgstr "曲線控制點 #" #: editor/plugins/path_editor_plugin.cpp msgid "Set Curve Point Position" -msgstr "è¨å®šæ›²ç·šæŽ§åˆ¶é»žçš„ä½ç½®" +msgstr "è¨å®šæ›²ç·šæŽ§åˆ¶é»žä½ç½®" #: editor/plugins/path_editor_plugin.cpp msgid "Set Curve In Position" -msgstr "è¨å®šæ›²ç·šçš„內控制點ä½ç½®" +msgstr "è¨å®šæ›²ç·šå…§æŽ§åˆ¶é»žä½ç½®" #: editor/plugins/path_editor_plugin.cpp msgid "Set Curve Out Position" -msgstr "è¨å®šæ›²ç·šçš„外控制點ä½ç½®" +msgstr "è¨å®šæ›²ç·šå¤–控制點ä½ç½®" #: editor/plugins/path_editor_plugin.cpp msgid "Split Path" @@ -6282,7 +6278,7 @@ msgstr "移動關節" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "" "The skeleton property of the Polygon2D does not point to a Skeleton2D node" -msgstr "多邊形 2D (Polygon2D) 的骨架屬性未指å‘骨架 2D (Skeleton2D) 節點" +msgstr "Polygon2D çš„éª¨æž¶å±¬æ€§æœªæŒ‡å‘ Skeleton2D 節點" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Sync Bones" @@ -6304,7 +6300,7 @@ msgstr "建立 UV Map" msgid "" "Polygon 2D has internal vertices, so it can no longer be edited in the " "viewport." -msgstr "多邊形 2D æœ‰å…§éƒ¨é ‚é»žï¼Œå°‡ç„¡æ³•åœ¨æª¢è¦–å€ç·¨è¼¯ã€‚" +msgstr "Polygon2D æœ‰å…§éƒ¨é ‚é»žï¼Œå°‡ç„¡æ³•åœ¨æª¢è¦–å€ç·¨è¼¯ã€‚" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Create Polygon & UV" @@ -6344,11 +6340,11 @@ msgstr "æ繪骨骼權é‡" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Open Polygon 2D UV editor." -msgstr "開啟多邊形 2D UV 編輯器。" +msgstr "Polygon2D UV 編輯器。" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Polygon 2D UV Editor" -msgstr "多邊形 2D UV 編輯器" +msgstr "Polygon2D UV 編輯器" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "UV" @@ -6396,13 +6392,13 @@ msgstr "縮放多邊形" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Create a custom polygon. Enables custom polygon rendering." -msgstr "建立自定多邊形。啟用自定多邊形算圖。" +msgstr "建立自定多邊形。啟用自定多邊形算繪。" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "" "Remove a custom polygon. If none remain, custom polygon rendering is " "disabled." -msgstr "移除自定多邊形。若無剩餘多邊形,將ç¦ç”¨è‡ªå®šå¤šé‚Šå½¢ç®—圖。" +msgstr "移除自定多邊形。若無剩餘多邊形,將ç¦ç”¨è‡ªå®šå¤šé‚Šå½¢ç®—繪。" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Paint weights with specified intensity." @@ -6520,11 +6516,11 @@ msgstr "載入資æº" #: editor/plugins/resource_preloader_editor_plugin.cpp msgid "ResourcePreloader" -msgstr "資æºé åŠ è¼‰ (ResourcePreloader)" +msgstr "ResourcePreloader" #: editor/plugins/root_motion_editor_plugin.cpp msgid "AnimationTree has no path set to an AnimationPlayer" -msgstr "動畫樹 (AnimationTree) 未è¨å®šè‡³å‹•ç•«æ’放器 (AnimationPlayer) 的路徑" +msgstr "AnimationTree 未è¨å®šè‡³ AnimationPlayer 的路徑" #: editor/plugins/root_motion_editor_plugin.cpp msgid "Path to AnimationPlayer is invalid" @@ -6540,7 +6536,7 @@ msgstr "關閉並ä¿å˜ä¿®æ”¹å—Žï¼Ÿ" #: editor/plugins/script_editor_plugin.cpp msgid "Error writing TextFile:" -msgstr "寫入文å—檔案 (TextFile) 時發生錯誤:" +msgstr "寫入 TextFile 時發生錯誤:" #: editor/plugins/script_editor_plugin.cpp msgid "Could not load file at:" @@ -6593,7 +6589,7 @@ msgstr "腳本ä¸åœ¨å·¥å…·æ¨¡å¼ä¸‹ï¼Œç„¡æ³•åŸ·è¡Œã€‚" #: editor/plugins/script_editor_plugin.cpp msgid "" "To run this script, it must inherit EditorScript and be set to tool mode." -msgstr "æ¬²åŸ·è¡Œè©²è…³æœ¬ï¼Œå…¶å¿…é ˆç¹¼æ‰¿è‡ªç·¨è¼¯å™¨è…³æœ¬ (EditorScript) 並è¨ç‚ºå·¥å…·æ¨¡å¼ã€‚" +msgstr "è©²è…³æœ¬å¿…é ˆç¹¼æ‰¿ EditorScript 並è¨ç‚ºå·¥å…·æ¨¡å¼æ‰å¯åŸ·è¡Œã€‚" #: editor/plugins/script_editor_plugin.cpp msgid "Import Theme" @@ -6627,7 +6623,7 @@ msgstr "尋找上一個" #: editor/plugins/script_editor_plugin.cpp msgid "Filter scripts" -msgstr "éŽæ¿¾è…³æœ¬" +msgstr "篩é¸è…³æœ¬" #: editor/plugins/script_editor_plugin.cpp msgid "Toggle alphabetical sorting of the method list." @@ -6635,7 +6631,7 @@ msgstr "é–‹å•Ÿï¼é—œé–‰æŒ‰ç…§å—æ¯é †åºæŽ’列方法列表。" #: editor/plugins/script_editor_plugin.cpp msgid "Filter methods" -msgstr "éŽæ¿¾æ–¹æ³•" +msgstr "篩é¸æ–¹æ³•" #: editor/plugins/script_editor_plugin.cpp msgid "Sort" @@ -6724,11 +6720,11 @@ msgstr "執行" #: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp msgid "Step Into" -msgstr "æ¥å…¥" +msgstr "é€æ¥åŸ·è¡Œ" #: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp msgid "Step Over" -msgstr "æ¥éŽ" +msgstr "ä¸é€²å…¥å‡½å¼" #: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp msgid "Break" @@ -6773,7 +6769,7 @@ msgid "" "What action should be taken?:" msgstr "" "ç£ç¢Ÿä¸çš„下列檔案已更新。\n" -"è¦åŸ·è¡Œä»€éº¼ï¼Ÿï¼š" +"è«‹é¸æ“‡æ–¼åŸ·è¡Œä¹‹æ“作:" #: editor/plugins/script_editor_plugin.cpp #: editor/plugins/shader_editor_plugin.cpp @@ -6833,7 +6829,7 @@ msgstr "åªå¯æ‹–移來自檔案系統的資æºã€‚" #: editor/plugins/script_text_editor.cpp #: modules/visual_script/visual_script_editor.cpp msgid "Can't drop nodes because script '%s' is not used in this scene." -msgstr "無法防æ¢ç¯€é»žï¼Œç”±æ–¼è…³æœ¬ã€Œ%sã€ä¸¦æœªåœ¨è©²å ´æ™¯ä¸ä½¿ç”¨ã€‚" +msgstr "無法放置節點,由於腳本「%sã€ä¸¦æœªåœ¨è©²å ´æ™¯ä¸ä½¿ç”¨ã€‚" #: editor/plugins/script_text_editor.cpp msgid "Lookup Symbol" @@ -6901,7 +6897,7 @@ msgstr "å‘å³ç¸®æŽ’" #: editor/plugins/script_text_editor.cpp msgid "Toggle Comment" -msgstr "展開ï¼æ”¶èµ·è¨»è§£" +msgstr "註解ï¼å–消註解" #: editor/plugins/script_text_editor.cpp msgid "Fold/Unfold Line" @@ -7006,27 +7002,27 @@ msgstr "著色器" #: editor/plugins/skeleton_2d_editor_plugin.cpp msgid "This skeleton has no bones, create some children Bone2D nodes." -msgstr "æ¤éª¨æž¶æœªåŒ…å«éª¨éª¼ï¼Œè«‹å»ºç«‹ä¸€äº›å骨骼 2D (Bone2D) 節點。" +msgstr "æ¤éª¨æž¶æœªåŒ…å«éª¨éª¼ï¼Œè«‹å»ºç«‹ä¸€äº›å Bone2D 節點。" #: editor/plugins/skeleton_2d_editor_plugin.cpp msgid "Create Rest Pose from Bones" -msgstr "自骨骼建立放鬆姿勢" +msgstr "自骨骼建立éœæ¢å§¿å‹¢" #: editor/plugins/skeleton_2d_editor_plugin.cpp msgid "Set Rest Pose to Bones" -msgstr "è¨å®šæ”¾é¬†å§¿å‹¢è‡³éª¨éª¼" +msgstr "è¨å®šéœæ¢å§¿å‹¢è‡³éª¨éª¼" #: editor/plugins/skeleton_2d_editor_plugin.cpp msgid "Skeleton2D" -msgstr "骨架2D (Sekeleton2D)" +msgstr "Sekeleton2D" #: editor/plugins/skeleton_2d_editor_plugin.cpp msgid "Make Rest Pose (From Bones)" -msgstr "製作放鬆姿勢(自骨骼)" +msgstr "製作éœæ¢å§¿å‹¢ï¼ˆè‡ªéª¨éª¼ï¼‰" #: editor/plugins/skeleton_2d_editor_plugin.cpp msgid "Set Bones to Rest Pose" -msgstr "è¨å®šéª¨éª¼ç‚ºæ”¾é¬†å§¿å‹¢" +msgstr "è¨å®šéª¨éª¼ç‚ºéœæ¢å§¿å‹¢" #: editor/plugins/skeleton_editor_plugin.cpp msgid "Create physical bones" @@ -7242,7 +7238,7 @@ msgstr "效果é 覽" #: editor/plugins/spatial_editor_plugin.cpp msgid "Not available when using the GLES2 renderer." -msgstr "使用 GLES2 算圖器時無法使用。" +msgstr "使用 GLES2 轉è¯å™¨æ™‚無法使用。" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Left" @@ -7285,7 +7281,7 @@ msgid "" "Note: The FPS value displayed is the editor's framerate.\n" "It cannot be used as a reliable indication of in-game performance." msgstr "" -"注æ„:顯示的 FPS 值時編輯器的畫é¢é€ŸçŽ‡ã€‚\n" +"注æ„:顯示的 FPS 值為編輯器之畫é¢é€ŸçŽ‡ã€‚\n" "無法實際åæ˜ ç‚ºéŠæˆ²ä¸çš„效能。" #: editor/plugins/spatial_editor_plugin.cpp @@ -7496,35 +7492,35 @@ msgstr "未命åçš„ Gizmo" #: editor/plugins/sprite_editor_plugin.cpp msgid "Create Mesh2D" -msgstr "å»ºç«‹ç¶²æ ¼ 2D (Mesh2D)" +msgstr "建立 Mesh2D" #: editor/plugins/sprite_editor_plugin.cpp msgid "Mesh2D Preview" -msgstr "å»ºç«‹ç¶²æ ¼ 2D (Mesh2D) é 覽" +msgstr "建立 Mesh2D é 覽" #: editor/plugins/sprite_editor_plugin.cpp msgid "Create Polygon2D" -msgstr "建立多邊形 2D (Polygon2D)" +msgstr "建立 Polygon2D" #: editor/plugins/sprite_editor_plugin.cpp msgid "Polygon2D Preview" -msgstr "é 覽多邊形 2D (Polygon2D)" +msgstr "é 覽 Polygon2D" #: editor/plugins/sprite_editor_plugin.cpp msgid "Create CollisionPolygon2D" -msgstr "建立碰撞多邊形 2D (CollisionPolygon2D)" +msgstr "建立 CollisionPolygon2D" #: editor/plugins/sprite_editor_plugin.cpp msgid "CollisionPolygon2D Preview" -msgstr "碰撞多邊形 2D (CollisionPolygon2D) é 覽" +msgstr "碰撞 CollisionPolygon2D é 覽" #: editor/plugins/sprite_editor_plugin.cpp msgid "Create LightOccluder2D" -msgstr "建立é®å…‰ 2D (LightOccluder2D)" +msgstr "建立 LightOccluder2D" #: editor/plugins/sprite_editor_plugin.cpp msgid "LightOccluder2D Preview" -msgstr "é®å…‰ 2D (LightOccluder2D) é 覽" +msgstr "LightOccluder2D é 覽" #: editor/plugins/sprite_editor_plugin.cpp msgid "Sprite is empty!" @@ -7540,7 +7536,7 @@ msgstr "ç„¡æ•ˆçš„å¹¾ä½•åœ–å½¢ï¼Œç„¡æ³•ä»¥ç¶²æ ¼å–代。" #: editor/plugins/sprite_editor_plugin.cpp msgid "Convert to Mesh2D" -msgstr "轉æ›ç‚ºç¶²æ ¼ 2D (Mesh2D)" +msgstr "轉æ›ç‚º Mesh2D" #: editor/plugins/sprite_editor_plugin.cpp msgid "Invalid geometry, can't create polygon." @@ -7548,7 +7544,7 @@ msgstr "無效的幾何圖形,無法建立多邊形。" #: editor/plugins/sprite_editor_plugin.cpp msgid "Convert to Polygon2D" -msgstr "轉æ›ç‚ºå¤šé‚Šå½¢ 2D (Polygon2D)" +msgstr "轉æ›ç‚º Polygon2D" #: editor/plugins/sprite_editor_plugin.cpp msgid "Invalid geometry, can't create collision polygon." @@ -7556,7 +7552,7 @@ msgstr "無效的幾何圖形,無法建立碰撞多邊形。" #: editor/plugins/sprite_editor_plugin.cpp msgid "Create CollisionPolygon2D Sibling" -msgstr "建立碰撞多邊形 2D (CollisionPolygon2D) åŒç´š" +msgstr "建立 CollisionPolygon2D åŒç´š" #: editor/plugins/sprite_editor_plugin.cpp msgid "Invalid geometry, can't create light occluder." @@ -7564,7 +7560,7 @@ msgstr "無效的幾何圖形,無法建立é®å…‰ã€‚" #: editor/plugins/sprite_editor_plugin.cpp msgid "Create LightOccluder2D Sibling" -msgstr "建立é®å…‰ 2D (LightOccluder2D) åŒç´š" +msgstr "建立 LightOccluder2D åŒç´š" #: editor/plugins/sprite_editor_plugin.cpp msgid "Sprite" @@ -7700,7 +7696,7 @@ msgstr "自 Sprite 表建立幀" #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "SpriteFrames" -msgstr "SpriteFrames(Sprite å½±æ ¼ï¼‰" +msgstr "SpriteFrame" #: editor/plugins/texture_region_editor_plugin.cpp msgid "Set Region Rect" @@ -7708,7 +7704,7 @@ msgstr "è¨å®šå€åŸŸçŸ©å½¢ (Region Rect)" #: editor/plugins/texture_region_editor_plugin.cpp msgid "Set Margin" -msgstr "è¨ç½®å¤–é‚Šè·" +msgstr "è¨å®šå¤–é‚Šè·" #: editor/plugins/texture_region_editor_plugin.cpp msgid "Snap Mode:" @@ -7745,7 +7741,7 @@ msgstr "分隔線:" #: editor/plugins/texture_region_editor_plugin.cpp msgid "TextureRegion" -msgstr "ç´‹ç†å€åŸŸ (TextureRegion)" +msgstr "TextureRegion" #: editor/plugins/theme_editor_plugin.cpp msgid "Add All Items" @@ -7849,7 +7845,7 @@ msgstr "許多" #: editor/plugins/theme_editor_plugin.cpp msgid "Disabled LineEdit" -msgstr "å·²åœç”¨çš„行編輯" +msgstr "å·²åœç”¨çš„ LineEdit" #: editor/plugins/theme_editor_plugin.cpp msgid "Tab 1" @@ -7951,7 +7947,7 @@ msgstr "啟用優先級" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Filter tiles" -msgstr "éŽæ¿¾åœ–å¡Š" +msgstr "篩é¸åœ–å¡Š" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Give a TileSet resource to this TileMap to use its tiles." @@ -8229,7 +8225,7 @@ msgstr "建立圖塊" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Set Tile Icon" -msgstr "è¨å®šç£è²¼åœ–示" +msgstr "è¨å®šåœ–塊圖示" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Edit Tile Bitmask" @@ -8466,7 +8462,7 @@ msgstr "è¨å®šè¡¨ç¤ºå¼" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Resize VisualShader node" -msgstr "調整視覺著色器 (VisualShader) 節點大å°" +msgstr "調整 VisualShader 節點大å°" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Set Uniform Name" @@ -8535,7 +8531,7 @@ msgstr "å°‡ HSV å‘é‡è½‰ç‚ºåŒç‰ä¹‹ RGB。" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Converts RGB vector to HSV equivalent." -msgstr "å°‡ RGB å‘é‡è½‰ç‚ºåŒç‰è‡³ HSV。" +msgstr "å°‡ RGB å‘é‡è½‰ç‚ºåŒç‰ä¹‹ HSV。" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Sepia function." @@ -8649,7 +8645,7 @@ msgstr "回傳兩個åƒæ•¸é–“比較的布林çµæžœã€‚" msgid "" "Returns the boolean result of the comparison between INF (or NaN) and a " "scalar parameter." -msgstr "回傳 INF(或 NaN)與一個純é‡é–“比較的布林çµæžœã€‚" +msgstr "回傳 INF (或 NaN) 與一個純é‡é–“比較的布林çµæžœã€‚" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Boolean constant." @@ -8701,7 +8697,7 @@ msgstr "ç´”é‡é‹ç®—å。" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "E constant (2.718282). Represents the base of the natural logarithm." -msgstr "E 常數(2.718282)。表示自然å°æ•¸çš„底數。" +msgstr "E 常數 (2.718282)。表示自然å°æ•¸çš„底數。" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Epsilon constant (0.00001). Smallest possible scalar number." @@ -8725,7 +8721,7 @@ msgstr "Ï€ (Pi) 常數 (3.141593) 或 180 度。" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Tau constant (6.283185) or 360 degrees." -msgstr "Ï„ 常數 (6.283185) 或 360 度。" +msgstr "Ï„ (Tau) 常數 (6.283185) 或 360 度。" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Sqrt2 constant (1.414214). Square root of 2." @@ -8770,7 +8766,7 @@ msgstr "尋找大於或ç‰æ–¼è©²åƒæ•¸æœ€è¿‘的整數。" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Constrains a value to lie between two further values." -msgstr "將值é™åˆ¶æ¬²å…©å€‹å€¼ä¹‹é–“。" +msgstr "將值é™åˆ¶æ–¼å…©å€‹å€¼ä¹‹é–“。" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the cosine of the parameter." @@ -8782,7 +8778,7 @@ msgstr "回傳åƒæ•¸çš„雙曲餘弦值。" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Converts a quantity in radians to degrees." -msgstr "將弧度轉æ›ç‚ºåº¦ã€‚" +msgstr "將弧度轉æ›ç‚ºè§’度。" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Base-e Exponential." @@ -8802,7 +8798,7 @@ msgstr "計算引數的å°æ•¸éƒ¨åˆ†ã€‚" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Returns the inverse of the square root of the parameter." -msgstr "回傳åƒæ•¸çš„å¹³æ–¹æ ¹çš„å€’æ•¸ã€‚" +msgstr "回傳åƒæ•¸çš„å¹³æ–¹æ ¹ä¹‹å€’æ•¸ã€‚" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Natural logarithm." @@ -8839,7 +8835,7 @@ msgstr "回傳第一個åƒæ•¸çš„第二個åƒæ•¸å†ªæ¬¡çš„值。" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Converts a quantity in degrees to radians." -msgstr "將度數轉æ›ç‚ºå¼§åº¦ã€‚" +msgstr "將角度轉æ›ç‚ºå¼§åº¦ã€‚" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "1.0 / scalar" @@ -8851,7 +8847,7 @@ msgstr "尋找åƒæ•¸æœ€è¿‘的整數。" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Finds the nearest even integer to the parameter." -msgstr "尋找åƒæ•¸æœ€è¿‘的整數。" +msgstr "尋找åƒæ•¸æœ€è¿‘çš„å¶æ•¸ã€‚" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Clamps the value between 0.0 and 1.0." @@ -9230,7 +9226,7 @@ msgstr "(é™ç‰‡æ®µï¼å…‰ç…§æ¨¡å¼ï¼‰ï¼ˆç´”é‡ï¼‰åŠ 總「xã€èˆ‡ã€Œyã€é€²è¡Œç #: editor/plugins/visual_shader_editor_plugin.cpp msgid "VisualShader" -msgstr "視覺著色器 (VisualShader)" +msgstr "VisualShader" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Edit Visual Property" @@ -9258,7 +9254,7 @@ msgstr "是å¦è¦è‡ªåˆ—表ä¸åˆªé™¤ã€Œ%sã€ä¿®æ£æª”?" #: editor/project_export.cpp msgid "Delete preset '%s'?" -msgstr "確定è¦åˆªé™¤ Preset「%sã€ï¼Ÿ" +msgstr "確定è¦åˆªé™¤é è¨è¨å®šã€Œ%sã€ï¼Ÿ" #: editor/project_export.cpp msgid "" @@ -9275,11 +9271,11 @@ msgid "" "export settings." msgstr "" "為平å°ã€Œ%sã€åŒ¯å‡ºå°ˆæ¡ˆå¤±æ•—。\n" -"å¯èƒ½ä½¿ç”±æ–¼åŒ¯å‡º Preset 或匯出è¨å®šä¸çš„組態è¨å®šæœ‰å•é¡Œå°Žè‡´ã€‚" +"å¯èƒ½æ˜¯ç”±æ–¼åŒ¯å‡ºé è¨è¨å®šæˆ–匯出è¨å®šä¸çš„組態è¨å®šæœ‰å•é¡Œå°Žè‡´ã€‚" #: editor/project_export.cpp msgid "Release" -msgstr "釋出" +msgstr "發行" #: editor/project_export.cpp msgid "Exporting All" @@ -9295,7 +9291,7 @@ msgstr "該平å°çš„匯出範本éºå¤±ï¼æ毀:" #: editor/project_export.cpp msgid "Presets" -msgstr "Preset" +msgstr "é è¨è¨å®š" #: editor/project_export.cpp editor/project_settings_editor.cpp msgid "Add..." @@ -9306,8 +9302,8 @@ msgid "" "If checked, the preset will be available for use in one-click deploy.\n" "Only one preset per platform may be marked as runnable." msgstr "" -"è‹¥é¸ä¸ï¼Œå‰‡ Preset å°‡å¯ä½¿ç”¨ä¸€éµéƒ¨ç½²ã€‚\n" -"æ¯å€‹å¹³å°åªå¯å°‡ä¸€å€‹ Preset è¨ç‚ºå¯åŸ·è¡Œã€‚" +"è‹¥é¸ä¸ï¼Œå‰‡é è¨è¨å®šå°‡å¯ä½¿ç”¨å–®éµéƒ¨ç½²ã€‚\n" +"æ¯å€‹å¹³å°åªå¯å°‡ä¸€å€‹é è¨è¨å®šè¨ç‚ºå¯åŸ·è¡Œã€‚" #: editor/project_export.cpp msgid "Export Path" @@ -9342,7 +9338,7 @@ msgid "" "Filters to export non-resource files/folders\n" "(comma-separated, e.g: *.json, *.txt, docs/*)" msgstr "" -"éŽæ¿¾éžè³‡æºçš„檔案ï¼è³‡æ–™å¤¾ä»¥åŒ¯å‡º\n" +"篩é¸éžè³‡æºçš„檔案ï¼è³‡æ–™å¤¾ä»¥é€²è¡ŒåŒ¯å‡º\n" "(以åŠå½¢é€—號å€åˆ†ï¼Œå¦‚: *.json, *.txt, docs/*)" #: editor/project_export.cpp @@ -9350,7 +9346,7 @@ msgid "" "Filters to exclude files/folders from project\n" "(comma-separated, e.g: *.json, *.txt, docs/*)" msgstr "" -"éŽæ¿¾ä»¥åœ¨å°ˆæ¡ˆå…§æŽ’除檔案ï¼è³‡æ–™å¤¾\n" +"進行篩é¸ä»¥åœ¨å°ˆæ¡ˆå…§æŽ’除檔案ï¼è³‡æ–™å¤¾\n" "(以åŠå½¢é€—號å€åˆ†ï¼Œå¦‚: *.json, *.txt, docs/*)" #: editor/project_export.cpp @@ -9550,7 +9546,7 @@ msgstr "專案安è£è·¯å¾‘:" #: editor/project_manager.cpp msgid "Renderer:" -msgstr "算圖器:" +msgstr "轉è¯å™¨ï¼š" #: editor/project_manager.cpp msgid "OpenGL ES 3.0" @@ -9586,7 +9582,7 @@ msgstr "" #: editor/project_manager.cpp msgid "Renderer can be changed later, but scenes may need to be adjusted." -msgstr "ç¨å¾Œä»å¯æ›´æ”¹ç®—圖器,但å¯èƒ½éœ€è¦å°å ´æ™¯é€²è¡Œèª¿æ•´ã€‚" +msgstr "ç¨å¾Œä»å¯æ›´æ”¹è½‰è¯å™¨ï¼Œä½†å¯èƒ½éœ€è¦å°å ´æ™¯é€²è¡Œèª¿æ•´ã€‚" #: editor/project_manager.cpp msgid "Unnamed Project" @@ -9602,7 +9598,7 @@ msgstr "錯誤:專案在檔案系統上éºå¤±ã€‚" #: editor/project_manager.cpp msgid "Can't open project at '%s'." -msgstr "無法在「%sã€ä¸æ‰“開專案。" +msgstr "無法於「%sã€æ‰“開專案。" #: editor/project_manager.cpp msgid "Are you sure to open more than one project?" @@ -9625,7 +9621,7 @@ msgstr "" "%s\n" "\n" "若您繼續開啟,會將其轉æ›ç‚ºç›®å‰ Godot 版本的組態è¨å®šæª”æ¡ˆæ ¼å¼ã€‚\n" -"è¦å‘Šï¼šæ‚¨å°‡ä¸å†å¯ä½¿ç”¨éŽå¾€ç‰ˆæœ¬çš„引擎開啟該專案。" +"è¦å‘Šï¼šæ‚¨å°‡ä¸å†å¯ä½¿ç”¨èˆŠç‰ˆçš„ Godot 開啟該專案。" #: editor/project_manager.cpp msgid "" @@ -9638,12 +9634,13 @@ msgid "" "Warning: You won't be able to open the project with previous versions of the " "engine anymore." msgstr "" -"下列專案è¨å®šæª”時由較舊版本的引擎所產生,且需è¦å°‡å…¶è½‰æ›ç‚ºç›®å‰çš„版本:\n" +"下列專案è¨å®šæª”是由較舊版本的 Godot 產生,需進行轉æ›ä»¥é©ç”¨æ–¼ç›®å‰ç‰ˆæœ¬çš„ " +"Godot:\n" "\n" "%s\n" "\n" "è¦é€²è¡Œè½‰æ›å—Žï¼Ÿ\n" -"è¦å‘Šï¼šæ‚¨å°‡ä¸å†å¯ä½¿ç”¨éŽå¾€ç‰ˆæœ¬çš„引擎開啟該專案。" +"è¦å‘Šï¼šæ‚¨å°‡ä¸å†å¯ä½¿ç”¨èˆŠç‰ˆçš„ Godot 開啟該專案。" #: editor/project_manager.cpp msgid "" @@ -9709,7 +9706,7 @@ msgid "" "Are you sure to scan %s folders for existing Godot projects?\n" "This could take a while." msgstr "" -"確定è¦ç‚ºç¾å˜çš„ Godot 專案掃æ %s 資料夾嗎?\n" +"確定è¦æŽƒæ %s ä¸çš„ Godot 專案嗎?\n" "這å¯èƒ½éœ€è¦ä¸€æ®µæ™‚間。" #: editor/project_manager.cpp @@ -9766,12 +9763,12 @@ msgid "" "To filter projects by name and full path, the query must contain at least " "one `/` character." msgstr "" -"æœå°‹æ¡†å¯ä»¥ç”¨ä¾†ä¾æ“šå稱與路徑ä¸çš„最後一部分來éŽæ¿¾å°ˆæ¡ˆã€‚\n" -"è‹¥è¦ä»¥å稱與完整路徑來éŽæ¿¾å°ˆæ¡ˆï¼Œæœå°‹å…§å®¹æ‡‰è©²è‡³å°‘包å«ä¸€å€‹ã€Œ/ã€å—元。" +"æœå°‹æ¡†å¯ä»¥ç”¨ä¾†ä¾æ“šå稱與路徑ä¸çš„最後一部分來篩é¸å°ˆæ¡ˆã€‚\n" +"è‹¥è¦ä»¥å稱與完整路徑來éŽæ¿¾å°ˆæ¡ˆï¼Œæœå°‹å…§å®¹æ‡‰è‡³å°‘包å«ä¸€å€‹ã€Œ/ã€å—元。" #: editor/project_settings_editor.cpp msgid "Key " -msgstr "éµ " +msgstr "æŒ‰éµ " #: editor/project_settings_editor.cpp msgid "Joy Button" @@ -9789,7 +9786,7 @@ msgstr "æ»‘é¼ æŒ‰éˆ•" msgid "" "Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or " "'\"'" -msgstr "無效的æ“作å稱。ä¸èƒ½ç‚ºç©ºæˆ–包å«ã€Œ/ã€ã€ã€Œ:ã€ã€ã€Œ=ã€ã€ã€Œ\\ã€æˆ–「\"ã€" +msgstr "無效的æ“作å稱。å稱ä¸å¯ç•™ç©ºæˆ–åŒ…å« â€œ/â€, “:â€, “=â€, “\\†或 “\"â€" #: editor/project_settings_editor.cpp msgid "An action with the name '%s' already exists." @@ -9885,7 +9882,7 @@ msgstr "新增事件" #: editor/project_settings_editor.cpp msgid "Button" -msgstr "Button (按鈕)" +msgstr "按鈕" #: editor/project_settings_editor.cpp msgid "Left Button." @@ -9931,7 +9928,7 @@ msgstr "åˆªé™¤é …ç›®" msgid "" "Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or " "'\"'." -msgstr "無效的æ“作å稱。ä¸èƒ½ç‚ºç©ºæˆ–包å«ã€Œ/ã€ã€ã€Œ:ã€ã€ã€Œ=ã€ã€ã€Œ\\ã€æˆ–「\"ã€ã€‚" +msgstr "無效的æ“作å稱。å稱ä¸å¯ç•™ç©ºæˆ–åŒ…å« â€œ/â€, “:â€, “=â€, “\\†或 “\"â€ã€‚" #: editor/project_settings_editor.cpp msgid "Add Input Action" @@ -9983,11 +9980,11 @@ msgstr "移除資æºé‡æ˜ å°„é¸é …" #: editor/project_settings_editor.cpp msgid "Changed Locale Filter" -msgstr "更改å€åŸŸéŽæ¿¾" +msgstr "更改地å€è¨å®šç¯©é¸æ¢ä»¶" #: editor/project_settings_editor.cpp msgid "Changed Locale Filter Mode" -msgstr "更改å€åŸŸéŽæ¿¾æ¨¡å¼" +msgstr "更改地å€è¨å®šç¯©é¸æ¨¡å¼" #: editor/project_settings_editor.cpp msgid "Project Settings (project.godot)" @@ -10051,31 +10048,31 @@ msgstr "資æºï¼š" #: editor/project_settings_editor.cpp msgid "Remaps by Locale:" -msgstr "ä¾èªžè¨€é‡æ˜ 射:" +msgstr "ä¾åœ°å€è¨å®šé‡æ˜ 射:" #: editor/project_settings_editor.cpp msgid "Locale" -msgstr "語言" +msgstr "地å€" #: editor/project_settings_editor.cpp msgid "Locales Filter" -msgstr "語言éŽæ¿¾" +msgstr "地å€ç¯©é¸æ¢ä»¶" #: editor/project_settings_editor.cpp msgid "Show All Locales" -msgstr "顯示所有語言" +msgstr "顯示所有地å€" #: editor/project_settings_editor.cpp msgid "Show Selected Locales Only" -msgstr "僅顯示é¸å®šçš„語言" +msgstr "僅顯示é¸å®šçš„地å€" #: editor/project_settings_editor.cpp msgid "Filter mode:" -msgstr "éŽæ¿¾æ¨¡å¼ï¼š" +msgstr "篩é¸æ¨¡å¼ï¼š" #: editor/project_settings_editor.cpp msgid "Locales:" -msgstr "語言:" +msgstr "地å€ï¼š" #: editor/project_settings_editor.cpp msgid "AutoLoad" @@ -10087,7 +10084,7 @@ msgstr "外掛" #: editor/property_editor.cpp msgid "Preset..." -msgstr "Preset..." +msgstr "é è¨è¨å®š..." #: editor/property_editor.cpp msgid "Zero" @@ -10099,7 +10096,7 @@ msgstr "緩入緩出" #: editor/property_editor.cpp msgid "Easing Out-In" -msgstr "緩入緩出(åå‘)" +msgstr "緩出緩入" #: editor/property_editor.cpp msgid "File..." @@ -10333,7 +10330,7 @@ msgstr "å–æ¶ˆé™„åŠ è…³æœ¬" #: editor/scene_tree_dock.cpp msgid "This operation can't be done on the tree root." -msgstr "æ¤æ“ä½œç„¡æ³•åœ¨æ¨¹ç‹€æ ¹åŸ·è¡Œã€‚" +msgstr "æ¤æ“ä½œç„¡æ³•åœ¨æ¨¹ç‹€æ ¹ç¯€é»žåŸ·è¡Œã€‚" #: editor/scene_tree_dock.cpp msgid "Move Node In Parent" @@ -10364,6 +10361,11 @@ msgid "Make node as Root" msgstr "將節點è¨ç‚ºæ ¹ç¯€é»ž" #: editor/scene_tree_dock.cpp +#, fuzzy +msgid "Delete %d nodes and any children?" +msgstr "確定è¦åˆªé™¤ç¯€é»žã€Œ%sã€èˆ‡å…¶å節點嗎?" + +#: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" msgstr "刪除 %d 個節點?" @@ -10456,7 +10458,7 @@ msgstr "更改節點的型別" msgid "" "Couldn't save new scene. Likely dependencies (instances) couldn't be " "satisfied." -msgstr "無法ä¿å˜æ–°å ´æ™¯ã€‚很å¯èƒ½ç”±æ–¼ç„¡æ³•æ»¿è¶³å…¶ä¾è³´æ€§ï¼ˆå¯¦é«”)。" +msgstr "無法ä¿å˜æ–°å ´æ™¯ã€‚å¯èƒ½æ˜¯ç”±æ–¼ç„¡æ³•æ»¿è¶³å…¶ä¾è³´æ€§ï¼ˆå¯¦é«”)。" #: editor/scene_tree_dock.cpp msgid "Error saving scene." @@ -10493,7 +10495,7 @@ msgid "" "disabled." msgstr "" "ç„¡æ³•é™„åŠ è…³æœ¬ï¼šæœªè¨»å†Šä»»ä½•èªžè¨€ã€‚\n" -"有å¯èƒ½æ˜¯ç”±æ–¼ç·¨è¼¯å™¨åœ¨å»ºæ§‹æ™‚未啟用任何語言模組。" +"å¯èƒ½æ˜¯ç”±æ–¼ç·¨è¼¯å™¨åœ¨å»ºæ§‹æ™‚未啟用任何語言模組。" #: editor/scene_tree_dock.cpp msgid "Add Child Node" @@ -10634,7 +10636,7 @@ msgid "" "AnimationPlayer is pinned.\n" "Click to unpin." msgstr "" -"已固定動畫æ’放器 (AnimationPlayer)。\n" +"已固定 AnimationPlayer。\n" "點擊以å–消固定。" #: editor/scene_tree_editor.cpp @@ -10739,7 +10741,7 @@ msgstr "å¯ç”¨çš„腳本路徑ï¼å稱。" #: editor/script_create_dialog.cpp msgid "Allowed: a-z, A-Z, 0-9, _ and ." -msgstr "å¯ä½¿ç”¨ï¼ša-zã€A-Zã€0-9ã€_ ä»¥åŠ ." +msgstr "å¯ä½¿ç”¨ï¼ša-z, A-Z, 0-9, _ ä»¥åŠ ." #: editor/script_create_dialog.cpp msgid "Built-in script (into scene file)." @@ -10761,7 +10763,7 @@ msgstr "腳本檔案已å˜åœ¨ã€‚" msgid "" "Note: Built-in scripts have some limitations and can't be edited using an " "external editor." -msgstr "注æ„:內置腳本有些é™åˆ¶ï¼Œä¸”無法使用外部編輯器來編輯。" +msgstr "注æ„:內建腳本有些é™åˆ¶ï¼Œä¸”無法使用外部編輯器來編輯。" #: editor/script_create_dialog.cpp msgid "Class Name:" @@ -10869,11 +10871,11 @@ msgstr "數值" #: editor/script_editor_debugger.cpp msgid "Monitors" -msgstr "監視程å¼" +msgstr "監視器" #: editor/script_editor_debugger.cpp msgid "Pick one or more items from the list to display the graph." -msgstr "å列表ä¸é¸æ“‡ä¸€å€‹æˆ–å¤šå€‹é …ç›®ä»¥é¡¯ç¤ºåœ–è¡¨ã€‚" +msgstr "在å列表ä¸é¸æ“‡ä¸€å€‹æˆ–å¤šå€‹é …ç›®ä»¥é¡¯ç¤ºåœ–è¡¨ã€‚" #: editor/script_editor_debugger.cpp msgid "List of Video Memory Usage by Resource:" @@ -10957,7 +10959,7 @@ msgstr "更改光照åŠå¾‘" #: editor/spatial_editor_gizmos.cpp msgid "Change AudioStreamPlayer3D Emission Angle" -msgstr "更改音訊串æµæ’放器 3D (AudioStreamPlayer3D) 發射角" +msgstr "更改 AudioStreamPlayer3D 發射角" #: editor/spatial_editor_gizmos.cpp msgid "Change Camera FOV" @@ -10977,7 +10979,7 @@ msgstr "更改粒å AABB" #: editor/spatial_editor_gizmos.cpp msgid "Change Probe Extents" -msgstr "更改探é‡ç¯„åœ" +msgstr "更改探查範åœ" #: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp msgid "Change Sphere Shape Radius" @@ -11237,11 +11239,11 @@ msgstr "é¸æ“‡è·é›¢ï¼š" #: modules/gridmap/grid_map_editor_plugin.cpp msgid "Filter meshes" -msgstr "éŽæ¿¾ç¶²æ ¼" +msgstr "篩é¸ç¶²æ ¼" #: modules/gridmap/grid_map_editor_plugin.cpp msgid "Give a MeshLibrary resource to this GridMap to use its meshes." -msgstr "æä¾›ç¶²æ ¼åº«è³‡æºäºˆè©²ç¶²æ ¼åœ°åœ–ä»¥ä½¿ç”¨å…¶ç¶²æ ¼ã€‚" +msgstr "æä¾› MeshLibrary 予該 GridMap ä»¥ä½¿ç”¨å…¶ç¶²æ ¼ã€‚" #: modules/mono/csharp_script.cpp msgid "Class name can't be a reserved keyword" @@ -11253,7 +11255,7 @@ msgstr "å…§éƒ¨ç•°å¸¸å †ç–Šå›žæº¯çµæŸ" #: modules/recast/navigation_mesh_editor_plugin.cpp msgid "Bake NavMesh" -msgstr "Bake å°Žèˆªç¶²æ ¼ (NavMesh)" +msgstr "製作 NavMesh" #: modules/recast/navigation_mesh_editor_plugin.cpp msgid "Clear the navigation mesh." @@ -11391,11 +11393,11 @@ msgstr "訊號:" #: modules/visual_script/visual_script_editor.cpp msgid "Create a new signal." -msgstr "建立一個新的訊號。" +msgstr "建立一個新訊號。" #: modules/visual_script/visual_script_editor.cpp msgid "Name is not a valid identifier:" -msgstr "å稱ä¸æ˜¯ä¸€å€‹æœ‰æ•ˆçš„è˜åˆ¥ç¬¦ï¼š" +msgstr "å稱並éžæœ‰æ•ˆè˜åˆ¥ç¬¦ï¼š" #: modules/visual_script/visual_script_editor.cpp msgid "Name already in use by another func/var/signal:" @@ -11451,13 +11453,12 @@ msgstr "é‡è¤‡è¦–覺腳本 (VisualScript) 節點" #: modules/visual_script/visual_script_editor.cpp msgid "Hold %s to drop a Getter. Hold Shift to drop a generic signature." -msgstr "" -"æŒ‰ä½ %s 以拖移 Getter ç¯€é»žã€‚æŒ‰ä½ Shift ä»¥æ‹–ç§»ä¸€å€‹é€šç”¨çš„ç°½ç« (Signature)。" +msgstr "æŒ‰ä½ %s 以拖移 Getter ç¯€é»žã€‚æŒ‰ä½ Shift ä»¥æ‹–ç§»é€šç”¨ç°½ç« (Signature)。" #: modules/visual_script/visual_script_editor.cpp msgid "Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature." msgstr "" -"æŒ‰ä½ Ctrl 以拖移 Getter ç¯€é»žã€‚æŒ‰ä½ Shift 以拖移一個通用的簽å (Signature)。" +"æŒ‰ä½ Ctrl 以拖移 Getter ç¯€é»žã€‚æŒ‰ä½ Shift ä»¥æ‹–ç§»é€šç”¨é€šç”¨ç°½ç« (Signature)。" #: modules/visual_script/visual_script_editor.cpp msgid "Hold %s to drop a simple reference to the node." @@ -11477,7 +11478,7 @@ msgstr "æŒ‰ä½ Ctrl 以拖動一個變數 Setter 節點。" #: modules/visual_script/visual_script_editor.cpp msgid "Add Preload Node" -msgstr "新增餘載 (Preload) 節點" +msgstr "新增é 載 (Preload) 節點" #: modules/visual_script/visual_script_editor.cpp msgid "Add Node(s) From Tree" @@ -11665,7 +11666,7 @@ msgstr "無效的索引屬性å稱。" #: modules/visual_script/visual_script_func_nodes.cpp msgid "Base object is not a Node!" -msgstr "基礎物件ä¸æ˜¯ä¸€å€‹ç¯€é»žï¼" +msgstr "基礎物件並éžç¯€é»žï¼" #: modules/visual_script/visual_script_func_nodes.cpp msgid "Path does not lead Node!" @@ -11677,11 +11678,11 @@ msgstr "無效的索引屬性å稱「%sã€ï¼Œæ–¼ç¯€é»žã€Œ%sã€ã€‚" #: modules/visual_script/visual_script_nodes.cpp msgid ": Invalid argument of type: " -msgstr ": 無效的引數型別 : " +msgstr ": 無效的引數型別: " #: modules/visual_script/visual_script_nodes.cpp msgid ": Invalid arguments: " -msgstr ": 無效的引數 : " +msgstr ": 無效的引數: " #: modules/visual_script/visual_script_nodes.cpp msgid "VariableGet not found in script: " @@ -11751,11 +11752,11 @@ msgstr "尚未於編輯器è¨å®šä¸è¨å®š OpenJDK Jarsigner。" #: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." -msgstr "尚未於編輯器è¨å®šæˆ– Preset ä¸è¨å®šé™¤éŒ¯é‘°åŒ™åœˆ (Keystore)。" +msgstr "尚未於編輯器è¨å®šæˆ–é è¨è¨å®šä¸è¨å®šé‡‘鑰儲å˜å€ (Keystore)。" #: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." -msgstr "釋出 Keystore ä¸ä¸æ£ç¢ºä¹‹çµ„æ…‹è¨å®šè‡³åŒ¯å‡º Preset。" +msgstr "發行金鑰儲å˜å€ä¸ä¸æ£ç¢ºä¹‹çµ„æ…‹è¨å®šè‡³åŒ¯å‡ºé è¨è¨å®šã€‚" #: platform/android/export/export.cpp msgid "Custom build requires a valid Android SDK path in Editor Settings." @@ -11866,7 +11867,7 @@ msgstr "無效的è˜åˆ¥ç¬¦ï¼š" #: platform/iphone/export/export.cpp msgid "Required icon is not specified in the preset." -msgstr "å¿…é ˆåœ¨ Preset ä¸æŒ‡å®šå¿…填圖示。" +msgstr "å¿…é ˆåœ¨é è¨è¨å®šä¸æŒ‡å®šå¿…填圖示。" #: platform/javascript/export/export.cpp msgid "Stop HTTP Server" @@ -11979,8 +11980,7 @@ msgid "" "define its shape." msgstr "" "該節點無形狀,故無法與其他物件碰撞或互動。\n" -"請考慮新增一個 CollisionShape2D 或 CollisionPolygon2D 為其å節點以定義其形" -"狀。" +"建è°æ‚¨æ–°å¢ž CollisionShape2D 或 CollisionPolygon2D 作為其å節點以定義其形狀。" #: scene/2d/collision_polygon_2d.cpp msgid "" @@ -11988,7 +11988,7 @@ msgid "" "CollisionObject2D derived node. Please only use it as a child of Area2D, " "StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape." msgstr "" -"CollisionPolygon2D åªèƒ½ç‚º CollisionObject2D è¡ç”Ÿçš„節點æ供碰撞形狀資訊。請僅" +"CollisionPolygon2D 僅å¯ç‚º CollisionObject2D è¡ç”Ÿçš„節點æ供碰撞形狀資訊。請僅" "æ–¼ Area2Dã€StaticBody2Dã€RigidBody2Dã€KinematicBody2D…ç‰ç¯€é»žä¸‹ä½œç‚ºå節點使" "用。" @@ -12002,7 +12002,7 @@ msgid "" "CollisionObject2D derived node. Please only use it as a child of Area2D, " "StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape." msgstr "" -"CollisionShape2D åªèƒ½ç‚º CollisionObject2D è¡ç”Ÿçš„節點æ供碰撞形狀資訊。請僅於 " +"CollisionShape2D 僅å¯ç‚º CollisionObject2D è¡ç”Ÿçš„節點æ供碰撞形狀資訊。請僅於 " "Area2Dã€StaticBody2Dã€RigidBody2Dã€KinematicBody2D…ç‰ç¯€é»žä¸‹ä½œç‚ºå節點使用以æ" "供形狀。" @@ -12012,6 +12012,12 @@ msgid "" "shape resource for it!" msgstr "CollisionShape2D å¿…é ˆè¢«è³¦äºˆå½¢ç‹€æ‰èƒ½é‹ä½œã€‚請先建立形狀ï¼" +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + #: scene/2d/cpu_particles_2d.cpp msgid "" "CPUParticles2D animation requires the usage of a CanvasItemMaterial with " @@ -12063,7 +12069,7 @@ msgid "" "CPUParticles\" option for this purpose." msgstr "" "GLES2 視訊驅動程å¼ç›®å‰ä¸æ”¯æ´åŸºæ–¼ GPU çš„ç²’å。\n" -"請改為使用 CPUParticles2D ç¯€é»žã€‚ä½ å¯ä»¥ä½¿ç”¨ã€Œè½‰æ›ç‚º CPUParticlesã€é¸é …。" +"請改為使用 CPUParticles2D 節點。å¯ä½¿ç”¨ã€ŒConvert to CPUParticlesã€é¸é …。" #: scene/2d/particles_2d.cpp scene/3d/particles.cpp msgid "" @@ -12075,7 +12081,9 @@ msgstr "尚未指定è¦è™•ç†ç²’åçš„æ料,故未產生任何行為。" msgid "" "Particles2D animation requires the usage of a CanvasItemMaterial with " "\"Particles Animation\" enabled." -msgstr "Particles2D 動畫需è¦ä½¿ç”¨é–‹å•Ÿäº†ã€Œç²’åå‹•ç•«ã€çš„ CanvasItemMaterial。" +msgstr "" +"Particles2D 動畫需è¦ä½¿ç”¨é–‹å•Ÿäº†ã€ŒParticles Animation(粒å動畫)ã€çš„ " +"CanvasItemMaterial。" #: scene/2d/path_2d.cpp msgid "PathFollow2D only works when set as a child of a Path2D node." @@ -12106,7 +12114,7 @@ msgstr "Bone2D 僅在其為 Skeleton2D 或å¦ä¸€å€‹ Bone2D çš„å節點時有效 #: scene/2d/skeleton_2d.cpp msgid "" "This bone lacks a proper REST pose. Go to the Skeleton2D node and set one." -msgstr "該骨骼缺少é©ç•¶çš„ REST 姿勢。請跳至 Skeleton2D 節點並進行è¨å®šã€‚" +msgstr "該骨骼缺少é©ç•¶çš„「éœæ¢å§¿å‹¢ã€ã€‚請跳至 Skeleton2D 節點並進行è¨å®šã€‚" #: scene/2d/tile_map.cpp msgid "" @@ -12114,7 +12122,7 @@ msgid "" "to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, " "KinematicBody2D, etc. to give them a shape." msgstr "" -"CollisionShape2D åªèƒ½ç‚º CollisionObject2D è¡ç”Ÿçš„節點æ供碰撞形狀資訊。請將其" +"CollisionShape2D 僅å¯ç‚º CollisionObject2D è¡ç”Ÿçš„節點æ供碰撞形狀資訊。請將其" "è¨ç‚º Area2Dã€StaticBody2Dã€RigidBody2Dã€KinematicBody2D… çš„å節點以賦予其形" "狀。" @@ -12183,7 +12191,7 @@ msgid "" "its shape." msgstr "" "該節點沒有形狀,故無法與其他物件碰撞或互動。\n" -"請考慮新增一個 CollisionShape 或 CollisionPolygon 作為其å節點以定義其形狀。" +"建è°æ‚¨æ–°å¢ž CollisionShape 或 CollisionPolygon 作為其å節點以定義其形狀。" #: scene/3d/collision_polygon.cpp msgid "" @@ -12191,7 +12199,7 @@ msgid "" "CollisionObject derived node. Please only use it as a child of Area, " "StaticBody, RigidBody, KinematicBody, etc. to give them a shape." msgstr "" -"CollisionPolygon åªèƒ½ç‚º CollisionObject è¡ç”Ÿçš„節點æ供碰撞形狀資訊。請僅於 " +"CollisionPolygon 僅å¯ç‚º CollisionObject è¡ç”Ÿçš„節點æ供碰撞形狀資訊。請僅於 " "Areaã€StaticBodyã€RigidBodyã€KinematicBody…ç‰ç¯€é»žä¸‹ä½œç‚ºå節點使用。" #: scene/3d/collision_polygon.cpp @@ -12204,7 +12212,7 @@ msgid "" "derived node. Please only use it as a child of Area, StaticBody, RigidBody, " "KinematicBody, etc. to give them a shape." msgstr "" -"CollisionShape åªèƒ½ç‚º CollisionObject è¡ç”Ÿçš„節點æ供碰撞形狀資訊。請僅於 " +"CollisionShape 僅å¯ç‚º CollisionObject è¡ç”Ÿçš„節點æ供碰撞形狀資訊。請僅於 " "Areaã€StaticBodyã€RigidBodyã€KinematicBody…ç‰ç¯€é»žä¸‹ä½œç‚ºå節點使用。" #: scene/3d/collision_shape.cpp @@ -12217,7 +12225,7 @@ msgstr "CollisionShape å¿…é ˆè¢«è³¦äºˆå½¢ç‹€æ‰èƒ½é‹ä½œã€‚請先建立形狀。 msgid "" "Plane shapes don't work well and will be removed in future versions. Please " "don't use them." -msgstr "å¹³é¢å½¢ç‹€çš„é‹ä½œä¸å¤ªæ£å¸¸ï¼Œä¸”將在未來的版本移除。請勿使用。" +msgstr "å¹³é¢å½¢ç‹€æ™‚常無法æ£å¸¸ä½¿ç”¨ï¼Œä¸”將在未來的版本移除。請勿使用。" #: scene/3d/collision_shape.cpp msgid "" @@ -12271,7 +12279,7 @@ msgid "" "\" option for this purpose." msgstr "" "GLES2 視訊驅動程å¼ä¸æ”¯æ´åŸºæ–¼ GPU çš„ç²’å。\n" -"請改為使用 CPUParticles 節點。為æ¤æ‚¨å¯ä»¥ä½¿ç”¨ã€Œè½‰æ›ç‚º CPUParticlesã€é¸é …。" +"請改為使用 CPUParticles 節點。å¯ä½¿ç”¨ã€ŒConvert to CPUParticlesã€é¸é …。" #: scene/3d/particles.cpp msgid "" @@ -12295,8 +12303,8 @@ msgid "" "PathFollow's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its " "parent Path's Curve resource." msgstr "" -"PathFollow çš„ ROTATION_ORIENTED 需è¦åœ¨å…¶æ¯ç¯€é»ž Path çš„ Curve 資æºå…§å•Ÿç”¨ã€Œä¸Šå‘" -"é‡ (Up Vector)ã€ã€‚" +"PathFollow çš„ ROTATION_ORIENTED 需è¦åœ¨å…¶æ¯ç¯€é»ž Path çš„ Curve 資æºå…§å•Ÿç”¨ã€ŒUp " +"Vectorã€ã€‚" #: scene/3d/physics_body.cpp msgid "" @@ -12313,7 +12321,7 @@ msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" "derived node to work." msgstr "" -"「é 端路徑ã€å±¬æ€§å¿…é ˆæŒ‡å‘一個有效的 Spatial 或 Spatial è¡ç”Ÿä¹‹ç¯€é»žæ‰å¯é‹ä½œã€‚" +"「Remote Pathã€å±¬æ€§å¿…é ˆæŒ‡å‘一個有效的 Spatial 或 Spatial è¡ç”Ÿä¹‹ç¯€é»žæ‰å¯é‹ä½œã€‚" #: scene/3d/soft_body.cpp msgid "This body will be ignored until you set a mesh." @@ -12362,8 +12370,8 @@ msgid "" "This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set " "this environment's Background Mode to Canvas (for 2D scenes)." msgstr "" -"已忽略該 WorldEnvironment。請(為 3D å ´æ™¯ï¼‰æ–°å¢žä¸€å€‹ç›¸æ©Ÿæˆ–ï¼ˆç‚º 2D å ´æ™¯ï¼‰è¨å®šç’°" -"å¢ƒä¹‹èƒŒæ™¯æ¨¡å¼ (Background Mode) 為畫布 (Canvas)。" +"已忽略該 WorldEnvironment。請(為 3D å ´æ™¯ï¼‰æ–°å¢žä¸€å€‹ç›¸æ©Ÿæˆ–ï¼ˆç‚º 2D å ´æ™¯ï¼‰å°‡ " +"Environment 之 Background Mode è¨ç‚º Canvas。" #: scene/animation/animation_blend_tree.cpp msgid "On BlendTree node '%s', animation not found: '%s'" @@ -12413,7 +12421,7 @@ msgid "" msgstr "" "色彩: #%s\n" "å·¦éµé»žæ“Šï¼šè¨å®šè‰²å½©\n" -"å³éµé»žæ“Šï¼šåˆªé™¤ Preset" +"å³éµé»žæ“Šï¼šåˆªé™¤é è¨è¨å®š" #: scene/gui/color_picker.cpp msgid "Pick a color from the editor window." @@ -12433,7 +12441,7 @@ msgstr "在 16 進ä½èˆ‡ä»£ç¢¼å€¼ä¹‹é–“切æ›ã€‚" #: scene/gui/color_picker.cpp msgid "Add current color as a preset." -msgstr "將目å‰çš„é¡è‰²åŠ å…¥ Preset。" +msgstr "將目å‰çš„é¡è‰²åŠ å…¥é è¨è¨å®šã€‚" #: scene/gui/container.cpp msgid "" @@ -12450,8 +12458,8 @@ msgid "" "The Hint Tooltip won't be displayed as the control's Mouse Filter is set to " "\"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"." msgstr "" -"由於è¨å®šçš„æ»‘é¼ ç¯©é¸ (Mouse Filter) è¨å®šç‚ºã€Œå¿½ç•¥ (Ignore)ã€ï¼Œå°‡ä¸æœƒé¡¯ç¤ºæ示 " -"Tooltip 。è¦è§£æ±ºè©²å•é¡Œï¼Œè«‹å°‡æ»‘é¼ ç¯©é¸è¨ç‚ºã€Œåœæ¢ (Stop)ã€æˆ–ã€Œé€šéŽ (Pass)ã€ã€‚" +"由於è¨å®šçš„ Mouse Filter è¨å®šç‚ºã€ŒIgnoreã€ï¼Œå°‡ä¸æœƒé¡¯ç¤ºæ示工具æ示 。è¦è§£æ±ºè©²å•" +"題,請將 Mouse Filter è¨ç‚ºã€ŒStopã€æˆ–「Passã€ã€‚" #: scene/gui/dialogs.cpp msgid "Alert!" @@ -12472,7 +12480,7 @@ msgstr "" #: scene/gui/range.cpp msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0." -msgstr "若啟用「表示å¼ç·¨è¼¯ã€ï¼Œå‰‡ã€Œæœ€å°å€¼ã€å¿…é ˆå¤§æ–¼ 0。" +msgstr "若啟用「Exp Editã€ï¼Œå‰‡ã€ŒMin Valueã€å¿…é ˆå¤§æ–¼ 0。" #: scene/gui/scroll_container.cpp msgid "" @@ -12492,7 +12500,7 @@ msgstr "(其它)" msgid "" "Default Environment as specified in Project Settings (Rendering -> " "Environment -> Default Environment) could not be loaded." -msgstr "無法載入專案è¨å®šä¸æŒ‡å®šçš„é è¨ç’°å¢ƒï¼ˆç®—圖 -> 環境 -> é è¨ç’°å¢ƒï¼‰ã€‚" +msgstr "無法載入專案è¨å®šä¸æŒ‡å®šçš„é è¨ç’°å¢ƒï¼ˆç®—繪 -> 環境 -> é è¨ç’°å¢ƒï¼‰ã€‚" #: scene/main/viewport.cpp msgid "" @@ -12501,13 +12509,13 @@ msgid "" "obtain a size. Otherwise, make it a RenderTarget and assign its internal " "texture to some node for display." msgstr "" -"該 Viewport 尚未被è¨å®šç‚ºç®—åœ–ç›®æ¨™ã€‚è‹¥ä½ æƒ³ç›´æŽ¥å°‡å…¶å…§å®¹é¡¯ç¤ºæ–¼ç•«é¢ä¸Šï¼Œè«‹å°‡å…¶è¨ç‚º " +"該 Viewport 尚未被è¨å®šç‚ºç®—ç¹ªç›®æ¨™ã€‚è‹¥ä½ æƒ³ç›´æŽ¥å°‡å…¶å…§å®¹é¡¯ç¤ºæ–¼ç•«é¢ä¸Šï¼Œè«‹å°‡å…¶è¨ç‚º " "Control çš„å節點以讓其å–得大å°ã€‚å¦å‰‡è«‹å°‡å…¶è¨ç‚º RenderTarget 並指派其內部紋ç†" "為其他節點以顯示。" #: scene/main/viewport.cpp msgid "Viewport size must be greater than 0 to render anything." -msgstr "Viewport 大å°å¿…é ˆå¤§æ–¼ 0 æ‰å¯é€²è¡Œç®—圖。" +msgstr "Viewport 大å°å¿…é ˆå¤§æ–¼ 0 æ‰å¯é€²è¡Œç®—繪。" #: scene/resources/visual_shader_nodes.cpp msgid "Invalid source for preview." @@ -12537,6 +12545,9 @@ msgstr "Varying 變數åªå¯åœ¨é ‚點函å¼ä¸æŒ‡æ´¾ã€‚" msgid "Constants cannot be modified." msgstr "ä¸å¯ä¿®æ”¹å¸¸æ•¸ã€‚" +#~ msgid "Current scene was never saved, please save it prior to running." +#~ msgstr "ç›®å‰çš„å ´æ™¯å¾žæœªè¢«ä¿å˜ï¼Œè«‹å…ˆä¿å˜ä»¥åŸ·è¡Œã€‚" + #~ msgid "Not in resource path." #~ msgstr "ä¸åœ¨è³‡æºè·¯å¾‘ä¸ã€‚" diff --git a/gles_builders.py b/gles_builders.py index 85d0112c9a..eca42236ab 100644 --- a/gles_builders.py +++ b/gles_builders.py @@ -230,59 +230,76 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2 fd.write("\t_FORCE_INLINE_ int get_uniform(Uniforms p_uniform) const { return _get_uniform(p_uniform); }\n\n") if header_data.conditionals: fd.write( - "\t_FORCE_INLINE_ void set_conditional(Conditionals p_conditional,bool p_enable) { _set_conditional(p_conditional,p_enable); }\n\n" + "\t_FORCE_INLINE_ void set_conditional(Conditionals p_conditional,bool p_enable) {" + " _set_conditional(p_conditional,p_enable); }\n\n" ) fd.write("\t#ifdef DEBUG_ENABLED\n ") fd.write( - "\t#define _FU if (get_uniform(p_uniform)<0) return; if (!is_version_valid()) return; ERR_FAIL_COND( get_active()!=this ); \n\n " + "\t#define _FU if (get_uniform(p_uniform)<0) return; if (!is_version_valid()) return; ERR_FAIL_COND(" + " get_active()!=this ); \n\n " ) fd.write("\t#else\n ") fd.write("\t#define _FU if (get_uniform(p_uniform)<0) return; \n\n ") fd.write("\t#endif\n") fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_value) { _FU" + " glUniform1f(get_uniform(p_uniform),p_value); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, double p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, double p_value) { _FU" + " glUniform1f(get_uniform(p_uniform),p_value); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint8_t p_value) { _FU" + " glUniform1i(get_uniform(p_uniform),p_value); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int8_t p_value) { _FU" + " glUniform1i(get_uniform(p_uniform),p_value); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint16_t p_value) { _FU" + " glUniform1i(get_uniform(p_uniform),p_value); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int16_t p_value) { _FU" + " glUniform1i(get_uniform(p_uniform),p_value); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint32_t p_value) { _FU" + " glUniform1i(get_uniform(p_uniform),p_value); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int32_t p_value) { _FU" + " glUniform1i(get_uniform(p_uniform),p_value); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Color& p_color) { _FU GLfloat col[4]={p_color.r,p_color.g,p_color.b,p_color.a}; glUniform4fv(get_uniform(p_uniform),1,col); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Color& p_color) { _FU GLfloat" + " col[4]={p_color.r,p_color.g,p_color.b,p_color.a}; glUniform4fv(get_uniform(p_uniform),1,col); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector2& p_vec2) { _FU GLfloat vec2[2]={p_vec2.x,p_vec2.y}; glUniform2fv(get_uniform(p_uniform),1,vec2); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector2& p_vec2) { _FU GLfloat" + " vec2[2]={p_vec2.x,p_vec2.y}; glUniform2fv(get_uniform(p_uniform),1,vec2); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Size2i& p_vec2) { _FU GLint vec2[2]={p_vec2.x,p_vec2.y}; glUniform2iv(get_uniform(p_uniform),1,vec2); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Size2i& p_vec2) { _FU GLint" + " vec2[2]={p_vec2.x,p_vec2.y}; glUniform2iv(get_uniform(p_uniform),1,vec2); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector3& p_vec3) { _FU GLfloat vec3[3]={p_vec3.x,p_vec3.y,p_vec3.z}; glUniform3fv(get_uniform(p_uniform),1,vec3); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector3& p_vec3) { _FU GLfloat" + " vec3[3]={p_vec3.x,p_vec3.y,p_vec3.z}; glUniform3fv(get_uniform(p_uniform),1,vec3); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b) { _FU glUniform2f(get_uniform(p_uniform),p_a,p_b); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b) { _FU" + " glUniform2f(get_uniform(p_uniform),p_a,p_b); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c) { _FU glUniform3f(get_uniform(p_uniform),p_a,p_b,p_c); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c) { _FU" + " glUniform3f(get_uniform(p_uniform),p_a,p_b,p_c); }\n\n" ) fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c, float p_d) { _FU glUniform4f(get_uniform(p_uniform),p_a,p_b,p_c,p_d); }\n\n" + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c, float p_d) { _FU" + " glUniform4f(get_uniform(p_uniform),p_a,p_b,p_c,p_d); }\n\n" ) fd.write( diff --git a/main/SCsub b/main/SCsub index bf188d7328..ebadefd450 100644 --- a/main/SCsub +++ b/main/SCsub @@ -2,26 +2,33 @@ Import("env") -from platform_methods import run_in_subprocess import main_builders env.main_sources = [] -env.add_source_files(env.main_sources, "*.cpp") +env_main = env.Clone() -env.Depends("#main/splash.gen.h", "#main/splash.png") -env.CommandNoCache("#main/splash.gen.h", "#main/splash.png", run_in_subprocess(main_builders.make_splash)) +env_main.add_source_files(env.main_sources, "*.cpp") -env.Depends("#main/splash_editor.gen.h", "#main/splash_editor.png") -env.CommandNoCache( - "#main/splash_editor.gen.h", "#main/splash_editor.png", run_in_subprocess(main_builders.make_splash_editor) +if env["tests"]: + env_main.Append(CPPDEFINES=["TESTS_ENABLED"]) + +env_main.Depends("#main/splash.gen.h", "#main/splash.png") +env_main.CommandNoCache( + "#main/splash.gen.h", "#main/splash.png", env.Run(main_builders.make_splash, "Building splash screen header."), ) -env.Depends("#main/app_icon.gen.h", "#main/app_icon.png") -env.CommandNoCache("#main/app_icon.gen.h", "#main/app_icon.png", run_in_subprocess(main_builders.make_app_icon)) +env_main.Depends("#main/splash_editor.gen.h", "#main/splash_editor.png") +env_main.CommandNoCache( + "#main/splash_editor.gen.h", + "#main/splash_editor.png", + env.Run(main_builders.make_splash_editor, "Building editor splash screen header."), +) -if env["tools"]: - SConscript("tests/SCsub") +env_main.Depends("#main/app_icon.gen.h", "#main/app_icon.png") +env_main.CommandNoCache( + "#main/app_icon.gen.h", "#main/app_icon.png", env.Run(main_builders.make_app_icon, "Building application icon."), +) -lib = env.add_library("main", env.main_sources) +lib = env_main.add_library("main", env.main_sources) env.Prepend(LIBS=[lib]) diff --git a/main/main.cpp b/main/main.cpp index 35aa99c720..5f791159f9 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -55,7 +55,6 @@ #include "main/performance.h" #include "main/splash.gen.h" #include "main/splash_editor.gen.h" -#include "main/tests/test_main.h" #include "modules/modules_enabled.gen.h" #include "modules/register_module_types.h" #include "platform/register_platform_apis.h" @@ -75,6 +74,10 @@ #include "servers/rendering/rendering_server_wrap_mt.h" #include "servers/xr_server.h" +#ifdef TESTS_ENABLED +#include "tests/test_main.h" +#endif + #ifdef TOOLS_ENABLED #include "editor/doc_data.h" @@ -259,25 +262,20 @@ void Main::print_help(const char *p_binary) { OS::get_singleton()->print(" -h, --help Display this help message.\n"); OS::get_singleton()->print(" --version Display the version string.\n"); OS::get_singleton()->print(" -v, --verbose Use verbose stdout mode.\n"); - OS::get_singleton()->print( - " --quiet Quiet mode, silences stdout messages. Errors are still displayed.\n"); + OS::get_singleton()->print(" --quiet Quiet mode, silences stdout messages. Errors are still displayed.\n"); OS::get_singleton()->print("\n"); OS::get_singleton()->print("Run options:\n"); #ifdef TOOLS_ENABLED OS::get_singleton()->print(" -e, --editor Start the editor instead of running the scene.\n"); - OS::get_singleton()->print( - " -p, --project-manager Start the project manager, even if a project is auto-detected.\n"); + OS::get_singleton()->print(" -p, --project-manager Start the project manager, even if a project is auto-detected.\n"); #endif OS::get_singleton()->print(" -q, --quit Quit after the first iteration.\n"); - OS::get_singleton()->print( - " -l, --language <locale> Use a specific locale (<locale> being a two-letter code).\n"); - OS::get_singleton()->print( - " --path <directory> Path to a project (<directory> must contain a 'project.godot' file).\n"); + OS::get_singleton()->print(" -l, --language <locale> Use a specific locale (<locale> being a two-letter code).\n"); + OS::get_singleton()->print(" --path <directory> Path to a project (<directory> must contain a 'project.godot' file).\n"); OS::get_singleton()->print(" -u, --upwards Scan folders upwards for project.godot file.\n"); OS::get_singleton()->print(" --main-pack <file> Path to a pack (.pck) file to load.\n"); - OS::get_singleton()->print( - " --render-thread <mode> Render thread mode ('unsafe', 'safe', 'separate').\n"); + OS::get_singleton()->print(" --render-thread <mode> Render thread mode ('unsafe', 'safe', 'separate').\n"); OS::get_singleton()->print(" --remote-fs <address> Remote filesystem (<host/IP>[:<port>] address).\n"); OS::get_singleton()->print(" --remote-fs-password <password> Password for remote filesystem.\n"); @@ -318,12 +316,9 @@ void Main::print_help(const char *p_binary) { OS::get_singleton()->print(" --resolution <W>x<H> Request window resolution.\n"); OS::get_singleton()->print(" --position <X>,<Y> Request window position.\n"); OS::get_singleton()->print(" --low-dpi Force low-DPI mode (macOS and Windows only).\n"); - OS::get_singleton()->print( - " --no-window Disable window creation (Windows only). Useful together with --script.\n"); - OS::get_singleton()->print( - " --enable-vsync-via-compositor When vsync is enabled, vsync via the OS' window compositor (Windows only).\n"); - OS::get_singleton()->print( - " --disable-vsync-via-compositor Disable vsync via the OS' window compositor (Windows only).\n"); + OS::get_singleton()->print(" --no-window Disable window creation (Windows only). Useful together with --script.\n"); + OS::get_singleton()->print(" --enable-vsync-via-compositor When vsync is enabled, vsync via the OS' window compositor (Windows only).\n"); + OS::get_singleton()->print(" --disable-vsync-via-compositor Disable vsync via the OS' window compositor (Windows only).\n"); OS::get_singleton()->print(" --single-window Use a single window (no separate subwindows).\n"); OS::get_singleton()->print(" --tablet-driver Tablet input driver ("); for (int i = 0; i < OS::get_singleton()->get_tablet_driver_count(); i++) { @@ -337,66 +332,45 @@ void Main::print_help(const char *p_binary) { OS::get_singleton()->print("Debug options:\n"); OS::get_singleton()->print(" -d, --debug Debug (local stdout debugger).\n"); - OS::get_singleton()->print( - " -b, --breakpoints Breakpoint list as source::line comma-separated pairs, no spaces (use %%20 instead).\n"); + OS::get_singleton()->print(" -b, --breakpoints Breakpoint list as source::line comma-separated pairs, no spaces (use %%20 instead).\n"); OS::get_singleton()->print(" --profiling Enable profiling in the script debugger.\n"); - OS::get_singleton()->print( - " --gpu-abort Abort on GPU errors (usually validation layer errors), may help see the problem if your system freezes.\n"); - OS::get_singleton()->print( - " --remote-debug <uri> Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n"); + OS::get_singleton()->print(" --gpu-abort Abort on GPU errors (usually validation layer errors), may help see the problem if your system freezes.\n"); + OS::get_singleton()->print(" --remote-debug <uri> Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n"); #if defined(DEBUG_ENABLED) && !defined(SERVER_ENABLED) OS::get_singleton()->print(" --debug-collisions Show collision shapes when running the scene.\n"); OS::get_singleton()->print(" --debug-navigation Show navigation polygons when running the scene.\n"); #endif - OS::get_singleton()->print( - " --frame-delay <ms> Simulate high CPU load (delay each frame by <ms> milliseconds).\n"); - OS::get_singleton()->print( - " --time-scale <scale> Force time scale (higher values are faster, 1.0 is normal speed).\n"); - OS::get_singleton()->print( - " --disable-render-loop Disable render loop so rendering only occurs when called explicitly from script.\n"); - OS::get_singleton()->print( - " --disable-crash-handler Disable crash handler when supported by the platform code.\n"); - OS::get_singleton()->print( - " --fixed-fps <fps> Force a fixed number of frames per second. This setting disables real-time synchronization.\n"); + OS::get_singleton()->print(" --frame-delay <ms> Simulate high CPU load (delay each frame by <ms> milliseconds).\n"); + OS::get_singleton()->print(" --time-scale <scale> Force time scale (higher values are faster, 1.0 is normal speed).\n"); + OS::get_singleton()->print(" --disable-render-loop Disable render loop so rendering only occurs when called explicitly from script.\n"); + OS::get_singleton()->print(" --disable-crash-handler Disable crash handler when supported by the platform code.\n"); + OS::get_singleton()->print(" --fixed-fps <fps> Force a fixed number of frames per second. This setting disables real-time synchronization.\n"); OS::get_singleton()->print(" --print-fps Print the frames per second to the stdout.\n"); OS::get_singleton()->print("\n"); OS::get_singleton()->print("Standalone tools:\n"); OS::get_singleton()->print(" -s, --script <script> Run a script.\n"); - OS::get_singleton()->print( - " --check-only Only parse for errors and quit (use with --script).\n"); + OS::get_singleton()->print(" --check-only Only parse for errors and quit (use with --script).\n"); #ifdef TOOLS_ENABLED - OS::get_singleton()->print( - " --export <preset> <path> Export the project using the given preset and matching release template. The preset name should match one defined in export_presets.cfg.\n"); - OS::get_singleton()->print( - " <path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. 'builds/game.exe'). The target directory should exist.\n"); + OS::get_singleton()->print(" --export <preset> <path> Export the project using the given preset and matching release template. The preset name should match one defined in export_presets.cfg.\n"); + OS::get_singleton()->print(" <path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. 'builds/game.exe'). The target directory should exist.\n"); OS::get_singleton()->print(" --export-debug <preset> <path> Same as --export, but using the debug template.\n"); - OS::get_singleton()->print( - " --export-pack <preset> <path> Same as --export, but only export the game pack for the given preset. The <path> extension determines whether it will be in PCK or ZIP format.\n"); - OS::get_singleton()->print( - " --doctool <path> Dump the engine API reference to the given <path> in XML format, merging if existing files are found.\n"); - OS::get_singleton()->print( - " --no-docbase Disallow dumping the base types (used with --doctool).\n"); - OS::get_singleton()->print( - " --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.\n"); + OS::get_singleton()->print(" --export-pack <preset> <path> Same as --export, but only export the game pack for the given preset. The <path> extension determines whether it will be in PCK or ZIP format.\n"); + OS::get_singleton()->print(" --doctool <path> Dump the engine API reference to the given <path> in XML format, merging if existing files are found.\n"); + OS::get_singleton()->print(" --no-docbase Disallow dumping the base types (used with --doctool).\n"); + OS::get_singleton()->print(" --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.\n"); #ifdef DEBUG_METHODS_ENABLED - OS::get_singleton()->print( - " --gdnative-generate-json-api Generate JSON dump of the Godot API for GDNative bindings.\n"); + OS::get_singleton()->print(" --gdnative-generate-json-api Generate JSON dump of the Godot API for GDNative bindings.\n"); #endif - OS::get_singleton()->print(" --test <test> Run a unit test ["); - const char **test_names = tests_get_names(); - const char *comma = ""; - while (*test_names) { - OS::get_singleton()->print("%s'%s'", comma, *test_names); - test_names++; - comma = ", "; - } - OS::get_singleton()->print("].\n"); +#ifdef TESTS_ENABLED + OS::get_singleton()->print(" --test [--help] Run unit tests. Use --test --help for more information.\n"); +#endif + OS::get_singleton()->print("\n"); #endif } int Main::test_entrypoint(int argc, char *argv[], bool &tests_need_run) { -#ifdef TOOLS_ENABLED // templates can't run unit test tool +#ifdef TESTS_ENABLED for (int x = 0; x < argc; x++) { if (strncmp(argv[x], "--test", 6) == 0) { tests_need_run = true; @@ -873,7 +847,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--time-scale") { // force time scale if (I->next()) { - Engine::get_singleton()->set_time_scale(I->next()->get().to_double()); + Engine::get_singleton()->set_time_scale(I->next()->get().to_float()); N = I->next()->next(); } else { OS::get_singleton()->print("Missing time scale argument, aborting.\n"); @@ -1191,7 +1165,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->_vsync_via_compositor = window_vsync_via_compositor; if (tablet_driver == "") { // specified in project.godot - tablet_driver = GLOBAL_DEF_RST("display/window/tablet_driver", OS::get_singleton()->get_tablet_driver_name(0)); + tablet_driver = GLOBAL_DEF_RST_NOVAL("display/window/tablet_driver", OS::get_singleton()->get_tablet_driver_name(0)); } for (int i = 0; i < OS::get_singleton()->get_tablet_driver_count(); i++) { @@ -1245,7 +1219,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } if (audio_driver == "") { // specified in project.godot - audio_driver = GLOBAL_DEF_RST("audio/driver", AudioDriverManager::get_driver(0)->get_name()); + audio_driver = GLOBAL_DEF_RST_NOVAL("audio/driver", AudioDriverManager::get_driver(0)->get_name()); } for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) { @@ -2011,7 +1985,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), + Size2i stretch_size = Size2i(GLOBAL_DEF("display/window/size/width", 0), GLOBAL_DEF("display/window/size/height", 0)); Window::ContentScaleMode cs_sm = Window::CONTENT_SCALE_MODE_DISABLED; diff --git a/main/tests/SCsub b/main/tests/SCsub deleted file mode 100644 index cb1d35b12f..0000000000 --- a/main/tests/SCsub +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/python - -Import("env") - -env.tests_sources = [] -env.add_source_files(env.tests_sources, "*.cpp") - -lib = env.add_library("tests", env.tests_sources) -env.Prepend(LIBS=[lib]) diff --git a/methods.py b/methods.py index 65a460f63d..65b0e2dd6b 100644 --- a/methods.py +++ b/methods.py @@ -4,6 +4,11 @@ import glob import subprocess from collections import OrderedDict +# We need to define our own `Action` method to control the verbosity of output +# and whenever we need to run those commands in a subprocess on some platforms. +from SCons.Script import Action +from platform_methods import run_in_subprocess + def add_source_files(self, sources, files, warn_duplicates=True): # Convert string to list of absolute paths (including expanding wildcard) @@ -549,15 +554,18 @@ def generate_vs_project(env, num_jobs): # in a backslash, so we need to remove this, lest it escape the # last double quote off, confusing MSBuild env["MSVSBUILDCOM"] = build_commandline( - "scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" platform=windows progress=no target=$(Configuration) tools=!tools! -j" + "scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" platform=windows progress=no target=$(Configuration)" + " tools=!tools! -j" + str(num_jobs) ) env["MSVSREBUILDCOM"] = build_commandline( - "scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" platform=windows progress=no target=$(Configuration) tools=!tools! vsproj=yes -j" + "scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" platform=windows progress=no target=$(Configuration)" + " tools=!tools! vsproj=yes -j" + str(num_jobs) ) env["MSVSCLEANCOM"] = build_commandline( - "scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" --clean platform=windows progress=no target=$(Configuration) tools=!tools! -j" + "scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" --clean platform=windows progress=no" + " target=$(Configuration) tools=!tools! -j" + str(num_jobs) ) @@ -618,6 +626,14 @@ def CommandNoCache(env, target, sources, command, **args): return result +def Run(env, function, short_message, subprocess=True): + output_print = short_message if not env["verbose"] else "" + if not subprocess: + return Action(function, output_print) + else: + return Action(run_in_subprocess(function), output_print) + + def detect_darwin_sdk_path(platform, env): sdk_name = "" if platform == "osx": diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj index 54dda2563d..9a1143a21a 100644 --- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj +++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj @@ -12,6 +12,8 @@ $modules_buildfile 1FF8DBB11FBA9DE1009DE660 /* dummy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1FF8DBB01FBA9DE1009DE660 /* dummy.cpp */; }; D07CD44E1C5D589C00B7FB28 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D07CD44D1C5D589C00B7FB28 /* Images.xcassets */; }; + 9039D3BE24C093AC0020482C /* MoltenVK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9039D3BD24C093AC0020482C /* MoltenVK.a */; }; + 9073252C24BF980B0063BCD4 /* vulkan in Resources */ = {isa = PBXBuildFile; fileRef = 905036DC24BF932E00301046 /* vulkan */; }; D0BCFE4618AEBDA2004A7AAE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D0BCFE4418AEBDA2004A7AAE /* InfoPlist.strings */; }; D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */ = {isa = PBXBuildFile; fileRef = D0BCFE7718AEBFEB004A7AAE /* $binary.pck */; }; $pbx_launch_screen_build_reference @@ -37,6 +39,8 @@ $modules_fileref 1FF4C1881F584E6300A41E41 /* $binary.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "$binary.entitlements"; sourceTree = "<group>"; }; 1FF8DBB01FBA9DE1009DE660 /* dummy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = dummy.cpp; sourceTree = "<group>"; }; + 9039D3BD24C093AC0020482C /* MoltenVK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = MoltenVK; path = MoltenVK.a; sourceTree = "<group>"; }; + 905036DC24BF932E00301046 /* vulkan */ = {isa = PBXFileReference; lastKnownFileType = folder; name = vulkan; path = "$binary/vulkan"; sourceTree = "<group>"; }; D07CD44D1C5D589C00B7FB28 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; }; D0BCFE3418AEBDA2004A7AAE /* $binary.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "$binary.app"; sourceTree = BUILT_PRODUCTS_DIR; }; D0BCFE4318AEBDA2004A7AAE /* $binary-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "$binary-Info.plist"; sourceTree = "<group>"; }; @@ -52,6 +56,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 9039D3BE24C093AC0020482C /* MoltenVK.a in Frameworks */, DEADBEEF2F582BE20003B888 /* $binary.a */, $modules_buildphase $additional_pbx_frameworks_build @@ -64,6 +69,7 @@ D0BCFE2B18AEBDA2004A7AAE = { isa = PBXGroup; children = ( + 905036DC24BF932E00301046 /* vulkan */, 1F1575711F582BE20003B888 /* dylibs */, D0BCFE7718AEBFEB004A7AAE /* $binary.pck */, D0BCFE4118AEBDA2004A7AAE /* $binary */, @@ -84,6 +90,7 @@ D0BCFE3618AEBDA2004A7AAE /* Frameworks */ = { isa = PBXGroup; children = ( + 9039D3BD24C093AC0020482C /* MoltenVK.a */, DEADBEEF1F582BE20003B888 /* $binary.a */, $modules_buildgrp $additional_pbx_frameworks_refs @@ -248,6 +255,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9073252C24BF980B0063BCD4 /* vulkan in Resources */, D07CD44E1C5D589C00B7FB28 /* Images.xcassets in Resources */, D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */, $pbx_launch_screen_build_phase @@ -319,7 +327,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; OTHER_LDFLAGS = "$linker_flags"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -358,7 +366,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; OTHER_LDFLAGS = "$linker_flags"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/misc/dist/ios_xcode/godot_ios/vulkan/icd.d/MoltenVK_icd.json b/misc/dist/ios_xcode/godot_ios/vulkan/icd.d/MoltenVK_icd.json new file mode 100644 index 0000000000..7501cb548c --- /dev/null +++ b/misc/dist/ios_xcode/godot_ios/vulkan/icd.d/MoltenVK_icd.json @@ -0,0 +1,7 @@ +{ + "file_format_version" : "1.0.0", + "ICD": { + "library_path": "./../../Frameworks/MoltenVK.framework/MoltenVK", + "api_version" : "1.0.0" + } +} diff --git a/misc/scripts/black_format.sh b/misc/scripts/black_format.sh index 04dfe32f60..f93e8cbc2a 100755 --- a/misc/scripts/black_format.sh +++ b/misc/scripts/black_format.sh @@ -16,11 +16,9 @@ PY_FILES=$(find \( -path "./.git" \ black -l 120 $PY_FILES git diff > patch.patch -FILESIZE="$(stat -c%s patch.patch)" -MAXSIZE=5 # If no patch has been generated all is OK, clean up, and exit. -if (( FILESIZE < MAXSIZE )); then +if [ ! -s patch.patch ] ; then printf "Files in this commit comply with the black style rules.\n" rm -f patch.patch exit 0 diff --git a/misc/scripts/clang_format.sh b/misc/scripts/clang_format.sh index 5131f7fe33..e686305dea 100755 --- a/misc/scripts/clang_format.sh +++ b/misc/scripts/clang_format.sh @@ -39,11 +39,9 @@ while IFS= read -rd '' f; do done git diff > patch.patch -FILESIZE="$(stat -c%s patch.patch)" -MAXSIZE=5 # If no patch has been generated all is OK, clean up, and exit. -if (( FILESIZE < MAXSIZE )); then +if [ ! -s patch.patch ] ; then printf "Files in this commit comply with the clang-format style rules.\n" rm -f patch.patch exit 0 diff --git a/misc/scripts/file_format.sh b/misc/scripts/file_format.sh index 30988e51c6..c570ec23a7 100755 --- a/misc/scripts/file_format.sh +++ b/misc/scripts/file_format.sh @@ -1,7 +1,13 @@ #!/usr/bin/env bash # This script ensures proper POSIX text file formatting and a few other things. -# This is supplementary to clang-black-format.sh, but should be run before it. +# This is supplementary to clang_format.sh and black_format.sh, but should be +# run before them. + +# We need dos2unix and recode. +if [ ! -x "$(command -v dos2unix)" -o ! -x "$(command -v recode)" ]; then + printf "Install 'dos2unix' and 'recode' to use this script.\n" +fi set -uo pipefail IFS=$'\n\t' @@ -25,26 +31,21 @@ while IFS= read -rd '' f; do elif [[ "$f" == "platform/android/java/lib/src/com/google"* ]]; then continue fi - # Ensures that files are UTF-8 formatted. + # Ensure that files are UTF-8 formatted. recode UTF-8 "$f" 2> /dev/null - # Ensures that files have LF line endings. + # Ensure that files have LF line endings and do not contain a BOM. dos2unix "$f" 2> /dev/null - # Ensures that files do not contain a BOM. - sed -i '1s/^\xEF\xBB\xBF//' "$f" - # Ensures that files end with newline characters. - tail -c1 < "$f" | read -r _ || echo >> "$f"; - # Remove trailing space characters. - sed -z -i 's/\x20\x0A/\x0A/g' "$f" + # Remove trailing space characters and ensures that files end + # with newline characters. -l option handles newlines conveniently. + perl -i -ple 's/\s*$//g' "$f" # Remove the character sequence "== true" if it has a leading space. - sed -z -i 's/\x20== true//g' "$f" + perl -i -pe 's/\x20== true//g' "$f" done git diff > patch.patch -FILESIZE="$(stat -c%s patch.patch)" -MAXSIZE=5 # If no patch has been generated all is OK, clean up, and exit. -if (( FILESIZE < MAXSIZE )); then +if [ ! -s patch.patch ] ; then printf "Files in this commit comply with the formatting rules.\n" rm -f patch.patch exit 0 diff --git a/modules/SCsub b/modules/SCsub index 9155a53eaf..edfc4ed9c6 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -1,16 +1,39 @@ #!/usr/bin/env python -Import("env") - import modules_builders import os +Import("env") + env_modules = env.Clone() Export("env_modules") # Header with MODULE_*_ENABLED defines. -env.CommandNoCache("modules_enabled.gen.h", Value(env.module_list), modules_builders.generate_modules_enabled) +env.CommandNoCache( + "modules_enabled.gen.h", + Value(env.module_list), + env.Run( + modules_builders.generate_modules_enabled, + "Generating enabled modules header.", + # NOTE: No need to run in subprocess since this is still executed serially. + subprocess=False, + ), +) + +# Header to be included in `tests/test_main.cpp` to run module-specific tests. +if env["tests"]: + env.CommandNoCache( + "modules_tests.gen.h", + Value(env.module_list), + env.Run( + modules_builders.generate_modules_tests, + "Generating modules tests header.", + # NOTE: No need to run in subprocess since this is still executed serially. + subprocess=False, + ), + ) + env.AlwaysBuild("modules_tests.gen.h") vs_sources = [] # libmodule_<name>.a for each active module. diff --git a/modules/arkit/arkit_interface.h b/modules/arkit/arkit_interface.h index 1044f3cf6f..5a2c50e213 100644 --- a/modules/arkit/arkit_interface.h +++ b/modules/arkit/arkit_interface.h @@ -60,8 +60,8 @@ private: float eye_height, z_near, z_far; Ref<CameraFeed> feed; - int image_width[2]; - int image_height[2]; + size_t image_width[2]; + size_t image_height[2]; Vector<uint8_t> img_data[2]; struct anchor_map { @@ -84,9 +84,9 @@ public: void start_session(); void stop_session(); - bool get_anchor_detection_is_enabled() const; - void set_anchor_detection_is_enabled(bool p_enable); - virtual int get_camera_feed_id(); + bool get_anchor_detection_is_enabled() const override; + void set_anchor_detection_is_enabled(bool p_enable) override; + virtual int get_camera_feed_id() override; bool get_light_estimation_is_enabled() const; void set_light_estimation_is_enabled(bool p_enable); @@ -97,22 +97,22 @@ public: /* while Godot has its own raycast logic this takes ARKits camera into account and hits on any ARAnchor */ Array raycast(Vector2 p_screen_coord); - void notification(int p_what); + virtual void notification(int p_what) override; - virtual StringName get_name() const; - virtual int get_capabilities() const; + virtual StringName get_name() const override; + virtual int get_capabilities() const override; - virtual bool is_initialized() const; - virtual bool initialize(); - virtual void uninitialize(); + virtual bool is_initialized() const override; + virtual bool initialize() override; + virtual void uninitialize() override; - virtual Size2 get_render_targetsize(); - virtual bool is_stereo(); - virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform); - virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far); - virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect); + virtual Size2 get_render_targetsize() override; + virtual bool is_stereo() override; + virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) override; + virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; + virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override; - virtual void process(); + virtual void process() override; // called by delegate (void * because C++ and Obj-C don't always mix, should really change all platform/iphone/*.cpp files to .mm) void _add_or_update_anchor(void *p_anchor); diff --git a/modules/arkit/arkit_interface.mm b/modules/arkit/arkit_interface.mm index 7de824815a..3fb2cc933d 100644 --- a/modules/arkit/arkit_interface.mm +++ b/modules/arkit/arkit_interface.mm @@ -42,7 +42,9 @@ #include "arkit_session_delegate.h" // just a dirty workaround for now, declare these as globals. I'll probably encapsulate ARSession and associated logic into an mm object and change ARKitInterface to a normal cpp object that consumes it. +API_AVAILABLE(ios(11.0)) ARSession *ar_session; + ARKitSessionDelegate *ar_delegate; NSTimeInterval last_timestamp; @@ -55,22 +57,28 @@ void ARKitInterface::start_session() { if (initialized) { print_line("Starting ARKit session"); - Class ARWorldTrackingConfigurationClass = NSClassFromString(@"ARWorldTrackingConfiguration"); - ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfigurationClass new]; + if (@available(iOS 11, *)) { + Class ARWorldTrackingConfigurationClass = NSClassFromString(@"ARWorldTrackingConfiguration"); + ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfigurationClass new]; - configuration.lightEstimationEnabled = light_estimation_is_enabled; - if (plane_detection_is_enabled) { - configuration.planeDetection = ARPlaneDetectionVertical | ARPlaneDetectionHorizontal; - } else { - configuration.planeDetection = 0; - } + configuration.lightEstimationEnabled = light_estimation_is_enabled; + if (plane_detection_is_enabled) { + if (@available(iOS 11.3, *)) { + configuration.planeDetection = ARPlaneDetectionVertical | ARPlaneDetectionHorizontal; + } else { + configuration.planeDetection = ARPlaneDetectionHorizontal; + } + } else { + configuration.planeDetection = 0; + } - // make sure our camera is on - if (feed.is_valid()) { - feed->set_active(true); - } + // make sure our camera is on + if (feed.is_valid()) { + feed->set_active(true); + } - [ar_session runWithConfiguration:configuration]; + [ar_session runWithConfiguration:configuration]; + } } } @@ -84,7 +92,9 @@ void ARKitInterface::stop_session() { feed->set_active(false); } - [ar_session pause]; + if (@available(iOS 11.0, *)) { + [ar_session pause]; + } } } @@ -92,12 +102,12 @@ void ARKitInterface::notification(int p_what) { // TODO, this is not being called, need to find out why, possibly because this is not a node. // in that case we need to find a way to get these notifications! switch (p_what) { - case MainLoop::NOTIFICATION_WM_FOCUS_IN: { + case DisplayServer::WINDOW_EVENT_FOCUS_IN: { print_line("Focus in"); start_session(); }; break; - case MainLoop::NOTIFICATION_WM_FOCUS_OUT: { + case DisplayServer::WINDOW_EVENT_FOCUS_OUT: { print_line("Focus out"); stop_session(); @@ -162,37 +172,42 @@ int ARKitInterface::get_capabilities() const { } Array ARKitInterface::raycast(Vector2 p_screen_coord) { - Array arr; - Size2 screen_size = OS::get_singleton()->get_window_size(); - CGPoint point; - point.x = p_screen_coord.x / screen_size.x; - point.y = p_screen_coord.y / screen_size.y; - - ///@TODO maybe give more options here, for now we're taking just ARAchors into account that were found during plane detection keeping their size into account - NSArray<ARHitTestResult *> *results = [ar_session.currentFrame hittest:point types:ARHitTestResultTypeExistingPlaneUsingExtent]; - - for (ARHitTestResult *result in results) { - Transform transform; - - matrix_float4x4 m44 = result.worldTransform; - transform.basis.elements[0].x = m44.columns[0][0]; - transform.basis.elements[1].x = m44.columns[0][1]; - transform.basis.elements[2].x = m44.columns[0][2]; - transform.basis.elements[0].y = m44.columns[1][0]; - transform.basis.elements[1].y = m44.columns[1][1]; - transform.basis.elements[2].y = m44.columns[1][2]; - transform.basis.elements[0].z = m44.columns[2][0]; - transform.basis.elements[1].z = m44.columns[2][1]; - transform.basis.elements[2].z = m44.columns[2][2]; - transform.origin.x = m44.columns[3][0]; - transform.origin.y = m44.columns[3][1]; - transform.origin.z = m44.columns[3][2]; - - /* important, NOT scaled to world_scale !! */ - arr.push_back(transform); - } + if (@available(iOS 11, *)) { + Array arr; + Size2 screen_size = DisplayServer::get_singleton()->screen_get_size(); + CGPoint point; + point.x = p_screen_coord.x / screen_size.x; + point.y = p_screen_coord.y / screen_size.y; + + ///@TODO maybe give more options here, for now we're taking just ARAchors into account that were found during plane detection keeping their size into account + + NSArray<ARHitTestResult *> *results = [ar_session.currentFrame hitTest:point types:ARHitTestResultTypeExistingPlaneUsingExtent]; + + for (ARHitTestResult *result in results) { + Transform transform; + + matrix_float4x4 m44 = result.worldTransform; + transform.basis.elements[0].x = m44.columns[0][0]; + transform.basis.elements[1].x = m44.columns[0][1]; + transform.basis.elements[2].x = m44.columns[0][2]; + transform.basis.elements[0].y = m44.columns[1][0]; + transform.basis.elements[1].y = m44.columns[1][1]; + transform.basis.elements[2].y = m44.columns[1][2]; + transform.basis.elements[0].z = m44.columns[2][0]; + transform.basis.elements[1].z = m44.columns[2][1]; + transform.basis.elements[2].z = m44.columns[2][2]; + transform.origin.x = m44.columns[3][0]; + transform.origin.y = m44.columns[3][1]; + transform.origin.z = m44.columns[3][2]; + + /* important, NOT scaled to world_scale !! */ + arr.push_back(transform); + } - return arr; + return arr; + } else { + return Array(); + } } void ARKitInterface::_bind_methods() { @@ -221,51 +236,55 @@ bool ARKitInterface::initialize() { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, false); - if (!initialized) { - print_line("initializing ARKit"); + if (@available(iOS 11, *)) { + if (!initialized) { + print_line("initializing ARKit"); - // create our ar session and delegate - Class ARSessionClass = NSClassFromString(@"ARSession"); - if (ARSessionClass == Nil) { - void *arkit_handle = dlopen("/System/Library/Frameworks/ARKit.framework/ARKit", RTLD_NOW); - if (arkit_handle) { - ARSessionClass = NSClassFromString(@"ARSession"); - } else { - print_line("ARKit init failed"); - return false; + // create our ar session and delegate + Class ARSessionClass = NSClassFromString(@"ARSession"); + if (ARSessionClass == Nil) { + void *arkit_handle = dlopen("/System/Library/Frameworks/ARKit.framework/ARKit", RTLD_NOW); + if (arkit_handle) { + ARSessionClass = NSClassFromString(@"ARSession"); + } else { + print_line("ARKit init failed"); + return false; + } } - } - ar_session = [ARSessionClass new]; - ar_delegate = [ARKitSessionDelegate new]; - ar_delegate.arkit_interface = this; - ar_session.delegate = ar_delegate; + ar_session = [ARSessionClass new]; + ar_delegate = [ARKitSessionDelegate new]; + ar_delegate.arkit_interface = this; + ar_session.delegate = ar_delegate; - // reset our transform - transform = Transform(); + // reset our transform + transform = Transform(); - // make this our primary interface - xr_server->set_primary_interface(this); + // make this our primary interface + xr_server->set_primary_interface(this); - // make sure we have our feed setup - if (feed.is_null()) { - feed.instance(); - feed->set_name("ARKit"); + // make sure we have our feed setup + if (feed.is_null()) { + feed.instance(); + feed->set_name("ARKit"); - CameraServer *cs = CameraServer::get_singleton(); - if (cs != NULL) { - cs->add_feed(feed); + CameraServer *cs = CameraServer::get_singleton(); + if (cs != NULL) { + cs->add_feed(feed); + } } - } - feed->set_active(true); + feed->set_active(true); - // yeah! - initialized = true; + // yeah! + initialized = true; - // Start our session... - start_session(); - } + // Start our session... + start_session(); + } - return true; + return true; + } else { + return false; + } } void ARKitInterface::uninitialize() { @@ -286,9 +305,12 @@ void ARKitInterface::uninitialize() { remove_all_anchors(); - [ar_session release]; + if (@available(iOS 11.0, *)) { + [ar_session release]; + ar_session = NULL; + } [ar_delegate release]; - ar_session = NULL; + ar_delegate = NULL; initialized = false; session_was_started = false; @@ -296,15 +318,15 @@ void ARKitInterface::uninitialize() { } Size2 ARKitInterface::get_render_targetsize() { - _THREAD_SAFE_METHOD_ + // _THREAD_SAFE_METHOD_ - Size2 target_size = OS::get_singleton()->get_window_size(); + Size2 target_size = DisplayServer::get_singleton()->screen_get_size(); return target_size; } Transform ARKitInterface::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) { - _THREAD_SAFE_METHOD_ + // _THREAD_SAFE_METHOD_ Transform transform_for_eye; @@ -336,7 +358,7 @@ CameraMatrix ARKitInterface::get_projection_for_eye(XRInterface::Eyes p_eye, rea } void ARKitInterface::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) { - _THREAD_SAFE_METHOD_ + // _THREAD_SAFE_METHOD_ // We must have a valid render target ERR_FAIL_COND(!p_render_target.is_valid()); @@ -345,15 +367,15 @@ void ARKitInterface::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target ERR_FAIL_COND(p_screen_rect == Rect2()); // get the size of our screen - Rect2 screen_rect = p_screen_rect; + // Rect2 screen_rect = p_screen_rect; // screen_rect.position.x += screen_rect.size.x; // screen_rect.size.x = -screen_rect.size.x; // screen_rect.position.y += screen_rect.size.y; // screen_rect.size.y = -screen_rect.size.y; - VSG::rasterizer->set_current_render_target(RID()); - VSG::rasterizer->blit_render_target_to_screen(p_render_target, screen_rect, 0); + // VSG::rasterizer->set_current_render_target(RID()); + // VSG::rasterizer->blit_render_target_to_screen(p_render_target, screen_rect, 0); } XRPositionalTracker *ARKitInterface::get_anchor_for_uuid(const unsigned char *p_uuid) { @@ -432,7 +454,7 @@ void ARKitInterface::remove_all_anchors() { } void ARKitInterface::process() { - _THREAD_SAFE_METHOD_ + // _THREAD_SAFE_METHOD_ if (@available(iOS 11.0, *)) { if (initialized) { @@ -443,8 +465,16 @@ void ARKitInterface::process() { last_timestamp = current_frame.timestamp; // get some info about our screen and orientation - Size2 screen_size = OS::get_singleton()->get_window_size(); - UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; + Size2 screen_size = DisplayServer::get_singleton()->screen_get_size(); + UIInterfaceOrientation orientation = UIInterfaceOrientationUnknown; + + if (@available(iOS 13, *)) { + orientation = [UIApplication sharedApplication].delegate.window.windowScene.interfaceOrientation; +#if !defined(TARGET_OS_SIMULATOR) || !TARGET_OS_SIMULATOR + } else { + orientation = [[UIApplication sharedApplication] statusBarOrientation]; +#endif + } // Grab our camera image for our backbuffer CVPixelBufferRef pixelBuffer = current_frame.capturedImage; @@ -475,27 +505,27 @@ void ARKitInterface::process() { { // do Y - int new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0); - int new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0); - int bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0); + size_t new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0); + size_t new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0); + size_t bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0); if ((image_width[0] != new_width) || (image_height[0] != new_height)) { printf("- Camera padding l:%lu r:%lu t:%lu b:%lu\n", extraLeft, extraRight, extraTop, extraBottom); - printf("- Camera Y plane size: %i, %i - %i\n", new_width, new_height, bytes_per_row); + printf("- Camera Y plane size: %lu, %lu - %lu\n", new_width, new_height, bytes_per_row); image_width[0] = new_width; image_height[0] = new_height; img_data[0].resize(new_width * new_height); } - uint8_t *w = img_data[0].write(); + uint8_t *w = img_data[0].ptrw(); if (new_width == bytes_per_row) { - memcpy(w.ptr(), dataY, new_width * new_height); + memcpy(w, dataY, new_width * new_height); } else { - int offset_a = 0; - int offset_b = extraLeft + (extraTop * bytes_per_row); - for (int r = 0; r < new_height; r++) { - memcpy(w.ptr() + offset_a, dataY + offset_b, new_width); + size_t offset_a = 0; + size_t offset_b = extraLeft + (extraTop * bytes_per_row); + for (size_t r = 0; r < new_height; r++) { + memcpy(w + offset_a, dataY + offset_b, new_width); offset_a += new_width; offset_b += bytes_per_row; } @@ -507,26 +537,26 @@ void ARKitInterface::process() { { // do CbCr - int new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1); - int new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1); - int bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0); + size_t new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1); + size_t new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1); + size_t bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0); if ((image_width[1] != new_width) || (image_height[1] != new_height)) { - printf("- Camera CbCr plane size: %i, %i - %i\n", new_width, new_height, bytes_per_row); + printf("- Camera CbCr plane size: %lu, %lu - %lu\n", new_width, new_height, bytes_per_row); image_width[1] = new_width; image_height[1] = new_height; img_data[1].resize(2 * new_width * new_height); } - uint8_t *w = img_data[1].write(); + uint8_t *w = img_data[1].ptrw(); if ((2 * new_width) == bytes_per_row) { - memcpy(w.ptr(), dataCbCr, 2 * new_width * new_height); + memcpy(w, dataCbCr, 2 * new_width * new_height); } else { - int offset_a = 0; - int offset_b = extraLeft + (extraTop * bytes_per_row); - for (int r = 0; r < new_height; r++) { - memcpy(w.ptr() + offset_a, dataCbCr + offset_b, 2 * new_width); + size_t offset_a = 0; + size_t offset_b = extraLeft + (extraTop * bytes_per_row); + for (size_t r = 0; r < new_height; r++) { + memcpy(w + offset_a, dataCbCr + offset_b, 2 * new_width); offset_a += 2 * new_width; offset_b += bytes_per_row; } @@ -658,69 +688,78 @@ void ARKitInterface::process() { } void ARKitInterface::_add_or_update_anchor(void *p_anchor) { - _THREAD_SAFE_METHOD_ - - ARAnchor *anchor = (ARAnchor *)p_anchor; - - unsigned char uuid[16]; - [anchor.identifier getUUIDBytes:uuid]; - - XRPositionalTracker *tracker = get_anchor_for_uuid(uuid); - if (tracker != NULL) { - // lets update our mesh! (using Arjens code as is for now) - // we should also probably limit how often we do this... + // _THREAD_SAFE_METHOD_ - // can we safely cast this? - ARPlaneAnchor *planeAnchor = (ARPlaneAnchor *)anchor; - - if (planeAnchor.geometry.triangleCount > 0) { - Ref<SurfaceTool> surftool; - surftool.instance(); - surftool->begin(Mesh::PRIMITIVE_TRIANGLES); + if (@available(iOS 11.0, *)) { + ARAnchor *anchor = (ARAnchor *)p_anchor; + + unsigned char uuid[16]; + [anchor.identifier getUUIDBytes:uuid]; + + XRPositionalTracker *tracker = get_anchor_for_uuid(uuid); + if (tracker != NULL) { + // lets update our mesh! (using Arjens code as is for now) + // we should also probably limit how often we do this... + + // can we safely cast this? + ARPlaneAnchor *planeAnchor = (ARPlaneAnchor *)anchor; + + if (@available(iOS 11.3, *)) { + if (planeAnchor.geometry.triangleCount > 0) { + Ref<SurfaceTool> surftool; + surftool.instance(); + surftool->begin(Mesh::PRIMITIVE_TRIANGLES); + + for (int j = planeAnchor.geometry.triangleCount * 3 - 1; j >= 0; j--) { + int16_t index = planeAnchor.geometry.triangleIndices[j]; + simd_float3 vrtx = planeAnchor.geometry.vertices[index]; + simd_float2 textcoord = planeAnchor.geometry.textureCoordinates[index]; + surftool->add_uv(Vector2(textcoord[0], textcoord[1])); + surftool->add_color(Color(0.8, 0.8, 0.8)); + surftool->add_vertex(Vector3(vrtx[0], vrtx[1], vrtx[2])); + } - for (int j = planeAnchor.geometry.triangleCount * 3 - 1; j >= 0; j--) { - int16_t index = planeAnchor.geometry.triangleIndices[j]; - simd_float3 vrtx = planeAnchor.geometry.vertices[index]; - simd_float2 textcoord = planeAnchor.geometry.textureCoordinates[index]; - surftool->add_uv(Vector2(textcoord[0], textcoord[1])); - surftool->add_color(Color(0.8, 0.8, 0.8)); - surftool->add_vertex(Vector3(vrtx[0], vrtx[1], vrtx[2])); + surftool->generate_normals(); + tracker->set_mesh(surftool->commit()); + } else { + Ref<Mesh> nomesh; + tracker->set_mesh(nomesh); + } + } else { + Ref<Mesh> nomesh; + tracker->set_mesh(nomesh); } - surftool->generate_normals(); - tracker->set_mesh(surftool->commit()); - } else { - Ref<Mesh> nomesh; - tracker->set_mesh(nomesh); + // Note, this also contains a scale factor which gives us an idea of the size of the anchor + // We may extract that in our XRAnchor class + Basis b; + matrix_float4x4 m44 = anchor.transform; + b.elements[0].x = m44.columns[0][0]; + b.elements[1].x = m44.columns[0][1]; + b.elements[2].x = m44.columns[0][2]; + b.elements[0].y = m44.columns[1][0]; + b.elements[1].y = m44.columns[1][1]; + b.elements[2].y = m44.columns[1][2]; + b.elements[0].z = m44.columns[2][0]; + b.elements[1].z = m44.columns[2][1]; + b.elements[2].z = m44.columns[2][2]; + tracker->set_orientation(b); + tracker->set_rw_position(Vector3(m44.columns[3][0], m44.columns[3][1], m44.columns[3][2])); } - - // Note, this also contains a scale factor which gives us an idea of the size of the anchor - // We may extract that in our XRAnchor class - Basis b; - matrix_float4x4 m44 = anchor.transform; - b.elements[0].x = m44.columns[0][0]; - b.elements[1].x = m44.columns[0][1]; - b.elements[2].x = m44.columns[0][2]; - b.elements[0].y = m44.columns[1][0]; - b.elements[1].y = m44.columns[1][1]; - b.elements[2].y = m44.columns[1][2]; - b.elements[0].z = m44.columns[2][0]; - b.elements[1].z = m44.columns[2][1]; - b.elements[2].z = m44.columns[2][2]; - tracker->set_orientation(b); - tracker->set_rw_position(Vector3(m44.columns[3][0], m44.columns[3][1], m44.columns[3][2])); } } void ARKitInterface::_remove_anchor(void *p_anchor) { - _THREAD_SAFE_METHOD_ + // _THREAD_SAFE_METHOD_ - ARAnchor *anchor = (ARAnchor *)p_anchor; + if (@available(iOS 11.0, *)) { + ARAnchor *anchor = (ARAnchor *)p_anchor; - unsigned char uuid[16]; - [anchor.identifier getUUIDBytes:uuid]; + unsigned char uuid[16]; + [anchor.identifier getUUIDBytes:uuid]; - remove_anchor_for_uuid(uuid); + remove_anchor_for_uuid(uuid); + } } ARKitInterface::ARKitInterface() { @@ -728,7 +767,9 @@ ARKitInterface::ARKitInterface() { session_was_started = false; plane_detection_is_enabled = false; light_estimation_is_enabled = false; - ar_session = NULL; + if (@available(iOS 11.0, *)) { + ar_session = NULL; + } z_near = 0.01; z_far = 1000.0; projection.set_perspective(60.0, 1.0, z_near, z_far, false); diff --git a/modules/arkit/arkit_session_delegate.h b/modules/arkit/arkit_session_delegate.h index 158b80a60a..df98bf506e 100644 --- a/modules/arkit/arkit_session_delegate.h +++ b/modules/arkit/arkit_session_delegate.h @@ -42,9 +42,9 @@ class ARKitInterface; @property(nonatomic) ARKitInterface *arkit_interface; -- (void)session:(ARSession *)session didAddAnchors:(NSArray<ARAnchor *> *)anchors; -- (void)session:(ARSession *)session didRemoveAnchors:(NSArray<ARAnchor *> *)anchors; -- (void)session:(ARSession *)session didUpdateAnchors:(NSArray<ARAnchor *> *)anchors; +- (void)session:(ARSession *)session didAddAnchors:(NSArray<ARAnchor *> *)anchors API_AVAILABLE(ios(11.0)); +- (void)session:(ARSession *)session didRemoveAnchors:(NSArray<ARAnchor *> *)anchors API_AVAILABLE(ios(11.0)); +- (void)session:(ARSession *)session didUpdateAnchors:(NSArray<ARAnchor *> *)anchors API_AVAILABLE(ios(11.0)); @end #endif /* !ARKIT_SESSION_DELEGATE_H */ diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp index edbd9565b8..b35019bea3 100644 --- a/modules/bullet/area_bullet.cpp +++ b/modules/bullet/area_bullet.cpp @@ -65,14 +65,11 @@ AreaBullet::~AreaBullet() { } void AreaBullet::dispatch_callbacks() { - if (!isScratched) { - return; - } - isScratched = false; + RigidCollisionObjectBullet::dispatch_callbacks(); // Reverse order because I've to remove EXIT objects for (int i = overlappingObjects.size() - 1; 0 <= i; --i) { - OverlappingObjectData &otherObj = overlappingObjects.write[i]; + OverlappingObjectData &otherObj = overlappingObjects[i]; switch (otherObj.state) { case OVERLAP_STATE_ENTER: @@ -112,10 +109,9 @@ void AreaBullet::call_event(CollisionObjectBullet *p_otherObject, PhysicsServer3 } void AreaBullet::scratch() { - if (isScratched) { - return; + if (space != nullptr) { + space->add_to_pre_flush_queue(this); } - isScratched = true; } void AreaBullet::clear_overlaps(bool p_notify) { @@ -173,9 +169,9 @@ void AreaBullet::do_reload_body() { void AreaBullet::set_space(SpaceBullet *p_space) { // Clear the old space if there is one + if (space) { clear_overlaps(false); - isScratched = false; // Remove this object form the physics world space->unregister_collision_object(this); @@ -187,10 +183,11 @@ void AreaBullet::set_space(SpaceBullet *p_space) { if (space) { space->register_collision_object(this); reload_body(); + scratch(); } } -void AreaBullet::on_collision_filters_change() { +void AreaBullet::do_reload_collision_filters() { if (space) { space->reload_collision_filters(this); } @@ -204,13 +201,13 @@ void AreaBullet::add_overlap(CollisionObjectBullet *p_otherObject) { void AreaBullet::put_overlap_as_exit(int p_index) { scratch(); - overlappingObjects.write[p_index].state = OVERLAP_STATE_EXIT; + overlappingObjects[p_index].state = OVERLAP_STATE_EXIT; } void AreaBullet::put_overlap_as_inside(int p_index) { // This check is required to be sure this body was inside if (OVERLAP_STATE_DIRTY == overlappingObjects[p_index].state) { - overlappingObjects.write[p_index].state = OVERLAP_STATE_INSIDE; + overlappingObjects[p_index].state = OVERLAP_STATE_INSIDE; } } diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h index 12272092f7..51fbc1f71d 100644 --- a/modules/bullet/area_bullet.h +++ b/modules/bullet/area_bullet.h @@ -32,7 +32,7 @@ #define AREABULLET_H #include "collision_object_bullet.h" -#include "core/vector.h" +#include "core/local_vector.h" #include "servers/physics_server_3d.h" #include "space_bullet.h" @@ -83,7 +83,7 @@ private: Variant *call_event_res_ptr[5]; btGhostObject *btGhost; - Vector<OverlappingObjectData> overlappingObjects; + LocalVector<OverlappingObjectData> overlappingObjects; bool monitorable = true; PhysicsServer3D::AreaSpaceOverrideMode spOv_mode = PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED; @@ -96,8 +96,6 @@ private: real_t spOv_angularDump = 0.1; int spOv_priority = 0; - bool isScratched = false; - InOutEventCallback eventsCallbacks[2]; public: @@ -139,11 +137,11 @@ public: _FORCE_INLINE_ void set_spOv_priority(int p_priority) { spOv_priority = p_priority; } _FORCE_INLINE_ int get_spOv_priority() { return spOv_priority; } - virtual void main_shape_changed(); - virtual void do_reload_body(); - virtual void set_space(SpaceBullet *p_space); + virtual void main_shape_changed() override; + virtual void do_reload_body() override; + virtual void set_space(SpaceBullet *p_space) override; - virtual void dispatch_callbacks(); + virtual void dispatch_callbacks() override; void call_event(CollisionObjectBullet *p_otherObject, PhysicsServer3D::AreaBodyStatus p_status); void set_on_state_change(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant()); void scratch(); @@ -152,9 +150,9 @@ public: // Dispatch the callbacks and removes from overlapping list void remove_overlap(CollisionObjectBullet *p_object, bool p_notify); - virtual void on_collision_filters_change(); - virtual void on_collision_checker_start() {} - virtual void on_collision_checker_end() { isTransformChanged = false; } + virtual void do_reload_collision_filters() override; + virtual void on_collision_checker_start() override {} + virtual void on_collision_checker_end() override { isTransformChanged = false; } void add_overlap(CollisionObjectBullet *p_otherObject); void put_overlap_as_exit(int p_index); @@ -166,8 +164,8 @@ public: void set_event_callback(Type p_callbackObjectType, ObjectID p_id, const StringName &p_method); bool has_event_callback(Type p_callbackObjectType); - virtual void on_enter_area(AreaBullet *p_area); - virtual void on_exit_area(AreaBullet *p_area); + virtual void on_enter_area(AreaBullet *p_area) override; + virtual void on_exit_area(AreaBullet *p_area) override; }; #endif diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index 6078babaf8..eb95120f74 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -52,7 +52,7 @@ class BulletPhysicsServer3D : public PhysicsServer3D { bool active = true; char active_spaces_count = 0; - Vector<SpaceBullet *> active_spaces; + LocalVector<SpaceBullet *> active_spaces; mutable RID_PtrOwner<SpaceBullet> space_owner; mutable RID_PtrOwner<ShapeBullet> shape_owner; diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp index dd208965bd..660e9afc5e 100644 --- a/modules/bullet/collision_object_bullet.cpp +++ b/modules/bullet/collision_object_bullet.cpp @@ -165,11 +165,20 @@ bool CollisionObjectBullet::has_collision_exception(const CollisionObjectBullet return !bt_collision_object->checkCollideWith(p_otherCollisionObject->bt_collision_object); } -void CollisionObjectBullet::prepare_object_for_dispatch() { - if (need_body_reload) { +void CollisionObjectBullet::reload_body() { + needs_body_reload = true; +} + +void CollisionObjectBullet::dispatch_callbacks() {} + +void CollisionObjectBullet::pre_process() { + if (needs_body_reload) { do_reload_body(); - need_body_reload = false; + } else if (needs_collision_filters_reload) { + do_reload_collision_filters(); } + needs_body_reload = false; + needs_collision_filters_reload = false; } void CollisionObjectBullet::set_collision_enabled(bool p_enabled) { @@ -245,7 +254,7 @@ void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform } void RigidCollisionObjectBullet::set_shape(int p_index, ShapeBullet *p_shape) { - ShapeWrapper &shp = shapes.write[p_index]; + ShapeWrapper &shp = shapes[p_index]; shp.shape->remove_owner(this); p_shape->add_owner(this); shp.shape = p_shape; @@ -307,7 +316,7 @@ void RigidCollisionObjectBullet::remove_all_shapes(bool p_permanentlyFromThisBod void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform &p_transform) { ERR_FAIL_INDEX(p_index, get_shape_count()); - shapes.write[p_index].set_transform(p_transform); + shapes[p_index].set_transform(p_transform); shape_changed(p_index); } @@ -325,7 +334,7 @@ void RigidCollisionObjectBullet::set_shape_disabled(int p_index, bool p_disabled if (shapes[p_index].active != p_disabled) { return; } - shapes.write[p_index].active = !p_disabled; + shapes[p_index].active = !p_disabled; shape_changed(p_index); } @@ -333,16 +342,16 @@ bool RigidCollisionObjectBullet::is_shape_disabled(int p_index) { return !shapes[p_index].active; } -void RigidCollisionObjectBullet::prepare_object_for_dispatch() { +void RigidCollisionObjectBullet::pre_process() { if (need_shape_reload) { do_reload_shapes(); need_shape_reload = false; } - CollisionObjectBullet::prepare_object_for_dispatch(); + CollisionObjectBullet::pre_process(); } void RigidCollisionObjectBullet::shape_changed(int p_shape_index) { - ShapeWrapper &shp = shapes.write[p_shape_index]; + ShapeWrapper &shp = shapes[p_shape_index]; if (shp.bt_shape == mainShape) { mainShape = nullptr; } @@ -363,12 +372,11 @@ void RigidCollisionObjectBullet::do_reload_shapes() { mainShape = nullptr; const int shape_count = shapes.size(); - ShapeWrapper *shapes_ptr = shapes.ptrw(); // Reset all shapes if required if (force_shape_reset) { for (int i(0); i < shape_count; ++i) { - shapes_ptr[i].release_bt_shape(); + shapes[i].release_bt_shape(); } force_shape_reset = false; } @@ -377,10 +385,10 @@ void RigidCollisionObjectBullet::do_reload_shapes() { if (1 == shape_count) { // Is it possible to optimize by not using compound? - btTransform transform = shapes_ptr[0].get_adjusted_transform(); + btTransform transform = shapes[0].get_adjusted_transform(); if (transform.getOrigin().isZero() && transform.getBasis() == transform.getBasis().getIdentity()) { - shapes_ptr[0].claim_bt_shape(body_scale); - mainShape = shapes_ptr[0].bt_shape; + shapes[0].claim_bt_shape(body_scale); + mainShape = shapes[0].bt_shape; main_shape_changed(); // Nothing more to do return; @@ -391,10 +399,10 @@ void RigidCollisionObjectBullet::do_reload_shapes() { btCompoundShape *compoundShape = bulletnew(btCompoundShape(enableDynamicAabbTree, shape_count)); for (int i(0); i < shape_count; ++i) { - shapes_ptr[i].claim_bt_shape(body_scale); - btTransform scaled_shape_transform(shapes_ptr[i].get_adjusted_transform()); + shapes[i].claim_bt_shape(body_scale); + btTransform scaled_shape_transform(shapes[i].get_adjusted_transform()); scaled_shape_transform.getOrigin() *= body_scale; - compoundShape->addChildShape(scaled_shape_transform, shapes_ptr[i].bt_shape); + compoundShape->addChildShape(scaled_shape_transform, shapes[i].bt_shape); } compoundShape->recalculateLocalAabb(); @@ -408,7 +416,7 @@ void RigidCollisionObjectBullet::body_scale_changed() { } void RigidCollisionObjectBullet::internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody) { - ShapeWrapper &shp = shapes.write[p_index]; + ShapeWrapper &shp = shapes[p_index]; shp.shape->remove_owner(this, p_permanentlyFromThisBody); if (shp.bt_shape == mainShape) { mainShape = nullptr; diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h index ac74661f24..920d80af23 100644 --- a/modules/bullet/collision_object_bullet.h +++ b/modules/bullet/collision_object_bullet.h @@ -31,6 +31,7 @@ #ifndef COLLISION_OBJECT_BULLET_H #define COLLISION_OBJECT_BULLET_H +#include "core/local_vector.h" #include "core/math/transform.h" #include "core/math/vector3.h" #include "core/object.h" @@ -126,16 +127,18 @@ protected: VSet<RID> exceptions; - bool need_body_reload = true; + bool needs_body_reload = true; + bool needs_collision_filters_reload = true; /// This array is used to know all areas where this Object is overlapped in /// New area is added when overlap with new area (AreaBullet::addOverlap), then is removed when it exit (CollisionObjectBullet::onExitArea) /// This array is used mainly to know which area hold the pointer of this object - Vector<AreaBullet *> areasOverlapped; + LocalVector<AreaBullet *> areasOverlapped; bool isTransformChanged = false; public: bool is_in_world = false; + bool is_in_flush_queue = false; public: CollisionObjectBullet(Type p_type); @@ -171,7 +174,7 @@ public: _FORCE_INLINE_ void set_collision_layer(uint32_t p_layer) { if (collisionLayer != p_layer) { collisionLayer = p_layer; - on_collision_filters_change(); + needs_collision_filters_reload = true; } } _FORCE_INLINE_ uint32_t get_collision_layer() const { return collisionLayer; } @@ -179,24 +182,23 @@ public: _FORCE_INLINE_ void set_collision_mask(uint32_t p_mask) { if (collisionMask != p_mask) { collisionMask = p_mask; - on_collision_filters_change(); + needs_collision_filters_reload = true; } } _FORCE_INLINE_ uint32_t get_collision_mask() const { return collisionMask; } - virtual void on_collision_filters_change() = 0; + virtual void do_reload_collision_filters() = 0; _FORCE_INLINE_ bool test_collision_mask(CollisionObjectBullet *p_other) const { return collisionLayer & p_other->collisionMask || p_other->collisionLayer & collisionMask; } bool need_reload_body() const { - return need_body_reload; + return needs_body_reload; } - void reload_body() { - need_body_reload = true; - } + void reload_body(); + virtual void do_reload_body() = 0; virtual void set_space(SpaceBullet *p_space) = 0; _FORCE_INLINE_ SpaceBullet *get_space() const { return space; } @@ -204,8 +206,8 @@ public: virtual void on_collision_checker_start() = 0; virtual void on_collision_checker_end() = 0; - virtual void prepare_object_for_dispatch(); - virtual void dispatch_callbacks() = 0; + virtual void dispatch_callbacks(); + virtual void pre_process(); void set_collision_enabled(bool p_enabled); bool is_collisions_response_enabled(); @@ -229,7 +231,7 @@ public: class RigidCollisionObjectBullet : public CollisionObjectBullet, public ShapeOwnerBullet { protected: btCollisionShape *mainShape = nullptr; - Vector<ShapeWrapper> shapes; + LocalVector<ShapeWrapper> shapes; bool need_shape_reload = true; public: @@ -237,7 +239,7 @@ public: CollisionObjectBullet(p_type) {} ~RigidCollisionObjectBullet(); - _FORCE_INLINE_ const Vector<ShapeWrapper> &get_shapes_wrappers() const { return shapes; } + _FORCE_INLINE_ const LocalVector<ShapeWrapper> &get_shapes_wrappers() const { return shapes; } _FORCE_INLINE_ btCollisionShape *get_main_shape() const { return mainShape; } @@ -248,9 +250,9 @@ public: ShapeBullet *get_shape(int p_index) const; btCollisionShape *get_bt_shape(int p_index) const; - int find_shape(ShapeBullet *p_shape) const; + virtual int find_shape(ShapeBullet *p_shape) const override; - virtual void remove_shape_full(ShapeBullet *p_shape); + virtual void remove_shape_full(ShapeBullet *p_shape) override; void remove_shape_full(int p_index); void remove_all_shapes(bool p_permanentlyFromThisBody = false, bool p_force_not_reload = false); @@ -262,15 +264,15 @@ public: void set_shape_disabled(int p_index, bool p_disabled); bool is_shape_disabled(int p_index); - virtual void prepare_object_for_dispatch(); + virtual void pre_process() override; - virtual void shape_changed(int p_shape_index); - void reload_shapes(); + virtual void shape_changed(int p_shape_index) override; + virtual void reload_shapes() override; bool need_reload_shapes() const { return need_shape_reload; } virtual void do_reload_shapes(); virtual void main_shape_changed() = 0; - virtual void body_scale_changed(); + virtual void body_scale_changed() override; private: void internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody = false); diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp index e1f950dad1..f82648d6ff 100644 --- a/modules/bullet/godot_result_callbacks.cpp +++ b/modules/bullet/godot_result_callbacks.cpp @@ -57,7 +57,7 @@ bool GodotFilterCallback::needBroadphaseCollision(btBroadphaseProxy *proxy0, btB bool GodotClosestRayResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask); - if (m_pickRay || needs) { + if (needs) { btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 717c99c738..5c1144b875 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -51,9 +51,7 @@ BulletPhysicsDirectBodyState3D *BulletPhysicsDirectBodyState3D::singleton = nullptr; Vector3 BulletPhysicsDirectBodyState3D::get_total_gravity() const { - Vector3 gVec; - B_TO_G(body->btBody->getGravity(), gVec); - return gVec; + return body->total_gravity; } float BulletPhysicsDirectBodyState3D::get_total_angular_damp() const { @@ -183,7 +181,7 @@ int BulletPhysicsDirectBodyState3D::get_contact_collider_shape(int p_contact_idx } Vector3 BulletPhysicsDirectBodyState3D::get_contact_collider_velocity_at_position(int p_contact_idx) const { - RigidBodyBullet::CollisionData &colDat = body->collisions.write[p_contact_idx]; + RigidBodyBullet::CollisionData &colDat = body->collisions[p_contact_idx]; btVector3 hitLocation; G_TO_B(colDat.hitLocalLocation, hitLocation); @@ -213,7 +211,7 @@ void RigidBodyBullet::KinematicUtilities::setSafeMargin(btScalar p_margin) { } void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { - const Vector<CollisionObjectBullet::ShapeWrapper> &shapes_wrappers(owner->get_shapes_wrappers()); + const LocalVector<CollisionObjectBullet::ShapeWrapper> &shapes_wrappers(owner->get_shapes_wrappers()); const int shapes_count = shapes_wrappers.size(); just_delete_shapes(shapes_count); @@ -228,8 +226,8 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { continue; } - shapes.write[i].transform = shape_wrapper->transform; - shapes.write[i].transform.getOrigin() *= owner_scale; + shapes[i].transform = shape_wrapper->transform; + shapes[i].transform.getOrigin() *= owner_scale; switch (shape_wrapper->shape->get_type()) { case PhysicsServer3D::SHAPE_SPHERE: case PhysicsServer3D::SHAPE_BOX: @@ -237,11 +235,11 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { case PhysicsServer3D::SHAPE_CYLINDER: case PhysicsServer3D::SHAPE_CONVEX_POLYGON: case PhysicsServer3D::SHAPE_RAY: { - shapes.write[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->internal_create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin)); + shapes[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->internal_create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin)); } break; default: WARN_PRINT("This shape is not supported for kinematic collision."); - shapes.write[i].shape = nullptr; + shapes[i].shape = nullptr; } } } @@ -249,7 +247,7 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { void RigidBodyBullet::KinematicUtilities::just_delete_shapes(int new_size) { for (int i = shapes.size() - 1; 0 <= i; --i) { if (shapes[i].shape) { - bulletdelete(shapes.write[i].shape); + bulletdelete(shapes[i].shape); } } shapes.resize(new_size); @@ -271,8 +269,8 @@ RigidBodyBullet::RigidBodyBullet() : reload_axis_lock(); areasWhereIam.resize(maxAreasWhereIam); - for (int i = areasWhereIam.size() - 1; 0 <= i; --i) { - areasWhereIam.write[i] = nullptr; + for (uint32_t i = 0; i < areasWhereIam.size(); i += 1) { + areasWhereIam[i] = nullptr; } btBody->setSleepingThresholds(0.2, 0.2); @@ -335,16 +333,15 @@ void RigidBodyBullet::set_space(SpaceBullet *p_space) { if (space) { space->register_collision_object(this); reload_body(); + space->add_to_flush_queue(this); } } void RigidBodyBullet::dispatch_callbacks() { + RigidCollisionObjectBullet::dispatch_callbacks(); + /// The check isFirstTransformChanged is necessary in order to call integrated forces only when the first transform is sent if ((btBody->isKinematicObject() || btBody->isActive() || previousActiveState != btBody->isActive()) && force_integration_callback && can_integrate_forces) { - if (omit_forces_integration) { - btBody->clearForces(); - } - BulletPhysicsDirectBodyState3D *bodyDirect = BulletPhysicsDirectBodyState3D::get_singleton(this); Variant variantBodyDirect = bodyDirect; @@ -362,16 +359,22 @@ void RigidBodyBullet::dispatch_callbacks() { } } + previousActiveState = btBody->isActive(); +} + +void RigidBodyBullet::pre_process() { + RigidCollisionObjectBullet::pre_process(); + if (isScratchedSpaceOverrideModificator || 0 < countGravityPointSpaces) { isScratchedSpaceOverrideModificator = false; reload_space_override_modificator(); } - /// Lock axis - btBody->setLinearVelocity(btBody->getLinearVelocity() * btBody->getLinearFactor()); - btBody->setAngularVelocity(btBody->getAngularVelocity() * btBody->getAngularFactor()); - - previousActiveState = btBody->isActive(); + if (is_active()) { + /// Lock axis + btBody->setLinearVelocity(btBody->getLinearVelocity() * btBody->getLinearFactor()); + btBody->setAngularVelocity(btBody->getAngularVelocity() * btBody->getAngularFactor()); + } } void RigidBodyBullet::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) { @@ -392,7 +395,7 @@ void RigidBodyBullet::scratch_space_override_modificator() { isScratchedSpaceOverrideModificator = true; } -void RigidBodyBullet::on_collision_filters_change() { +void RigidBodyBullet::do_reload_collision_filters() { if (space) { space->reload_collision_filters(this); } @@ -405,14 +408,15 @@ void RigidBodyBullet::on_collision_checker_start() { collisionsCount = 0; // Swap array - Vector<RigidBodyBullet *> *s = prev_collision_traces; - prev_collision_traces = curr_collision_traces; - curr_collision_traces = s; + SWAP(prev_collision_traces, curr_collision_traces); } void RigidBodyBullet::on_collision_checker_end() { // Always true if active and not a static or kinematic body isTransformChanged = btBody->isActive() && !btBody->isStaticOrKinematicObject(); + if (isTransformChanged && space != nullptr) { + space->add_to_flush_queue(this); + } } bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const float &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index) { @@ -420,7 +424,7 @@ bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const return false; } - CollisionData &cd = collisions.write[collisionsCount]; + CollisionData &cd = collisions[collisionsCount]; cd.hitLocalLocation = p_hitLocalLocation; cd.otherObject = p_otherObject; cd.hitWorldLocation = p_hitWorldLocation; @@ -429,7 +433,7 @@ bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const cd.other_object_shape = p_other_shape_index; cd.local_shape = p_local_shape_index; - curr_collision_traces->write[collisionsCount] = p_otherObject; + (*curr_collision_traces)[collisionsCount] = p_otherObject; ++collisionsCount; return true; @@ -464,6 +468,7 @@ bool RigidBodyBullet::is_active() const { void RigidBodyBullet::set_omit_forces_integration(bool p_omit) { omit_forces_integration = p_omit; + scratch_space_override_modificator(); } void RigidBodyBullet::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) { @@ -839,15 +844,15 @@ void RigidBodyBullet::on_enter_area(AreaBullet *p_area) { for (int i = 0; i < areaWhereIamCount; ++i) { if (nullptr == areasWhereIam[i]) { // This area has the highest priority - areasWhereIam.write[i] = p_area; + areasWhereIam[i] = p_area; break; } else { if (areasWhereIam[i]->get_spOv_priority() > p_area->get_spOv_priority()) { // The position was found, just shift all elements for (int j = i; j < areaWhereIamCount; ++j) { - areasWhereIam.write[j + 1] = areasWhereIam[j]; + areasWhereIam[j + 1] = areasWhereIam[j]; } - areasWhereIam.write[i] = p_area; + areasWhereIam[i] = p_area; break; } } @@ -871,7 +876,7 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) { if (p_area == areasWhereIam[i]) { // The area was found, just shift down all elements for (int j = i; j < areaWhereIamCount; ++j) { - areasWhereIam.write[j] = areasWhereIam[j + 1]; + areasWhereIam[j] = areasWhereIam[j + 1]; } wasTheAreaFound = true; break; @@ -884,7 +889,7 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) { } --areaWhereIamCount; - areasWhereIam.write[areaWhereIamCount] = nullptr; // Even if this is not required, I clear the last element to be safe + areasWhereIam[areaWhereIamCount] = nullptr; // Even if this is not required, I clear the last element to be safe if (PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED != p_area->get_spOv_mode()) { scratch_space_override_modificator(); } @@ -897,36 +902,31 @@ void RigidBodyBullet::reload_space_override_modificator() { return; } - Vector3 newGravity(0.0, 0.0, 0.0); + Vector3 newGravity; real_t newLinearDamp = MAX(0.0, linearDamp); real_t newAngularDamp = MAX(0.0, angularDamp); - AreaBullet *currentArea; - // Variable used to calculate new gravity for gravity point areas, it is pointed by currentGravity pointer - Vector3 support_gravity(0, 0, 0); - bool stopped = false; - for (int i = areaWhereIamCount - 1; (0 <= i) && !stopped; --i) { - currentArea = areasWhereIam[i]; + for (int i = 0; i < areaWhereIamCount && !stopped; i += 1) { + AreaBullet *currentArea = areasWhereIam[i]; if (!currentArea || PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED == currentArea->get_spOv_mode()) { continue; } + Vector3 support_gravity; + /// Here is calculated the gravity if (currentArea->is_spOv_gravityPoint()) { /// It calculates the direction of new gravity support_gravity = currentArea->get_transform().xform(currentArea->get_spOv_gravityVec()) - get_transform().get_origin(); - real_t distanceMag = support_gravity.length(); + + const real_t distanceMag = support_gravity.length(); // Normalized in this way to avoid the double call of function "length()" if (distanceMag == 0) { - support_gravity.x = 0; - support_gravity.y = 0; - support_gravity.z = 0; + support_gravity = Vector3(); } else { - support_gravity.x /= distanceMag; - support_gravity.y /= distanceMag; - support_gravity.z /= distanceMag; + support_gravity /= distanceMag; } /// Here is calculated the final gravity @@ -988,10 +988,17 @@ void RigidBodyBullet::reload_space_override_modificator() { newAngularDamp += space->get_angular_damp(); } - btVector3 newBtGravity; - G_TO_B(newGravity * gravity_scale, newBtGravity); + total_gravity = newGravity; + + if (omit_forces_integration) { + // Custom behaviour. + btBody->setGravity(btVector3(0, 0, 0)); + } else { + btVector3 newBtGravity; + G_TO_B(newGravity * gravity_scale, newBtGravity); + btBody->setGravity(newBtGravity); + } - btBody->setGravity(newBtGravity); btBody->setDamping(newLinearDamp, newAngularDamp); } diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index eb62d0d39e..047645677b 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -171,7 +171,7 @@ public: struct KinematicUtilities { RigidBodyBullet *owner; btScalar safe_margin; - Vector<KinematicShape> shapes; + LocalVector<KinematicShape> shapes; KinematicUtilities(RigidBodyBullet *p_owner); ~KinematicUtilities(); @@ -193,6 +193,7 @@ private: PhysicsServer3D::BodyMode mode; GodotMotionState *godotMotionState; btRigidBody *btBody; + Vector3 total_gravity; uint16_t locked_axis = 0; real_t mass = 1; real_t gravity_scale = 1; @@ -202,18 +203,18 @@ private: bool omit_forces_integration = false; bool can_integrate_forces = false; - Vector<CollisionData> collisions; - Vector<RigidBodyBullet *> collision_traces_1; - Vector<RigidBodyBullet *> collision_traces_2; - Vector<RigidBodyBullet *> *prev_collision_traces; - Vector<RigidBodyBullet *> *curr_collision_traces; + LocalVector<CollisionData> collisions; + LocalVector<RigidBodyBullet *> collision_traces_1; + LocalVector<RigidBodyBullet *> collision_traces_2; + LocalVector<RigidBodyBullet *> *prev_collision_traces; + LocalVector<RigidBodyBullet *> *curr_collision_traces; // these parameters are used to avoid vector resize - int maxCollisionsDetection = 0; - int collisionsCount = 0; - int prev_collision_count = 0; + uint32_t maxCollisionsDetection = 0; + uint32_t collisionsCount = 0; + uint32_t prev_collision_count = 0; - Vector<AreaBullet *> areasWhereIam; + LocalVector<AreaBullet *> areasWhereIam; // these parameters are used to avoid vector resize int maxAreasWhereIam = 10; int areaWhereIamCount = 0; @@ -235,21 +236,20 @@ public: _FORCE_INLINE_ btRigidBody *get_bt_rigid_body() { return btBody; } - virtual void main_shape_changed(); - virtual void do_reload_body(); - virtual void set_space(SpaceBullet *p_space); + virtual void main_shape_changed() override; + virtual void do_reload_body() override; + virtual void set_space(SpaceBullet *p_space) override; - virtual void dispatch_callbacks(); + virtual void dispatch_callbacks() override; + virtual void pre_process() override; void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant()); void scratch_space_override_modificator(); - virtual void on_collision_filters_change(); - virtual void on_collision_checker_start(); - virtual void on_collision_checker_end(); - - void set_max_collisions_detection(int p_maxCollisionsDetection) { - ERR_FAIL_COND(0 > p_maxCollisionsDetection); + virtual void do_reload_collision_filters() override; + virtual void on_collision_checker_start() override; + virtual void on_collision_checker_end() override; + void set_max_collisions_detection(uint32_t p_maxCollisionsDetection) { maxCollisionsDetection = p_maxCollisionsDetection; collisions.resize(p_maxCollisionsDetection); @@ -312,19 +312,19 @@ public: void set_angular_velocity(const Vector3 &p_velocity); Vector3 get_angular_velocity() const; - virtual void set_transform__bullet(const btTransform &p_global_transform); - virtual const btTransform &get_transform__bullet() const; + virtual void set_transform__bullet(const btTransform &p_global_transform) override; + virtual const btTransform &get_transform__bullet() const override; - virtual void do_reload_shapes(); + virtual void do_reload_shapes() override; - virtual void on_enter_area(AreaBullet *p_area); - virtual void on_exit_area(AreaBullet *p_area); + virtual void on_enter_area(AreaBullet *p_area) override; + virtual void on_exit_area(AreaBullet *p_area) override; void reload_space_override_modificator(); /// Kinematic void reload_kinematic_shapes(); - virtual void notify_transform_changed(); + virtual void notify_transform_changed() override; private: void _internal_set_mass(real_t p_mass); diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp index f4550c2024..274493ed17 100644 --- a/modules/bullet/shape_bullet.cpp +++ b/modules/bullet/shape_bullet.cpp @@ -504,6 +504,9 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) { int l_width = d["width"]; int l_depth = d["depth"]; + ERR_FAIL_COND_MSG(l_width < 2, "Map width must be at least 2."); + ERR_FAIL_COND_MSG(l_depth < 2, "Map depth must be at least 2."); + // TODO This code will need adjustments if real_t is set to `double`, // because that precision is unnecessary for a heightmap and Bullet doesn't support it... diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp index 3fccd3d8a2..ee48b3c5f0 100644 --- a/modules/bullet/soft_body_bullet.cpp +++ b/modules/bullet/soft_body_bullet.cpp @@ -346,14 +346,14 @@ void SoftBodyBullet::set_trimesh_body_shape(Vector<int> p_indices, Vector<Vector indices_table.push_back(Vector<int>()); } - indices_table.write[vertex_id].push_back(vs_vertex_index); + indices_table[vertex_id].push_back(vs_vertex_index); vs_indices_to_physics_table.push_back(vertex_id); } } const int indices_map_size(indices_table.size()); - Vector<btScalar> bt_vertices; + LocalVector<btScalar> bt_vertices; { // Parse vertices to bullet @@ -361,13 +361,13 @@ void SoftBodyBullet::set_trimesh_body_shape(Vector<int> p_indices, Vector<Vector const Vector3 *p_vertices_read = p_vertices.ptr(); for (int i = 0; i < indices_map_size; ++i) { - bt_vertices.write[3 * i + 0] = p_vertices_read[indices_table[i][0]].x; - bt_vertices.write[3 * i + 1] = p_vertices_read[indices_table[i][0]].y; - bt_vertices.write[3 * i + 2] = p_vertices_read[indices_table[i][0]].z; + bt_vertices[3 * i + 0] = p_vertices_read[indices_table[i][0]].x; + bt_vertices[3 * i + 1] = p_vertices_read[indices_table[i][0]].y; + bt_vertices[3 * i + 2] = p_vertices_read[indices_table[i][0]].z; } } - Vector<int> bt_triangles; + LocalVector<int> bt_triangles; const int triangles_size(p_indices.size() / 3); { // Parse indices @@ -377,9 +377,9 @@ void SoftBodyBullet::set_trimesh_body_shape(Vector<int> p_indices, Vector<Vector const int *p_indices_read = p_indices.ptr(); for (int i = 0; i < triangles_size; ++i) { - bt_triangles.write[3 * i + 0] = vs_indices_to_physics_table[p_indices_read[3 * i + 2]]; - bt_triangles.write[3 * i + 1] = vs_indices_to_physics_table[p_indices_read[3 * i + 1]]; - bt_triangles.write[3 * i + 2] = vs_indices_to_physics_table[p_indices_read[3 * i + 0]]; + bt_triangles[3 * i + 0] = vs_indices_to_physics_table[p_indices_read[3 * i + 2]]; + bt_triangles[3 * i + 1] = vs_indices_to_physics_table[p_indices_read[3 * i + 1]]; + bt_triangles[3 * i + 2] = vs_indices_to_physics_table[p_indices_read[3 * i + 0]]; } } diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h index ba968f4271..229204b539 100644 --- a/modules/bullet/soft_body_bullet.h +++ b/modules/bullet/soft_body_bullet.h @@ -32,7 +32,6 @@ #define SOFT_BODY_BULLET_H #include "collision_object_bullet.h" -#include "scene/resources/material.h" // TODO remove this please #ifdef None /// This is required to remove the macro None defined by x11 compiler because this word "None" is used internally by Bullet @@ -58,7 +57,7 @@ class SoftBodyBullet : public CollisionObjectBullet { private: btSoftBody *bt_soft_body = nullptr; - Vector<Vector<int>> indices_table; + LocalVector<Vector<int>> indices_table; btSoftBody::Material *mat0; // This is just a copy of pointer managed by btSoftBody bool isScratched = false; @@ -73,7 +72,7 @@ private: real_t pose_matching_coefficient = 0.; // [0,1] real_t damping_coefficient = 0.01; // [0,1] real_t drag_coefficient = 0.; // [0,1] - Vector<int> pinned_nodes; + LocalVector<int> pinned_nodes; // Other property to add //btScalar kVC; // Volume conversation coefficient [0,+inf] @@ -87,15 +86,14 @@ public: SoftBodyBullet(); ~SoftBodyBullet(); - virtual void do_reload_body(); - virtual void set_space(SpaceBullet *p_space); + virtual void do_reload_body() override; + virtual void set_space(SpaceBullet *p_space) override; - virtual void dispatch_callbacks() {} - virtual void on_collision_filters_change() {} - virtual void on_collision_checker_start() {} - virtual void on_collision_checker_end() {} - virtual void on_enter_area(AreaBullet *p_area); - virtual void on_exit_area(AreaBullet *p_area); + virtual void do_reload_collision_filters() override {} + virtual void on_collision_checker_start() override {} + virtual void on_collision_checker_end() override {} + virtual void on_enter_area(AreaBullet *p_area) override; + virtual void on_exit_area(AreaBullet *p_area) override; _FORCE_INLINE_ btSoftBody *get_bt_soft_body() const { return bt_soft_body; } diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 9dc307c629..2b60f8df36 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -348,16 +348,46 @@ SpaceBullet::~SpaceBullet() { destroy_world(); } +void SpaceBullet::add_to_pre_flush_queue(CollisionObjectBullet *p_co) { + if (p_co->is_in_flush_queue == false) { + p_co->is_in_flush_queue = true; + queue_pre_flush.push_back(p_co); + } +} + +void SpaceBullet::add_to_flush_queue(CollisionObjectBullet *p_co) { + if (p_co->is_in_flush_queue == false) { + p_co->is_in_flush_queue = true; + queue_flush.push_back(p_co); + } +} + +void SpaceBullet::remove_from_any_queue(CollisionObjectBullet *p_co) { + if (p_co->is_in_flush_queue) { + p_co->is_in_flush_queue = false; + queue_pre_flush.erase(p_co); + queue_flush.erase(p_co); + } +} + void SpaceBullet::flush_queries() { - const int size = collision_objects.size(); - CollisionObjectBullet **objects = collision_objects.ptrw(); - for (int i = 0; i < size; i += 1) { - objects[i]->prepare_object_for_dispatch(); - objects[i]->dispatch_callbacks(); + for (uint32_t i = 0; i < queue_pre_flush.size(); i += 1) { + queue_pre_flush[i]->dispatch_callbacks(); + queue_pre_flush[i]->is_in_flush_queue = false; } + for (uint32_t i = 0; i < queue_flush.size(); i += 1) { + queue_flush[i]->dispatch_callbacks(); + queue_flush[i]->is_in_flush_queue = false; + } + queue_pre_flush.clear(); + queue_flush.clear(); } void SpaceBullet::step(real_t p_delta_time) { + for (uint32_t i = 0; i < collision_objects.size(); i += 1) { + collision_objects[i]->pre_process(); + } + delta_time = p_delta_time; dynamicsWorld->stepSimulation(p_delta_time, 0, 0); } @@ -488,6 +518,7 @@ void SpaceBullet::register_collision_object(CollisionObjectBullet *p_object) { } void SpaceBullet::unregister_collision_object(CollisionObjectBullet *p_object) { + remove_from_any_queue(p_object); collision_objects.erase(p_object); } @@ -702,7 +733,7 @@ void SpaceBullet::check_ghost_overlaps() { /// 1. Reset all states for (i = area->overlappingObjects.size() - 1; 0 <= i; --i) { - AreaBullet::OverlappingObjectData &otherObj = area->overlappingObjects.write[i]; + AreaBullet::OverlappingObjectData &otherObj = area->overlappingObjects[i]; // This check prevent the overwrite of ENTER state // if this function is called more times before dispatchCallbacks if (otherObj.state != AreaBullet::OVERLAP_STATE_ENTER) { diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index aa9a70594e..897f902fe1 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -31,8 +31,8 @@ #ifndef SPACE_BULLET_H #define SPACE_BULLET_H +#include "core/local_vector.h" #include "core/variant.h" -#include "core/vector.h" #include "godot_result_callbacks.h" #include "rid_bullet.h" #include "servers/physics_server_3d.h" @@ -110,17 +110,23 @@ class SpaceBullet : public RIDBullet { real_t linear_damp = 0.0; real_t angular_damp = 0.0; - Vector<CollisionObjectBullet *> collision_objects; - Vector<AreaBullet *> areas; + LocalVector<CollisionObjectBullet *> queue_pre_flush; + LocalVector<CollisionObjectBullet *> queue_flush; + LocalVector<CollisionObjectBullet *> collision_objects; + LocalVector<AreaBullet *> areas; - Vector<Vector3> contactDebug; - int contactDebugCount = 0; + LocalVector<Vector3> contactDebug; + uint32_t contactDebugCount = 0; real_t delta_time = 0.; public: SpaceBullet(); virtual ~SpaceBullet(); + void add_to_flush_queue(CollisionObjectBullet *p_co); + void add_to_pre_flush_queue(CollisionObjectBullet *p_co); + void remove_from_any_queue(CollisionObjectBullet *p_co); + void flush_queries(); real_t get_delta_time() { return delta_time; } void step(real_t p_delta_time); @@ -177,7 +183,7 @@ public: } _FORCE_INLINE_ void add_debug_contact(const Vector3 &p_contact) { if (contactDebugCount < contactDebug.size()) { - contactDebug.write[contactDebugCount++] = p_contact; + contactDebug[contactDebugCount++] = p_contact; } } _FORCE_INLINE_ Vector<Vector3> get_debug_contacts() { return contactDebug; } diff --git a/modules/camera/camera_ios.mm b/modules/camera/camera_ios.mm index f01135f251..c10b13b2af 100644 --- a/modules/camera/camera_ios.mm +++ b/modules/camera/camera_ios.mm @@ -158,25 +158,31 @@ } else if (dataCbCr == NULL) { print_line("Couldn't access CbCr pixel buffer data"); } else { - UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; + UIInterfaceOrientation orientation = UIInterfaceOrientationUnknown; + + if (@available(iOS 13, *)) { + orientation = [UIApplication sharedApplication].delegate.window.windowScene.interfaceOrientation; +#if !defined(TARGET_OS_SIMULATOR) || !TARGET_OS_SIMULATOR + } else { + orientation = [[UIApplication sharedApplication] statusBarOrientation]; +#endif + } + Ref<Image> img[2]; { // do Y - int new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0); - int new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0); - int _bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0); + size_t new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0); + size_t new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0); if ((width[0] != new_width) || (height[0] != new_height)) { - // printf("Camera Y plane %i, %i - %i\n", new_width, new_height, bytes_per_row); - width[0] = new_width; height[0] = new_height; img_data[0].resize(new_width * new_height); } uint8_t *w = img_data[0].ptrw(); - memcpy(w.ptr(), dataY, new_width * new_height); + memcpy(w, dataY, new_width * new_height); img[0].instance(); img[0]->create(new_width, new_height, 0, Image::FORMAT_R8, img_data[0]); @@ -184,20 +190,17 @@ { // do CbCr - int new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1); - int new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1); - int bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1); + size_t new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1); + size_t new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1); if ((width[1] != new_width) || (height[1] != new_height)) { - // printf("Camera CbCr plane %i, %i - %i\n", new_width, new_height, bytes_per_row); - width[1] = new_width; height[1] = new_height; img_data[1].resize(2 * new_width * new_height); } uint8_t *w = img_data[1].ptrw(); - memcpy(w.ptr(), dataCbCr, 2 * new_width * new_height); + memcpy(w, dataCbCr, 2 * new_width * new_height); ///TODO GLES2 doesn't support FORMAT_RG8, need to do some form of conversion img[1].instance(); @@ -359,41 +362,59 @@ void CameraIOS::update_feeds() { // this way of doing things is deprecated but still works, // rewrite to using AVCaptureDeviceDiscoverySession - AVCaptureDeviceDiscoverySession *session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:[NSArray arrayWithObjects:AVCaptureDeviceTypeBuiltInTelephotoCamera, AVCaptureDeviceTypeBuiltInDualCamera, AVCaptureDeviceTypeBuiltInTrueDepthCamera, AVCaptureDeviceTypeBuiltInWideAngleCamera, nil] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified]; + NSMutableArray *deviceTypes = [NSMutableArray array]; - // remove devices that are gone.. - for (int i = feeds.size() - 1; i >= 0; i--) { - Ref<CameraFeedIOS> feed(feeds[i]); + if (@available(iOS 10, *)) { + [deviceTypes addObject:AVCaptureDeviceTypeBuiltInWideAngleCamera]; + [deviceTypes addObject:AVCaptureDeviceTypeBuiltInTelephotoCamera]; - if (feed.is_null()) { - // feed not managed by us - } else if (![session.devices containsObject:feed->get_device()]) { - // remove it from our array, this will also destroy it ;) - remove_feed(feed); - }; - }; + if (@available(iOS 10.2, *)) { + [deviceTypes addObject:AVCaptureDeviceTypeBuiltInDualCamera]; + } - // add new devices.. - for (AVCaptureDevice *device in session.devices) { - bool found = false; + if (@available(iOS 11.1, *)) { + [deviceTypes addObject:AVCaptureDeviceTypeBuiltInTrueDepthCamera]; + } + + AVCaptureDeviceDiscoverySession *session = [AVCaptureDeviceDiscoverySession + discoverySessionWithDeviceTypes:deviceTypes + mediaType:AVMediaTypeVideo + position:AVCaptureDevicePositionUnspecified]; - for (int i = 0; i < feeds.size() && !found; i++) { + // remove devices that are gone.. + for (int i = feeds.size() - 1; i >= 0; i--) { Ref<CameraFeedIOS> feed(feeds[i]); if (feed.is_null()) { // feed not managed by us - } else if (feed->get_device() == device) { - found = true; + } else if (![session.devices containsObject:feed->get_device()]) { + // remove it from our array, this will also destroy it ;) + remove_feed(feed); }; }; - if (!found) { - Ref<CameraFeedIOS> newfeed; - newfeed.instance(); - newfeed->set_device(device); - add_feed(newfeed); + // add new devices.. + for (AVCaptureDevice *device in session.devices) { + bool found = false; + + for (int i = 0; i < feeds.size() && !found; i++) { + Ref<CameraFeedIOS> feed(feeds[i]); + + if (feed.is_null()) { + // feed not managed by us + } else if (feed->get_device() == device) { + found = true; + }; + }; + + if (!found) { + Ref<CameraFeedIOS> newfeed; + newfeed.instance(); + newfeed->set_device(device); + add_feed(newfeed); + }; }; - }; + } }; CameraIOS::CameraIOS() { diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index cea006364f..82a47f594b 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -132,18 +132,13 @@ void CSGShape3D::_make_dirty() { return; } - if (dirty) { - return; - } - - dirty = true; - if (parent) { parent->_make_dirty(); - } else { - //only parent will do + } else if (!dirty) { call_deferred("_update_shape"); } + + dirty = true; } CSGBrush *CSGShape3D::_get_brush() { diff --git a/modules/denoise/SCsub b/modules/denoise/SCsub index 0fa65c6296..bf3bd7d073 100644 --- a/modules/denoise/SCsub +++ b/modules/denoise/SCsub @@ -1,7 +1,6 @@ #!/usr/bin/env python import resource_to_cpp -from platform_methods import run_in_subprocess Import("env") Import("env_modules") diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp index ed3924f2d2..64977ad237 100644 --- a/modules/enet/networked_multiplayer_enet.cpp +++ b/modules/enet/networked_multiplayer_enet.cpp @@ -104,6 +104,7 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int if (dtls_enabled) { enet_host_dtls_server_setup(host, dtls_key.ptr(), dtls_cert.ptr()); } + enet_host_refuse_new_connections(host, refuse_connections); #endif _setup_compressor(); @@ -160,6 +161,7 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por if (dtls_enabled) { enet_host_dtls_client_setup(host, dtls_cert.ptr(), dtls_verify, p_address.utf8().get_data()); } + enet_host_refuse_new_connections(host, refuse_connections); #endif _setup_compressor(); @@ -641,7 +643,9 @@ int NetworkedMultiplayerENet::get_unique_id() const { void NetworkedMultiplayerENet::set_refuse_new_connections(bool p_enable) { refuse_connections = p_enable; #ifdef GODOT_ENET - enet_host_refuse_new_connections(host, p_enable); + if (active) { + enet_host_refuse_new_connections(host, p_enable); + } #endif } diff --git a/modules/etc/image_etc.cpp b/modules/etc/image_etc.cpp index 9b6d8a2d35..d1ba3dc355 100644 --- a/modules/etc/image_etc.cpp +++ b/modules/etc/image_etc.cpp @@ -106,7 +106,7 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f // If VRAM compression is using ETC, but image has alpha, convert to RGBA4444 or LA8 // This saves space while maintaining the alpha channel if (detected_channels == Image::USED_CHANNELS_RGBA) { - + if (p_img->has_mipmaps()) { // Image doesn't support mipmaps with RGBA4444 textures p_img->clear_mipmaps(); diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub index cab05549d2..0e2291c1f9 100644 --- a/modules/gdnative/SCsub +++ b/modules/gdnative/SCsub @@ -22,13 +22,12 @@ SConscript("pluginscript/SCsub") SConscript("videodecoder/SCsub") -from platform_methods import run_in_subprocess import gdnative_builders _, gensource = env_gdnative.CommandNoCache( ["include/gdnative_api_struct.gen.h", "gdnative_api_struct.gen.cpp"], "gdnative_api.json", - run_in_subprocess(gdnative_builders.build_gdnative_api_struct), + env.Run(gdnative_builders.build_gdnative_api_struct, "Generating GDNative API."), ) env_gdnative.add_source_files(env.modules_sources, [gensource]) diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp index 8b0c7474e8..26c40b625c 100644 --- a/modules/gdnative/gdnative/string.cpp +++ b/modules/gdnative/gdnative/string.cpp @@ -541,13 +541,7 @@ godot_string GDAPI godot_string_substr(const godot_string *p_self, godot_int p_f return result; } -double GDAPI godot_string_to_double(const godot_string *p_self) { - const String *self = (const String *)p_self; - - return self->to_double(); -} - -godot_real GDAPI godot_string_to_float(const godot_string *p_self) { +double GDAPI godot_string_to_float(const godot_string *p_self) { const String *self = (const String *)p_self; return self->to_float(); @@ -583,8 +577,8 @@ godot_string GDAPI godot_string_camelcase_to_underscore_lowercased(const godot_s return result; } -double GDAPI godot_string_char_to_double(const char *p_what) { - return String::to_double(p_what); +double GDAPI godot_string_char_to_float(const char *p_what) { + return String::to_float(p_what); } godot_int GDAPI godot_string_char_to_int(const char *p_what) { @@ -621,8 +615,8 @@ int64_t GDAPI godot_string_to_int64(const godot_string *p_self) { return self->to_int(); } -double GDAPI godot_string_unicode_char_to_double(const wchar_t *p_str, const wchar_t **r_end) { - return String::to_double(p_str, r_end); +double GDAPI godot_string_unicode_char_to_float(const wchar_t *p_str, const wchar_t **r_end) { + return String::to_float(p_str, r_end); } godot_string GDAPI godot_string_get_slice(const godot_string *p_self, godot_string p_splitter, godot_int p_slice) { diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 9852928d22..8ccf44ff1a 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -4237,15 +4237,8 @@ ] }, { - "name": "godot_string_to_double", - "return_type": "double", - "arguments": [ - ["const godot_string *", "p_self"] - ] - }, - { "name": "godot_string_to_float", - "return_type": "godot_real", + "return_type": "double", "arguments": [ ["const godot_string *", "p_self"] ] @@ -4279,7 +4272,7 @@ ] }, { - "name": "godot_string_char_to_double", + "name": "godot_string_char_to_float", "return_type": "double", "arguments": [ ["const char *", "p_what"] @@ -4337,7 +4330,7 @@ ] }, { - "name": "godot_string_unicode_char_to_double", + "name": "godot_string_unicode_char_to_float", "return_type": "double", "arguments": [ ["const wchar_t *", "p_str"], diff --git a/modules/gdnative/gdnative_builders.py b/modules/gdnative/gdnative_builders.py index a6f8afb85b..28e4957b2f 100644 --- a/modules/gdnative/gdnative_builders.py +++ b/modules/gdnative/gdnative_builders.py @@ -74,7 +74,7 @@ def _build_gdnative_api_struct_header(api): ret_val += [ "typedef struct godot_gdnative_core_" - + ("{0}_{1}".format(core["version"]["major"], core["version"]["minor"])) + + "{0}_{1}".format(core["version"]["major"], core["version"]["minor"]) + "_api_struct {", "\tunsigned int type;", "\tgodot_gdnative_api_version version;", @@ -185,7 +185,7 @@ def _build_gdnative_api_struct_source(api): ret_val += [ "extern const godot_gdnative_core_" - + ("{0}_{1}_api_struct api_{0}_{1}".format(core["version"]["major"], core["version"]["minor"])) + + "{0}_{1}_api_struct api_{0}_{1}".format(core["version"]["major"], core["version"]["minor"]) + " = {", "\tGDNATIVE_" + core["type"] + ",", "\t{" + str(core["version"]["major"]) + ", " + str(core["version"]["minor"]) + "},", diff --git a/modules/gdnative/include/gdnative/string.h b/modules/gdnative/include/gdnative/string.h index dfd4fcab89..d89383dc1b 100644 --- a/modules/gdnative/include/gdnative/string.h +++ b/modules/gdnative/include/gdnative/string.h @@ -145,14 +145,13 @@ godot_string GDAPI godot_string_rpad_with_custom_character(const godot_string *p godot_real GDAPI godot_string_similarity(const godot_string *p_self, const godot_string *p_string); godot_string GDAPI godot_string_sprintf(const godot_string *p_self, const godot_array *p_values, godot_bool *p_error); godot_string GDAPI godot_string_substr(const godot_string *p_self, godot_int p_from, godot_int p_chars); -double GDAPI godot_string_to_double(const godot_string *p_self); -godot_real GDAPI godot_string_to_float(const godot_string *p_self); +double GDAPI godot_string_to_float(const godot_string *p_self); godot_int GDAPI godot_string_to_int(const godot_string *p_self); godot_string GDAPI godot_string_camelcase_to_underscore(const godot_string *p_self); godot_string GDAPI godot_string_camelcase_to_underscore_lowercased(const godot_string *p_self); godot_string GDAPI godot_string_capitalize(const godot_string *p_self); -double GDAPI godot_string_char_to_double(const char *p_what); +double GDAPI godot_string_char_to_float(const char *p_what); godot_int GDAPI godot_string_char_to_int(const char *p_what); int64_t GDAPI godot_string_wchar_to_int(const wchar_t *p_str); godot_int GDAPI godot_string_char_to_int_with_len(const char *p_what, godot_int p_len); @@ -160,7 +159,7 @@ int64_t GDAPI godot_string_char_to_int64_with_len(const wchar_t *p_str, int p_le int64_t GDAPI godot_string_hex_to_int64(const godot_string *p_self); int64_t GDAPI godot_string_hex_to_int64_with_prefix(const godot_string *p_self); int64_t GDAPI godot_string_to_int64(const godot_string *p_self); -double GDAPI godot_string_unicode_char_to_double(const wchar_t *p_str, const wchar_t **r_end); +double GDAPI godot_string_unicode_char_to_float(const wchar_t *p_str, const wchar_t **r_end); godot_int GDAPI godot_string_get_slice_count(const godot_string *p_self, godot_string p_splitter); godot_string GDAPI godot_string_get_slice(const godot_string *p_self, godot_string p_splitter, godot_int p_slice); diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 94aa2125c2..632f4e5fee 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -991,7 +991,8 @@ void NativeScriptInstance::notification(int p_notification) { Variant value = p_notification; const Variant *args[1] = { &value }; - call_multilevel("_notification", args, 1); + Callable::CallError error; + call("_notification", args, 1, error); } String NativeScriptInstance::to_string(bool *r_valid) { @@ -1087,31 +1088,6 @@ ScriptLanguage *NativeScriptInstance::get_language() { return NativeScriptLanguage::get_singleton(); } -void NativeScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - NativeScriptDesc *script_data = GET_SCRIPT_DESC(); - - while (script_data) { - Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); - if (E) { - godot_variant res = E->get().method.method((godot_object *)owner, - E->get().method.method_data, - userdata, - p_argcount, - (godot_variant **)p_args); - godot_variant_destroy(&res); - } - script_data = script_data->base_data; - } -} - -void NativeScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - NativeScriptDesc *script_data = GET_SCRIPT_DESC(); - - if (script_data) { - _ml_call_reversed(script_data, p_method, p_args, p_argcount); - } -} - NativeScriptInstance::~NativeScriptInstance() { NativeScriptDesc *script_data = GET_SCRIPT_DESC(); diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index e709ce2337..145bf7dcb6 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -231,9 +231,6 @@ public: virtual ScriptLanguage *get_language(); - virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); - virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); - virtual void refcount_incremented(); virtual bool refcount_decremented(); diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h index 6309b6fde3..690d1a0432 100644 --- a/modules/gdnative/pluginscript/pluginscript_instance.h +++ b/modules/gdnative/pluginscript/pluginscript_instance.h @@ -62,12 +62,6 @@ public: virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - // Rely on default implementations provided by ScriptInstance for the moment. - // Note that multilevel call could be removed in 3.0 release, so stay tuned - // (see https://godotengine.org/qa/9244/can-override-the-_ready-and-_process-functions-child-classes) - //virtual void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount); - //virtual void call_multilevel_reversed(const StringName& p_method,const Variant** p_args,int p_argcount); - virtual void notification(int p_notification); virtual Ref<Script> get_script() const; diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 36de66ea52..9e40a69712 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -112,7 +112,7 @@ </argument> <description> Returns the arc tangent of [code]s[/code] in radians. Use it to get the angle from an angle's tangent in trigonometry: [code]atan(tan(angle)) == angle[/code]. - The method cannot know in which quadrant the angle should fall. See [method atan2] if you have both [code]y[code] and [code]x[/code]. + The method cannot know in which quadrant the angle should fall. See [method atan2] if you have both [code]y[/code] and [code]x[/code]. [codeblock] a = atan(0.5) # a is 0.463648 [/codeblock] @@ -318,7 +318,7 @@ </argument> <description> The natural exponential function. It raises the mathematical constant [b]e[/b] to the power of [code]s[/code] and returns it. - [b]e[/b] has an approximate value of 2.71828. + [b]e[/b] has an approximate value of 2.71828, and can be obtained with [code]exp(1)[/code]. For exponents to other bases use the method [method pow]. [codeblock] a = exp(2) # Approximately 7.39 @@ -505,6 +505,8 @@ </argument> <description> Returns [code]true[/code] if [code]a[/code] and [code]b[/code] are approximately equal to each other. + Here, approximately equal means that [code]a[/code] and [code]b[/code] are within a small internal epsilon of each other, which scales with the magnitude of the numbers. + Infinity values of the same sign are considered equal. </description> </method> <method name="is_inf"> @@ -641,6 +643,7 @@ [codeblock] log(10) # Returns 2.302585 [/codeblock] + [b]Note:[/b] The logarithm of [code]0[/code] returns [code]-inf[/code], while negative values return [code]-nan[/code]. </description> </method> <method name="max"> @@ -686,7 +689,9 @@ Moves [code]from[/code] toward [code]to[/code] by the [code]delta[/code] value. Use a negative [code]delta[/code] value to move away. [codeblock] + move_toward(5, 10, 4) # Returns 9 move_toward(10, 5, 4) # Returns 6 + move_toward(10, 5, -1.5) # Returns 11.5 [/codeblock] </description> </method> @@ -696,12 +701,17 @@ <argument index="0" name="value" type="int"> </argument> <description> - Returns the nearest larger power of 2 for integer [code]value[/code]. + Returns the nearest equal or larger power of 2 for integer [code]value[/code]. + In other words, returns the smallest value [code]a[/code] where [code]a = pow(2, n)[/code] such that [code]value <= a[/code] for some non-negative integer [code]n[/code]. [codeblock] nearest_po2(3) # Returns 4 nearest_po2(4) # Returns 4 nearest_po2(5) # Returns 8 + + nearest_po2(0) # Returns 0 (this may not be what you expect) + nearest_po2(-1) # Returns 0 (this may not be what you expect) [/codeblock] + [b]WARNING:[/b] Due to the way it is implemented, this function returns [code]0[/code] rather than [code]1[/code] for non-positive values of [code]value[/code] (in reality, 1 is the smallest integer power of 2). </description> </method> <method name="ord"> @@ -725,16 +735,17 @@ <argument index="0" name="json" type="String"> </argument> <description> - Parse JSON text to a Variant (use [method typeof] to check if it is what you expect). - Be aware that the JSON specification does not define integer or float types, but only a number type. Therefore, parsing a JSON text will convert all numerical values to [float] types. - Note that JSON objects do not preserve key order like Godot dictionaries, thus you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements: + Parse JSON text to a Variant. (Use [method typeof] to check if the Variant's type is what you expect.) + [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, parsing a JSON text will convert all numerical values to [float] types. + [b]Note:[/b] JSON objects do not preserve key order like Godot dictionaries, thus, you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements: [codeblock] - p = parse_json('["a", "b", "c"]') - if typeof(p) == TYPE_ARRAY: - print(p[0]) # Prints a + var p = JSON.parse('["hello", "world", "!"]') + if typeof(p.result) == TYPE_ARRAY: + print(p.result[0]) # Prints "hello" else: - print("unexpected results") + push_error("Unexpected results.") [/codeblock] + See also [JSON] for an alternative way to parse JSON text. </description> </method> <method name="polar2cartesian"> @@ -1093,12 +1104,15 @@ </argument> <argument index="1" name="to" type="float"> </argument> - <argument index="2" name="weight" type="float"> + <argument index="2" name="s" type="float"> </argument> <description> - Returns a number smoothly interpolated between the [code]from[/code] and [code]to[/code], based on the [code]weight[/code]. Similar to [method lerp], but interpolates faster at the beginning and slower at the end. + Returns the result of smoothly interpolating the value of [code]s[/code] between [code]0[/code] and [code]1[/code], based on the where [code]s[/code] lies with respect to the edges [code]from[/code] and [code]to[/code]. + The return value is [code]0[/code] if [code]s <= from[/code], and [code]1[/code] if [code]s >= to[/code]. If [code]s[/code] lies between [code]from[/code] and [code]to[/code], the returned value follows an S-shaped curve that maps [code]s[/code] between [code]0[/code] and [code]1[/code]. + This S-shaped curve is the cubic Hermite interpolator, given by [code]f(s) = 3*s^2 - 2*s^3[/code]. [codeblock] - smoothstep(0, 2, 0.5) # Returns 0.15 + smoothstep(0, 2, -5.0) # Returns 0.0 + smoothstep(0, 2, 0.5) # Returns 0.15625 smoothstep(0, 2, 1.0) # Returns 0.5 smoothstep(0, 2, 2.0) # Returns 1.0 [/codeblock] @@ -1114,7 +1128,7 @@ [codeblock] sqrt(9) # Returns 3 [/codeblock] - If you need negative inputs, use [code]System.Numerics.Complex[/code] in C#. + [b]Note:[/b]Negative values of [code]s[/code] return NaN. If you need negative inputs, use [code]System.Numerics.Complex[/code] in C#. </description> </method> <method name="step_decimals"> @@ -1207,12 +1221,16 @@ <argument index="0" name="var" type="Variant"> </argument> <description> - Converts a Variant [code]var[/code] to JSON text and return the result. Useful for serializing data to store or send over the network. + Converts a [Variant] [code]var[/code] to JSON text and return the result. Useful for serializing data to store or send over the network. [codeblock] + # Both numbers below are integers. a = { "a": 1, "b": 2 } b = to_json(a) print(b) # {"a":1, "b":2} + # Both numbers above are floats, even if they display without any decimal places. [/codeblock] + [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, converting a [Variant] to JSON text will convert all numerical values to [float] types. + See also [JSON] for an alternative way to convert a [Variant] to JSON text. </description> </method> <method name="type_exists"> @@ -1255,9 +1273,9 @@ j = to_json([1, 2, 3]) v = validate_json(j) if not v: - print("valid") + print("Valid JSON.") else: - prints("invalid", v) + push_error("Invalid JSON: " + v) [/codeblock] </description> </method> @@ -1354,42 +1372,6 @@ [code]wrapi[/code] is more flexible than using the [method posmod] approach by giving the user control over the minimum value. </description> </method> - <method name="yield"> - <return type="GDScriptFunctionState"> - </return> - <argument index="0" name="object" type="Object" default="null"> - </argument> - <argument index="1" name="signal" type="String" default=""""> - </argument> - <description> - Stops the function execution and returns the current suspended state to the calling function. - From the caller, call [method GDScriptFunctionState.resume] on the state to resume execution. This invalidates the state. Within the resumed function, [code]yield()[/code] returns whatever was passed to the [code]resume()[/code] function call. - If passed an object and a signal, the execution is resumed when the object emits the given signal. In this case, [code]yield()[/code] returns the argument passed to [code]emit_signal()[/code] if the signal takes only one argument, or an array containing all the arguments passed to [code]emit_signal()[/code] if the signal takes multiple arguments. - You can also use [code]yield[/code] to wait for a function to finish: - [codeblock] - func _ready(): - yield(countdown(), "completed") # waiting for the countdown() function to complete - print('Ready') - - func countdown(): - yield(get_tree(), "idle_frame") # returns a GDScriptFunctionState object to _ready() - print(3) - yield(get_tree().create_timer(1.0), "timeout") - print(2) - yield(get_tree().create_timer(1.0), "timeout") - print(1) - yield(get_tree().create_timer(1.0), "timeout") - - # prints: - # 3 - # 2 - # 1 - # Ready - [/codeblock] - When yielding on a function, the [code]completed[/code] signal will be emitted automatically when the function returns. It can, therefore, be used as the [code]signal[/code] parameter of the [code]yield[/code] method to resume. - In order to yield on a function, the resulting function should also return a [code]GDScriptFunctionState[/code]. Notice [code]yield(get_tree(), "idle_frame")[/code] from the above example. - </description> - </method> </methods> <constants> <constant name="PI" value="3.141593"> diff --git a/modules/gdscript/doc_classes/GDScriptFunctionState.xml b/modules/gdscript/doc_classes/GDScriptFunctionState.xml index 9a73764646..5e369b32d9 100644 --- a/modules/gdscript/doc_classes/GDScriptFunctionState.xml +++ b/modules/gdscript/doc_classes/GDScriptFunctionState.xml @@ -4,7 +4,8 @@ State of a function call after yielding. </brief_description> <description> - Calling [method @GDScript.yield] within a function will cause that function to yield and return its current state as an object of this type. The yielded function call can then be resumed later by calling [method resume] on this state object. + FIXME: Outdated docs as of GDScript rewrite in 4.0. + Calling [code]yield[/code] within a function will cause that function to yield and return its current state as an object of this type. The yielded function call can then be resumed later by calling [method resume] on this state object. </description> <tutorials> </tutorials> @@ -26,7 +27,7 @@ </argument> <description> Resume execution of the yielded function call. - If handed an argument, return the argument from the [method @GDScript.yield] call in the yielded function call. You can pass e.g. an [Array] to hand multiple arguments. + If handed an argument, return the argument from the [code]yield[/code] call in the yielded function call. You can pass e.g. an [Array] to hand multiple arguments. This function returns what the resumed function call returns, possibly another function state if yielded again. </description> </method> diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 40ef0aeec6..9170255c02 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1309,39 +1309,6 @@ Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_arg return Variant(); } -void GDScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - GDScript *sptr = script.ptr(); - Callable::CallError ce; - - while (sptr) { - Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method); - if (E) { - E->get()->call(this, p_args, p_argcount, ce); - return; - } - sptr = sptr->_base; - } -} - -void GDScriptInstance::_ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount) { - if (sptr->_base) { - _ml_call_reversed(sptr->_base, p_method, p_args, p_argcount); - } - - Callable::CallError ce; - - Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method); - if (E) { - E->get()->call(this, p_args, p_argcount, ce); - } -} - -void GDScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - if (script.ptr()) { - _ml_call_reversed(script.ptr(), p_method, p_args, p_argcount); - } -} - void GDScriptInstance::notification(int p_notification) { //notification is not virtual, it gets called at ALL levels just like in C. Variant value = p_notification; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 8236464f15..9906b4014d 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -146,7 +146,6 @@ protected: void _get_property_list(List<PropertyInfo> *p_properties) const; Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; - //void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount); static void _bind_methods(); @@ -258,8 +257,6 @@ class GDScriptInstance : public ScriptInstance { SelfList<GDScriptFunctionState>::List pending_func_states; - void _ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount); - public: virtual Object *get_owner() { return owner; } @@ -271,8 +268,6 @@ public: virtual void get_method_list(List<MethodInfo> *p_list) const; virtual bool has_method(const StringName &p_method) const; virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); - virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); Variant debug_get_member_by_index(int p_idx) const { return members[p_idx]; } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index fdcd4412d2..531666bec5 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -342,6 +342,16 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type return result; } + if (first == "Object") { + result.kind = GDScriptParser::DataType::NATIVE; + result.native_type = "Object"; + if (p_type->type_chain.size() > 1) { + push_error(R"("Object" type don't contain nested types.)", p_type->type_chain[1]); + return GDScriptParser::DataType(); + } + return result; + } + if (GDScriptParser::get_builtin_type(first) < Variant::VARIANT_MAX) { // Built-in types. if (p_type->type_chain.size() > 1) { @@ -484,7 +494,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas if (member.variable->initializer != nullptr) { if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true)) { - push_error(vformat(R"(Value of type "%s" cannot be assigned to variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer); + push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer); } else if (datatype.builtin_type == Variant::INT && member.variable->initializer->get_datatype().builtin_type == Variant::FLOAT) { #ifdef DEBUG_ENABLED parser->push_warning(member.variable->initializer, GDScriptWarning::NARROWING_CONVERSION); @@ -979,7 +989,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable if (p_variable->initializer != nullptr) { if (!is_type_compatible(type, p_variable->initializer->get_datatype(), true)) { - push_error(vformat(R"(Value of type "%s" cannot be assigned to variable of type "%s".)", p_variable->initializer->get_datatype().to_string(), type.to_string()), p_variable->initializer); + push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", p_variable->initializer->get_datatype().to_string(), type.to_string()), p_variable->initializer); #ifdef DEBUG_ENABLED } else if (type.builtin_type == Variant::INT && p_variable->initializer->get_datatype().builtin_type == Variant::FLOAT) { parser->push_warning(p_variable->initializer, GDScriptWarning::NARROWING_CONVERSION); @@ -1468,6 +1478,12 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig } void GDScriptAnalyzer::reduce_await(GDScriptParser::AwaitNode *p_await) { + if (p_await->to_await == nullptr) { + GDScriptParser::DataType await_type; + await_type.kind = GDScriptParser::DataType::VARIANT; + p_await->set_datatype(await_type); + return; + } if (p_await->to_await->type == GDScriptParser::Node::CALL) { reduce_call(static_cast<GDScriptParser::CallNode *>(p_await->to_await), true); } else { @@ -2051,7 +2067,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod GDScriptParser::ClassNode *outer = base_class->outer; while (outer != nullptr) { if (outer->has_member(name)) { - const GDScriptParser::ClassNode::Member &member = base_class->get_member(name); + const GDScriptParser::ClassNode::Member &member = outer->get_member(name); if (member.type == GDScriptParser::ClassNode::Member::CONSTANT) { // TODO: Make sure loops won't cause problem. And make special error message for those. // For out-of-order resolution: diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 3d37c7f803..e34d87f5cc 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -736,7 +736,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } else { if (callee->type == GDScriptParser::Node::IDENTIFIER) { // Self function call. - if (codegen.function_node && codegen.function_node->is_static) { + if ((codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") { ret = (GDScriptFunction::ADDR_TYPE_CLASS << GDScriptFunction::ADDR_BITS); } else { ret = (GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS); diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp index 7f2a62a8e9..fefbf906f0 100644 --- a/modules/gdscript/gdscript_functions.cpp +++ b/modules/gdscript/gdscript_functions.cpp @@ -1636,7 +1636,7 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { return mi; } break; case MATH_SMOOTHSTEP: { - MethodInfo mi("smoothstep", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "weight")); + MethodInfo mi("smoothstep", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "s")); mi.return_val.type = Variant::FLOAT; return mi; } break; diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index d230173e9a..7a4bdd88ba 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -646,7 +646,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { int64_t value = number.bin_to_int(); return make_literal(value); } else if (has_decimal || has_exponent) { - double value = number.to_double(); + double value = number.to_float(); return make_literal(value); } else { int64_t value = number.to_int(); diff --git a/modules/modules_builders.py b/modules/modules_builders.py index e7be6380d1..2243162555 100644 --- a/modules/modules_builders.py +++ b/modules/modules_builders.py @@ -12,5 +12,16 @@ def generate_modules_enabled(target, source, env): f.write("#define %s\n" % ("MODULE_" + module.upper() + "_ENABLED")) +def generate_modules_tests(target, source, env): + import os + import glob + + with open(target[0].path, "w") as f: + for name, path in env.module_list.items(): + headers = glob.glob(os.path.join(path, "tests", "*.h")) + for h in headers: + f.write('#include "%s"\n' % (os.path.normpath(h))) + + if __name__ == "__main__": subprocess_main(globals()) diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index 80e3b59325..3e771e06f0 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -125,7 +125,8 @@ def configure(env, env_mono): if not mono_prefix and (os.getenv("MONO32_PREFIX") or os.getenv("MONO64_PREFIX")): print( - "WARNING: The environment variables 'MONO32_PREFIX' and 'MONO64_PREFIX' are deprecated; use the 'mono_prefix' SCons parameter instead" + "WARNING: The environment variables 'MONO32_PREFIX' and 'MONO64_PREFIX' are deprecated; use the" + " 'mono_prefix' SCons parameter instead" ) # Although we don't support building with tools for any platform where we currently use static AOT, diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 7d3ae31588..bbdec224f0 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -44,7 +44,6 @@ #ifdef TOOLS_ENABLED #include "editor/bindings_generator.h" -#include "editor/csharp_project.h" #include "editor/editor_node.h" #include "editor/node_dock.h" #endif @@ -897,7 +896,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { // Call OnBeforeSerialize if (csi->script->script_class->implements_interface(CACHED_CLASS(ISerializationListener))) { - obj->get_script_instance()->call_multilevel(string_names.on_before_serialize); + obj->get_script_instance()->call(string_names.on_before_serialize); } // Save instance info @@ -1133,7 +1132,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { // Call OnAfterDeserialization if (csi->script->script_class->implements_interface(CACHED_CLASS(ISerializationListener))) { - obj->get_script_instance()->call_multilevel(string_names.on_after_deserialize); + obj->get_script_instance()->call(string_names.on_after_deserialize); } } } @@ -1866,41 +1865,6 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, return Variant(); } -void CSharpInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - GD_MONO_SCOPE_THREAD_ATTACH; - - if (script.is_valid()) { - MonoObject *mono_object = get_mono_object(); - - ERR_FAIL_NULL(mono_object); - - _call_multilevel(mono_object, p_method, p_args, p_argcount); - } -} - -void CSharpInstance::_call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount) { - GD_MONO_ASSERT_THREAD_ATTACHED; - - GDMonoClass *top = script->script_class; - - while (top && top != script->native) { - GDMonoMethod *method = top->get_method(p_method, p_argcount); - - if (method) { - method->invoke(p_mono_object, p_args); - return; - } - - top = top->get_parent_class(); - } -} - -void CSharpInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - // Sorry, the method is the one that controls the call order - - call_multilevel(p_method, p_args, p_argcount); -} - bool CSharpInstance::_reference_owner_unsafe() { #ifdef DEBUG_ENABLED CRASH_COND(!base_ref); @@ -3759,13 +3723,9 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r #ifdef TOOLS_ENABLED if (!FileAccess::exists(p_path)) { - // The file does not yet exists, let's assume the user just created this script - - if (_create_project_solution_if_needed()) { - CSharpProject::add_item(GodotSharpDirs::get_project_csproj_path(), - "Compile", - ProjectSettings::get_singleton()->globalize_path(p_path)); - } else { + // The file does not yet exist, let's assume the user just created this script. In such + // cases we need to check whether the solution and csproj were already created or not. + if (!_create_project_solution_if_needed()) { ERR_PRINT("C# project could not be created; cannot add file: '" + p_path + "'."); } } diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index c2370364f9..f0b43a40f9 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -265,8 +265,6 @@ class CSharpInstance : public ScriptInstance { friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *); static CSharpInstance *create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle); - void _call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount); - void get_properties_state_for_reloading(List<Pair<StringName, Variant>> &r_state); void get_event_signals_state_for_reloading(List<Pair<StringName, Array>> &r_state); @@ -285,8 +283,6 @@ public: /* TODO */ void get_method_list(List<MethodInfo> *p_list) const override {} bool has_method(const StringName &p_method) const override; Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; - void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) override; - void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) override; void mono_object_disposed(MonoObject *p_obj); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln new file mode 100644 index 0000000000..56c0cb7703 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.NET.Sdk", "Godot.NET.Sdk\Godot.NET.Sdk.csproj", "{31B00BFA-DEA1-42FA-A472-9E54A92A8A5F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {31B00BFA-DEA1-42FA-A472-9E54A92A8A5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {31B00BFA-DEA1-42FA-A472-9E54A92A8A5F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {31B00BFA-DEA1-42FA-A472-9E54A92A8A5F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {31B00BFA-DEA1-42FA-A472-9E54A92A8A5F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj new file mode 100644 index 0000000000..86a0a4393e --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj @@ -0,0 +1,35 @@ +<Project Sdk="Microsoft.Build.NoTargets/2.0.1"> + <PropertyGroup> + <TargetFramework>netstandard2.0</TargetFramework> + + <Description>MSBuild .NET Sdk for Godot projects.</Description> + <Authors>Godot Engine contributors</Authors> + + <PackageId>Godot.NET.Sdk</PackageId> + <Version>4.0.0</Version> + <PackageVersion>4.0.0-dev2</PackageVersion> + <PackageProjectUrl>https://github.com/godotengine/godot/tree/master/modules/mono/editor/Godot.NET.Sdk</PackageProjectUrl> + <PackageType>MSBuildSdk</PackageType> + <PackageTags>MSBuildSdk</PackageTags> + <GeneratePackageOnBuild>true</GeneratePackageOnBuild> + </PropertyGroup> + + <PropertyGroup> + <NuspecFile>Godot.NET.Sdk.nuspec</NuspecFile> + <GenerateNuspecDependsOn>$(GenerateNuspecDependsOn);SetNuSpecProperties</GenerateNuspecDependsOn> + </PropertyGroup> + + <Target Name="SetNuSpecProperties" Condition=" Exists('$(NuspecFile)') "> + <PropertyGroup> + <NuspecProperties> + id=$(PackageId); + description=$(Description); + authors=$(Authors); + version=$(PackageVersion); + packagetype=$(PackageType); + tags=$(PackageTags); + projecturl=$(PackageProjectUrl) + </NuspecProperties> + </PropertyGroup> + </Target> +</Project> diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.nuspec b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.nuspec new file mode 100644 index 0000000000..5b5cefe80e --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.nuspec @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8" ?> +<package xmlns="http://schemas.microsoft.com/packaging/2011/10/nuspec.xsd"> + <metadata> + <id>$id$</id> + <version>$version$</version> + <description>$description$</description> + <authors>$authors$</authors> + <owners>$authors$</owners> + <projectUrl>$projecturl$</projectUrl> + <requireLicenseAcceptance>false</requireLicenseAcceptance> + <license type="expression">MIT</license> + <licenseUrl>https://licenses.nuget.org/MIT</licenseUrl> + <tags>$tags$</tags> + <packageTypes> + <packageType name="$packagetype$" /> + </packageTypes> + <repository url="$projecturl$" /> + </metadata> + <files> + <file src="Sdk\**" target="Sdk" />\ + </files> +</package> diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props new file mode 100644 index 0000000000..dfc59e6ccb --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props @@ -0,0 +1,112 @@ +<Project> + <PropertyGroup> + <!-- Determines if we should import Microsoft.NET.Sdk, if it wasn't already imported. --> + <GodotSdkImportsMicrosoftNetSdk Condition=" '$(UsingMicrosoftNETSdk)' != 'true' ">true</GodotSdkImportsMicrosoftNetSdk> + + <GodotProjectTypeGuid>{8F3E2DF0-C35C-4265-82FC-BEA011F4A7ED}</GodotProjectTypeGuid> + </PropertyGroup> + + <PropertyGroup> + <Configurations>Debug;ExportDebug;ExportRelease</Configurations> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + + <GodotProjectDir Condition=" '$(SolutionDir)' != '' ">$(SolutionDir)</GodotProjectDir> + <GodotProjectDir Condition=" '$(SolutionDir)' == '' ">$(MSBuildProjectDirectory)</GodotProjectDir> + <GodotProjectDir>$([MSBuild]::EnsureTrailingSlash('$(GodotProjectDir)'))</GodotProjectDir> + + <!-- Custom output paths for Godot projects. In brief, 'bin\' and 'obj\' are moved to '$(GodotProjectDir)\.mono\temp\'. --> + <BaseOutputPath>$(GodotProjectDir).mono\temp\bin\</BaseOutputPath> + <OutputPath>$(GodotProjectDir).mono\temp\bin\$(Configuration)\</OutputPath> + <!-- + Use custom IntermediateOutputPath and BaseIntermediateOutputPath only if it wasn't already set. + Otherwise the old values may have already been changed by MSBuild which can cause problems with NuGet. + --> + <IntermediateOutputPath Condition=" '$(IntermediateOutputPath)' == '' ">$(GodotProjectDir).mono\temp\obj\$(Configuration)\</IntermediateOutputPath> + <BaseIntermediateOutputPath Condition=" '$(BaseIntermediateOutputPath)' == '' ">$(GodotProjectDir).mono\temp\obj\</BaseIntermediateOutputPath> + + <!-- Do not append the target framework name to the output path. --> + <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> + </PropertyGroup> + + <Import Sdk="Microsoft.NET.Sdk" Project="Sdk.props" Condition=" '$(GodotSdkImportsMicrosoftNetSdk)' == 'true' " /> + + <PropertyGroup> + <EnableDefaultNoneItems>false</EnableDefaultNoneItems> + </PropertyGroup> + + <!-- + The Microsoft.NET.Sdk only understands of the Debug and Release configurations. + We need to set the following properties manually for ExportDebug and ExportRelease. + --> + <PropertyGroup Condition=" '$(Configuration)' == 'Debug' or '$(Configuration)' == 'ExportDebug' "> + <DebugSymbols Condition=" '$(DebugSymbols)' == '' ">true</DebugSymbols> + <Optimize Condition=" '$(Optimize)' == '' ">false</Optimize> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)' == 'ExportRelease' "> + <Optimize Condition=" '$(Optimize)' == '' ">true</Optimize> + </PropertyGroup> + + <PropertyGroup> + <GodotApiConfiguration Condition=" '$(Configuration)' != 'ExportRelease' ">Debug</GodotApiConfiguration> + <GodotApiConfiguration Condition=" '$(Configuration)' == 'ExportRelease' ">Release</GodotApiConfiguration> + </PropertyGroup> + + <!-- Auto-detect the target Godot platform if it was not specified. --> + <PropertyGroup Condition=" '$(GodotTargetPlatform)' == '' "> + <GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(Linux))' ">linuxbsd</GodotTargetPlatform> + <GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(FreeBSD))' ">linuxbsd</GodotTargetPlatform> + <GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(OSX))' ">osx</GodotTargetPlatform> + <GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(Windows))' ">windows</GodotTargetPlatform> + </PropertyGroup> + + <PropertyGroup> + <GodotRealTIsDouble Condition=" '$(GodotRealTIsDouble)' == '' ">false</GodotRealTIsDouble> + </PropertyGroup> + + <!-- Godot DefineConstants. --> + <PropertyGroup> + <!-- Define constant to identify Godot builds. --> + <GodotDefineConstants>GODOT</GodotDefineConstants> + + <!-- + Define constant to determine the target Godot platform. This includes the + recognized platform names and the platform category (PC, MOBILE or WEB). + --> + <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'windows' ">GODOT_WINDOWS;GODOT_PC</GodotPlatformConstants> + <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'linuxbsd' ">GODOT_LINUXBSD;GODOT_PC</GodotPlatformConstants> + <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'osx' ">GODOT_OSX;GODOT_MACOS;GODOT_PC</GodotPlatformConstants> + <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'server' ">GODOT_SERVER;GODOT_PC</GodotPlatformConstants> + <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'uwp' ">GODOT_UWP;GODOT_PC</GodotPlatformConstants> + <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'haiku' ">GODOT_HAIKU;GODOT_PC</GodotPlatformConstants> + <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'android' ">GODOT_ANDROID;GODOT_MOBILE</GodotPlatformConstants> + <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'iphone' ">GODOT_IPHONE;GODOT_IOS;GODOT_MOBILE</GodotPlatformConstants> + <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'javascript' ">GODOT_JAVASCRIPT;GODOT_HTML5;GODOT_WASM;GODOT_WEB</GodotPlatformConstants> + + <GodotDefineConstants>$(GodotDefineConstants);$(GodotPlatformConstants)</GodotDefineConstants> + </PropertyGroup> + + <PropertyGroup> + <!-- ExportDebug also defines DEBUG like Debug does. --> + <DefineConstants Condition=" '$(Configuration)' == 'ExportDebug' ">$(DefineConstants);DEBUG</DefineConstants> + <!-- Debug defines TOOLS to differenciate between Debug and ExportDebug configurations. --> + <DefineConstants Condition=" '$(Configuration)' == 'Debug' ">$(DefineConstants);TOOLS</DefineConstants> + + <DefineConstants>$(GodotDefineConstants);$(DefineConstants)</DefineConstants> + </PropertyGroup> + + <ItemGroup> + <!-- + TODO: + We should consider a nuget package for reference assemblies. This is difficult because the + Godot scripting API is continuaslly breaking backwards compatibility even in patch releases. + --> + <Reference Include="GodotSharp"> + <Private>false</Private> + <HintPath>$(GodotProjectDir).mono\assemblies\$(GodotApiConfiguration)\GodotSharp.dll</HintPath> + </Reference> + <Reference Include="GodotSharpEditor" Condition=" '$(Configuration)' == 'Debug' "> + <Private>false</Private> + <HintPath>$(GodotProjectDir).mono\assemblies\$(GodotApiConfiguration)\GodotSharpEditor.dll</HintPath> + </Reference> + </ItemGroup> +</Project> diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets new file mode 100644 index 0000000000..f5afd75505 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets @@ -0,0 +1,17 @@ +<Project> + <Import Sdk="Microsoft.NET.Sdk" Project="Sdk.targets" Condition=" '$(GodotSdkImportsMicrosoftNetSdk)' == 'true' " /> + + <PropertyGroup> + <EnableGodotProjectTypeGuid Condition=" '$(EnableGodotProjectTypeGuid)' == '' ">true</EnableGodotProjectTypeGuid> + <ProjectTypeGuids Condition=" '$(EnableGodotProjectTypeGuid)' == 'true' ">$(GodotProjectTypeGuid);$(DefaultProjectTypeGuid)</ProjectTypeGuids> + </PropertyGroup> + + <PropertyGroup> + <!-- + Define constant to determine whether the real_t type in Godot is double precision or not. + By default this is false, like the official Godot builds. If someone is using a custom + Godot build where real_t is double, they can override the GodotRealTIsDouble property. + --> + <DefineConstants Condition=" '$(GodotRealTIsDouble)' == 'true' ">GODOT_REAL_T_IS_DOUBLE;$(DefineConstants)</DefineConstants> + </PropertyGroup> +</Project> diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/FileUtils.cs b/modules/mono/editor/GodotTools/GodotTools.Core/FileUtils.cs index 85760a3705..e1ccf0454a 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Core/FileUtils.cs +++ b/modules/mono/editor/GodotTools/GodotTools.Core/FileUtils.cs @@ -19,7 +19,10 @@ namespace GodotTools.Core } if (attempt > maxAttempts + 1) - return; + { + // Overwrite the oldest one + backupPath = backupPathBase; + } File.Copy(filePath, backupPath, overwrite: true); } diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/IdentifierUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/IdentifierUtils.cs index f93eb9a1fa..ed77076df3 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/IdentifierUtils.cs +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/IdentifierUtils.cs @@ -22,6 +22,37 @@ namespace GodotTools.ProjectEditor return string.Join(".", identifiers); } + /// <summary> + /// Skips invalid identifier characters including decimal digit numbers at the start of the identifier. + /// </summary> + private static void SkipInvalidCharacters(string source, int startIndex, StringBuilder outputBuilder) + { + for (int i = startIndex; i < source.Length; i++) + { + char @char = source[i]; + + switch (char.GetUnicodeCategory(@char)) + { + case UnicodeCategory.UppercaseLetter: + case UnicodeCategory.LowercaseLetter: + case UnicodeCategory.TitlecaseLetter: + case UnicodeCategory.ModifierLetter: + case UnicodeCategory.LetterNumber: + case UnicodeCategory.OtherLetter: + outputBuilder.Append(@char); + break; + case UnicodeCategory.NonSpacingMark: + case UnicodeCategory.SpacingCombiningMark: + case UnicodeCategory.ConnectorPunctuation: + case UnicodeCategory.DecimalDigitNumber: + // Identifiers may start with underscore + if (outputBuilder.Length > startIndex || @char == '_') + outputBuilder.Append(@char); + break; + } + } + } + public static string SanitizeIdentifier(string identifier, bool allowEmpty) { if (string.IsNullOrEmpty(identifier)) @@ -44,30 +75,7 @@ namespace GodotTools.ProjectEditor startIndex += 1; } - for (int i = startIndex; i < identifier.Length; i++) - { - char @char = identifier[i]; - - switch (Char.GetUnicodeCategory(@char)) - { - case UnicodeCategory.UppercaseLetter: - case UnicodeCategory.LowercaseLetter: - case UnicodeCategory.TitlecaseLetter: - case UnicodeCategory.ModifierLetter: - case UnicodeCategory.LetterNumber: - case UnicodeCategory.OtherLetter: - identifierBuilder.Append(@char); - break; - case UnicodeCategory.NonSpacingMark: - case UnicodeCategory.SpacingCombiningMark: - case UnicodeCategory.ConnectorPunctuation: - case UnicodeCategory.DecimalDigitNumber: - // Identifiers may start with underscore - if (identifierBuilder.Length > startIndex || @char == '_') - identifierBuilder.Append(@char); - break; - } - } + SkipInvalidCharacters(identifier, startIndex, identifierBuilder); if (identifierBuilder.Length == startIndex) { diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectExtensions.cs deleted file mode 100644 index 704f2ec194..0000000000 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectExtensions.cs +++ /dev/null @@ -1,118 +0,0 @@ -using GodotTools.Core; -using System; -using System.Collections.Generic; -using System.IO; -using Microsoft.Build.Construction; -using Microsoft.Build.Globbing; - -namespace GodotTools.ProjectEditor -{ - public static class ProjectExtensions - { - public static ProjectItemElement FindItemOrNull(this ProjectRootElement root, string itemType, string include, bool noCondition = false) - { - string normalizedInclude = include.NormalizePath(); - - foreach (var itemGroup in root.ItemGroups) - { - if (noCondition && itemGroup.Condition.Length != 0) - continue; - - foreach (var item in itemGroup.Items) - { - if (item.ItemType != itemType) - continue; - - //var glob = Glob.Parse(item.Include.NormalizePath(), globOptions); - var glob = MSBuildGlob.Parse(item.Include.NormalizePath()); - - if (glob.IsMatch(normalizedInclude)) - return item; - } - } - - return null; - } - public static ProjectItemElement FindItemOrNullAbs(this ProjectRootElement root, string itemType, string include, bool noCondition = false) - { - string normalizedInclude = Path.GetFullPath(include).NormalizePath(); - - foreach (var itemGroup in root.ItemGroups) - { - if (noCondition && itemGroup.Condition.Length != 0) - continue; - - foreach (var item in itemGroup.Items) - { - if (item.ItemType != itemType) - continue; - - var glob = MSBuildGlob.Parse(Path.GetFullPath(item.Include).NormalizePath()); - - if (glob.IsMatch(normalizedInclude)) - return item; - } - } - - return null; - } - - public static IEnumerable<ProjectItemElement> FindAllItemsInFolder(this ProjectRootElement root, string itemType, string folder) - { - string absFolderNormalizedWithSep = Path.GetFullPath(folder).NormalizePath() + Path.DirectorySeparatorChar; - - foreach (var itemGroup in root.ItemGroups) - { - foreach (var item in itemGroup.Items) - { - if (item.ItemType != itemType) - continue; - - string absPathNormalized = Path.GetFullPath(item.Include).NormalizePath(); - - if (absPathNormalized.StartsWith(absFolderNormalizedWithSep)) - yield return item; - } - } - } - - public static bool HasItem(this ProjectRootElement root, string itemType, string include, bool noCondition = false) - { - return root.FindItemOrNull(itemType, include, noCondition) != null; - } - - public static bool AddItemChecked(this ProjectRootElement root, string itemType, string include) - { - if (!root.HasItem(itemType, include, noCondition: true)) - { - root.AddItem(itemType, include); - return true; - } - - return false; - } - - public static bool RemoveItemChecked(this ProjectRootElement root, string itemType, string include) - { - var item = root.FindItemOrNullAbs(itemType, include); - if (item != null) - { - item.Parent.RemoveChild(item); - return true; - } - - return false; - } - - public static Guid GetGuid(this ProjectRootElement root) - { - foreach (var property in root.Properties) - { - if (property.Name == "ProjectGuid") - return Guid.Parse(property.Value); - } - - return Guid.Empty; - } - } -} diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs index 679d5bb444..5541876f9e 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs @@ -1,174 +1,49 @@ -using GodotTools.Core; using System; -using System.Collections.Generic; using System.IO; -using System.Reflection; using Microsoft.Build.Construction; +using Microsoft.Build.Evaluation; namespace GodotTools.ProjectEditor { public static class ProjectGenerator { - private const string CoreApiProjectName = "GodotSharp"; - private const string EditorApiProjectName = "GodotSharpEditor"; + public const string GodotSdkVersionToUse = "4.0.0-dev2"; - public const string CSharpProjectTypeGuid = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"; - public const string GodotProjectTypeGuid = "{8F3E2DF0-C35C-4265-82FC-BEA011F4A7ED}"; + public static string GodotSdkAttrValue => $"Godot.NET.Sdk/{GodotSdkVersionToUse}"; - public static readonly string GodotDefaultProjectTypeGuids = $"{GodotProjectTypeGuid};{CSharpProjectTypeGuid}"; - - public static string GenGameProject(string dir, string name, IEnumerable<string> compileItems) - { - string path = Path.Combine(dir, name + ".csproj"); - - ProjectPropertyGroupElement mainGroup; - var root = CreateLibraryProject(name, "Debug", out mainGroup); - - mainGroup.SetProperty("ProjectTypeGuids", GodotDefaultProjectTypeGuids); - mainGroup.SetProperty("OutputPath", Path.Combine(".mono", "temp", "bin", "$(Configuration)")); - mainGroup.SetProperty("BaseIntermediateOutputPath", Path.Combine(".mono", "temp", "obj")); - mainGroup.SetProperty("IntermediateOutputPath", Path.Combine("$(BaseIntermediateOutputPath)", "$(Configuration)")); - mainGroup.SetProperty("ApiConfiguration", "Debug").Condition = " '$(Configuration)' != 'ExportRelease' "; - mainGroup.SetProperty("ApiConfiguration", "Release").Condition = " '$(Configuration)' == 'ExportRelease' "; - - var debugGroup = root.AddPropertyGroup(); - debugGroup.Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "; - debugGroup.AddProperty("DebugSymbols", "true"); - debugGroup.AddProperty("DebugType", "portable"); - debugGroup.AddProperty("Optimize", "false"); - debugGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;DEBUG;TOOLS;"); - debugGroup.AddProperty("ErrorReport", "prompt"); - debugGroup.AddProperty("WarningLevel", "4"); - debugGroup.AddProperty("ConsolePause", "false"); - - var coreApiRef = root.AddItem("Reference", CoreApiProjectName); - coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", "$(ApiConfiguration)", CoreApiProjectName + ".dll")); - coreApiRef.AddMetadata("Private", "False"); - - var editorApiRef = root.AddItem("Reference", EditorApiProjectName); - editorApiRef.Condition = " '$(Configuration)' == 'Debug' "; - editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", "$(ApiConfiguration)", EditorApiProjectName + ".dll")); - editorApiRef.AddMetadata("Private", "False"); - - GenAssemblyInfoFile(root, dir, name); - - foreach (var item in compileItems) - { - root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\")); - } - - root.Save(path); - - return root.GetGuid().ToString().ToUpper(); - } - - private static void GenAssemblyInfoFile(ProjectRootElement root, string dir, string name, string[] assemblyLines = null, string[] usingDirectives = null) + public static ProjectRootElement GenGameProject(string name) { - string propertiesDir = Path.Combine(dir, "Properties"); - if (!Directory.Exists(propertiesDir)) - Directory.CreateDirectory(propertiesDir); - - string usingDirectivesText = string.Empty; + if (name.Length == 0) + throw new ArgumentException("Project name is empty", nameof(name)); - if (usingDirectives != null) - { - foreach (var usingDirective in usingDirectives) - usingDirectivesText += "\nusing " + usingDirective + ";"; - } + var root = ProjectRootElement.Create(NewProjectFileOptions.None); - string assemblyLinesText = string.Empty; + root.Sdk = GodotSdkAttrValue; - if (assemblyLines != null) - assemblyLinesText += string.Join("\n", assemblyLines) + "\n"; + var mainGroup = root.AddPropertyGroup(); + mainGroup.AddProperty("TargetFramework", "netstandard2.1"); - string content = string.Format(AssemblyInfoTemplate, usingDirectivesText, name, assemblyLinesText); + string sanitizedName = IdentifierUtils.SanitizeQualifiedIdentifier(name, allowEmptyIdentifiers: true); - string assemblyInfoFile = Path.Combine(propertiesDir, "AssemblyInfo.cs"); + // If the name is not a valid namespace, manually set RootNamespace to a sanitized one. + if (sanitizedName != name) + mainGroup.AddProperty("RootNamespace", sanitizedName); - File.WriteAllText(assemblyInfoFile, content); - - root.AddItem("Compile", assemblyInfoFile.RelativeToPath(dir).Replace("/", "\\")); + return root; } - public static ProjectRootElement CreateLibraryProject(string name, string defaultConfig, out ProjectPropertyGroupElement mainGroup) + public static string GenAndSaveGameProject(string dir, string name) { - if (string.IsNullOrEmpty(name)) - throw new ArgumentException($"{nameof(name)} cannot be empty", nameof(name)); - - var root = ProjectRootElement.Create(); - root.DefaultTargets = "Build"; - - mainGroup = root.AddPropertyGroup(); - mainGroup.AddProperty("Configuration", defaultConfig).Condition = " '$(Configuration)' == '' "; - mainGroup.AddProperty("Platform", "AnyCPU").Condition = " '$(Platform)' == '' "; - mainGroup.AddProperty("ProjectGuid", "{" + Guid.NewGuid().ToString().ToUpper() + "}"); - mainGroup.AddProperty("OutputType", "Library"); - mainGroup.AddProperty("OutputPath", Path.Combine("bin", "$(Configuration)")); - mainGroup.AddProperty("RootNamespace", IdentifierUtils.SanitizeQualifiedIdentifier(name, allowEmptyIdentifiers: true)); - mainGroup.AddProperty("AssemblyName", name); - mainGroup.AddProperty("TargetFrameworkVersion", "v4.7"); - mainGroup.AddProperty("GodotProjectGeneratorVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString()); + if (name.Length == 0) + throw new ArgumentException("Project name is empty", nameof(name)); - var exportDebugGroup = root.AddPropertyGroup(); - exportDebugGroup.Condition = " '$(Configuration)|$(Platform)' == 'ExportDebug|AnyCPU' "; - exportDebugGroup.AddProperty("DebugSymbols", "true"); - exportDebugGroup.AddProperty("DebugType", "portable"); - exportDebugGroup.AddProperty("Optimize", "false"); - exportDebugGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;DEBUG;"); - exportDebugGroup.AddProperty("ErrorReport", "prompt"); - exportDebugGroup.AddProperty("WarningLevel", "4"); - exportDebugGroup.AddProperty("ConsolePause", "false"); - - var exportReleaseGroup = root.AddPropertyGroup(); - exportReleaseGroup.Condition = " '$(Configuration)|$(Platform)' == 'ExportRelease|AnyCPU' "; - exportReleaseGroup.AddProperty("DebugType", "portable"); - exportReleaseGroup.AddProperty("Optimize", "true"); - exportReleaseGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;"); - exportReleaseGroup.AddProperty("ErrorReport", "prompt"); - exportReleaseGroup.AddProperty("WarningLevel", "4"); - exportReleaseGroup.AddProperty("ConsolePause", "false"); - - // References - var referenceGroup = root.AddItemGroup(); - referenceGroup.AddItem("Reference", "System"); - var frameworkRefAssembliesItem = referenceGroup.AddItem("PackageReference", "Microsoft.NETFramework.ReferenceAssemblies"); + string path = Path.Combine(dir, name + ".csproj"); - // Use metadata (child nodes) instead of attributes for the PackageReference. - // This is for compatibility with 3.2, where GodotTools uses an old Microsoft.Build. - frameworkRefAssembliesItem.AddMetadata("Version", "1.0.0"); - frameworkRefAssembliesItem.AddMetadata("PrivateAssets", "All"); + var root = GenGameProject(name); - root.AddImport(Path.Combine("$(MSBuildBinPath)", "Microsoft.CSharp.targets").Replace("/", "\\")); + root.Save(path); - return root; + return Guid.NewGuid().ToString().ToUpper(); } - - private const string AssemblyInfoTemplate = - @"using System.Reflection;{0} - -// Information about this assembly is defined by the following attributes. -// Change them to the values specific to your project. - -[assembly: AssemblyTitle(""{1}"")] -[assembly: AssemblyDescription("""")] -[assembly: AssemblyConfiguration("""")] -[assembly: AssemblyCompany("""")] -[assembly: AssemblyProduct("""")] -[assembly: AssemblyCopyright("""")] -[assembly: AssemblyTrademark("""")] -[assembly: AssemblyCulture("""")] - -// The assembly version has the format ""{{Major}}.{{Minor}}.{{Build}}.{{Revision}}"". -// The form ""{{Major}}.{{Minor}}.*"" will automatically update the build and revision, -// and ""{{Major}}.{{Minor}}.{{Build}}.*"" will update just the revision. - -[assembly: AssemblyVersion(""1.0.*"")] - -// The following attributes are used to specify the signing key for the assembly, -// if desired. See the Mono documentation for more information about signing. - -//[assembly: AssemblyDelaySign(false)] -//[assembly: AssemblyKeyFile("""")] -{2}"; } } diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs index 8774b4ee31..4041c56597 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs @@ -1,9 +1,9 @@ +using System; using GodotTools.Core; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; using Microsoft.Build.Construction; using Microsoft.Build.Globbing; @@ -11,7 +11,7 @@ namespace GodotTools.ProjectEditor { public sealed class MSBuildProject { - public ProjectRootElement Root { get; } + internal ProjectRootElement Root { get; set; } public bool HasUnsavedChanges { get; set; } @@ -31,91 +31,7 @@ namespace GodotTools.ProjectEditor return root != null ? new MSBuildProject(root) : null; } - public static void AddItemToProjectChecked(string projectPath, string itemType, string include) - { - var dir = Directory.GetParent(projectPath).FullName; - var root = ProjectRootElement.Open(projectPath); - Debug.Assert(root != null); - - var normalizedInclude = include.RelativeToPath(dir).Replace("/", "\\"); - - if (root.AddItemChecked(itemType, normalizedInclude)) - root.Save(); - } - - public static void RenameItemInProjectChecked(string projectPath, string itemType, string oldInclude, string newInclude) - { - var dir = Directory.GetParent(projectPath).FullName; - var root = ProjectRootElement.Open(projectPath); - Debug.Assert(root != null); - - var normalizedOldInclude = oldInclude.NormalizePath(); - var normalizedNewInclude = newInclude.NormalizePath(); - - var item = root.FindItemOrNullAbs(itemType, normalizedOldInclude); - - if (item == null) - return; - - item.Include = normalizedNewInclude.RelativeToPath(dir).Replace("/", "\\"); - root.Save(); - } - - public static void RemoveItemFromProjectChecked(string projectPath, string itemType, string include) - { - var root = ProjectRootElement.Open(projectPath); - Debug.Assert(root != null); - - var normalizedInclude = include.NormalizePath(); - - if (root.RemoveItemChecked(itemType, normalizedInclude)) - root.Save(); - } - - public static void RenameItemsToNewFolderInProjectChecked(string projectPath, string itemType, string oldFolder, string newFolder) - { - var dir = Directory.GetParent(projectPath).FullName; - var root = ProjectRootElement.Open(projectPath); - Debug.Assert(root != null); - - bool dirty = false; - - var oldFolderNormalized = oldFolder.NormalizePath(); - var newFolderNormalized = newFolder.NormalizePath(); - string absOldFolderNormalized = Path.GetFullPath(oldFolderNormalized).NormalizePath(); - string absNewFolderNormalized = Path.GetFullPath(newFolderNormalized).NormalizePath(); - - foreach (var item in root.FindAllItemsInFolder(itemType, oldFolderNormalized)) - { - string absPathNormalized = Path.GetFullPath(item.Include).NormalizePath(); - string absNewIncludeNormalized = absNewFolderNormalized + absPathNormalized.Substring(absOldFolderNormalized.Length); - item.Include = absNewIncludeNormalized.RelativeToPath(dir).Replace("/", "\\"); - dirty = true; - } - - if (dirty) - root.Save(); - } - - public static void RemoveItemsInFolderFromProjectChecked(string projectPath, string itemType, string folder) - { - var root = ProjectRootElement.Open(projectPath); - Debug.Assert(root != null); - - var folderNormalized = folder.NormalizePath(); - - var itemsToRemove = root.FindAllItemsInFolder(itemType, folderNormalized).ToList(); - - if (itemsToRemove.Count > 0) - { - foreach (var item in itemsToRemove) - item.Parent.RemoveChild(item); - - root.Save(); - } - } - - private static string[] GetAllFilesRecursive(string rootDirectory, string mask) + private static List<string> GetAllFilesRecursive(string rootDirectory, string mask) { string[] files = Directory.GetFiles(rootDirectory, mask, SearchOption.AllDirectories); @@ -125,262 +41,59 @@ namespace GodotTools.ProjectEditor files[i] = files[i].RelativeToPath(rootDirectory); } - return files; + return new List<string>(files); } - public static string[] GetIncludeFiles(string projectPath, string itemType) + // NOTE: Assumes auto-including items. Only used by the scripts metadata generator, which will be replaced with source generators in the future. + public static IEnumerable<string> GetIncludeFiles(string projectPath, string itemType) { - var result = new List<string>(); - var existingFiles = GetAllFilesRecursive(Path.GetDirectoryName(projectPath), "*.cs"); + var excluded = new List<string>(); + var includedFiles = GetAllFilesRecursive(Path.GetDirectoryName(projectPath), "*.cs"); var root = ProjectRootElement.Open(projectPath); Debug.Assert(root != null); - foreach (var itemGroup in root.ItemGroups) + foreach (var item in root.Items) { - if (itemGroup.Condition.Length != 0) + if (string.IsNullOrEmpty(item.Condition)) continue; - foreach (var item in itemGroup.Items) - { - if (item.ItemType != itemType) - continue; - - string normalizedInclude = item.Include.NormalizePath(); + if (item.ItemType != itemType) + continue; - var glob = MSBuildGlob.Parse(normalizedInclude); + string normalizedExclude = item.Exclude.NormalizePath(); - // TODO Check somehow if path has no blob to avoid the following loop... + var glob = MSBuildGlob.Parse(normalizedExclude); - foreach (var existingFile in existingFiles) - { - if (glob.IsMatch(existingFile)) - { - result.Add(existingFile); - } - } - } + excluded.AddRange(includedFiles.Where(includedFile => glob.IsMatch(includedFile))); } - return result.ToArray(); + includedFiles.RemoveAll(f => excluded.Contains(f)); + + return includedFiles; } - public static void EnsureHasProjectTypeGuids(MSBuildProject project) + public static void MigrateToProjectSdksStyle(MSBuildProject project, string projectName) { - var root = project.Root; - - bool found = root.PropertyGroups.Any(pg => - string.IsNullOrEmpty(pg.Condition) && pg.Properties.Any(p => p.Name == "ProjectTypeGuids")); + var origRoot = project.Root; - if (found) + if (!string.IsNullOrEmpty(origRoot.Sdk)) return; - root.AddProperty("ProjectTypeGuids", ProjectGenerator.GodotDefaultProjectTypeGuids); - + project.Root = ProjectGenerator.GenGameProject(projectName); + project.Root.FullPath = origRoot.FullPath; project.HasUnsavedChanges = true; } - /// Simple function to make sure the Api assembly references are configured correctly - public static void FixApiHintPath(MSBuildProject project) - { - var root = project.Root; - - void AddPropertyIfNotPresent(string name, string condition, string value) - { - if (root.PropertyGroups - .Any(g => (string.IsNullOrEmpty(g.Condition) || g.Condition.Trim() == condition) && - g.Properties - .Any(p => p.Name == name && - p.Value == value && - (p.Condition.Trim() == condition || g.Condition.Trim() == condition)))) - { - return; - } - - root.AddProperty(name, value).Condition = " " + condition + " "; - project.HasUnsavedChanges = true; - } - - AddPropertyIfNotPresent(name: "ApiConfiguration", - condition: "'$(Configuration)' != 'ExportRelease'", - value: "Debug"); - AddPropertyIfNotPresent(name: "ApiConfiguration", - condition: "'$(Configuration)' == 'ExportRelease'", - value: "Release"); - - void SetReferenceHintPath(string referenceName, string condition, string hintPath) - { - foreach (var itemGroup in root.ItemGroups.Where(g => - g.Condition.Trim() == string.Empty || g.Condition.Trim() == condition)) - { - var references = itemGroup.Items.Where(item => - item.ItemType == "Reference" && - item.Include == referenceName && - (item.Condition.Trim() == condition || itemGroup.Condition.Trim() == condition)); - - var referencesWithHintPath = references.Where(reference => - reference.Metadata.Any(m => m.Name == "HintPath")); - - if (referencesWithHintPath.Any(reference => reference.Metadata - .Any(m => m.Name == "HintPath" && m.Value == hintPath))) - { - // Found a Reference item with the right HintPath - return; - } - - var referenceWithHintPath = referencesWithHintPath.FirstOrDefault(); - if (referenceWithHintPath != null) - { - // Found a Reference item with a wrong HintPath - foreach (var metadata in referenceWithHintPath.Metadata.ToList() - .Where(m => m.Name == "HintPath")) - { - // Safe to remove as we duplicate with ToList() to loop - referenceWithHintPath.RemoveChild(metadata); - } - - referenceWithHintPath.AddMetadata("HintPath", hintPath); - project.HasUnsavedChanges = true; - return; - } - - var referenceWithoutHintPath = references.FirstOrDefault(); - if (referenceWithoutHintPath != null) - { - // Found a Reference item without a HintPath - referenceWithoutHintPath.AddMetadata("HintPath", hintPath); - project.HasUnsavedChanges = true; - return; - } - } - - // Found no Reference item at all. Add it. - root.AddItem("Reference", referenceName).Condition = " " + condition + " "; - project.HasUnsavedChanges = true; - } - - const string coreProjectName = "GodotSharp"; - const string editorProjectName = "GodotSharpEditor"; - - const string coreCondition = ""; - const string editorCondition = "'$(Configuration)' == 'Debug'"; - - var coreHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{coreProjectName}.dll"; - var editorHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{editorProjectName}.dll"; - - SetReferenceHintPath(coreProjectName, coreCondition, coreHintPath); - SetReferenceHintPath(editorProjectName, editorCondition, editorHintPath); - } - - public static void MigrateFromOldConfigNames(MSBuildProject project) - { - var root = project.Root; - - bool hasGodotProjectGeneratorVersion = false; - bool foundOldConfiguration = false; - - foreach (var propertyGroup in root.PropertyGroups.Where(g => string.IsNullOrEmpty(g.Condition))) - { - if (!hasGodotProjectGeneratorVersion && propertyGroup.Properties.Any(p => p.Name == "GodotProjectGeneratorVersion")) - hasGodotProjectGeneratorVersion = true; - - foreach (var configItem in propertyGroup.Properties - .Where(p => p.Condition.Trim() == "'$(Configuration)' == ''" && p.Value == "Tools")) - { - configItem.Value = "Debug"; - foundOldConfiguration = true; - project.HasUnsavedChanges = true; - } - } - - if (!hasGodotProjectGeneratorVersion) - { - root.PropertyGroups.First(g => string.IsNullOrEmpty(g.Condition))? - .AddProperty("GodotProjectGeneratorVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString()); - project.HasUnsavedChanges = true; - } - - if (!foundOldConfiguration) - { - var toolsConditions = new[] - { - "'$(Configuration)|$(Platform)' == 'Tools|AnyCPU'", - "'$(Configuration)|$(Platform)' != 'Tools|AnyCPU'", - "'$(Configuration)' == 'Tools'", - "'$(Configuration)' != 'Tools'" - }; - - foundOldConfiguration = root.PropertyGroups - .Any(g => toolsConditions.Any(c => c == g.Condition.Trim())); - } - - if (foundOldConfiguration) - { - void MigrateConfigurationConditions(string oldConfiguration, string newConfiguration) - { - void MigrateConditions(string oldCondition, string newCondition) - { - foreach (var propertyGroup in root.PropertyGroups.Where(g => g.Condition.Trim() == oldCondition)) - { - propertyGroup.Condition = " " + newCondition + " "; - project.HasUnsavedChanges = true; - } - - foreach (var propertyGroup in root.PropertyGroups) - { - foreach (var prop in propertyGroup.Properties.Where(p => p.Condition.Trim() == oldCondition)) - { - prop.Condition = " " + newCondition + " "; - project.HasUnsavedChanges = true; - } - } - - foreach (var itemGroup in root.ItemGroups.Where(g => g.Condition.Trim() == oldCondition)) - { - itemGroup.Condition = " " + newCondition + " "; - project.HasUnsavedChanges = true; - } - - foreach (var itemGroup in root.ItemGroups) - { - foreach (var item in itemGroup.Items.Where(item => item.Condition.Trim() == oldCondition)) - { - item.Condition = " " + newCondition + " "; - project.HasUnsavedChanges = true; - } - } - } - - foreach (var op in new[] {"==", "!="}) - { - MigrateConditions($"'$(Configuration)|$(Platform)' {op} '{oldConfiguration}|AnyCPU'", $"'$(Configuration)|$(Platform)' {op} '{newConfiguration}|AnyCPU'"); - MigrateConditions($"'$(Configuration)' {op} '{oldConfiguration}'", $"'$(Configuration)' {op} '{newConfiguration}'"); - } - } - - MigrateConfigurationConditions("Debug", "ExportDebug"); - MigrateConfigurationConditions("Release", "ExportRelease"); - MigrateConfigurationConditions("Tools", "Debug"); // Must be last - } - } - - public static void EnsureHasNugetNetFrameworkRefAssemblies(MSBuildProject project) + public static void EnsureGodotSdkIsUpToDate(MSBuildProject project) { var root = project.Root; + string godotSdkAttrValue = ProjectGenerator.GodotSdkAttrValue; - bool found = root.ItemGroups.Any(g => string.IsNullOrEmpty(g.Condition) && g.Items.Any( - item => item.ItemType == "PackageReference" && item.Include == "Microsoft.NETFramework.ReferenceAssemblies")); - - if (found) + if (!string.IsNullOrEmpty(root.Sdk) && root.Sdk.Trim().Equals(godotSdkAttrValue, StringComparison.OrdinalIgnoreCase)) return; - var frameworkRefAssembliesItem = root.AddItem("PackageReference", "Microsoft.NETFramework.ReferenceAssemblies"); - - // Use metadata (child nodes) instead of attributes for the PackageReference. - // This is for compatibility with 3.2, where GodotTools uses an old Microsoft.Build. - frameworkRefAssembliesItem.AddMetadata("Version", "1.0.0"); - frameworkRefAssembliesItem.AddMetadata("PrivateAssets", "All"); - + root.Sdk = godotSdkAttrValue; project.HasUnsavedChanges = true; } } diff --git a/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs b/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs index 3de3d8d318..3ab669a9f3 100644 --- a/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs +++ b/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs @@ -24,48 +24,50 @@ namespace GodotTools private Button errorsBtn; private Button viewLogBtn; - private void _UpdateBuildTabsList() + private void _UpdateBuildTab(int index, int? currentTab) { - buildTabsList.Clear(); + var tab = (BuildTab)buildTabs.GetChild(index); - int currentTab = buildTabs.CurrentTab; + string itemName = Path.GetFileNameWithoutExtension(tab.BuildInfo.Solution); + itemName += " [" + tab.BuildInfo.Configuration + "]"; - bool noCurrentTab = currentTab < 0 || currentTab >= buildTabs.GetTabCount(); + buildTabsList.AddItem(itemName, tab.IconTexture); - for (int i = 0; i < buildTabs.GetChildCount(); i++) - { - var tab = (BuildTab)buildTabs.GetChild(i); + string itemTooltip = "Solution: " + tab.BuildInfo.Solution; + itemTooltip += "\nConfiguration: " + tab.BuildInfo.Configuration; + itemTooltip += "\nStatus: "; - if (tab == null) - continue; + if (tab.BuildExited) + itemTooltip += tab.BuildResult == BuildTab.BuildResults.Success ? "Succeeded" : "Errored"; + else + itemTooltip += "Running"; - string itemName = Path.GetFileNameWithoutExtension(tab.BuildInfo.Solution); - itemName += " [" + tab.BuildInfo.Configuration + "]"; + if (!tab.BuildExited || tab.BuildResult == BuildTab.BuildResults.Error) + itemTooltip += $"\nErrors: {tab.ErrorCount}"; - buildTabsList.AddItem(itemName, tab.IconTexture); + itemTooltip += $"\nWarnings: {tab.WarningCount}"; - string itemTooltip = "Solution: " + tab.BuildInfo.Solution; - itemTooltip += "\nConfiguration: " + tab.BuildInfo.Configuration; - itemTooltip += "\nStatus: "; + buildTabsList.SetItemTooltip(index, itemTooltip); - if (tab.BuildExited) - itemTooltip += tab.BuildResult == BuildTab.BuildResults.Success ? "Succeeded" : "Errored"; - else - itemTooltip += "Running"; + // If this tab was already selected before the changes or if no tab was selected + if (currentTab == null || currentTab == index) + { + buildTabsList.Select(index); + _BuildTabsItemSelected(index); + } + } - if (!tab.BuildExited || tab.BuildResult == BuildTab.BuildResults.Error) - itemTooltip += $"\nErrors: {tab.ErrorCount}"; + private void _UpdateBuildTabsList() + { + buildTabsList.Clear(); - itemTooltip += $"\nWarnings: {tab.WarningCount}"; + int? currentTab = buildTabs.CurrentTab; - buildTabsList.SetItemTooltip(i, itemTooltip); + if (currentTab < 0 || currentTab >= buildTabs.GetTabCount()) + currentTab = null; - if (noCurrentTab || currentTab == i) - { - buildTabsList.Select(i); - _BuildTabsItemSelected(i); - } - } + for (int i = 0; i < buildTabs.GetChildCount(); i++) + _UpdateBuildTab(i, currentTab); } public BuildTab GetBuildTabFor(BuildInfo buildInfo) @@ -160,13 +162,7 @@ namespace GodotTools } } - var godotDefines = new[] - { - OS.GetName(), - Internal.GodotIs32Bits() ? "32" : "64" - }; - - bool buildSuccess = BuildManager.BuildProjectBlocking("Debug", godotDefines); + bool buildSuccess = BuildManager.BuildProjectBlocking("Debug"); if (!buildSuccess) return; @@ -272,7 +268,7 @@ namespace GodotTools }; panelTabs.AddChild(panelBuildsTab); - var toolBarHBox = new HBoxContainer { SizeFlagsHorizontal = (int)SizeFlags.ExpandFill }; + var toolBarHBox = new HBoxContainer {SizeFlagsHorizontal = (int)SizeFlags.ExpandFill}; panelBuildsTab.AddChild(toolBarHBox); var buildProjectBtn = new Button @@ -325,7 +321,7 @@ namespace GodotTools }; panelBuildsTab.AddChild(hsc); - buildTabsList = new ItemList { SizeFlagsHorizontal = (int)SizeFlags.ExpandFill }; + buildTabsList = new ItemList {SizeFlagsHorizontal = (int)SizeFlags.ExpandFill}; buildTabsList.ItemSelected += _BuildTabsItemSelected; buildTabsList.NothingSelected += _BuildTabsNothingSelected; hsc.AddChild(buildTabsList); diff --git a/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs b/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs index 0974d23176..6399991b84 100644 --- a/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs +++ b/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs @@ -6,6 +6,7 @@ using GodotTools.Build; using GodotTools.Ides.Rider; using GodotTools.Internals; using GodotTools.Utils; +using JetBrains.Annotations; using static GodotTools.Internals.Globals; using File = GodotTools.Utils.File; @@ -152,7 +153,7 @@ namespace GodotTools } } - public static bool BuildProjectBlocking(string config, IEnumerable<string> godotDefines) + public static bool BuildProjectBlocking(string config, [CanBeNull] string platform = null) { if (!File.Exists(GodotSharpDirs.ProjectSlnPath)) return true; // No solution to build @@ -168,29 +169,18 @@ namespace GodotTools return false; } - var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings(); - var buildTool = (BuildTool)editorSettings.GetSetting("mono/builds/build_tool"); - using (var pr = new EditorProgress("mono_project_debug_build", "Building project solution...", 1)) { pr.Step("Building project solution", 0); var buildInfo = new BuildInfo(GodotSharpDirs.ProjectSlnPath, targets: new[] {"Build"}, config, restore: true); - bool escapeNeedsDoubleBackslash = buildTool == BuildTool.MsBuildMono || buildTool == BuildTool.DotnetCli; - - // Add Godot defines - string constants = !escapeNeedsDoubleBackslash ? "GodotDefineConstants=\"" : "GodotDefineConstants=\\\""; - - foreach (var godotDefine in godotDefines) - constants += $"GODOT_{godotDefine.ToUpper().Replace("-", "_").Replace(" ", "_").Replace(";", "_")};"; + // If a platform was not specified, try determining the current one. If that fails, let MSBuild auto-detect it. + if (platform != null || OS.PlatformNameMap.TryGetValue(Godot.OS.GetName(), out platform)) + buildInfo.CustomProperties.Add($"GodotTargetPlatform={platform}"); if (Internal.GodotIsRealTDouble()) - constants += "GODOT_REAL_T_IS_DOUBLE;"; - - constants += !escapeNeedsDoubleBackslash ? "\"" : "\\\""; - - buildInfo.CustomProperties.Add(constants); + buildInfo.CustomProperties.Add("GodotRealTIsDouble=true"); if (!Build(buildInfo)) { @@ -233,13 +223,7 @@ namespace GodotTools return true; // Requested play from an external editor/IDE which already built the project } - var godotDefines = new[] - { - Godot.OS.GetName(), - Internal.GodotIs32Bits() ? "32" : "64" - }; - - return BuildProjectBlocking("Debug", godotDefines); + return BuildProjectBlocking("Debug"); } public static void Initialize() diff --git a/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs b/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs index 421729cc11..a8afb38728 100644 --- a/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs +++ b/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs @@ -1,9 +1,9 @@ using Godot; using System; +using System.Linq; using Godot.Collections; using GodotTools.Internals; using GodotTools.ProjectEditor; -using static GodotTools.Internals.Globals; using File = GodotTools.Utils.File; using Directory = GodotTools.Utils.Directory; @@ -15,7 +15,7 @@ namespace GodotTools { try { - return ProjectGenerator.GenGameProject(dir, name, compileItems: new string[] { }); + return ProjectGenerator.GenAndSaveGameProject(dir, name); } catch (Exception e) { @@ -24,14 +24,6 @@ namespace GodotTools } } - public static void AddItem(string projectPath, string itemType, string include) - { - if (!(bool)GlobalDef("mono/project/auto_update_project", true)) - return; - - ProjectUtils.AddItemToProjectChecked(projectPath, itemType, include); - } - private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); private static ulong ConvertToTimestamp(this DateTime value) @@ -40,81 +32,77 @@ namespace GodotTools return (ulong)elapsedTime.TotalSeconds; } - public static void GenerateScriptsMetadata(string projectPath, string outputPath) + private static bool TryParseFileMetadata(string includeFile, ulong modifiedTime, out Dictionary fileMetadata) { - if (File.Exists(outputPath)) - File.Delete(outputPath); + fileMetadata = null; - var oldDict = Internal.GetScriptsMetadataOrNothing(); - var newDict = new Godot.Collections.Dictionary<string, object>(); + var parseError = ScriptClassParser.ParseFile(includeFile, out var classes, out string errorStr); - foreach (var includeFile in ProjectUtils.GetIncludeFiles(projectPath, "Compile")) + if (parseError != Error.Ok) { - string projectIncludeFile = ("res://" + includeFile).SimplifyGodotPath(); + GD.PushError($"Failed to determine namespace and class for script: {includeFile}. Parse error: {errorStr ?? parseError.ToString()}"); + return false; + } - ulong modifiedTime = File.GetLastWriteTime(projectIncludeFile).ConvertToTimestamp(); + string searchName = System.IO.Path.GetFileNameWithoutExtension(includeFile); - if (oldDict.TryGetValue(projectIncludeFile, out var oldFileVar)) - { - var oldFileDict = (Dictionary)oldFileVar; - - if (ulong.TryParse(oldFileDict["modified_time"] as string, out ulong storedModifiedTime)) - { - if (storedModifiedTime == modifiedTime) - { - // No changes so no need to parse again - newDict[projectIncludeFile] = oldFileDict; - continue; - } - } - } + var firstMatch = classes.FirstOrDefault(classDecl => + classDecl.BaseCount != 0 && // If it doesn't inherit anything, it can't be a Godot.Object. + classDecl.SearchName != searchName // Filter by the name we're looking for + ); + + if (firstMatch == null) + return false; // Not found - Error parseError = ScriptClassParser.ParseFile(projectIncludeFile, out var classes, out string errorStr); - if (parseError != Error.Ok) + fileMetadata = new Dictionary + { + ["modified_time"] = $"{modifiedTime}", + ["class"] = new Dictionary { - GD.PushError($"Failed to determine namespace and class for script: {projectIncludeFile}. Parse error: {errorStr ?? parseError.ToString()}"); - continue; + ["namespace"] = firstMatch.Namespace, + ["class_name"] = firstMatch.Name, + ["nested"] = firstMatch.Nested } + }; - string searchName = System.IO.Path.GetFileNameWithoutExtension(projectIncludeFile); - - var classDict = new Dictionary(); + return true; + } - foreach (var classDecl in classes) - { - if (classDecl.BaseCount == 0) - continue; // Does not inherit nor implement anything, so it can't be a script class + public static void GenerateScriptsMetadata(string projectPath, string outputPath) + { + var metadataDict = Internal.GetScriptsMetadataOrNothing().Duplicate(); - string classCmp = classDecl.Nested ? - classDecl.Name.Substring(classDecl.Name.LastIndexOf(".", StringComparison.Ordinal) + 1) : - classDecl.Name; + bool IsUpToDate(string includeFile, ulong modifiedTime) + { + return metadataDict.TryGetValue(includeFile, out var oldFileVar) && + ulong.TryParse(((Dictionary)oldFileVar)["modified_time"] as string, + out ulong storedModifiedTime) && storedModifiedTime == modifiedTime; + } - if (classCmp != searchName) - continue; + var outdatedFiles = ProjectUtils.GetIncludeFiles(projectPath, "Compile") + .Select(path => ("res://" + path).SimplifyGodotPath()) + .ToDictionary(path => path, path => File.GetLastWriteTime(path).ConvertToTimestamp()) + .Where(pair => !IsUpToDate(includeFile: pair.Key, modifiedTime: pair.Value)) + .ToArray(); - classDict["namespace"] = classDecl.Namespace; - classDict["class_name"] = classDecl.Name; - classDict["nested"] = classDecl.Nested; - break; - } + foreach (var pair in outdatedFiles) + { + metadataDict.Remove(pair.Key); - if (classDict.Count == 0) - continue; // Not found + string includeFile = pair.Key; - newDict[projectIncludeFile] = new Dictionary { ["modified_time"] = $"{modifiedTime}", ["class"] = classDict }; + if (TryParseFileMetadata(includeFile, modifiedTime: pair.Value, out var fileMetadata)) + metadataDict[includeFile] = fileMetadata; } - if (newDict.Count > 0) - { - string json = JSON.Print(newDict); + string json = metadataDict.Count <= 0 ? "{}" : JSON.Print(metadataDict); - string baseDir = outputPath.GetBaseDir(); + string baseDir = outputPath.GetBaseDir(); - if (!Directory.Exists(baseDir)) - Directory.CreateDirectory(baseDir); + if (!Directory.Exists(baseDir)) + Directory.CreateDirectory(baseDir); - File.WriteAllText(outputPath, json); - } + File.WriteAllText(outputPath, json); } } } diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs index 6bfbc62f3b..554763eecb 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Runtime.CompilerServices; using GodotTools.Core; using GodotTools.Internals; +using JetBrains.Annotations; using static GodotTools.Internals.Globals; using Directory = GodotTools.Utils.Directory; using File = GodotTools.Utils.File; @@ -145,9 +146,7 @@ namespace GodotTools.Export if (!File.Exists(GodotSharpDirs.ProjectSlnPath)) return; - string platform = DeterminePlatformFromFeatures(features); - - if (platform == null) + if (!DeterminePlatformFromFeatures(features, out string platform)) throw new NotSupportedException("Target platform not supported"); string outputDir = new FileInfo(path).Directory?.FullName ?? @@ -160,10 +159,7 @@ namespace GodotTools.Export AddFile(scriptsMetadataPath, scriptsMetadataPath); - // Turn export features into defines - var godotDefines = features; - - if (!BuildManager.BuildProjectBlocking(buildConfig, godotDefines)) + if (!BuildManager.BuildProjectBlocking(buildConfig, platform)) throw new Exception("Failed to build project"); // Add dependency assemblies @@ -289,6 +285,7 @@ namespace GodotTools.Export } } + [NotNull] private static string ExportDataDirectory(string[] features, string platform, bool isDebug, string outputDir) { string target = isDebug ? "release_debug" : "release"; @@ -343,18 +340,19 @@ namespace GodotTools.Export private static bool PlatformHasTemplateDir(string platform) { // OSX export templates are contained in a zip, so we place our custom template inside it and let Godot do the rest. - return !new[] { OS.Platforms.OSX, OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5 }.Contains(platform); + return !new[] {OS.Platforms.OSX, OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5}.Contains(platform); } - private static string DeterminePlatformFromFeatures(IEnumerable<string> features) + private static bool DeterminePlatformFromFeatures(IEnumerable<string> features, out string platform) { foreach (var feature in features) { - if (OS.PlatformNameMap.TryGetValue(feature, out string platform)) - return platform; + if (OS.PlatformNameMap.TryGetValue(feature, out platform)) + return true; } - return null; + platform = null; + return false; } private static string GetBclProfileDir(string profile) @@ -391,7 +389,7 @@ namespace GodotTools.Export /// </summary> private static bool PlatformRequiresCustomBcl(string platform) { - if (new[] { OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5 }.Contains(platform)) + if (new[] {OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5}.Contains(platform)) return true; // The 'net_4_x' BCL is not compatible between Windows and the other platforms. diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index f330f9ed2c..a363ecc920 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -175,36 +175,6 @@ namespace GodotTools // Once shown a first time, it can be seen again via the Mono menu - it doesn't have to be exclusive from that time on. aboutDialog.Exclusive = false; } - - var fileSystemDock = GetEditorInterface().GetFileSystemDock(); - - fileSystemDock.FilesMoved += (file, newFile) => - { - if (Path.GetExtension(file) == Internal.CSharpLanguageExtension) - { - ProjectUtils.RenameItemInProjectChecked(GodotSharpDirs.ProjectCsProjPath, "Compile", - ProjectSettings.GlobalizePath(file), ProjectSettings.GlobalizePath(newFile)); - } - }; - - fileSystemDock.FileRemoved += file => - { - if (Path.GetExtension(file) == Internal.CSharpLanguageExtension) - ProjectUtils.RemoveItemFromProjectChecked(GodotSharpDirs.ProjectCsProjPath, "Compile", - ProjectSettings.GlobalizePath(file)); - }; - - fileSystemDock.FolderMoved += (oldFolder, newFolder) => - { - ProjectUtils.RenameItemsToNewFolderInProjectChecked(GodotSharpDirs.ProjectCsProjPath, "Compile", - ProjectSettings.GlobalizePath(oldFolder), ProjectSettings.GlobalizePath(newFolder)); - }; - - fileSystemDock.FolderRemoved += oldFolder => - { - ProjectUtils.RemoveItemsInFolderFromProjectChecked(GodotSharpDirs.ProjectCsProjPath, "Compile", - ProjectSettings.GlobalizePath(oldFolder)); - }; } } @@ -389,6 +359,37 @@ namespace GodotTools return BuildManager.EditorBuildCallback(); } + private void ApplyNecessaryChangesToSolution() + { + try + { + // Migrate solution from old configuration names to: Debug, ExportDebug and ExportRelease + DotNetSolution.MigrateFromOldConfigNames(GodotSharpDirs.ProjectSlnPath); + + var msbuildProject = ProjectUtils.Open(GodotSharpDirs.ProjectCsProjPath) + ?? throw new Exception("Cannot open C# project"); + + // NOTE: The order in which changes are made to the project is important + + // Migrate to MSBuild project Sdks style if using the old style + ProjectUtils.MigrateToProjectSdksStyle(msbuildProject, ProjectAssemblyName); + + ProjectUtils.EnsureGodotSdkIsUpToDate(msbuildProject); + + if (msbuildProject.HasUnsavedChanges) + { + // Save a copy of the project before replacing it + FileUtils.SaveBackupCopy(GodotSharpDirs.ProjectCsProjPath); + + msbuildProject.Save(); + } + } + catch (Exception e) + { + GD.PushError(e.ToString()); + } + } + public override void EnablePlugin() { base.EnablePlugin(); @@ -468,42 +469,7 @@ namespace GodotTools if (File.Exists(GodotSharpDirs.ProjectSlnPath) && File.Exists(GodotSharpDirs.ProjectCsProjPath)) { - try - { - // Migrate solution from old configuration names to: Debug, ExportDebug and ExportRelease - DotNetSolution.MigrateFromOldConfigNames(GodotSharpDirs.ProjectSlnPath); - - var msbuildProject = ProjectUtils.Open(GodotSharpDirs.ProjectCsProjPath) - ?? throw new Exception("Cannot open C# project"); - - // NOTE: The order in which changes are made to the project is important - - // Migrate csproj from old configuration names to: Debug, ExportDebug and ExportRelease - ProjectUtils.MigrateFromOldConfigNames(msbuildProject); - - // Apply the other fixes only after configurations have been migrated - - // Make sure the existing project has the ProjectTypeGuids property (for VisualStudio) - ProjectUtils.EnsureHasProjectTypeGuids(msbuildProject); - - // Make sure the existing project has Api assembly references configured correctly - ProjectUtils.FixApiHintPath(msbuildProject); - - // Make sure the existing project references the Microsoft.NETFramework.ReferenceAssemblies nuget package - ProjectUtils.EnsureHasNugetNetFrameworkRefAssemblies(msbuildProject); - - if (msbuildProject.HasUnsavedChanges) - { - // Save a copy of the project before replacing it - FileUtils.SaveBackupCopy(GodotSharpDirs.ProjectCsProjPath); - - msbuildProject.Save(); - } - } - catch (Exception e) - { - GD.PushError(e.ToString()); - } + ApplyNecessaryChangesToSolution(); } else { diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/ScriptClassParser.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/ScriptClassParser.cs index 569f27649f..c72a84c513 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Internals/ScriptClassParser.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/ScriptClassParser.cs @@ -15,6 +15,10 @@ namespace GodotTools.Internals public bool Nested { get; } public long BaseCount { get; } + public string SearchName => Nested ? + Name.Substring(Name.LastIndexOf(".", StringComparison.Ordinal) + 1) : + Name; + public ClassDecl(string name, string @namespace, bool nested, long baseCount) { Name = name; diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 79e4b7c794..a17c371117 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -45,7 +45,6 @@ #include "../mono_gd/gd_mono_marshal.h" #include "../utils/path_utils.h" #include "../utils/string_utils.h" -#include "csharp_project.h" #define CS_INDENT " " // 4 whitespaces diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp deleted file mode 100644 index 6f54eb09a2..0000000000 --- a/modules/mono/editor/csharp_project.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/*************************************************************************/ -/* csharp_project.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "csharp_project.h" - -#include "core/io/json.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" -#include "core/os/os.h" -#include "core/project_settings.h" - -#include "../csharp_script.h" -#include "../mono_gd/gd_mono_class.h" -#include "../mono_gd/gd_mono_marshal.h" -#include "../utils/string_utils.h" -#include "script_class_parser.h" - -namespace CSharpProject { - -void add_item(const String &p_project_path, const String &p_item_type, const String &p_include) { - if (!GLOBAL_DEF("mono/project/auto_update_project", true)) { - return; - } - - GDMonoAssembly *tools_project_editor_assembly = GDMono::get_singleton()->get_tools_project_editor_assembly(); - - GDMonoClass *klass = tools_project_editor_assembly->get_class("GodotTools.ProjectEditor", "ProjectUtils"); - - Variant project_path = p_project_path; - Variant item_type = p_item_type; - Variant include = p_include; - const Variant *args[3] = { &project_path, &item_type, &include }; - MonoException *exc = nullptr; - klass->get_method("AddItemToProjectChecked", 3)->invoke(nullptr, args, &exc); - - if (exc) { - GDMonoUtils::debug_print_unhandled_exception(exc); - ERR_FAIL(); - } -} - -} // namespace CSharpProject diff --git a/modules/mono/editor/script_class_parser.cpp b/modules/mono/editor/script_class_parser.cpp index 012ccd5339..430c82953e 100644 --- a/modules/mono/editor/script_class_parser.cpp +++ b/modules/mono/editor/script_class_parser.cpp @@ -235,7 +235,7 @@ ScriptClassParser::Token ScriptClassParser::get_token() { if (code[idx] == '-' || (code[idx] >= '0' && code[idx] <= '9')) { //a number const CharType *rptr; - double number = String::to_double(&code[idx], &rptr); + double number = String::to_float(&code[idx], &rptr); idx += (rptr - &code[idx]); value = number; return TK_NUMBER; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index 06ec2483c8..86a16c17f1 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -1,39 +1,17 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProjectGuid>{AEBF0036-DA76-4341-B651-A3F2856AB2FA}</ProjectGuid> - <OutputType>Library</OutputType> <OutputPath>bin/$(Configuration)</OutputPath> + <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <RootNamespace>Godot</RootNamespace> - <AssemblyName>GodotSharp</AssemblyName> - <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <TargetFramework>netstandard2.1</TargetFramework> <DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile> - <BaseIntermediateOutputPath>obj</BaseIntermediateOutputPath> + <EnableDefaultItems>false</EnableDefaultItems> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - <DebugSymbols>true</DebugSymbols> - <DebugType>portable</DebugType> - <Optimize>false</Optimize> - <DefineConstants>$(GodotDefineConstants);GODOT;DEBUG;</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>portable</DebugType> - <Optimize>true</Optimize> - <DefineConstants>$(GodotDefineConstants);GODOT;</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> + <PropertyGroup> + <DefineConstants>$(DefineConstants);GODOT</DefineConstants> </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" /> - <Reference Include="System" /> - </ItemGroup> - <ItemGroup> <Compile Include="Core\AABB.cs" /> <Compile Include="Core\Array.cs" /> <Compile Include="Core\Attributes\ExportAttribute.cs" /> @@ -90,5 +68,4 @@ Fortunately code completion, go to definition and such still work. --> <Import Project="Generated\GeneratedIncludes.props" /> - <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> </Project> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs index f84e0183f6..da6f293871 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs @@ -1,27 +1,3 @@ -using System.Reflection; using System.Runtime.CompilerServices; -// Information about this assembly is defined by the following attributes. -// Change them to the values specific to your project. - -[assembly: AssemblyTitle("GodotSharp")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("")] -[assembly: AssemblyCopyright("")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". -// The form "{Major}.{Minor}.*" will automatically update the build and revision, -// and "{Major}.{Minor}.{Build}.*" will update just the revision. - -[assembly: AssemblyVersion("1.0.*")] - -// The following attributes are used to specify the signing key for the assembly, -// if desired. See the Mono documentation for more information about signing. - -//[assembly: AssemblyDelaySign(false)] -//[assembly: AssemblyKeyFile("")] [assembly: InternalsVisibleTo("GodotSharpEditor")] diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj index 8785931312..a8c4ba96b5 100644 --- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj @@ -1,46 +1,26 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProjectGuid>{8FBEC238-D944-4074-8548-B3B524305905}</ProjectGuid> - <OutputType>Library</OutputType> <OutputPath>bin/$(Configuration)</OutputPath> + <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <RootNamespace>Godot</RootNamespace> - <AssemblyName>GodotSharpEditor</AssemblyName> - <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <TargetFramework>netstandard2.1</TargetFramework> <DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile> - <BaseIntermediateOutputPath>obj</BaseIntermediateOutputPath> + <EnableDefaultItems>false</EnableDefaultItems> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - <DebugSymbols>true</DebugSymbols> - <DebugType>portable</DebugType> - <Optimize>false</Optimize> - <DefineConstants>$(GodotDefineConstants);GODOT;DEBUG;</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>portable</DebugType> - <Optimize>true</Optimize> - <DefineConstants>$(GodotDefineConstants);GODOT;</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> + <PropertyGroup> + <DefineConstants>$(DefineConstants);GODOT</DefineConstants> </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" /> - <Reference Include="System" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Properties\AssemblyInfo.cs" /> - </ItemGroup> - <Import Project="Generated\GeneratedIncludes.props" /> - <ItemGroup> <ProjectReference Include="..\GodotSharp\GodotSharp.csproj"> - <Private>False</Private> + <Private>false</Private> </ProjectReference> </ItemGroup> - <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <!-- + We import a props file with auto-generated includes. This works well with Rider. + However, Visual Studio and MonoDevelop won't list them in the solution explorer. + We can't use wildcards as there may be undesired old files still hanging around. + Fortunately code completion, go to definition and such still work. + --> + <Import Project="Generated\GeneratedIncludes.props" /> </Project> diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/Properties/AssemblyInfo.cs b/modules/mono/glue/GodotSharp/GodotSharpEditor/Properties/AssemblyInfo.cs deleted file mode 100644 index 3684b7a3cb..0000000000 --- a/modules/mono/glue/GodotSharp/GodotSharpEditor/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Reflection; - -// Information about this assembly is defined by the following attributes. -// Change them to the values specific to your project. - -[assembly: AssemblyTitle("GodotSharpEditor")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("")] -[assembly: AssemblyCopyright("")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". -// The form "{Major}.{Minor}.*" will automatically update the build and revision, -// and "{Major}.{Minor}.{Build}.*" will update just the revision. - -[assembly: AssemblyVersion("1.0.*")] - -// The following attributes are used to specify the signing key for the assembly, -// if desired. See the Mono documentation for more information about signing. - -//[assembly: AssemblyDelaySign(false)] -//[assembly: AssemblyKeyFile("")] diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index a170fd36e7..9dbeee57ce 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -425,7 +425,7 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class) while (!nested_classes.empty()) { GDMonoClass *current_nested = nested_classes.front()->get(); - nested_classes.pop_back(); + nested_classes.pop_front(); void *iter = nullptr; diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml index c00fa96b2e..312275842a 100644 --- a/modules/regex/doc_classes/RegEx.xml +++ b/modules/regex/doc_classes/RegEx.xml @@ -11,7 +11,7 @@ regex.compile("\\w-(\\d+)") [/codeblock] The search pattern must be escaped first for GDScript before it is escaped for the expression. For example, [code]compile("\\d+")[/code] would be read by RegEx as [code]\d+[/code]. Similarly, [code]compile("\"(?:\\\\.|[^\"])*\"")[/code] would be read as [code]"(?:\\.|[^"])*"[/code]. - Using [method search] you can find the pattern within the given text. If a pattern is found, [RegExMatch] is returned and you can retrieve details of the results using functions such as [method RegExMatch.get_string] and [method RegExMatch.get_start]. + Using [method search], you can find the pattern within the given text. If a pattern is found, [RegExMatch] is returned and you can retrieve details of the results using methods such as [method RegExMatch.get_string] and [method RegExMatch.get_start]. [codeblock] var regex = RegEx.new() regex.compile("\\w-(\\d+)") @@ -19,7 +19,7 @@ if result: print(result.get_string()) # Would print n-0123 [/codeblock] - The results of capturing groups [code]()[/code] can be retrieved by passing the group number to the various functions in [RegExMatch]. Group 0 is the default and will always refer to the entire pattern. In the above example, calling [code]result.get_string(1)[/code] would give you [code]0123[/code]. + The results of capturing groups [code]()[/code] can be retrieved by passing the group number to the various methods in [RegExMatch]. Group 0 is the default and will always refer to the entire pattern. In the above example, calling [code]result.get_string(1)[/code] would give you [code]0123[/code]. This version of RegEx also supports named capturing groups, and the names can be used to retrieve the results. If two or more groups have the same name, the name would only refer to the first one with a match. [codeblock] var regex = RegEx.new() @@ -34,6 +34,15 @@ print(result.get_string("digit")) # Would print 01 03 0 3f 42 [/codeblock] + [b]Example of splitting a string using a RegEx:[/b] + [codeblock] + var regex = RegEx.new() + regex.compile("\\S+") # Negated whitespace character class. + var results = [] + for match in regex.search_all("One Two \n\tThree"): + results.push_back(match.get_string()) + # The `results` array now contains "One", "Two", "Three". + [/codeblock] [b]Note:[/b] Godot's regex implementation is based on the [url=https://www.pcre.org/]PCRE2[/url] library. You can view the full pattern reference [url=https://www.pcre.org/current/doc/html/pcre2pattern.html]here[/url]. [b]Tip:[/b] You can use [url=https://regexr.com/]Regexr[/url] to test regular expressions online. </description> diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 2fcd9332a1..5581ea9318 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -2513,6 +2513,8 @@ RES VisualScriptEditor::get_edited_resource() const { } void VisualScriptEditor::set_edited_resource(const RES &p_res) { + ERR_FAIL_COND(script.is_valid()); + ERR_FAIL_COND(p_res.is_null()); script = p_res; signal_editor->script = script; signal_editor->undo_redo = undo_redo; @@ -2533,6 +2535,9 @@ void VisualScriptEditor::set_edited_resource(const RES &p_res) { _update_members(); } +void VisualScriptEditor::enable_editor() { +} + Vector<String> VisualScriptEditor::get_functions() { return Vector<String>(); } @@ -2546,6 +2551,9 @@ String VisualScriptEditor::get_name() { if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) { name = script->get_path().get_file(); if (is_unsaved()) { + if (script->get_path().empty()) { + name = TTR("[unsaved]"); + } name += "(*)"; } } else if (script->get_name() != "") { @@ -2562,7 +2570,11 @@ Ref<Texture2D> VisualScriptEditor::get_theme_icon() { } bool VisualScriptEditor::is_unsaved() { - return script->is_edited() || script->are_subnodes_edited(); + bool unsaved = + script->is_edited() || + script->are_subnodes_edited() || + script->get_path().empty(); // In memory. + return unsaved; } Variant VisualScriptEditor::get_edit_state() { diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index e59618e120..0c5665cee8 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -294,6 +294,7 @@ public: virtual void apply_code() override; virtual RES get_edited_resource() const override; virtual void set_edited_resource(const RES &p_res) override; + virtual void enable_editor() override; virtual Vector<String> get_functions() override; virtual void reload_text() override; virtual String get_name() override; diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp index bd41117497..2ac7793b8c 100644 --- a/modules/visual_script/visual_script_expression.cpp +++ b/modules/visual_script/visual_script_expression.cpp @@ -489,7 +489,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) { r_token.type = TK_CONSTANT; if (is_float) { - r_token.value = num.to_double(); + r_token.value = num.to_float(); } else { r_token.value = num.to_int(); } diff --git a/platform/android/detect.py b/platform/android/detect.py index a4ac87f723..0accacb679 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -115,7 +115,8 @@ def configure(env): if env["android_arch"] == "x86_64": if get_platform(env["ndk_platform"]) < 21: print( - "WARNING: android_arch=x86_64 is not supported by ndk_platform lower than android-21; setting ndk_platform=android-21" + "WARNING: android_arch=x86_64 is not supported by ndk_platform lower than android-21; setting" + " ndk_platform=android-21" ) env["ndk_platform"] = "android-21" env["ARCH"] = "arch-x86_64" @@ -136,7 +137,8 @@ def configure(env): elif env["android_arch"] == "arm64v8": if get_platform(env["ndk_platform"]) < 21: print( - "WARNING: android_arch=arm64v8 is not supported by ndk_platform lower than android-21; setting ndk_platform=android-21" + "WARNING: android_arch=arm64v8 is not supported by ndk_platform lower than android-21; setting" + " ndk_platform=android-21" ) env["ndk_platform"] = "android-21" env["ARCH"] = "arch-arm64" @@ -231,7 +233,10 @@ def configure(env): env.Append(CPPDEFINES=[("__ANDROID_API__", str(get_platform(env["ndk_platform"])))]) env.Append( - CCFLAGS="-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing".split() + CCFLAGS=( + "-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden" + " -fno-strict-aliasing".split() + ) ) env.Append(CPPDEFINES=["NO_STATVFS", "GLES_ENABLED"]) diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 7193519a52..235c9ff665 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -155,12 +155,12 @@ bool DisplayServerAndroid::screen_is_touchscreen(int p_screen) const { return true; } -void DisplayServerAndroid::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_length, int p_cursor_start, int p_cursor_end) { +void DisplayServerAndroid::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) { GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java(); ERR_FAIL_COND(!godot_io_java); if (godot_io_java->has_vk()) { - godot_io_java->show_vk(p_existing_text, p_max_length, p_cursor_start, p_cursor_end); + godot_io_java->show_vk(p_existing_text, p_multiline, p_max_length, p_cursor_start, p_cursor_end); } else { ERR_PRINT("Virtual keyboard not available"); } diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index 4cae52fa76..5cdc69ee83 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -113,7 +113,7 @@ public: virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const; virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const; - virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1); + virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1); virtual void virtual_keyboard_hide(); virtual int virtual_keyboard_get_height() const; diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 0213094c60..6f8a968c82 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -768,6 +768,30 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { } } + void _write_tmp_manifest(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, bool p_debug) { + String manifest_text = + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " xmlns:tools=\"http://schemas.android.com/tools\">\n"; + + manifest_text += _get_screen_sizes_tag(p_preset); + manifest_text += _get_gles_tag(); + + Vector<String> perms; + _get_permissions(p_preset, p_give_internet, perms); + for (int i = 0; i < perms.size(); i++) { + manifest_text += vformat(" <uses-permission android:name=\"%s\" />\n", perms.get(i)); + } + + manifest_text += _get_xr_features_tag(p_preset); + manifest_text += _get_instrumentation_tag(p_preset); + String plugins_names = get_plugins_names(get_enabled_plugins(p_preset)); + manifest_text += _get_application_tag(p_preset, plugins_names); + manifest_text += "</manifest>\n"; + String manifest_path = vformat("res://android/build/src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release")); + store_string_at_path(manifest_path, manifest_text); + } + void _fix_manifest(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_manifest, bool p_give_internet) { // Leaving the unused types commented because looking these constants up // again later would be annoying @@ -2056,6 +2080,93 @@ public: return OK; } + Error sign_apk(const Ref<EditorExportPreset> &p_preset, bool p_debug, String apk_path, EditorProgress ep) { + String release_keystore = p_preset->get("keystore/release"); + String release_username = p_preset->get("keystore/release_user"); + String release_password = p_preset->get("keystore/release_password"); + + String jarsigner = EditorSettings::get_singleton()->get("export/android/jarsigner"); + if (!FileAccess::exists(jarsigner)) { + EditorNode::add_io_error("'jarsigner' could not be found.\nPlease supply a path in the Editor Settings.\nThe resulting APK is unsigned."); + return OK; + } + + String keystore; + String password; + String user; + if (p_debug) { + keystore = p_preset->get("keystore/debug"); + password = p_preset->get("keystore/debug_password"); + user = p_preset->get("keystore/debug_user"); + + if (keystore.empty()) { + keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore"); + password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass"); + user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user"); + } + + if (ep.step("Signing debug APK...", 103)) { + return ERR_SKIP; + } + + } else { + keystore = release_keystore; + password = release_password; + user = release_username; + + if (ep.step("Signing release APK...", 103)) { + return ERR_SKIP; + } + } + + if (!FileAccess::exists(keystore)) { + EditorNode::add_io_error("Could not find keystore, unable to export."); + return ERR_FILE_CANT_OPEN; + } + + List<String> args; + args.push_back("-digestalg"); + args.push_back("SHA-256"); + args.push_back("-sigalg"); + args.push_back("SHA256withRSA"); + String tsa_url = EditorSettings::get_singleton()->get("export/android/timestamping_authority_url"); + if (tsa_url != "") { + args.push_back("-tsa"); + args.push_back(tsa_url); + } + args.push_back("-verbose"); + args.push_back("-keystore"); + args.push_back(keystore); + args.push_back("-storepass"); + args.push_back(password); + args.push_back(apk_path); + args.push_back(user); + int retval; + OS::get_singleton()->execute(jarsigner, args, true, NULL, NULL, &retval); + if (retval) { + EditorNode::add_io_error("'jarsigner' returned with error #" + itos(retval)); + return ERR_CANT_CREATE; + } + + if (ep.step("Verifying APK...", 104)) { + return ERR_SKIP; + } + + args.clear(); + args.push_back("-verify"); + args.push_back("-keystore"); + args.push_back(keystore); + args.push_back(apk_path); + args.push_back("-verbose"); + + OS::get_singleton()->execute(jarsigner, args, true, NULL, NULL, &retval); + if (retval) { + EditorNode::add_io_error("'jarsigner' verification of APK failed. Make sure to use a jarsigner from OpenJDK 8."); + return ERR_CANT_CREATE; + } + return OK; + } + virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override { ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); @@ -2064,6 +2175,7 @@ public: EditorProgress ep("export", "Exporting for Android", 105, true); bool use_custom_build = bool(p_preset->get("custom_template/use_custom_build")); + bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG); Ref<Image> main_image; Ref<Image> foreground; @@ -2093,9 +2205,10 @@ public: if (err != OK) { EditorNode::add_io_error("Unable to overwrite res://android/build/res/*.xml files with project name"); } - // Copies the project icon files into the appropriate Gradle project directory + // Copies the project icon files into the appropriate Gradle project directory. _copy_icons_to_gradle_project(p_preset, main_image, foreground, background); - + // Write an AndroidManifest.xml file into the Gradle project directory. + _write_tmp_manifest(p_preset, p_give_internet, p_debug); //build project if custom build is enabled String sdk_path = EDITOR_GET("export/android/custom_build_sdk_path"); @@ -2115,6 +2228,8 @@ public: build_command = build_path.plus_file(build_command); String package_name = get_package_name(p_preset->get("package/unique_name")); + String version_code = itos(p_preset->get("version/code")); + String version_name = p_preset->get("version/name"); Vector<PluginConfig> enabled_plugins = get_enabled_plugins(p_preset); String local_plugins_binaries = get_plugins_binaries(BINARY_TYPE_LOCAL, enabled_plugins); @@ -2128,6 +2243,8 @@ public: } cmdline.push_back("build"); cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name. + cmdline.push_back("-Pexport_version_code=" + version_code); // argument to specify the version code. + cmdline.push_back("-Pexport_version_name=" + version_name); // argument to specify the version name. cmdline.push_back("-Pplugins_local_binaries=" + local_plugins_binaries); // argument to specify the list of plugins local dependencies. cmdline.push_back("-Pplugins_remote_binaries=" + remote_plugins_binaries); // argument to specify the list of plugins remote dependencies. cmdline.push_back("-Pplugins_maven_repos=" + custom_maven_repos); // argument to specify the list of custom maven repos for the plugins dependencies. @@ -2219,10 +2336,6 @@ public: bool apk_expansion = p_preset->get("apk_expansion/enable"); String apk_expansion_pkey = p_preset->get("apk_expansion/public_key"); - String release_keystore = p_preset->get("keystore/release"); - String release_username = p_preset->get("keystore/release_user"); - String release_password = p_preset->get("keystore/release_password"); - Vector<String> enabled_abis = get_enabled_abis(p_preset); // Prepare images to be resized for the icons. If some image ends up being uninitialized, the default image from the export template will be used. @@ -2248,11 +2361,10 @@ public: //write - if (file == "AndroidManifest.xml") { - _fix_manifest(p_preset, data, p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG)); - } - if (!use_custom_build) { + if (file == "AndroidManifest.xml") { + _fix_manifest(p_preset, data, p_give_internet); + } if (file == "resources.arsc") { _fix_resources(p_preset, data); } @@ -2375,84 +2487,9 @@ public: } if (_signed) { - String jarsigner = EditorSettings::get_singleton()->get("export/android/jarsigner"); - if (!FileAccess::exists(jarsigner)) { - EditorNode::add_io_error("'jarsigner' could not be found.\nPlease supply a path in the Editor Settings.\nThe resulting APK is unsigned."); - CLEANUP_AND_RETURN(OK); - } - - String keystore; - String password; - String user; - if (p_debug) { - keystore = p_preset->get("keystore/debug"); - password = p_preset->get("keystore/debug_password"); - user = p_preset->get("keystore/debug_user"); - - if (keystore.empty()) { - keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore"); - password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass"); - user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user"); - } - - if (ep.step("Signing debug APK...", 103)) { - CLEANUP_AND_RETURN(ERR_SKIP); - } - - } else { - keystore = release_keystore; - password = release_password; - user = release_username; - - if (ep.step("Signing release APK...", 103)) { - CLEANUP_AND_RETURN(ERR_SKIP); - } - } - - if (!FileAccess::exists(keystore)) { - EditorNode::add_io_error("Could not find keystore, unable to export."); - CLEANUP_AND_RETURN(ERR_FILE_CANT_OPEN); - } - - List<String> args; - args.push_back("-digestalg"); - args.push_back("SHA-256"); - args.push_back("-sigalg"); - args.push_back("SHA256withRSA"); - String tsa_url = EditorSettings::get_singleton()->get("export/android/timestamping_authority_url"); - if (tsa_url != "") { - args.push_back("-tsa"); - args.push_back(tsa_url); - } - args.push_back("-verbose"); - args.push_back("-keystore"); - args.push_back(keystore); - args.push_back("-storepass"); - args.push_back(password); - args.push_back(tmp_unaligned_path); - args.push_back(user); - int retval; - OS::get_singleton()->execute(jarsigner, args, true, nullptr, nullptr, &retval); - if (retval) { - EditorNode::add_io_error("'jarsigner' returned with error #" + itos(retval)); - CLEANUP_AND_RETURN(ERR_CANT_CREATE); - } - - if (ep.step("Verifying APK...", 104)) { - CLEANUP_AND_RETURN(ERR_SKIP); - } - - args.clear(); - args.push_back("-verify"); - args.push_back("-keystore"); - args.push_back(keystore); - args.push_back(tmp_unaligned_path); - args.push_back("-verbose"); - - OS::get_singleton()->execute(jarsigner, args, true, nullptr, nullptr, &retval); - if (retval) { - EditorNode::add_io_error("'jarsigner' verification of APK failed. Make sure to use a jarsigner from OpenJDK 8."); - CLEANUP_AND_RETURN(ERR_CANT_CREATE); + err = sign_apk(p_preset, p_debug, tmp_unaligned_path, ep); + if (err != OK) { + CLEANUP_AND_RETURN(err); } } diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 622860c307..209a664f8f 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -142,4 +142,104 @@ Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset return OK; } +String bool_to_string(bool v) { + return v ? "true" : "false"; +} + +String _get_gles_tag() { + bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name") == "GLES3" && + !ProjectSettings::get_singleton()->get("rendering/quality/driver/fallback_to_gles2"); + return min_gles3 ? " <uses-feature android:glEsVersion=\"0x00030000\" android:required=\"true\" />\n" : ""; +} + +String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) { + String manifest_screen_sizes = " <supports-screens \n tools:node=\"replace\""; + String sizes[] = { "small", "normal", "large", "xlarge" }; + size_t num_sizes = sizeof(sizes) / sizeof(sizes[0]); + for (size_t i = 0; i < num_sizes; i++) { + String feature_name = vformat("screen/support_%s", sizes[i]); + String feature_support = bool_to_string(p_preset->get(feature_name)); + String xml_entry = vformat("\n android:%sScreens=\"%s\"", sizes[i], feature_support); + manifest_screen_sizes += xml_entry; + } + manifest_screen_sizes += " />\n"; + return manifest_screen_sizes; +} + +String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) { + String manifest_xr_features; + bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1; + if (uses_xr) { + int dof_index = p_preset->get("xr_features/degrees_of_freedom"); // 0: none, 1: 3dof and 6dof, 2: 6dof + if (dof_index == 1) { + manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vr.headtracking\" android:required=\"false\" android:version=\"1\" />\n"; + } else if (dof_index == 2) { + manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vr.headtracking\" android:required=\"true\" android:version=\"1\" />\n"; + } + int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required + if (hand_tracking_index == 1) { + manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"false\" />\n"; + } else if (hand_tracking_index == 2) { + manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"true\" />\n"; + } + } + return manifest_xr_features; +} + +String _get_instrumentation_tag(const Ref<EditorExportPreset> &p_preset) { + String package_name = p_preset->get("package/unique_name"); + String manifest_instrumentation_text = vformat( + " <instrumentation\n" + " tools:node=\"replace\"\n" + " android:name=\".GodotInstrumentation\"\n" + " android:icon=\"@mipmap/icon\"\n" + " android:label=\"@string/godot_project_name_string\"\n" + " android:targetPackage=\"%s\" />\n", + package_name); + return manifest_instrumentation_text; +} + +String _get_plugins_tag(const String &plugins_names) { + if (!plugins_names.empty()) { + return vformat(" <meta-data tools:node=\"replace\" android:name=\"plugins\" android:value=\"%s\" />\n", plugins_names); + } else { + return " <meta-data tools:node=\"remove\" android:name=\"plugins\" />\n"; + } +} + +String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) { + bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1; + String orientation = (int)(p_preset->get("screen/orientation")) == 1 ? "portrait" : "landscape"; + String manifest_activity_text = vformat( + " <activity android:name=\"com.godot.game.GodotApp\" " + "tools:replace=\"android:screenOrientation\" " + "android:screenOrientation=\"%s\">\n", + orientation); + if (uses_xr) { + String focus_awareness = bool_to_string(p_preset->get("xr_features/focus_awareness")); + manifest_activity_text += vformat(" <meta-data tools:node=\"replace\" android:name=\"com.oculus.vr.focusaware\" android:value=\"%s\" />\n", focus_awareness); + } else { + manifest_activity_text += " <meta-data tools:node=\"remove\" android:name=\"com.oculus.vr.focusaware\" />\n"; + } + manifest_activity_text += " </activity>\n"; + return manifest_activity_text; +} + +String _get_application_tag(const Ref<EditorExportPreset> &p_preset, const String &plugins_names) { + bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1; + String manifest_application_text = + " <application android:label=\"@string/godot_project_name_string\"\n" + " android:allowBackup=\"false\" tools:ignore=\"GoogleAppIndexingWarning\"\n" + " android:icon=\"@mipmap/icon\">)\n\n" + " <meta-data tools:node=\"remove\" android:name=\"xr_mode_metadata_name\" />\n"; + + manifest_application_text += _get_plugins_tag(plugins_names); + if (uses_xr) { + manifest_application_text += " <meta-data tools:node=\"replace\" android:name=\"com.samsung.android.vr.application.mode\" android:value=\"vr_only\" />\n"; + } + manifest_application_text += _get_activity_tag(p_preset); + manifest_application_text += " </application>\n"; + return manifest_application_text; +} + #endif //GODOT_GRADLE_EXPORT_UTIL_H diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle index 19202d2310..3f8d138e8f 100644 --- a/platform/android/java/app/build.gradle +++ b/platform/android/java/app/build.gradle @@ -82,6 +82,8 @@ android { // Feel free to modify the application id to your own. applicationId getExportPackageName() + versionCode getExportVersionCode() + versionName getExportVersionName() minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk } diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle index acfdef531e..7d5d238100 100644 --- a/platform/android/java/app/config.gradle +++ b/platform/android/java/app/config.gradle @@ -28,6 +28,22 @@ ext.getExportPackageName = { -> return appId } +ext.getExportVersionCode = { -> + String versionCode = project.hasProperty("export_version_code") ? project.property("export_version_code") : "" + if (versionCode == null || versionCode.isEmpty()) { + versionCode = "1" + } + return Integer.parseInt(versionCode) +} + +ext.getExportVersionName = { -> + String versionName = project.hasProperty("export_version_name") ? project.property("export_version_name") : "" + if (versionName == null || versionName.isEmpty()) { + versionName = "1.0" + } + return versionName +} + final String PLUGIN_VALUE_SEPARATOR_REGEX = "\\|" /** diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index 1ae400abb5..35852f31ef 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -56,8 +56,6 @@ import android.content.SharedPreferences.Editor; import android.content.pm.ConfigurationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.graphics.Point; -import android.graphics.Rect; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; @@ -77,7 +75,6 @@ import android.view.Surface; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; -import android.view.ViewTreeObserver; import android.view.Window; import android.view.WindowManager; import android.widget.Button; @@ -163,6 +160,8 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC public GodotRenderView mRenderView; private boolean godot_initialized = false; + private GodotEditText mEditText; + private SensorManager mSensorManager; private Sensor mAccelerometer; private Sensor mGravity; @@ -219,12 +218,6 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC containerLayout = new FrameLayout(activity); containerLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); - // GodotEditText layout - GodotEditText editText = new GodotEditText(activity); - editText.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - // ...add to FrameLayout - containerLayout.addView(editText); - GodotLib.setup(command_line); final String videoDriver = GodotLib.getGlobal("rendering/quality/driver/driver_name"); @@ -237,21 +230,9 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC View view = mRenderView.getView(); containerLayout.addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); - editText.setView(mRenderView); - io.setEdit(editText); - view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - Point fullSize = new Point(); - activity.getWindowManager().getDefaultDisplay().getSize(fullSize); - Rect gameSize = new Rect(); - mRenderView.getView().getWindowVisibleDisplayFrame(gameSize); - - final int keyboardHeight = fullSize.y - gameSize.bottom; - GodotLib.setVirtualKeyboardHeight(keyboardHeight); - } - }); + mEditText = new GodotEditText(activity, mRenderView); + io.setEdit(mEditText); mRenderView.queueOnRenderThread(new Runnable() { @Override @@ -604,7 +585,21 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC } @Override + public void onStart() { + super.onStart(); + + mRenderView.getView().post(new Runnable() { + @Override + public void run() { + mEditText.onInitView(); + } + }); + } + + @Override public void onDestroy() { + mEditText.onDestroyView(); + for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) { plugin.onMainDestroy(); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java index 4dd228e53b..c2f3c88416 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java @@ -461,9 +461,9 @@ public class GodotIO { return (int)(metrics.density * 160f); } - public void showKeyboard(String p_existing_text, int p_max_input_length, int p_cursor_start, int p_cursor_end) { + public void showKeyboard(String p_existing_text, boolean p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { if (edit != null) - edit.showKeyboard(p_existing_text, p_max_input_length, p_cursor_start, p_cursor_end); + edit.showKeyboard(p_existing_text, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end); //InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE); //inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java index c0defd008e..6855f91f1c 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java @@ -32,15 +32,27 @@ package org.godotengine.godot.input; import org.godotengine.godot.*; +import android.app.Activity; import android.content.Context; +import android.graphics.Point; +import android.graphics.Rect; import android.os.Handler; import android.os.Message; import android.text.InputFilter; +import android.text.InputType; import android.util.AttributeSet; +import android.view.Gravity; import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.view.ViewTreeObserver; +import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.PopupWindow; import java.lang.ref.WeakReference; @@ -55,10 +67,13 @@ public class GodotEditText extends EditText { // Fields // =========================================================== private GodotRenderView mRenderView; + private View mKeyboardView; + private PopupWindow mKeyboardWindow; private GodotTextInputWrapper mInputWrapper; private EditHandler sHandler = new EditHandler(this); private String mOriginText; - private int mMaxInputLength; + private int mMaxInputLength = Integer.MAX_VALUE; + private boolean mMultiline = false; private static class EditHandler extends Handler { private final WeakReference<GodotEditText> mEdit; @@ -78,24 +93,56 @@ public class GodotEditText extends EditText { // =========================================================== // Constructors // =========================================================== - public GodotEditText(final Context context) { + public GodotEditText(final Context context, final GodotRenderView view) { super(context); - initView(); + + setPadding(0, 0, 0, 0); + setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE); + setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); + + mRenderView = view; + mInputWrapper = new GodotTextInputWrapper(mRenderView, this); + setOnEditorActionListener(mInputWrapper); + view.getView().requestFocus(); + + // Create a popup window with an invisible layout for the virtual keyboard, + // so the view can be resized to get the vk height without resizing the main godot view. + final FrameLayout keyboardLayout = new FrameLayout(context); + keyboardLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + keyboardLayout.setVisibility(View.INVISIBLE); + keyboardLayout.addView(this); + mKeyboardView = keyboardLayout; + + mKeyboardWindow = new PopupWindow(keyboardLayout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + mKeyboardWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + mKeyboardWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); + mKeyboardWindow.setFocusable(true); // for the text edit to work + mKeyboardWindow.setTouchable(false); // inputs need to go through + + keyboardLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + Point fullSize = new Point(); + ((Activity)mRenderView.getView().getContext()).getWindowManager().getDefaultDisplay().getSize(fullSize); + Rect gameSize = new Rect(); + mKeyboardWindow.getContentView().getWindowVisibleDisplayFrame(gameSize); + + final int keyboardHeight = fullSize.y - gameSize.bottom; + GodotLib.setVirtualKeyboardHeight(keyboardHeight); + } + }); } - public GodotEditText(final Context context, final AttributeSet attrs) { - super(context, attrs); - initView(); + public void onInitView() { + mKeyboardWindow.showAtLocation(mRenderView.getView(), Gravity.NO_GRAVITY, 0, 0); } - public GodotEditText(final Context context, final AttributeSet attrs, final int defStyle) { - super(context, attrs, defStyle); - initView(); + public void onDestroyView() { + mKeyboardWindow.dismiss(); } - protected void initView() { - setPadding(0, 0, 0, 0); - setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); + public boolean isMultiline() { + return mMultiline; } private void handleMessage(final Message msg) { @@ -115,9 +162,15 @@ public class GodotEditText extends EditText { edit.mInputWrapper.setSelection(false); } + int inputType = InputType.TYPE_CLASS_TEXT; + if (edit.isMultiline()) { + inputType |= InputType.TYPE_TEXT_FLAG_MULTI_LINE; + } + edit.setInputType(inputType); + edit.mInputWrapper.setOriginText(text); edit.addTextChangedListener(edit.mInputWrapper); - final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + final InputMethodManager imm = (InputMethodManager)mKeyboardView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(edit, 0); } } break; @@ -126,7 +179,7 @@ public class GodotEditText extends EditText { GodotEditText edit = (GodotEditText)msg.obj; edit.removeTextChangedListener(mInputWrapper); - final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + final InputMethodManager imm = (InputMethodManager)mKeyboardView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(edit.getWindowToken(), 0); edit.mRenderView.getView().requestFocus(); } break; @@ -140,17 +193,6 @@ public class GodotEditText extends EditText { } // =========================================================== - // Getter & Setter - // =========================================================== - public void setView(final GodotRenderView view) { - mRenderView = view; - if (mInputWrapper == null) - mInputWrapper = new GodotTextInputWrapper(mRenderView, this); - setOnEditorActionListener(mInputWrapper); - view.getView().requestFocus(); - } - - // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== @Override @@ -189,7 +231,7 @@ public class GodotEditText extends EditText { // =========================================================== // Methods // =========================================================== - public void showKeyboard(String p_existing_text, int p_max_input_length, int p_cursor_start, int p_cursor_end) { + public void showKeyboard(String p_existing_text, boolean p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { int maxInputLength = (p_max_input_length <= 0) ? Integer.MAX_VALUE : p_max_input_length; if (p_cursor_start == -1) { // cursor position not given this.mOriginText = p_existing_text; @@ -202,6 +244,8 @@ public class GodotEditText extends EditText { this.mMaxInputLength = maxInputLength - (p_existing_text.length() - p_cursor_end); } + this.mMultiline = p_multiline; + final Message msg = new Message(); msg.what = HANDLER_OPEN_IME_KEYBOARD; msg.obj = this; diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java index 9c7cf9f341..4dd1054738 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java @@ -123,7 +123,7 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene public void run() { for (int i = 0; i < count; ++i) { int key = newChars[i]; - if (key == '\n') { + if ((key == '\n') && !mEdit.isMultiline()) { // Return keys are handled through action events continue; } @@ -151,7 +151,7 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene }); } - if (pActionID == EditorInfo.IME_NULL) { + if (pActionID == EditorInfo.IME_ACTION_DONE) { // Enter key has been pressed GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, true); GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, false); diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt index aeb4628d5d..7fa8e3b4e5 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt @@ -71,7 +71,7 @@ internal class VkRenderer { */ fun onVkSurfaceChanged(surface: Surface, width: Int, height: Int) { GodotLib.resize(surface, width, height) - + for (plugin in pluginRegistry.getAllPlugins()) { plugin.onVkSurfaceChanged(surface, width, height) } diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp index 0a42adeaf2..4ccbc6b97e 100644 --- a/platform/android/java_godot_io_wrapper.cpp +++ b/platform/android/java_godot_io_wrapper.cpp @@ -53,7 +53,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc _get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;"); _get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I"); _get_unique_id = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;"); - _show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;III)V"); + _show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;ZIII)V"); _hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V"); _set_screen_orientation = p_env->GetMethodID(cls, "setScreenOrientation", "(I)V"); _get_screen_orientation = p_env->GetMethodID(cls, "getScreenOrientation", "()I"); @@ -132,11 +132,11 @@ bool GodotIOJavaWrapper::has_vk() { return (_show_keyboard != 0) && (_hide_keyboard != 0); } -void GodotIOJavaWrapper::show_vk(const String &p_existing, int p_max_input_length, int p_cursor_start, int p_cursor_end) { +void GodotIOJavaWrapper::show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { if (_show_keyboard) { JNIEnv *env = ThreadAndroid::get_env(); jstring jStr = env->NewStringUTF(p_existing.utf8().get_data()); - env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_max_input_length, p_cursor_start, p_cursor_end); + env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end); } } diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h index 1742021379..6465ded985 100644 --- a/platform/android/java_godot_io_wrapper.h +++ b/platform/android/java_godot_io_wrapper.h @@ -70,7 +70,7 @@ public: int get_screen_dpi(); String get_unique_id(); bool has_vk(); - void show_vk(const String &p_existing, int p_max_input_length, int p_cursor_start, int p_cursor_end); + void show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end); void hide_vk(); int get_vk_height(); void set_vk_height(int p_height); diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub index b72d29149c..49c77468ed 100644 --- a/platform/iphone/SCsub +++ b/platform/iphone/SCsub @@ -3,10 +3,8 @@ Import("env") iphone_lib = [ - "godot_iphone.cpp", - "os_iphone.cpp", - "semaphore_iphone.cpp", - "gl_view.mm", + "godot_iphone.mm", + "os_iphone.mm", "main.m", "app_delegate.mm", "view_controller.mm", @@ -15,6 +13,12 @@ iphone_lib = [ "icloud.mm", "ios.mm", "vulkan_context_iphone.mm", + "display_server_iphone.mm", + "joypad_iphone.mm", + "godot_view.mm", + "display_layer.mm", + "godot_view_renderer.mm", + "godot_view_gesture_recognizer.m", ] env_ios = env.Clone() diff --git a/platform/iphone/app_delegate.h b/platform/iphone/app_delegate.h index 27552d781a..2f082f1e07 100644 --- a/platform/iphone/app_delegate.h +++ b/platform/iphone/app_delegate.h @@ -28,29 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#if defined(OPENGL_ENABLED) -#import "gl_view.h" -#endif -#import "view_controller.h" #import <UIKit/UIKit.h> -#import <CoreMotion/CoreMotion.h> +@class ViewController; // FIXME: Add support for both GLES2 and Vulkan when GLES2 is implemented again, // so it can't be done with compilation time branching. //#if defined(OPENGL_ENABLED) //@interface AppDelegate : NSObject <UIApplicationDelegate, GLViewDelegate> { //#endif -#if defined(VULKAN_ENABLED) -@interface AppDelegate : NSObject <UIApplicationDelegate> { -#endif - //@property (strong, nonatomic) UIWindow *window; - ViewController *view_controller; - bool is_focus_out; -}; +//#if defined(VULKAN_ENABLED) +@interface AppDelegate : NSObject <UIApplicationDelegate> +//#endif @property(strong, nonatomic) UIWindow *window; - -+ (ViewController *)getViewController; +@property(strong, class, readonly, nonatomic) ViewController *viewController; @end diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm index c4ef185bf1..7edbcc4667 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -29,644 +29,60 @@ /*************************************************************************/ #import "app_delegate.h" - #include "core/project_settings.h" #include "drivers/coreaudio/audio_driver_coreaudio.h" -#if defined(OPENGL_ENABLED) -#import "gl_view.h" -#endif +#import "godot_view.h" #include "main/main.h" #include "os_iphone.h" +#import "view_controller.h" -#import "GameController/GameController.h" #import <AudioToolbox/AudioServices.h> -#define kFilteringFactor 0.1 #define kRenderingFrequency 60 -#define kAccelerometerFrequency 100.0 // Hz - -Error _shell_open(String); -void _set_keep_screen_on(bool p_enabled); - -Error _shell_open(String p_uri) { - NSString *url = [[NSString alloc] initWithUTF8String:p_uri.utf8().get_data()]; - - if (![[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:url]]) - return ERR_CANT_OPEN; - - printf("opening url %ls\n", p_uri.c_str()); - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]]; - [url release]; - return OK; -}; - -void _set_keep_screen_on(bool p_enabled) { - [[UIApplication sharedApplication] setIdleTimerDisabled:(BOOL)p_enabled]; -}; - -void _vibrate() { - AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); -}; - -@implementation AppDelegate - -@synthesize window; extern int gargc; extern char **gargv; -extern int iphone_main(int, int, int, char **, String); + +extern int iphone_main(int, char **, String); extern void iphone_finish(); -CMMotionManager *motionManager; -bool motionInitialised; +@implementation AppDelegate static ViewController *mainViewController = nil; -+ (ViewController *)getViewController { - return mainViewController; -} - -NSMutableDictionary *ios_joysticks = nil; -NSMutableArray *pending_ios_joysticks = nil; - -- (GCControllerPlayerIndex)getFreePlayerIndex { - bool have_player_1 = false; - bool have_player_2 = false; - bool have_player_3 = false; - bool have_player_4 = false; - - if (ios_joysticks == nil) { - NSArray *keys = [ios_joysticks allKeys]; - for (NSNumber *key in keys) { - GCController *controller = [ios_joysticks objectForKey:key]; - if (controller.playerIndex == GCControllerPlayerIndex1) { - have_player_1 = true; - } else if (controller.playerIndex == GCControllerPlayerIndex2) { - have_player_2 = true; - } else if (controller.playerIndex == GCControllerPlayerIndex3) { - have_player_3 = true; - } else if (controller.playerIndex == GCControllerPlayerIndex4) { - have_player_4 = true; - }; - }; - }; - - if (!have_player_1) { - return GCControllerPlayerIndex1; - } else if (!have_player_2) { - return GCControllerPlayerIndex2; - } else if (!have_player_3) { - return GCControllerPlayerIndex3; - } else if (!have_player_4) { - return GCControllerPlayerIndex4; - } else { - return GCControllerPlayerIndexUnset; - }; -}; - -void _ios_add_joystick(GCController *controller, AppDelegate *delegate) { - // get a new id for our controller - int joy_id = OSIPhone::get_singleton()->get_unused_joy_id(); - if (joy_id != -1) { - // assign our player index - if (controller.playerIndex == GCControllerPlayerIndexUnset) { - controller.playerIndex = [delegate getFreePlayerIndex]; - }; - - // tell Godot about our new controller - OSIPhone::get_singleton()->joy_connection_changed( - joy_id, true, [controller.vendorName UTF8String]); - - // add it to our dictionary, this will retain our controllers - [ios_joysticks setObject:controller - forKey:[NSNumber numberWithInt:joy_id]]; - - // set our input handler - [delegate setControllerInputHandler:controller]; - } else { - printf("Couldn't retrieve new joy id\n"); - }; -} - -static void on_focus_out(ViewController *view_controller, bool *is_focus_out) { - if (!*is_focus_out) { - *is_focus_out = true; - if (OS::get_singleton()->get_main_loop()) - OS::get_singleton()->get_main_loop()->notification( - MainLoop::NOTIFICATION_WM_FOCUS_OUT); - - [view_controller.view stopAnimation]; - if (OS::get_singleton()->native_video_is_playing()) { - OSIPhone::get_singleton()->native_video_focus_out(); - } - AudioDriverCoreAudio *audio = dynamic_cast<AudioDriverCoreAudio *>(AudioDriverCoreAudio::get_singleton()); - if (audio) - audio->stop(); - } -} - -static void on_focus_in(ViewController *view_controller, bool *is_focus_out) { - if (*is_focus_out) { - *is_focus_out = false; - if (OS::get_singleton()->get_main_loop()) - OS::get_singleton()->get_main_loop()->notification( - MainLoop::NOTIFICATION_WM_FOCUS_IN); - - [view_controller.view startAnimation]; - if (OSIPhone::get_singleton()->native_video_is_playing()) { - OSIPhone::get_singleton()->native_video_unpause(); - } - - AudioDriverCoreAudio *audio = dynamic_cast<AudioDriverCoreAudio *>(AudioDriverCoreAudio::get_singleton()); - if (audio) - audio->start(); - } ++ (ViewController *)viewController { + return mainViewController; } -- (void)controllerWasConnected:(NSNotification *)notification { - // create our dictionary if we don't have one yet - if (ios_joysticks == nil) { - ios_joysticks = [[NSMutableDictionary alloc] init]; - }; - - // get our controller - GCController *controller = (GCController *)notification.object; - if (controller == nil) { - printf("Couldn't retrieve new controller\n"); - } else if ([[ios_joysticks allKeysForObject:controller] count] != 0) { - printf("Controller is already registered\n"); - } else if (frame_count > 1) { - _ios_add_joystick(controller, self); - } else { - if (pending_ios_joysticks == nil) - pending_ios_joysticks = [[NSMutableArray alloc] init]; - [pending_ios_joysticks addObject:controller]; - }; -}; - -- (void)controllerWasDisconnected:(NSNotification *)notification { - if (ios_joysticks != nil) { - // find our joystick, there should be only one in our dictionary - GCController *controller = (GCController *)notification.object; - NSArray *keys = [ios_joysticks allKeysForObject:controller]; - for (NSNumber *key in keys) { - // tell Godot this joystick is no longer there - int joy_id = [key intValue]; - OSIPhone::get_singleton()->joy_connection_changed(joy_id, false, ""); - - // and remove it from our dictionary - [ios_joysticks removeObjectForKey:key]; - }; - }; -}; - -- (int)getJoyIdForController:(GCController *)controller { - if (ios_joysticks != nil) { - // find our joystick, there should be only one in our dictionary - NSArray *keys = [ios_joysticks allKeysForObject:controller]; - for (NSNumber *key in keys) { - int joy_id = [key intValue]; - return joy_id; - }; - }; - - return -1; -}; - -- (void)setControllerInputHandler:(GCController *)controller { - // Hook in the callback handler for the correct gamepad profile. - // This is a bit of a weird design choice on Apples part. - // You need to select the most capable gamepad profile for the - // gamepad attached. - if (controller.extendedGamepad != nil) { - // The extended gamepad profile has all the input you could possibly find on - // a gamepad but will only be active if your gamepad actually has all of - // these... - controller.extendedGamepad.valueChangedHandler = ^( - GCExtendedGamepad *gamepad, GCControllerElement *element) { - int joy_id = [self getJoyIdForController:controller]; - - if (element == gamepad.buttonA) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_A, - gamepad.buttonA.isPressed); - } else if (element == gamepad.buttonB) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_B, - gamepad.buttonB.isPressed); - } else if (element == gamepad.buttonX) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_X, - gamepad.buttonX.isPressed); - } else if (element == gamepad.buttonY) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_Y, - gamepad.buttonY.isPressed); - } else if (element == gamepad.leftShoulder) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_LEFT_SHOULDER, - gamepad.leftShoulder.isPressed); - } else if (element == gamepad.rightShoulder) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_RIGHT_SHOULDER, - gamepad.rightShoulder.isPressed); - } else if (element == gamepad.dpad) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_UP, - gamepad.dpad.up.isPressed); - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_DOWN, - gamepad.dpad.down.isPressed); - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_LEFT, - gamepad.dpad.left.isPressed); - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_RIGHT, - gamepad.dpad.right.isPressed); - }; - - InputDefault::JoyAxis jx; - jx.min = -1; - if (element == gamepad.leftThumbstick) { - jx.value = gamepad.leftThumbstick.xAxis.value; - OSIPhone::get_singleton()->joy_axis(joy_id, JOY_AXIS_LEFT_X, jx); - jx.value = -gamepad.leftThumbstick.yAxis.value; - OSIPhone::get_singleton()->joy_axis(joy_id, JOY_AXIS_LEFT_Y, jx); - } else if (element == gamepad.rightThumbstick) { - jx.value = gamepad.rightThumbstick.xAxis.value; - OSIPhone::get_singleton()->joy_axis(joy_id, JOY_AXIS_RIGHT_X, jx); - jx.value = -gamepad.rightThumbstick.yAxis.value; - OSIPhone::get_singleton()->joy_axis(joy_id, JOY_AXIS_RIGHT_Y, jx); - } else if (element == gamepad.leftTrigger) { - jx.value = gamepad.leftTrigger.value; - OSIPhone::get_singleton()->joy_axis(joy_id, JOY_AXIS_TRIGGER_LEFT, jx); - } else if (element == gamepad.rightTrigger) { - jx.value = gamepad.rightTrigger.value; - OSIPhone::get_singleton()->joy_axis(joy_id, JOY_AXIS_TRIGGER_RIGHT, jx); - }; - }; - } else if (controller.gamepad != nil) { - // gamepad is the standard profile with 4 buttons, shoulder buttons and a - // D-pad - controller.gamepad.valueChangedHandler = ^(GCGamepad *gamepad, - GCControllerElement *element) { - int joy_id = [self getJoyIdForController:controller]; - - if (element == gamepad.buttonA) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_A, - gamepad.buttonA.isPressed); - } else if (element == gamepad.buttonB) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_B, - gamepad.buttonB.isPressed); - } else if (element == gamepad.buttonX) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_X, - gamepad.buttonX.isPressed); - } else if (element == gamepad.buttonY) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_Y, - gamepad.buttonY.isPressed); - } else if (element == gamepad.leftShoulder) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_LEFT_SHOULDER, - gamepad.leftShoulder.isPressed); - } else if (element == gamepad.rightShoulder) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_RIGHT_SHOULDER, - gamepad.rightShoulder.isPressed); - } else if (element == gamepad.dpad) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_UP, - gamepad.dpad.up.isPressed); - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_DOWN, - gamepad.dpad.down.isPressed); - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_LEFT, - gamepad.dpad.left.isPressed); - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_RIGHT, - gamepad.dpad.right.isPressed); - }; - }; -#ifdef ADD_MICRO_GAMEPAD // disabling this for now, only available on iOS 9+, - // while we are setting that as the minimum, seems our - // build environment doesn't like it - } else if (controller.microGamepad != nil) { - // micro gamepads were added in OS 9 and feature just 2 buttons and a d-pad - controller.microGamepad.valueChangedHandler = - ^(GCMicroGamepad *gamepad, GCControllerElement *element) { - int joy_id = [self getJoyIdForController:controller]; - - if (element == gamepad.buttonA) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_A, - gamepad.buttonA.isPressed); - } else if (element == gamepad.buttonX) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_X, - gamepad.buttonX.isPressed); - } else if (element == gamepad.dpad) { - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_UP, - gamepad.dpad.up.isPressed); - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_DOWN, - gamepad.dpad.down.isPressed); - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_LEFT, - gamepad.dpad.left.isPressed); - OSIPhone::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_RIGHT, - gamepad.dpad.right.isPressed); - }; - }; -#endif - }; - - ///@TODO need to add support for controller.motion which gives us access to - /// the orientation of the device (if supported) - - ///@TODO need to add support for controllerPausedHandler which should be a - /// toggle -}; - -- (void)initGameControllers { - // get told when controllers connect, this will be called right away for - // already connected controllers - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(controllerWasConnected:) - name:GCControllerDidConnectNotification - object:nil]; - - // get told when controllers disconnect - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(controllerWasDisconnected:) - name:GCControllerDidDisconnectNotification - object:nil]; -}; - -- (void)deinitGameControllers { - [[NSNotificationCenter defaultCenter] - removeObserver:self - name:GCControllerDidConnectNotification - object:nil]; - [[NSNotificationCenter defaultCenter] - removeObserver:self - name:GCControllerDidDisconnectNotification - object:nil]; - - if (ios_joysticks != nil) { - [ios_joysticks dealloc]; - ios_joysticks = nil; - }; - - if (pending_ios_joysticks != nil) { - [pending_ios_joysticks dealloc]; - pending_ios_joysticks = nil; - }; -}; - -OS::VideoMode _get_video_mode() { - int backingWidth; - int backingHeight; -#if defined(OPENGL_ENABLED) - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, - GL_RENDERBUFFER_WIDTH_OES, &backingWidth); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, - GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); -#endif - - OS::VideoMode vm; - vm.fullscreen = true; - vm.width = backingWidth; - vm.height = backingHeight; - vm.resizable = false; - return vm; -}; - -static int frame_count = 0; -- (void)drawView:(UIView *)view; -{ - switch (frame_count) { - case 0: { - OS::get_singleton()->set_video_mode(_get_video_mode()); - - if (!OS::get_singleton()) { - exit(0); - }; - ++frame_count; - - NSString *locale_code = [[NSLocale currentLocale] localeIdentifier]; - OSIPhone::get_singleton()->set_locale( - String::utf8([locale_code UTF8String])); - - NSString *uuid; - if ([[UIDevice currentDevice] - respondsToSelector:@selector(identifierForVendor)]) { - uuid = [UIDevice currentDevice].identifierForVendor.UUIDString; - } else { - // before iOS 6, so just generate an identifier and store it - uuid = [[NSUserDefaults standardUserDefaults] - objectForKey:@"identiferForVendor"]; - if (!uuid) { - CFUUIDRef cfuuid = CFUUIDCreate(NULL); - uuid = (__bridge_transfer NSString *)CFUUIDCreateString(NULL, cfuuid); - CFRelease(cfuuid); - [[NSUserDefaults standardUserDefaults] - setObject:uuid - forKey:@"identifierForVendor"]; - } - } - - OSIPhone::get_singleton()->set_unique_id(String::utf8([uuid UTF8String])); - - }; break; - - case 1: { - Main::setup2(); - ++frame_count; - - if (pending_ios_joysticks != nil) { - for (GCController *controller in pending_ios_joysticks) { - _ios_add_joystick(controller, self); - } - [pending_ios_joysticks dealloc]; - pending_ios_joysticks = nil; - } - - // this might be necessary before here - NSDictionary *dict = [[NSBundle mainBundle] infoDictionary]; - for (NSString *key in dict) { - NSObject *value = [dict objectForKey:key]; - String ukey = String::utf8([key UTF8String]); - - // we need a NSObject to Variant conversor - - if ([value isKindOfClass:[NSString class]]) { - NSString *str = (NSString *)value; - String uval = String::utf8([str UTF8String]); - - ProjectSettings::get_singleton()->set("Info.plist/" + ukey, uval); - - } else if ([value isKindOfClass:[NSNumber class]]) { - NSNumber *n = (NSNumber *)value; - double dval = [n doubleValue]; - - ProjectSettings::get_singleton()->set("Info.plist/" + ukey, dval); - }; - // do stuff - } - - }; break; - - case 2: { - Main::start(); - ++frame_count; - - }; break; // no fallthrough - - default: { - if (OSIPhone::get_singleton()) { - // OSIPhone::get_singleton()->update_accelerometer(accel[0], accel[1], - // accel[2]); - if (motionInitialised) { - // Just using polling approach for now, we can set this up so it sends - // data to us in intervals, might be better. See Apple reference pages - // for more details: - // https://developer.apple.com/reference/coremotion/cmmotionmanager?language=objc - - // Apple splits our accelerometer date into a gravity and user movement - // component. We add them back together - CMAcceleration gravity = motionManager.deviceMotion.gravity; - CMAcceleration acceleration = - motionManager.deviceMotion.userAcceleration; - - ///@TODO We don't seem to be getting data here, is my device broken or - /// is this code incorrect? - CMMagneticField magnetic = - motionManager.deviceMotion.magneticField.field; - - ///@TODO we can access rotationRate as a CMRotationRate variable - ///(processed date) or CMGyroData (raw data), have to see what works - /// best - CMRotationRate rotation = motionManager.deviceMotion.rotationRate; - - // Adjust for screen orientation. - // [[UIDevice currentDevice] orientation] changes even if we've fixed - // our orientation which is not a good thing when you're trying to get - // your user to move the screen in all directions and want consistent - // output - - ///@TODO Using [[UIApplication sharedApplication] statusBarOrientation] - /// is a bit of a hack. Godot obviously knows the orientation so maybe - /// we - // can use that instead? (note that left and right seem swapped) - - switch ([[UIApplication sharedApplication] statusBarOrientation]) { - case UIDeviceOrientationLandscapeLeft: { - OSIPhone::get_singleton()->update_gravity(-gravity.y, gravity.x, - gravity.z); - OSIPhone::get_singleton()->update_accelerometer( - -(acceleration.y + gravity.y), (acceleration.x + gravity.x), - acceleration.z + gravity.z); - OSIPhone::get_singleton()->update_magnetometer( - -magnetic.y, magnetic.x, magnetic.z); - OSIPhone::get_singleton()->update_gyroscope(-rotation.y, rotation.x, - rotation.z); - }; break; - case UIDeviceOrientationLandscapeRight: { - OSIPhone::get_singleton()->update_gravity(gravity.y, -gravity.x, - gravity.z); - OSIPhone::get_singleton()->update_accelerometer( - (acceleration.y + gravity.y), -(acceleration.x + gravity.x), - acceleration.z + gravity.z); - OSIPhone::get_singleton()->update_magnetometer( - magnetic.y, -magnetic.x, magnetic.z); - OSIPhone::get_singleton()->update_gyroscope(rotation.y, -rotation.x, - rotation.z); - }; break; - case UIDeviceOrientationPortraitUpsideDown: { - OSIPhone::get_singleton()->update_gravity(-gravity.x, gravity.y, - gravity.z); - OSIPhone::get_singleton()->update_accelerometer( - -(acceleration.x + gravity.x), (acceleration.y + gravity.y), - acceleration.z + gravity.z); - OSIPhone::get_singleton()->update_magnetometer( - -magnetic.x, magnetic.y, magnetic.z); - OSIPhone::get_singleton()->update_gyroscope(-rotation.x, rotation.y, - rotation.z); - }; break; - default: { // assume portrait - OSIPhone::get_singleton()->update_gravity(gravity.x, gravity.y, - gravity.z); - OSIPhone::get_singleton()->update_accelerometer( - acceleration.x + gravity.x, acceleration.y + gravity.y, - acceleration.z + gravity.z); - OSIPhone::get_singleton()->update_magnetometer(magnetic.x, magnetic.y, - magnetic.z); - OSIPhone::get_singleton()->update_gyroscope(rotation.x, rotation.y, - rotation.z); - }; break; - }; - } - - bool quit_request = OSIPhone::get_singleton()->iterate(); - }; - - }; break; - }; -}; - -- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { - if (OS::get_singleton()->get_main_loop()) { - OS::get_singleton()->get_main_loop()->notification( - MainLoop::NOTIFICATION_OS_MEMORY_WARNING); - } -}; - - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - CGRect rect = [[UIScreen mainScreen] bounds]; + // TODO: might be required to make an early return, so app wouldn't crash because of timeout. + // TODO: logo screen is not displayed while shaders are compiling + // DummyViewController(Splash/LoadingViewController) -> setup -> GodotViewController - is_focus_out = false; - - [application setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone]; - // disable idle timer - // application.idleTimerDisabled = YES; + CGRect windowBounds = [[UIScreen mainScreen] bounds]; // Create a full-screen window - window = [[UIWindow alloc] initWithFrame:rect]; - - OS::VideoMode vm = _get_video_mode(); + self.window = [[[UIWindow alloc] initWithFrame:windowBounds] autorelease]; - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, - NSUserDomainMask, YES); + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; - int err = iphone_main(vm.width, vm.height, gargc, gargv, String::utf8([documentsDirectory UTF8String])); + int err = iphone_main(gargc, gargv, String::utf8([documentsDirectory UTF8String])); + if (err != 0) { // bail, things did not go very well for us, should probably output a message on screen with our error code... exit(0); - return FALSE; + return NO; }; -#if defined(OPENGL_ENABLED) - // WARNING: We must *always* create the GLView after we have constructed the - // OS with iphone_main. This allows the GLView to access project settings so - // it can properly initialize the OpenGL context - GLView *glView = [[GLView alloc] initWithFrame:rect]; - glView.delegate = self; - - view_controller = [[ViewController alloc] init]; - view_controller.view = glView; - - _set_keep_screen_on(bool(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true)) ? YES : NO); - glView.useCADisplayLink = - bool(GLOBAL_DEF("display.iOS/use_cadisplaylink", true)) ? YES : NO; - printf("cadisaplylink: %d", glView.useCADisplayLink); - glView.animationInterval = 1.0 / kRenderingFrequency; - [glView startAnimation]; -#endif - -#if defined(VULKAN_ENABLED) - view_controller = [[ViewController alloc] init]; -#endif + ViewController *viewController = [[ViewController alloc] init]; + viewController.godotView.useCADisplayLink = bool(GLOBAL_DEF("display.iOS/use_cadisplaylink", true)) ? YES : NO; + viewController.godotView.renderingInterval = 1.0 / kRenderingFrequency; - window.rootViewController = view_controller; + self.window.rootViewController = viewController; // Show the window - [window makeKeyAndVisible]; - - // Configure and start accelerometer - if (!motionInitialised) { - motionManager = [[CMMotionManager alloc] init]; - if (motionManager.deviceMotionAvailable) { - motionManager.deviceMotionUpdateInterval = 1.0 / 70.0; - [motionManager startDeviceMotionUpdatesUsingReferenceFrame: - CMAttitudeReferenceFrameXMagneticNorthZVertical]; - motionInitialised = YES; - }; - }; - - [self initGameControllers]; + [self.window makeKeyAndVisible]; [[NSNotificationCenter defaultCenter] addObserver:self @@ -674,40 +90,33 @@ static int frame_count = 0; name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]]; - // OSIPhone::screen_width = rect.size.width - rect.origin.x; - // OSIPhone::screen_height = rect.size.height - rect.origin.y; - - mainViewController = view_controller; + mainViewController = viewController; // prevent to stop music in another background app [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil]; - return TRUE; + return YES; }; - (void)onAudioInterruption:(NSNotification *)notification { if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) { if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) { NSLog(@"Audio interruption began"); - on_focus_out(view_controller, &is_focus_out); + OSIPhone::get_singleton()->on_focus_out(); } else if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded]]) { NSLog(@"Audio interruption ended"); - on_focus_in(view_controller, &is_focus_out); + OSIPhone::get_singleton()->on_focus_in(); } } }; -- (void)applicationWillTerminate:(UIApplication *)application { - [self deinitGameControllers]; - - if (motionInitialised) { - ///@TODO is this the right place to clean this up? - [motionManager stopDeviceMotionUpdates]; - [motionManager release]; - motionManager = nil; - motionInitialised = NO; - }; +- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_MEMORY_WARNING); + } +}; +- (void)applicationWillTerminate:(UIApplication *)application { iphone_finish(); }; @@ -722,15 +131,15 @@ static int frame_count = 0; // notification panel by swiping from the upper part of the screen. - (void)applicationWillResignActive:(UIApplication *)application { - on_focus_out(view_controller, &is_focus_out); + OSIPhone::get_singleton()->on_focus_out(); } - (void)applicationDidBecomeActive:(UIApplication *)application { - on_focus_in(view_controller, &is_focus_out); + OSIPhone::get_singleton()->on_focus_in(); } - (void)dealloc { - [window release]; + self.window = nil; [super dealloc]; } diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index c48eb7ff0e..f4ef40a0ba 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -31,7 +31,8 @@ def get_opts(): ("IPHONESDK", "Path to the iPhone SDK", ""), BoolVariable( "use_static_mvk", - "Link MoltenVK statically as Level-0 driver (better portability) or use Vulkan ICD loader (enables validation layers)", + "Link MoltenVK statically as Level-0 driver (better portability) or use Vulkan ICD loader (enables" + " validation layers)", False, ), BoolVariable("game_center", "Support for game center", True), @@ -120,18 +121,31 @@ def configure(env): CCFLAGS=( "-arch " + arch_flag - + " -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -isysroot $IPHONESDK -mios-simulator-version-min=10.0" + + " -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks" + " -fasm-blocks -isysroot $IPHONESDK -mios-simulator-version-min=13.0" ).split() ) elif env["arch"] == "arm": detect_darwin_sdk_path("iphone", env) env.Append( - CCFLAGS='-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=10.0 -MMD -MT dependencies'.split() + CCFLAGS=( + "-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing" + " -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits" + " -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb" + ' "-DIBOutlet=__attribute__((iboutlet))"' + ' "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))"' + ' "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=11.0 -MMD -MT dependencies'.split() + ) ) elif env["arch"] == "arm64": detect_darwin_sdk_path("iphone", env) env.Append( - CCFLAGS="-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies -miphoneos-version-min=10.0 -isysroot $IPHONESDK".split() + CCFLAGS=( + "-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing" + " -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits" + " -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies -miphoneos-version-min=11.0" + " -isysroot $IPHONESDK".split() + ) ) env.Append(CPPDEFINES=["NEED_LONG_INT"]) env.Append(CPPDEFINES=["LIBYUV_DISABLE_NEON"]) @@ -143,6 +157,9 @@ def configure(env): else: env.Append(CCFLAGS=["-fno-exceptions"]) + # Temp fix for ABS/MAX/MIN macros in iPhone SDK blocking compilation + env.Append(CCFLAGS=["-Wno-ambiguous-macro"]) + ## Link flags if env["arch"] == "x86" or env["arch"] == "x86_64": @@ -151,7 +168,7 @@ def configure(env): LINKFLAGS=[ "-arch", arch_flag, - "-mios-simulator-version-min=10.0", + "-mios-simulator-version-min=13.0", "-isysroot", "$IPHONESDK", "-Xlinker", @@ -162,9 +179,9 @@ def configure(env): ] ) elif env["arch"] == "arm": - env.Append(LINKFLAGS=["-arch", "armv7", "-Wl,-dead_strip", "-miphoneos-version-min=10.0"]) + env.Append(LINKFLAGS=["-arch", "armv7", "-Wl,-dead_strip", "-miphoneos-version-min=11.0"]) if env["arch"] == "arm64": - env.Append(LINKFLAGS=["-arch", "arm64", "-Wl,-dead_strip", "-miphoneos-version-min=10.0"]) + env.Append(LINKFLAGS=["-arch", "arm64", "-Wl,-dead_strip", "-miphoneos-version-min=11.0"]) env.Append( LINKFLAGS=[ @@ -228,8 +245,7 @@ def configure(env): env.Append(CPPDEFINES=["VULKAN_ENABLED"]) env.Append(LINKFLAGS=["-framework", "IOSurface"]) - if env["use_static_mvk"]: - env.Append(LINKFLAGS=["-framework", "MoltenVK"]) - env["builtin_vulkan"] = False - elif not env["builtin_vulkan"]: - env.Append(LIBS=["vulkan"]) + + # Use Static Vulkan for iOS. Dynamic Framework works fine too. + env.Append(LINKFLAGS=["-framework", "MoltenVK"]) + env["builtin_vulkan"] = False diff --git a/platform/iphone/display_layer.h b/platform/iphone/display_layer.h new file mode 100644 index 0000000000..bfde8f96a3 --- /dev/null +++ b/platform/iphone/display_layer.h @@ -0,0 +1,58 @@ +/*************************************************************************/ +/* display_layer.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import <OpenGLES/EAGLDrawable.h> +#import <QuartzCore/QuartzCore.h> + +@protocol DisplayLayer <NSObject> + +- (void)renderDisplayLayer; +- (void)initializeDisplayLayer; +- (void)layoutDisplayLayer; + +@end + +// An ugly workaround for iOS simulator +#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR +#if defined(__IPHONE_13_0) +API_AVAILABLE(ios(13.0)) +@interface GodotMetalLayer : CAMetalLayer <DisplayLayer> +#else +@interface GodotMetalLayer : CALayer <DisplayLayer> +#endif +#else +@interface GodotMetalLayer : CAMetalLayer <DisplayLayer> +#endif +@end + +API_DEPRECATED("OpenGLES is deprecated", ios(2.0, 12.0)) +@interface GodotOpenGLLayer : CAEAGLLayer <DisplayLayer> + +@end diff --git a/platform/iphone/display_layer.mm b/platform/iphone/display_layer.mm new file mode 100644 index 0000000000..5ec94fb471 --- /dev/null +++ b/platform/iphone/display_layer.mm @@ -0,0 +1,186 @@ +/*************************************************************************/ +/* display_layer.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import "display_layer.h" +#include "core/os/keyboard.h" +#include "core/project_settings.h" +#include "display_server_iphone.h" +#include "main/main.h" +#include "os_iphone.h" +#include "servers/audio_server.h" + +#import <AudioToolbox/AudioServices.h> +#import <GameController/GameController.h> +#import <OpenGLES/EAGL.h> +#import <OpenGLES/ES1/gl.h> +#import <OpenGLES/ES1/glext.h> +#import <QuartzCore/QuartzCore.h> +#import <UIKit/UIKit.h> + +@implementation GodotMetalLayer + +- (void)initializeDisplayLayer { +#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR + if (@available(iOS 13, *)) { + // Simulator supports Metal since iOS 13 + } else { + NSLog(@"iOS Simulator prior to iOS 13 does not support Metal rendering."); + } +#endif +} + +- (void)layoutDisplayLayer { +} + +- (void)renderDisplayLayer { +} + +@end + +@implementation GodotOpenGLLayer { + // The pixel dimensions of the backbuffer + GLint backingWidth; + GLint backingHeight; + + EAGLContext *context; + GLuint viewRenderbuffer, viewFramebuffer; + GLuint depthRenderbuffer; +} + +- (void)initializeDisplayLayer { + // Get our backing layer + + // Configure it so that it is opaque, does not retain the contents of the backbuffer when displayed, and uses RGBA8888 color. + self.opaque = YES; + self.drawableProperties = [NSDictionary + dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:FALSE], + kEAGLDrawablePropertyRetainedBacking, + kEAGLColorFormatRGBA8, + kEAGLDrawablePropertyColorFormat, + nil]; + + // FIXME: Add Vulkan support via MoltenVK. Add fallback code back? + + // Create GL ES 2 context + if (GLOBAL_GET("rendering/quality/driver/driver_name") == "GLES2") { + context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + NSLog(@"Setting up an OpenGL ES 2.0 context."); + if (!context) { + NSLog(@"Failed to create OpenGL ES 2.0 context!"); + return; + } + } + + if (![EAGLContext setCurrentContext:context]) { + NSLog(@"Failed to set EAGLContext!"); + return; + } + if (![self createFramebuffer]) { + NSLog(@"Failed to create frame buffer!"); + return; + } +} + +- (void)layoutDisplayLayer { + [EAGLContext setCurrentContext:context]; + [self destroyFramebuffer]; + [self createFramebuffer]; +} + +- (void)renderDisplayLayer { + [EAGLContext setCurrentContext:context]; +} + +- (void)dealloc { + if ([EAGLContext currentContext] == context) { + [EAGLContext setCurrentContext:nil]; + } + + if (context) { + [context release]; + context = nil; + } + + [super dealloc]; +} + +- (BOOL)createFramebuffer { + glGenFramebuffersOES(1, &viewFramebuffer); + glGenRenderbuffersOES(1, &viewRenderbuffer); + + glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); + // This call associates the storage for the current render buffer with the EAGLDrawable (our CAself) + // allowing us to draw into a buffer that will later be rendered to screen wherever the layer is (which corresponds with our view). + [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self]; + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer); + + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); + + // For this sample, we also need a depth buffer, so we'll create and attach one via another renderbuffer. + glGenRenderbuffersOES(1, &depthRenderbuffer); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); + glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight); + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer); + + if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { + NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); + return NO; + } + + // if (OS::get_singleton()) { + // OS::VideoMode vm; + // vm.fullscreen = true; + // vm.width = backingWidth; + // vm.height = backingHeight; + // vm.resizable = false; + // OS::get_singleton()->set_video_mode(vm); + // OSIPhone::get_singleton()->set_base_framebuffer(viewFramebuffer); + // }; + // gl_view_base_fb = viewFramebuffer; + + return YES; +} + +// Clean up any buffers we have allocated. +- (void)destroyFramebuffer { + glDeleteFramebuffersOES(1, &viewFramebuffer); + viewFramebuffer = 0; + glDeleteRenderbuffersOES(1, &viewRenderbuffer); + viewRenderbuffer = 0; + + if (depthRenderbuffer) { + glDeleteRenderbuffersOES(1, &depthRenderbuffer); + depthRenderbuffer = 0; + } +} + +@end diff --git a/platform/iphone/display_server_iphone.h b/platform/iphone/display_server_iphone.h new file mode 100644 index 0000000000..229b1e80db --- /dev/null +++ b/platform/iphone/display_server_iphone.h @@ -0,0 +1,202 @@ +/*************************************************************************/ +/* display_server_iphone.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef display_server_iphone_h +#define display_server_iphone_h + +#include "core/input/input.h" +#include "servers/display_server.h" + +#if defined(VULKAN_ENABLED) +#include "drivers/vulkan/rendering_device_vulkan.h" +#include "servers/rendering/rasterizer_rd/rasterizer_rd.h" + +#include "vulkan_context_iphone.h" + +#import <QuartzCore/CAMetalLayer.h> +#include <vulkan/vulkan_metal.h> +#endif + +class DisplayServerIPhone : public DisplayServer { + GDCLASS(DisplayServerIPhone, DisplayServer) + + _THREAD_SAFE_CLASS_ + +#if defined(VULKAN_ENABLED) + VulkanContextIPhone *context_vulkan; + RenderingDeviceVulkan *rendering_device_vulkan; +#endif + + DisplayServer::ScreenOrientation screen_orientation; + + ObjectID window_attached_instance_id; + + Callable window_event_callback; + Callable window_resize_callback; + Callable input_event_callback; + Callable input_text_callback; + + int virtual_keyboard_height = 0; + + void perform_event(const Ref<InputEvent> &p_event); + + DisplayServerIPhone(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + ~DisplayServerIPhone(); + +public: + String rendering_driver; + + static DisplayServerIPhone *get_singleton(); + + static void register_iphone_driver(); + static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + static Vector<String> get_rendering_drivers_func(); + + // MARK: - Events + + virtual void process_events() override; + + virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + + static void _dispatch_input_events(const Ref<InputEvent> &p_event); + void send_input_event(const Ref<InputEvent> &p_event) const; + void send_input_text(const String &p_text) const; + void send_window_event(DisplayServer::WindowEvent p_event) const; + void _window_callback(const Callable &p_callable, const Variant &p_arg) const; + + // MARK: - Input + + // MARK: Touches + + void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick); + void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y); + void touches_cancelled(int p_idx); + + // MARK: Keyboard + + void key(uint32_t p_key, bool p_pressed); + + // MARK: Motion + + void update_gravity(float p_x, float p_y, float p_z); + void update_accelerometer(float p_x, float p_y, float p_z); + void update_magnetometer(float p_x, float p_y, float p_z); + void update_gyroscope(float p_x, float p_y, float p_z); + + // MARK: - + + virtual bool has_feature(Feature p_feature) const override; + virtual String get_name() const override; + + virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override; + + virtual int get_screen_count() const override; + virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + + virtual Vector<DisplayServer::WindowID> get_window_list() const override; + + virtual WindowID + get_window_at_screen_position(const Point2i &p_position) const override; + + virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override; + virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override; + + virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) override; + + virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) override; + + virtual void window_set_transient(WindowID p_window, WindowID p_parent) override; + + virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; + virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; + virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; + virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) override; + virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) override; + virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override; + + virtual float screen_get_max_scale() const override; + + virtual void screen_set_orientation(DisplayServer::ScreenOrientation p_orientation, int p_screen) override; + virtual DisplayServer::ScreenOrientation screen_get_orientation(int p_screen) const override; + + virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual bool can_any_window_draw() const override; + + virtual bool screen_is_touchscreen(int p_screen) const override; + + virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) override; + virtual void virtual_keyboard_hide() override; + + void virtual_keyboard_set_height(int height); + virtual int virtual_keyboard_get_height() const override; + + virtual void clipboard_set(const String &p_text) override; + virtual String clipboard_get() const override; + + virtual void screen_set_keep_on(bool p_enable) override; + virtual bool screen_is_kept_on() const override; + + virtual Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track, int p_screen = SCREEN_OF_MAIN_WINDOW) override; + virtual bool native_video_is_playing() const override; + virtual void native_video_pause() override; + virtual void native_video_unpause() override; + virtual void native_video_stop() override; + + void resize_window(CGSize size); +}; + +#endif /* display_server_iphone_h */ diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm new file mode 100644 index 0000000000..1721da3db6 --- /dev/null +++ b/platform/iphone/display_server_iphone.mm @@ -0,0 +1,766 @@ +/*************************************************************************/ +/* display_server_iphone.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "display_server_iphone.h" +#import "app_delegate.h" +#include "core/io/file_access_pack.h" +#include "core/project_settings.h" +#import "godot_view.h" +#include "ios.h" +#include "os_iphone.h" +#import "view_controller.h" + +#import <Foundation/Foundation.h> +#import <sys/utsname.h> + +static const float kDisplayServerIPhoneAcceleration = 1; +static NSDictionary *iOSModelToDPI = @{ + @[ + @"iPad1,1", + @"iPad2,1", + @"iPad2,2", + @"iPad2,3", + @"iPad2,4", + ] : @132, + @[ + @"iPhone1,1", + @"iPhone1,2", + @"iPhone2,1", + @"iPad2,5", + @"iPad2,6", + @"iPad2,7", + @"iPod1,1", + @"iPod2,1", + @"iPod3,1", + ] : @163, + @[ + @"iPad3,1", + @"iPad3,2", + @"iPad3,3", + @"iPad3,4", + @"iPad3,5", + @"iPad3,6", + @"iPad4,1", + @"iPad4,2", + @"iPad4,3", + @"iPad5,3", + @"iPad5,4", + @"iPad6,3", + @"iPad6,4", + @"iPad6,7", + @"iPad6,8", + @"iPad6,11", + @"iPad6,12", + @"iPad7,1", + @"iPad7,2", + @"iPad7,3", + @"iPad7,4", + @"iPad7,5", + @"iPad7,6", + @"iPad7,11", + @"iPad7,12", + @"iPad8,1", + @"iPad8,2", + @"iPad8,3", + @"iPad8,4", + @"iPad8,5", + @"iPad8,6", + @"iPad8,7", + @"iPad8,8", + @"iPad8,9", + @"iPad8,10", + @"iPad8,11", + @"iPad8,12", + @"iPad11,3", + @"iPad11,4", + ] : @264, + @[ + @"iPhone3,1", + @"iPhone3,2", + @"iPhone3,3", + @"iPhone4,1", + @"iPhone5,1", + @"iPhone5,2", + @"iPhone5,3", + @"iPhone5,4", + @"iPhone6,1", + @"iPhone6,2", + @"iPhone7,2", + @"iPhone8,1", + @"iPhone8,4", + @"iPhone9,1", + @"iPhone9,3", + @"iPhone10,1", + @"iPhone10,4", + @"iPhone11,8", + @"iPhone12,1", + @"iPhone12,8", + @"iPad4,4", + @"iPad4,5", + @"iPad4,6", + @"iPad4,7", + @"iPad4,8", + @"iPad4,9", + @"iPad5,1", + @"iPad5,2", + @"iPad11,1", + @"iPad11,2", + @"iPod4,1", + @"iPod5,1", + @"iPod7,1", + @"iPod9,1", + ] : @326, + @[ + @"iPhone7,1", + @"iPhone8,2", + @"iPhone9,2", + @"iPhone9,4", + @"iPhone10,2", + @"iPhone10,5", + ] : @401, + @[ + @"iPhone10,3", + @"iPhone10,6", + @"iPhone11,2", + @"iPhone11,4", + @"iPhone11,6", + @"iPhone12,3", + @"iPhone12,5", + ] : @458, +}; + +DisplayServerIPhone *DisplayServerIPhone::get_singleton() { + return (DisplayServerIPhone *)DisplayServer::get_singleton(); +} + +DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + rendering_driver = p_rendering_driver; + +#if defined(OPENGL_ENABLED) + // FIXME: Add support for both GLES2 and Vulkan when GLES2 is implemented + // again, + + if (rendering_driver == "opengl_es") { + bool gl_initialization_error = false; + + // FIXME: Add Vulkan support via MoltenVK. Add fallback code back? + + if (RasterizerGLES2::is_viable() == OK) { + RasterizerGLES2::register_config(); + RasterizerGLES2::make_current(); + } else { + gl_initialization_error = true; + } + + if (gl_initialization_error) { + OS::get_singleton()->alert("Your device does not support any of the supported OpenGL versions.", "Unable to initialize video driver"); + // return ERR_UNAVAILABLE; + } + + // rendering_server = memnew(RenderingServerRaster); + // // FIXME: Reimplement threaded rendering + // if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) { + // rendering_server = memnew(RenderingServerWrapMT(rendering_server, + // false)); + // } + // rendering_server->init(); + // rendering_server->cursor_set_visible(false, 0); + + // reset this to what it should be, it will have been set to 0 after + // rendering_server->init() is called + // RasterizerStorageGLES2::system_fbo = gl_view_base_fb; + } +#endif + +#if defined(VULKAN_ENABLED) + rendering_driver = "vulkan"; + + context_vulkan = nullptr; + rendering_device_vulkan = nullptr; + + if (rendering_driver == "vulkan") { + context_vulkan = memnew(VulkanContextIPhone); + if (context_vulkan->initialize() != OK) { + memdelete(context_vulkan); + context_vulkan = nullptr; + ERR_FAIL_MSG("Failed to initialize Vulkan context"); + } + + CALayer *layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"vulkan"]; + + if (!layer) { + ERR_FAIL_MSG("Failed to create iOS rendering layer."); + } + + Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale(); + if (context_vulkan->window_create(MAIN_WINDOW_ID, layer, size.width, size.height) != OK) { + memdelete(context_vulkan); + context_vulkan = nullptr; + ERR_FAIL_MSG("Failed to create Vulkan window."); + } + + rendering_device_vulkan = memnew(RenderingDeviceVulkan); + rendering_device_vulkan->initialize(context_vulkan); + + RasterizerRD::make_current(); + } +#endif + + bool keep_screen_on = bool(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true)); + screen_set_keep_on(keep_screen_on); + + Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); + + r_error = OK; +} + +DisplayServerIPhone::~DisplayServerIPhone() { +#if defined(VULKAN_ENABLED) + if (rendering_driver == "vulkan") { + if (rendering_device_vulkan) { + rendering_device_vulkan->finalize(); + memdelete(rendering_device_vulkan); + rendering_device_vulkan = NULL; + } + + if (context_vulkan) { + context_vulkan->window_destroy(MAIN_WINDOW_ID); + memdelete(context_vulkan); + context_vulkan = NULL; + } + } +#endif +} + +DisplayServer *DisplayServerIPhone::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + return memnew(DisplayServerIPhone(p_rendering_driver, p_mode, p_flags, p_resolution, r_error)); +} + +Vector<String> DisplayServerIPhone::get_rendering_drivers_func() { + Vector<String> drivers; + +#if defined(VULKAN_ENABLED) + drivers.push_back("vulkan"); +#endif +#if defined(OPENGL_ENABLED) + drivers.push_back("opengl_es"); +#endif + + return drivers; +} + +void DisplayServerIPhone::register_iphone_driver() { + register_create_function("iphone", create_func, get_rendering_drivers_func); +} + +// MARK: Events + +void DisplayServerIPhone::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { + window_resize_callback = p_callable; +} + +void DisplayServerIPhone::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { + window_event_callback = p_callable; +} +void DisplayServerIPhone::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { + input_event_callback = p_callable; +} + +void DisplayServerIPhone::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { + input_text_callback = p_callable; +} + +void DisplayServerIPhone::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { + // Probably not supported for iOS +} + +void DisplayServerIPhone::process_events() { +} + +void DisplayServerIPhone::_dispatch_input_events(const Ref<InputEvent> &p_event) { + DisplayServerIPhone::get_singleton()->send_input_event(p_event); +} + +void DisplayServerIPhone::send_input_event(const Ref<InputEvent> &p_event) const { + _window_callback(input_event_callback, p_event); +} + +void DisplayServerIPhone::send_input_text(const String &p_text) const { + _window_callback(input_text_callback, p_text); +} + +void DisplayServerIPhone::send_window_event(DisplayServer::WindowEvent p_event) const { + _window_callback(window_event_callback, int(p_event)); +} + +void DisplayServerIPhone::_window_callback(const Callable &p_callable, const Variant &p_arg) const { + if (!p_callable.is_null()) { + const Variant *argp = &p_arg; + Variant ret; + Callable::CallError ce; + p_callable.call((const Variant **)&argp, 1, ret, ce); + } +} + +// MARK: - Input + +// MARK: Touches + +void DisplayServerIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick) { + if (!GLOBAL_DEF("debug/disable_touch", false)) { + Ref<InputEventScreenTouch> ev; + ev.instance(); + + ev->set_index(p_idx); + ev->set_pressed(p_pressed); + ev->set_position(Vector2(p_x, p_y)); + perform_event(ev); + } +}; + +void DisplayServerIPhone::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) { + if (!GLOBAL_DEF("debug/disable_touch", false)) { + Ref<InputEventScreenDrag> ev; + ev.instance(); + ev->set_index(p_idx); + ev->set_position(Vector2(p_x, p_y)); + ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y)); + perform_event(ev); + }; +}; + +void DisplayServerIPhone::perform_event(const Ref<InputEvent> &p_event) { + Input::get_singleton()->parse_input_event(p_event); +}; + +void DisplayServerIPhone::touches_cancelled(int p_idx) { + touch_press(p_idx, -1, -1, false, false); +}; + +// MARK: Keyboard + +void DisplayServerIPhone::key(uint32_t p_key, bool p_pressed) { + Ref<InputEventKey> ev; + ev.instance(); + ev->set_echo(false); + ev->set_pressed(p_pressed); + ev->set_keycode(p_key); + ev->set_physical_keycode(p_key); + ev->set_unicode(p_key); + perform_event(ev); +}; + +// MARK: Motion + +void DisplayServerIPhone::update_gravity(float p_x, float p_y, float p_z) { + Input::get_singleton()->set_gravity(Vector3(p_x, p_y, p_z)); +}; + +void DisplayServerIPhone::update_accelerometer(float p_x, float p_y, + float p_z) { + // Found out the Z should not be negated! Pass as is! + Vector3 v_accelerometer = Vector3( + p_x / kDisplayServerIPhoneAcceleration, + p_y / kDisplayServerIPhoneAcceleration, + p_z / kDisplayServerIPhoneAcceleration); + + Input::get_singleton()->set_accelerometer(v_accelerometer); + + /* + if (p_x != last_accel.x) { + //printf("updating accel x %f\n", p_x); + InputEvent ev; + ev.type = InputEvent::JOYPAD_MOTION; + ev.device = 0; + ev.joy_motion.axis = JOY_ANALOG_0; + ev.joy_motion.axis_value = (p_x / (float)ACCEL_RANGE); + last_accel.x = p_x; + queue_event(ev); + }; + if (p_y != last_accel.y) { + //printf("updating accel y %f\n", p_y); + InputEvent ev; + ev.type = InputEvent::JOYPAD_MOTION; + ev.device = 0; + ev.joy_motion.axis = JOY_ANALOG_1; + ev.joy_motion.axis_value = (p_y / (float)ACCEL_RANGE); + last_accel.y = p_y; + queue_event(ev); + }; + if (p_z != last_accel.z) { + //printf("updating accel z %f\n", p_z); + InputEvent ev; + ev.type = InputEvent::JOYPAD_MOTION; + ev.device = 0; + ev.joy_motion.axis = JOY_ANALOG_2; + ev.joy_motion.axis_value = ( (1.0 - p_z) / (float)ACCEL_RANGE); + last_accel.z = p_z; + queue_event(ev); + }; + */ +}; + +void DisplayServerIPhone::update_magnetometer(float p_x, float p_y, float p_z) { + Input::get_singleton()->set_magnetometer(Vector3(p_x, p_y, p_z)); +}; + +void DisplayServerIPhone::update_gyroscope(float p_x, float p_y, float p_z) { + Input::get_singleton()->set_gyroscope(Vector3(p_x, p_y, p_z)); +}; + +// MARK: - + +bool DisplayServerIPhone::has_feature(Feature p_feature) const { + switch (p_feature) { + // case FEATURE_CONSOLE_WINDOW: + // case FEATURE_CURSOR_SHAPE: + // case FEATURE_CUSTOM_CURSOR_SHAPE: + // case FEATURE_GLOBAL_MENU: + // case FEATURE_HIDPI: + // case FEATURE_ICON: + // case FEATURE_IME: + // case FEATURE_MOUSE: + // case FEATURE_MOUSE_WARP: + // case FEATURE_NATIVE_DIALOG: + // case FEATURE_NATIVE_ICON: + // case FEATURE_NATIVE_VIDEO: + // case FEATURE_WINDOW_TRANSPARENCY: + case FEATURE_CLIPBOARD: + case FEATURE_KEEP_SCREEN_ON: + case FEATURE_ORIENTATION: + case FEATURE_TOUCHSCREEN: + case FEATURE_VIRTUAL_KEYBOARD: + return true; + default: + return false; + } +} + +String DisplayServerIPhone::get_name() const { + return "iPhone"; +} + +void DisplayServerIPhone::alert(const String &p_alert, const String &p_title) { + const CharString utf8_alert = p_alert.utf8(); + const CharString utf8_title = p_title.utf8(); + iOS::alert(utf8_alert.get_data(), utf8_title.get_data()); +} + +int DisplayServerIPhone::get_screen_count() const { + return 1; +} + +Point2i DisplayServerIPhone::screen_get_position(int p_screen) const { + return Size2i(); +} + +Size2i DisplayServerIPhone::screen_get_size(int p_screen) const { + CALayer *layer = AppDelegate.viewController.godotView.renderingLayer; + + if (!layer) { + return Size2i(); + } + + return Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_scale(p_screen); +} + +Rect2i DisplayServerIPhone::screen_get_usable_rect(int p_screen) const { + if (@available(iOS 11, *)) { + UIEdgeInsets insets = UIEdgeInsetsZero; + UIView *view = AppDelegate.viewController.godotView; + + if ([view respondsToSelector:@selector(safeAreaInsets)]) { + insets = [view safeAreaInsets]; + } + + float scale = screen_get_scale(p_screen); + Size2i insets_position = Size2i(insets.left, insets.top) * scale; + Size2i insets_size = Size2i(insets.left + insets.right, insets.top + insets.bottom) * scale; + + return Rect2i(screen_get_position(p_screen) + insets_position, screen_get_size(p_screen) - insets_size); + } else { + return Rect2i(screen_get_position(p_screen), screen_get_size(p_screen)); + } +} + +int DisplayServerIPhone::screen_get_dpi(int p_screen) const { + struct utsname systemInfo; + uname(&systemInfo); + + NSString *string = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; + + for (NSArray *keyArray in iOSModelToDPI) { + if ([keyArray containsObject:string]) { + NSNumber *value = iOSModelToDPI[keyArray]; + return [value intValue]; + } + } + + return 163; +} + +float DisplayServerIPhone::screen_get_scale(int p_screen) const { + return [UIScreen mainScreen].nativeScale; +} + +Vector<DisplayServer::WindowID> DisplayServerIPhone::get_window_list() const { + Vector<DisplayServer::WindowID> list; + list.push_back(MAIN_WINDOW_ID); + return list; +} + +DisplayServer::WindowID DisplayServerIPhone::get_window_at_screen_position(const Point2i &p_position) const { + return MAIN_WINDOW_ID; +} + +void DisplayServerIPhone::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { + window_attached_instance_id = p_instance; +} + +ObjectID DisplayServerIPhone::window_get_attached_instance_id(WindowID p_window) const { + return window_attached_instance_id; +} + +void DisplayServerIPhone::window_set_title(const String &p_title, WindowID p_window) { + // Probably not supported for iOS +} + +int DisplayServerIPhone::window_get_current_screen(WindowID p_window) const { + return SCREEN_OF_MAIN_WINDOW; +} + +void DisplayServerIPhone::window_set_current_screen(int p_screen, WindowID p_window) { + // Probably not supported for iOS +} + +Point2i DisplayServerIPhone::window_get_position(WindowID p_window) const { + return Point2i(); +} + +void DisplayServerIPhone::window_set_position(const Point2i &p_position, WindowID p_window) { + // Probably not supported for single window iOS app +} + +void DisplayServerIPhone::window_set_transient(WindowID p_window, WindowID p_parent) { + // Probably not supported for iOS +} + +void DisplayServerIPhone::window_set_max_size(const Size2i p_size, WindowID p_window) { + // Probably not supported for iOS +} + +Size2i DisplayServerIPhone::window_get_max_size(WindowID p_window) const { + return Size2i(); +} + +void DisplayServerIPhone::window_set_min_size(const Size2i p_size, WindowID p_window) { + // Probably not supported for iOS +} + +Size2i DisplayServerIPhone::window_get_min_size(WindowID p_window) const { + return Size2i(); +} + +void DisplayServerIPhone::window_set_size(const Size2i p_size, WindowID p_window) { + // Probably not supported for iOS +} + +Size2i DisplayServerIPhone::window_get_size(WindowID p_window) const { + CGRect screenBounds = [UIScreen mainScreen].bounds; + return Size2i(screenBounds.size.width, screenBounds.size.height) * screen_get_max_scale(); +} + +Size2i DisplayServerIPhone::window_get_real_size(WindowID p_window) const { + return window_get_size(p_window); +} + +void DisplayServerIPhone::window_set_mode(WindowMode p_mode, WindowID p_window) { + // Probably not supported for iOS +} + +DisplayServer::WindowMode DisplayServerIPhone::window_get_mode(WindowID p_window) const { + return WindowMode::WINDOW_MODE_FULLSCREEN; +} + +bool DisplayServerIPhone::window_is_maximize_allowed(WindowID p_window) const { + return false; +} + +void DisplayServerIPhone::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { + // Probably not supported for iOS +} + +bool DisplayServerIPhone::window_get_flag(WindowFlags p_flag, WindowID p_window) const { + return false; +} + +void DisplayServerIPhone::window_request_attention(WindowID p_window) { + // Probably not supported for iOS +} + +void DisplayServerIPhone::window_move_to_foreground(WindowID p_window) { + // Probably not supported for iOS +} + +float DisplayServerIPhone::screen_get_max_scale() const { + return screen_get_scale(SCREEN_OF_MAIN_WINDOW); +}; + +void DisplayServerIPhone::screen_set_orientation(DisplayServer::ScreenOrientation p_orientation, int p_screen) { + screen_orientation = p_orientation; +} + +DisplayServer::ScreenOrientation DisplayServerIPhone::screen_get_orientation(int p_screen) const { + return screen_orientation; +} + +bool DisplayServerIPhone::window_can_draw(WindowID p_window) const { + return true; +} + +bool DisplayServerIPhone::can_any_window_draw() const { + return true; +} + +bool DisplayServerIPhone::screen_is_touchscreen(int p_screen) const { + return true; +} + +void DisplayServerIPhone::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) { + [AppDelegate.viewController.godotView becomeFirstResponderWithString:p_existing_text]; +} + +void DisplayServerIPhone::virtual_keyboard_hide() { + [AppDelegate.viewController.godotView resignFirstResponder]; +} + +void DisplayServerIPhone::virtual_keyboard_set_height(int height) { + virtual_keyboard_height = height * screen_get_max_scale(); +} + +int DisplayServerIPhone::virtual_keyboard_get_height() const { + return virtual_keyboard_height; +} + +void DisplayServerIPhone::clipboard_set(const String &p_text) { + [UIPasteboard generalPasteboard].string = [NSString stringWithUTF8String:p_text.utf8()]; +} + +String DisplayServerIPhone::clipboard_get() const { + NSString *text = [UIPasteboard generalPasteboard].string; + + return String::utf8([text UTF8String]); +} + +void DisplayServerIPhone::screen_set_keep_on(bool p_enable) { + [UIApplication sharedApplication].idleTimerDisabled = p_enable; +} + +bool DisplayServerIPhone::screen_is_kept_on() const { + return [UIApplication sharedApplication].idleTimerDisabled; +} + +Error DisplayServerIPhone::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track, int p_screen) { + FileAccess *f = FileAccess::open(p_path, FileAccess::READ); + bool exists = f && f->is_open(); + + String user_data_dir = OSIPhone::get_singleton()->get_user_data_dir(); + + if (!exists) { + return FAILED; + } + + String tempFile = OSIPhone::get_singleton()->get_user_data_dir(); + + if (p_path.begins_with("res://")) { + if (PackedData::get_singleton()->has_path(p_path)) { + printf("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:/", ProjectSettings::get_singleton()->get_resource_path()); + } + } else if (p_path.begins_with("user://")) { + p_path = p_path.replace("user:/", user_data_dir); + } + + memdelete(f); + + printf("Playing video: %S\n", p_path.c_str()); + + String file_path = ProjectSettings::get_singleton()->globalize_path(p_path); + + NSString *filePath = [[[NSString alloc] initWithUTF8String:file_path.utf8().get_data()] autorelease]; + NSString *audioTrack = [NSString stringWithUTF8String:p_audio_track.utf8()]; + NSString *subtitleTrack = [NSString stringWithUTF8String:p_subtitle_track.utf8()]; + + if (![AppDelegate.viewController playVideoAtPath:filePath + volume:p_volume + audio:audioTrack + subtitle:subtitleTrack]) { + return OK; + } + + return FAILED; +} + +bool DisplayServerIPhone::native_video_is_playing() const { + return [AppDelegate.viewController isVideoPlaying]; +} + +void DisplayServerIPhone::native_video_pause() { + if (native_video_is_playing()) { + [AppDelegate.viewController pauseVideo]; + } +} + +void DisplayServerIPhone::native_video_unpause() { + [AppDelegate.viewController unpauseVideo]; +}; + +void DisplayServerIPhone::native_video_stop() { + if (native_video_is_playing()) { + [AppDelegate.viewController stopVideo]; + } +} + +void DisplayServerIPhone::resize_window(CGSize viewSize) { + Size2i size = Size2i(viewSize.width, viewSize.height) * screen_get_max_scale(); + +#if defined(VULKAN_ENABLED) + if (rendering_driver == "vulkan") { + if (context_vulkan) { + context_vulkan->window_resize(MAIN_WINDOW_ID, size.x, size.y); + } + } +#endif + + Variant resize_rect = Rect2i(Point2i(), size); + _window_callback(window_resize_callback, resize_rect); +} diff --git a/platform/iphone/game_center.h b/platform/iphone/game_center.h index 0d3ef5b696..1e9a68fe48 100644 --- a/platform/iphone/game_center.h +++ b/platform/iphone/game_center.h @@ -51,12 +51,12 @@ public: void connect(); bool is_authenticated(); - Error post_score(Variant p_score); - Error award_achievement(Variant p_params); + Error post_score(Dictionary p_score); + Error award_achievement(Dictionary p_params); void reset_achievements(); void request_achievements(); void request_achievement_descriptions(); - Error show_game_center(Variant p_params); + Error show_game_center(Dictionary p_params); Error request_identity_verification_signature(); void game_center_closed(); diff --git a/platform/iphone/game_center.mm b/platform/iphone/game_center.mm index 8d470da1a8..4481775c32 100644 --- a/platform/iphone/game_center.mm +++ b/platform/iphone/game_center.mm @@ -47,13 +47,15 @@ extern "C" { #import "app_delegate.h" }; +#import "view_controller.h" + GameCenter *GameCenter::instance = NULL; void GameCenter::_bind_methods() { ClassDB::bind_method(D_METHOD("is_authenticated"), &GameCenter::is_authenticated); ClassDB::bind_method(D_METHOD("post_score"), &GameCenter::post_score); - ClassDB::bind_method(D_METHOD("award_achievement"), &GameCenter::award_achievement); + ClassDB::bind_method(D_METHOD("award_achievement", "achievement"), &GameCenter::award_achievement); ClassDB::bind_method(D_METHOD("reset_achievements"), &GameCenter::reset_achievements); ClassDB::bind_method(D_METHOD("request_achievements"), &GameCenter::request_achievements); ClassDB::bind_method(D_METHOD("request_achievement_descriptions"), &GameCenter::request_achievement_descriptions); @@ -105,7 +107,14 @@ void GameCenter::connect() { ret["type"] = "authentication"; if (player.isAuthenticated) { ret["result"] = "ok"; - ret["player_id"] = [player.playerID UTF8String]; + if (@available(iOS 13, *)) { + ret["player_id"] = [player.teamPlayerID UTF8String]; +#if !defined(TARGET_OS_SIMULATOR) || !TARGET_OS_SIMULATOR + } else { + ret["player_id"] = [player.playerID UTF8String]; +#endif + } + GameCenter::get_singleton()->authenticated = true; } else { ret["result"] = "error"; @@ -123,11 +132,10 @@ bool GameCenter::is_authenticated() { return authenticated; }; -Error GameCenter::post_score(Variant p_score) { - Dictionary params = p_score; - ERR_FAIL_COND_V(!params.has("score") || !params.has("category"), ERR_INVALID_PARAMETER); - float score = params["score"]; - String category = params["category"]; +Error GameCenter::post_score(Dictionary p_score) { + ERR_FAIL_COND_V(!p_score.has("score") || !p_score.has("category"), ERR_INVALID_PARAMETER); + float score = p_score["score"]; + String category = p_score["category"]; NSString *cat_str = [[[NSString alloc] initWithUTF8String:category.utf8().get_data()] autorelease]; GKScore *reporter = [[[GKScore alloc] initWithLeaderboardIdentifier:cat_str] autorelease]; @@ -153,11 +161,10 @@ Error GameCenter::post_score(Variant p_score) { return OK; }; -Error GameCenter::award_achievement(Variant p_params) { - Dictionary params = p_params; - ERR_FAIL_COND_V(!params.has("name") || !params.has("progress"), ERR_INVALID_PARAMETER); - String name = params["name"]; - float progress = params["progress"]; +Error GameCenter::award_achievement(Dictionary p_params) { + ERR_FAIL_COND_V(!p_params.has("name") || !p_params.has("progress"), ERR_INVALID_PARAMETER); + String name = p_params["name"]; + float progress = p_params["progress"]; NSString *name_str = [[[NSString alloc] initWithUTF8String:name.utf8().get_data()] autorelease]; GKAchievement *achievement = [[[GKAchievement alloc] initWithIdentifier:name_str] autorelease]; @@ -167,8 +174,8 @@ Error GameCenter::award_achievement(Variant p_params) { achievement.percentComplete = progress; achievement.showsCompletionBanner = NO; - if (params.has("show_completion_banner")) { - achievement.showsCompletionBanner = params["show_completion_banner"] ? YES : NO; + if (p_params.has("show_completion_banner")) { + achievement.showsCompletionBanner = p_params["show_completion_banner"] ? YES : NO; } [GKAchievement reportAchievements:@[ achievement ] @@ -202,7 +209,7 @@ void GameCenter::request_achievement_descriptions() { Array hidden; Array replayable; - for (int i = 0; i < [descriptions count]; i++) { + for (NSUInteger i = 0; i < [descriptions count]; i++) { GKAchievementDescription *description = [descriptions objectAtIndex:i]; const char *str = [description.identifier UTF8String]; @@ -250,7 +257,7 @@ void GameCenter::request_achievements() { PackedStringArray names; PackedFloat32Array percentages; - for (int i = 0; i < [achievements count]; i++) { + for (NSUInteger i = 0; i < [achievements count]; i++) { GKAchievement *achievement = [achievements objectAtIndex:i]; const char *str = [achievement.identifier UTF8String]; names.push_back(String::utf8(str != NULL ? str : "")); @@ -285,14 +292,12 @@ void GameCenter::reset_achievements() { }]; }; -Error GameCenter::show_game_center(Variant p_params) { +Error GameCenter::show_game_center(Dictionary p_params) { ERR_FAIL_COND_V(!NSProtocolFromString(@"GKGameCenterControllerDelegate"), FAILED); - Dictionary params = p_params; - GKGameCenterViewControllerState view_state = GKGameCenterViewControllerStateDefault; - if (params.has("view")) { - String view_name = params["view"]; + if (p_params.has("view")) { + String view_name = p_params["view"]; if (view_name == "default") { view_state = GKGameCenterViewControllerStateDefault; } else if (view_name == "leaderboards") { @@ -306,7 +311,7 @@ Error GameCenter::show_game_center(Variant p_params) { } } - GKGameCenterViewController *controller = [[GKGameCenterViewController alloc] init]; + GKGameCenterViewController *controller = [[[GKGameCenterViewController alloc] init] autorelease]; ERR_FAIL_COND_V(!controller, FAILED); ViewController *root_controller = (ViewController *)((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController; @@ -316,8 +321,8 @@ Error GameCenter::show_game_center(Variant p_params) { controller.viewState = view_state; if (view_state == GKGameCenterViewControllerStateLeaderboards) { controller.leaderboardIdentifier = nil; - if (params.has("leaderboard_name")) { - String name = params["leaderboard_name"]; + if (p_params.has("leaderboard_name")) { + String name = p_params["leaderboard_name"]; NSString *name_str = [[[NSString alloc] initWithUTF8String:name.utf8().get_data()] autorelease]; controller.leaderboardIdentifier = name_str; } @@ -341,7 +346,13 @@ Error GameCenter::request_identity_verification_signature() { ret["signature"] = [[signature base64EncodedStringWithOptions:0] UTF8String]; ret["salt"] = [[salt base64EncodedStringWithOptions:0] UTF8String]; ret["timestamp"] = timestamp; - ret["player_id"] = [player.playerID UTF8String]; + if (@available(iOS 13, *)) { + ret["player_id"] = [player.teamPlayerID UTF8String]; +#if !defined(TARGET_OS_SIMULATOR) || !TARGET_OS_SIMULATOR + } else { + ret["player_id"] = [player.playerID UTF8String]; +#endif + } } else { ret["result"] = "error"; ret["error_code"] = (int64_t)error.code; diff --git a/platform/iphone/gl_view.h b/platform/iphone/gl_view.h deleted file mode 100644 index 975aa4b70a..0000000000 --- a/platform/iphone/gl_view.h +++ /dev/null @@ -1,123 +0,0 @@ -/*************************************************************************/ -/* gl_view.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#import <AVFoundation/AVFoundation.h> -#import <MediaPlayer/MediaPlayer.h> -#import <OpenGLES/EAGL.h> -#import <OpenGLES/ES1/gl.h> -#import <OpenGLES/ES1/glext.h> -#import <UIKit/UIKit.h> - -@protocol GLViewDelegate; - -@interface GLView : UIView <UIKeyInput> { -@private - // The pixel dimensions of the backbuffer - GLint backingWidth; - GLint backingHeight; - - EAGLContext *context; - - // OpenGL names for the renderbuffer and framebuffers used to render to this view - GLuint viewRenderbuffer, viewFramebuffer; - - // OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) - GLuint depthRenderbuffer; - - BOOL useCADisplayLink; - // CADisplayLink available on 3.1+ synchronizes the animation timer & drawing with the refresh rate of the display, only supports animation intervals of 1/60 1/30 & 1/15 - CADisplayLink *displayLink; - - // An animation timer that, when animation is started, will periodically call -drawView at the given rate. - // Only used if CADisplayLink is not - NSTimer *animationTimer; - - NSTimeInterval animationInterval; - - // Delegate to do our drawing, called by -drawView, which can be called manually or via the animation timer. - id<GLViewDelegate> delegate; - - // Flag to denote that the -setupView method of a delegate has been called. - // Resets to NO whenever the delegate changes. - BOOL delegateSetup; - BOOL active; - float screen_scale; -} - -@property(nonatomic, assign) id<GLViewDelegate> delegate; - -// AVPlayer-related properties -@property(strong, nonatomic) AVAsset *avAsset; -@property(strong, nonatomic) AVPlayerItem *avPlayerItem; -@property(strong, nonatomic) AVPlayer *avPlayer; -@property(strong, nonatomic) AVPlayerLayer *avPlayerLayer; - -@property(strong, nonatomic) UIWindow *backgroundWindow; - -@property(nonatomic) UITextAutocorrectionType autocorrectionType; - -- (void)startAnimation; -- (void)stopAnimation; -- (void)drawView; - -- (BOOL)canBecomeFirstResponder; - -- (void)open_keyboard; -- (void)hide_keyboard; -- (void)deleteBackward; -- (BOOL)hasText; -- (void)insertText:(NSString *)p_text; - -- (id)initGLES; -- (BOOL)createFramebuffer; -- (void)destroyFramebuffer; - -- (void)audioRouteChangeListenerCallback:(NSNotification *)notification; -- (void)keyboardOnScreen:(NSNotification *)notification; -- (void)keyboardHidden:(NSNotification *)notification; - -@property NSTimeInterval animationInterval; -@property(nonatomic, assign) BOOL useCADisplayLink; - -@end - -@protocol GLViewDelegate <NSObject> - -@required - -// Draw with OpenGL ES -- (void)drawView:(GLView *)view; - -@optional - -// Called whenever you need to do some initialization before rendering. -- (void)setupView:(GLView *)view; - -@end diff --git a/platform/iphone/gl_view.mm b/platform/iphone/gl_view.mm deleted file mode 100644 index 1169ebc6b4..0000000000 --- a/platform/iphone/gl_view.mm +++ /dev/null @@ -1,702 +0,0 @@ -/*************************************************************************/ -/* gl_view.mm */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#import "gl_view.h" - -#include "core/os/keyboard.h" -#include "core/project_settings.h" -#include "os_iphone.h" -#include "servers/audio_server.h" - -#import <OpenGLES/EAGLDrawable.h> -#import <QuartzCore/QuartzCore.h> - -/* -@interface GLView (private) - -- (id)initGLES; -- (BOOL)createFramebuffer; -- (void)destroyFramebuffer; -@end -*/ - -int gl_view_base_fb; -static String keyboard_text; -static GLView *_instance = NULL; - -static bool video_found_error = false; -static bool video_playing = false; -static CMTime video_current_time; - -void _show_keyboard(String); -void _hide_keyboard(); -bool _play_video(String, float, String, String); -bool _is_video_playing(); -void _pause_video(); -void _focus_out_video(); -void _unpause_video(); -void _stop_video(); -CGFloat _points_to_pixels(CGFloat); - -void _show_keyboard(String p_existing) { - keyboard_text = p_existing; - printf("instance on show is %p\n", _instance); - [_instance open_keyboard]; -}; - -void _hide_keyboard() { - printf("instance on hide is %p\n", _instance); - [_instance hide_keyboard]; - keyboard_text = ""; -}; - -Rect2 _get_ios_window_safe_area(float p_window_width, float p_window_height) { - UIEdgeInsets insets = UIEdgeInsetsMake(0, 0, 0, 0); - if (_instance != nil && [_instance respondsToSelector:@selector(safeAreaInsets)]) { - insets = [_instance safeAreaInsets]; - } - ERR_FAIL_COND_V(insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0, - Rect2(0, 0, p_window_width, p_window_height)); - UIEdgeInsets window_insets = UIEdgeInsetsMake(_points_to_pixels(insets.top), _points_to_pixels(insets.left), _points_to_pixels(insets.bottom), _points_to_pixels(insets.right)); - return Rect2(window_insets.left, window_insets.top, p_window_width - window_insets.right - window_insets.left, p_window_height - window_insets.bottom - window_insets.top); -} - -bool _play_video(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) { - p_path = ProjectSettings::get_singleton()->globalize_path(p_path); - - NSString *file_path = [[[NSString alloc] initWithUTF8String:p_path.utf8().get_data()] autorelease]; - - _instance.avAsset = [AVAsset assetWithURL:[NSURL fileURLWithPath:file_path]]; - - _instance.avPlayerItem = [[AVPlayerItem alloc] initWithAsset:_instance.avAsset]; - [_instance.avPlayerItem addObserver:_instance forKeyPath:@"status" options:0 context:nil]; - - _instance.avPlayer = [[AVPlayer alloc] initWithPlayerItem:_instance.avPlayerItem]; - _instance.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:_instance.avPlayer]; - - [_instance.avPlayer addObserver:_instance forKeyPath:@"status" options:0 context:nil]; - [[NSNotificationCenter defaultCenter] - addObserver:_instance - selector:@selector(playerItemDidReachEnd:) - name:AVPlayerItemDidPlayToEndTimeNotification - object:[_instance.avPlayer currentItem]]; - - [_instance.avPlayer addObserver:_instance forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:0]; - - [_instance.avPlayerLayer setFrame:_instance.bounds]; - [_instance.layer addSublayer:_instance.avPlayerLayer]; - [_instance.avPlayer play]; - - AVMediaSelectionGroup *audioGroup = [_instance.avAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicAudible]; - - NSMutableArray *allAudioParams = [NSMutableArray array]; - for (id track in audioGroup.options) { - NSString *language = [[track locale] localeIdentifier]; - NSLog(@"subtitle lang: %@", language); - - if ([language isEqualToString:[NSString stringWithUTF8String:p_audio_track.utf8()]]) { - AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters]; - [audioInputParams setVolume:p_volume atTime:kCMTimeZero]; - [audioInputParams setTrackID:[track trackID]]; - [allAudioParams addObject:audioInputParams]; - - AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix]; - [audioMix setInputParameters:allAudioParams]; - - [_instance.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup:audioGroup]; - [_instance.avPlayer.currentItem setAudioMix:audioMix]; - - break; - } - } - - AVMediaSelectionGroup *subtitlesGroup = [_instance.avAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicLegible]; - NSArray *useableTracks = [AVMediaSelectionGroup mediaSelectionOptionsFromArray:subtitlesGroup.options withoutMediaCharacteristics:[NSArray arrayWithObject:AVMediaCharacteristicContainsOnlyForcedSubtitles]]; - - for (id track in useableTracks) { - NSString *language = [[track locale] localeIdentifier]; - NSLog(@"subtitle lang: %@", language); - - if ([language isEqualToString:[NSString stringWithUTF8String:p_subtitle_track.utf8()]]) { - [_instance.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup:subtitlesGroup]; - break; - } - } - - video_playing = true; - - return true; -} - -bool _is_video_playing() { - if (_instance.avPlayer.error) { - printf("Error during playback\n"); - } - return (_instance.avPlayer.rate > 0 && !_instance.avPlayer.error); -} - -void _pause_video() { - video_current_time = _instance.avPlayer.currentTime; - [_instance.avPlayer pause]; - video_playing = false; -} - -void _focus_out_video() { - printf("focus out pausing video\n"); - [_instance.avPlayer pause]; -}; - -void _unpause_video() { - [_instance.avPlayer play]; - video_playing = true; -}; - -void _stop_video() { - [_instance.avPlayer pause]; - [_instance.avPlayerLayer removeFromSuperlayer]; - _instance.avPlayer = nil; - video_playing = false; -} - -CGFloat _points_to_pixels(CGFloat points) { - float pixelPerInch; - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { - pixelPerInch = 132; - } else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { - pixelPerInch = 163; - } else { - pixelPerInch = 160; - } - CGFloat pointsPerInch = 72.0; - return (points / pointsPerInch * pixelPerInch); -} - -@implementation GLView - -@synthesize animationInterval; - -static const int max_touches = 8; -static UITouch *touches[max_touches]; - -static void init_touches() { - for (int i = 0; i < max_touches; i++) { - touches[i] = NULL; - }; -}; - -static int get_touch_id(UITouch *p_touch) { - int first = -1; - for (int i = 0; i < max_touches; i++) { - if (first == -1 && touches[i] == NULL) { - first = i; - continue; - }; - if (touches[i] == p_touch) - return i; - }; - - if (first != -1) { - touches[first] = p_touch; - return first; - }; - - return -1; -}; - -static int remove_touch(UITouch *p_touch) { - int remaining = 0; - for (int i = 0; i < max_touches; i++) { - if (touches[i] == NULL) - continue; - if (touches[i] == p_touch) - touches[i] = NULL; - else - ++remaining; - }; - return remaining; -}; - -static void clear_touches() { - for (int i = 0; i < max_touches; i++) { - touches[i] = NULL; - }; -}; - -// Implement this to override the default layer class (which is [CALayer class]). -// We do this so that our view will be backed by a layer that is capable of OpenGL ES rendering. -+ (Class)layerClass { - return [CAEAGLLayer class]; -} - -//The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder: -- (id)initWithCoder:(NSCoder *)coder { - active = FALSE; - if ((self = [super initWithCoder:coder])) { - self = [self initGLES]; - } - return self; -} - -- (id)initGLES { - // Get our backing layer - CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; - - // Configure it so that it is opaque, does not retain the contents of the backbuffer when displayed, and uses RGBA8888 color. - eaglLayer.opaque = YES; - eaglLayer.drawableProperties = [NSDictionary - dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:FALSE], - kEAGLDrawablePropertyRetainedBacking, - kEAGLColorFormatRGBA8, - kEAGLDrawablePropertyColorFormat, - nil]; - - // FIXME: Add Vulkan support via MoltenVK. Add fallback code back? - - // Create GL ES 2 context - if (GLOBAL_GET("rendering/quality/driver/driver_name") == "GLES2") { - context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - NSLog(@"Setting up an OpenGL ES 2.0 context."); - if (!context) { - NSLog(@"Failed to create OpenGL ES 2.0 context!"); - return nil; - } - } - - if (![EAGLContext setCurrentContext:context]) { - NSLog(@"Failed to set EAGLContext!"); - return nil; - } - if (![self createFramebuffer]) { - NSLog(@"Failed to create frame buffer!"); - return nil; - } - - // Default the animation interval to 1/60th of a second. - animationInterval = 1.0 / 60.0; - return self; -} - -- (id<GLViewDelegate>)delegate { - return delegate; -} - -// Update the delegate, and if it needs a -setupView: call, set our internal flag so that it will be called. -- (void)setDelegate:(id<GLViewDelegate>)d { - delegate = d; - delegateSetup = ![delegate respondsToSelector:@selector(setupView:)]; -} - -@synthesize useCADisplayLink; - -// If our view is resized, we'll be asked to layout subviews. -// This is the perfect opportunity to also update the framebuffer so that it is -// the same size as our display area. - -- (void)layoutSubviews { - [EAGLContext setCurrentContext:context]; - [self destroyFramebuffer]; - [self createFramebuffer]; - [self drawView]; -} - -- (BOOL)createFramebuffer { - // Generate IDs for a framebuffer object and a color renderbuffer - UIScreen *mainscr = [UIScreen mainScreen]; - printf("******** screen size %i, %i\n", (int)mainscr.currentMode.size.width, (int)mainscr.currentMode.size.height); - self.contentScaleFactor = mainscr.nativeScale; - - glGenFramebuffersOES(1, &viewFramebuffer); - glGenRenderbuffersOES(1, &viewRenderbuffer); - - glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); - // This call associates the storage for the current render buffer with the EAGLDrawable (our CAEAGLLayer) - // allowing us to draw into a buffer that will later be rendered to screen wherever the layer is (which corresponds with our view). - [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self.layer]; - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer); - - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); - - // For this sample, we also need a depth buffer, so we'll create and attach one via another renderbuffer. - glGenRenderbuffersOES(1, &depthRenderbuffer); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); - glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight); - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer); - - if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { - NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); - return NO; - } - - if (OS::get_singleton()) { - OS::VideoMode vm; - vm.fullscreen = true; - vm.width = backingWidth; - vm.height = backingHeight; - vm.resizable = false; - OS::get_singleton()->set_video_mode(vm); - OSIPhone::get_singleton()->set_base_framebuffer(viewFramebuffer); - }; - gl_view_base_fb = viewFramebuffer; - - return YES; -} - -// Clean up any buffers we have allocated. -- (void)destroyFramebuffer { - glDeleteFramebuffersOES(1, &viewFramebuffer); - viewFramebuffer = 0; - glDeleteRenderbuffersOES(1, &viewRenderbuffer); - viewRenderbuffer = 0; - - if (depthRenderbuffer) { - glDeleteRenderbuffersOES(1, &depthRenderbuffer); - depthRenderbuffer = 0; - } -} - -- (void)startAnimation { - if (active) - return; - active = TRUE; - printf("start animation!\n"); - if (useCADisplayLink) { - // Approximate frame rate - // assumes device refreshes at 60 fps - int frameInterval = (int)floor(animationInterval * 60.0f); - - displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView)]; - [displayLink setFrameInterval:frameInterval]; - - // Setup DisplayLink in main thread - [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; - } else { - animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES]; - } - - if (video_playing) { - _unpause_video(); - } -} - -- (void)stopAnimation { - if (!active) - return; - active = FALSE; - printf("******** stop animation!\n"); - - if (useCADisplayLink) { - [displayLink invalidate]; - displayLink = nil; - } else { - [animationTimer invalidate]; - animationTimer = nil; - } - - clear_touches(); - - if (video_playing) { - // save position - } -} - -- (void)setAnimationInterval:(NSTimeInterval)interval { - animationInterval = interval; - if ((useCADisplayLink && displayLink) || (!useCADisplayLink && animationTimer)) { - [self stopAnimation]; - [self startAnimation]; - } -} - -// Updates the OpenGL view when the timer fires -- (void)drawView { - if (!active) { - printf("draw view not active!\n"); - return; - }; - if (useCADisplayLink) { - // Pause the CADisplayLink to avoid recursion - [displayLink setPaused:YES]; - - // Process all input events - while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, TRUE) == kCFRunLoopRunHandledSource) - ; - - // We are good to go, resume the CADisplayLink - [displayLink setPaused:NO]; - } - - // Make sure that you are drawing to the current context - [EAGLContext setCurrentContext:context]; - - // If our drawing delegate needs to have the view setup, then call -setupView: and flag that it won't need to be called again. - if (!delegateSetup) { - [delegate setupView:self]; - delegateSetup = YES; - } - - glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); - - [delegate drawView:self]; - - glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); - [context presentRenderbuffer:GL_RENDERBUFFER_OES]; - -#ifdef DEBUG_ENABLED - GLenum err = glGetError(); - if (err) - NSLog(@"DrawView: %x error", err); -#endif -} - -- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - NSArray *tlist = [[event allTouches] allObjects]; - for (unsigned int i = 0; i < [tlist count]; i++) { - if ([touches containsObject:[tlist objectAtIndex:i]]) { - UITouch *touch = [tlist objectAtIndex:i]; - if (touch.phase != UITouchPhaseBegan) - continue; - int tid = get_touch_id(touch); - ERR_FAIL_COND(tid == -1); - CGPoint touchPoint = [touch locationInView:self]; - OSIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1); - }; - }; -} - -- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - NSArray *tlist = [[event allTouches] allObjects]; - for (unsigned int i = 0; i < [tlist count]; i++) { - if ([touches containsObject:[tlist objectAtIndex:i]]) { - UITouch *touch = [tlist objectAtIndex:i]; - if (touch.phase != UITouchPhaseMoved) - continue; - int tid = get_touch_id(touch); - ERR_FAIL_COND(tid == -1); - CGPoint touchPoint = [touch locationInView:self]; - CGPoint prev_point = [touch previousLocationInView:self]; - OSIPhone::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor); - }; - }; -} - -- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - NSArray *tlist = [[event allTouches] allObjects]; - for (unsigned int i = 0; i < [tlist count]; i++) { - if ([touches containsObject:[tlist objectAtIndex:i]]) { - UITouch *touch = [tlist objectAtIndex:i]; - if (touch.phase != UITouchPhaseEnded) - continue; - int tid = get_touch_id(touch); - ERR_FAIL_COND(tid == -1); - remove_touch(touch); - CGPoint touchPoint = [touch locationInView:self]; - OSIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false); - }; - }; -} - -- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - OSIPhone::get_singleton()->touches_cancelled(); - clear_touches(); -}; - -- (BOOL)canBecomeFirstResponder { - return YES; -}; - -- (void)open_keyboard { - //keyboard_text = p_existing; - [self becomeFirstResponder]; -}; - -- (void)hide_keyboard { - //keyboard_text = p_existing; - [self resignFirstResponder]; -}; - -- (void)keyboardOnScreen:(NSNotification *)notification { - NSDictionary *info = notification.userInfo; - NSValue *value = info[UIKeyboardFrameEndUserInfoKey]; - - CGRect rawFrame = [value CGRectValue]; - CGRect keyboardFrame = [self convertRect:rawFrame fromView:nil]; - - OSIPhone::get_singleton()->set_virtual_keyboard_height(_points_to_pixels(keyboardFrame.size.height)); -} - -- (void)keyboardHidden:(NSNotification *)notification { - OSIPhone::get_singleton()->set_virtual_keyboard_height(0); -} - -- (void)deleteBackward { - if (keyboard_text.length()) - keyboard_text.erase(keyboard_text.length() - 1, 1); - OSIPhone::get_singleton()->key(KEY_BACKSPACE, true); -}; - -- (BOOL)hasText { - return keyboard_text.length() ? YES : NO; -}; - -- (void)insertText:(NSString *)p_text { - String character; - character.parse_utf8([p_text UTF8String]); - keyboard_text = keyboard_text + character; - OSIPhone::get_singleton()->key(character[0] == 10 ? KEY_ENTER : character[0], true); - printf("inserting text with character %lc\n", (CharType)character[0]); -}; - -- (void)audioRouteChangeListenerCallback:(NSNotification *)notification { - printf("*********** route changed!\n"); - NSDictionary *interuptionDict = notification.userInfo; - - NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue]; - - switch (routeChangeReason) { - case AVAudioSessionRouteChangeReasonNewDeviceAvailable: { - NSLog(@"AVAudioSessionRouteChangeReasonNewDeviceAvailable"); - NSLog(@"Headphone/Line plugged in"); - }; break; - - case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: { - NSLog(@"AVAudioSessionRouteChangeReasonOldDeviceUnavailable"); - NSLog(@"Headphone/Line was pulled. Resuming video play...."); - if (_is_video_playing()) { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - [_instance.avPlayer play]; // NOTE: change this line according your current player implementation - NSLog(@"resumed play"); - }); - }; - }; break; - - case AVAudioSessionRouteChangeReasonCategoryChange: { - // called at start - also when other audio wants to play - NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange"); - }; break; - } -} - -// When created via code however, we get initWithFrame -- (id)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - _instance = self; - printf("after init super %p\n", self); - if (self != nil) { - self = [self initGLES]; - printf("after init gles %p\n", self); - } - init_touches(); - self.multipleTouchEnabled = YES; - self.autocorrectionType = UITextAutocorrectionTypeNo; - - printf("******** adding observer for sound routing changes\n"); - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(audioRouteChangeListenerCallback:) - name:AVAudioSessionRouteChangeNotification - object:nil]; - - printf("******** adding observer for keyboard show/hide\n"); - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(keyboardOnScreen:) - name:UIKeyboardDidShowNotification - object:nil]; - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(keyboardHidden:) - name:UIKeyboardDidHideNotification - object:nil]; - - //self.autoresizesSubviews = YES; - //[self setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleWidth]; - - return self; -} - -//- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers { -// return YES; -//} - -//- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{ -// return YES; -//} - -// Stop animating and release resources when they are no longer needed. -- (void)dealloc { - [self stopAnimation]; - - if ([EAGLContext currentContext] == context) { - [EAGLContext setCurrentContext:nil]; - } - - [context release]; - context = nil; - - [super dealloc]; -} - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - if (object == _instance.avPlayerItem && [keyPath isEqualToString:@"status"]) { - if (_instance.avPlayerItem.status == AVPlayerStatusFailed || _instance.avPlayer.status == AVPlayerStatusFailed) { - _stop_video(); - video_found_error = true; - } - - if (_instance.avPlayer.status == AVPlayerStatusReadyToPlay && - _instance.avPlayerItem.status == AVPlayerItemStatusReadyToPlay && - CMTIME_COMPARE_INLINE(video_current_time, ==, kCMTimeZero)) { - //NSLog(@"time: %@", video_current_time); - - [_instance.avPlayer seekToTime:video_current_time]; - video_current_time = kCMTimeZero; - } - } - - if (object == _instance.avPlayer && [keyPath isEqualToString:@"rate"]) { - NSLog(@"Player playback rate changed: %.5f", _instance.avPlayer.rate); - if (_is_video_playing() && _instance.avPlayer.rate == 0.0 && !_instance.avPlayer.error) { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - [_instance.avPlayer play]; // NOTE: change this line according your current player implementation - NSLog(@"resumed play"); - }); - - NSLog(@" . . . PAUSED (or just started)"); - } - } -} - -- (void)playerItemDidReachEnd:(NSNotification *)notification { - _stop_video(); -} - -@end diff --git a/platform/iphone/godot_iphone.cpp b/platform/iphone/godot_iphone.mm index aa5dbd5130..090b772947 100644 --- a/platform/iphone/godot_iphone.cpp +++ b/platform/iphone/godot_iphone.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_iphone.cpp */ +/* godot_iphone.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -38,19 +38,53 @@ static OSIPhone *os = nullptr; -extern "C" { -int add_path(int p_argc, char **p_args); -int add_cmdline(int p_argc, char **p_args); +int add_path(int, char **); +int add_cmdline(int, char **); +int iphone_main(int, char **, String); + +int add_path(int p_argc, char **p_args) { + NSString *str = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"godot_path"]; + if (!str) { + return p_argc; + } + + p_args[p_argc++] = (char *)"--path"; + [str retain]; // memory leak lol (maybe make it static here and delete it in ViewController destructor? @todo + p_args[p_argc++] = (char *)[str cStringUsingEncoding:NSUTF8StringEncoding]; + p_args[p_argc] = NULL; + [str release]; + + return p_argc; }; -int iphone_main(int, int, int, char **, String); +int add_cmdline(int p_argc, char **p_args) { + NSArray *arr = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"godot_cmdline"]; + if (!arr) { + return p_argc; + } + + for (NSUInteger i = 0; i < [arr count]; i++) { + NSString *str = [arr objectAtIndex:i]; + if (!str) { + continue; + } + [str retain]; // @todo delete these at some point + p_args[p_argc++] = (char *)[str cStringUsingEncoding:NSUTF8StringEncoding]; + [str release]; + }; -int iphone_main(int width, int height, int argc, char **argv, String data_dir) { + p_args[p_argc] = NULL; + + return p_argc; +}; + +int iphone_main(int argc, char **argv, String data_dir) { size_t len = strlen(argv[0]); while (len--) { - if (argv[0][len] == '/') + if (argv[0][len] == '/') { break; + } } if (len >= 0) { @@ -65,7 +99,7 @@ int iphone_main(int width, int height, int argc, char **argv, String data_dir) { char cwd[512]; getcwd(cwd, sizeof(cwd)); printf("cwd %s\n", cwd); - os = new OSIPhone(width, height, data_dir); + os = new OSIPhone(data_dir); // We must override main when testing is enabled TEST_MAIN_OVERRIDE @@ -79,10 +113,14 @@ int iphone_main(int width, int height, int argc, char **argv, String data_dir) { argc = add_cmdline(argc, fargv); printf("os created\n"); + Error err = Main::setup(fargv[0], argc - 1, &fargv[1], false); printf("setup %i\n", err); - if (err != OK) + if (err != OK) { return 255; + } + + os->initialize_modules(); return 0; }; diff --git a/platform/iphone/godot_view.h b/platform/iphone/godot_view.h new file mode 100644 index 0000000000..62fa2f5a32 --- /dev/null +++ b/platform/iphone/godot_view.h @@ -0,0 +1,56 @@ +/*************************************************************************/ +/* godot_view.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import <UIKit/UIKit.h> + +class String; + +@protocol DisplayLayer; +@protocol GodotViewRendererProtocol; + +@interface GodotView : UIView <UIKeyInput> + +@property(assign, nonatomic) id<GodotViewRendererProtocol> renderer; + +@property(assign, readonly, nonatomic) BOOL isActive; + +@property(assign, nonatomic) BOOL useCADisplayLink; +@property(strong, readonly, nonatomic) CALayer<DisplayLayer> *renderingLayer; +@property(assign, readonly, nonatomic) BOOL canRender; + +@property(assign, nonatomic) NSTimeInterval renderingInterval; + +- (CALayer<DisplayLayer> *)initializeRenderingForDriver:(NSString *)driverName; +- (void)stopRendering; +- (void)startRendering; + +- (BOOL)becomeFirstResponderWithString:(String)p_existing; + +@end diff --git a/platform/iphone/godot_view.mm b/platform/iphone/godot_view.mm new file mode 100644 index 0000000000..c0a31549c4 --- /dev/null +++ b/platform/iphone/godot_view.mm @@ -0,0 +1,499 @@ +/*************************************************************************/ +/* godot_view.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import "godot_view.h" +#include "core/os/keyboard.h" +#include "core/ustring.h" +#import "display_layer.h" +#include "display_server_iphone.h" +#import "godot_view_gesture_recognizer.h" +#import "godot_view_renderer.h" + +#import <CoreMotion/CoreMotion.h> + +static const int max_touches = 8; + +@interface GodotView () { + UITouch *godot_touches[max_touches]; + String keyboard_text; +} + +@property(assign, nonatomic) BOOL isActive; + +// CADisplayLink available on 3.1+ synchronizes the animation timer & drawing with the refresh rate of the display, only supports animation intervals of 1/60 1/30 & 1/15 +@property(strong, nonatomic) CADisplayLink *displayLink; + +// An animation timer that, when animation is started, will periodically call -drawView at the given rate. +// Only used if CADisplayLink is not +@property(strong, nonatomic) NSTimer *animationTimer; + +@property(strong, nonatomic) CALayer<DisplayLayer> *renderingLayer; + +@property(strong, nonatomic) CMMotionManager *motionManager; + +@property(strong, nonatomic) GodotViewGestureRecognizer *delayGestureRecognizer; + +@end + +@implementation GodotView + +- (CALayer<DisplayLayer> *)initializeRenderingForDriver:(NSString *)driverName { + if (self.renderingLayer) { + return self.renderingLayer; + } + + CALayer<DisplayLayer> *layer; + + if ([driverName isEqualToString:@"vulkan"]) { + layer = [GodotMetalLayer layer]; + } else if ([driverName isEqualToString:@"opengl_es"]) { + if (@available(iOS 13, *)) { + NSLog(@"OpenGL ES is deprecated on iOS 13"); + } +#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR + return nil; +#else + layer = [GodotOpenGLLayer layer]; +#endif + } else { + return nil; + } + + layer.frame = self.bounds; + layer.contentsScale = self.contentScaleFactor; + + [self.layer addSublayer:layer]; + self.renderingLayer = layer; + + [layer initializeDisplayLayer]; + + return self.renderingLayer; +} + +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + + if (self) { + [self godot_commonInit]; + } + + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + + if (self) { + [self godot_commonInit]; + } + + return self; +} + +- (void)dealloc { + [self stopRendering]; + + self.renderer = nil; + + if (self.renderingLayer) { + [self.renderingLayer removeFromSuperlayer]; + self.renderingLayer = nil; + } + + if (self.motionManager) { + [self.motionManager stopDeviceMotionUpdates]; + self.motionManager = nil; + } + + if (self.displayLink) { + [self.displayLink invalidate]; + self.displayLink = nil; + } + + if (self.animationTimer) { + [self.animationTimer invalidate]; + self.animationTimer = nil; + } + + if (self.delayGestureRecognizer) { + self.delayGestureRecognizer = nil; + } + + [super dealloc]; +} + +- (void)godot_commonInit { + self.contentScaleFactor = [UIScreen mainScreen].nativeScale; + + [self initTouches]; + + // Configure and start accelerometer + if (!self.motionManager) { + self.motionManager = [[[CMMotionManager alloc] init] autorelease]; + if (self.motionManager.deviceMotionAvailable) { + self.motionManager.deviceMotionUpdateInterval = 1.0 / 70.0; + [self.motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXMagneticNorthZVertical]; + } else { + self.motionManager = nil; + } + } + + // Initialize delay gesture recognizer + GodotViewGestureRecognizer *gestureRecognizer = [[GodotViewGestureRecognizer alloc] init]; + self.delayGestureRecognizer = gestureRecognizer; + [self addGestureRecognizer:self.delayGestureRecognizer]; + [gestureRecognizer release]; +} + +- (void)stopRendering { + if (!self.isActive) { + return; + } + + self.isActive = NO; + + printf("******** stop animation!\n"); + + if (self.useCADisplayLink) { + [self.displayLink invalidate]; + self.displayLink = nil; + } else { + [self.animationTimer invalidate]; + self.animationTimer = nil; + } + + [self clearTouches]; +} + +- (void)startRendering { + if (self.isActive) { + return; + } + + self.isActive = YES; + + printf("start animation!\n"); + + if (self.useCADisplayLink) { + self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView)]; + + // if (@available(iOS 10, *)) { + self.displayLink.preferredFramesPerSecond = (NSInteger)(1.0 / self.renderingInterval); + // } else { + // // Approximate frame rate + // // assumes device refreshes at 60 fps + // int frameInterval = (int)floor(self.renderingInterval * 60.0f); + // [self.displayLink setFrameInterval:frameInterval]; + // } + + // Setup DisplayLink in main thread + [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; + } else { + self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:self.renderingInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES]; + } +} + +- (void)drawView { + if (!self.isActive) { + printf("draw view not active!\n"); + return; + } + + if (self.useCADisplayLink) { + // Pause the CADisplayLink to avoid recursion + [self.displayLink setPaused:YES]; + + // Process all input events + while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, TRUE) == kCFRunLoopRunHandledSource) + ; + + // We are good to go, resume the CADisplayLink + [self.displayLink setPaused:NO]; + } + + [self.renderingLayer renderDisplayLayer]; + + if (!self.renderer) { + return; + } + + if ([self.renderer setupView:self]) { + return; + } + + [self handleMotion]; + [self.renderer renderOnView:self]; +} + +- (BOOL)canRender { + if (self.useCADisplayLink) { + return self.displayLink != nil; + } else { + return self.animationTimer != nil; + } +} + +- (void)setRenderingInterval:(NSTimeInterval)renderingInterval { + _renderingInterval = renderingInterval; + + if (self.canRender) { + [self stopRendering]; + [self startRendering]; + } +} + +- (void)layoutSubviews { + if (self.renderingLayer) { + self.renderingLayer.frame = self.bounds; + [self.renderingLayer layoutDisplayLayer]; + + if (DisplayServerIPhone::get_singleton()) { + DisplayServerIPhone::get_singleton()->resize_window(self.bounds.size); + } + } + + [super layoutSubviews]; +} + +// MARK: - Input + +// MARK: Keyboard + +- (BOOL)canBecomeFirstResponder { + return YES; +} + +- (BOOL)becomeFirstResponderWithString:(String)p_existing { + keyboard_text = p_existing; + return [self becomeFirstResponder]; +} + +- (BOOL)resignFirstResponder { + keyboard_text = String(); + return [super resignFirstResponder]; +} + +- (void)deleteBackward { + if (keyboard_text.length()) { + keyboard_text.erase(keyboard_text.length() - 1, 1); + } + DisplayServerIPhone::get_singleton()->key(KEY_BACKSPACE, true); +} + +- (BOOL)hasText { + return keyboard_text.length() > 0; +} + +- (void)insertText:(NSString *)p_text { + String character; + character.parse_utf8([p_text UTF8String]); + keyboard_text = keyboard_text + character; + DisplayServerIPhone::get_singleton()->key(character[0] == 10 ? KEY_ENTER : character[0], true); +} + +// MARK: Touches + +- (void)initTouches { + for (int i = 0; i < max_touches; i++) { + godot_touches[i] = NULL; + } +} + +- (int)getTouchIDForTouch:(UITouch *)p_touch { + int first = -1; + for (int i = 0; i < max_touches; i++) { + if (first == -1 && godot_touches[i] == NULL) { + first = i; + continue; + } + if (godot_touches[i] == p_touch) { + return i; + } + } + + if (first != -1) { + godot_touches[first] = p_touch; + return first; + } + + return -1; +} + +- (int)removeTouch:(UITouch *)p_touch { + int remaining = 0; + for (int i = 0; i < max_touches; i++) { + if (godot_touches[i] == NULL) { + continue; + } + if (godot_touches[i] == p_touch) { + godot_touches[i] = NULL; + } else { + ++remaining; + } + } + return remaining; +} + +- (void)clearTouches { + for (int i = 0; i < max_touches; i++) { + godot_touches[i] = NULL; + } +} + +- (void)touchesBegan:(NSSet *)touchesSet withEvent:(UIEvent *)event { + NSArray *tlist = [event.allTouches allObjects]; + for (unsigned int i = 0; i < [tlist count]; i++) { + if ([touchesSet containsObject:[tlist objectAtIndex:i]]) { + UITouch *touch = [tlist objectAtIndex:i]; + int tid = [self getTouchIDForTouch:touch]; + ERR_FAIL_COND(tid == -1); + CGPoint touchPoint = [touch locationInView:self]; + DisplayServerIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1); + } + } +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + NSArray *tlist = [event.allTouches allObjects]; + for (unsigned int i = 0; i < [tlist count]; i++) { + if ([touches containsObject:[tlist objectAtIndex:i]]) { + UITouch *touch = [tlist objectAtIndex:i]; + int tid = [self getTouchIDForTouch:touch]; + ERR_FAIL_COND(tid == -1); + CGPoint touchPoint = [touch locationInView:self]; + CGPoint prev_point = [touch previousLocationInView:self]; + DisplayServerIPhone::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor); + } + } +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + NSArray *tlist = [event.allTouches allObjects]; + for (unsigned int i = 0; i < [tlist count]; i++) { + if ([touches containsObject:[tlist objectAtIndex:i]]) { + UITouch *touch = [tlist objectAtIndex:i]; + int tid = [self getTouchIDForTouch:touch]; + ERR_FAIL_COND(tid == -1); + [self removeTouch:touch]; + CGPoint touchPoint = [touch locationInView:self]; + DisplayServerIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false); + } + } +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + NSArray *tlist = [event.allTouches allObjects]; + for (unsigned int i = 0; i < [tlist count]; i++) { + if ([touches containsObject:[tlist objectAtIndex:i]]) { + UITouch *touch = [tlist objectAtIndex:i]; + int tid = [self getTouchIDForTouch:touch]; + ERR_FAIL_COND(tid == -1); + DisplayServerIPhone::get_singleton()->touches_cancelled(tid); + } + } + [self clearTouches]; +} + +// MARK: Motion + +- (void)handleMotion { + if (!self.motionManager) { + return; + } + + // Just using polling approach for now, we can set this up so it sends + // data to us in intervals, might be better. See Apple reference pages + // for more details: + // https://developer.apple.com/reference/coremotion/cmmotionmanager?language=objc + + // Apple splits our accelerometer date into a gravity and user movement + // component. We add them back together + CMAcceleration gravity = self.motionManager.deviceMotion.gravity; + CMAcceleration acceleration = self.motionManager.deviceMotion.userAcceleration; + + ///@TODO We don't seem to be getting data here, is my device broken or + /// is this code incorrect? + CMMagneticField magnetic = self.motionManager.deviceMotion.magneticField.field; + + ///@TODO we can access rotationRate as a CMRotationRate variable + ///(processed date) or CMGyroData (raw data), have to see what works + /// best + CMRotationRate rotation = self.motionManager.deviceMotion.rotationRate; + + // Adjust for screen orientation. + // [[UIDevice currentDevice] orientation] changes even if we've fixed + // our orientation which is not a good thing when you're trying to get + // your user to move the screen in all directions and want consistent + // output + + ///@TODO Using [[UIApplication sharedApplication] statusBarOrientation] + /// is a bit of a hack. Godot obviously knows the orientation so maybe + /// we + // can use that instead? (note that left and right seem swapped) + + UIInterfaceOrientation interfaceOrientation = UIInterfaceOrientationUnknown; + + if (@available(iOS 13, *)) { + interfaceOrientation = [UIApplication sharedApplication].delegate.window.windowScene.interfaceOrientation; +#if !defined(TARGET_OS_SIMULATOR) || !TARGET_OS_SIMULATOR + } else { + interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation]; +#endif + } + + switch (interfaceOrientation) { + case UIInterfaceOrientationLandscapeLeft: { + DisplayServerIPhone::get_singleton()->update_gravity(-gravity.y, gravity.x, gravity.z); + DisplayServerIPhone::get_singleton()->update_accelerometer(-(acceleration.y + gravity.y), (acceleration.x + gravity.x), acceleration.z + gravity.z); + DisplayServerIPhone::get_singleton()->update_magnetometer(-magnetic.y, magnetic.x, magnetic.z); + DisplayServerIPhone::get_singleton()->update_gyroscope(-rotation.y, rotation.x, rotation.z); + } break; + case UIInterfaceOrientationLandscapeRight: { + DisplayServerIPhone::get_singleton()->update_gravity(gravity.y, -gravity.x, gravity.z); + DisplayServerIPhone::get_singleton()->update_accelerometer((acceleration.y + gravity.y), -(acceleration.x + gravity.x), acceleration.z + gravity.z); + DisplayServerIPhone::get_singleton()->update_magnetometer(magnetic.y, -magnetic.x, magnetic.z); + DisplayServerIPhone::get_singleton()->update_gyroscope(rotation.y, -rotation.x, rotation.z); + } break; + case UIInterfaceOrientationPortraitUpsideDown: { + DisplayServerIPhone::get_singleton()->update_gravity(-gravity.x, gravity.y, gravity.z); + DisplayServerIPhone::get_singleton()->update_accelerometer(-(acceleration.x + gravity.x), (acceleration.y + gravity.y), acceleration.z + gravity.z); + DisplayServerIPhone::get_singleton()->update_magnetometer(-magnetic.x, magnetic.y, magnetic.z); + DisplayServerIPhone::get_singleton()->update_gyroscope(-rotation.x, rotation.y, rotation.z); + } break; + default: { // assume portrait + DisplayServerIPhone::get_singleton()->update_gravity(gravity.x, gravity.y, gravity.z); + DisplayServerIPhone::get_singleton()->update_accelerometer(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z); + DisplayServerIPhone::get_singleton()->update_magnetometer(magnetic.x, magnetic.y, magnetic.z); + DisplayServerIPhone::get_singleton()->update_gyroscope(rotation.x, rotation.y, rotation.z); + } break; + } +} + +@end diff --git a/platform/iphone/godot_view_gesture_recognizer.h b/platform/iphone/godot_view_gesture_recognizer.h new file mode 100644 index 0000000000..ca3bd808d1 --- /dev/null +++ b/platform/iphone/godot_view_gesture_recognizer.h @@ -0,0 +1,44 @@ +/*************************************************************************/ +/* godot_view_gesture_recognizer.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +// GLViewGestureRecognizer allows iOS gestures to work currectly by +// emulating UIScrollView's UIScrollViewDelayedTouchesBeganGestureRecognizer. +// It catches all gestures incoming to UIView and delays them for 150ms +// (the same value used by UIScrollViewDelayedTouchesBeganGestureRecognizer) +// If touch cancelation or end message is fired it fires delayed +// begin touch immediately as well as last touch signal + +#import <UIKit/UIKit.h> + +@interface GodotViewGestureRecognizer : UIGestureRecognizer + +- (instancetype)init; + +@end diff --git a/platform/iphone/godot_view_gesture_recognizer.m b/platform/iphone/godot_view_gesture_recognizer.m new file mode 100644 index 0000000000..377ccd52a5 --- /dev/null +++ b/platform/iphone/godot_view_gesture_recognizer.m @@ -0,0 +1,171 @@ +/*************************************************************************/ +/* godot_view_gesture_recognizer.m */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import "godot_view_gesture_recognizer.h" + +// Using same delay interval that is used for `UIScrollView` +const NSTimeInterval kGLGestureDelayInterval = 0.150; + +// Minimum distance for touches to move to fire +// a delay timer before scheduled time. +// Should be the low enough to not cause issues with dragging +// but big enough to allow click to work. +const CGFloat kGLGestureMovementDistance = 0.5; + +@interface GodotViewGestureRecognizer () + +// Timer used to delay begin touch message. +// Should work as simple emulation of UIDelayedAction +@property(strong, nonatomic) NSTimer *delayTimer; + +// Delayed touch parameters +@property(strong, nonatomic) NSSet *delayedTouches; +@property(strong, nonatomic) UIEvent *delayedEvent; + +@end + +@implementation GodotViewGestureRecognizer + +- (instancetype)init { + self = [super init]; + + self.cancelsTouchesInView = YES; + self.delaysTouchesBegan = YES; + self.delaysTouchesEnded = YES; + + return self; +} + +- (void)dealloc { + if (self.delayTimer) { + [self.delayTimer invalidate]; + self.delayTimer = nil; + } + + if (self.delayedTouches) { + self.delayedTouches = nil; + } + + if (self.delayedEvent) { + self.delayedEvent = nil; + } + + [super dealloc]; +} + +- (void)delayTouches:(NSSet *)touches andEvent:(UIEvent *)event { + [self.delayTimer fire]; + + self.delayedTouches = touches; + self.delayedEvent = event; + + self.delayTimer = [NSTimer + scheduledTimerWithTimeInterval:kGLGestureDelayInterval + target:self + selector:@selector(fireDelayedTouches:) + userInfo:nil + repeats:NO]; +} + +- (void)fireDelayedTouches:(id)timer { + [self.delayTimer invalidate]; + self.delayTimer = nil; + + if (self.delayedTouches) { + [self.view touchesBegan:self.delayedTouches withEvent:self.delayedEvent]; + } + + self.delayedTouches = nil; + self.delayedEvent = nil; +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseBegan]; + [self delayTouches:cleared andEvent:event]; + [cleared release]; +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseMoved]; + + if (self.delayTimer) { + // We should check if movement was significant enough to fire an event + // for dragging to work correctly. + for (UITouch *touch in cleared) { + CGPoint from = [touch locationInView:self.view]; + CGPoint to = [touch previousLocationInView:self.view]; + CGFloat xDistance = from.x - to.x; + CGFloat yDistance = from.y - to.y; + + CGFloat distance = sqrt(xDistance * xDistance + yDistance * yDistance); + + // Early exit, since one of touches has moved enough to fire a drag event. + if (distance > kGLGestureMovementDistance) { + [self.delayTimer fire]; + [self.view touchesMoved:cleared withEvent:event]; + [cleared release]; + return; + } + } + + [cleared release]; + return; + } + + [self.view touchesMoved:cleared withEvent:event]; + [cleared release]; +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [self.delayTimer fire]; + + NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseEnded]; + [self.view touchesEnded:cleared withEvent:event]; + [cleared release]; +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + [self.delayTimer fire]; + [self.view touchesCancelled:touches withEvent:event]; +}; + +- (NSSet *)copyClearedTouches:(NSSet *)touches phase:(UITouchPhase)phaseToSave { + NSMutableSet *cleared = [touches mutableCopy]; + + for (UITouch *touch in touches) { + if (touch.phase != phaseToSave) { + [cleared removeObject:touch]; + } + } + + return cleared; +} + +@end diff --git a/modules/mono/editor/csharp_project.h b/platform/iphone/godot_view_renderer.h index 515b8d3d62..ea8998c808 100644 --- a/modules/mono/editor/csharp_project.h +++ b/platform/iphone/godot_view_renderer.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* csharp_project.h */ +/* godot_view_renderer.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,15 +28,17 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CSHARP_PROJECT_H -#define CSHARP_PROJECT_H +#import <UIKit/UIKit.h> -#include "core/ustring.h" +@protocol GodotViewRendererProtocol <NSObject> -namespace CSharpProject { +@property(assign, readonly, nonatomic) BOOL hasFinishedSetup; -void add_item(const String &p_project_path, const String &p_item_type, const String &p_include); +- (BOOL)setupView:(UIView *)view; +- (void)renderOnView:(UIView *)view; -} // namespace CSharpProject +@end -#endif // CSHARP_PROJECT_H +@interface GodotViewRenderer : NSObject <GodotViewRendererProtocol> + +@end diff --git a/platform/iphone/godot_view_renderer.mm b/platform/iphone/godot_view_renderer.mm new file mode 100644 index 0000000000..1fc822b457 --- /dev/null +++ b/platform/iphone/godot_view_renderer.mm @@ -0,0 +1,146 @@ +/*************************************************************************/ +/* godot_view_renderer.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import "godot_view_renderer.h" +#include "core/os/keyboard.h" +#include "core/project_settings.h" +#import "display_server_iphone.h" +#include "main/main.h" +#include "os_iphone.h" +#include "servers/audio_server.h" + +#import <AudioToolbox/AudioServices.h> +#import <CoreMotion/CoreMotion.h> +#import <GameController/GameController.h> +#import <QuartzCore/QuartzCore.h> +#import <UIKit/UIKit.h> + +@interface GodotViewRenderer () + +@property(assign, nonatomic) BOOL hasFinishedLocaleSetup; +@property(assign, nonatomic) BOOL hasFinishedProjectDataSetup; +@property(assign, nonatomic) BOOL hasStartedMain; +@property(assign, nonatomic) BOOL hasFinishedSetup; + +@end + +@implementation GodotViewRenderer + +- (BOOL)setupView:(UIView *)view { + if (self.hasFinishedSetup) { + return NO; + } + + if (!self.hasFinishedLocaleSetup) { + [self setupLocaleAndUUID]; + return YES; + } + + if (!self.hasFinishedProjectDataSetup) { + [self setupProjectData]; + return YES; + } + + if (!self.hasStartedMain) { + self.hasStartedMain = YES; + OSIPhone::get_singleton()->start(); + return YES; + } + + self.hasFinishedSetup = YES; + + return NO; +} + +- (void)setupLocaleAndUUID { + self.hasFinishedLocaleSetup = YES; + + if (!OS::get_singleton()) { + exit(0); + } + + NSString *locale_code = [[NSLocale currentLocale] localeIdentifier]; + OSIPhone::get_singleton()->set_locale(String::utf8([locale_code UTF8String])); + + NSString *uuid; + if ([[UIDevice currentDevice] respondsToSelector:@selector(identifierForVendor)]) { + uuid = [UIDevice currentDevice].identifierForVendor.UUIDString; + } else { + // before iOS 6, so just generate an identifier and store it + uuid = [[NSUserDefaults standardUserDefaults] objectForKey:@"identiferForVendor"]; + if (!uuid) { + CFUUIDRef cfuuid = CFUUIDCreate(NULL); + uuid = [(NSString *)CFUUIDCreateString(NULL, cfuuid) autorelease]; + CFRelease(cfuuid); + [[NSUserDefaults standardUserDefaults] setObject:uuid forKey:@"identifierForVendor"]; + } + } + + OSIPhone::get_singleton()->set_unique_id(String::utf8([uuid UTF8String])); +} + +- (void)setupProjectData { + self.hasFinishedProjectDataSetup = YES; + + Main::setup2(); + + // this might be necessary before here + NSDictionary *dict = [[NSBundle mainBundle] infoDictionary]; + for (NSString *key in dict) { + NSObject *value = [dict objectForKey:key]; + String ukey = String::utf8([key UTF8String]); + + // we need a NSObject to Variant conversor + + if ([value isKindOfClass:[NSString class]]) { + NSString *str = (NSString *)value; + String uval = String::utf8([str UTF8String]); + + ProjectSettings::get_singleton()->set("Info.plist/" + ukey, uval); + + } else if ([value isKindOfClass:[NSNumber class]]) { + NSNumber *n = (NSNumber *)value; + double dval = [n doubleValue]; + + ProjectSettings::get_singleton()->set("Info.plist/" + ukey, dval); + }; + // do stuff + } +} + +- (void)renderOnView:(UIView *)view { + if (!OSIPhone::get_singleton()) { + return; + } + + OSIPhone::get_singleton()->iterate(); +} + +@end diff --git a/platform/iphone/icloud.h b/platform/iphone/icloud.h index b11e22fec6..381edfa718 100644 --- a/platform/iphone/icloud.h +++ b/platform/iphone/icloud.h @@ -44,9 +44,9 @@ class ICloud : public Object { List<Variant> pending_events; public: - Error remove_key(Variant p_param); - Variant set_key_values(Variant p_param); - Variant get_key_value(Variant p_param); + Error remove_key(String p_param); + Array set_key_values(Dictionary p_params); + Variant get_key_value(String p_param); Error synchronize_key_values(); Variant get_all_key_values(); diff --git a/platform/iphone/icloud.mm b/platform/iphone/icloud.mm index c768274b1f..d3086e6cea 100644 --- a/platform/iphone/icloud.mm +++ b/platform/iphone/icloud.mm @@ -48,8 +48,10 @@ ICloud *ICloud::instance = NULL; void ICloud::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_key"), &ICloud::remove_key); + ClassDB::bind_method(D_METHOD("set_key_values"), &ICloud::set_key_values); ClassDB::bind_method(D_METHOD("get_key_value"), &ICloud::get_key_value); + ClassDB::bind_method(D_METHOD("synchronize_key_values"), &ICloud::synchronize_key_values); ClassDB::bind_method(D_METHOD("get_all_key_values"), &ICloud::get_all_key_values); @@ -91,7 +93,7 @@ Variant nsobject_to_variant(NSObject *object) { } else if ([object isKindOfClass:[NSArray class]]) { Array result; NSArray *array = (NSArray *)object; - for (unsigned int i = 0; i < [array count]; ++i) { + for (NSUInteger i = 0; i < [array count]; ++i) { NSObject *value = [array objectAtIndex:i]; result.push_back(nsobject_to_variant(value)); } @@ -149,7 +151,7 @@ Variant nsobject_to_variant(NSObject *object) { NSObject *variant_to_nsobject(Variant v) { if (v.get_type() == Variant::STRING) { return [[[NSString alloc] initWithUTF8String:((String)v).utf8().get_data()] autorelease]; - } else if (v.get_type() == Variant::REAL) { + } else if (v.get_type() == Variant::FLOAT) { return [NSNumber numberWithDouble:(double)v]; } else if (v.get_type() == Variant::INT) { return [NSNumber numberWithLongLong:(long)(int)v]; @@ -159,7 +161,7 @@ NSObject *variant_to_nsobject(Variant v) { NSMutableDictionary *result = [[[NSMutableDictionary alloc] init] autorelease]; Dictionary dic = v; Array keys = dic.keys(); - for (unsigned int i = 0; i < keys.size(); ++i) { + for (int i = 0; i < keys.size(); ++i) { NSString *key = [[[NSString alloc] initWithUTF8String:((String)(keys[i])).utf8().get_data()] autorelease]; NSObject *value = variant_to_nsobject(dic[keys[i]]); @@ -173,7 +175,7 @@ NSObject *variant_to_nsobject(Variant v) { } else if (v.get_type() == Variant::ARRAY) { NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease]; Array arr = v; - for (unsigned int i = 0; i < arr.size(); ++i) { + for (int i = 0; i < arr.size(); ++i) { NSObject *value = variant_to_nsobject(arr[i]); if (value == NULL) { //trying to add something unsupported to the array. cancel the whole array @@ -192,9 +194,8 @@ NSObject *variant_to_nsobject(Variant v) { return NULL; } -Error ICloud::remove_key(Variant p_param) { - String param = p_param; - NSString *key = [[[NSString alloc] initWithUTF8String:param.utf8().get_data()] autorelease]; +Error ICloud::remove_key(String p_param) { + NSString *key = [[[NSString alloc] initWithUTF8String:p_param.utf8().get_data()] autorelease]; NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore]; @@ -207,15 +208,14 @@ Error ICloud::remove_key(Variant p_param) { } //return an array of the keys that could not be set -Variant ICloud::set_key_values(Variant p_params) { - Dictionary params = p_params; - Array keys = params.keys(); +Array ICloud::set_key_values(Dictionary p_params) { + Array keys = p_params.keys(); Array error_keys; - for (unsigned int i = 0; i < keys.size(); ++i) { + for (int i = 0; i < keys.size(); ++i) { String variant_key = keys[i]; - Variant variant_value = params[variant_key]; + Variant variant_value = p_params[variant_key]; NSString *key = [[[NSString alloc] initWithUTF8String:variant_key.utf8().get_data()] autorelease]; if (key == NULL) { @@ -237,10 +237,8 @@ Variant ICloud::set_key_values(Variant p_params) { return error_keys; } -Variant ICloud::get_key_value(Variant p_param) { - String param = p_param; - - NSString *key = [[[NSString alloc] initWithUTF8String:param.utf8().get_data()] autorelease]; +Variant ICloud::get_key_value(String p_param) { + NSString *key = [[[NSString alloc] initWithUTF8String:p_param.utf8().get_data()] autorelease]; NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore]; if (![[store dictionaryRepresentation] objectForKey:key]) { diff --git a/platform/iphone/in_app_store.h b/platform/iphone/in_app_store.h index 44e65e77ed..beb58af2c7 100644 --- a/platform/iphone/in_app_store.h +++ b/platform/iphone/in_app_store.h @@ -44,9 +44,9 @@ class InAppStore : public Object { List<Variant> pending_events; public: - Error request_product_info(Variant p_params); + Error request_product_info(Dictionary p_params); Error restore_purchases(); - Error purchase(Variant p_params); + Error purchase(Dictionary p_params); int get_pending_event_count(); Variant pop_pending_event(); diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm index 548dcc549d..dfec5d7634 100644 --- a/platform/iphone/in_app_store.mm +++ b/platform/iphone/in_app_store.mm @@ -39,8 +39,10 @@ extern "C" { bool auto_finish_transactions = true; NSMutableDictionary *pending_transactions = [NSMutableDictionary dictionary]; +static NSArray *latestProducts; @interface SKProduct (LocalizedPrice) + @property(nonatomic, readonly) NSString *localizedPrice; @end @@ -82,6 +84,8 @@ void InAppStore::_bind_methods() { - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response { NSArray *products = response.products; + latestProducts = products; + Dictionary ret; ret["type"] = "product_info"; ret["result"] = "ok"; @@ -126,11 +130,10 @@ void InAppStore::_bind_methods() { @end -Error InAppStore::request_product_info(Variant p_params) { - Dictionary params = p_params; - ERR_FAIL_COND_V(!params.has("product_ids"), ERR_INVALID_PARAMETER); +Error InAppStore::request_product_info(Dictionary p_params) { + ERR_FAIL_COND_V(!p_params.has("product_ids"), ERR_INVALID_PARAMETER); - PackedStringArray pids = params["product_ids"]; + PackedStringArray pids = p_params["product_ids"]; printf("************ request product info! %i\n", pids.size()); NSMutableArray *array = [[[NSMutableArray alloc] initWithCapacity:pids.size()] autorelease]; @@ -198,11 +201,11 @@ Error InAppStore::restore_purchases() { // which is still available in iOS 7. // Use SKPaymentTransaction's transactionReceipt. - receipt = transaction.transactionReceipt; + receipt = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]]; } } else { - receipt = transaction.transactionReceipt; + receipt = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]]; } NSString *receipt_to_send = nil; @@ -254,17 +257,32 @@ Error InAppStore::restore_purchases() { @end -Error InAppStore::purchase(Variant p_params) { +Error InAppStore::purchase(Dictionary p_params) { ERR_FAIL_COND_V(![SKPaymentQueue canMakePayments], ERR_UNAVAILABLE); if (![SKPaymentQueue canMakePayments]) return ERR_UNAVAILABLE; printf("purchasing!\n"); - Dictionary params = p_params; - ERR_FAIL_COND_V(!params.has("product_id"), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!p_params.has("product_id"), ERR_INVALID_PARAMETER); + + NSString *pid = [[[NSString alloc] initWithUTF8String:String(p_params["product_id"]).utf8().get_data()] autorelease]; + + SKProduct *product = nil; + + if (latestProducts) { + for (SKProduct *storedProduct in latestProducts) { + if ([storedProduct.productIdentifier isEqualToString:pid]) { + product = storedProduct; + break; + } + } + } + + if (!product) { + return ERR_INVALID_PARAMETER; + } - NSString *pid = [[[NSString alloc] initWithUTF8String:String(params["product_id"]).utf8().get_data()] autorelease]; - SKPayment *payment = [SKPayment paymentWithProductIdentifier:pid]; + SKPayment *payment = [SKPayment paymentWithProduct:product]; SKPaymentQueue *defq = [SKPaymentQueue defaultQueue]; [defq addPayment:payment]; printf("purchase sent!\n"); diff --git a/platform/iphone/ios.mm b/platform/iphone/ios.mm index 5923f558a5..ad26d0ada3 100644 --- a/platform/iphone/ios.mm +++ b/platform/iphone/ios.mm @@ -29,17 +29,27 @@ /*************************************************************************/ #include "ios.h" -#include <sys/sysctl.h> - +#import "app_delegate.h" #import <UIKit/UIKit.h> +#include <sys/sysctl.h> void iOS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_rate_url", "app_id"), &iOS::get_rate_url); }; void iOS::alert(const char *p_alert, const char *p_title) { - UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:[NSString stringWithUTF8String:p_title] message:[NSString stringWithUTF8String:p_alert] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] autorelease]; - [alert show]; + NSString *title = [NSString stringWithUTF8String:p_title]; + NSString *message = [NSString stringWithUTF8String:p_alert]; + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *button = [UIAlertAction actionWithTitle:@"OK" + style:UIAlertActionStyleCancel + handler:^(id){ + }]; + + [alert addAction:button]; + + [AppDelegate.viewController presentViewController:alert animated:YES completion:nil]; } String iOS::get_model() const { diff --git a/main/tests/test_astar.h b/platform/iphone/joypad_iphone.h index 0992812c18..85e26e1dc8 100644 --- a/main/tests/test_astar.h +++ b/platform/iphone/joypad_iphone.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* test_astar.h */ +/* joypad_iphone.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,14 +28,23 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef TEST_ASTAR_H -#define TEST_ASTAR_H +#import <GameController/GameController.h> -#include "core/os/main_loop.h" +@interface JoypadIPhoneObserver : NSObject -namespace TestAStar { +- (void)startObserving; +- (void)startProcessing; +- (void)finishObserving; -MainLoop *test(); -} +@end -#endif +class JoypadIPhone { +private: + JoypadIPhoneObserver *observer; + +public: + JoypadIPhone(); + ~JoypadIPhone(); + + void start_processing(); +}; diff --git a/platform/iphone/joypad_iphone.mm b/platform/iphone/joypad_iphone.mm new file mode 100644 index 0000000000..6088f1c25c --- /dev/null +++ b/platform/iphone/joypad_iphone.mm @@ -0,0 +1,380 @@ +/*************************************************************************/ +/* joypad_iphone.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import "joypad_iphone.h" +#include "core/project_settings.h" +#include "drivers/coreaudio/audio_driver_coreaudio.h" +#include "main/main.h" + +#import "godot_view.h" + +#include "os_iphone.h" + +JoypadIPhone::JoypadIPhone() { + observer = [[JoypadIPhoneObserver alloc] init]; + [observer startObserving]; +} + +JoypadIPhone::~JoypadIPhone() { + if (observer) { + [observer finishObserving]; + observer = nil; + } +} + +void JoypadIPhone::start_processing() { + if (observer) { + [observer startProcessing]; + } +} + +@interface JoypadIPhoneObserver () + +@property(assign, nonatomic) BOOL isObserving; +@property(assign, nonatomic) BOOL isProcessing; +@property(strong, nonatomic) NSMutableDictionary *connectedJoypads; +@property(strong, nonatomic) NSMutableArray *joypadsQueue; + +@end + +@implementation JoypadIPhoneObserver + +- (instancetype)init { + self = [super init]; + + if (self) { + [self godot_commonInit]; + } + + return self; +} + +- (void)godot_commonInit { + self.isObserving = NO; + self.isProcessing = NO; +} + +- (void)startProcessing { + self.isProcessing = YES; + + for (GCController *controller in self.joypadsQueue) { + [self addiOSJoypad:controller]; + } + + [self.joypadsQueue removeAllObjects]; +} + +- (void)startObserving { + if (self.isObserving) { + return; + } + + self.isObserving = YES; + + self.connectedJoypads = [NSMutableDictionary dictionary]; + self.joypadsQueue = [NSMutableArray array]; + + // get told when controllers connect, this will be called right away for + // already connected controllers + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(controllerWasConnected:) + name:GCControllerDidConnectNotification + object:nil]; + + // get told when controllers disconnect + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(controllerWasDisconnected:) + name:GCControllerDidDisconnectNotification + object:nil]; +} + +- (void)finishObserving { + if (self.isObserving) { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + } + + self.isObserving = NO; + self.isProcessing = NO; + + self.connectedJoypads = nil; + self.joypadsQueue = nil; +} + +- (void)dealloc { + [self finishObserving]; + + [super dealloc]; +} + +- (int)getJoyIdForController:(GCController *)controller { + NSArray *keys = [self.connectedJoypads allKeysForObject:controller]; + + for (NSNumber *key in keys) { + int joy_id = [key intValue]; + return joy_id; + }; + + return -1; +}; + +- (void)addiOSJoypad:(GCController *)controller { + // get a new id for our controller + int joy_id = Input::get_singleton()->get_unused_joy_id(); + + if (joy_id == -1) { + printf("Couldn't retrieve new joy id\n"); + return; + } + + // assign our player index + if (controller.playerIndex == GCControllerPlayerIndexUnset) { + controller.playerIndex = [self getFreePlayerIndex]; + }; + + // tell Godot about our new controller + Input::get_singleton()->joy_connection_changed(joy_id, true, [controller.vendorName UTF8String]); + + // add it to our dictionary, this will retain our controllers + [self.connectedJoypads setObject:controller forKey:[NSNumber numberWithInt:joy_id]]; + + // set our input handler + [self setControllerInputHandler:controller]; +} + +- (void)controllerWasConnected:(NSNotification *)notification { + // get our controller + GCController *controller = (GCController *)notification.object; + + if (!controller) { + printf("Couldn't retrieve new controller\n"); + return; + } + + if ([[self.connectedJoypads allKeysForObject:controller] count] > 0) { + printf("Controller is already registered\n"); + } else if (!self.isProcessing) { + [self.joypadsQueue addObject:controller]; + } else { + [self addiOSJoypad:controller]; + } +} + +- (void)controllerWasDisconnected:(NSNotification *)notification { + // find our joystick, there should be only one in our dictionary + GCController *controller = (GCController *)notification.object; + + if (!controller) { + return; + } + + NSArray *keys = [self.connectedJoypads allKeysForObject:controller]; + for (NSNumber *key in keys) { + // tell Godot this joystick is no longer there + int joy_id = [key intValue]; + Input::get_singleton()->joy_connection_changed(joy_id, false, ""); + + // and remove it from our dictionary + [self.connectedJoypads removeObjectForKey:key]; + }; +}; + +- (GCControllerPlayerIndex)getFreePlayerIndex { + bool have_player_1 = false; + bool have_player_2 = false; + bool have_player_3 = false; + bool have_player_4 = false; + + if (self.connectedJoypads == nil) { + NSArray *keys = [self.connectedJoypads allKeys]; + for (NSNumber *key in keys) { + GCController *controller = [self.connectedJoypads objectForKey:key]; + if (controller.playerIndex == GCControllerPlayerIndex1) { + have_player_1 = true; + } else if (controller.playerIndex == GCControllerPlayerIndex2) { + have_player_2 = true; + } else if (controller.playerIndex == GCControllerPlayerIndex3) { + have_player_3 = true; + } else if (controller.playerIndex == GCControllerPlayerIndex4) { + have_player_4 = true; + }; + }; + }; + + if (!have_player_1) { + return GCControllerPlayerIndex1; + } else if (!have_player_2) { + return GCControllerPlayerIndex2; + } else if (!have_player_3) { + return GCControllerPlayerIndex3; + } else if (!have_player_4) { + return GCControllerPlayerIndex4; + } else { + return GCControllerPlayerIndexUnset; + }; +} + +- (void)setControllerInputHandler:(GCController *)controller { + // Hook in the callback handler for the correct gamepad profile. + // This is a bit of a weird design choice on Apples part. + // You need to select the most capable gamepad profile for the + // gamepad attached. + if (controller.extendedGamepad != nil) { + // The extended gamepad profile has all the input you could possibly find on + // a gamepad but will only be active if your gamepad actually has all of + // these... + controller.extendedGamepad.valueChangedHandler = ^( + GCExtendedGamepad *gamepad, GCControllerElement *element) { + int joy_id = [self getJoyIdForController:controller]; + + if (element == gamepad.buttonA) { + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_A, + gamepad.buttonA.isPressed); + } else if (element == gamepad.buttonB) { + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_B, + gamepad.buttonB.isPressed); + } else if (element == gamepad.buttonX) { + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_X, + gamepad.buttonX.isPressed); + } else if (element == gamepad.buttonY) { + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_Y, + gamepad.buttonY.isPressed); + } else if (element == gamepad.leftShoulder) { + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_LEFT_SHOULDER, + gamepad.leftShoulder.isPressed); + } else if (element == gamepad.rightShoulder) { + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_RIGHT_SHOULDER, + gamepad.rightShoulder.isPressed); + } else if (element == gamepad.dpad) { + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_UP, + gamepad.dpad.up.isPressed); + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_DOWN, + gamepad.dpad.down.isPressed); + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_LEFT, + gamepad.dpad.left.isPressed); + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_RIGHT, + gamepad.dpad.right.isPressed); + }; + + Input::JoyAxis jx; + jx.min = -1; + if (element == gamepad.leftThumbstick) { + jx.value = gamepad.leftThumbstick.xAxis.value; + Input::get_singleton()->joy_axis(joy_id, JOY_AXIS_LEFT_X, jx); + jx.value = -gamepad.leftThumbstick.yAxis.value; + Input::get_singleton()->joy_axis(joy_id, JOY_AXIS_LEFT_Y, jx); + } else if (element == gamepad.rightThumbstick) { + jx.value = gamepad.rightThumbstick.xAxis.value; + Input::get_singleton()->joy_axis(joy_id, JOY_AXIS_RIGHT_X, jx); + jx.value = -gamepad.rightThumbstick.yAxis.value; + Input::get_singleton()->joy_axis(joy_id, JOY_AXIS_RIGHT_Y, jx); + } else if (element == gamepad.leftTrigger) { + jx.value = gamepad.leftTrigger.value; + Input::get_singleton()->joy_axis(joy_id, JOY_AXIS_TRIGGER_LEFT, jx); + } else if (element == gamepad.rightTrigger) { + jx.value = gamepad.rightTrigger.value; + Input::get_singleton()->joy_axis(joy_id, JOY_AXIS_TRIGGER_RIGHT, jx); + }; + }; + } + // else if (controller.gamepad != nil) { + // // gamepad is the standard profile with 4 buttons, shoulder buttons and a + // // D-pad + // controller.gamepad.valueChangedHandler = ^(GCGamepad *gamepad, + // GCControllerElement *element) { + // int joy_id = [self getJoyIdForController:controller]; + // + // if (element == gamepad.buttonA) { + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_A, + // gamepad.buttonA.isPressed); + // } else if (element == gamepad.buttonB) { + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_B, + // gamepad.buttonB.isPressed); + // } else if (element == gamepad.buttonX) { + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_X, + // gamepad.buttonX.isPressed); + // } else if (element == gamepad.buttonY) { + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_Y, + // gamepad.buttonY.isPressed); + // } else if (element == gamepad.leftShoulder) { + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_LEFT_SHOULDER, + // gamepad.leftShoulder.isPressed); + // } else if (element == gamepad.rightShoulder) { + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_RIGHT_SHOULDER, + // gamepad.rightShoulder.isPressed); + // } else if (element == gamepad.dpad) { + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_UP, + // gamepad.dpad.up.isPressed); + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_DOWN, + // gamepad.dpad.down.isPressed); + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_LEFT, + // gamepad.dpad.left.isPressed); + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_RIGHT, + // gamepad.dpad.right.isPressed); + // }; + // }; + //#ifdef ADD_MICRO_GAMEPAD // disabling this for now, only available on iOS 9+, + // // while we are setting that as the minimum, seems our + // // build environment doesn't like it + // } else if (controller.microGamepad != nil) { + // // micro gamepads were added in OS 9 and feature just 2 buttons and a d-pad + // controller.microGamepad.valueChangedHandler = + // ^(GCMicroGamepad *gamepad, GCControllerElement *element) { + // int joy_id = [self getJoyIdForController:controller]; + // + // if (element == gamepad.buttonA) { + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_A, + // gamepad.buttonA.isPressed); + // } else if (element == gamepad.buttonX) { + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_X, + // gamepad.buttonX.isPressed); + // } else if (element == gamepad.dpad) { + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_UP, + // gamepad.dpad.up.isPressed); + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_DOWN, + // gamepad.dpad.down.isPressed); + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_LEFT, + // gamepad.dpad.left.isPressed); + // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_RIGHT, + // gamepad.dpad.right.isPressed); + // }; + // }; + //#endif + // }; + + ///@TODO need to add support for controller.motion which gives us access to + /// the orientation of the device (if supported) + + ///@TODO need to add support for controllerPausedHandler which should be a + /// toggle +}; + +@end diff --git a/platform/iphone/main.m b/platform/iphone/main.m index 164db2a74b..c292f02822 100644 --- a/platform/iphone/main.m +++ b/platform/iphone/main.m @@ -32,20 +32,25 @@ #import <UIKit/UIKit.h> #include <stdio.h> +#include <vulkan/vulkan.h> int gargc; char **gargv; int main(int argc, char *argv[]) { +#if defined(VULKAN_ENABLED) + //MoltenVK - enable full component swizzling support + setenv("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE", "1", 1); +#endif + printf("*********** main.m\n"); gargc = argc; gargv = argv; - NSAutoreleasePool *pool = [NSAutoreleasePool new]; - AppDelegate *app = [AppDelegate alloc]; printf("running app main\n"); - UIApplicationMain(argc, argv, nil, @"AppDelegate"); - printf("main done, pool release\n"); - [pool release]; + @autoreleasepool { + UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } + printf("main done\n"); return 0; } diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp deleted file mode 100644 index 41dd623e69..0000000000 --- a/platform/iphone/os_iphone.cpp +++ /dev/null @@ -1,632 +0,0 @@ -/*************************************************************************/ -/* os_iphone.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef IPHONE_ENABLED - -#include "os_iphone.h" - -#if defined(OPENGL_ENABLED) -#include "drivers/gles2/rasterizer_gles2.h" -#endif - -#if defined(VULKAN_ENABLED) -#include "servers/rendering/rasterizer_rd/rasterizer_rd.h" -// #import <QuartzCore/CAMetalLayer.h> -#include <vulkan/vulkan_metal.h> -#endif - -#include "servers/rendering/rendering_server_raster.h" -#include "servers/rendering/rendering_server_wrap_mt.h" - -#include "main/main.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 "drivers/unix/syslog_logger.h" - -#include "semaphore_iphone.h" - -#include <dlfcn.h> - -int OSIPhone::get_video_driver_count() const { - return 2; -}; - -const char *OSIPhone::get_video_driver_name(int p_driver) const { - switch (p_driver) { - case VIDEO_DRIVER_GLES2: - return "GLES2"; - } - ERR_FAIL_V_MSG(nullptr, "Invalid video driver index: " + itos(p_driver) + "."); -}; - -OSIPhone *OSIPhone::get_singleton() { - return (OSIPhone *)OS::get_singleton(); -}; - -extern int gl_view_base_fb; // from gl_view.mm - -void OSIPhone::set_data_dir(String p_dir) { - DirAccess *da = DirAccess::open(p_dir); - - data_dir = da->get_current_dir(); - printf("setting data dir to %ls from %ls\n", data_dir.c_str(), p_dir.c_str()); - memdelete(da); -}; - -void OSIPhone::set_unique_id(String p_id) { - unique_id = p_id; -}; - -String OSIPhone::get_unique_id() const { - return unique_id; -}; - -void OSIPhone::initialize_core() { - OS_Unix::initialize_core(); - - set_data_dir(data_dir); -}; - -int OSIPhone::get_current_video_driver() const { - return video_driver_index; -} - -Error OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { - video_driver_index = p_video_driver; - -#if defined(OPENGL_ENABLED) - bool gl_initialization_error = false; - - // FIXME: Add Vulkan support via MoltenVK. Add fallback code back? - - if (RasterizerGLES2::is_viable() == OK) { - RasterizerGLES2::register_config(); - RasterizerGLES2::make_current(); - } else { - gl_initialization_error = true; - } - - if (gl_initialization_error) { - OS::get_singleton()->alert("Your device does not support any of the supported OpenGL versions.", - "Unable to initialize video driver"); - return ERR_UNAVAILABLE; - } -#endif - -#if defined(VULKAN_ENABLED) - RasterizerRD::make_current(); -#endif - - rendering_server = memnew(RenderingServerRaster); - // FIXME: Reimplement threaded rendering - if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) { - rendering_server = memnew(RenderingServerWrapMT(rendering_server, false)); - } - rendering_server->init(); - //rendering_server->cursor_set_visible(false, 0); - -#if defined(OPENGL_ENABLED) - // reset this to what it should be, it will have been set to 0 after rendering_server->init() is called - RasterizerStorageGLES2::system_fbo = gl_view_base_fb; -#endif - - AudioDriverManager::initialize(p_audio_driver); - - input = memnew(InputDefault); - -#ifdef GAME_CENTER_ENABLED - game_center = memnew(GameCenter); - Engine::get_singleton()->add_singleton(Engine::Singleton("GameCenter", game_center)); - game_center->connect(); -#endif - -#ifdef STOREKIT_ENABLED - store_kit = memnew(InAppStore); - Engine::get_singleton()->add_singleton(Engine::Singleton("InAppStore", store_kit)); -#endif - -#ifdef ICLOUD_ENABLED - icloud = memnew(ICloud); - Engine::get_singleton()->add_singleton(Engine::Singleton("ICloud", icloud)); - //icloud->connect(); -#endif - ios = memnew(iOS); - Engine::get_singleton()->add_singleton(Engine::Singleton("iOS", ios)); - - return OK; -}; - -MainLoop *OSIPhone::get_main_loop() const { - return main_loop; -}; - -void OSIPhone::set_main_loop(MainLoop *p_main_loop) { - main_loop = p_main_loop; - - if (main_loop) { - input->set_main_loop(p_main_loop); - main_loop->init(); - } -}; - -bool OSIPhone::iterate() { - if (!main_loop) - return true; - - if (main_loop) { - for (int i = 0; i < event_count; i++) { - input->parse_input_event(event_queue[i]); - }; - }; - event_count = 0; - - return Main::iteration(); -}; - -void OSIPhone::key(uint32_t p_key, bool p_pressed) { - Ref<InputEventKey> ev; - ev.instance(); - ev->set_echo(false); - ev->set_pressed(p_pressed); - ev->set_keycode(p_key); - ev->set_physical_keycode(p_key); - ev->set_unicode(p_key); - queue_event(ev); -}; - -void OSIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick) { - if (!GLOBAL_DEF("debug/disable_touch", false)) { - Ref<InputEventScreenTouch> ev; - ev.instance(); - - ev->set_index(p_idx); - ev->set_pressed(p_pressed); - ev->set_position(Vector2(p_x, p_y)); - queue_event(ev); - }; - - touch_list.pressed[p_idx] = p_pressed; -}; - -void OSIPhone::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) { - if (!GLOBAL_DEF("debug/disable_touch", false)) { - Ref<InputEventScreenDrag> ev; - ev.instance(); - ev->set_index(p_idx); - ev->set_position(Vector2(p_x, p_y)); - ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y)); - queue_event(ev); - }; -}; - -void OSIPhone::queue_event(const Ref<InputEvent> &p_event) { - ERR_FAIL_INDEX(event_count, MAX_EVENTS); - - event_queue[event_count++] = p_event; -}; - -void OSIPhone::touches_cancelled() { - for (int i = 0; i < MAX_MOUSE_COUNT; i++) { - if (touch_list.pressed[i]) { - // send a mouse_up outside the screen - touch_press(i, -1, -1, false, false); - }; - }; -}; - -static const float ACCEL_RANGE = 1; - -void OSIPhone::update_gravity(float p_x, float p_y, float p_z) { - input->set_gravity(Vector3(p_x, p_y, p_z)); -}; - -void OSIPhone::update_accelerometer(float p_x, float p_y, float p_z) { - // Found out the Z should not be negated! Pass as is! - input->set_accelerometer(Vector3(p_x / (float)ACCEL_RANGE, p_y / (float)ACCEL_RANGE, p_z / (float)ACCEL_RANGE)); - - /* - if (p_x != last_accel.x) { - //printf("updating accel x %f\n", p_x); - InputEvent ev; - ev.type = InputEvent::JOYPAD_MOTION; - ev.device = 0; - ev.joy_motion.axis = JOY_ANALOG_0; - ev.joy_motion.axis_value = (p_x / (float)ACCEL_RANGE); - last_accel.x = p_x; - queue_event(ev); - }; - if (p_y != last_accel.y) { - //printf("updating accel y %f\n", p_y); - InputEvent ev; - ev.type = InputEvent::JOYPAD_MOTION; - ev.device = 0; - ev.joy_motion.axis = JOY_ANALOG_1; - ev.joy_motion.axis_value = (p_y / (float)ACCEL_RANGE); - last_accel.y = p_y; - queue_event(ev); - }; - if (p_z != last_accel.z) { - //printf("updating accel z %f\n", p_z); - InputEvent ev; - ev.type = InputEvent::JOYPAD_MOTION; - ev.device = 0; - ev.joy_motion.axis = JOY_ANALOG_2; - ev.joy_motion.axis_value = ( (1.0 - p_z) / (float)ACCEL_RANGE); - last_accel.z = p_z; - queue_event(ev); - }; - */ -}; - -void OSIPhone::update_magnetometer(float p_x, float p_y, float p_z) { - input->set_magnetometer(Vector3(p_x, p_y, p_z)); -}; - -void OSIPhone::update_gyroscope(float p_x, float p_y, float p_z) { - input->set_gyroscope(Vector3(p_x, p_y, p_z)); -}; - -int OSIPhone::get_unused_joy_id() { - return input->get_unused_joy_id(); -}; - -void OSIPhone::joy_connection_changed(int p_idx, bool p_connected, String p_name) { - input->joy_connection_changed(p_idx, p_connected, p_name); -}; - -void OSIPhone::joy_button(int p_device, int p_button, bool p_pressed) { - input->joy_button(p_device, p_button, p_pressed); -}; - -void OSIPhone::joy_axis(int p_device, int p_axis, const InputDefault::JoyAxis &p_value) { - input->joy_axis(p_device, p_axis, p_value); -}; - -void OSIPhone::delete_main_loop() { - if (main_loop) { - main_loop->finish(); - memdelete(main_loop); - }; - - main_loop = nullptr; -}; - -void OSIPhone::finalize() { - delete_main_loop(); - - memdelete(input); - memdelete(ios); - -#ifdef GAME_CENTER_ENABLED - memdelete(game_center); -#endif - -#ifdef STOREKIT_ENABLED - memdelete(store_kit); -#endif - -#ifdef ICLOUD_ENABLED - memdelete(icloud); -#endif - - rendering_server->finish(); - memdelete(rendering_server); - // memdelete(rasterizer); - - // Free unhandled events before close - for (int i = 0; i < MAX_EVENTS; i++) { - event_queue[i].unref(); - }; - event_count = 0; -}; - -void OSIPhone::set_mouse_show(bool p_show) {} -void OSIPhone::set_mouse_grab(bool p_grab) {} - -bool OSIPhone::is_mouse_grab_enabled() const { - return true; -}; - -Point2 OSIPhone::get_mouse_position() const { - return Point2(); -}; - -int OSIPhone::get_mouse_button_state() const { - return 0; -}; - -void OSIPhone::set_window_title(const String &p_title) {} - -void OSIPhone::alert(const String &p_alert, const String &p_title) { - const CharString utf8_alert = p_alert.utf8(); - const CharString utf8_title = p_title.utf8(); - iOS::alert(utf8_alert.get_data(), utf8_title.get_data()); -} - -Error OSIPhone::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { - if (p_path.length() == 0) { - p_library_handle = RTLD_SELF; - return OK; - } - return OS_Unix::open_dynamic_library(p_path, p_library_handle, p_also_set_library_path); -} - -Error OSIPhone::close_dynamic_library(void *p_library_handle) { - if (p_library_handle == RTLD_SELF) { - return OK; - } - return OS_Unix::close_dynamic_library(p_library_handle); -} - -HashMap<String, void *> OSIPhone::dynamic_symbol_lookup_table; -void register_dynamic_symbol(char *name, void *address) { - OSIPhone::dynamic_symbol_lookup_table[String(name)] = address; -} - -Error OSIPhone::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) { - if (p_library_handle == RTLD_SELF) { - void **ptr = OSIPhone::dynamic_symbol_lookup_table.getptr(p_name); - if (ptr) { - p_symbol_handle = *ptr; - return OK; - } - } - return OS_Unix::get_dynamic_library_symbol_handle(p_library_handle, p_name, p_symbol_handle, p_optional); -} - -void OSIPhone::set_video_mode(const VideoMode &p_video_mode, int p_screen) { - video_mode = p_video_mode; -}; - -OS::VideoMode OSIPhone::get_video_mode(int p_screen) const { - return video_mode; -}; - -void OSIPhone::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const { - p_list->push_back(video_mode); -}; - -bool OSIPhone::can_draw() const { - if (native_video_is_playing()) - return false; - return true; -}; - -int OSIPhone::set_base_framebuffer(int p_fb) { -#if defined(OPENGL_ENABLED) - // gl_view_base_fb has not been updated yet - RasterizerStorageGLES2::system_fbo = p_fb; -#endif - - return 0; -}; - -bool OSIPhone::has_virtual_keyboard() const { - return true; -}; - -extern void _show_keyboard(String p_existing); -extern void _hide_keyboard(); -extern Error _shell_open(String p_uri); -extern void _set_keep_screen_on(bool p_enabled); -extern void _vibrate(); - -void OSIPhone::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length, int p_cursor_start, int p_cursor_end) { - _show_keyboard(p_existing_text); -}; - -void OSIPhone::hide_virtual_keyboard() { - _hide_keyboard(); -}; - -void OSIPhone::set_virtual_keyboard_height(int p_height) { - virtual_keyboard_height = p_height; -} - -int OSIPhone::get_virtual_keyboard_height() const { - return virtual_keyboard_height; -} - -Error OSIPhone::shell_open(String p_uri) { - return _shell_open(p_uri); -}; - -void OSIPhone::set_keep_screen_on(bool p_enabled) { - OS::set_keep_screen_on(p_enabled); - _set_keep_screen_on(p_enabled); -}; - -String OSIPhone::get_user_data_dir() const { - return data_dir; -}; - -String OSIPhone::get_name() const { - return "iOS"; -}; - -String OSIPhone::get_model_name() const { - String model = ios->get_model(); - if (model != "") - return model; - - return OS_Unix::get_model_name(); -} - -Size2 OSIPhone::get_window_size() const { - return Vector2(video_mode.width, video_mode.height); -} - -extern Rect2 _get_ios_window_safe_area(float p_window_width, float p_window_height); - -Rect2 OSIPhone::get_window_safe_area() const { - return _get_ios_window_safe_area(video_mode.width, video_mode.height); -} - -bool OSIPhone::has_touchscreen_ui_hint() const { - return true; -} - -void OSIPhone::set_locale(String p_locale) { - locale_code = p_locale; -} - -String OSIPhone::get_locale() const { - return locale_code; -} - -extern bool _play_video(String p_path, float p_volume, String p_audio_track, String p_subtitle_track); -extern bool _is_video_playing(); -extern void _pause_video(); -extern void _unpause_video(); -extern void _stop_video(); -extern void _focus_out_video(); - -Error OSIPhone::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - bool exists = f && f->is_open(); - - String tempFile = get_user_data_dir(); - if (!exists) - return FAILED; - - if (p_path.begins_with("res://")) { - if (PackedData::get_singleton()->has_path(p_path)) { - 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:/", ProjectSettings::get_singleton()->get_resource_path()); - } - } else if (p_path.begins_with("user://")) - p_path = p_path.replace("user:/", get_user_data_dir()); - - memdelete(f); - - print("Playing video: %S\n", p_path.c_str()); - if (_play_video(p_path, p_volume, p_audio_track, p_subtitle_track)) - return OK; - return FAILED; -} - -bool OSIPhone::native_video_is_playing() const { - return _is_video_playing(); -} - -void OSIPhone::native_video_pause() { - if (native_video_is_playing()) - _pause_video(); -} - -void OSIPhone::native_video_unpause() { - _unpause_video(); -}; - -void OSIPhone::native_video_focus_out() { - _focus_out_video(); -}; - -void OSIPhone::native_video_stop() { - if (native_video_is_playing()) - _stop_video(); -} - -void OSIPhone::vibrate_handheld(int p_duration_ms) { - // iOS does not support duration for vibration - _vibrate(); -} - -bool OSIPhone::_check_internal_feature_support(const String &p_feature) { - return p_feature == "mobile"; -} - -// Initialization order between compilation units is not guaranteed, -// so we use this as a hack to ensure certain code is called before -// everything else, but after all units are initialized. -typedef void (*init_callback)(); -static init_callback *ios_init_callbacks = nullptr; -static int ios_init_callbacks_count = 0; -static int ios_init_callbacks_capacity = 0; - -void add_ios_init_callback(init_callback cb) { - if (ios_init_callbacks_count == ios_init_callbacks_capacity) { - void *new_ptr = realloc(ios_init_callbacks, sizeof(cb) * 32); - if (new_ptr) { - ios_init_callbacks = (init_callback *)(new_ptr); - ios_init_callbacks_capacity += 32; - } - } - if (ios_init_callbacks_capacity > ios_init_callbacks_count) { - ios_init_callbacks[ios_init_callbacks_count] = cb; - ++ios_init_callbacks_count; - } -} - -OSIPhone::OSIPhone(int width, int height, String p_data_dir) { - for (int i = 0; i < ios_init_callbacks_count; ++i) { - ios_init_callbacks[i](); - } - free(ios_init_callbacks); - ios_init_callbacks = nullptr; - ios_init_callbacks_count = 0; - ios_init_callbacks_capacity = 0; - - main_loop = nullptr; - rendering_server = nullptr; - - VideoMode vm; - vm.fullscreen = true; - vm.width = width; - vm.height = height; - vm.resizable = false; - set_video_mode(vm); - event_count = 0; - virtual_keyboard_height = 0; - - // can't call set_data_dir from here, since it requires DirAccess - // which is initialized in initialize_core - data_dir = p_data_dir; - - Vector<Logger *> loggers; - loggers.push_back(memnew(SyslogLogger)); -#ifdef DEBUG_ENABLED - // it seems iOS app's stdout/stderr is only obtainable if you launch it from Xcode - loggers.push_back(memnew(StdLogger)); -#endif - _set_logger(memnew(CompositeLogger(loggers))); - - AudioDriverManager::add_driver(&audio_driver); -}; - -OSIPhone::~OSIPhone() { -} - -#endif diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 955eb15d57..f3bde46717 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -33,16 +33,15 @@ #ifndef OS_IPHONE_H #define OS_IPHONE_H -#include "core/input/input.h" #include "drivers/coreaudio/audio_driver_coreaudio.h" #include "drivers/unix/os_unix.h" #include "game_center.h" #include "icloud.h" #include "in_app_store.h" #include "ios.h" +#include "joypad_iphone.h" #include "servers/audio_server.h" #include "servers/rendering/rasterizer.h" -#include "servers/rendering_server.h" #if defined(VULKAN_ENABLED) #include "drivers/vulkan/rendering_device_vulkan.h" @@ -51,16 +50,9 @@ class OSIPhone : public OS_Unix { private: - enum { - MAX_MOUSE_COUNT = 8, - MAX_EVENTS = 64, - }; - static HashMap<String, void *> dynamic_symbol_lookup_table; friend void register_dynamic_symbol(char *name, void *address); - RenderingServer *rendering_server; - AudioDriverCoreAudio audio_driver; #ifdef GAME_CENTER_ENABLED @@ -74,139 +66,72 @@ private: #endif iOS *ios; - MainLoop *main_loop; - -#if defined(VULKAN_ENABLED) - VulkanContextIPhone *context_vulkan; - RenderingDeviceVulkan *rendering_device_vulkan; -#endif - VideoMode video_mode; - - virtual int get_video_driver_count() const; - virtual const char *get_video_driver_name(int p_driver) const; + JoypadIPhone *joypad_iphone; - virtual int get_current_video_driver() const; - - virtual void initialize_core(); - virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); - - virtual void set_main_loop(MainLoop *p_main_loop); - virtual MainLoop *get_main_loop() const; - - virtual void delete_main_loop(); + MainLoop *main_loop; - virtual void finalize(); + virtual void initialize_core() override; + virtual void initialize() override; - struct MouseList { - bool pressed[MAX_MOUSE_COUNT]; - MouseList() { - for (int i = 0; i < MAX_MOUSE_COUNT; i++) - pressed[i] = false; - }; - }; + virtual void initialize_joypads() override { + } - MouseList touch_list; + virtual void set_main_loop(MainLoop *p_main_loop) override; + virtual MainLoop *get_main_loop() const override; - Vector3 last_accel; + virtual void delete_main_loop() override; - Ref<InputEvent> event_queue[MAX_EVENTS]; - int event_count; - void queue_event(const Ref<InputEvent> &p_event); + virtual void finalize() override; - String data_dir; + String user_data_dir; String unique_id; String locale_code; - InputDefault *input; + bool is_focused = false; - int virtual_keyboard_height; - - int video_driver_index; + void deinitialize_modules(); public: - bool iterate(); - - uint8_t get_orientations() const; - - void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick); - void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y); - void touches_cancelled(); - void key(uint32_t p_key, bool p_pressed); - void set_virtual_keyboard_height(int p_height); - - int set_base_framebuffer(int p_fb); - - void update_gravity(float p_x, float p_y, float p_z); - void update_accelerometer(float p_x, float p_y, float p_z); - void update_magnetometer(float p_x, float p_y, float p_z); - void update_gyroscope(float p_x, float p_y, float p_z); - - int get_unused_joy_id(); - void joy_connection_changed(int p_idx, bool p_connected, String p_name); - void joy_button(int p_device, int p_button, bool p_pressed); - void joy_axis(int p_device, int p_axis, const InputDefault::JoyAxis &p_value); - static OSIPhone *get_singleton(); - virtual void set_mouse_show(bool p_show); - virtual void set_mouse_grab(bool p_grab); - virtual bool is_mouse_grab_enabled() const; - virtual Point2 get_mouse_position() const; - virtual int get_mouse_button_state() const; - virtual void set_window_title(const String &p_title); - - virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); + OSIPhone(String p_data_dir); + ~OSIPhone(); - virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false); - virtual Error close_dynamic_library(void *p_library_handle); - virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false); + void initialize_modules(); - virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0); - virtual VideoMode get_video_mode(int p_screen = 0) const; - virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const; + bool iterate(); - virtual void set_keep_screen_on(bool p_enabled); + void start(); - virtual bool can_draw() const; + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override; + virtual Error close_dynamic_library(void *p_library_handle) override; + virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override; - virtual bool has_virtual_keyboard() const; - virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1); - virtual void hide_virtual_keyboard(); - virtual int get_virtual_keyboard_height() const; + virtual void alert(const String &p_alert, + const String &p_title = "ALERT!") override; - virtual Size2 get_window_size() const; - virtual Rect2 get_window_safe_area() const; + virtual String get_name() const override; + virtual String get_model_name() const override; - virtual bool has_touchscreen_ui_hint() const; + virtual Error shell_open(String p_uri) override; - void set_data_dir(String p_dir); + void set_user_data_dir(String p_dir); + virtual String get_user_data_dir() const override; - virtual String get_name() const; - virtual String get_model_name() const; + void set_locale(String p_locale); + virtual String get_locale() const override; - Error shell_open(String p_uri); + void set_unique_id(String p_id); + virtual String get_unique_id() const override; - String get_user_data_dir() const; + virtual void vibrate_handheld(int p_duration_ms = 500) override; - void set_locale(String p_locale); - String get_locale() const; + virtual bool _check_internal_feature_support(const String &p_feature) override; - void set_unique_id(String p_id); - String get_unique_id() const; - - virtual Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track); - virtual bool native_video_is_playing() const; - virtual void native_video_pause(); - virtual void native_video_unpause(); - virtual void native_video_focus_out(); - virtual void native_video_stop(); - virtual void vibrate_handheld(int p_duration_ms = 500); - - virtual bool _check_internal_feature_support(const String &p_feature); - OSIPhone(int width, int height, String p_data_dir); - ~OSIPhone(); + void on_focus_out(); + void on_focus_in(); }; #endif // OS_IPHONE_H -#endif +#endif // IPHONE_ENABLED diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm new file mode 100644 index 0000000000..f0bbbd39ca --- /dev/null +++ b/platform/iphone/os_iphone.mm @@ -0,0 +1,369 @@ +/*************************************************************************/ +/* os_iphone.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef IPHONE_ENABLED + +#include "os_iphone.h" +#import "app_delegate.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 "display_server_iphone.h" +#include "drivers/unix/syslog_logger.h" +#import "godot_view.h" +#include "main/main.h" +#import "view_controller.h" + +#import <AudioToolbox/AudioServices.h> +#import <UIKit/UIKit.h> +#import <dlfcn.h> + +#if defined(OPENGL_ENABLED) +#include "drivers/gles2/rasterizer_gles2.h" +#endif + +#if defined(VULKAN_ENABLED) +#include "servers/rendering/rasterizer_rd/rasterizer_rd.h" +#import <QuartzCore/CAMetalLayer.h> +#include <vulkan/vulkan_metal.h> +#endif + +// Initialization order between compilation units is not guaranteed, +// so we use this as a hack to ensure certain code is called before +// everything else, but after all units are initialized. +typedef void (*init_callback)(); +static init_callback *ios_init_callbacks = nullptr; +static int ios_init_callbacks_count = 0; +static int ios_init_callbacks_capacity = 0; +HashMap<String, void *> OSIPhone::dynamic_symbol_lookup_table; + +void add_ios_init_callback(init_callback cb) { + if (ios_init_callbacks_count == ios_init_callbacks_capacity) { + void *new_ptr = realloc(ios_init_callbacks, sizeof(cb) * 32); + if (new_ptr) { + ios_init_callbacks = (init_callback *)(new_ptr); + ios_init_callbacks_capacity += 32; + } + } + if (ios_init_callbacks_capacity > ios_init_callbacks_count) { + ios_init_callbacks[ios_init_callbacks_count] = cb; + ++ios_init_callbacks_count; + } +} + +void register_dynamic_symbol(char *name, void *address) { + OSIPhone::dynamic_symbol_lookup_table[String(name)] = address; +} + +OSIPhone *OSIPhone::get_singleton() { + return (OSIPhone *)OS::get_singleton(); +} + +OSIPhone::OSIPhone(String p_data_dir) { + for (int i = 0; i < ios_init_callbacks_count; ++i) { + ios_init_callbacks[i](); + } + free(ios_init_callbacks); + ios_init_callbacks = nullptr; + ios_init_callbacks_count = 0; + ios_init_callbacks_capacity = 0; + + main_loop = nullptr; + + // can't call set_data_dir from here, since it requires DirAccess + // which is initialized in initialize_core + user_data_dir = p_data_dir; + + Vector<Logger *> loggers; + loggers.push_back(memnew(SyslogLogger)); +#ifdef DEBUG_ENABLED + // it seems iOS app's stdout/stderr is only obtainable if you launch it from + // Xcode + loggers.push_back(memnew(StdLogger)); +#endif + _set_logger(memnew(CompositeLogger(loggers))); + + AudioDriverManager::add_driver(&audio_driver); + + DisplayServerIPhone::register_iphone_driver(); +} + +OSIPhone::~OSIPhone() {} + +void OSIPhone::initialize_core() { + OS_Unix::initialize_core(); + + set_user_data_dir(user_data_dir); +} + +void OSIPhone::initialize() { + initialize_core(); +} + +void OSIPhone::initialize_modules() { +#ifdef GAME_CENTER_ENABLED + game_center = memnew(GameCenter); + Engine::get_singleton()->add_singleton(Engine::Singleton("GameCenter", game_center)); + game_center->connect(); +#endif + +#ifdef STOREKIT_ENABLED + store_kit = memnew(InAppStore); + Engine::get_singleton()->add_singleton(Engine::Singleton("InAppStore", store_kit)); +#endif + +#ifdef ICLOUD_ENABLED + icloud = memnew(ICloud); + Engine::get_singleton()->add_singleton(Engine::Singleton("ICloud", icloud)); +#endif + + ios = memnew(iOS); + Engine::get_singleton()->add_singleton(Engine::Singleton("iOS", ios)); + + joypad_iphone = memnew(JoypadIPhone); +} + +void OSIPhone::deinitialize_modules() { + if (joypad_iphone) { + memdelete(joypad_iphone); + } + + if (ios) { + memdelete(ios); + } + +#ifdef GAME_CENTER_ENABLED + if (game_center) { + memdelete(game_center); + } +#endif + +#ifdef STOREKIT_ENABLED + if (store_kit) { + memdelete(store_kit); + } +#endif + +#ifdef ICLOUD_ENABLED + if (icloud) { + memdelete(icloud); + } +#endif +} + +void OSIPhone::set_main_loop(MainLoop *p_main_loop) { + main_loop = p_main_loop; + + if (main_loop) { + main_loop->init(); + } +} + +MainLoop *OSIPhone::get_main_loop() const { + return main_loop; +} + +void OSIPhone::delete_main_loop() { + if (main_loop) { + main_loop->finish(); + memdelete(main_loop); + }; + + main_loop = nullptr; +} + +bool OSIPhone::iterate() { + if (!main_loop) { + return true; + } + + if (DisplayServer::get_singleton()) { + DisplayServer::get_singleton()->process_events(); + } + + return Main::iteration(); +} + +void OSIPhone::start() { + Main::start(); + + if (joypad_iphone) { + joypad_iphone->start_processing(); + } +} + +void OSIPhone::finalize() { + deinitialize_modules(); + + // Already gets called + // delete_main_loop(); +} + +// MARK: Dynamic Libraries + +Error OSIPhone::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { + if (p_path.length() == 0) { + p_library_handle = RTLD_SELF; + return OK; + } + return OS_Unix::open_dynamic_library(p_path, p_library_handle, p_also_set_library_path); +} + +Error OSIPhone::close_dynamic_library(void *p_library_handle) { + if (p_library_handle == RTLD_SELF) { + return OK; + } + return OS_Unix::close_dynamic_library(p_library_handle); +} + +Error OSIPhone::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) { + if (p_library_handle == RTLD_SELF) { + void **ptr = OSIPhone::dynamic_symbol_lookup_table.getptr(p_name); + if (ptr) { + p_symbol_handle = *ptr; + return OK; + } + } + return OS_Unix::get_dynamic_library_symbol_handle(p_library_handle, p_name, p_symbol_handle, p_optional); +} + +void OSIPhone::alert(const String &p_alert, const String &p_title) { + const CharString utf8_alert = p_alert.utf8(); + const CharString utf8_title = p_title.utf8(); + iOS::alert(utf8_alert.get_data(), utf8_title.get_data()); +} + +String OSIPhone::get_name() const { + return "iOS"; +}; + +String OSIPhone::get_model_name() const { + String model = ios->get_model(); + if (model != "") + return model; + + return OS_Unix::get_model_name(); +} + +Error OSIPhone::shell_open(String p_uri) { + NSString *urlPath = [[NSString alloc] initWithUTF8String:p_uri.utf8().get_data()]; + NSURL *url = [NSURL URLWithString:urlPath]; + [urlPath release]; + + if (![[UIApplication sharedApplication] canOpenURL:url]) { + return ERR_CANT_OPEN; + } + + printf("opening url %ls\n", p_uri.c_str()); + + // if (@available(iOS 10, *)) { + [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; + // } else { + // [[UIApplication sharedApplication] openURL:url]; + // } + + return OK; +}; + +void OSIPhone::set_user_data_dir(String p_dir) { + DirAccess *da = DirAccess::open(p_dir); + + user_data_dir = da->get_current_dir(); + printf("setting data dir to %ls from %ls\n", user_data_dir.c_str(), p_dir.c_str()); + memdelete(da); +} + +String OSIPhone::get_user_data_dir() const { + return user_data_dir; +} + +void OSIPhone::set_locale(String p_locale) { + locale_code = p_locale; +} + +String OSIPhone::get_locale() const { + return locale_code; +} + +void OSIPhone::set_unique_id(String p_id) { + unique_id = p_id; +} + +String OSIPhone::get_unique_id() const { + return unique_id; +} + +void OSIPhone::vibrate_handheld(int p_duration_ms) { + // iOS does not support duration for vibration + AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); +} + +bool OSIPhone::_check_internal_feature_support(const String &p_feature) { + return p_feature == "mobile"; +} + +void OSIPhone::on_focus_out() { + if (is_focused) { + is_focused = false; + + if (DisplayServerIPhone::get_singleton()) { + DisplayServerIPhone::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_OUT); + } + + [AppDelegate.viewController.godotView stopRendering]; + + if (DisplayServerIPhone::get_singleton() && DisplayServerIPhone::get_singleton()->native_video_is_playing()) { + DisplayServerIPhone::get_singleton()->native_video_pause(); + } + + audio_driver.stop(); + } +} + +void OSIPhone::on_focus_in() { + if (!is_focused) { + is_focused = true; + + if (DisplayServerIPhone::get_singleton()) { + DisplayServerIPhone::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_IN); + } + + [AppDelegate.viewController.godotView startRendering]; + + if (DisplayServerIPhone::get_singleton() && DisplayServerIPhone::get_singleton()->native_video_is_playing()) { + DisplayServerIPhone::get_singleton()->native_video_unpause(); + } + + audio_driver.start(); + } +} + +#endif // IPHONE_ENABLED diff --git a/platform/iphone/view_controller.h b/platform/iphone/view_controller.h index f6bbe11d97..dffdc01d4a 100644 --- a/platform/iphone/view_controller.h +++ b/platform/iphone/view_controller.h @@ -31,20 +31,18 @@ #import <GameKit/GameKit.h> #import <UIKit/UIKit.h> -@interface ViewController : UIViewController <GKGameCenterControllerDelegate> { -}; +@class GodotView; -- (BOOL)shouldAutorotateToInterfaceOrientation: - (UIInterfaceOrientation)p_orientation; +@interface ViewController : UIViewController <GKGameCenterControllerDelegate> -- (void)didReceiveMemoryWarning; +- (GodotView *)godotView; -- (void)viewDidLoad; +// MARK: Native Video Player -- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures; - -- (BOOL)prefersStatusBarHidden; - -- (BOOL)prefersHomeIndicatorAutoHidden; +- (BOOL)playVideoAtPath:(NSString *)filePath volume:(float)videoVolume audio:(NSString *)audioTrack subtitle:(NSString *)subtitleTrack; +- (BOOL)isVideoPlaying; +- (void)pauseVideo; +- (void)unpauseVideo; +- (void)stopVideo; @end diff --git a/platform/iphone/view_controller.mm b/platform/iphone/view_controller.mm index 279bcc1226..31597f7856 100644 --- a/platform/iphone/view_controller.mm +++ b/platform/iphone/view_controller.mm @@ -29,96 +29,174 @@ /*************************************************************************/ #import "view_controller.h" - +#include "core/project_settings.h" +#include "display_server_iphone.h" +#import "godot_view.h" +#import "godot_view_renderer.h" #include "os_iphone.h" -#include "core/project_settings.h" +#import <GameController/GameController.h> -extern "C" { +@interface ViewController () -int add_path(int, char **); -int add_cmdline(int, char **); +@property(strong, nonatomic) GodotViewRenderer *renderer; -int add_path(int p_argc, char **p_args) { - NSString *str = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"godot_path"]; - if (!str) - return p_argc; +// TODO: separate view to handle video +// AVPlayer-related properties +@property(strong, nonatomic) AVAsset *avAsset; +@property(strong, nonatomic) AVPlayerItem *avPlayerItem; +@property(strong, nonatomic) AVPlayer *avPlayer; +@property(strong, nonatomic) AVPlayerLayer *avPlayerLayer; +@property(assign, nonatomic) CMTime videoCurrentTime; +@property(assign, nonatomic) BOOL isVideoCurrentlyPlaying; +@property(assign, nonatomic) BOOL videoHasFoundError; - p_args[p_argc++] = "--path"; - [str retain]; // memory leak lol (maybe make it static here and delete it in ViewController destructor? @todo - p_args[p_argc++] = (char *)[str cString]; - p_args[p_argc] = NULL; +@end - return p_argc; -}; +@implementation ViewController -int add_cmdline(int p_argc, char **p_args) { - NSArray *arr = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"godot_cmdline"]; - if (!arr) - return p_argc; +- (GodotView *)godotView { + return (GodotView *)self.view; +} - for (int i = 0; i < [arr count]; i++) { - NSString *str = [arr objectAtIndex:i]; - if (!str) - continue; - [str retain]; // @todo delete these at some point - p_args[p_argc++] = (char *)[str cString]; - }; +- (void)loadView { + GodotView *view = [[GodotView alloc] init]; + GodotViewRenderer *renderer = [[GodotViewRenderer alloc] init]; - p_args[p_argc] = NULL; + self.renderer = renderer; + self.view = view; - return p_argc; -}; -}; // extern "C" + view.renderer = self.renderer; -@interface ViewController () + [renderer release]; + [view release]; +} -@end +- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; -@implementation ViewController + if (self) { + [self godot_commonInit]; + } + + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + + if (self) { + [self godot_commonInit]; + } + + return self; +} + +- (void)godot_commonInit { + self.isVideoCurrentlyPlaying = NO; + self.videoCurrentTime = kCMTimeZero; + self.videoHasFoundError = false; +} - (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; printf("*********** did receive memory warning!\n"); -}; +} - (void)viewDidLoad { [super viewDidLoad]; + [self observeKeyboard]; + [self observeAudio]; + if (@available(iOS 11.0, *)) { [self setNeedsUpdateOfScreenEdgesDeferringSystemGestures]; } } +- (void)observeKeyboard { + printf("******** adding observer for keyboard show/hide\n"); + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(keyboardOnScreen:) + name:UIKeyboardDidShowNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(keyboardHidden:) + name:UIKeyboardDidHideNotification + object:nil]; +} + +- (void)observeAudio { + printf("******** adding observer for sound routing changes\n"); + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(audioRouteChangeListenerCallback:) + name:AVAudioSessionRouteChangeNotification + object:nil]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if (object == self.avPlayerItem && [keyPath isEqualToString:@"status"]) { + [self handleVideoOrPlayerStatus]; + } + + if (object == self.avPlayer && [keyPath isEqualToString:@"rate"]) { + [self handleVideoPlayRate]; + } +} + +- (void)dealloc { + [self stopVideo]; + + self.renderer = nil; + + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [super dealloc]; +} + +// MARK: Orientation + - (UIRectEdge)preferredScreenEdgesDeferringSystemGestures { return UIRectEdgeAll; } - (BOOL)shouldAutorotate { - switch (OS::get_singleton()->get_screen_orientation()) { - case OS::SCREEN_SENSOR: - case OS::SCREEN_SENSOR_LANDSCAPE: - case OS::SCREEN_SENSOR_PORTRAIT: + if (!DisplayServerIPhone::get_singleton()) { + return NO; + } + + switch (DisplayServerIPhone::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) { + case DisplayServer::SCREEN_SENSOR: + case DisplayServer::SCREEN_SENSOR_LANDSCAPE: + case DisplayServer::SCREEN_SENSOR_PORTRAIT: return YES; default: return NO; } -}; +} - (UIInterfaceOrientationMask)supportedInterfaceOrientations { - switch (OS::get_singleton()->get_screen_orientation()) { - case OS::SCREEN_PORTRAIT: + if (!DisplayServerIPhone::get_singleton()) { + return UIInterfaceOrientationMaskAll; + } + + switch (DisplayServerIPhone::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) { + case DisplayServer::SCREEN_PORTRAIT: return UIInterfaceOrientationMaskPortrait; - case OS::SCREEN_REVERSE_LANDSCAPE: + case DisplayServer::SCREEN_REVERSE_LANDSCAPE: return UIInterfaceOrientationMaskLandscapeRight; - case OS::SCREEN_REVERSE_PORTRAIT: + case DisplayServer::SCREEN_REVERSE_PORTRAIT: return UIInterfaceOrientationMaskPortraitUpsideDown; - case OS::SCREEN_SENSOR_LANDSCAPE: + case DisplayServer::SCREEN_SENSOR_LANDSCAPE: return UIInterfaceOrientationMaskLandscape; - case OS::SCREEN_SENSOR_PORTRAIT: + case DisplayServer::SCREEN_SENSOR_PORTRAIT: return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; - case OS::SCREEN_SENSOR: + case DisplayServer::SCREEN_SENSOR: return UIInterfaceOrientationMaskAll; - case OS::SCREEN_LANDSCAPE: + case DisplayServer::SCREEN_LANDSCAPE: return UIInterfaceOrientationMaskLandscapeLeft; } }; @@ -135,6 +213,190 @@ int add_cmdline(int p_argc, char **p_args) { } } +// MARK: Keyboard + +- (void)keyboardOnScreen:(NSNotification *)notification { + NSDictionary *info = notification.userInfo; + NSValue *value = info[UIKeyboardFrameEndUserInfoKey]; + + CGRect rawFrame = [value CGRectValue]; + CGRect keyboardFrame = [self.view convertRect:rawFrame fromView:nil]; + + if (DisplayServerIPhone::get_singleton()) { + DisplayServerIPhone::get_singleton()->virtual_keyboard_set_height(keyboardFrame.size.height); + } +} + +- (void)keyboardHidden:(NSNotification *)notification { + if (DisplayServerIPhone::get_singleton()) { + DisplayServerIPhone::get_singleton()->virtual_keyboard_set_height(0); + } +} + +// MARK: Audio + +- (void)audioRouteChangeListenerCallback:(NSNotification *)notification { + printf("*********** route changed!\n"); + NSDictionary *interuptionDict = notification.userInfo; + + NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue]; + + switch (routeChangeReason) { + case AVAudioSessionRouteChangeReasonNewDeviceAvailable: { + NSLog(@"AVAudioSessionRouteChangeReasonNewDeviceAvailable"); + NSLog(@"Headphone/Line plugged in"); + } break; + case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: { + NSLog(@"AVAudioSessionRouteChangeReasonOldDeviceUnavailable"); + NSLog(@"Headphone/Line was pulled. Resuming video play...."); + if ([self isVideoPlaying]) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self.avPlayer play]; // NOTE: change this line according your current player implementation + NSLog(@"resumed play"); + }); + } + } break; + case AVAudioSessionRouteChangeReasonCategoryChange: { + // called at start - also when other audio wants to play + NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange"); + } break; + } +} + +// MARK: Native Video Player + +- (void)handleVideoOrPlayerStatus { + if (self.avPlayerItem.status == AVPlayerItemStatusFailed || self.avPlayer.status == AVPlayerStatusFailed) { + [self stopVideo]; + self.videoHasFoundError = true; + } + + if (self.avPlayer.status == AVPlayerStatusReadyToPlay && self.avPlayerItem.status == AVPlayerItemStatusReadyToPlay && CMTimeCompare(self.videoCurrentTime, kCMTimeZero) == 0) { + // NSLog(@"time: %@", self.video_current_time); + [self.avPlayer seekToTime:self.videoCurrentTime]; + self.videoCurrentTime = kCMTimeZero; + } +} + +- (void)handleVideoPlayRate { + NSLog(@"Player playback rate changed: %.5f", self.avPlayer.rate); + if ([self isVideoPlaying] && self.avPlayer.rate == 0.0 && !self.avPlayer.error) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self.avPlayer play]; // NOTE: change this line according your current player implementation + NSLog(@"resumed play"); + }); + + NSLog(@" . . . PAUSED (or just started)"); + } +} + +- (BOOL)playVideoAtPath:(NSString *)filePath volume:(float)videoVolume audio:(NSString *)audioTrack subtitle:(NSString *)subtitleTrack { + self.avAsset = [AVAsset assetWithURL:[NSURL fileURLWithPath:filePath]]; + + self.avPlayerItem = [AVPlayerItem playerItemWithAsset:self.avAsset]; + [self.avPlayerItem addObserver:self forKeyPath:@"status" options:0 context:nil]; + + self.avPlayer = [AVPlayer playerWithPlayerItem:self.avPlayerItem]; + self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer]; + + [self.avPlayer addObserver:self forKeyPath:@"status" options:0 context:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(playerItemDidReachEnd:) + name:AVPlayerItemDidPlayToEndTimeNotification + object:[self.avPlayer currentItem]]; + + [self.avPlayer addObserver:self forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:0]; + + [self.avPlayerLayer setFrame:self.view.bounds]; + [self.view.layer addSublayer:self.avPlayerLayer]; + [self.avPlayer play]; + + AVMediaSelectionGroup *audioGroup = [self.avAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicAudible]; + + NSMutableArray *allAudioParams = [NSMutableArray array]; + for (id track in audioGroup.options) { + NSString *language = [[track locale] localeIdentifier]; + NSLog(@"subtitle lang: %@", language); + + if ([language isEqualToString:audioTrack]) { + AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters]; + [audioInputParams setVolume:videoVolume atTime:kCMTimeZero]; + [audioInputParams setTrackID:[track trackID]]; + [allAudioParams addObject:audioInputParams]; + + AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix]; + [audioMix setInputParameters:allAudioParams]; + + [self.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup:audioGroup]; + [self.avPlayer.currentItem setAudioMix:audioMix]; + + break; + } + } + + AVMediaSelectionGroup *subtitlesGroup = [self.avAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicLegible]; + NSArray *useableTracks = [AVMediaSelectionGroup mediaSelectionOptionsFromArray:subtitlesGroup.options withoutMediaCharacteristics:[NSArray arrayWithObject:AVMediaCharacteristicContainsOnlyForcedSubtitles]]; + + for (id track in useableTracks) { + NSString *language = [[track locale] localeIdentifier]; + NSLog(@"subtitle lang: %@", language); + + if ([language isEqualToString:subtitleTrack]) { + [self.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup:subtitlesGroup]; + break; + } + } + + self.isVideoCurrentlyPlaying = YES; + + return true; +} + +- (BOOL)isVideoPlaying { + if (self.avPlayer.error) { + printf("Error during playback\n"); + } + return (self.avPlayer.rate > 0 && !self.avPlayer.error); +} + +- (void)pauseVideo { + self.videoCurrentTime = self.avPlayer.currentTime; + [self.avPlayer pause]; + self.isVideoCurrentlyPlaying = NO; +} + +- (void)unpauseVideo { + [self.avPlayer play]; + self.isVideoCurrentlyPlaying = YES; +} + +- (void)playerItemDidReachEnd:(NSNotification *)notification { + [self stopVideo]; +} + +- (void)stopVideo { + [self.avPlayer pause]; + [self.avPlayerLayer removeFromSuperlayer]; + self.avPlayerLayer = nil; + + if (self.avPlayerItem) { + [self.avPlayerItem removeObserver:self forKeyPath:@"status"]; + self.avPlayerItem = nil; + } + + if (self.avPlayer) { + [self.avPlayer removeObserver:self forKeyPath:@"status"]; + self.avPlayer = nil; + } + + self.avAsset = nil; + + self.isVideoCurrentlyPlaying = NO; +} + +// MARK: Delegates + #ifdef GAME_CENTER_ENABLED - (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController { //[gameCenterViewController dismissViewControllerAnimated:YES completion:^{GameCenter::get_singleton()->game_center_closed();}];//version for signaling when overlay is completely gone diff --git a/platform/iphone/vulkan_context_iphone.h b/platform/iphone/vulkan_context_iphone.h index cadd701636..5c3d5fe33e 100644 --- a/platform/iphone/vulkan_context_iphone.h +++ b/platform/iphone/vulkan_context_iphone.h @@ -32,13 +32,14 @@ #define VULKAN_CONTEXT_IPHONE_H #include "drivers/vulkan/vulkan_context.h" -// #import <UIKit/UIKit.h> + +#import <UIKit/UIKit.h> class VulkanContextIPhone : public VulkanContext { virtual const char *_get_platform_surface_extension() const; public: - int window_create(void *p_window, int p_width, int p_height); + Error window_create(DisplayServer::WindowID p_window_id, CALayer *p_metal_layer, int p_width, int p_height); VulkanContextIPhone(); ~VulkanContextIPhone(); diff --git a/platform/iphone/vulkan_context_iphone.mm b/platform/iphone/vulkan_context_iphone.mm index 44c940dc3a..cb4dbe7f85 100644 --- a/platform/iphone/vulkan_context_iphone.mm +++ b/platform/iphone/vulkan_context_iphone.mm @@ -35,21 +35,23 @@ const char *VulkanContextIPhone::_get_platform_surface_extension() const { return VK_MVK_IOS_SURFACE_EXTENSION_NAME; } -int VulkanContextIPhone::window_create(void *p_window, int p_width, int p_height) { +Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, + CALayer *p_metal_layer, int p_width, + int p_height) { VkIOSSurfaceCreateInfoMVK createInfo; - createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; + createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK; createInfo.pNext = NULL; createInfo.flags = 0; - createInfo.pView = p_window; + createInfo.pView = p_metal_layer; VkSurfaceKHR surface; - VkResult err = vkCreateIOSSurfaceMVK(_get_instance(), &createInfo, NULL, &surface); - ERR_FAIL_COND_V(err, -1); - return _window_create(surface, p_width, p_height); -} + VkResult err = + vkCreateIOSSurfaceMVK(_get_instance(), &createInfo, NULL, &surface); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); -VulkanContextIPhone::VulkanContextIPhone() { + return _window_create(p_window_id, surface, p_width, p_height); } -VulkanContextIPhone::~VulkanContextIPhone() { -} +VulkanContextIPhone::VulkanContextIPhone() {} + +VulkanContextIPhone::~VulkanContextIPhone() {} diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp index 2f0a2faa83..2fd1f45939 100644 --- a/platform/javascript/display_server_javascript.cpp +++ b/platform/javascript/display_server_javascript.cpp @@ -829,6 +829,19 @@ DisplayServer *DisplayServerJavaScript::create_func(const String &p_rendering_dr } DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + r_error = OK; // Always succeeds for now. + + /* clang-format off */ + swap_cancel_ok = EM_ASM_INT({ + const win = (['Windows', 'Win64', 'Win32', 'WinCE']); + const plat = navigator.platform || ""; + if (win.indexOf(plat) !== -1) { + return 1; + } + return 0; + }) == 1; + /* clang-format on */ + RasterizerDummy::make_current(); // TODO GLES2 in Godot 4.0... or webgpu? #if 0 EmscriptenWebGLContextAttributes attributes; @@ -1181,6 +1194,10 @@ int DisplayServerJavaScript::get_current_video_driver() const { return 1; } +bool DisplayServerJavaScript::get_swap_cancel_ok() { + return swap_cancel_ok; +} + void DisplayServerJavaScript::swap_buffers() { //emscripten_webgl_commit_frame(); } diff --git a/platform/javascript/display_server_javascript.h b/platform/javascript/display_server_javascript.h index b149665d67..6569ef1e42 100644 --- a/platform/javascript/display_server_javascript.h +++ b/platform/javascript/display_server_javascript.h @@ -56,6 +56,8 @@ class DisplayServerJavaScript : public DisplayServer { int last_width = 0; int last_height = 0; + bool swap_cancel_ok = false; + // utilities static Point2 compute_position_in_canvas(int p_x, int p_y); static void focus_canvas(); @@ -195,6 +197,7 @@ public: virtual void set_icon(const Ref<Image> &p_icon); // others + virtual bool get_swap_cancel_ok(); virtual void swap_buffers(); static void register_javascript_driver(); diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp index f697887f08..a30d84a52c 100644 --- a/platform/javascript/javascript_main.cpp +++ b/platform/javascript/javascript_main.cpp @@ -34,6 +34,7 @@ #include "platform/javascript/os_javascript.h" #include <emscripten/emscripten.h> +#include <stdlib.h> static OS_JavaScript *os = nullptr; static uint64_t target_ticks = 0; diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 874a3a6392..d35941bdcd 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -685,6 +685,14 @@ DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, u return id; } +void DisplayServerX11::show_window(WindowID p_id) { + _THREAD_SAFE_METHOD_ + + WindowData &wd = windows[p_id]; + + XMapWindow(x11_display, wd.x11_window); +} + void DisplayServerX11::delete_sub_window(WindowID p_id) { _THREAD_SAFE_METHOD_ @@ -873,6 +881,46 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent } } +// Helper method. Assumes that the window id has already been checked and exists. +void DisplayServerX11::_update_size_hints(WindowID p_window) { + WindowData &wd = windows[p_window]; + WindowMode window_mode = window_get_mode(p_window); + XSizeHints *xsh = XAllocSizeHints(); + + // Always set the position and size hints - they should be synchronized with the actual values after the window is mapped anyway + xsh->flags |= PPosition | PSize; + xsh->x = wd.position.x; + xsh->y = wd.position.y; + xsh->width = wd.size.width; + xsh->height = wd.size.height; + + if (window_mode == WINDOW_MODE_FULLSCREEN) { + // Do not set any other hints to prevent the window manager from ignoring the fullscreen flags + } else if (window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { + // If resizing is disabled, use the forced size + xsh->flags |= PMinSize | PMaxSize; + xsh->min_width = wd.size.x; + xsh->max_width = wd.size.x; + xsh->min_height = wd.size.y; + xsh->max_height = wd.size.y; + } else { + // Otherwise, just respect min_size and max_size + if (wd.min_size != Size2i()) { + xsh->flags |= PMinSize; + xsh->min_width = wd.min_size.x; + xsh->min_height = wd.min_size.y; + } + if (wd.max_size != Size2i()) { + xsh->flags |= PMaxSize; + xsh->max_width = wd.max_size.x; + xsh->max_height = wd.max_size.y; + } + } + + XSetWMNormalHints(x11_display, wd.x11_window, xsh); + XFree(xsh); +} + Point2i DisplayServerX11::window_get_position(WindowID p_window) const { _THREAD_SAFE_METHOD_ @@ -926,25 +974,8 @@ void DisplayServerX11::window_set_max_size(const Size2i p_size, WindowID p_windo } wd.max_size = p_size; - if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { - XSizeHints *xsh; - xsh = XAllocSizeHints(); - xsh->flags = 0L; - if (wd.min_size != Size2i()) { - xsh->flags |= PMinSize; - xsh->min_width = wd.min_size.x; - xsh->min_height = wd.min_size.y; - } - if (wd.max_size != Size2i()) { - xsh->flags |= PMaxSize; - xsh->max_width = wd.max_size.x; - xsh->max_height = wd.max_size.y; - } - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); - - XFlush(x11_display); - } + _update_size_hints(p_window); + XFlush(x11_display); } Size2i DisplayServerX11::window_get_max_size(WindowID p_window) const { @@ -968,25 +999,8 @@ void DisplayServerX11::window_set_min_size(const Size2i p_size, WindowID p_windo } wd.min_size = p_size; - if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { - XSizeHints *xsh; - xsh = XAllocSizeHints(); - xsh->flags = 0L; - if (wd.min_size != Size2i()) { - xsh->flags |= PMinSize; - xsh->min_width = wd.min_size.x; - xsh->min_height = wd.min_size.y; - } - if (wd.max_size != Size2i()) { - xsh->flags |= PMaxSize; - xsh->max_width = wd.max_size.x; - xsh->max_height = wd.max_size.y; - } - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); - - XFlush(x11_display); - } + _update_size_hints(p_window); + XFlush(x11_display); } Size2i DisplayServerX11::window_get_min_size(WindowID p_window) const { @@ -1019,37 +1033,15 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) { int old_w = xwa.width; int old_h = xwa.height; - // If window resizable is disabled we need to update the attributes first - XSizeHints *xsh; - xsh = XAllocSizeHints(); - if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { - xsh->flags = PMinSize | PMaxSize; - xsh->min_width = size.x; - xsh->max_width = size.x; - xsh->min_height = size.y; - xsh->max_height = size.y; - } else { - xsh->flags = 0L; - if (wd.min_size != Size2i()) { - xsh->flags |= PMinSize; - xsh->min_width = wd.min_size.x; - xsh->min_height = wd.min_size.y; - } - if (wd.max_size != Size2i()) { - xsh->flags |= PMaxSize; - xsh->max_width = wd.max_size.x; - xsh->max_height = wd.max_size.y; - } - } - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); + // Update our videomode width and height + wd.size = size; + + // Update the size hints first to make sure the window size can be set + _update_size_hints(p_window); // Resize the window XResizeWindow(x11_display, wd.x11_window, size.x, size.y); - // Update our videomode width and height - wd.size = size; - for (int timeout = 0; timeout < 50; ++timeout) { XSync(x11_display, False); XGetWindowAttributes(x11_display, wd.x11_window, &xwa); @@ -1205,14 +1197,9 @@ void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) { XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); } - if (p_enabled && window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { + if (p_enabled) { // Set the window as resizable to prevent window managers to ignore the fullscreen state flag. - XSizeHints *xsh; - - xsh = XAllocSizeHints(); - xsh->flags = 0L; - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); + _update_size_hints(p_window); } // Using EWMH -- Extended Window Manager Hints @@ -1240,30 +1227,7 @@ void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) { if (!p_enabled) { // Reset the non-resizable flags if we un-set these before. - Size2i size = window_get_size(p_window); - XSizeHints *xsh; - xsh = XAllocSizeHints(); - if (window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { - xsh->flags = PMinSize | PMaxSize; - xsh->min_width = size.x; - xsh->max_width = size.x; - xsh->min_height = size.y; - xsh->max_height = size.y; - } else { - xsh->flags = 0L; - if (wd.min_size != Size2i()) { - xsh->flags |= PMinSize; - xsh->min_width = wd.min_size.x; - xsh->min_height = wd.min_size.y; - } - if (wd.max_size != Size2i()) { - xsh->flags |= PMaxSize; - xsh->max_width = wd.max_size.x; - xsh->max_height = wd.max_size.y; - } - } - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); + _update_size_hints(p_window); // put back or remove decorations according to the last set borderless state Hints hints; @@ -1321,13 +1285,13 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) { } break; case WINDOW_MODE_FULLSCREEN: { //Remove full-screen + wd.fullscreen = false; + _set_wm_fullscreen(p_window, false); //un-maximize required for always on top bool on_top = window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window); - wd.fullscreen = false; - window_set_position(wd.last_position_before_fs, p_window); if (on_top) { @@ -1373,15 +1337,16 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) { } break; case WINDOW_MODE_FULLSCREEN: { wd.last_position_before_fs = wd.position; + if (window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window)) { _set_wm_maximized(p_window, true); } - _set_wm_fullscreen(p_window, true); + wd.fullscreen = true; + _set_wm_fullscreen(p_window, true); } break; case WINDOW_MODE_MAXIMIZED: { _set_wm_maximized(p_window, true); - } break; } } @@ -1448,37 +1413,11 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo switch (p_flag) { case WINDOW_FLAG_RESIZE_DISABLED: { - XSizeHints *xsh; - xsh = XAllocSizeHints(); - if (p_enabled) { - Size2i size = window_get_size(p_window); - - xsh->flags = PMinSize | PMaxSize; - xsh->min_width = size.x; - xsh->max_width = size.x; - xsh->min_height = size.y; - xsh->max_height = size.y; - } else { - xsh->flags = 0L; - if (wd.min_size != Size2i()) { - xsh->flags |= PMinSize; - xsh->min_width = wd.min_size.x; - xsh->min_height = wd.min_size.y; - } - if (wd.max_size != Size2i()) { - xsh->flags |= PMaxSize; - xsh->max_width = wd.max_size.x; - xsh->max_height = wd.max_size.y; - } - } - - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); - wd.resize_disabled = p_enabled; - XFlush(x11_display); + _update_size_hints(p_window); + XFlush(x11_display); } break; case WINDOW_FLAG_BORDERLESS: { Hints hints; @@ -3218,8 +3157,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u WindowData wd; wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes); - XMapWindow(x11_display, wd.x11_window); - //associate PID // make PID known to X11 { @@ -3299,20 +3236,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u windows[id] = wd; { - if (p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT) { - XSizeHints *xsh; - xsh = XAllocSizeHints(); - - xsh->flags = PMinSize | PMaxSize; - xsh->min_width = p_rect.size.width; - xsh->max_width = p_rect.size.width; - xsh->min_height = p_rect.size.height; - xsh->max_height = p_rect.size.height; - - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); - } - bool make_utility = false; if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) { @@ -3362,18 +3285,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u } } - if (id != MAIN_WINDOW_ID) { - XSizeHints my_hints = XSizeHints(); - - my_hints.flags = PPosition | PSize; /* I want to specify position and size */ - my_hints.x = p_rect.position.x; /* The origin and size coords I want */ - my_hints.y = p_rect.position.y; - my_hints.width = p_rect.size.width; - my_hints.height = p_rect.size.height; - - XSetNormalHints(x11_display, wd.x11_window, &my_hints); - XMoveWindow(x11_display, wd.x11_window, p_rect.position.x, p_rect.position.y); - } + _update_size_hints(id); #if defined(VULKAN_ENABLED) if (context_vulkan) { @@ -3414,6 +3326,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u if (cursors[current_cursor] != None) { XDefineCursor(x11_display, wd.x11_window, cursors[current_cursor]); } + return id; } @@ -3653,6 +3566,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode window_set_flag(WindowFlags(i), true, main_window); } } + show_window(main_window); //create RenderingDevice if used #if defined(VULKAN_ENABLED) diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index b5d2ea1c63..8e1f941bbf 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -235,6 +235,7 @@ class DisplayServerX11 : public DisplayServer { void _update_real_mouse_position(const WindowData &wd); bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const; + void _update_size_hints(WindowID p_window); void _set_wm_fullscreen(WindowID p_window, bool p_enabled); void _set_wm_maximized(WindowID p_window, bool p_enabled); @@ -276,6 +277,7 @@ public: virtual Vector<DisplayServer::WindowID> get_window_list() const; virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); + virtual void show_window(WindowID p_id); virtual void delete_sub_window(WindowID p_id); virtual WindowID get_window_at_screen_position(const Point2i &p_position) const; diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index 5edaf35c50..fda1358dfd 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -311,16 +311,9 @@ void JoypadLinux::open_joypad(const char *p_path) { return; } - //check if the device supports basic gamepad events, prevents certain keyboards from - //being detected as joypads + // Check if the device supports basic gamepad events if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) && - (test_bit(ABS_X, absbit) || test_bit(ABS_Y, absbit) || test_bit(ABS_HAT0X, absbit) || - test_bit(ABS_GAS, absbit) || test_bit(ABS_RUDDER, absbit)) && - (test_bit(BTN_A, keybit) || test_bit(BTN_THUMBL, keybit) || - test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_1, keybit))) && - !(test_bit(EV_ABS, evbit) && - test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) && - test_bit(ABS_RX, absbit) && test_bit(ABS_RY, absbit))) { + test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) { close(fd); return; } diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 25d230fc89..272ae1b620 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -28,7 +28,8 @@ def get_opts(): ("MACOS_SDK_PATH", "Path to the macOS SDK", ""), BoolVariable( "use_static_mvk", - "Link MoltenVK statically as Level-0 driver (better portability) or use Vulkan ICD loader (enables validation layers)", + "Link MoltenVK statically as Level-0 driver (better portability) or use Vulkan ICD loader (enables" + " validation layers)", False, ), EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")), @@ -50,9 +51,11 @@ def configure(env): if env["target"] == "release": if env["optimize"] == "speed": # optimize for speed (default) - env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize", "-msse2"]) + env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize"]) else: # optimize for size - env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize", "-msse2"]) + env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize"]) + if env["arch"] != "arm64": + env.Prepend(CCFLAGS=["-msse2"]) if env["debug_symbols"] == "yes": env.Prepend(CCFLAGS=["-g1"]) diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h index 68e8454fd0..d8f3f81ff6 100644 --- a/platform/osx/display_server_osx.h +++ b/platform/osx/display_server_osx.h @@ -230,6 +230,7 @@ public: virtual Vector<int> get_window_list() const override; virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override; + virtual void show_window(WindowID p_id) override; virtual void delete_sub_window(WindowID p_id) override; virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index 5e209a6e6b..4c04151791 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -1944,8 +1944,12 @@ void DisplayServerOSX::alert(const String &p_alert, const String &p_title) { [window setInformativeText:ns_alert]; [window setAlertStyle:NSAlertStyleWarning]; + id key_window = [[NSApplication sharedApplication] keyWindow]; [window runModal]; [window release]; + if (key_window) { + [key_window makeKeyAndOrderFront:nil]; + } } Error DisplayServerOSX::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) { @@ -2311,18 +2315,23 @@ DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, u _THREAD_SAFE_METHOD_ WindowID id = _create_window(p_mode, p_rect); - WindowData &wd = windows[id]; for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { window_set_flag(WindowFlags(i), true, id); } } + + return id; +} + +void DisplayServerOSX::show_window(WindowID p_id) { + WindowData &wd = windows[p_id]; + if (wd.no_focus) { [wd.window_object orderFront:nil]; } else { [wd.window_object makeKeyAndOrderFront:nil]; } - return id; } void DisplayServerOSX::_send_window_event(const WindowData &wd, WindowEvent p_event) { @@ -2793,7 +2802,9 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo } break; case WINDOW_FLAG_BORDERLESS: { // OrderOut prevents a lose focus bug with the window - [wd.window_object orderOut:nil]; + if ([wd.window_object isVisible]) { + [wd.window_object orderOut:nil]; + } wd.borderless = p_enabled; if (p_enabled) { [wd.window_object setStyleMask:NSWindowStyleMaskBorderless]; @@ -2807,7 +2818,13 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo [wd.window_object setFrame:frameRect display:NO]; } _update_window(wd); - [wd.window_object makeKeyAndOrderFront:nil]; + if ([wd.window_object isVisible]) { + if (wd.no_focus) { + [wd.window_object orderFront:nil]; + } else { + [wd.window_object makeKeyAndOrderFront:nil]; + } + } } break; case WINDOW_FLAG_ALWAYS_ON_TOP: { wd.on_top = p_enabled; @@ -2875,7 +2892,11 @@ void DisplayServerOSX::window_move_to_foreground(WindowID p_window) { const WindowData &wd = windows[p_window]; [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - [wd.window_object makeKeyAndOrderFront:nil]; + if (wd.no_focus) { + [wd.window_object orderFront:nil]; + } else { + [wd.window_object makeKeyAndOrderFront:nil]; + } } bool DisplayServerOSX::window_can_draw(WindowID p_window) const { @@ -3755,7 +3776,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode window_set_flag(WindowFlags(i), true, main_window); } } - [windows[main_window].window_object makeKeyAndOrderFront:nil]; + show_window(MAIN_WINDOW_ID); #if defined(OPENGL_ENABLED) if (rendering_driver == "opengl_es") { diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py index c23a65ef75..04b743f2c8 100644 --- a/platform/uwp/detect.py +++ b/platform/uwp/detect.py @@ -120,7 +120,9 @@ def configure(env): print("Compiled program architecture will be a x86 executable. (forcing bits=32).") else: print( - "Failed to detect MSVC compiler architecture version... Defaulting to 32-bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup." + "Failed to detect MSVC compiler architecture version... Defaulting to 32-bit executable settings" + " (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture" + " this build is compiled for. You should check your settings/compilation setup." ) env["bits"] = "32" @@ -160,7 +162,10 @@ def configure(env): env.Append(CPPFLAGS=["/AI", vc_base_path + "lib/x86/store/references"]) env.Append( - CCFLAGS='/FS /MP /GS /wd"4453" /wd"28204" /wd"4291" /Zc:wchar_t /Gm- /fp:precise /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo'.split() + CCFLAGS=( + '/FS /MP /GS /wd"4453" /wd"28204" /wd"4291" /Zc:wchar_t /Gm- /fp:precise /errorReport:prompt /WX-' + " /Zc:forScope /Gd /EHsc /nologo".split() + ) ) env.Append(CPPDEFINES=["_UNICODE", "UNICODE", ("WINAPI_FAMILY", "WINAPI_FAMILY_APP")]) env.Append(CXXFLAGS=["/ZW"]) diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index ee25754704..1dddb07990 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -715,7 +715,7 @@ bool OS_UWP::has_virtual_keyboard() const { return UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Touch; } -void OS_UWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length, int p_cursor_start, int p_cursor_end) { +void OS_UWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { InputPane ^ pane = InputPane::GetForCurrentView(); pane->TryShow(); } diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index c35b634353..892327bac5 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -234,7 +234,7 @@ public: virtual bool has_touchscreen_ui_hint() const; virtual bool has_virtual_keyboard() const; - virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1); + virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1); virtual void hide_virtual_keyboard(); virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false); diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 0ab0e1ed3c..271ffc8871 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -128,7 +128,9 @@ def setup_msvc_manual(env): print("Compiled program architecture will be a 32 bit executable. (forcing bits=32).") else: print( - "Failed to manually detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup, or avoid setting VCINSTALLDIR." + "Failed to manually detect MSVC compiler architecture version... Defaulting to 32bit executable settings" + " (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this" + " build is compiled for. You should check your settings/compilation setup, or avoid setting VCINSTALLDIR." ) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 6ee9b6d698..da2fc1c2c1 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -495,13 +495,17 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod _update_window_style(window_id); - ShowWindow(wd.hWnd, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) ? SW_SHOWNOACTIVATE : SW_SHOW); // Show The Window - if (!(p_flags & WINDOW_FLAG_NO_FOCUS_BIT)) { + return window_id; +} + +void DisplayServerWindows::show_window(WindowID p_id) { + WindowData &wd = windows[p_id]; + + ShowWindow(wd.hWnd, wd.no_focus ? SW_SHOWNOACTIVATE : SW_SHOW); // Show The Window + if (!wd.no_focus) { SetForegroundWindow(wd.hWnd); // Slightly Higher Priority SetFocus(wd.hWnd); // Sets Keyboard Focus To } - - return window_id; } void DisplayServerWindows::delete_sub_window(WindowID p_window) { @@ -3121,9 +3125,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win } } - ShowWindow(windows[MAIN_WINDOW_ID].hWnd, SW_SHOW); // Show The Window - SetForegroundWindow(windows[MAIN_WINDOW_ID].hWnd); // Slightly Higher Priority - SetFocus(windows[MAIN_WINDOW_ID].hWnd); // Sets Keyboard Focus To + show_window(MAIN_WINDOW_ID); #if defined(VULKAN_ENABLED) diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 725f9697c5..7bd93a7086 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -460,6 +460,7 @@ public: virtual Vector<DisplayServer::WindowID> get_window_list() const; virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); + virtual void show_window(WindowID p_window); virtual void delete_sub_window(WindowID p_window); virtual WindowID get_window_at_screen_position(const Point2i &p_position) const; diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis index 593557cc69..90f0b55d0a 100644 --- a/platform/windows/godot.natvis +++ b/platform/windows/godot.natvis @@ -19,7 +19,7 @@ </ArrayItems> </Expand> </Type> - + <Type Name="List<*>"> <Expand> <Item Name="[size]">_data ? (_data->size_cache) : 0</Item> @@ -62,7 +62,7 @@ <DisplayString Condition="type == Variant::POOL_COLOR_ARRAY">{*(PoolColorArray *)_data._mem}</DisplayString> <StringView Condition="type == Variant::STRING && ((String *)(_data._mem))->_cowdata._ptr">((String *)(_data._mem))->_cowdata._ptr,su</StringView> - + <Expand> <Item Name="[value]" Condition="type == Variant::BOOL">_data._bool</Item> <Item Name="[value]" Condition="type == Variant::INT">_data._int</Item> @@ -143,7 +143,7 @@ <Item Name="alpha">a</Item> </Expand> </Type> - + <Type Name="Node" Inheritable="false"> <Expand> <Item Name="Object">(Object*)this</Item> diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp index 65caee3035..d1454c9096 100644 --- a/platform/windows/joypad_windows.cpp +++ b/platform/windows/joypad_windows.cpp @@ -146,8 +146,8 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) { if (have_device(instance->guidInstance) || num == -1) return false; - d_joypads[joypad_count] = dinput_gamepad(); - dinput_gamepad *joy = &d_joypads[joypad_count]; + d_joypads[num] = dinput_gamepad(); + dinput_gamepad *joy = &d_joypads[num]; const DWORD devtype = (instance->dwDevType & 0xFF); @@ -171,7 +171,7 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) { WORD version = 0; sprintf_s(uid, "%04x%04x%04x%04x%04x%04x%04x%04x", type, 0, vendor, 0, product, 0, version, 0); - id_to_change = joypad_count; + id_to_change = num; slider_count = 0; joy->di_joy->SetDataFormat(&c_dfDIJoystick2); diff --git a/platform_methods.py b/platform_methods.py index 805d7de82a..ec394d76d8 100644 --- a/platform_methods.py +++ b/platform_methods.py @@ -44,11 +44,12 @@ def run_in_subprocess(builder_function): json.dump(data, json_file, indent=2) json_file_size = os.stat(json_path).st_size - print( - "Executing builder function in subprocess: " - "module_path=%r, parameter_file=%r, parameter_file_size=%r, target=%r, source=%r" - % (module_path, json_path, json_file_size, target, source) - ) + if env["verbose"]: + print( + "Executing builder function in subprocess: " + "module_path=%r, parameter_file=%r, parameter_file_size=%r, target=%r, source=%r" + % (module_path, json_path, json_file_size, target, source) + ) try: exit_code = subprocess.call([sys.executable, module_path, json_path], env=subprocess_env) finally: diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 73f17060df..bd9e4f5bde 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -174,7 +174,7 @@ void Node3D::_notification(int p_what) { ERR_FAIL_COND(!data.viewport); if (get_script_instance()) { - get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_enter_world, nullptr, 0); + get_script_instance()->call(SceneStringNames::get_singleton()->_enter_world); } #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) { @@ -202,7 +202,7 @@ void Node3D::_notification(int p_what) { #endif if (get_script_instance()) { - get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_world, nullptr, 0); + get_script_instance()->call(SceneStringNames::get_singleton()->_exit_world); } data.viewport = nullptr; diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp index 9023f3c68a..32d7afd5df 100644 --- a/scene/3d/skeleton_ik_3d.cpp +++ b/scene/3d/skeleton_ik_3d.cpp @@ -511,6 +511,11 @@ bool SkeletonIK3D::is_running() { void SkeletonIK3D::start(bool p_one_time) { if (p_one_time) { set_process_internal(false); + + if (target_node_override) { + reload_goal(); + } + _solve_chain(); } else { set_process_internal(true); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 646f9f6095..5afc1f438e 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -120,9 +120,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { if (selection.enabled) { - DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, selection.begin, selection.end); + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end); } else { - DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, cursor_pos); + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, cursor_pos); } } } @@ -313,6 +313,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { DisplayServer::get_singleton()->virtual_keyboard_hide(); } + return; } break; case KEY_BACKSPACE: { @@ -943,9 +944,9 @@ void LineEdit::_notification(int p_what) { if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { if (selection.enabled) { - DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, selection.begin, selection.end); + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end); } else { - DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, cursor_pos); + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, cursor_pos); } } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 572be8d901..41cd67dbf1 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -2898,7 +2898,7 @@ Dictionary RichTextLabel::parse_expressions_for_values(Vector<String> p_expressi a.append(false); } } else if (!decimal.search(values[j]).is_null()) { - a.append(values[j].to_double()); + a.append(values[j].to_float()); } else if (!numerical.search(values[j]).is_null()) { a.append(values[j].to_int()); } else { diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 4db6ca2949..0e9ef71892 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -522,7 +522,7 @@ void ScrollBar::_drag_node_input(const Ref<InputEvent> &p_input) { drag_node_accum = Vector2(); last_drag_node_accum = Vector2(); drag_node_from = Vector2(orientation == HORIZONTAL ? get_value() : 0, orientation == VERTICAL ? get_value() : 0); - drag_node_touching = !DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())); + drag_node_touching = DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())); drag_node_touching_deaccel = false; time_since_motion = 0; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 07ebdb6523..b974dc2897 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1632,7 +1632,7 @@ void TextEdit::_notification(int p_what) { } if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) { - DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect()); + DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), true); } } break; case NOTIFICATION_FOCUS_EXIT: { @@ -4889,6 +4889,7 @@ void TextEdit::_update_caches() { cache.folded_eol_icon = get_theme_icon("GuiEllipsis", "EditorIcons"); cache.executing_icon = get_theme_icon("MainPlay", "EditorIcons"); text.set_font(cache.font); + text.clear_width_cache(); if (syntax_highlighter.is_valid()) { syntax_highlighter->set_text_edit(this); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index eeb7f9430d..5057f84192 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1971,7 +1971,7 @@ void Tree::_text_editor_enter(String p_text) { //popup_edited_item->edited_signal.call( popup_edited_item_col ); } break; case TreeItem::CELL_MODE_RANGE: { - c.val = p_text.to_double(); + c.val = p_text.to_float(); if (c.step > 0) { c.val = Math::stepify(c.val, c.step); } diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index d1bf038b8d..d6d1134cc9 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -434,7 +434,7 @@ void CanvasItem::_update_callback() { notification(NOTIFICATION_DRAW); emit_signal(SceneStringNames::get_singleton()->draw); if (get_script_instance()) { - get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_draw, nullptr, 0); + get_script_instance()->call(SceneStringNames::get_singleton()->_draw); } current_item_drawn = nullptr; drawing = false; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 88f9730f78..4dcfcd9d96 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -55,15 +55,13 @@ void Node::_notification(int p_notification) { case NOTIFICATION_PROCESS: { if (get_script_instance()) { Variant time = get_process_delta_time(); - const Variant *ptr[1] = { &time }; - get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_process, ptr, 1); + get_script_instance()->call(SceneStringNames::get_singleton()->_process, time); } } break; case NOTIFICATION_PHYSICS_PROCESS: { if (get_script_instance()) { Variant time = get_physics_process_delta_time(); - const Variant *ptr[1] = { &time }; - get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_physics_process, ptr, 1); + get_script_instance()->call(SceneStringNames::get_singleton()->_physics_process, time); } } break; @@ -146,7 +144,7 @@ void Node::_notification(int p_notification) { set_physics_process(true); } - get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_ready, nullptr, 0); + get_script_instance()->call(SceneStringNames::get_singleton()->_ready); } } break; @@ -216,7 +214,7 @@ void Node::_propagate_enter_tree() { notification(NOTIFICATION_ENTER_TREE); if (get_script_instance()) { - get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_enter_tree, nullptr, 0); + get_script_instance()->call(SceneStringNames::get_singleton()->_enter_tree); } emit_signal(SceneStringNames::get_singleton()->tree_entered); @@ -264,7 +262,7 @@ void Node::_propagate_exit_tree() { data.blocked--; if (get_script_instance()) { - get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_tree, nullptr, 0); + get_script_instance()->call(SceneStringNames::get_singleton()->_exit_tree); } emit_signal(SceneStringNames::get_singleton()->tree_exiting); @@ -1060,7 +1058,7 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) { bool unique = true; - if (p_child->data.name == StringName() || p_child->data.name.operator String()[0] == '@') { + if (p_child->data.name == StringName()) { //new unique name must be assigned unique = false; } else { diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index d6159e089b..2449b3bd35 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -250,11 +250,7 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou } if (p_call_flags & GROUP_CALL_REALTIME) { - if (p_call_flags & GROUP_CALL_MULTILEVEL) { - nodes[i]->call_multilevel(p_function, VARIANT_ARG_PASS); - } else { - nodes[i]->call(p_function, VARIANT_ARG_PASS); - } + nodes[i]->call(p_function, VARIANT_ARG_PASS); } else { MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS); } @@ -267,11 +263,7 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou } if (p_call_flags & GROUP_CALL_REALTIME) { - if (p_call_flags & GROUP_CALL_MULTILEVEL) { - nodes[i]->call_multilevel(p_function, VARIANT_ARG_PASS); - } else { - nodes[i]->call(p_function, VARIANT_ARG_PASS); - } + nodes[i]->call(p_function, VARIANT_ARG_PASS); } else { MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS); } @@ -883,8 +875,12 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p continue; } - n->call_multilevel(p_method, (const Variant **)v, 1); - //ERR_FAIL_COND(node_count != g.nodes.size()); + Callable::CallError err; + // Call both script and native method. + if (n->get_script_instance()) { + n->get_script_instance()->call(p_method, (const Variant **)v, 1, err); + } + n->call(p_method, (const Variant **)v, 1, err); } call_lock--; diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 41dc49bc64..0f74f2e973 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -223,7 +223,6 @@ public: GROUP_CALL_REVERSE = 1, GROUP_CALL_REALTIME = 2, GROUP_CALL_UNIQUE = 4, - GROUP_CALL_MULTILEVEL = 8, }; _FORCE_INLINE_ Window *get_root() const { return root; } diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 1c259b7d32..d962171555 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1607,7 +1607,17 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu } if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) { - control->call_multilevel(SceneStringNames::get_singleton()->_gui_input, ev); + // Call both script and native methods. + Callable::CallError error; + Variant event = ev; + const Variant *args[1] = { &event }; + if (control->get_script_instance()) { + control->get_script_instance()->call(SceneStringNames::get_singleton()->_gui_input, args, 1, error); + } + MethodBind *method = ClassDB::get_method(control->get_class_name(), SceneStringNames::get_singleton()->_gui_input); + if (method) { + method->call(control, args, 1, error); + } } if (!control->is_inside_tree() || control->is_set_as_toplevel()) { @@ -2306,7 +2316,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (gui.key_focus) { gui.key_event_accepted = false; if (gui.key_focus->can_process()) { - gui.key_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, p_event); + gui.key_focus->call(SceneStringNames::get_singleton()->_gui_input, p_event); if (gui.key_focus) { //maybe lost it gui.key_focus->emit_signal(SceneStringNames::get_singleton()->gui_input, p_event); } @@ -2516,7 +2526,7 @@ void Viewport::_drop_mouse_focus() { mb->set_global_position(c->get_local_mouse_position()); mb->set_button_index(i + 1); mb->set_pressed(false); - c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb); + c->call(SceneStringNames::get_singleton()->_gui_input, mb); } } } @@ -2581,7 +2591,7 @@ void Viewport::_post_gui_grab_click_focus() { mb->set_position(click); mb->set_button_index(i + 1); mb->set_pressed(false); - gui.mouse_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb); + gui.mouse_focus->call(SceneStringNames::get_singleton()->_gui_input, mb); } } @@ -2989,10 +2999,8 @@ void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coor } get_tree()->_call_input_pause(unhandled_input_group, "_unhandled_input", ev, this); - //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_input","_unhandled_input",ev); if (!is_input_handled() && Object::cast_to<InputEventKey>(*ev) != nullptr) { get_tree()->_call_input_pause(unhandled_key_input_group, "_unhandled_key_input", ev, this); - //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_key_input","_unhandled_key_input",ev); } if (physics_object_picking && !is_input_handled()) { diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 81f33d74fe..a5c5be8a44 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -247,6 +247,7 @@ void Window::_make_window() { } RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE); + DisplayServer::get_singleton()->show_window(window_id); } void Window::_update_from_window() { @@ -526,11 +527,11 @@ void Window::_update_window_size() { size.x = MAX(size_limit.x, size.x); size.y = MAX(size_limit.y, size.y); - if (max_size.x > 0 && max_size.x > min_size.x && max_size.x > size.x) { + if (max_size.x > 0 && max_size.x > min_size.x && size.x > max_size.x) { size.x = max_size.x; } - if (max_size.y > 0 && max_size.y > min_size.y && max_size.y > size.y) { + if (max_size.y > 0 && max_size.y > min_size.y && size.y > max_size.y) { size.y = max_size.y; } diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 3cbc64c075..47b8b6073b 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -372,7 +372,7 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init - AcceptDialog::set_swap_cancel_ok(GLOBAL_DEF("gui/common/swap_cancel_ok", bool(DisplayServer::get_singleton()->get_swap_cancel_ok()))); + AcceptDialog::set_swap_cancel_ok(GLOBAL_DEF_NOVAL("gui/common/swap_cancel_ok", bool(DisplayServer::get_singleton()->get_swap_cancel_ok()))); #endif /* REGISTER 3D */ @@ -547,6 +547,7 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeTexture2DArray>(); ClassDB::register_class<VisualShaderNodeCubemap>(); ClassDB::register_virtual_class<VisualShaderNodeUniform>(); + ClassDB::register_class<VisualShaderNodeUniformRef>(); ClassDB::register_class<VisualShaderNodeFloatUniform>(); ClassDB::register_class<VisualShaderNodeIntUniform>(); ClassDB::register_class<VisualShaderNodeBooleanUniform>(); diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp index abf7235fd6..9c8f9334a9 100644 --- a/scene/resources/syntax_highlighter.cpp +++ b/scene/resources/syntax_highlighter.cpp @@ -488,7 +488,7 @@ void CodeHighlighter::add_color_region(const String &p_start_key, const String & color_region.color = p_color; color_region.start_key = p_start_key; color_region.end_key = p_end_key; - color_region.line_only = p_line_only; + color_region.line_only = p_line_only || p_end_key == ""; color_regions.push_back(color_region); clear_highlighting_cache(); } diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 8236f9a9e3..e4851ad9f7 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -63,6 +63,44 @@ bool VisualShaderNode::is_port_separator(int p_index) const { return false; } +bool VisualShaderNode::is_output_port_connected(int p_port) const { + if (connected_output_ports.has(p_port)) { + return connected_output_ports[p_port]; + } + return false; +} + +void VisualShaderNode::set_output_port_connected(int p_port, bool p_connected) { + if (p_connected) { + connected_output_ports[p_port] = true; + ++connected_output_count; + } else { + --connected_output_count; + if (connected_output_count == 0) { + connected_output_ports[p_port] = false; + } + } +} + +bool VisualShaderNode::is_input_port_connected(int p_port) const { + if (connected_input_ports.has(p_port)) { + return connected_input_ports[p_port]; + } + return false; +} + +void VisualShaderNode::set_input_port_connected(int p_port, bool p_connected) { + connected_input_ports[p_port] = p_connected; +} + +bool VisualShaderNode::is_generate_input_var(int p_port) const { + return true; +} + +bool VisualShaderNode::is_code_generated() const { + return true; +} + Vector<VisualShader::DefaultTextureParam> VisualShaderNode::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { return Vector<VisualShader::DefaultTextureParam>(); } @@ -429,6 +467,7 @@ void VisualShader::remove_node(Type p_type, int p_id) { g->connections.erase(E); if (E->get().from_node == p_id) { g->nodes[E->get().to_node].prev_connected_nodes.erase(p_id); + g->nodes[E->get().to_node].node->set_input_port_connected(E->get().to_port, false); } } E = N; @@ -526,6 +565,8 @@ void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from c.to_port = p_to_port; g->connections.push_back(c); g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node); + g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true); + g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true); _queue_update(); } @@ -557,6 +598,8 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port, c.to_port = p_to_port; g->connections.push_back(c); g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node); + g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true); + g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true); _queue_update(); return OK; @@ -570,6 +613,8 @@ void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_por if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) { g->connections.erase(E); g->nodes[p_to_node].prev_connected_nodes.erase(p_from_node); + g->nodes[p_from_node].node->set_output_port_connected(p_from_port, false); + g->nodes[p_to_node].node->set_input_port_connected(p_to_port, false); _queue_update(); return; } @@ -1105,6 +1150,38 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui // then this node + Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, node); + for (int i = 0; i < params.size(); i++) { + def_tex_params.push_back(params[i]); + } + + Ref<VisualShaderNodeInput> input = vsnode; + bool skip_global = input.is_valid() && for_preview; + + if (!skip_global) { + Ref<VisualShaderNodeUniform> uniform = vsnode; + if (!uniform.is_valid() || !uniform->is_global_code_generated()) { + global_code += vsnode->generate_global(get_mode(), type, node); + } + + String class_name = vsnode->get_class_name(); + if (class_name == "VisualShaderNodeCustom") { + class_name = vsnode->get_script_instance()->get_script()->get_path(); + } + if (!r_classes.has(class_name)) { + global_code_per_node += vsnode->generate_global_per_node(get_mode(), type, node); + for (int i = 0; i < TYPE_MAX; i++) { + global_code_per_func[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node); + } + r_classes.insert(class_name); + } + } + + if (!vsnode->is_code_generated()) { // just generate globals and ignore locals + processed.insert(node); + return OK; + } + code += "// " + vsnode->get_caption() + ":" + itos(node) + "\n"; Vector<String> input_vars; @@ -1163,6 +1240,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui inputs[i] = "int(" + src_var + ")"; } } else { + if (!vsnode->is_generate_input_var(i)) { + continue; + } + Variant defval = vsnode->get_input_port_default_value(i); if (defval.get_type() == Variant::FLOAT) { float val = defval; @@ -1255,30 +1336,6 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui } } - Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, node); - for (int i = 0; i < params.size(); i++) { - def_tex_params.push_back(params[i]); - } - - Ref<VisualShaderNodeInput> input = vsnode; - bool skip_global = input.is_valid() && for_preview; - - if (!skip_global) { - global_code += vsnode->generate_global(get_mode(), type, node); - - String class_name = vsnode->get_class_name(); - if (class_name == "VisualShaderNodeCustom") { - class_name = vsnode->get_script_instance()->get_script()->get_path(); - } - if (!r_classes.has(class_name)) { - global_code_per_node += vsnode->generate_global_per_node(get_mode(), type, node); - for (int i = 0; i < TYPE_MAX; i++) { - global_code_per_func[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node); - } - r_classes.insert(class_name); - } - } - code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview); code += "\n"; // @@ -1352,6 +1409,9 @@ void VisualShader::_update_shader() const { static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light" }; String global_expressions; + Set<String> used_uniform_names; + List<VisualShaderNodeUniform *> uniforms; + for (int i = 0, index = 0; i < TYPE_MAX; i++) { if (!ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader_mode)).has(func_name[i])) { continue; @@ -1367,6 +1427,24 @@ void VisualShader::_update_shader() const { expr += "\n"; global_expressions += expr; } + Ref<VisualShaderNodeUniformRef> uniform_ref = Object::cast_to<VisualShaderNodeUniformRef>(E->get().node.ptr()); + if (uniform_ref.is_valid()) { + used_uniform_names.insert(uniform_ref->get_uniform_name()); + } + Ref<VisualShaderNodeUniform> uniform = Object::cast_to<VisualShaderNodeUniform>(E->get().node.ptr()); + if (uniform.is_valid()) { + uniforms.push_back(uniform.ptr()); + } + } + } + + for (int i = 0; i < uniforms.size(); i++) { + VisualShaderNodeUniform *uniform = uniforms[i]; + if (used_uniform_names.has(uniform->get_uniform_name())) { + global_code += uniform->generate_global(get_mode(), Type(i), -1); + const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(true); + } else { + const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(false); } } @@ -1956,6 +2034,199 @@ VisualShaderNodeInput::VisualShaderNodeInput() { shader_mode = Shader::MODE_MAX; } +////////////// UniformRef + +List<VisualShaderNodeUniformRef::Uniform> uniforms; + +void VisualShaderNodeUniformRef::add_uniform(const String &p_name, UniformType p_type) { + uniforms.push_back({ p_name, p_type }); +} + +void VisualShaderNodeUniformRef::clear_uniforms() { + uniforms.clear(); +} + +String VisualShaderNodeUniformRef::get_caption() const { + return "UniformRef"; +} + +int VisualShaderNodeUniformRef::get_input_port_count() const { + return 0; +} + +VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_input_port_type(int p_port) const { + return PortType::PORT_TYPE_SCALAR; +} + +String VisualShaderNodeUniformRef::get_input_port_name(int p_port) const { + return ""; +} + +int VisualShaderNodeUniformRef::get_output_port_count() const { + if (uniform_name == "[None]") { + return 0; + } + + switch (uniform_type) { + case UniformType::UNIFORM_TYPE_FLOAT: + return 1; + case UniformType::UNIFORM_TYPE_INT: + return 1; + case UniformType::UNIFORM_TYPE_BOOLEAN: + return 1; + case UniformType::UNIFORM_TYPE_VECTOR: + return 1; + case UniformType::UNIFORM_TYPE_TRANSFORM: + return 1; + case UniformType::UNIFORM_TYPE_COLOR: + return 2; + case UniformType::UNIFORM_TYPE_SAMPLER: + return 1; + default: + break; + } + return 0; +} + +VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port_type(int p_port) const { + switch (uniform_type) { + case UniformType::UNIFORM_TYPE_FLOAT: + return PortType::PORT_TYPE_SCALAR; + case UniformType::UNIFORM_TYPE_INT: + return PortType::PORT_TYPE_SCALAR_INT; + case UniformType::UNIFORM_TYPE_BOOLEAN: + return PortType::PORT_TYPE_BOOLEAN; + case UniformType::UNIFORM_TYPE_VECTOR: + return PortType::PORT_TYPE_VECTOR; + case UniformType::UNIFORM_TYPE_TRANSFORM: + return PortType::PORT_TYPE_TRANSFORM; + case UniformType::UNIFORM_TYPE_COLOR: + if (p_port == 0) { + return PortType::PORT_TYPE_VECTOR; + } else if (p_port == 1) { + return PORT_TYPE_SCALAR; + } + break; + case UniformType::UNIFORM_TYPE_SAMPLER: + return PortType::PORT_TYPE_SAMPLER; + default: + break; + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const { + switch (uniform_type) { + case UniformType::UNIFORM_TYPE_FLOAT: + return ""; + case UniformType::UNIFORM_TYPE_INT: + return ""; + case UniformType::UNIFORM_TYPE_BOOLEAN: + return ""; + case UniformType::UNIFORM_TYPE_VECTOR: + return ""; + case UniformType::UNIFORM_TYPE_TRANSFORM: + return ""; + case UniformType::UNIFORM_TYPE_COLOR: + if (p_port == 0) { + return "rgb"; + } else if (p_port == 1) { + return "alpha"; + } + break; + case UniformType::UNIFORM_TYPE_SAMPLER: + return ""; + break; + default: + break; + } + return ""; +} + +void VisualShaderNodeUniformRef::set_uniform_name(const String &p_name) { + uniform_name = p_name; + if (p_name != "[None]") { + uniform_type = get_uniform_type_by_name(p_name); + } else { + uniform_type = UniformType::UNIFORM_TYPE_FLOAT; + } + emit_changed(); +} + +String VisualShaderNodeUniformRef::get_uniform_name() const { + return uniform_name; +} + +int VisualShaderNodeUniformRef::get_uniforms_count() const { + return uniforms.size(); +} + +String VisualShaderNodeUniformRef::get_uniform_name_by_index(int p_idx) const { + if (p_idx >= 0 && p_idx < uniforms.size()) { + return uniforms[p_idx].name; + } + return ""; +} + +VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_name(const String &p_name) const { + for (int i = 0; i < uniforms.size(); i++) { + if (uniforms[i].name == p_name) { + return uniforms[i].type; + } + } + return UniformType::UNIFORM_TYPE_FLOAT; +} + +VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_index(int p_idx) const { + if (p_idx >= 0 && p_idx < uniforms.size()) { + return uniforms[p_idx].type; + } + return UniformType::UNIFORM_TYPE_FLOAT; +} + +String VisualShaderNodeUniformRef::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + switch (uniform_type) { + case UniformType::UNIFORM_TYPE_FLOAT: + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + case UniformType::UNIFORM_TYPE_INT: + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + case UniformType::UNIFORM_TYPE_BOOLEAN: + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + case UniformType::UNIFORM_TYPE_VECTOR: + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + case UniformType::UNIFORM_TYPE_TRANSFORM: + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + case UniformType::UNIFORM_TYPE_COLOR: { + String code = "\t" + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n"; + code += "\t" + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n"; + return code; + } break; + case UniformType::UNIFORM_TYPE_SAMPLER: + break; + default: + break; + } + return ""; +} + +void VisualShaderNodeUniformRef::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniformRef::set_uniform_name); + ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniformRef::get_uniform_name); + + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name", PROPERTY_HINT_ENUM, ""), "set_uniform_name", "get_uniform_name"); +} + +Vector<StringName> VisualShaderNodeUniformRef::get_editable_properties() const { + Vector<StringName> props; + props.push_back("uniform_name"); + return props; +} + +VisualShaderNodeUniformRef::VisualShaderNodeUniformRef() { + uniform_name = "[None]"; + uniform_type = UniformType::UNIFORM_TYPE_FLOAT; +} + //////////////////////////////////////////// const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { @@ -2149,6 +2420,14 @@ VisualShaderNodeUniform::Qualifier VisualShaderNodeUniform::get_qualifier() cons return qualifier; } +void VisualShaderNodeUniform::set_global_code_generated(bool p_enabled) { + global_code_generated = p_enabled; +} + +bool VisualShaderNodeUniform::is_global_code_generated() const { + return global_code_generated; +} + void VisualShaderNodeUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniform::set_uniform_name); ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniform::get_uniform_name); diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index dbb8d1d28c..05d8950be9 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -182,6 +182,9 @@ class VisualShaderNode : public Resource { int port_preview; Map<int, Variant> default_input_values; + Map<int, bool> connected_input_ports; + Map<int, bool> connected_output_ports; + int connected_output_count = 0; protected: bool simple_decl; @@ -222,6 +225,14 @@ public: virtual bool is_port_separator(int p_index) const; + bool is_output_port_connected(int p_port) const; + void set_output_port_connected(int p_port, bool p_connected); + bool is_input_port_connected(int p_port) const; + void set_input_port_connected(int p_port, bool p_connected); + virtual bool is_generate_input_var(int p_port) const; + + virtual bool is_code_generated() const; + virtual Vector<StringName> get_editable_properties() const; virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const; @@ -378,6 +389,7 @@ public: private: String uniform_name; Qualifier qualifier; + bool global_code_generated = false; protected: static void _bind_methods(); @@ -390,6 +402,9 @@ public: void set_qualifier(Qualifier p_qual); Qualifier get_qualifier() const; + void set_global_code_generated(bool p_enabled); + bool is_global_code_generated() const; + virtual bool is_qualifier_supported(Qualifier p_qual) const = 0; virtual Vector<StringName> get_editable_properties() const override; @@ -400,6 +415,62 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeUniform::Qualifier) +class VisualShaderNodeUniformRef : public VisualShaderNode { + GDCLASS(VisualShaderNodeUniformRef, VisualShaderNode); + +public: + enum UniformType { + UNIFORM_TYPE_FLOAT, + UNIFORM_TYPE_INT, + UNIFORM_TYPE_BOOLEAN, + UNIFORM_TYPE_VECTOR, + UNIFORM_TYPE_TRANSFORM, + UNIFORM_TYPE_COLOR, + UNIFORM_TYPE_SAMPLER, + }; + + struct Uniform { + String name; + UniformType type; + }; + +private: + String uniform_name; + UniformType uniform_type; + +protected: + static void _bind_methods(); + +public: + static void add_uniform(const String &p_name, UniformType p_type); + static void clear_uniforms(); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + void set_uniform_name(const String &p_name); + String get_uniform_name() const; + + int get_uniforms_count() const; + String get_uniform_name_by_index(int p_idx) const; + UniformType get_uniform_type_by_name(const String &p_name) const; + UniformType get_uniform_type_by_index(int p_idx) const; + + virtual Vector<StringName> get_editable_properties() const override; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + VisualShaderNodeUniformRef(); +}; + class VisualShaderNodeGroupBase : public VisualShaderNode { GDCLASS(VisualShaderNodeGroupBase, VisualShaderNode); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 88f5287831..b0c871bc71 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -3435,12 +3435,19 @@ String VisualShaderNodeFloatUniform::get_output_port_name(int p_port) const { } String VisualShaderNodeFloatUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = ""; if (hint == HINT_RANGE) { - return _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ");\n"; + code += _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ")"; } else if (hint == HINT_RANGE_STEP) { - return _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ");\n"; + code += _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ")"; + } else { + code += _get_qual_str() + "uniform float " + get_uniform_name(); + } + if (default_value_enabled) { + code += " = " + rtos(default_value); } - return _get_qual_str() + "uniform float " + get_uniform_name() + ";\n"; + code += ";\n"; + return code; } String VisualShaderNodeFloatUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { @@ -3483,6 +3490,24 @@ float VisualShaderNodeFloatUniform::get_step() const { return hint_range_step; } +void VisualShaderNodeFloatUniform::set_default_value_enabled(bool p_enabled) { + default_value_enabled = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeFloatUniform::is_default_value_enabled() const { + return default_value_enabled; +} + +void VisualShaderNodeFloatUniform::set_default_value(float p_value) { + default_value = p_value; + emit_changed(); +} + +float VisualShaderNodeFloatUniform::get_default_value() const { + return default_value; +} + void VisualShaderNodeFloatUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeFloatUniform::set_hint); ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeFloatUniform::get_hint); @@ -3496,10 +3521,18 @@ void VisualShaderNodeFloatUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeFloatUniform::set_step); ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeFloatUniform::get_step); + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeFloatUniform::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeFloatUniform::is_default_value_enabled); + + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeFloatUniform::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeFloatUniform::get_default_value); + ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range+Step"), "set_hint", "get_hint"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "min"), "set_min", "get_min"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max"), "set_max", "get_max"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step"), "set_step", "get_step"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "default_value"), "set_default_value", "get_default_value"); BIND_ENUM_CONSTANT(HINT_NONE); BIND_ENUM_CONSTANT(HINT_RANGE); @@ -3520,6 +3553,10 @@ Vector<StringName> VisualShaderNodeFloatUniform::get_editable_properties() const if (hint == HINT_RANGE_STEP) { props.push_back("step"); } + props.push_back("default_value_enabled"); + if (default_value_enabled) { + props.push_back("default_value"); + } return props; } @@ -3528,6 +3565,8 @@ VisualShaderNodeFloatUniform::VisualShaderNodeFloatUniform() { hint_range_min = 0.0; hint_range_max = 1.0; hint_range_step = 0.1; + default_value_enabled = false; + default_value = 0.0; } ////////////// Integer Uniform @@ -3561,12 +3600,19 @@ String VisualShaderNodeIntUniform::get_output_port_name(int p_port) const { } String VisualShaderNodeIntUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = ""; if (hint == HINT_RANGE) { - return _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ");\n"; + code += _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ")"; } else if (hint == HINT_RANGE_STEP) { - return _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ");\n"; + code += _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ", " + itos(hint_range_step) + ")"; + } else { + code += _get_qual_str() + "uniform int " + get_uniform_name(); + } + if (default_value_enabled) { + code += " = " + itos(default_value); } - return _get_qual_str() + "uniform int " + get_uniform_name() + ";\n"; + code += ";\n"; + return code; } String VisualShaderNodeIntUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { @@ -3609,6 +3655,24 @@ int VisualShaderNodeIntUniform::get_step() const { return hint_range_step; } +void VisualShaderNodeIntUniform::set_default_value_enabled(bool p_enabled) { + default_value_enabled = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeIntUniform::is_default_value_enabled() const { + return default_value_enabled; +} + +void VisualShaderNodeIntUniform::set_default_value(int p_value) { + default_value = p_value; + emit_changed(); +} + +int VisualShaderNodeIntUniform::get_default_value() const { + return default_value; +} + void VisualShaderNodeIntUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeIntUniform::set_hint); ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeIntUniform::get_hint); @@ -3622,10 +3686,18 @@ void VisualShaderNodeIntUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeIntUniform::set_step); ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeIntUniform::get_step); + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeIntUniform::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeIntUniform::is_default_value_enabled); + + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeIntUniform::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeIntUniform::get_default_value); + ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range+Step"), "set_hint", "get_hint"); ADD_PROPERTY(PropertyInfo(Variant::INT, "min"), "set_min", "get_min"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max"), "set_max", "get_max"); ADD_PROPERTY(PropertyInfo(Variant::INT, "step"), "set_step", "get_step"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "default_value"), "set_default_value", "get_default_value"); BIND_ENUM_CONSTANT(HINT_NONE); BIND_ENUM_CONSTANT(HINT_RANGE); @@ -3646,6 +3718,10 @@ Vector<StringName> VisualShaderNodeIntUniform::get_editable_properties() const { if (hint == HINT_RANGE_STEP) { props.push_back("step"); } + props.push_back("default_value_enabled"); + if (default_value_enabled) { + props.push_back("default_value"); + } return props; } @@ -3654,6 +3730,8 @@ VisualShaderNodeIntUniform::VisualShaderNodeIntUniform() { hint_range_min = 0; hint_range_max = 100; hint_range_step = 1; + default_value_enabled = false; + default_value = 0; } ////////////// Boolean Uniform @@ -3686,19 +3764,68 @@ String VisualShaderNodeBooleanUniform::get_output_port_name(int p_port) const { return ""; //no output port means the editor will be used as port } +void VisualShaderNodeBooleanUniform::set_default_value_enabled(bool p_enabled) { + default_value_enabled = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeBooleanUniform::is_default_value_enabled() const { + return default_value_enabled; +} + +void VisualShaderNodeBooleanUniform::set_default_value(bool p_value) { + default_value = p_value; + emit_changed(); +} + +bool VisualShaderNodeBooleanUniform::get_default_value() const { + return default_value; +} + String VisualShaderNodeBooleanUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - return _get_qual_str() + "uniform bool " + get_uniform_name() + ";\n"; + String code = _get_qual_str() + "uniform bool " + get_uniform_name(); + if (default_value_enabled) { + if (default_value) { + code += " = true"; + } else { + code += " = false"; + } + } + code += ";\n"; + return code; } String VisualShaderNodeBooleanUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } +void VisualShaderNodeBooleanUniform::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeBooleanUniform::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeBooleanUniform::is_default_value_enabled); + + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeBooleanUniform::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeBooleanUniform::get_default_value); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value"), "set_default_value", "get_default_value"); +} + bool VisualShaderNodeBooleanUniform::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } +Vector<StringName> VisualShaderNodeBooleanUniform::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); + props.push_back("default_value_enabled"); + if (default_value_enabled) { + props.push_back("default_value"); + } + return props; +} + VisualShaderNodeBooleanUniform::VisualShaderNodeBooleanUniform() { + default_value_enabled = false; + default_value = false; } ////////////// Color Uniform @@ -3731,8 +3858,31 @@ String VisualShaderNodeColorUniform::get_output_port_name(int p_port) const { return p_port == 0 ? "color" : "alpha"; //no output port means the editor will be used as port } +void VisualShaderNodeColorUniform::set_default_value_enabled(bool p_enabled) { + default_value_enabled = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeColorUniform::is_default_value_enabled() const { + return default_value_enabled; +} + +void VisualShaderNodeColorUniform::set_default_value(const Color &p_value) { + default_value = p_value; + emit_changed(); +} + +Color VisualShaderNodeColorUniform::get_default_value() const { + return default_value; +} + String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - return _get_qual_str() + "uniform vec4 " + get_uniform_name() + " : hint_color;\n"; + String code = _get_qual_str() + "uniform vec4 " + get_uniform_name() + " : hint_color"; + if (default_value_enabled) { + code += vformat(" = vec4(%.6f, %.6f, %.6f, %.6f)", default_value.r, default_value.g, default_value.b, default_value.a); + } + code += ";\n"; + return code; } String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { @@ -3741,11 +3891,33 @@ String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualSh return code; } +void VisualShaderNodeColorUniform::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeColorUniform::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeColorUniform::is_default_value_enabled); + + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeColorUniform::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeColorUniform::get_default_value); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_value"), "set_default_value", "get_default_value"); +} + bool VisualShaderNodeColorUniform::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } +Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); + props.push_back("default_value_enabled"); + if (default_value_enabled) { + props.push_back("default_value"); + } + return props; +} + VisualShaderNodeColorUniform::VisualShaderNodeColorUniform() { + default_value_enabled = false; + default_value = Color(1.0, 1.0, 1.0, 1.0); } ////////////// Vector Uniform @@ -3778,19 +3950,64 @@ String VisualShaderNodeVec3Uniform::get_output_port_name(int p_port) const { return ""; //no output port means the editor will be used as port } +void VisualShaderNodeVec3Uniform::set_default_value_enabled(bool p_enabled) { + default_value_enabled = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeVec3Uniform::is_default_value_enabled() const { + return default_value_enabled; +} + +void VisualShaderNodeVec3Uniform::set_default_value(const Vector3 &p_value) { + default_value = p_value; + emit_changed(); +} + +Vector3 VisualShaderNodeVec3Uniform::get_default_value() const { + return default_value; +} + String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - return _get_qual_str() + "uniform vec3 " + get_uniform_name() + ";\n"; + String code = _get_qual_str() + "uniform vec3 " + get_uniform_name(); + if (default_value_enabled) { + code += vformat(" = vec3(%.6f, %.6f, %.6f)", default_value.x, default_value.y, default_value.z); + } + code += ";\n"; + return code; } String VisualShaderNodeVec3Uniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } +void VisualShaderNodeVec3Uniform::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec3Uniform::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec3Uniform::is_default_value_enabled); + + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec3Uniform::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec3Uniform::get_default_value); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "default_value"), "set_default_value", "get_default_value"); +} + bool VisualShaderNodeVec3Uniform::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } +Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); + props.push_back("default_value_enabled"); + if (default_value_enabled) { + props.push_back("default_value"); + } + return props; +} + VisualShaderNodeVec3Uniform::VisualShaderNodeVec3Uniform() { + default_value_enabled = false; + default_value = Vector3(0.0, 0.0, 0.0); } ////////////// Transform Uniform @@ -3823,19 +4040,68 @@ String VisualShaderNodeTransformUniform::get_output_port_name(int p_port) const return ""; //no output port means the editor will be used as port } +void VisualShaderNodeTransformUniform::set_default_value_enabled(bool p_enabled) { + default_value_enabled = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeTransformUniform::is_default_value_enabled() const { + return default_value_enabled; +} + +void VisualShaderNodeTransformUniform::set_default_value(const Transform &p_value) { + default_value = p_value; + emit_changed(); +} + +Transform VisualShaderNodeTransformUniform::get_default_value() const { + return default_value; +} + String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - return _get_qual_str() + "uniform mat4 " + get_uniform_name() + ";\n"; + String code = _get_qual_str() + "uniform mat4 " + get_uniform_name(); + if (default_value_enabled) { + Vector3 row0 = default_value.basis.get_row(0); + Vector3 row1 = default_value.basis.get_row(1); + Vector3 row2 = default_value.basis.get_row(2); + Vector3 origin = default_value.origin; + code += " = mat4(" + vformat("vec4(%.6f, %.6f, %.6f, 0.0)", row0.x, row0.y, row0.z) + vformat(", vec4(%.6f, %.6f, %.6f, 0.0)", row1.x, row1.y, row1.z) + vformat(", vec4(%.6f, %.6f, %.6f, 0.0)", row2.x, row2.y, row2.z) + vformat(", vec4(%.6f, %.6f, %.6f, 1.0)", origin.x, origin.y, origin.z) + ")"; + } + code += ";\n"; + return code; } String VisualShaderNodeTransformUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } +void VisualShaderNodeTransformUniform::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeTransformUniform::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeTransformUniform::is_default_value_enabled); + + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeTransformUniform::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeTransformUniform::get_default_value); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "default_value"), "set_default_value", "get_default_value"); +} + bool VisualShaderNodeTransformUniform::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } +Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); + props.push_back("default_value_enabled"); + if (default_value_enabled) { + props.push_back("default_value"); + } + return props; +} + VisualShaderNodeTransformUniform::VisualShaderNodeTransformUniform() { + default_value_enabled = false; + default_value = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0); } ////////////// Texture Uniform @@ -3915,6 +4181,10 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu return code; } +bool VisualShaderNodeTextureUniform::is_code_generated() const { + return is_output_port_connected(0) || is_output_port_connected(1); // rgb or alpha +} + String VisualShaderNodeTextureUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String id = get_uniform_name(); String code = "\t{\n"; @@ -4453,6 +4723,13 @@ String VisualShaderNodeFresnel::get_output_port_name(int p_port) const { return "result"; } +bool VisualShaderNodeFresnel::is_generate_input_var(int p_port) const { + if (p_port == 2) { + return false; + } + return true; +} + String VisualShaderNodeFresnel::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String normal; String view; @@ -4467,7 +4744,15 @@ String VisualShaderNodeFresnel::generate_code(Shader::Mode p_mode, VisualShader: view = p_input_vars[1]; } - return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + "));\n"; + if (is_input_port_connected(2)) { + return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + "));\n"; + } else { + if (get_input_port_default_value(2)) { + return "\t" + p_output_vars[0] + " = pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n"; + } else { + return "\t" + p_output_vars[0] + " = pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n"; + } + } } String VisualShaderNodeFresnel::get_input_port_default_hint(int p_port) const { diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 13a132c60e..b9c40d0521 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -1486,6 +1486,8 @@ private: float hint_range_min; float hint_range_max; float hint_range_step; + bool default_value_enabled; + float default_value; protected: static void _bind_methods(); @@ -1516,6 +1518,12 @@ public: void set_step(float p_value); float get_step() const; + void set_default_value_enabled(bool p_enabled); + bool is_default_value_enabled() const; + + void set_default_value(float p_value); + float get_default_value() const; + bool is_qualifier_supported(Qualifier p_qual) const override; virtual Vector<StringName> get_editable_properties() const override; @@ -1540,6 +1548,8 @@ private: int hint_range_min; int hint_range_max; int hint_range_step; + bool default_value_enabled; + int default_value; protected: static void _bind_methods(); @@ -1570,6 +1580,12 @@ public: void set_step(int p_value); int get_step() const; + void set_default_value_enabled(bool p_enabled); + bool is_default_value_enabled() const; + + void set_default_value(int p_value); + int get_default_value() const; + bool is_qualifier_supported(Qualifier p_qual) const override; virtual Vector<StringName> get_editable_properties() const override; @@ -1584,6 +1600,13 @@ VARIANT_ENUM_CAST(VisualShaderNodeIntUniform::Hint) class VisualShaderNodeBooleanUniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeBooleanUniform, VisualShaderNodeUniform); +private: + bool default_value_enabled; + bool default_value; + +protected: + static void _bind_methods(); + public: virtual String get_caption() const override; @@ -1598,8 +1621,16 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + void set_default_value_enabled(bool p_enabled); + bool is_default_value_enabled() const; + + void set_default_value(bool p_value); + bool get_default_value() const; + bool is_qualifier_supported(Qualifier p_qual) const override; + virtual Vector<StringName> get_editable_properties() const override; + VisualShaderNodeBooleanUniform(); }; @@ -1608,6 +1639,13 @@ public: class VisualShaderNodeColorUniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeColorUniform, VisualShaderNodeUniform); +private: + bool default_value_enabled; + Color default_value; + +protected: + static void _bind_methods(); + public: virtual String get_caption() const override; @@ -1622,8 +1660,16 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + void set_default_value_enabled(bool p_enabled); + bool is_default_value_enabled() const; + + void set_default_value(const Color &p_value); + Color get_default_value() const; + bool is_qualifier_supported(Qualifier p_qual) const override; + virtual Vector<StringName> get_editable_properties() const override; + VisualShaderNodeColorUniform(); }; @@ -1632,6 +1678,13 @@ public: class VisualShaderNodeVec3Uniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform); +private: + bool default_value_enabled; + Vector3 default_value; + +protected: + static void _bind_methods(); + public: virtual String get_caption() const override; @@ -1646,8 +1699,16 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + void set_default_value_enabled(bool p_enabled); + bool is_default_value_enabled() const; + + void set_default_value(const Vector3 &p_value); + Vector3 get_default_value() const; + bool is_qualifier_supported(Qualifier p_qual) const override; + virtual Vector<StringName> get_editable_properties() const override; + VisualShaderNodeVec3Uniform(); }; @@ -1656,6 +1717,13 @@ public: class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform); +private: + bool default_value_enabled; + Transform default_value; + +protected: + static void _bind_methods(); + public: virtual String get_caption() const override; @@ -1670,8 +1738,16 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + void set_default_value_enabled(bool p_enabled); + bool is_default_value_enabled() const; + + void set_default_value(const Transform &p_value); + Transform get_default_value() const; + bool is_qualifier_supported(Qualifier p_qual) const override; + virtual Vector<StringName> get_editable_properties() const override; + VisualShaderNodeTransformUniform(); }; @@ -1715,6 +1791,8 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + virtual bool is_code_generated() const override; + Vector<StringName> get_editable_properties() const override; void set_texture_type(TextureType p_type); @@ -1875,6 +1953,7 @@ public: virtual String get_output_port_name(int p_port) const override; virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_generate_input_var(int p_port) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; VisualShaderNodeFresnel(); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index f46e56cd5a..8f6d6d3b99 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -31,6 +31,7 @@ #include "display_server.h" #include "core/input/input.h" +#include "core/method_bind_ext.gen.inc" #include "scene/resources/texture.h" DisplayServer *DisplayServer::singleton = nullptr; @@ -185,6 +186,10 @@ DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, uint ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server."); } +void DisplayServer::show_window(WindowID p_id) { + ERR_FAIL_MSG("Sub-windows not supported by this display server."); +} + void DisplayServer::delete_sub_window(WindowID p_id) { ERR_FAIL_MSG("Sub-windows not supported by this display server."); } @@ -213,7 +218,7 @@ bool DisplayServer::is_console_visible() const { return false; } -void DisplayServer::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_length, int p_cursor_start, int p_cursor_end) { +void DisplayServer::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) { WARN_PRINT("Virtual keyboard not supported by this display server."); } @@ -455,7 +460,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("console_set_visible", "console_visible"), &DisplayServer::console_set_visible); ClassDB::bind_method(D_METHOD("is_console_visible"), &DisplayServer::is_console_visible); - ClassDB::bind_method(D_METHOD("virtual_keyboard_show", "existing_text", "position", "max_length", "cursor_start", "cursor_end"), &DisplayServer::virtual_keyboard_show, DEFVAL(Rect2i()), DEFVAL(-1), DEFVAL(-1), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("virtual_keyboard_show", "existing_text", "position", "multiline", "max_length", "cursor_start", "cursor_end"), &DisplayServer::virtual_keyboard_show, DEFVAL(Rect2i()), DEFVAL(false), DEFVAL(-1), DEFVAL(-1), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("virtual_keyboard_hide"), &DisplayServer::virtual_keyboard_hide); ClassDB::bind_method(D_METHOD("virtual_keyboard_get_height"), &DisplayServer::virtual_keyboard_get_height); diff --git a/servers/display_server.h b/servers/display_server.h index 2cf0a83dbd..b652418244 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -220,6 +220,7 @@ public: }; virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); + virtual void show_window(WindowID p_id); virtual void delete_sub_window(WindowID p_id); virtual WindowID get_window_at_screen_position(const Point2i &p_position) const = 0; @@ -288,7 +289,7 @@ public: virtual void console_set_visible(bool p_enabled); virtual bool is_console_visible() const; - virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1); + virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1); virtual void virtual_keyboard_hide(); // returns height of the currently shown virtual keyboard (0 if keyboard is hidden) diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 2083caf4c3..966dcbd651 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -34,9 +34,8 @@ #include "core/os/os.h" #include "core/pair.h" #include "physics_server_2d_sw.h" - -_FORCE_INLINE_ static bool _can_collide_with(CollisionObject2DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_ignore_layers = false) { - if (!p_ignore_layers && !(p_object->get_collision_layer() & p_collision_mask)) { +_FORCE_INLINE_ static bool _can_collide_with(CollisionObject2DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { + if (!(p_object->get_collision_layer() & p_collision_mask)) { return false; } @@ -65,7 +64,7 @@ int PhysicsDirectSpaceState2DSW::_intersect_point_impl(const Vector2 &p_point, S int cc = 0; for (int i = 0; i < amount; i++) { - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas, p_filter_by_canvas)) { + if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { continue; } diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp index aa4cb894dd..48f250ba35 100644 --- a/servers/physics_3d/space_3d_sw.cpp +++ b/servers/physics_3d/space_3d_sw.cpp @@ -34,8 +34,8 @@ #include "core/project_settings.h" #include "physics_server_3d_sw.h" -_FORCE_INLINE_ static bool _can_collide_with(CollisionObject3DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_ignore_layers = false) { - if (!p_ignore_layers && !(p_object->get_collision_layer() & p_collision_mask)) { +_FORCE_INLINE_ static bool _can_collide_with(CollisionObject3DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { + if (!(p_object->get_collision_layer() & p_collision_mask)) { return false; } @@ -117,7 +117,7 @@ bool PhysicsDirectSpaceState3DSW::intersect_ray(const Vector3 &p_from, const Vec real_t min_d = 1e10; for (int i = 0; i < amount; i++) { - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas, p_pick_ray)) { + if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { continue; } diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp index 873f74e3be..8c122983da 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp @@ -1331,8 +1331,8 @@ void RasterizerSceneHighEndRD::_add_geometry(InstanceBase *p_instance, uint32_t material = (MaterialData *)storage->material_get_data(material->next_pass, RasterizerStorageRD::SHADER_TYPE_3D); if (!material || !material->shader_data->valid) { break; - _add_geometry_with_material(p_instance, p_surface, material, material->next_pass, p_pass_mode, p_geometry_index, p_using_sdfgi); } + _add_geometry_with_material(p_instance, p_surface, material, material->next_pass, p_pass_mode, p_geometry_index, p_using_sdfgi); } } diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 535011710d..d6acad83f7 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -645,7 +645,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { if (hexa_found) { tk.constant = (double)str.hex_to_int(true); } else { - tk.constant = str.to_double(); + tk.constant = str.to_float(); } tk.line = tk_line; diff --git a/tests/SCsub b/tests/SCsub new file mode 100644 index 0000000000..84c9fc1ffe --- /dev/null +++ b/tests/SCsub @@ -0,0 +1,22 @@ +#!/usr/bin/python + +Import("env") + +env.tests_sources = [] + +env_tests = env.Clone() + +# Enable test framework and inform it of configuration method. +env_tests.Append(CPPDEFINES=["DOCTEST_CONFIG_IMPLEMENT"]) + +# We must disable the THREAD_LOCAL entirely in doctest to prevent crashes on debugging +# Since we link with /MT thread_local is always expired when the header is used +# So the debugger crashes the engine and it causes weird errors +# Explained in https://github.com/onqtam/doctest/issues/401 +if env_tests["platform"] == "windows": + env_tests.Append(CPPDEFINES=[("DOCTEST_THREAD_LOCAL", "")]) + +env_tests.add_source_files(env.tests_sources, "*.cpp") + +lib = env_tests.add_library("tests", env.tests_sources) +env.Prepend(LIBS=[lib]) diff --git a/main/tests/test_astar.cpp b/tests/test_astar.h index cb5fcfe37b..bef6127471 100644 --- a/main/tests/test_astar.cpp +++ b/tests/test_astar.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* test_astar.cpp */ +/* test_astar.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "test_astar.h" +#ifndef TEST_ASTAR_H +#define TEST_ASTAR_H #include "core/math/a_star.h" #include "core/math/math_funcs.h" @@ -37,14 +38,18 @@ #include <math.h> #include <stdio.h> +#include "tests/test_macros.h" + namespace TestAStar { class ABCX : public AStar { public: - enum { A, + enum { + A, B, C, - X }; + X, + }; ABCX() { add_point(A, Vector3(0, 0, 0)); @@ -57,7 +62,7 @@ public: connect_points(X, A); } - // Disable heuristic completely + // Disable heuristic completely. float _compute_cost(int p_from, int p_to) { if (p_from == A && p_to == C) { return 1000; @@ -66,34 +71,29 @@ public: } }; -bool test_abc() { +TEST_CASE("[AStar] ABC path") { ABCX abcx; Vector<int> path = abcx.get_id_path(ABCX::A, ABCX::C); - bool ok = path.size() == 3; - int i = 0; - ok = ok && path[i++] == ABCX::A; - ok = ok && path[i++] == ABCX::B; - ok = ok && path[i++] == ABCX::C; - return ok; + REQUIRE(path.size() == 3); + CHECK(path[0] == ABCX::A); + CHECK(path[1] == ABCX::B); + CHECK(path[2] == ABCX::C); } -bool test_abcx() { +TEST_CASE("[AStar] ABCX path") { ABCX abcx; Vector<int> path = abcx.get_id_path(ABCX::X, ABCX::C); - bool ok = path.size() == 4; - int i = 0; - ok = ok && path[i++] == ABCX::X; - ok = ok && path[i++] == ABCX::A; - ok = ok && path[i++] == ABCX::B; - ok = ok && path[i++] == ABCX::C; - return ok; + REQUIRE(path.size() == 4); + CHECK(path[0] == ABCX::X); + CHECK(path[1] == ABCX::A); + CHECK(path[2] == ABCX::B); + CHECK(path[3] == ABCX::C); } -bool test_add_remove() { +TEST_CASE("[AStar] Add/Remove") { AStar a; - bool ok = true; - // Manual tests + // Manual tests. a.add_point(1, Vector3(0, 0, 0)); a.add_point(2, Vector3(0, 1, 0)); a.add_point(3, Vector3(1, 1, 0)); @@ -102,47 +102,47 @@ bool test_add_remove() { a.connect_points(1, 3, true); a.connect_points(1, 4, false); - ok = ok && (a.are_points_connected(2, 1)); - ok = ok && (a.are_points_connected(4, 1)); - ok = ok && (a.are_points_connected(2, 1, false)); - ok = ok && (a.are_points_connected(4, 1, false) == false); + CHECK(a.are_points_connected(2, 1)); + CHECK(a.are_points_connected(4, 1)); + CHECK(a.are_points_connected(2, 1, false)); + CHECK_FALSE(a.are_points_connected(4, 1, false)); a.disconnect_points(1, 2, true); - ok = ok && (a.get_point_connections(1).size() == 2); // 3, 4 - ok = ok && (a.get_point_connections(2).size() == 0); + CHECK(a.get_point_connections(1).size() == 2); // 3, 4 + CHECK(a.get_point_connections(2).size() == 0); a.disconnect_points(4, 1, false); - ok = ok && (a.get_point_connections(1).size() == 2); // 3, 4 - ok = ok && (a.get_point_connections(4).size() == 0); + CHECK(a.get_point_connections(1).size() == 2); // 3, 4 + CHECK(a.get_point_connections(4).size() == 0); a.disconnect_points(4, 1, true); - ok = ok && (a.get_point_connections(1).size() == 1); // 3 - ok = ok && (a.get_point_connections(4).size() == 0); + CHECK(a.get_point_connections(1).size() == 1); // 3 + CHECK(a.get_point_connections(4).size() == 0); a.connect_points(2, 3, false); - ok = ok && (a.get_point_connections(2).size() == 1); // 3 - ok = ok && (a.get_point_connections(3).size() == 1); // 1 + CHECK(a.get_point_connections(2).size() == 1); // 3 + CHECK(a.get_point_connections(3).size() == 1); // 1 a.connect_points(2, 3, true); - ok = ok && (a.get_point_connections(2).size() == 1); // 3 - ok = ok && (a.get_point_connections(3).size() == 2); // 1, 2 + CHECK(a.get_point_connections(2).size() == 1); // 3 + CHECK(a.get_point_connections(3).size() == 2); // 1, 2 a.disconnect_points(2, 3, false); - ok = ok && (a.get_point_connections(2).size() == 0); - ok = ok && (a.get_point_connections(3).size() == 2); // 1, 2 + CHECK(a.get_point_connections(2).size() == 0); + CHECK(a.get_point_connections(3).size() == 2); // 1, 2 a.connect_points(4, 3, true); - ok = ok && (a.get_point_connections(3).size() == 3); // 1, 2, 4 - ok = ok && (a.get_point_connections(4).size() == 1); // 3 + CHECK(a.get_point_connections(3).size() == 3); // 1, 2, 4 + CHECK(a.get_point_connections(4).size() == 1); // 3 a.disconnect_points(3, 4, false); - ok = ok && (a.get_point_connections(3).size() == 2); // 1, 2 - ok = ok && (a.get_point_connections(4).size() == 1); // 3 + CHECK(a.get_point_connections(3).size() == 2); // 1, 2 + CHECK(a.get_point_connections(4).size() == 1); // 3 a.remove_point(3); - ok = ok && (a.get_point_connections(1).size() == 0); - ok = ok && (a.get_point_connections(2).size() == 0); - ok = ok && (a.get_point_connections(4).size() == 0); + CHECK(a.get_point_connections(1).size() == 0); + CHECK(a.get_point_connections(2).size() == 0); + CHECK(a.get_point_connections(4).size() == 0); a.add_point(0, Vector3(0, -1, 0)); a.add_point(3, Vector3(2, 1, 0)); @@ -152,9 +152,9 @@ bool test_add_remove() { // 3: (2, 1) // 4: (2, 0) - // Tests for get_closest_position_in_segment + // Tests for get_closest_position_in_segment. a.connect_points(2, 3); - ok = ok && (a.get_closest_position_in_segment(Vector3(0.5, 0.5, 0)) == Vector3(0.5, 1, 0)); + CHECK(a.get_closest_position_in_segment(Vector3(0.5, 0.5, 0)) == Vector3(0.5, 1, 0)); a.connect_points(3, 4); a.connect_points(0, 3); @@ -162,10 +162,10 @@ bool test_add_remove() { a.disconnect_points(1, 4, false); a.disconnect_points(4, 3, false); a.disconnect_points(3, 4, false); - // Remaining edges: <2, 3>, <0, 3>, <1, 4> (directed) - ok = ok && (a.get_closest_position_in_segment(Vector3(2, 0.5, 0)) == Vector3(1.75, 0.75, 0)); - ok = ok && (a.get_closest_position_in_segment(Vector3(-1, 0.2, 0)) == Vector3(0, 0, 0)); - ok = ok && (a.get_closest_position_in_segment(Vector3(3, 2, 0)) == Vector3(2, 1, 0)); + // Remaining edges: <2, 3>, <0, 3>, <1, 4> (directed). + CHECK(a.get_closest_position_in_segment(Vector3(2, 0.5, 0)) == Vector3(1.75, 0.75, 0)); + CHECK(a.get_closest_position_in_segment(Vector3(-1, 0.2, 0)) == Vector3(0, 0, 0)); + CHECK(a.get_closest_position_in_segment(Vector3(3, 2, 0)) == Vector3(2, 1, 0)); Math::seed(0); @@ -177,24 +177,24 @@ bool test_add_remove() { v = 4; } if (Math::rand() % 2 == 1) { - // Add a (possibly existing) directed edge and confirm connectivity + // Add a (possibly existing) directed edge and confirm connectivity. a.connect_points(u, v, false); - ok = ok && (a.are_points_connected(u, v, false)); + CHECK(a.are_points_connected(u, v, false)); } else { - // Remove a (possibly nonexistent) directed edge and confirm disconnectivity + // Remove a (possibly nonexistent) directed edge and confirm disconnectivity. a.disconnect_points(u, v, false); - ok = ok && (a.are_points_connected(u, v, false) == false); + CHECK_FALSE(a.are_points_connected(u, v, false)); } } - // Random tests for point removal + // Random tests for point removal. for (int i = 0; i < 20000; i++) { a.clear(); for (int j = 0; j < 5; j++) { a.add_point(j, Vector3(0, 0, 0)); } - // Add or remove random edges + // Add or remove random edges. for (int j = 0; j < 10; j++) { int u = Math::rand() % 5; int v = Math::rand() % 4; @@ -208,21 +208,18 @@ bool test_add_remove() { } } - // Remove point 0 + // Remove point 0. a.remove_point(0); - // White box: this will check all edges remaining in the segments set + // White box: this will check all edges remaining in the segments set. for (int j = 1; j < 5; j++) { - ok = ok && (a.are_points_connected(0, j, true) == false); + CHECK_FALSE(a.are_points_connected(0, j, true)); } } - - // It's been great work, cheers \(^ ^)/ - return ok; + // It's been great work, cheers. \(^ ^)/ } -bool test_solutions() { - // Random stress tests with Floyd-Warshall - +TEST_CASE("[Stress][AStar] Find paths") { + // Random stress tests with Floyd-Warshall. const int N = 30; Math::seed(0); @@ -231,25 +228,23 @@ bool test_solutions() { Vector3 p[N]; bool adj[N][N] = { { false } }; - // Assign initial coordinates + // Assign initial coordinates. for (int u = 0; u < N; u++) { p[u].x = Math::rand() % 100; p[u].y = Math::rand() % 100; p[u].z = Math::rand() % 100; a.add_point(u, p[u]); } - - // Generate a random sequence of operations + // Generate a random sequence of operations. for (int i = 0; i < 1000; i++) { - // Pick two different vertices + // Pick two different vertices. int u, v; u = Math::rand() % N; v = Math::rand() % (N - 1); if (u == v) { v = N - 1; } - - // Pick a random operation + // Pick a random operation. int op = Math::rand(); switch (op % 9) { case 0: @@ -258,7 +253,7 @@ bool test_solutions() { case 3: case 4: case 5: - // Add edge (u, v); possibly bidirectional + // Add edge (u, v); possibly bidirectional. a.connect_points(u, v, op % 2); adj[u][v] = true; if (op % 2) { @@ -267,7 +262,7 @@ bool test_solutions() { break; case 6: case 7: - // Remove edge (u, v); possibly bidirectional + // Remove edge (u, v); possibly bidirectional. a.disconnect_points(u, v, op % 2); adj[u][v] = false; if (op % 2) { @@ -275,7 +270,7 @@ bool test_solutions() { } break; case 8: - // Remove point u and add it back; clears adjacent edges and changes coordinates + // Remove point u and add it back; clears adjacent edges and changes coordinates. a.remove_point(u); p[u].x = Math::rand() % 100; p[u].y = Math::rand() % 100; @@ -287,15 +282,13 @@ bool test_solutions() { break; } } - - // Floyd-Warshall + // Floyd-Warshall. float d[N][N]; for (int u = 0; u < N; u++) { for (int v = 0; v < N; v++) { d[u][v] = (u == v || adj[u][v]) ? p[u].distance_to(p[v]) : INFINITY; } } - for (int w = 0; w < N; w++) { for (int u = 0; u < N; u++) { for (int v = 0; v < N; v++) { @@ -305,8 +298,7 @@ bool test_solutions() { } } } - - // Display statistics + // Display statistics. int count = 0; for (int u = 0; u < N; u++) { for (int v = 0; v < N; v++) { @@ -315,7 +307,7 @@ bool test_solutions() { } } } - printf("Test #%4d: %3d edges, ", test + 1, count); + print_verbose(vformat("Test #%4d: %3d edges, ", test + 1, count)); count = 0; for (int u = 0; u < N; u++) { for (int v = 0; v < N; v++) { @@ -324,41 +316,41 @@ bool test_solutions() { } } } - printf("%3d/%d pairs of reachable points\n", count - N, N * (N - 1)); + print_verbose(vformat("%3d/%d pairs of reachable points\n", count - N, N * (N - 1))); - // Check A*'s output + // Check A*'s output. bool match = true; for (int u = 0; u < N; u++) { for (int v = 0; v < N; v++) { if (u != v) { Vector<int> route = a.get_id_path(u, v); if (!Math::is_inf(d[u][v])) { - // Reachable + // Reachable. if (route.size() == 0) { - printf("From %d to %d: A* did not find a path\n", u, v); + print_verbose(vformat("From %d to %d: A* did not find a path\n", u, v)); match = false; goto exit; } float astar_dist = 0; for (int i = 1; i < route.size(); i++) { if (!adj[route[i - 1]][route[i]]) { - printf("From %d to %d: edge (%d, %d) does not exist\n", - u, v, route[i - 1], route[i]); + print_verbose(vformat("From %d to %d: edge (%d, %d) does not exist\n", + u, v, route[i - 1], route[i])); match = false; goto exit; } astar_dist += p[route[i - 1]].distance_to(p[route[i]]); } if (!Math::is_equal_approx(astar_dist, d[u][v])) { - printf("From %d to %d: Floyd-Warshall gives %.6f, A* gives %.6f\n", - u, v, d[u][v], astar_dist); + print_verbose(vformat("From %d to %d: Floyd-Warshall gives %.6f, A* gives %.6f\n", + u, v, d[u][v], astar_dist)); match = false; goto exit; } } else { - // Unreachable + // Unreachable. if (route.size() > 0) { - printf("From %d to %d: A* somehow found a nonexistent path\n", u, v); + print_verbose(vformat("From %d to %d: A* somehow found a nonexistent path\n", u, v)); match = false; goto exit; } @@ -366,44 +358,11 @@ bool test_solutions() { } } } - exit: - if (!match) { - return false; - } + CHECK_MESSAGE(match, "Found all paths."); } - return true; -} - -typedef bool (*TestFunc)(); - -TestFunc test_funcs[] = { - test_abc, - test_abcx, - test_add_remove, - test_solutions, - nullptr -}; - -MainLoop *test() { - int count = 0; - int passed = 0; - - while (true) { - if (!test_funcs[count]) { - break; - } - bool pass = test_funcs[count](); - if (pass) { - passed++; - } - OS::get_singleton()->print("\t%s\n", pass ? "PASS" : "FAILED"); - - count++; - } - OS::get_singleton()->print("\n"); - OS::get_singleton()->print("Passed %i of %i tests\n", passed, count); - return nullptr; } } // namespace TestAStar + +#endif // TEST_ASTAR_H diff --git a/main/tests/test_basis.cpp b/tests/test_basis.cpp index 5904fc386a..5904fc386a 100644 --- a/main/tests/test_basis.cpp +++ b/tests/test_basis.cpp diff --git a/main/tests/test_basis.h b/tests/test_basis.h index 63297bd3b8..63297bd3b8 100644 --- a/main/tests/test_basis.h +++ b/tests/test_basis.h diff --git a/main/tests/test_class_db.cpp b/tests/test_class_db.cpp index 3171091402..3171091402 100644 --- a/main/tests/test_class_db.cpp +++ b/tests/test_class_db.cpp diff --git a/main/tests/test_class_db.h b/tests/test_class_db.h index 1a31cfb01b..1a31cfb01b 100644 --- a/main/tests/test_class_db.h +++ b/tests/test_class_db.h diff --git a/tests/test_color.h b/tests/test_color.h new file mode 100644 index 0000000000..3633f2746d --- /dev/null +++ b/tests/test_color.h @@ -0,0 +1,213 @@ +/*************************************************************************/ +/* test_color.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_COLOR_H +#define TEST_COLOR_H + +#include "core/color.h" + +#include "thirdparty/doctest/doctest.h" + +namespace TestColor { + +TEST_CASE("[Color] Constructor methods") { + const Color blue_rgba = Color(0.25098, 0.376471, 1, 0.501961); + // HTML currently uses ARGB notation, which is contrary to the CSS standard. + // This may be changed to RGBA in 4.0. + const Color blue_html = Color::html("#804060ff"); + const Color blue_hex = Color::hex(0x4060ff80); + const Color blue_hex64 = Color::hex64(0x4040'6060'ffff'8080); + + CHECK_MESSAGE( + blue_rgba.is_equal_approx(blue_html), + "Creation with HTML notation should result in components approximately equal to the default constructor."); + CHECK_MESSAGE( + blue_rgba.is_equal_approx(blue_hex), + "Creation with a 32-bit hexadecimal number should result in components approximately equal to the default constructor."); + CHECK_MESSAGE( + blue_rgba.is_equal_approx(blue_hex64), + "Creation with a 64-bit hexadecimal number should result in components approximately equal to the default constructor."); + + ERR_PRINT_OFF; + const Color html_invalid = Color::html("invalid"); + ERR_PRINT_ON; + + CHECK_MESSAGE( + html_invalid.is_equal_approx(Color()), + "Creation with invalid HTML notation should result in a Color with the default values."); + + const Color green_rgba = Color(0, 1, 0, 0.25); + const Color green_hsva = Color(0, 0, 0).from_hsv(120 / 360.0, 1, 1, 0.25); + + CHECK_MESSAGE( + green_rgba.is_equal_approx(green_hsva), + "Creation with HSV notation should result in components approximately equal to the default constructor."); +} + +TEST_CASE("[Color] Operators") { + const Color blue = Color(0.2, 0.2, 1); + const Color dark_red = Color(0.3, 0.1, 0.1); + + // Color components may be negative. Also, the alpha component may be greater than 1.0. + CHECK_MESSAGE( + (blue + dark_red).is_equal_approx(Color(0.5, 0.3, 1.1, 2)), + "Color addition should behave as expected."); + CHECK_MESSAGE( + (blue - dark_red).is_equal_approx(Color(-0.1, 0.1, 0.9, 0)), + "Color subtraction should behave as expected."); + CHECK_MESSAGE( + (blue * 2).is_equal_approx(Color(0.4, 0.4, 2, 2)), + "Color multiplication with a scalar should behave as expected."); + CHECK_MESSAGE( + (blue / 2).is_equal_approx(Color(0.1, 0.1, 0.5, 0.5)), + "Color division with a scalar should behave as expected."); + CHECK_MESSAGE( + (blue * dark_red).is_equal_approx(Color(0.06, 0.02, 0.1)), + "Color multiplication with another Color should behave as expected."); + CHECK_MESSAGE( + (blue / dark_red).is_equal_approx(Color(0.666667, 2, 10)), + "Color division with another Color should behave as expected."); + CHECK_MESSAGE( + (-blue).is_equal_approx(Color(0.8, 0.8, 0, 0)), + "Color negation should behave as expected (affecting the alpha channel, unlike `invert()`)."); +} + +TEST_CASE("[Color] Reading methods") { + const Color dark_blue = Color(0, 0, 0.5, 0.4); + + CHECK_MESSAGE( + Math::is_equal_approx(dark_blue.get_h(), 240 / 360.0), + "The returned HSV hue should match the expected value."); + CHECK_MESSAGE( + Math::is_equal_approx(dark_blue.get_s(), 1), + "The returned HSV saturation should match the expected value."); + CHECK_MESSAGE( + Math::is_equal_approx(dark_blue.get_v(), 0.5), + "The returned HSV value should match the expected value."); +} + +TEST_CASE("[Color] Conversion methods") { + const Color cyan = Color(0, 1, 1); + const Color cyan_transparent = Color(0, 1, 1, 0); + + CHECK_MESSAGE( + cyan.to_html() == "ff00ffff", + "The returned RGB HTML color code should match the expected value."); + CHECK_MESSAGE( + cyan_transparent.to_html() == "0000ffff", + "The returned RGBA HTML color code should match the expected value."); + CHECK_MESSAGE( + cyan.to_argb32() == 0xff00ffff, + "The returned 32-bit RGB number should match the expected value."); + CHECK_MESSAGE( + cyan.to_abgr32() == 0xffffff00, + "The returned 32-bit BGR number should match the expected value."); + CHECK_MESSAGE( + cyan.to_rgba32() == 0x00ffffff, + "The returned 32-bit BGR number should match the expected value."); + CHECK_MESSAGE( + cyan.to_argb64() == 0xffff'0000'ffff'ffff, + "The returned 64-bit RGB number should match the expected value."); + CHECK_MESSAGE( + cyan.to_abgr64() == 0xffff'ffff'ffff'0000, + "The returned 64-bit BGR number should match the expected value."); + CHECK_MESSAGE( + cyan.to_rgba64() == 0x0000'ffff'ffff'ffff, + "The returned 64-bit BGR number should match the expected value."); + CHECK_MESSAGE( + String(cyan) == "0, 1, 1, 1", + "The string representation should match the expected value."); +} + +TEST_CASE("[Color] Named colors") { + CHECK_MESSAGE( + Color::named("red").is_equal_approx(Color(1, 0, 0)), + "The named color \"red\" should match the expected value."); + + // Named colors have their names automatically normalized. + CHECK_MESSAGE( + Color::named("white_smoke").is_equal_approx(Color(0.96, 0.96, 0.96)), + "The named color \"white_smoke\" should match the expected value."); + CHECK_MESSAGE( + Color::named("Slate Blue").is_equal_approx(Color(0.42, 0.35, 0.80)), + "The named color \"Slate Blue\" should match the expected value."); + + ERR_PRINT_OFF; + CHECK_MESSAGE( + Color::named("doesn't exist").is_equal_approx(Color()), + "The invalid named color \"doesn't exist\" should result in a Color with the default values."); + ERR_PRINT_ON; +} + +TEST_CASE("[Color] Validation methods") { + CHECK_MESSAGE( + Color::html_is_valid("#4080ff"), + "Valid HTML color (with leading #) should be considered valid."); + CHECK_MESSAGE( + Color::html_is_valid("4080ff"), + "Valid HTML color (without leading #) should be considered valid."); + CHECK_MESSAGE( + !Color::html_is_valid("12345"), + "Invalid HTML color should be considered invalid."); + CHECK_MESSAGE( + !Color::html_is_valid("#fuf"), + "Invalid HTML color should be considered invalid."); +} + +TEST_CASE("[Color] Manipulation methods") { + const Color blue = Color(0, 0, 1, 0.4); + + CHECK_MESSAGE( + blue.inverted().is_equal_approx(Color(1, 1, 0, 0.4)), + "Inverted color should have its red, green and blue components inverted."); + CHECK_MESSAGE( + blue.contrasted().is_equal_approx(Color(0.5, 0.5, 0.5, 0.4)), + "Contrasted pure blue should be fully gray."); + + const Color purple = Color(0.5, 0.2, 0.5, 0.25); + + CHECK_MESSAGE( + purple.lightened(0.2).is_equal_approx(Color(0.6, 0.36, 0.6, 0.25)), + "Color should be lightened by the expected amount."); + CHECK_MESSAGE( + purple.darkened(0.2).is_equal_approx(Color(0.4, 0.16, 0.4, 0.25)), + "Color should be darkened by the expected amount."); + + const Color red = Color(1, 0, 0, 0.2); + const Color yellow = Color(1, 1, 0, 0.8); + + CHECK_MESSAGE( + red.lerp(yellow, 0.5).is_equal_approx(Color(1, 0.5, 0, 0.5)), + "Red interpolated with yellow should be orange (with interpolated alpha)."); +} + +} // namespace TestColor + +#endif // TEST_COLOR_H diff --git a/main/tests/test_gdscript.cpp b/tests/test_gdscript.cpp index a50311972f..a50311972f 100644 --- a/main/tests/test_gdscript.cpp +++ b/tests/test_gdscript.cpp diff --git a/main/tests/test_gdscript.h b/tests/test_gdscript.h index 6595da1430..6595da1430 100644 --- a/main/tests/test_gdscript.h +++ b/tests/test_gdscript.h diff --git a/main/tests/test_gui.cpp b/tests/test_gui.cpp index d46a13d2c0..d46a13d2c0 100644 --- a/main/tests/test_gui.cpp +++ b/tests/test_gui.cpp diff --git a/main/tests/test_gui.h b/tests/test_gui.h index 5a23179eee..5a23179eee 100644 --- a/main/tests/test_gui.h +++ b/tests/test_gui.h diff --git a/tests/test_macros.h b/tests/test_macros.h new file mode 100644 index 0000000000..e4494ce11a --- /dev/null +++ b/tests/test_macros.h @@ -0,0 +1,50 @@ +/*************************************************************************/ +/* test_macros.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_MACROS_H +#define TEST_MACROS_H + +// See documentation for doctest at: +// https://github.com/onqtam/doctest/blob/master/doc/markdown/readme.md#reference +#include "thirdparty/doctest/doctest.h" + +// The test is skipped with this, run pending tests with `--test --no-skip`. +#define TEST_CASE_PENDING(name) TEST_CASE(name *doctest::skip()) + +// Temporarily disable error prints to test failure paths. +// This allows to avoid polluting the test summary with error messages. +// The `_print_error_enabled` boolean is defined in `core/print_string.cpp` and +// works at global scope. It's used by various loggers in `should_log()` method, +// which are used by error macros which call into `OS::print_error`, effectively +// disabling any error messages to be printed from the engine side (not tests). +#define ERR_PRINT_OFF _print_error_enabled = false; +#define ERR_PRINT_ON _print_error_enabled = true; + +#endif // TEST_MACROS_H diff --git a/main/tests/test_main.cpp b/tests/test_main.cpp index 91eff28f86..137882841c 100644 --- a/main/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -32,11 +32,10 @@ #include "core/list.h" -#ifdef DEBUG_ENABLED - #include "test_astar.h" #include "test_basis.h" #include "test_class_db.h" +#include "test_color.h" #include "test_gdscript.h" #include "test_gui.h" #include "test_math.h" @@ -48,40 +47,18 @@ #include "test_shader_lang.h" #include "test_string.h" #include "test_validate_testing.h" +#include "test_variant.h" -#include "thirdparty/doctest/doctest.h" - -const char **tests_get_names() { - static const char *test_names[] = { - "*", - "all", - "math", - "basis", - "physics_2d", - "physics_3d", - "render", - "oa_hash_map", - "class_db", - "gui", - "shaderlang", - "gd_tokenizer", - "gd_parser", - "gd_compiler", - "gd_bytecode", - "ordered_hash_map", - "astar", - nullptr - }; +#include "modules/modules_tests.gen.h" - return test_names; -} +#include "tests/test_macros.h" int test_main(int argc, char *argv[]) { - // doctest runner for when legacy unit tests are no found + // Doctest runner. doctest::Context test_context; List<String> valid_arguments; - // clean arguments of --test from the args + // Clean arguments of "--test" from the args. int argument_count = 0; for (int x = 0; x < argc; x++) { if (strncmp(argv[x], "--test", 6) != 0) { @@ -89,15 +66,15 @@ int test_main(int argc, char *argv[]) { argument_count++; } } - - // convert godot command line arguments back to standard arguments. + // Convert Godot command line arguments back to standard arguments. char **args = new char *[valid_arguments.size()]; for (int x = 0; x < valid_arguments.size(); x++) { - // operation to convert godot string to non wchar string - const char *str = valid_arguments[x].utf8().ptr(); - // allocate the string copy + // Operation to convert Godot string to non wchar string. + CharString cs = valid_arguments[x].utf8(); + const char *str = cs.get_data(); + // Allocate the string copy. args[x] = new char[strlen(str) + 1]; - // copy this into memory + // Copy this into memory. std::memcpy(args[x], str, strlen(str) + 1); } @@ -106,22 +83,11 @@ int test_main(int argc, char *argv[]) { test_context.setOption("order-by", "name"); test_context.setOption("abort-after", 5); test_context.setOption("no-breaks", true); - delete[] args; - return test_context.run(); -} - -#else -const char **tests_get_names() { - static const char *test_names[] = { - nullptr - }; - - return test_names; -} + for (int x = 0; x < valid_arguments.size(); x++) { + delete[] args[x]; + } + delete[] args; -int test_main(int argc, char *argv[]) { - return 0; + return test_context.run(); } - -#endif diff --git a/main/tests/test_main.h b/tests/test_main.h index 8273b74eac..983bfde402 100644 --- a/main/tests/test_main.h +++ b/tests/test_main.h @@ -31,11 +31,6 @@ #ifndef TEST_MAIN_H #define TEST_MAIN_H -#include "core/list.h" -#include "core/os/main_loop.h" -#include "core/ustring.h" - -const char **tests_get_names(); int test_main(int argc, char *argv[]); #endif // TEST_MAIN_H diff --git a/main/tests/test_math.cpp b/tests/test_math.cpp index 5f84bad4e9..84a85be2f6 100644 --- a/main/tests/test_math.cpp +++ b/tests/test_math.cpp @@ -242,7 +242,7 @@ class GetClassAndNamespace { if (code[idx] == '-' || (code[idx] >= '0' && code[idx] <= '9')) { //a number const CharType *rptr; - double number = String::to_double(&code[idx], &rptr); + double number = String::to_float(&code[idx], &rptr); idx += (rptr - &code[idx]); value = number; return TK_NUMBER; diff --git a/main/tests/test_math.h b/tests/test_math.h index 77bce8dd66..77bce8dd66 100644 --- a/main/tests/test_math.h +++ b/tests/test_math.h diff --git a/main/tests/test_oa_hash_map.cpp b/tests/test_oa_hash_map.cpp index 9182f66b61..9182f66b61 100644 --- a/main/tests/test_oa_hash_map.cpp +++ b/tests/test_oa_hash_map.cpp diff --git a/main/tests/test_oa_hash_map.h b/tests/test_oa_hash_map.h index eb2b3d1e99..eb2b3d1e99 100644 --- a/main/tests/test_oa_hash_map.h +++ b/tests/test_oa_hash_map.h diff --git a/main/tests/test_ordered_hash_map.cpp b/tests/test_ordered_hash_map.cpp index d18a3784be..d18a3784be 100644 --- a/main/tests/test_ordered_hash_map.cpp +++ b/tests/test_ordered_hash_map.cpp diff --git a/main/tests/test_ordered_hash_map.h b/tests/test_ordered_hash_map.h index f251da0ba2..f251da0ba2 100644 --- a/main/tests/test_ordered_hash_map.h +++ b/tests/test_ordered_hash_map.h diff --git a/main/tests/test_physics_2d.cpp b/tests/test_physics_2d.cpp index c82ae920bc..c82ae920bc 100644 --- a/main/tests/test_physics_2d.cpp +++ b/tests/test_physics_2d.cpp diff --git a/main/tests/test_physics_2d.h b/tests/test_physics_2d.h index 517d324f3b..517d324f3b 100644 --- a/main/tests/test_physics_2d.h +++ b/tests/test_physics_2d.h diff --git a/main/tests/test_physics_3d.cpp b/tests/test_physics_3d.cpp index 72de2041e4..72de2041e4 100644 --- a/main/tests/test_physics_3d.cpp +++ b/tests/test_physics_3d.cpp diff --git a/main/tests/test_physics_3d.h b/tests/test_physics_3d.h index d03f2c6573..d03f2c6573 100644 --- a/main/tests/test_physics_3d.h +++ b/tests/test_physics_3d.h diff --git a/main/tests/test_render.cpp b/tests/test_render.cpp index d936dd72e7..d936dd72e7 100644 --- a/main/tests/test_render.cpp +++ b/tests/test_render.cpp diff --git a/main/tests/test_render.h b/tests/test_render.h index 4a6340c443..4a6340c443 100644 --- a/main/tests/test_render.h +++ b/tests/test_render.h diff --git a/main/tests/test_shader_lang.cpp b/tests/test_shader_lang.cpp index 34ee3e3210..34ee3e3210 100644 --- a/main/tests/test_shader_lang.cpp +++ b/tests/test_shader_lang.cpp diff --git a/main/tests/test_shader_lang.h b/tests/test_shader_lang.h index 2811c5f46e..2811c5f46e 100644 --- a/main/tests/test_shader_lang.h +++ b/tests/test_shader_lang.h diff --git a/main/tests/test_string.h b/tests/test_string.h index 25fd513a1a..22019a64c6 100644 --- a/main/tests/test_string.h +++ b/tests/test_string.h @@ -44,7 +44,7 @@ #include "modules/regex/regex.h" #endif -#include "thirdparty/doctest/doctest.h" +#include "tests/test_macros.h" namespace TestString { @@ -209,7 +209,7 @@ TEST_CASE("[String] String to float") { static const double num[4] = { -12348298412.2, 0.05, 2.0002, -0.0001 }; for (int i = 0; i < 4; i++) { - CHECK(!(ABS(String(nums[i]).to_double() - num[i]) > 0.00001)); + CHECK(!(ABS(String(nums[i]).to_float() - num[i]) > 0.00001)); } } diff --git a/main/tests/test_validate_testing.h b/tests/test_validate_testing.h index 5be7d45185..24acdec96c 100644 --- a/main/tests/test_validate_testing.h +++ b/tests/test_validate_testing.h @@ -33,10 +33,26 @@ #include "core/os/os.h" -#include "thirdparty/doctest/doctest.h" +#include "tests/test_macros.h" -TEST_CASE("Validate Test will always pass") { - CHECK(true); +TEST_SUITE("Validate tests") { + TEST_CASE("Always pass") { + CHECK(true); + } + TEST_CASE_PENDING("Pending tests are skipped") { + if (!doctest::getContextOptions()->no_skip) { // Normal run. + FAIL("This should be skipped if `--no-skip` is NOT set (missing `doctest::skip()` decorator?)"); + } else { + CHECK_MESSAGE(true, "Pending test is run with `--no-skip`"); + } + } + TEST_CASE("Muting Godot error messages") { + ERR_PRINT_OFF; + CHECK_MESSAGE(!_print_error_enabled, "Error printing should be disabled."); + ERR_PRINT("Still waiting for Godot!"); // This should never get printed! + ERR_PRINT_ON; + CHECK_MESSAGE(_print_error_enabled, "Error printing should be re-enabled."); + } } #endif // TEST_VALIDATE_TESTING_H diff --git a/tests/test_variant.h b/tests/test_variant.h new file mode 100644 index 0000000000..a384a3e91f --- /dev/null +++ b/tests/test_variant.h @@ -0,0 +1,111 @@ +/*************************************************************************/ +/* test_variant.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_VARIANT_H +#define TEST_VARIANT_H + +#include "core/variant.h" +#include "core/variant_parser.h" + +#include "tests/test_macros.h" + +namespace TestVariant { + +TEST_CASE("[Variant] Writer and parser integer") { + int64_t a32 = 2147483648; // 2^31, so out of bounds for 32-bit signed int [-2^31,-2^31-1]. + String a32_str; + VariantWriter::write_to_string(a32, a32_str); + + CHECK_MESSAGE(a32_str != "-2147483648", "Should not wrap around"); + + int64_t b64 = 9223372036854775807; // 2^63-1, upper bound for signed 64-bit int. + String b64_str; + VariantWriter::write_to_string(b64, b64_str); + + CHECK_MESSAGE(b64_str == "9223372036854775807", "Should not wrap around."); + + VariantParser::StreamString ss; + String errs; + int line; + Variant b64_parsed; + int64_t b64_int_parsed; + + ss.s = b64_str; + VariantParser::parse(&ss, b64_parsed, errs, line); + b64_int_parsed = b64_parsed; + + CHECK_MESSAGE(b64_int_parsed == 9223372036854775807, "Should parse back."); + + ss.s = "9223372036854775808"; // Overflowed by one. + VariantParser::parse(&ss, b64_parsed, errs, line); + b64_int_parsed = b64_parsed; + + CHECK_MESSAGE(b64_int_parsed == 9223372036854775807, "The result should be clamped to max value."); + + ss.s = "1e100"; // Googol! Scientific notation. + VariantParser::parse(&ss, b64_parsed, errs, line); + b64_int_parsed = b64_parsed; + + CHECK_MESSAGE(b64_int_parsed == 9223372036854775807, "The result should be clamped to max value."); +} + +TEST_CASE("[Variant] Writer and parser float") { + // Assuming real_t is double. + real_t a64 = 340282346638528859811704183484516925440.0; // std::numeric_limits<real_t>::max() + String a64_str; + VariantWriter::write_to_string(a64, a64_str); + + CHECK_MESSAGE(a64_str == "3.40282e+38", "Writes in scientific notation."); + CHECK_MESSAGE(a64_str != "inf", "Should not overflow."); + CHECK_MESSAGE(a64_str != "nan", "The result should be defined."); + + VariantParser::StreamString ss; + String errs; + int line; + Variant b64_parsed; + real_t b64_float_parsed; + + ss.s = a64_str; + VariantParser::parse(&ss, b64_parsed, errs, line); + b64_float_parsed = b64_parsed; + + CHECK_MESSAGE(b64_float_parsed == 340282001837565597733306976381245063168.0, "Should parse back."); + // Loses precision, but that's alright. + + ss.s = "1.0e+100"; // Float version of Googol! + VariantParser::parse(&ss, b64_parsed, errs, line); + b64_float_parsed = b64_parsed; + + CHECK_MESSAGE(b64_float_parsed == 340282001837565597733306976381245063168.0, "Should not overflow."); +} + +} // namespace TestVariant + +#endif // TEST_VARIANT_H diff --git a/thirdparty/README.md b/thirdparty/README.md index f5b44d7a39..c1b230cfb7 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -81,6 +81,9 @@ Files extracted from upstream source: Extracted from .zip provided. Extracted license and header only. +Important: Some files have Godot-made changes. +They are marked with `// -- GODOT start --` and `// -- GODOT end --` +comments. ## enet diff --git a/thirdparty/doctest/doctest.h b/thirdparty/doctest/doctest.h index 9444698286..e4fed12767 100644 --- a/thirdparty/doctest/doctest.h +++ b/thirdparty/doctest/doctest.h @@ -356,7 +356,13 @@ DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum' #ifndef DOCTEST_BREAK_INTO_DEBUGGER // should probably take a look at https://github.com/scottt/debugbreak #ifdef DOCTEST_PLATFORM_MAC +// -- GODOT start -- +#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) #define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) +#else +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("brk #0"); +#endif +// -- GODOT end -- #elif DOCTEST_MSVC #define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() #elif defined(__MINGW32__) diff --git a/thirdparty/doctest/patches/fix-arm64-mac.patch b/thirdparty/doctest/patches/fix-arm64-mac.patch new file mode 100644 index 0000000000..f78014534f --- /dev/null +++ b/thirdparty/doctest/patches/fix-arm64-mac.patch @@ -0,0 +1,18 @@ +diff --git a/thirdparty/doctest/doctest.h b/thirdparty/doctest/doctest.h +index 9444698286..e4fed12767 100644 +--- a/thirdparty/doctest/doctest.h ++++ b/thirdparty/doctest/doctest.h +@@ -356,7 +356,13 @@ DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum' + #ifndef DOCTEST_BREAK_INTO_DEBUGGER + // should probably take a look at https://github.com/scottt/debugbreak + #ifdef DOCTEST_PLATFORM_MAC ++// -- GODOT start -- ++#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) + #define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) ++#else ++#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("brk #0"); ++#endif ++// -- GODOT end -- + #elif DOCTEST_MSVC + #define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() + #elif defined(__MINGW32__) diff --git a/thirdparty/vulkan/patches/VMA-assert-remove.patch b/thirdparty/vulkan/patches/VMA-assert-remove.patch new file mode 100644 index 0000000000..3d57ab7d42 --- /dev/null +++ b/thirdparty/vulkan/patches/VMA-assert-remove.patch @@ -0,0 +1,29 @@ +diff --git a/thirdparty/vulkan/vk_mem_alloc.h b/thirdparty/vulkan/vk_mem_alloc.h +index 0dfb66efc6..8a42699e7f 100644 +--- a/thirdparty/vulkan/vk_mem_alloc.h ++++ b/thirdparty/vulkan/vk_mem_alloc.h +@@ -17508,24 +17508,6 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( + allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq, + requiresDedicatedAllocation, prefersDedicatedAllocation); + +- // Make sure alignment requirements for specific buffer usages reported +- // in Physical Device Properties are included in alignment reported by memory requirements. +- if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) != 0) +- { +- VMA_ASSERT(vkMemReq.alignment % +- allocator->m_PhysicalDeviceProperties.limits.minTexelBufferOffsetAlignment == 0); +- } +- if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) != 0) +- { +- VMA_ASSERT(vkMemReq.alignment % +- allocator->m_PhysicalDeviceProperties.limits.minUniformBufferOffsetAlignment == 0); +- } +- if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) != 0) +- { +- VMA_ASSERT(vkMemReq.alignment % +- allocator->m_PhysicalDeviceProperties.limits.minStorageBufferOffsetAlignment == 0); +- } +- + // 3. Allocate memory using allocator. + res = allocator->AllocateMemory( + vkMemReq, diff --git a/thirdparty/vulkan/vk_mem_alloc.h b/thirdparty/vulkan/vk_mem_alloc.h index 0dfb66efc6..8a42699e7f 100644 --- a/thirdparty/vulkan/vk_mem_alloc.h +++ b/thirdparty/vulkan/vk_mem_alloc.h @@ -17508,24 +17508,6 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq, requiresDedicatedAllocation, prefersDedicatedAllocation); - // Make sure alignment requirements for specific buffer usages reported - // in Physical Device Properties are included in alignment reported by memory requirements. - if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) != 0) - { - VMA_ASSERT(vkMemReq.alignment % - allocator->m_PhysicalDeviceProperties.limits.minTexelBufferOffsetAlignment == 0); - } - if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) != 0) - { - VMA_ASSERT(vkMemReq.alignment % - allocator->m_PhysicalDeviceProperties.limits.minUniformBufferOffsetAlignment == 0); - } - if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) != 0) - { - VMA_ASSERT(vkMemReq.alignment % - allocator->m_PhysicalDeviceProperties.limits.minStorageBufferOffsetAlignment == 0); - } - // 3. Allocate memory using allocator. res = allocator->AllocateMemory( vkMemReq, |