diff options
253 files changed, 2858 insertions, 1019 deletions
diff --git a/.clang-format b/.clang-format index 1df6c35bfb..eda00dd8dd 100644 --- a/.clang-format +++ b/.clang-format @@ -1,29 +1,59 @@ # Commented out parameters are those with the same value as base LLVM style. # We can uncomment them if we want to change their value, or enforce the -# chosen value in case the base style changes (last sync: Clang 14.0). ---- -### General config, applies to all languages ### -BasedOnStyle: LLVM +# chosen value in case the base style changes (last sync: Clang 18.1.8). +BasedOnStyle: LLVM AccessModifierOffset: -4 AlignAfterOpenBracket: DontAlign # AlignArrayOfStructures: None -# AlignConsecutiveMacros: None -# AlignConsecutiveAssignments: None -# AlignConsecutiveBitFields: None -# AlignConsecutiveDeclarations: None +# AlignConsecutiveAssignments: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionPointers: false +# PadOperators: true +# AlignConsecutiveBitFields: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionPointers: false +# PadOperators: false +# AlignConsecutiveDeclarations: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionPointers: false +# PadOperators: false +# AlignConsecutiveMacros: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionPointers: false +# PadOperators: false +# AlignConsecutiveShortCaseStatements: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCaseColons: false # AlignEscapedNewlines: Right -AlignOperands: DontAlign -AlignTrailingComments: false +AlignOperands: DontAlign +AlignTrailingComments: + Kind: Never + OverEmptyLines: 0 # AllowAllArgumentsOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: false -# AllowShortEnumsOnASingleLine: true +# AllowBreakBeforeNoexceptSpecifier: Never # AllowShortBlocksOnASingleLine: Never # AllowShortCaseLabelsOnASingleLine: false +# AllowShortCompoundRequirementOnASingleLine: true +# AllowShortEnumsOnASingleLine: true # AllowShortFunctionsOnASingleLine: All -# AllowShortLambdasOnASingleLine: All # AllowShortIfStatementsOnASingleLine: Never +# AllowShortLambdasOnASingleLine: All # AllowShortLoopsOnASingleLine: false -# AlwaysBreakAfterDefinitionReturnType: None # AlwaysBreakAfterReturnType: None # AlwaysBreakBeforeMultilineStrings: false # AlwaysBreakTemplateDeclarations: MultiLine @@ -31,50 +61,49 @@ AllowAllParametersOfDeclarationOnNextLine: false # - __capability # BinPackArguments: true # BinPackParameters: true +# BitFieldColonSpacing: Both # BraceWrapping: -# AfterCaseLabel: false -# AfterClass: false +# AfterCaseLabel: false +# AfterClass: false # AfterControlStatement: Never -# AfterEnum: false -# AfterFunction: false -# AfterNamespace: false +# AfterEnum: false +# AfterFunction: false +# AfterNamespace: false # AfterObjCDeclaration: false -# AfterStruct: false -# AfterUnion: false +# AfterStruct: false +# AfterUnion: false # AfterExternBlock: false -# BeforeCatch: false -# BeforeElse: false +# BeforeCatch: false +# BeforeElse: false # BeforeLambdaBody: false -# BeforeWhile: false -# IndentBraces: false +# BeforeWhile: false +# IndentBraces: false # SplitEmptyFunction: true # SplitEmptyRecord: true # SplitEmptyNamespace: true +# BreakAdjacentStringLiterals: true +# BreakAfterAttributes: Leave +# BreakAfterJavaFieldAnnotations: false +# BreakArrays: true # BreakBeforeBinaryOperators: None -# BreakBeforeConceptDeclarations: true # BreakBeforeBraces: Attach -# BreakBeforeInheritanceComma: false -# BreakInheritanceList: BeforeColon +# BreakBeforeConceptDeclarations: Always +# BreakBeforeInlineASMColon: OnlyMultiline # BreakBeforeTernaryOperators: true -# BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: AfterColon +# BreakInheritanceList: BeforeColon # BreakStringLiterals: true -ColumnLimit: 0 -# CommentPragmas: '^ IWYU pragma:' -# QualifierAlignment: Leave +ColumnLimit: 0 +# CommentPragmas: '^ IWYU pragma:' # CompactNamespaces: false ConstructorInitializerIndentWidth: 8 ContinuationIndentWidth: 8 Cpp11BracedListStyle: false -# DeriveLineEnding: true # DerivePointerAlignment: false -# DisableFormat: false +# DisableFormat: false # EmptyLineAfterAccessModifier: Never # EmptyLineBeforeAccessModifier: LogicalBlock # ExperimentalAutoDetectBinPacking: false -# PackConstructorInitializers: BinPack -ConstructorInitializerAllOnOneLineOrOnePerLine: true -# AllowAllConstructorInitializersOnNextLine: true # FixNamespaceComments: true # ForEachMacros: # - foreach @@ -82,118 +111,138 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true # - BOOST_FOREACH # IfMacros: # - KJ_IF_MAYBE -# IncludeBlocks: Preserve +# IncludeBlocks: Preserve IncludeCategories: - - Regex: '".*"' - Priority: 1 - - Regex: '^<.*\.h>' - Priority: 2 - - Regex: '^<.*' - Priority: 3 -# IncludeIsMainRegex: '(Test)?$' + - Regex: ^".*"$ + Priority: 1 + - Regex: ^<.*\.h>$ + Priority: 2 + - Regex: ^<.*>$ + Priority: 3 +# IncludeIsMainRegex: (Test)?$ # IncludeIsMainSourceRegex: '' # IndentAccessModifiers: false -IndentCaseLabels: true # IndentCaseBlocks: false +IndentCaseLabels: true +# IndentExternBlock: AfterExternBlock # IndentGotoLabels: true # IndentPPDirectives: None -# IndentExternBlock: AfterExternBlock -# IndentRequires: false -IndentWidth: 4 +# IndentRequiresClause: true +IndentWidth: 4 # IndentWrappedFunctionNames: false +# InsertBraces: false +# InsertNewlineAtEOF: false # InsertTrailingCommas: None +# IntegerLiteralSeparator: +# Binary: 0 +# BinaryMinDigits: 0 +# Decimal: 0 +# DecimalMinDigits: 0 +# Hex: 0 +# HexMinDigits: 0 +JavaImportGroups: + - org.godotengine + - android + - androidx + - com.android + - com.google + - java + - javax # JavaScriptQuotes: Leave # JavaScriptWrapImports: true +# KeepEmptyLinesAtEOF: false KeepEmptyLinesAtTheStartOfBlocks: false # LambdaBodyIndentation: Signature +# Language: Cpp +# LineEnding: DeriveLF # MacroBlockBegin: '' -# MacroBlockEnd: '' +# MacroBlockEnd: '' # MaxEmptyLinesToKeep: 1 # NamespaceIndentation: None +# ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 4 +# ObjCBreakBeforeNestedBlockParam: true +# ObjCSpaceAfterProperty: false +# ObjCSpaceBeforeProtocolList: true +# PPIndentWidth: -1 +PackConstructorInitializers: NextLine # PenaltyBreakAssignment: 2 # PenaltyBreakBeforeFirstCallParameter: 19 # PenaltyBreakComment: 300 # PenaltyBreakFirstLessLess: 120 # PenaltyBreakOpenParenthesis: 0 +# PenaltyBreakScopeResolution: 500 # PenaltyBreakString: 1000 # PenaltyBreakTemplateDeclaration: 10 # PenaltyExcessCharacter: 1000000 -# PenaltyReturnTypeOnItsOwnLine: 60 # PenaltyIndentedWhitespace: 0 +# PenaltyReturnTypeOnItsOwnLine: 60 # PointerAlignment: Right -# PPIndentWidth: -1 +# QualifierAlignment: Leave # ReferenceAlignment: Pointer -# ReflowComments: true +# ReflowComments: true # RemoveBracesLLVM: false +# RemoveParentheses: Leave +# RemoveSemicolon: false +# RequiresClausePosition: OwnLine +# RequiresExpressionIndentation: OuterScope # SeparateDefinitionBlocks: Leave # ShortNamespaceLines: 1 -# SortIncludes: CaseSensitive +# SkipMacroDefinitionBody: false +# SortIncludes: CaseSensitive # SortJavaStaticImport: Before -# SortUsingDeclarations: true +# SortUsingDeclarations: LexicographicNumeric # SpaceAfterCStyleCast: false # SpaceAfterLogicalNot: false # SpaceAfterTemplateKeyword: true +# SpaceAroundPointerQualifiers: Default # SpaceBeforeAssignmentOperators: true # SpaceBeforeCaseColon: false # SpaceBeforeCpp11BracedList: false # SpaceBeforeCtorInitializerColon: true # SpaceBeforeInheritanceColon: true -# SpaceBeforeParens: ControlStatements +# SpaceBeforeJsonColon: false # SpaceBeforeParensOptions: # AfterControlStatements: true # AfterForeachMacros: true -# AfterFunctionDefinitionName: false # AfterFunctionDeclarationName: false -# AfterIfMacros: true +# AfterFunctionDefinitionName: false +# AfterIfMacros: true # AfterOverloadedOperator: false +# AfterPlacementOperator: true +# AfterRequiresInClause: false +# AfterRequiresInExpression: false # BeforeNonEmptyParentheses: false -# SpaceAroundPointerQualifiers: Default # SpaceBeforeRangeBasedForLoopColon: true +# SpaceBeforeSquareBrackets: false # SpaceInEmptyBlock: false -# SpaceInEmptyParentheses: false # SpacesBeforeTrailingComments: 1 -# SpacesInAngles: Never -# SpacesInConditionalStatement: false +# SpacesInAngles: Never # SpacesInContainerLiterals: true -# SpacesInCStyleCastParentheses: false ## Godot TODO: We'll want to use a min of 1, but we need to see how to fix ## our comment capitalization at the same time. SpacesInLineCommentPrefix: - Minimum: 0 - Maximum: -1 -# SpacesInParentheses: false + Minimum: 0 + Maximum: -1 +# SpacesInParens: Never +# SpacesInParensOptions: +# InConditionalStatements: false +# InCStyleCasts: false +# InEmptyParentheses: false +# Other: false # SpacesInSquareBrackets: false -# SpaceBeforeSquareBrackets: false -# BitFieldColonSpacing: Both +Standard: c++17 # StatementAttributeLikeMacros: # - Q_EMIT # StatementMacros: # - Q_UNUSED # - QT_REQUIRE_VERSION -TabWidth: 4 -# UseCRLF: false -UseTab: Always +TabWidth: 4 +UseTab: Always +# VerilogBreakBetweenInstancePorts: true # WhitespaceSensitiveMacros: -# - STRINGIZE -# - PP_STRINGIZE # - BOOST_PP_STRINGIZE -# - NS_SWIFT_NAME # - CF_SWIFT_NAME ---- -### C++ specific config ### -Language: Cpp -Standard: c++17 ---- -### ObjC specific config ### -Language: ObjC -# ObjCBinPackProtocolList: Auto -ObjCBlockIndentWidth: 4 -# ObjCBreakBeforeNestedBlockParam: true -# ObjCSpaceAfterProperty: false -# ObjCSpaceBeforeProtocolList: true ---- -### Java specific config ### -Language: Java -# BreakAfterJavaFieldAnnotations: false -JavaImportGroups: ['org.godotengine', 'android', 'androidx', 'com.android', 'com.google', 'java', 'javax'] -... +# - NS_SWIFT_NAME +# - PP_STRINGIZE +# - STRINGIZE diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index ebfd3b515a..1c78dde7a4 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -54,3 +54,6 @@ df61dc4b2bd54a5a40c515493c76f5a458e5b541 # Enforce template syntax `typename` over `class` 9903e6779b70fc03aae70a37b9cf053f4f355b91 + +# Style: Apply new `clang-format` fixes +b37fc1014abf7adda70dc30b0822d775b3a4433f diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a3bf09bb56..8cfb00fd8e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ exclude: | repos: - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v17.0.6 + rev: v18.1.8 hooks: - id: clang-format files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java|glsl)$ @@ -39,14 +39,14 @@ repos: stages: [manual] # Not automatically triggered, invoked via `pre-commit run --hook-stage manual clang-tidy` - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.4 + rev: v0.6.6 hooks: - id: ruff args: [--fix] - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.971 + rev: v1.11.2 hooks: - id: mypy files: \.py$ diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index 5b6dcbb567..c0bb756d2e 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -63,6 +63,39 @@ Copyright: 2011, Ole Kniemeyer, MAXON, www.maxon.net 2007-2014, Juan Linietsky, Ariel Manzur License: Expat and Zlib +Files: ./modules/godot_physics_3d/gjk_epa.cpp + ./modules/godot_physics_3d/joints/godot_generic_6dof_joint_3d.cpp + ./modules/godot_physics_3d/joints/godot_generic_6dof_joint_3d.h + ./modules/godot_physics_3d/joints/godot_hinge_joint_3d.cpp + ./modules/godot_physics_3d/joints/godot_hinge_joint_3d_sw.h + ./modules/godot_physics_3d/joints/godot_jacobian_entry_3d_sw.h + ./modules/godot_physics_3d/joints/godot_pin_joint_3d.cpp + ./modules/godot_physics_3d/joints/godot_pin_joint_3d.h + ./modules/godot_physics_3d/joints/godot_slider_joint_3d.cpp + ./modules/godot_physics_3d/joints/godot_slider_joint_3d.h + ./modules/godot_physics_3d/godot_soft_body_3d.cpp + ./modules/godot_physics_3d/godot_soft_body_3d.h + ./modules/godot_physics_3d/godot_shape_3d.cpp + ./modules/godot_physics_3d/godot_shape_3d.h +Comment: Bullet Continuous Collision Detection and Physics Library +Copyright: 2003-2008, Erwin Coumans + 2014-present, Godot Engine contributors + 2007-2014, Juan Linietsky, Ariel Manzur +License: Expat and Zlib + +Files: ./modules/godot_physics_3d/godot_collision_solver_3d_sat.cpp +Comment: Open Dynamics Engine +Copyright: 2001-2003, Russell L. Smith, Alen Ladavac, Nguyen Binh +License: BSD-3-clause + +Files: ./modules/godot_physics_3d/joints/godot_cone_twist_joint_3d.cpp + ./modules/godot_physics_3d/joints/godot_cone_twist_joint_3d.h +Comment: Bullet Continuous Collision Detection and Physics Library +Copyright: 2007, Starbreeze Studios + 2014-present, Godot Engine contributors + 2007-2014, Juan Linietsky, Ariel Manzur +License: Expat and Zlib + Files: ./modules/lightmapper_rd/lm_compute.glsl Comment: Joint Non-Local Means (JNLM) denoiser Copyright: 2020, Manuel Prandini @@ -98,39 +131,6 @@ Comment: Chipmunk2D Joint Constraints Copyright: 2007, Scott Lembcke License: Expat -Files: ./servers/physics_3d/collision_solver_3d_sat.cpp -Comment: Open Dynamics Engine -Copyright: 2001-2003, Russell L. Smith, Alen Ladavac, Nguyen Binh -License: BSD-3-clause - -Files: ./servers/physics_3d/gjk_epa.cpp - ./servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp - ./servers/physics_3d/joints/generic_6dof_joint_3d_sw.h - ./servers/physics_3d/joints/hinge_joint_3d_sw.cpp - ./servers/physics_3d/joints/hinge_joint_3d_sw.h - ./servers/physics_3d/joints/jacobian_entry_3d_sw.h - ./servers/physics_3d/joints/pin_joint_3d_sw.cpp - ./servers/physics_3d/joints/pin_joint_3d_sw.h - ./servers/physics_3d/joints/slider_joint_3d_sw.cpp - ./servers/physics_3d/joints/slider_joint_3d_sw.h - ./servers/physics_3d/soft_body_3d_sw.cpp - ./servers/physics_3d/soft_body_3d_sw.h - ./servers/physics_3d/shape_3d_sw.cpp - ./servers/physics_3d/shape_3d_sw.h -Comment: Bullet Continuous Collision Detection and Physics Library -Copyright: 2003-2008, Erwin Coumans - 2014-present, Godot Engine contributors - 2007-2014, Juan Linietsky, Ariel Manzur -License: Expat and Zlib - -Files: ./servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp - ./servers/physics_3d/joints/cone_twist_joint_3d_sw.h -Comment: Bullet Continuous Collision Detection and Physics Library -Copyright: 2007, Starbreeze Studios - 2014-present, Godot Engine contributors - 2007-2014, Juan Linietsky, Ariel Manzur -License: Expat and Zlib - Files: ./servers/rendering/renderer_rd/shaders/ss_effects_downsample.glsl ./servers/rendering/renderer_rd/shaders/ssao_blur.glsl ./servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl diff --git a/core/config/engine.cpp b/core/config/engine.cpp index 9cdc21fe8e..d77c913314 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -267,6 +267,14 @@ bool Engine::is_extra_gpu_memory_tracking_enabled() const { return extra_gpu_memory_tracking; } +void Engine::set_print_to_stdout(bool p_enabled) { + CoreGlobals::print_line_enabled = p_enabled; +} + +bool Engine::is_printing_to_stdout() const { + return CoreGlobals::print_line_enabled; +} + void Engine::set_print_error_messages(bool p_enabled) { CoreGlobals::print_error_enabled = p_enabled; } diff --git a/core/config/engine.h b/core/config/engine.h index f858eba328..a0b1ffa981 100644 --- a/core/config/engine.h +++ b/core/config/engine.h @@ -128,6 +128,9 @@ public: void set_time_scale(double p_scale); double get_time_scale() const; + void set_print_to_stdout(bool p_enabled); + bool is_printing_to_stdout() const; + void set_print_error_messages(bool p_enabled); bool is_printing_error_messages() const; void print_header(const String &p_string) const; diff --git a/core/core_bind.cpp b/core/core_bind.cpp index bbfbb6e3cd..891e3a28c9 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -184,6 +184,10 @@ void ResourceSaver::remove_resource_format_saver(Ref<ResourceFormatSaver> p_form ::ResourceSaver::remove_resource_format_saver(p_format_saver); } +ResourceUID::ID ResourceSaver::get_resource_id_for_path(const String &p_path, bool p_generate) { + return ::ResourceSaver::get_resource_id_for_path(p_path, p_generate); +} + ResourceSaver *ResourceSaver::singleton = nullptr; void ResourceSaver::_bind_methods() { @@ -191,6 +195,7 @@ void ResourceSaver::_bind_methods() { ClassDB::bind_method(D_METHOD("get_recognized_extensions", "type"), &ResourceSaver::get_recognized_extensions); ClassDB::bind_method(D_METHOD("add_resource_format_saver", "format_saver", "at_front"), &ResourceSaver::add_resource_format_saver, DEFVAL(false)); ClassDB::bind_method(D_METHOD("remove_resource_format_saver", "format_saver"), &ResourceSaver::remove_resource_format_saver); + ClassDB::bind_method(D_METHOD("get_resource_id_for_path", "path", "generate"), &ResourceSaver::get_resource_id_for_path, DEFVAL(false)); BIND_BITFIELD_FLAG(FLAG_NONE); BIND_BITFIELD_FLAG(FLAG_RELATIVE_PATHS); @@ -1848,6 +1853,14 @@ String Engine::get_write_movie_path() const { return ::Engine::get_singleton()->get_write_movie_path(); } +void Engine::set_print_to_stdout(bool p_enabled) { + ::Engine::get_singleton()->set_print_to_stdout(p_enabled); +} + +bool Engine::is_printing_to_stdout() const { + return ::Engine::get_singleton()->is_printing_to_stdout(); +} + void Engine::set_print_error_messages(bool p_enabled) { ::Engine::get_singleton()->set_print_error_messages(p_enabled); } @@ -1916,10 +1929,14 @@ void Engine::_bind_methods() { ClassDB::bind_method(D_METHOD("get_write_movie_path"), &Engine::get_write_movie_path); + ClassDB::bind_method(D_METHOD("set_print_to_stdout", "enabled"), &Engine::set_print_to_stdout); + ClassDB::bind_method(D_METHOD("is_printing_to_stdout"), &Engine::is_printing_to_stdout); + ClassDB::bind_method(D_METHOD("set_print_error_messages", "enabled"), &Engine::set_print_error_messages); ClassDB::bind_method(D_METHOD("is_printing_error_messages"), &Engine::is_printing_error_messages); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "print_error_messages"), "set_print_error_messages", "is_printing_error_messages"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "print_to_stdout"), "set_print_to_stdout", "is_printing_to_stdout"); ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_ticks_per_second"), "set_physics_ticks_per_second", "get_physics_ticks_per_second"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_physics_steps_per_frame"), "set_max_physics_steps_per_frame", "get_max_physics_steps_per_frame"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_fps"), "set_max_fps", "get_max_fps"); diff --git a/core/core_bind.h b/core/core_bind.h index 2a31e64425..ce0bde3c05 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -116,6 +116,8 @@ public: void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front); void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver); + ResourceUID::ID get_resource_id_for_path(const String &p_path, bool p_generate = false); + ResourceSaver() { singleton = this; } }; @@ -567,6 +569,9 @@ public: // `set_write_movie_path()` is not exposed to the scripting API as changing it at run-time has no effect. String get_write_movie_path() const; + void set_print_to_stdout(bool p_enabled); + bool is_printing_to_stdout() const; + void set_print_error_messages(bool p_enabled); bool is_printing_error_messages() const; diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index a7c715c318..93179d9a11 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -47,12 +47,12 @@ static int _get_pad(int p_alignment, int p_n) { } void PCKPacker::_bind_methods() { - ClassDB::bind_method(D_METHOD("pck_start", "pck_name", "alignment", "key", "encrypt_directory"), &PCKPacker::pck_start, DEFVAL(32), DEFVAL("0000000000000000000000000000000000000000000000000000000000000000"), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("pck_start", "pck_path", "alignment", "key", "encrypt_directory"), &PCKPacker::pck_start, DEFVAL(32), DEFVAL("0000000000000000000000000000000000000000000000000000000000000000"), DEFVAL(false)); ClassDB::bind_method(D_METHOD("add_file", "pck_path", "source_path", "encrypt"), &PCKPacker::add_file, DEFVAL(false)); ClassDB::bind_method(D_METHOD("flush", "verbose"), &PCKPacker::flush, DEFVAL(false)); } -Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String &p_key, bool p_encrypt_directory) { +Error PCKPacker::pck_start(const String &p_pck_path, int p_alignment, const String &p_key, bool p_encrypt_directory) { ERR_FAIL_COND_V_MSG((p_key.is_empty() || !p_key.is_valid_hex_number(false) || p_key.length() != 64), ERR_CANT_CREATE, "Invalid Encryption Key (must be 64 characters long)."); ERR_FAIL_COND_V_MSG(p_alignment <= 0, ERR_CANT_CREATE, "Invalid alignment, must be greater then 0."); @@ -83,8 +83,8 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String & } enc_dir = p_encrypt_directory; - file = FileAccess::open(p_file, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(file.is_null(), ERR_CANT_CREATE, "Can't open file to write: " + String(p_file) + "."); + file = FileAccess::open(p_pck_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(file.is_null(), ERR_CANT_CREATE, "Can't open file to write: " + String(p_pck_path) + "."); alignment = p_alignment; @@ -106,7 +106,7 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String & return OK; } -Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encrypt) { +Error PCKPacker::add_file(const String &p_pck_path, const String &p_src, bool p_encrypt) { ERR_FAIL_COND_V_MSG(file.is_null(), ERR_INVALID_PARAMETER, "File must be opened before use."); Ref<FileAccess> f = FileAccess::open(p_src, FileAccess::READ); @@ -117,7 +117,7 @@ Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encr File pf; // Simplify path here and on every 'files' access so that paths that have extra '/' // symbols in them still match to the MD5 hash for the saved path. - pf.path = p_file.simplify_path(); + pf.path = p_pck_path.simplify_path(); pf.src_path = p_src; pf.ofs = ofs; pf.size = f->get_length(); diff --git a/core/io/pck_packer.h b/core/io/pck_packer.h index 8764fc90a0..5aac833532 100644 --- a/core/io/pck_packer.h +++ b/core/io/pck_packer.h @@ -58,8 +58,8 @@ class PCKPacker : public RefCounted { Vector<File> files; public: - Error pck_start(const String &p_file, int p_alignment = 32, const String &p_key = "0000000000000000000000000000000000000000000000000000000000000000", bool p_encrypt_directory = false); - Error add_file(const String &p_file, const String &p_src, bool p_encrypt = false); + Error pck_start(const String &p_pck_path, int p_alignment = 32, const String &p_key = "0000000000000000000000000000000000000000000000000000000000000000", bool p_encrypt_directory = false); + Error add_file(const String &p_pck_path, const String &p_src, bool p_encrypt = false); Error flush(bool p_verbose = false); PCKPacker() {} diff --git a/core/io/resource.cpp b/core/io/resource.cpp index 6177cba6a4..5f8a4b85a4 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -96,6 +96,7 @@ String Resource::get_path() const { void Resource::set_path_cache(const String &p_path) { path_cache = p_path; + GDVIRTUAL_CALL(_set_path_cache, p_path); } String Resource::generate_scene_unique_id() { @@ -188,6 +189,7 @@ void Resource::disconnect_changed(const Callable &p_callable) { } void Resource::reset_state() { + GDVIRTUAL_CALL(_reset_state); } Error Resource::copy_from(const Ref<Resource> &p_resource) { @@ -495,9 +497,9 @@ void Resource::set_as_translation_remapped(bool p_remapped) { } } -#ifdef TOOLS_ENABLED //helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored void Resource::set_id_for_path(const String &p_path, const String &p_id) { +#ifdef TOOLS_ENABLED if (p_id.is_empty()) { ResourceCache::path_cache_lock.write_lock(); ResourceCache::resource_path_cache[p_path].erase(get_path()); @@ -507,9 +509,11 @@ void Resource::set_id_for_path(const String &p_path, const String &p_id) { ResourceCache::resource_path_cache[p_path][get_path()] = p_id; ResourceCache::path_cache_lock.write_unlock(); } +#endif } String Resource::get_id_for_path(const String &p_path) const { +#ifdef TOOLS_ENABLED ResourceCache::path_cache_lock.read_lock(); if (ResourceCache::resource_path_cache[p_path].has(get_path())) { String result = ResourceCache::resource_path_cache[p_path][get_path()]; @@ -519,13 +523,16 @@ String Resource::get_id_for_path(const String &p_path) const { ResourceCache::path_cache_lock.read_unlock(); return ""; } -} +#else + return ""; #endif +} void Resource::_bind_methods() { ClassDB::bind_method(D_METHOD("set_path", "path"), &Resource::_set_path); ClassDB::bind_method(D_METHOD("take_over_path", "path"), &Resource::_take_over_path); ClassDB::bind_method(D_METHOD("get_path"), &Resource::get_path); + ClassDB::bind_method(D_METHOD("set_path_cache", "path"), &Resource::set_path_cache); ClassDB::bind_method(D_METHOD("set_name", "name"), &Resource::set_name); ClassDB::bind_method(D_METHOD("get_name"), &Resource::get_name); ClassDB::bind_method(D_METHOD("get_rid"), &Resource::get_rid); @@ -533,6 +540,12 @@ void Resource::_bind_methods() { ClassDB::bind_method(D_METHOD("is_local_to_scene"), &Resource::is_local_to_scene); ClassDB::bind_method(D_METHOD("get_local_scene"), &Resource::get_local_scene); ClassDB::bind_method(D_METHOD("setup_local_to_scene"), &Resource::setup_local_to_scene); + ClassDB::bind_method(D_METHOD("reset_state"), &Resource::reset_state); + + ClassDB::bind_method(D_METHOD("set_id_for_path", "path", "id"), &Resource::set_id_for_path); + ClassDB::bind_method(D_METHOD("get_id_for_path", "path"), &Resource::get_id_for_path); + + ClassDB::bind_method(D_METHOD("is_built_in"), &Resource::is_built_in); ClassDB::bind_static_method("Resource", D_METHOD("generate_scene_unique_id"), &Resource::generate_scene_unique_id); ClassDB::bind_method(D_METHOD("set_scene_unique_id", "id"), &Resource::set_scene_unique_id); @@ -552,6 +565,8 @@ void Resource::_bind_methods() { GDVIRTUAL_BIND(_setup_local_to_scene); GDVIRTUAL_BIND(_get_rid); + GDVIRTUAL_BIND(_reset_state); + GDVIRTUAL_BIND(_set_path_cache, "path"); } Resource::Resource() : diff --git a/core/io/resource.h b/core/io/resource.h index 2c1a431255..8966c0233c 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -89,6 +89,9 @@ protected: GDVIRTUAL0RC(RID, _get_rid); + GDVIRTUAL1C(_set_path_cache, String); + GDVIRTUAL0(_reset_state); + public: static Node *(*_get_local_scene_func)(); //used by editor static void (*_update_configuration_warning)(); //used by editor @@ -144,11 +147,9 @@ public: virtual RID get_rid() const; // some resources may offer conversion to RID -#ifdef TOOLS_ENABLED //helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored void set_id_for_path(const String &p_path, const String &p_id); String get_id_for_path(const String &p_path) const; -#endif Resource(); ~Resource(); diff --git a/core/math/basis.h b/core/math/basis.h index 5c1a5fbdda..236d666103 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -41,11 +41,11 @@ struct [[nodiscard]] Basis { Vector3(0, 0, 1) }; - _FORCE_INLINE_ const Vector3 &operator[](int p_axis) const { - return rows[p_axis]; + _FORCE_INLINE_ const Vector3 &operator[](int p_row) const { + return rows[p_row]; } - _FORCE_INLINE_ Vector3 &operator[](int p_axis) { - return rows[p_axis]; + _FORCE_INLINE_ Vector3 &operator[](int p_row) { + return rows[p_row]; } void invert(); diff --git a/core/object/object.cpp b/core/object/object.cpp index da3ca6bc61..b3a4ec6e2e 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -1457,6 +1457,24 @@ bool Object::is_connected(const StringName &p_signal, const Callable &p_callable return s->slot_map.has(*p_callable.get_base_comparator()); } +bool Object::has_connections(const StringName &p_signal) const { + const SignalData *s = signal_map.getptr(p_signal); + if (!s) { + bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal); + if (signal_is_valid) { + return false; + } + + if (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)) { + return false; + } + + ERR_FAIL_V_MSG(false, "Nonexistent signal: " + p_signal + "."); + } + + return !s->slot_map.is_empty(); +} + void Object::disconnect(const StringName &p_signal, const Callable &p_callable) { _disconnect(p_signal, p_callable); } @@ -1527,21 +1545,21 @@ void Object::initialize_class() { initialized = true; } +StringName Object::get_translation_domain() const { + return _translation_domain; +} + +void Object::set_translation_domain(const StringName &p_domain) { + _translation_domain = p_domain; +} + String Object::tr(const StringName &p_message, const StringName &p_context) const { if (!_can_translate || !TranslationServer::get_singleton()) { return p_message; } - if (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint()) { - String tr_msg = TranslationServer::get_singleton()->extractable_translate(p_message, p_context); - if (!tr_msg.is_empty() && tr_msg != p_message) { - return tr_msg; - } - - return TranslationServer::get_singleton()->tool_translate(p_message, p_context); - } - - return TranslationServer::get_singleton()->translate(p_message, p_context); + const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain(get_translation_domain()); + return domain->translate(p_message, p_context); } String Object::tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { @@ -1553,16 +1571,8 @@ String Object::tr_n(const StringName &p_message, const StringName &p_message_plu return p_message_plural; } - if (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint()) { - String tr_msg = TranslationServer::get_singleton()->extractable_translate_plural(p_message, p_message_plural, p_n, p_context); - if (!tr_msg.is_empty() && tr_msg != p_message && tr_msg != p_message_plural) { - return tr_msg; - } - - return TranslationServer::get_singleton()->tool_translate_plural(p_message, p_message_plural, p_n, p_context); - } - - return TranslationServer::get_singleton()->translate_plural(p_message, p_message_plural, p_n, p_context); + const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain(get_translation_domain()); + return domain->translate_plural(p_message, p_message_plural, p_n, p_context); } void Object::_clear_internal_resource_paths(const Variant &p_var) { @@ -1705,6 +1715,7 @@ void Object::_bind_methods() { ClassDB::bind_method(D_METHOD("connect", "signal", "callable", "flags"), &Object::connect, DEFVAL(0)); ClassDB::bind_method(D_METHOD("disconnect", "signal", "callable"), &Object::disconnect); ClassDB::bind_method(D_METHOD("is_connected", "signal", "callable"), &Object::is_connected); + ClassDB::bind_method(D_METHOD("has_connections", "signal"), &Object::has_connections); ClassDB::bind_method(D_METHOD("set_block_signals", "enable"), &Object::set_block_signals); ClassDB::bind_method(D_METHOD("is_blocking_signals"), &Object::is_blocking_signals); @@ -1714,6 +1725,8 @@ void Object::_bind_methods() { ClassDB::bind_method(D_METHOD("can_translate_messages"), &Object::can_translate_messages); ClassDB::bind_method(D_METHOD("tr", "message", "context"), &Object::tr, DEFVAL(StringName())); ClassDB::bind_method(D_METHOD("tr_n", "message", "plural_message", "n", "context"), &Object::tr_n, DEFVAL(StringName())); + ClassDB::bind_method(D_METHOD("get_translation_domain"), &Object::get_translation_domain); + ClassDB::bind_method(D_METHOD("set_translation_domain", "domain"), &Object::set_translation_domain); ClassDB::bind_method(D_METHOD("is_queued_for_deletion"), &Object::is_queued_for_deletion); ClassDB::bind_method(D_METHOD("cancel_free"), &Object::cancel_free); diff --git a/core/object/object.h b/core/object/object.h index 6d22f320af..763e2974b9 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -665,6 +665,8 @@ private: Object(bool p_reference); protected: + StringName _translation_domain; + _FORCE_INLINE_ bool _instance_binding_reference(bool p_reference) { bool can_die = true; if (_instance_bindings) { @@ -930,6 +932,7 @@ public: MTVIRTUAL Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0); MTVIRTUAL void disconnect(const StringName &p_signal, const Callable &p_callable); MTVIRTUAL bool is_connected(const StringName &p_signal, const Callable &p_callable) const; + MTVIRTUAL bool has_connections(const StringName &p_signal) const; template <typename... VarArgs> void call_deferred(const StringName &p_name, VarArgs... p_args) { @@ -954,6 +957,9 @@ public: _FORCE_INLINE_ void set_message_translation(bool p_enable) { _can_translate = p_enable; } _FORCE_INLINE_ bool can_translate_messages() const { return _can_translate; } + virtual StringName get_translation_domain() const; + virtual void set_translation_domain(const StringName &p_domain); + #ifdef TOOLS_ENABLED virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const; void editor_set_section_unfold(const String &p_section, bool p_unfolded); diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index d2fc7392c8..c5856a8a81 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -191,7 +191,17 @@ void Script::reload_from_file() { set_source_code(rel->get_source_code()); set_last_modified_time(rel->get_last_modified_time()); - reload(); + // Only reload the script when there are no compilation errors to prevent printing the error messages twice. + if (rel->is_valid()) { + if (Engine::get_singleton()->is_editor_hint() && is_tool()) { + get_language()->reload_tool_script(this, true); + } else { + // It's important to set p_keep_state to true in order to manage reloading scripts + // that are currently instantiated. + reload(true); + } + } + #else Resource::reload_from_file(); #endif diff --git a/core/object/script_language.h b/core/object/script_language.h index d0023d70e8..3ddfbb3e7d 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -112,7 +112,10 @@ class Script : public Resource { OBJ_SAVE_TYPE(Script); protected: - virtual bool editor_can_reload_from_file() override { return false; } // this is handled by editor better + // Scripts are reloaded via the Script Editor when edited in Godot, + // the LSP server when edited in a connected external editor, or + // through EditorFileSystem::_update_script_documentation when updated directly on disk. + virtual bool editor_can_reload_from_file() override { return false; } void _notification(int p_what); static void _bind_methods(); diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index c866ff0415..3a578d01a6 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -233,6 +233,7 @@ void register_core_types() { GDREGISTER_CLASS(MainLoop); GDREGISTER_CLASS(Translation); + GDREGISTER_CLASS(TranslationDomain); GDREGISTER_CLASS(OptimizedTranslation); GDREGISTER_CLASS(UndoRedo); GDREGISTER_CLASS(TriangleMesh); diff --git a/core/string/translation_domain.cpp b/core/string/translation_domain.cpp new file mode 100644 index 0000000000..b44eb40366 --- /dev/null +++ b/core/string/translation_domain.cpp @@ -0,0 +1,165 @@ +/**************************************************************************/ +/* translation_domain.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "translation_domain.h" + +#include "core/string/translation.h" +#include "core/string/translation_server.h" + +StringName TranslationDomain::get_message_from_translations(const String &p_locale, const StringName &p_message, const StringName &p_context) const { + StringName res; + int best_score = 0; + + for (const Ref<Translation> &E : translations) { + ERR_CONTINUE(E.is_null()); + int score = TranslationServer::get_singleton()->compare_locales(p_locale, E->get_locale()); + if (score > 0 && score >= best_score) { + const StringName r = E->get_message(p_message, p_context); + if (!r) { + continue; + } + res = r; + best_score = score; + if (score == 10) { + break; // Exact match, skip the rest. + } + } + } + + return res; +} + +StringName TranslationDomain::get_message_from_translations(const String &p_locale, const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { + StringName res; + int best_score = 0; + + for (const Ref<Translation> &E : translations) { + ERR_CONTINUE(E.is_null()); + int score = TranslationServer::get_singleton()->compare_locales(p_locale, E->get_locale()); + if (score > 0 && score >= best_score) { + const StringName r = E->get_plural_message(p_message, p_message_plural, p_n, p_context); + if (!r) { + continue; + } + res = r; + best_score = score; + if (score == 10) { + break; // Exact match, skip the rest. + } + } + } + + return res; +} + +PackedStringArray TranslationDomain::get_loaded_locales() const { + PackedStringArray locales; + for (const Ref<Translation> &E : translations) { + ERR_CONTINUE(E.is_null()); + locales.push_back(E->get_locale()); + } + return locales; +} + +Ref<Translation> TranslationDomain::get_translation_object(const String &p_locale) const { + Ref<Translation> res; + int best_score = 0; + + for (const Ref<Translation> &E : translations) { + ERR_CONTINUE(E.is_null()); + + int score = TranslationServer::get_singleton()->compare_locales(p_locale, E->get_locale()); + if (score > 0 && score >= best_score) { + res = E; + best_score = score; + if (score == 10) { + break; // Exact match, skip the rest. + } + } + } + return res; +} + +void TranslationDomain::add_translation(const Ref<Translation> &p_translation) { + translations.insert(p_translation); +} + +void TranslationDomain::remove_translation(const Ref<Translation> &p_translation) { + translations.erase(p_translation); +} + +void TranslationDomain::clear() { + translations.clear(); +} + +StringName TranslationDomain::translate(const StringName &p_message, const StringName &p_context) const { + const String &locale = TranslationServer::get_singleton()->get_locale(); + StringName res = get_message_from_translations(locale, p_message, p_context); + + const String &fallback = TranslationServer::get_singleton()->get_fallback_locale(); + if (!res && fallback.length() >= 2) { + res = get_message_from_translations(fallback, p_message, p_context); + } + + if (!res) { + return p_message; + } + return res; +} + +StringName TranslationDomain::translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { + const String &locale = TranslationServer::get_singleton()->get_locale(); + StringName res = get_message_from_translations(locale, p_message, p_message_plural, p_n, p_context); + + const String &fallback = TranslationServer::get_singleton()->get_fallback_locale(); + if (!res && fallback.length() >= 2) { + res = get_message_from_translations(fallback, p_message, p_message_plural, p_n, p_context); + } + + if (!res) { + if (p_n == 1) { + return p_message; + } + return p_message_plural; + } + return res; +} + +void TranslationDomain::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_translation_object", "locale"), &TranslationDomain::get_translation_object); + ClassDB::bind_method(D_METHOD("add_translation", "translation"), &TranslationDomain::add_translation); + ClassDB::bind_method(D_METHOD("remove_translation", "translation"), &TranslationDomain::remove_translation); + ClassDB::bind_method(D_METHOD("clear"), &TranslationDomain::clear); + ClassDB::bind_method(D_METHOD("translate", "message", "context"), &TranslationDomain::translate, DEFVAL(StringName())); + ClassDB::bind_method(D_METHOD("translate_plural", "message", "message_plural", "n", "context"), &TranslationDomain::translate_plural, DEFVAL(StringName())); +} + +TranslationDomain::TranslationDomain() { +} diff --git a/core/string/translation_domain.h b/core/string/translation_domain.h new file mode 100644 index 0000000000..6139967217 --- /dev/null +++ b/core/string/translation_domain.h @@ -0,0 +1,65 @@ +/**************************************************************************/ +/* translation_domain.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 TRANSLATION_DOMAIN_H +#define TRANSLATION_DOMAIN_H + +#include "core/object/ref_counted.h" + +class Translation; + +class TranslationDomain : public RefCounted { + GDCLASS(TranslationDomain, RefCounted); + + HashSet<Ref<Translation>> translations; + +protected: + static void _bind_methods(); + +public: + // Methods in this section are not intended for scripting. + StringName get_message_from_translations(const String &p_locale, const StringName &p_message, const StringName &p_context) const; + StringName get_message_from_translations(const String &p_locale, const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const; + PackedStringArray get_loaded_locales() const; + +public: + Ref<Translation> get_translation_object(const String &p_locale) const; + + void add_translation(const Ref<Translation> &p_translation); + void remove_translation(const Ref<Translation> &p_translation); + void clear(); + + StringName translate(const StringName &p_message, const StringName &p_context) const; + StringName translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const; + + TranslationDomain(); +}; + +#endif // TRANSLATION_DOMAIN_H diff --git a/core/string/translation_server.cpp b/core/string/translation_server.cpp index d4aa152340..c6b818a49b 100644 --- a/core/string/translation_server.cpp +++ b/core/string/translation_server.cpp @@ -404,69 +404,36 @@ String TranslationServer::get_locale() const { return locale; } -PackedStringArray TranslationServer::get_loaded_locales() const { - PackedStringArray locales; - for (const Ref<Translation> &E : translations) { - const Ref<Translation> &t = E; - ERR_FAIL_COND_V(t.is_null(), PackedStringArray()); - String l = t->get_locale(); - - locales.push_back(l); - } +String TranslationServer::get_fallback_locale() const { + return fallback; +} - return locales; +PackedStringArray TranslationServer::get_loaded_locales() const { + return main_domain->get_loaded_locales(); } void TranslationServer::add_translation(const Ref<Translation> &p_translation) { - translations.insert(p_translation); + main_domain->add_translation(p_translation); } void TranslationServer::remove_translation(const Ref<Translation> &p_translation) { - translations.erase(p_translation); + main_domain->remove_translation(p_translation); } Ref<Translation> TranslationServer::get_translation_object(const String &p_locale) { - Ref<Translation> res; - int best_score = 0; - - for (const Ref<Translation> &E : translations) { - const Ref<Translation> &t = E; - ERR_FAIL_COND_V(t.is_null(), nullptr); - String l = t->get_locale(); - - int score = compare_locales(p_locale, l); - if (score > 0 && score >= best_score) { - res = t; - best_score = score; - if (score == 10) { - break; // Exact match, skip the rest. - } - } - } - return res; + return main_domain->get_translation_object(p_locale); } void TranslationServer::clear() { - translations.clear(); + main_domain->clear(); } StringName TranslationServer::translate(const StringName &p_message, const StringName &p_context) const { - // Match given message against the translation catalog for the project locale. - if (!enabled) { return p_message; } - StringName res = _get_message_from_translations(p_message, p_context, locale, false); - - if (!res && fallback.length() >= 2) { - res = _get_message_from_translations(p_message, p_context, fallback, false); - } - - if (!res) { - return pseudolocalization_enabled ? pseudolocalize(p_message) : p_message; - } - + const StringName res = main_domain->translate(p_message, p_context); return pseudolocalization_enabled ? pseudolocalize(res) : res; } @@ -478,51 +445,7 @@ StringName TranslationServer::translate_plural(const StringName &p_message, cons return p_message_plural; } - StringName res = _get_message_from_translations(p_message, p_context, locale, true, p_message_plural, p_n); - - if (!res && fallback.length() >= 2) { - res = _get_message_from_translations(p_message, p_context, fallback, true, p_message_plural, p_n); - } - - if (!res) { - if (p_n == 1) { - return p_message; - } - return p_message_plural; - } - - return res; -} - -StringName TranslationServer::_get_message_from_translations(const StringName &p_message, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural, int p_n) const { - StringName res; - int best_score = 0; - - for (const Ref<Translation> &E : translations) { - const Ref<Translation> &t = E; - ERR_FAIL_COND_V(t.is_null(), p_message); - String l = t->get_locale(); - - int score = compare_locales(p_locale, l); - if (score > 0 && score >= best_score) { - StringName r; - if (!plural) { - r = t->get_message(p_message, p_context); - } else { - r = t->get_plural_message(p_message, p_message_plural, p_n, p_context); - } - if (!r) { - continue; - } - res = r; - best_score = score; - if (score == 10) { - break; // Exact match, skip the rest. - } - } - } - - return res; + return main_domain->translate_plural(p_message, p_message_plural, p_n, p_context); } TranslationServer *TranslationServer::singleton = nullptr; @@ -549,6 +472,34 @@ bool TranslationServer::_load_translations(const String &p_from) { return false; } +bool TranslationServer::has_domain(const StringName &p_domain) const { + if (p_domain == StringName()) { + return true; + } + return custom_domains.has(p_domain); +} + +Ref<TranslationDomain> TranslationServer::get_or_add_domain(const StringName &p_domain) { + if (p_domain == StringName()) { + return main_domain; + } + const Ref<TranslationDomain> *domain = custom_domains.getptr(p_domain); + if (domain) { + if (domain->is_valid()) { + return *domain; + } + ERR_PRINT("Bug (please report): Found invalid translation domain."); + } + Ref<TranslationDomain> new_domain = memnew(TranslationDomain); + custom_domains[p_domain] = new_domain; + return new_domain; +} + +void TranslationServer::remove_domain(const StringName &p_domain) { + ERR_FAIL_COND_MSG(p_domain == StringName(), "Cannot remove main translation domain."); + custom_domains.erase(p_domain); +} + void TranslationServer::setup() { String test = GLOBAL_DEF("internationalization/locale/test", ""); test = test.strip_edges(); @@ -574,140 +525,45 @@ void TranslationServer::setup() { #endif } -void TranslationServer::set_tool_translation(const Ref<Translation> &p_translation) { - tool_translation = p_translation; -} - -Ref<Translation> TranslationServer::get_tool_translation() const { - return tool_translation; -} - String TranslationServer::get_tool_locale() { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint()) { - if (TranslationServer::get_singleton()->get_tool_translation().is_valid()) { - return tool_translation->get_locale(); - } else { + const PackedStringArray &locales = editor_domain->get_loaded_locales(); + if (locales.is_empty()) { return "en"; } + return locales[0]; } else { #else { #endif // Look for best matching loaded translation. - String best_locale = "en"; - int best_score = 0; - - for (const Ref<Translation> &E : translations) { - const Ref<Translation> &t = E; - ERR_FAIL_COND_V(t.is_null(), best_locale); - String l = t->get_locale(); - - int score = compare_locales(locale, l); - if (score > 0 && score >= best_score) { - best_locale = l; - best_score = score; - if (score == 10) { - break; // Exact match, skip the rest. - } - } + Ref<Translation> t = main_domain->get_translation_object(locale); + if (t.is_null()) { + return "en"; } - return best_locale; + return t->get_locale(); } } StringName TranslationServer::tool_translate(const StringName &p_message, const StringName &p_context) const { - if (tool_translation.is_valid()) { - StringName r = tool_translation->get_message(p_message, p_context); - if (r) { - return r; - } - } - return p_message; + return editor_domain->translate(p_message, p_context); } StringName TranslationServer::tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { - if (tool_translation.is_valid()) { - StringName r = tool_translation->get_plural_message(p_message, p_message_plural, p_n, p_context); - if (r) { - return r; - } - } - - if (p_n == 1) { - return p_message; - } - return p_message_plural; -} - -void TranslationServer::set_property_translation(const Ref<Translation> &p_translation) { - property_translation = p_translation; + return editor_domain->translate_plural(p_message, p_message_plural, p_n, p_context); } StringName TranslationServer::property_translate(const StringName &p_message, const StringName &p_context) const { - if (property_translation.is_valid()) { - StringName r = property_translation->get_message(p_message, p_context); - if (r) { - return r; - } - } - return p_message; -} - -void TranslationServer::set_doc_translation(const Ref<Translation> &p_translation) { - doc_translation = p_translation; + return property_domain->translate(p_message, p_context); } StringName TranslationServer::doc_translate(const StringName &p_message, const StringName &p_context) const { - if (doc_translation.is_valid()) { - StringName r = doc_translation->get_message(p_message, p_context); - if (r) { - return r; - } - } - return p_message; + return doc_domain->translate(p_message, p_context); } StringName TranslationServer::doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { - if (doc_translation.is_valid()) { - StringName r = doc_translation->get_plural_message(p_message, p_message_plural, p_n, p_context); - if (r) { - return r; - } - } - - if (p_n == 1) { - return p_message; - } - return p_message_plural; -} - -void TranslationServer::set_extractable_translation(const Ref<Translation> &p_translation) { - extractable_translation = p_translation; -} - -StringName TranslationServer::extractable_translate(const StringName &p_message, const StringName &p_context) const { - if (extractable_translation.is_valid()) { - StringName r = extractable_translation->get_message(p_message, p_context); - if (r) { - return r; - } - } - return p_message; -} - -StringName TranslationServer::extractable_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { - if (extractable_translation.is_valid()) { - StringName r = extractable_translation->get_plural_message(p_message, p_message_plural, p_n, p_context); - if (r) { - return r; - } - } - - if (p_n == 1) { - return p_message; - } - return p_message_plural; + return doc_domain->translate_plural(p_message, p_message_plural, p_n, p_context); } bool TranslationServer::is_pseudolocalization_enabled() const { @@ -925,6 +781,10 @@ void TranslationServer::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_translation", "translation"), &TranslationServer::remove_translation); ClassDB::bind_method(D_METHOD("get_translation_object", "locale"), &TranslationServer::get_translation_object); + ClassDB::bind_method(D_METHOD("has_domain", "domain"), &TranslationServer::has_domain); + ClassDB::bind_method(D_METHOD("get_or_add_domain", "domain"), &TranslationServer::get_or_add_domain); + ClassDB::bind_method(D_METHOD("remove_domain", "domain"), &TranslationServer::remove_domain); + ClassDB::bind_method(D_METHOD("clear"), &TranslationServer::clear); ClassDB::bind_method(D_METHOD("get_loaded_locales"), &TranslationServer::get_loaded_locales); @@ -947,5 +807,9 @@ void TranslationServer::load_translations() { TranslationServer::TranslationServer() { singleton = this; + main_domain.instantiate(); + editor_domain = get_or_add_domain("godot.editor"); + property_domain = get_or_add_domain("godot.properties"); + doc_domain = get_or_add_domain("godot.documentation"); init_locale_info(); } diff --git a/core/string/translation_server.h b/core/string/translation_server.h index bb285ab19c..272fa1f11c 100644 --- a/core/string/translation_server.h +++ b/core/string/translation_server.h @@ -32,6 +32,7 @@ #define TRANSLATION_SERVER_H #include "core/string/translation.h" +#include "core/string/translation_domain.h" class TranslationServer : public Object { GDCLASS(TranslationServer, Object); @@ -39,11 +40,11 @@ class TranslationServer : public Object { String locale = "en"; String fallback; - HashSet<Ref<Translation>> translations; - Ref<Translation> tool_translation; - Ref<Translation> property_translation; - Ref<Translation> doc_translation; - Ref<Translation> extractable_translation; + Ref<TranslationDomain> main_domain; + Ref<TranslationDomain> editor_domain; + Ref<TranslationDomain> property_domain; + Ref<TranslationDomain> doc_domain; + HashMap<StringName, Ref<TranslationDomain>> custom_domains; bool enabled = true; @@ -70,8 +71,6 @@ class TranslationServer : public Object { bool _load_translations(const String &p_from); String _standardize_locale(const String &p_locale, bool p_add_defaults) const; - StringName _get_message_from_translations(const StringName &p_message, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural = "", int p_n = 0) const; - static void _bind_methods(); struct LocaleScriptInfo { @@ -99,6 +98,7 @@ public: void set_locale(const String &p_locale); String get_locale() const; + String get_fallback_locale() const; Ref<Translation> get_translation_object(const String &p_locale); Vector<String> get_all_languages() const; @@ -131,18 +131,15 @@ public: int compare_locales(const String &p_locale_a, const String &p_locale_b) const; String get_tool_locale(); - void set_tool_translation(const Ref<Translation> &p_translation); - Ref<Translation> get_tool_translation() const; StringName tool_translate(const StringName &p_message, const StringName &p_context = "") const; StringName tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; - void set_property_translation(const Ref<Translation> &p_translation); StringName property_translate(const StringName &p_message, const StringName &p_context = "") const; - void set_doc_translation(const Ref<Translation> &p_translation); StringName doc_translate(const StringName &p_message, const StringName &p_context = "") const; StringName doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; - void set_extractable_translation(const Ref<Translation> &p_translation); - StringName extractable_translate(const StringName &p_message, const StringName &p_context = "") const; - StringName extractable_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; + + bool has_domain(const StringName &p_domain) const; + Ref<TranslationDomain> get_or_add_domain(const StringName &p_domain); + void remove_domain(const StringName &p_domain); void setup(); diff --git a/core/variant/array.cpp b/core/variant/array.cpp index 869499e668..3e62d3dffa 100644 --- a/core/variant/array.cpp +++ b/core/variant/array.cpp @@ -369,6 +369,34 @@ int Array::find(const Variant &p_value, int p_from) const { return ret; } +int Array::find_custom(const Callable &p_callable, int p_from) const { + int ret = -1; + + if (p_from < 0 || size() == 0) { + return ret; + } + + const Variant *argptrs[1]; + + for (int i = p_from; i < size(); i++) { + const Variant &val = _p->array[i]; + argptrs[0] = &val; + Variant res; + Callable::CallError ce; + p_callable.callp(argptrs, 1, res, ce); + if (unlikely(ce.error != Callable::CallError::CALL_OK)) { + ERR_FAIL_V_MSG(ret, "Error calling method from 'find_custom': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce)); + } + + ERR_FAIL_COND_V_MSG(res.get_type() != Variant::Type::BOOL, ret, "Error on method from 'find_custom': Return type of callable must be boolean."); + if (res.operator bool()) { + return i; + } + } + + return ret; +} + int Array::rfind(const Variant &p_value, int p_from) const { if (_p->array.size() == 0) { return -1; @@ -394,6 +422,41 @@ int Array::rfind(const Variant &p_value, int p_from) const { return -1; } +int Array::rfind_custom(const Callable &p_callable, int p_from) const { + if (_p->array.size() == 0) { + return -1; + } + + if (p_from < 0) { + // Relative offset from the end. + p_from = _p->array.size() + p_from; + } + if (p_from < 0 || p_from >= _p->array.size()) { + // Limit to array boundaries. + p_from = _p->array.size() - 1; + } + + const Variant *argptrs[1]; + + for (int i = p_from; i >= 0; i--) { + const Variant &val = _p->array[i]; + argptrs[0] = &val; + Variant res; + Callable::CallError ce; + p_callable.callp(argptrs, 1, res, ce); + if (unlikely(ce.error != Callable::CallError::CALL_OK)) { + ERR_FAIL_V_MSG(-1, "Error calling method from 'rfind_custom': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce)); + } + + ERR_FAIL_COND_V_MSG(res.get_type() != Variant::Type::BOOL, -1, "Error on method from 'rfind_custom': Return type of callable must be boolean."); + if (res.operator bool()) { + return i; + } + } + + return -1; +} + int Array::count(const Variant &p_value) const { Variant value = p_value; ERR_FAIL_COND_V(!_p->typed.validate(value, "count"), 0); @@ -761,7 +824,7 @@ Variant Array::max() const { return Variant(); //not a valid comparison } if (bool(ret)) { - //is less + //is greater maxval = test; } } diff --git a/core/variant/array.h b/core/variant/array.h index 12824ee3f6..6c3bae6ccb 100644 --- a/core/variant/array.h +++ b/core/variant/array.h @@ -152,7 +152,9 @@ public: void reverse(); int find(const Variant &p_value, int p_from = 0) const; + int find_custom(const Callable &p_callable, int p_from = 0) const; int rfind(const Variant &p_value, int p_from = -1) const; + int rfind_custom(const Callable &p_callable, int p_from = -1) const; int count(const Variant &p_value) const; bool has(const Variant &p_value) const; diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp index 9dff5c1e91..bb2d0313f6 100644 --- a/core/variant/callable.cpp +++ b/core/variant/callable.cpp @@ -545,6 +545,13 @@ bool Signal::is_connected(const Callable &p_callable) const { return obj->is_connected(name, p_callable); } +bool Signal::has_connections() const { + Object *obj = get_object(); + ERR_FAIL_NULL_V(obj, false); + + return obj->has_connections(name); +} + Array Signal::get_connections() const { Object *obj = get_object(); if (!obj) { diff --git a/core/variant/callable.h b/core/variant/callable.h index 63757d9d6e..e3c940a0e5 100644 --- a/core/variant/callable.h +++ b/core/variant/callable.h @@ -192,6 +192,7 @@ public: Error connect(const Callable &p_callable, uint32_t p_flags = 0); void disconnect(const Callable &p_callable); bool is_connected(const Callable &p_callable) const; + bool has_connections() const; Array get_connections() const; Signal(const Object *p_object, const StringName &p_name); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 2da94de875..63fb5e8d94 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -2121,6 +2121,7 @@ static void _register_variant_builtin_methods_misc() { bind_method(Signal, disconnect, sarray("callable"), varray()); bind_method(Signal, is_connected, sarray("callable"), varray()); bind_method(Signal, get_connections, sarray(), varray()); + bind_method(Signal, has_connections, sarray(), varray()); bind_custom(Signal, emit, _VariantCall::func_Signal_emit, false, Variant); @@ -2305,7 +2306,9 @@ static void _register_variant_builtin_methods_array() { bind_method(Array, back, sarray(), varray()); bind_method(Array, pick_random, sarray(), varray()); bind_method(Array, find, sarray("what", "from"), varray(0)); + bind_method(Array, find_custom, sarray("method", "from"), varray(0)); bind_method(Array, rfind, sarray("what", "from"), varray(-1)); + bind_method(Array, rfind_custom, sarray("method", "from"), varray(-1)); bind_method(Array, count, sarray("value"), varray()); bind_method(Array, has, sarray("value"), varray()); bind_method(Array, pop_back, sarray(), varray()); diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h index ac39a4135f..0bd8b830e0 100644 --- a/core/variant/variant_op.h +++ b/core/variant/variant_op.h @@ -923,7 +923,10 @@ public: static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { bool valid = true; String result = do_mod(*VariantGetInternalPtr<S>::get_ptr(left), &valid); - ERR_FAIL_COND_MSG(!valid, result); + if (unlikely(!valid)) { + *VariantGetInternalPtr<String>::get_ptr(r_ret) = *VariantGetInternalPtr<S>::get_ptr(left); + ERR_FAIL_MSG(vformat("String formatting error: %s.", result)); + } *VariantGetInternalPtr<String>::get_ptr(r_ret) = result; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -948,7 +951,10 @@ public: static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { bool valid = true; String result = do_mod(*VariantGetInternalPtr<S>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right), &valid); - ERR_FAIL_COND_MSG(!valid, result); + if (unlikely(!valid)) { + *VariantGetInternalPtr<String>::get_ptr(r_ret) = *VariantGetInternalPtr<S>::get_ptr(left); + ERR_FAIL_MSG(vformat("String formatting error: %s.", result)); + } *VariantGetInternalPtr<String>::get_ptr(r_ret) = result; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -976,7 +982,10 @@ public: static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { bool valid = true; String result = do_mod(*VariantGetInternalPtr<S>::get_ptr(left), right->get_validated_object(), &valid); - ERR_FAIL_COND_MSG(!valid, result); + if (unlikely(!valid)) { + *VariantGetInternalPtr<String>::get_ptr(r_ret) = *VariantGetInternalPtr<S>::get_ptr(left); + ERR_FAIL_MSG(vformat("String formatting error: %s.", result)); + } *VariantGetInternalPtr<String>::get_ptr(r_ret) = result; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -1003,7 +1012,10 @@ public: static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { bool valid = true; String result = do_mod(*VariantGetInternalPtr<S>::get_ptr(left), *VariantGetInternalPtr<T>::get_ptr(right), &valid); - ERR_FAIL_COND_MSG(!valid, result); + if (unlikely(!valid)) { + *VariantGetInternalPtr<String>::get_ptr(r_ret) = *VariantGetInternalPtr<S>::get_ptr(left); + ERR_FAIL_MSG(vformat("String formatting error: %s.", result)); + } *VariantGetInternalPtr<String>::get_ptr(r_ret) = result; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -1492,7 +1504,10 @@ public: } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { Object *l = right->get_validated_object(); - ERR_FAIL_NULL(l); + if (unlikely(!l)) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = false; + ERR_FAIL_MSG("Invalid base object for 'in'."); + } const String &a = *VariantGetInternalPtr<String>::get_ptr(left); bool valid; @@ -1526,7 +1541,10 @@ public: } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { Object *l = right->get_validated_object(); - ERR_FAIL_NULL(l); + if (unlikely(!l)) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = false; + ERR_FAIL_MSG("Invalid base object for 'in'."); + } const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(left); bool valid; diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index f222cbc969..a86f41cd9c 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -856,7 +856,7 @@ GD.Print("a", "b", a); // Prints ab[1, 2, 3] [/csharp] [/codeblocks] - [b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print] or [method print_rich]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed. + [b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print] or [method print_rich]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed. See also [member Engine.print_to_stdout] and [member ProjectSettings.application/run/disable_stdout]. </description> </method> <method name="print_rich" qualifiers="vararg"> diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index 2a06b98d06..adb6be1070 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -324,6 +324,7 @@ <param index="0" name="value" type="Variant" /> <description> Returns the number of times an element is in the array. + To count how many elements in an array satisfy a condition, see [method reduce]. </description> </method> <method name="duplicate" qualifiers="const"> @@ -395,6 +396,25 @@ [b]Note:[/b] For performance reasons, the search is affected by [param what]'s [enum Variant.Type]. For example, [code]7[/code] ([int]) and [code]7.0[/code] ([float]) are not considered equal for this method. </description> </method> + <method name="find_custom" qualifiers="const"> + <return type="int" /> + <param index="0" name="method" type="Callable" /> + <param index="1" name="from" type="int" default="0" /> + <description> + Returns the index of the [b]first[/b] element in the array that causes [param method] to return [code]true[/code], or [code]-1[/code] if there are none. The search's start can be specified with [param from], continuing to the end of the array. + [param method] is a callable that takes an element of the array, and returns a [bool]. + [b]Note:[/b] If you just want to know whether the array contains [i]anything[/i] that satisfies [param method], use [method any]. + [codeblocks] + [gdscript] + func is_even(number): + return number % 2 == 0 + + func _ready(): + print([1, 3, 4, 7].find_custom(is_even.bind())) # prints 2 + [/gdscript] + [/codeblocks] + </description> + </method> <method name="front" qualifiers="const"> <return type="Variant" /> <description> @@ -618,6 +638,17 @@ func is_length_greater(a, b): return a.length() > b.length() [/codeblock] + This method can also be used to count how many elements in an array satisfy a certain condition, similar to [method count]: + [codeblock] + func is_even(number): + return number % 2 == 0 + + func _ready(): + var arr = [1, 2, 3, 4, 5] + # Increment count if it's even, else leaves count the same. + var even_count = arr.reduce(func(count, next): return count + 1 if is_even(next) else count, 0) + print(even_count) # Prints 2 + [/codeblock] See also [method map], [method filter], [method any] and [method all]. </description> </method> @@ -654,6 +685,14 @@ Returns the index of the [b]last[/b] occurrence of [param what] in this array, or [code]-1[/code] if there are none. The search's start can be specified with [param from], continuing to the beginning of the array. This method is the reverse of [method find]. </description> </method> + <method name="rfind_custom" qualifiers="const"> + <return type="int" /> + <param index="0" name="method" type="Callable" /> + <param index="1" name="from" type="int" default="-1" /> + <description> + Returns the index of the [b]last[/b] element of the array that causes [param method] to return [code]true[/code], or [code]-1[/code] if there are none. The search's start can be specified with [param from], continuing to the beginning of the array. This method is the reverse of [method find_custom]. + </description> + </method> <method name="shuffle"> <return type="void" /> <description> diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml index 764f4a65b5..18dccfa5a9 100644 --- a/doc/classes/BaseButton.xml +++ b/doc/classes/BaseButton.xml @@ -57,7 +57,7 @@ </member> <member name="button_pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false"> If [code]true[/code], the button's state is pressed. Means the button is pressed down or toggled (if [member toggle_mode] is active). Only works if [member toggle_mode] is [code]true[/code]. - [b]Note:[/b] Setting [member button_pressed] will result in [signal toggled] to be emitted. If you want to change the pressed state without emitting that signal, use [method set_pressed_no_signal]. + [b]Note:[/b] Changing the value of [member button_pressed] will result in [signal toggled] to be emitted. If you want to change the pressed state without emitting that signal, use [method set_pressed_no_signal]. </member> <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false" keywords="enabled"> If [code]true[/code], the button is in disabled state and can't be clicked or toggled. diff --git a/doc/classes/CompositorEffect.xml b/doc/classes/CompositorEffect.xml index 9ac54edb11..8961e10f91 100644 --- a/doc/classes/CompositorEffect.xml +++ b/doc/classes/CompositorEffect.xml @@ -87,7 +87,7 @@ The callback is called before our transparent rendering pass, but after our sky is rendered and we've created our back buffers. </constant> <constant name="EFFECT_CALLBACK_TYPE_POST_TRANSPARENT" value="4" enum="EffectCallbackType"> - The callback is called after our transparent rendering pass, but before any build in post effects and output to our render target. + The callback is called after our transparent rendering pass, but before any built-in post-processing effects and output to our render target. </constant> <constant name="EFFECT_CALLBACK_TYPE_MAX" value="5" enum="EffectCallbackType"> Represents the size of the [enum EffectCallbackType] enum. diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index de49764f0d..8189f253fb 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -701,7 +701,7 @@ <return type="void" /> <param index="0" name="plugin" type="EditorInspectorPlugin" /> <description> - Removes an inspector plugin registered by [method add_import_plugin] + Removes an inspector plugin registered by [method add_inspector_plugin]. </description> </method> <method name="remove_node_3d_gizmo_plugin"> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index a151d8a41e..5eb8ac6199 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -904,7 +904,7 @@ </member> <member name="interface/inspector/delimitate_all_container_and_resources" type="bool" setter="" getter=""> If [code]true[/code], add a margin around Array, Dictionary, and Resource Editors that are not already colored. - [b]Note:[/b] If [member interface/inspector/nested_color_mode] is set to [b]Containers & Resources[/b] this parameter will have no effect since those editors will already be colored + [b]Note:[/b] If [member interface/inspector/nested_color_mode] is set to [b]Containers & Resources[/b] this parameter will have no effect since those editors will already be colored. </member> <member name="interface/inspector/disable_folding" type="bool" setter="" getter=""> If [code]true[/code], forces all property groups to be expanded in the Inspector dock and prevents collapsing them. @@ -1200,6 +1200,9 @@ <member name="text_editor/behavior/files/trim_trailing_whitespace_on_save" type="bool" setter="" getter=""> If [code]true[/code], trims trailing whitespace when saving a script. Trailing whitespace refers to tab and space characters placed at the end of lines. Since these serve no practical purpose, they can and should be removed to make version control diffs less noisy. </member> + <member name="text_editor/behavior/general/empty_selection_clipboard" type="bool" setter="" getter=""> + If [code]true[/code], copying or cutting without a selection is performed on all lines with a caret. Otherwise, copy and cut require a selection. + </member> <member name="text_editor/behavior/indent/auto_indent" type="bool" setter="" getter=""> If [code]true[/code], automatically indents code when pressing the [kbd]Enter[/kbd] key based on blocks above the new line. </member> diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index ca78054875..bba5157053 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -337,6 +337,10 @@ [b]Note:[/b] This property does not impact the editor's Errors tab when running a project from the editor. [b]Warning:[/b] If set to [code]false[/code] anywhere in the project, important error messages may be hidden even if they are emitted from other scripts. In a [code]@tool[/code] script, this will also impact the editor itself. Do [i]not[/i] report bugs before ensuring error messages are enabled (as they are by default). </member> + <member name="print_to_stdout" type="bool" setter="set_print_to_stdout" getter="is_printing_to_stdout" default="true"> + If [code]false[/code], stops printing messages (for example using [method @GlobalScope.print]) to the console, log files, and editor Output log. This property is equivalent to the [member ProjectSettings.application/run/disable_stdout] project setting. + [b]Note:[/b] This does not stop printing errors or warnings produced by scripts to the console or log files, for more details see [member print_error_messages]. + </member> <member name="time_scale" type="float" setter="set_time_scale" getter="get_time_scale" default="1.0"> The speed multiplier at which the in-game clock updates, compared to real time. For example, if set to [code]2.0[/code] the game runs twice as fast, and if set to [code]0.5[/code] the game runs half as fast. This value affects [Timer], [SceneTreeTimer], and all other simulations that make use of [code]delta[/code] time (such as [method Node._process] and [method Node._physics_process]). diff --git a/doc/classes/EngineDebugger.xml b/doc/classes/EngineDebugger.xml index 7583520da0..bcc1ac5299 100644 --- a/doc/classes/EngineDebugger.xml +++ b/doc/classes/EngineDebugger.xml @@ -87,7 +87,7 @@ <method name="line_poll"> <return type="void" /> <description> - Forces a processing loop of debugger events. The purpose of this method is just processing events every now and then when the script might get too busy, so that bugs like infinite loops can be caught + Forces a processing loop of debugger events. The purpose of this method is just processing events every now and then when the script might get too busy, so that bugs like infinite loops can be caught. </description> </method> <method name="profiler_add_frame_data"> diff --git a/doc/classes/ExternalTexture.xml b/doc/classes/ExternalTexture.xml new file mode 100644 index 0000000000..6f27b62f24 --- /dev/null +++ b/doc/classes/ExternalTexture.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ExternalTexture" inherits="Texture2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Texture which displays the content of an external buffer. + </brief_description> + <description> + Displays the content of an external buffer provided by the platform. + Requires the [url=https://registry.khronos.org/OpenGL/extensions/OES/OES_EGL_image_external.txt]OES_EGL_image_external[/url] extension (OpenGL) or [url=https://registry.khronos.org/vulkan/specs/1.1-extensions/html/vkspec.html#VK_ANDROID_external_memory_android_hardware_buffer]VK_ANDROID_external_memory_android_hardware_buffer[/url] extension (Vulkan). + [b]Note:[/b] This is currently only supported in Android builds. + </description> + <tutorials> + </tutorials> + <methods> + <method name="get_external_texture_id" qualifiers="const"> + <return type="int" /> + <description> + Returns the external texture ID. + Depending on your use case, you may need to pass this to platform APIs, for example, when creating an [code]android.graphics.SurfaceTexture[/code] on Android. + </description> + </method> + <method name="set_external_buffer_id"> + <return type="void" /> + <param index="0" name="external_buffer_id" type="int" /> + <description> + Sets the external buffer ID. + Depending on your use case, you may need to call this with data received from a platform API, for example, [code]SurfaceTexture.getHardwareBuffer()[/code] on Android. + </description> + </method> + </methods> + <members> + <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" /> + <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(256, 256)"> + External texture size. + </member> + </members> +</class> diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml index 1b8fa00772..c230bf5ad2 100644 --- a/doc/classes/FontFile.xml +++ b/doc/classes/FontFile.xml @@ -58,7 +58,7 @@ <return type="void" /> <param index="0" name="cache_index" type="int" /> <description> - Removes all font sizes from the cache entry + Removes all font sizes from the cache entry. </description> </method> <method name="clear_textures"> diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index d218f720a3..9c460e6d62 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -151,12 +151,24 @@ Returns [code]true[/code] if the user has text in the [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] (IME). </description> </method> + <method name="has_redo" qualifiers="const"> + <return type="bool" /> + <description> + Returns [code]true[/code] if a "redo" action is available. + </description> + </method> <method name="has_selection" qualifiers="const"> <return type="bool" /> <description> Returns [code]true[/code] if the user has selected text. </description> </method> + <method name="has_undo" qualifiers="const"> + <return type="bool" /> + <description> + Returns [code]true[/code] if an "undo" action is available. + </description> + </method> <method name="insert_text_at_caret"> <return type="void" /> <param index="0" name="text" type="String" /> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 0042ce67d5..42753f7071 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -973,6 +973,13 @@ Similar to [method call_thread_safe], but for setting properties. </description> </method> + <method name="set_translation_domain_inherited"> + <return type="void" /> + <description> + Makes this node inherit the translation domain from its parent node. If this node has no parent, the main translation domain will be used. + This is the default behavior for all nodes. Calling [method Object.set_translation_domain] disables this behavior. + </description> + </method> <method name="update_configuration_warnings"> <return type="void" /> <description> diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index a331c05e47..2767a11e80 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -818,6 +818,20 @@ [b]Note:[/b] Due of the implementation, each [Dictionary] is formatted very similarly to the returned values of [method get_method_list]. </description> </method> + <method name="get_translation_domain" qualifiers="const"> + <return type="StringName" /> + <description> + Returns the name of the translation domain used by [method tr] and [method tr_n]. See also [TranslationServer]. + </description> + </method> + <method name="has_connections" qualifiers="const"> + <return type="bool" /> + <param index="0" name="signal" type="StringName" /> + <description> + Returns [code]true[/code] if any connection exists on the given [param signal] name. + [b]Note:[/b] In C#, [param signal] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]SignalName[/code] class to avoid allocating a new [StringName] on each call. + </description> + </method> <method name="has_meta" qualifiers="const"> <return type="bool" /> <param index="0" name="name" type="StringName" /> @@ -1070,6 +1084,13 @@ If a script already exists, its instance is detached, and its property values and state are lost. Built-in property values are still kept. </description> </method> + <method name="set_translation_domain"> + <return type="void" /> + <param index="0" name="domain" type="StringName" /> + <description> + Sets the name of the translation domain used by [method tr] and [method tr_n]. See also [TranslationServer]. + </description> + </method> <method name="to_string"> <return type="String" /> <description> @@ -1121,7 +1142,7 @@ Notification received when the object is initialized, before its script is attached. Used internally. </constant> <constant name="NOTIFICATION_PREDELETE" value="1"> - Notification received when the object is about to be deleted. Can act as the deconstructor of some programming languages. + Notification received when the object is about to be deleted. Can be used like destructors in object-oriented programming languages. </constant> <constant name="NOTIFICATION_EXTENSION_RELOADED" value="2"> Notification received when the object finishes hot reloading. This notification is only sent for extensions classes and derived. diff --git a/doc/classes/PCKPacker.xml b/doc/classes/PCKPacker.xml index 494e9966ac..ec0300c068 100644 --- a/doc/classes/PCKPacker.xml +++ b/doc/classes/PCKPacker.xml @@ -42,12 +42,12 @@ </method> <method name="pck_start"> <return type="int" enum="Error" /> - <param index="0" name="pck_name" type="String" /> + <param index="0" name="pck_path" type="String" /> <param index="1" name="alignment" type="int" default="32" /> <param index="2" name="key" type="String" default=""0000000000000000000000000000000000000000000000000000000000000000"" /> <param index="3" name="encrypt_directory" type="bool" default="false" /> <description> - Creates a new PCK file with the name [param pck_name]. The [code].pck[/code] file extension isn't added automatically, so it should be part of [param pck_name] (even though it's not required). + Creates a new PCK file at the file path [param pck_path]. The [code].pck[/code] file extension isn't added automatically, so it should be part of [param pck_path] (even though it's not required). </description> </method> </methods> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index d35d30efd8..0e5097b7b2 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -314,11 +314,11 @@ </member> <member name="application/run/disable_stderr" type="bool" setter="" getter="" default="false"> If [code]true[/code], disables printing to standard error. If [code]true[/code], this also hides error and warning messages printed by [method @GlobalScope.push_error] and [method @GlobalScope.push_warning]. See also [member application/run/disable_stdout]. - Changes to this setting will only be applied upon restarting the application. + Changes to this setting will only be applied upon restarting the application. To control this at runtime, use [member Engine.print_error_messages]. </member> <member name="application/run/disable_stdout" type="bool" setter="" getter="" default="false"> If [code]true[/code], disables printing to standard output. This is equivalent to starting the editor or project with the [code]--quiet[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url]. See also [member application/run/disable_stderr]. - Changes to this setting will only be applied upon restarting the application. + Changes to this setting will only be applied upon restarting the application. To control this at runtime, use [member Engine.print_to_stdout]. </member> <member name="application/run/enable_alt_space_menu" type="bool" setter="" getter="" default="false"> If [code]true[/code], allows the [kbd]Alt + Space[/kbd] keys to display the window menu. This menu allows the user to perform various window management operations such as moving, resizing, or minimizing the window. @@ -2293,6 +2293,7 @@ <member name="physics/3d/physics_engine" type="String" setter="" getter="" default=""DEFAULT""> Sets which physics engine to use for 3D physics. "DEFAULT" and "GodotPhysics3D" are the same, as there is currently no alternative 3D physics server implemented. + "Dummy" is a 3D physics server that does nothing and returns only dummy values, effectively disabling all 3D physics functionality. </member> <member name="physics/3d/run_on_separate_thread" type="bool" setter="" getter="" default="false"> If [code]true[/code], the 3D physics server runs on a separate thread, making better use of multi-core CPUs. If [code]false[/code], the 3D physics server runs on the main thread. Running the physics server on a separate thread can increase performance, but restricts API access to only physics process. @@ -2795,6 +2796,10 @@ If [code]true[/code], the forward renderer will fall back to Direct3D 12 if Vulkan is not supported. [b]Note:[/b] This setting is implemented only on Windows. </member> + <member name="rendering/rendering_device/fallback_to_opengl3" type="bool" setter="" getter="" default="true"> + If [code]true[/code], the forward renderer will fall back to OpenGL 3 if both Direct3D 12, Metal and Vulkan are not supported. + [b]Note:[/b] This setting is implemented only on Windows, Android, macOS, iOS, and Linux/X11. + </member> <member name="rendering/rendering_device/fallback_to_vulkan" type="bool" setter="" getter="" default="true"> If [code]true[/code], the forward renderer will fall back to Vulkan if Direct3D 12 is not supported. [b]Note:[/b] This setting is implemented only on Windows. diff --git a/doc/classes/RDPipelineDepthStencilState.xml b/doc/classes/RDPipelineDepthStencilState.xml index b8245f97af..dc1e70eb55 100644 --- a/doc/classes/RDPipelineDepthStencilState.xml +++ b/doc/classes/RDPipelineDepthStencilState.xml @@ -19,7 +19,7 @@ The operation to perform on the stencil buffer for back pixels that pass the stencil test but fail the depth test. </member> <member name="back_op_fail" type="int" setter="set_back_op_fail" getter="get_back_op_fail" enum="RenderingDevice.StencilOperation" default="1"> - The operation to perform on the stencil buffer for back pixels that fail the stencil test + The operation to perform on the stencil buffer for back pixels that fail the stencil test. </member> <member name="back_op_pass" type="int" setter="set_back_op_pass" getter="get_back_op_pass" enum="RenderingDevice.StencilOperation" default="1"> The operation to perform on the stencil buffer for back pixels that pass the stencil test. diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml index ddd52c6835..2ff7e934e9 100644 --- a/doc/classes/RenderingDevice.xml +++ b/doc/classes/RenderingDevice.xml @@ -905,7 +905,7 @@ <param index="4" name="mipmaps" type="int" default="1" /> <param index="5" name="slice_type" type="int" enum="RenderingDevice.TextureSliceType" default="0" /> <description> - Creates a shared texture using the specified [param view] and the texture information from [param with_texture]'s [param layer] and [param mipmap]. The number of included mipmaps from the original texture can be controlled using the [param mipmaps] parameter. Only relevant for textures with multiple layers, such as 3D textures, texture arrays and cubemaps. For single-layer textures, use [method texture_create_shared] + Creates a shared texture using the specified [param view] and the texture information from [param with_texture]'s [param layer] and [param mipmap]. The number of included mipmaps from the original texture can be controlled using the [param mipmaps] parameter. Only relevant for textures with multiple layers, such as 3D textures, texture arrays and cubemaps. For single-layer textures, use [method texture_create_shared]. For 2D textures (which only have one layer), [param layer] must be [code]0[/code]. [b]Note:[/b] Layer slicing is only supported for 2D texture arrays, not 3D textures or cubemaps. </description> diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 3658dafea6..144f78349f 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -3532,7 +3532,7 @@ <method name="texture_2d_placeholder_create"> <return type="RID" /> <description> - Creates a placeholder for a 2-dimensional layered texture and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]texture_2d_layered_*[/code] RenderingServer functions, although it does nothing when used. See also [method texture_2d_layered_placeholder_create] + Creates a placeholder for a 2-dimensional layered texture and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]texture_2d_layered_*[/code] RenderingServer functions, although it does nothing when used. See also [method texture_2d_layered_placeholder_create]. Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] method. [b]Note:[/b] The equivalent resource is [PlaceholderTexture2D]. </description> @@ -5148,7 +5148,7 @@ The callback is called before our transparent rendering pass, but after our sky is rendered and we've created our back buffers. </constant> <constant name="COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_TRANSPARENT" value="4" enum="CompositorEffectCallbackType"> - The callback is called after our transparent rendering pass, but before any build in post effects and output to our render target. + The callback is called after our transparent rendering pass, but before any built-in post-processing effects and output to our render target. </constant> <constant name="COMPOSITOR_EFFECT_CALLBACK_TYPE_ANY" value="-1" enum="CompositorEffectCallbackType"> </constant> @@ -5660,7 +5660,10 @@ <constant name="GLOBAL_VAR_TYPE_SAMPLERCUBE" value="27" enum="GlobalShaderParameterType"> Cubemap sampler global shader parameter ([code]global uniform samplerCube ...[/code]). Exposed as a [Cubemap] in the editor UI. </constant> - <constant name="GLOBAL_VAR_TYPE_MAX" value="28" enum="GlobalShaderParameterType"> + <constant name="GLOBAL_VAR_TYPE_SAMPLEREXT" value="28" enum="GlobalShaderParameterType"> + External sampler global shader parameter ([code]global uniform samplerExternalOES ...[/code]). Exposed as a [ExternalTexture] in the editor UI. + </constant> + <constant name="GLOBAL_VAR_TYPE_MAX" value="29" enum="GlobalShaderParameterType"> Represents the size of the [enum GlobalShaderParameterType] enum. </constant> <constant name="RENDERING_INFO_TOTAL_OBJECTS_IN_FRAME" value="0" enum="RenderingInfo"> diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml index fe09472c14..18d4047339 100644 --- a/doc/classes/Resource.xml +++ b/doc/classes/Resource.xml @@ -20,6 +20,19 @@ Override this method to return a custom [RID] when [method get_rid] is called. </description> </method> + <method name="_reset_state" qualifiers="virtual"> + <return type="void" /> + <description> + For resources that use a variable number of properties, either via [method Object._validate_property] or [method Object._get_property_list], this method should be implemented to correctly clear the resource's state. + </description> + </method> + <method name="_set_path_cache" qualifiers="virtual const"> + <return type="void" /> + <param index="0" name="path" type="String" /> + <description> + Sets the resource's path to [param path] without involving the resource cache. + </description> + </method> <method name="_setup_local_to_scene" qualifiers="virtual"> <return type="void" /> <description> @@ -68,6 +81,14 @@ Generates a unique identifier for a resource to be contained inside a [PackedScene], based on the current date, time, and a random value. The returned string is only composed of letters ([code]a[/code] to [code]y[/code]) and numbers ([code]0[/code] to [code]8[/code]). See also [member resource_scene_unique_id]. </description> </method> + <method name="get_id_for_path" qualifiers="const"> + <return type="String" /> + <param index="0" name="path" type="String" /> + <description> + Returns the unique identifier for the resource with the given [param path] from the resource cache. If the resource is not loaded and cached, an empty string is returned. + [b]Note:[/b] This method is only implemented when running in an editor context. At runtime, it returns an empty string. + </description> + </method> <method name="get_local_scene" qualifiers="const"> <return type="Node" /> <description> @@ -80,6 +101,34 @@ Returns the [RID] of this resource (or an empty RID). Many resources (such as [Texture2D], [Mesh], and so on) are high-level abstractions of resources stored in a specialized server ([DisplayServer], [RenderingServer], etc.), so this function will return the original [RID]. </description> </method> + <method name="is_built_in" qualifiers="const"> + <return type="bool" /> + <description> + Returns [code]true[/code] if the resource is built-in (from the engine) or [code]false[/code] if it is user-defined. + </description> + </method> + <method name="reset_state"> + <return type="void" /> + <description> + For resources that use a variable number of properties, either via [method Object._validate_property] or [method Object._get_property_list], override [method _reset_state] to correctly clear the resource's state. + </description> + </method> + <method name="set_id_for_path"> + <return type="void" /> + <param index="0" name="path" type="String" /> + <param index="1" name="id" type="String" /> + <description> + Sets the unique identifier to [param id] for the resource with the given [param path] in the resource cache. If the unique identifier is empty, the cache entry using [param path] is removed if it exists. + [b]Note:[/b] This method is only implemented when running in an editor context. + </description> + </method> + <method name="set_path_cache"> + <return type="void" /> + <param index="0" name="path" type="String" /> + <description> + Sets the resource's path to [param path] without involving the resource cache. + </description> + </method> <method name="setup_local_to_scene" deprecated="This method should only be called internally."> <return type="void" /> <description> diff --git a/doc/classes/ResourceSaver.xml b/doc/classes/ResourceSaver.xml index 42c9bd7a3c..05c749bc24 100644 --- a/doc/classes/ResourceSaver.xml +++ b/doc/classes/ResourceSaver.xml @@ -26,6 +26,14 @@ Returns the list of extensions available for saving a resource of a given type. </description> </method> + <method name="get_resource_id_for_path"> + <return type="int" /> + <param index="0" name="path" type="String" /> + <param index="1" name="generate" type="bool" default="false" /> + <description> + Returns the resource ID for the given path. If [param generate] is [code]true[/code], a new resource ID will be generated if one for the path is not found. If [param generate] is [code]false[/code] and the path is not found, [constant ResourceUID.INVALID_ID] is returned. + </description> + </method> <method name="remove_resource_format_saver"> <return type="void" /> <param index="0" name="format_saver" type="ResourceFormatSaver" /> diff --git a/doc/classes/ScrollContainer.xml b/doc/classes/ScrollContainer.xml index 2181194fd4..405bba3564 100644 --- a/doc/classes/ScrollContainer.xml +++ b/doc/classes/ScrollContainer.xml @@ -102,6 +102,9 @@ <constant name="SCROLL_MODE_SHOW_NEVER" value="3" enum="ScrollMode"> Scrolling enabled, scrollbar will be hidden. </constant> + <constant name="SCROLL_MODE_RESERVE" value="4" enum="ScrollMode"> + Combines [constant SCROLL_MODE_AUTO] and [constant SCROLL_MODE_SHOW_ALWAYS]. The scrollbar is only visible if necessary, but the content size is adjusted as if it was always visible. It's useful for ensuring that content size stays the same regardless if the scrollbar is visible. + </constant> </constants> <theme_items> <theme_item name="panel" data_type="style" type="StyleBox"> diff --git a/doc/classes/Signal.xml b/doc/classes/Signal.xml index 7d6ff1e9b0..65168d6980 100644 --- a/doc/classes/Signal.xml +++ b/doc/classes/Signal.xml @@ -109,6 +109,12 @@ Returns the ID of the object emitting this signal (see [method Object.get_instance_id]). </description> </method> + <method name="has_connections" qualifiers="const"> + <return type="bool" /> + <description> + Returns [code]true[/code] if any [Callable] is connected to this signal. + </description> + </method> <method name="is_connected" qualifiers="const"> <return type="bool" /> <param index="0" name="callable" type="Callable" /> diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml index a8bd068b1c..9c1525d8f8 100644 --- a/doc/classes/SurfaceTool.xml +++ b/doc/classes/SurfaceTool.xml @@ -241,7 +241,7 @@ <param index="0" name="count" type="int" enum="SurfaceTool.SkinWeightCount" /> <description> Set to [constant SKIN_8_WEIGHTS] to indicate that up to 8 bone influences per vertex may be used. - By default, only 4 bone influences are used ([constant SKIN_4_WEIGHTS]) + By default, only 4 bone influences are used ([constant SKIN_4_WEIGHTS]). [b]Note:[/b] This function takes an enum, not the exact number of weights. </description> </method> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 9fada9db35..42558bf992 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -1299,6 +1299,9 @@ <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true" keywords="readonly, disabled, enabled"> If [code]false[/code], existing text cannot be modified and new text cannot be added. </member> + <member name="empty_selection_clipboard_enabled" type="bool" setter="set_empty_selection_clipboard_enabled" getter="is_empty_selection_clipboard_enabled" default="true"> + If [code]true[/code], copying or cutting without a selection is performed on all lines with a caret. Otherwise, copy and cut require a selection. + </member> <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" /> <member name="highlight_all_occurrences" type="bool" setter="set_highlight_all_occurrences" getter="is_highlight_all_occurrences_enabled" default="false"> If [code]true[/code], all occurrences of the selected text will be highlighted. diff --git a/doc/classes/TranslationDomain.xml b/doc/classes/TranslationDomain.xml new file mode 100644 index 0000000000..da6f2704bf --- /dev/null +++ b/doc/classes/TranslationDomain.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="TranslationDomain" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + A self-contained collection of [Translation] resources. + </brief_description> + <description> + [TranslationDomain] is a self-contained collection of [Translation] resources. Translations can be added to or removed from it. + If you're working with the main translation domain, it is more convenient to use the wrap methods on [TranslationServer]. + </description> + <tutorials> + </tutorials> + <methods> + <method name="add_translation"> + <return type="void" /> + <param index="0" name="translation" type="Translation" /> + <description> + Adds a translation. + </description> + </method> + <method name="clear"> + <return type="void" /> + <description> + Removes all translations. + </description> + </method> + <method name="get_translation_object" qualifiers="const"> + <return type="Translation" /> + <param index="0" name="locale" type="String" /> + <description> + Returns the [Translation] instance that best matches [param locale]. Returns [code]null[/code] if there are no matches. + </description> + </method> + <method name="remove_translation"> + <return type="void" /> + <param index="0" name="translation" type="Translation" /> + <description> + Removes the given translation. + </description> + </method> + <method name="translate" qualifiers="const"> + <return type="StringName" /> + <param index="0" name="message" type="StringName" /> + <param index="1" name="context" type="StringName" default="&""" /> + <description> + Returns the current locale's translation for the given message and context. + </description> + </method> + <method name="translate_plural" qualifiers="const"> + <return type="StringName" /> + <param index="0" name="message" type="StringName" /> + <param index="1" name="message_plural" type="StringName" /> + <param index="2" name="n" type="int" /> + <param index="3" name="context" type="StringName" default="&""" /> + <description> + Returns the current locale's translation for the given message, plural message and context. + The number [param n] is the number or quantity of the plural object. It will be used to guide the translation system to fetch the correct plural form for the selected language. + </description> + </method> + </methods> +</class> diff --git a/doc/classes/TranslationServer.xml b/doc/classes/TranslationServer.xml index db1a65278c..0a4965c36c 100644 --- a/doc/classes/TranslationServer.xml +++ b/doc/classes/TranslationServer.xml @@ -4,7 +4,8 @@ The server responsible for language translations. </brief_description> <description> - The server that manages all language translations. Translations can be added to or removed from it. + The translation server is the API backend that manages all language translations. + Translations are stored in [TranslationDomain]s, which can be accessed by name. The most commonly used translation domain is the main translation domain. It always exists and can be accessed using an empty [StringName]. The translation server provides wrapper methods for accessing the main translation domain directly, without having to fetch the translation domain first. Custom translation domains are mainly for advanced usages like editor plugins. Names starting with [code]godot.[/code] are reserved for engine internals. </description> <tutorials> <link title="Internationalizing games">$DOCS_URL/tutorials/i18n/internationalizing_games.html</link> @@ -15,13 +16,13 @@ <return type="void" /> <param index="0" name="translation" type="Translation" /> <description> - Adds a [Translation] resource. + Adds a translation to the main translation domain. </description> </method> <method name="clear"> <return type="void" /> <description> - Clears the server from all translations. + Removes all translations from the main translation domain. </description> </method> <method name="compare_locales" qualifiers="const"> @@ -84,6 +85,13 @@ Returns a locale's language and its variant (e.g. [code]"en_US"[/code] would return [code]"English (United States)"[/code]). </description> </method> + <method name="get_or_add_domain"> + <return type="TranslationDomain" /> + <param index="0" name="domain" type="StringName" /> + <description> + Returns the translation domain with the specified name. An empty translation domain will be created and added if it does not exist. + </description> + </method> <method name="get_script_name" qualifiers="const"> <return type="String" /> <param index="0" name="script" type="String" /> @@ -102,8 +110,14 @@ <return type="Translation" /> <param index="0" name="locale" type="String" /> <description> - Returns the [Translation] instance based on the [param locale] passed in. - It will return [code]null[/code] if there is no [Translation] instance that matches the [param locale]. + Returns the [Translation] instance that best matches [param locale] in the main translation domain. Returns [code]null[/code] if there are no matches. + </description> + </method> + <method name="has_domain" qualifiers="const"> + <return type="bool" /> + <param index="0" name="domain" type="StringName" /> + <description> + Returns [code]true[/code] if a translation domain with the specified name exists. </description> </method> <method name="pseudolocalize" qualifiers="const"> @@ -119,11 +133,19 @@ Reparses the pseudolocalization options and reloads the translation. </description> </method> + <method name="remove_domain"> + <return type="void" /> + <param index="0" name="domain" type="StringName" /> + <description> + Removes the translation domain with the specified name. + [b]Note:[/b] Trying to remove the main translation domain is an error. + </description> + </method> <method name="remove_translation"> <return type="void" /> <param index="0" name="translation" type="Translation" /> <description> - Removes the given translation from the server. + Removes the given translation from the main translation domain. </description> </method> <method name="set_locale"> @@ -146,7 +168,8 @@ <param index="0" name="message" type="StringName" /> <param index="1" name="context" type="StringName" default="&""" /> <description> - Returns the current locale's translation for the given message (key) and context. + Returns the current locale's translation for the given message and context. + [b]Note:[/b] This method always uses the main translation domain. </description> </method> <method name="translate_plural" qualifiers="const"> @@ -156,8 +179,9 @@ <param index="2" name="n" type="int" /> <param index="3" name="context" type="StringName" default="&""" /> <description> - Returns the current locale's translation for the given message (key), plural message and context. + Returns the current locale's translation for the given message, plural message and context. The number [param n] is the number or quantity of the plural object. It will be used to guide the translation system to fetch the correct plural form for the selected language. + [b]Note:[/b] This method always uses the main translation domain. </description> </method> </methods> diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 85663e10b2..95a1d0f77e 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -33,6 +33,18 @@ Returns the first valid [World3D] for this viewport, searching the [member world_3d] property of itself and any Viewport ancestor. </description> </method> + <method name="get_audio_listener_2d" qualifiers="const"> + <return type="AudioListener2D" /> + <description> + Returns the currently active 2D audio listener. Returns [code]null[/code] if there are no active 2D audio listeners, in which case the active 2D camera will be treated as listener. + </description> + </method> + <method name="get_audio_listener_3d" qualifiers="const"> + <return type="AudioListener3D" /> + <description> + Returns the currently active 3D audio listener. Returns [code]null[/code] if there are no active 3D audio listeners, in which case the active 3D camera will be treated as listener. + </description> + </method> <method name="get_camera_2d" qualifiers="const"> <return type="Camera2D" /> <description> diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py index 101660881b..e1a6aa4a98 100755 --- a/doc/tools/make_rst.py +++ b/doc/tools/make_rst.py @@ -150,7 +150,7 @@ PACKED_ARRAY_TYPES: List[str] = [ "PackedByteArray", "PackedColorArray", "PackedFloat32Array", - "Packedfloat64Array", + "PackedFloat64Array", "PackedInt32Array", "PackedInt64Array", "PackedStringArray", @@ -949,13 +949,17 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: inherits = class_def.inherits.strip() f.write(f'**{translate("Inherits:")}** ') first = True - while inherits in state.classes: + while inherits is not None: if not first: f.write(" **<** ") else: first = False f.write(make_type(inherits, state)) + + if inherits not in state.classes: + break # Parent unknown. + inode = state.classes[inherits].inherits if inode: inherits = inode.strip() diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 5a0f394db0..b73debf04a 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -189,6 +189,14 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant } builder.append("\n"); //make sure defines begin at newline + // Optional support for external textures. + if (GLES3::Config::get_singleton()->external_texture_supported) { + builder.append("#extension GL_OES_EGL_image_external : enable\n"); + builder.append("#extension GL_OES_EGL_image_external_essl3 : enable\n"); + } else { + builder.append("#define samplerExternalOES sampler2D\n"); + } + // Insert multiview extension loading, because it needs to appear before // any non-preprocessor code (like the "precision highp..." lines below). builder.append("#ifdef USE_MULTIVIEW\n"); diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index e358230747..76881c8032 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -262,6 +262,8 @@ void main() { color_interp = color; + vertex = (canvas_transform * vec4(vertex, 0.0, 1.0)).xy; + if (use_pixel_snap) { vertex = floor(vertex + 0.5); // precision issue on some hardware creates artifacts within texture @@ -269,8 +271,6 @@ void main() { uv += 1e-5; } - vertex = (canvas_transform * vec4(vertex, 0.0, 1.0)).xy; - vertex_interp = vertex; uv_interp = uv; diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl index f734e4b355..186b630bc8 100644 --- a/drivers/gles3/shaders/sky.glsl +++ b/drivers/gles3/shaders/sky.glsl @@ -212,9 +212,7 @@ void main() { #endif { - #CODE : SKY - } color *= sky_energy_multiplier; diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index d6472c44c1..4947d5d4ce 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -138,6 +138,7 @@ Config::Config() { // These are GLES only rt_msaa_supported = extensions.has("GL_EXT_multisampled_render_to_texture"); rt_msaa_multiview_supported = extensions.has("GL_OVR_multiview_multisampled_render_to_texture"); + external_texture_supported = extensions.has("GL_OES_EGL_image_external_essl3"); if (multiview_supported) { eglFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)eglGetProcAddress("glFramebufferTextureMultiviewOVR"); @@ -166,6 +167,13 @@ Config::Config() { rt_msaa_multiview_supported = false; } } + + if (external_texture_supported) { + eglEGLImageTargetTexture2DOES = (PFNEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES"); + if (eglEGLImageTargetTexture2DOES == nullptr) { + external_texture_supported = false; + } + } #endif force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h index ff72fc5b58..1de00094f0 100644 --- a/drivers/gles3/storage/config.h +++ b/drivers/gles3/storage/config.h @@ -45,6 +45,7 @@ typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, typedef void (*PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei, GLboolean); typedef void (*PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei); typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLsizei, GLint, GLsizei); +typedef void (*PFNEGLIMAGETARGETTEXTURE2DOESPROC)(GLenum, void *); #endif namespace GLES3 { @@ -91,6 +92,7 @@ public: bool rt_msaa_supported = false; bool rt_msaa_multiview_supported = false; bool multiview_supported = false; + bool external_texture_supported = false; // Adreno 3XX compatibility bool disable_particles_workaround = false; // set to 'true' to disable 'GPUParticles' @@ -104,6 +106,7 @@ public: PFNGLTEXSTORAGE3DMULTISAMPLEPROC eglTexStorage3DMultisample = nullptr; PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC eglFramebufferTexture2DMultisampleEXT = nullptr; PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC eglFramebufferTextureMultisampleMultiviewOVR = nullptr; + PFNEGLIMAGETARGETTEXTURE2DOESPROC eglEGLImageTargetTexture2DOES = nullptr; #endif static Config *get_singleton() { return singleton; }; diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index 7d5af48384..c29c741c2a 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -675,6 +675,7 @@ static const GLenum target_from_type[ShaderLanguage::TYPE_MAX] = { GL_TEXTURE_3D, // TYPE_USAMPLER3D, GL_TEXTURE_CUBE_MAP, // TYPE_SAMPLERCUBE, GL_TEXTURE_CUBE_MAP, // TYPE_SAMPLERCUBEARRAY, + _GL_TEXTURE_EXTERNAL_OES, // TYPE_SAMPLEREXT GL_TEXTURE_2D, // TYPE_STRUCT }; @@ -946,6 +947,9 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: { ERR_PRINT_ONCE("Type: SamplerCubeArray not supported in GL Compatibility rendering backend, please use another type."); } break; + case ShaderLanguage::TYPE_SAMPLEREXT: { + gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_EXT); + } break; case ShaderLanguage::TYPE_ISAMPLER3D: case ShaderLanguage::TYPE_USAMPLER3D: @@ -1949,6 +1953,7 @@ void MaterialStorage::global_shader_parameters_load_settings(bool p_load_texture "sampler2DArray", "sampler3D", "samplerCube", + "samplerExternalOES" }; RS::GlobalShaderParameterType gvtype = RS::GLOBAL_VAR_TYPE_MAX; @@ -2661,7 +2666,11 @@ static void bind_uniforms_generic(const Vector<RID> &p_textures, const Vector<Sh const ShaderCompiler::GeneratedCode::Texture &texture_uniform = texture_uniforms[texture_uniform_index]; if (texture) { glActiveTexture(GL_TEXTURE0 + texture_offset + ti); - glBindTexture(target_from_type[texture_uniform.type], texture->tex_id); + GLenum target = target_from_type[texture_uniform.type]; + if (target == _GL_TEXTURE_EXTERNAL_OES && !GLES3::Config::get_singleton()->external_texture_supported) { + target = GL_TEXTURE_2D; + } + glBindTexture(target, texture->tex_id); if (texture->render_target) { texture->render_target->used_in_frame = true; } diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h index a7a676ad33..9a2912f978 100644 --- a/drivers/gles3/storage/render_scene_buffers_gles3.h +++ b/drivers/gles3/storage/render_scene_buffers_gles3.h @@ -103,9 +103,9 @@ public: virtual void configure(const RenderSceneBuffersConfiguration *p_config) override; void configure_for_probe(Size2i p_size); - virtual void set_fsr_sharpness(float p_fsr_sharpness) override{}; - virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override{}; - virtual void set_use_debanding(bool p_use_debanding) override{}; + virtual void set_fsr_sharpness(float p_fsr_sharpness) override {} + virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override {} + virtual void set_use_debanding(bool p_use_debanding) override {} void set_apply_color_adjustments_in_post(bool p_apply_in_post); void free_render_buffer_data(); diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index bd824a076e..27ba89aa5f 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -153,6 +153,11 @@ TextureStorage::TextureStorage() { } { + default_gl_textures[DEFAULT_GL_TEXTURE_EXT] = texture_allocate(); + texture_external_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_EXT], 1, 1, 0); + } + + { unsigned char pixel_data[4 * 4 * 4]; for (int i = 0; i < 16; i++) { pixel_data[i * 4 + 0] = 0; @@ -769,6 +774,48 @@ void TextureStorage::texture_2d_initialize(RID p_texture, const Ref<Image> &p_im texture_set_data(p_texture, p_image); } +void TextureStorage::texture_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) { + Texture texture; + texture.active = true; + texture.alloc_width = texture.width = p_width; + texture.alloc_height = texture.height = p_height; + texture.real_format = texture.format = Image::FORMAT_RGB8; + texture.type = Texture::TYPE_2D; + + if (GLES3::Config::get_singleton()->external_texture_supported) { + texture.target = _GL_TEXTURE_EXTERNAL_OES; + } else { + texture.target = GL_TEXTURE_2D; + } + + glGenTextures(1, &texture.tex_id); + glBindTexture(texture.target, texture.tex_id); + +#ifdef ANDROID_ENABLED + if (texture.target == _GL_TEXTURE_EXTERNAL_OES) { + if (p_external_buffer) { + GLES3::Config::get_singleton()->eglEGLImageTargetTexture2DOES(_GL_TEXTURE_EXTERNAL_OES, reinterpret_cast<void *>(p_external_buffer)); + } + texture.total_data_size = 0; + } else +#endif + { + // If external textures aren't supported, allocate an empty 1x1 texture. + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); + texture.total_data_size = 3; + } + + glTexParameteri(texture.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(texture.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(texture.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(texture.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + GLES3::Utilities::get_singleton()->texture_allocated_data(texture.tex_id, texture.total_data_size, "Texture External"); + texture_owner.initialize_rid(p_texture, texture); + + glBindTexture(texture.target, 0); +} + void TextureStorage::texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) { ERR_FAIL_COND(p_layers.is_empty()); @@ -930,6 +977,22 @@ void TextureStorage::texture_3d_update(RID p_texture, const Vector<Ref<Image>> & GLES3::Utilities::get_singleton()->texture_resize_data(tex->tex_id, tex->total_data_size); } +void TextureStorage::texture_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) { + Texture *tex = texture_owner.get_or_null(p_texture); + ERR_FAIL_NULL(tex); + + tex->alloc_width = tex->width = p_width; + tex->alloc_height = tex->height = p_height; + +#ifdef ANDROID_ENABLED + if (tex->target == _GL_TEXTURE_EXTERNAL_OES && p_external_buffer) { + glBindTexture(_GL_TEXTURE_EXTERNAL_OES, tex->tex_id); + GLES3::Config::get_singleton()->eglEGLImageTargetTexture2DOES(_GL_TEXTURE_EXTERNAL_OES, reinterpret_cast<void *>(p_external_buffer)); + glBindTexture(_GL_TEXTURE_EXTERNAL_OES, 0); + } +#endif +} + void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) { Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_NULL(tex); diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index 26864c2f3b..2bf8546c0f 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -126,6 +126,7 @@ enum DefaultGLTexture { DEFAULT_GL_TEXTURE_3D_BLACK, DEFAULT_GL_TEXTURE_2D_ARRAY_WHITE, DEFAULT_GL_TEXTURE_2D_UINT, + DEFAULT_GL_TEXTURE_EXT, DEFAULT_GL_TEXTURE_MAX }; @@ -512,12 +513,14 @@ public: virtual void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) override; virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override; virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override; + virtual void texture_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override; virtual void texture_proxy_initialize(RID p_texture, RID p_base) override; //all slices, then all the mipmaps, must be coherent virtual RID texture_create_from_native_handle(RS::TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers = 1, RS::TextureLayeredType p_layered_type = RS::TEXTURE_LAYERED_2D_ARRAY) override; virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override; virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override; + virtual void texture_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override; virtual void texture_proxy_update(RID p_proxy, RID p_base) override; //these two APIs can be used together or in combination with the others. @@ -582,7 +585,7 @@ public: virtual RID decal_allocate() override; virtual void decal_initialize(RID p_rid) override; - virtual void decal_free(RID p_rid) override{}; + virtual void decal_free(RID p_rid) override {} virtual void decal_set_size(RID p_decal, const Vector3 &p_size) override; virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) override; diff --git a/drivers/metal/metal_objects.h b/drivers/metal/metal_objects.h index 97f33bb1e8..030b353ee8 100644 --- a/drivers/metal/metal_objects.h +++ b/drivers/metal/metal_objects.h @@ -318,6 +318,13 @@ public: dirty.set_flag(DirtyFlag::DIRTY_UNIFORMS); } + _FORCE_INLINE_ void mark_blend_dirty() { + if (!blend_constants.has_value()) { + return; + } + dirty.set_flag(DirtyFlag::DIRTY_BLEND); + } + MTLScissorRect clip_to_render_area(MTLScissorRect p_rect) const { uint32_t raLeft = render_area.position.x; uint32_t raRight = raLeft + render_area.size.width; diff --git a/drivers/metal/metal_objects.mm b/drivers/metal/metal_objects.mm index d3c3d2b232..1d08a10781 100644 --- a/drivers/metal/metal_objects.mm +++ b/drivers/metal/metal_objects.mm @@ -143,6 +143,9 @@ void MDCommandBuffer::bind_pipeline(RDD::PipelineID p_pipeline) { if (render.pipeline != nullptr && render.pipeline->depth_stencil != rp->depth_stencil) { render.dirty.set_flag(RenderState::DIRTY_DEPTH); } + if (rp->raster_state.blend.enabled) { + render.dirty.set_flag(RenderState::DIRTY_BLEND); + } render.pipeline = rp; } } else if (p->type == MDPipelineType::Compute) { @@ -301,6 +304,7 @@ void MDCommandBuffer::render_clear_attachments(VectorView<RDD::AttachmentClear> render.mark_viewport_dirty(); render.mark_scissors_dirty(); render.mark_vertex_dirty(); + render.mark_blend_dirty(); } void MDCommandBuffer::_render_set_dirty_state() { diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 59783c58b5..40b58d2c62 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -820,7 +820,7 @@ FindReplaceBar::FindReplaceBar() { /*** CODE EDITOR ****/ -static constexpr float ZOOM_FACTOR_PRESETS[7] = { 0.25f, 0.5f, 0.75f, 1.0f, 1.5f, 2.0f, 3.0f }; +static constexpr float ZOOM_FACTOR_PRESETS[8] = { 0.5f, 0.75f, 0.9f, 1.0f, 1.1f, 1.25f, 1.5f, 2.0f }; // This function should be used to handle shortcuts that could otherwise // be handled too late if they weren't handled here. @@ -1090,6 +1090,9 @@ void CodeTextEditor::update_editor_settings() { text_editor->set_draw_spaces(EDITOR_GET("text_editor/appearance/whitespace/draw_spaces")); text_editor->add_theme_constant_override("line_spacing", EDITOR_GET("text_editor/appearance/whitespace/line_spacing")); + // Behavior: General + text_editor->set_empty_selection_clipboard_enabled(EDITOR_GET("text_editor/behavior/general/empty_selection_clipboard")); + // Behavior: Navigation text_editor->set_scroll_past_end_of_file_enabled(EDITOR_GET("text_editor/behavior/navigation/scroll_past_end_of_file")); text_editor->set_smooth_scroll_enabled(EDITOR_GET("text_editor/behavior/navigation/smooth_scrolling")); @@ -1716,8 +1719,7 @@ void CodeTextEditor::_zoom_to(float p_zoom_factor) { } void CodeTextEditor::set_zoom_factor(float p_zoom_factor) { - int preset_count = sizeof(ZOOM_FACTOR_PRESETS) / sizeof(float); - zoom_factor = CLAMP(p_zoom_factor, ZOOM_FACTOR_PRESETS[0], ZOOM_FACTOR_PRESETS[preset_count - 1]); + zoom_factor = CLAMP(p_zoom_factor, 0.25f, 3.0f); int neutral_font_size = int(EDITOR_GET("interface/editor/code_font_size")) * EDSCALE; int new_font_size = Math::round(zoom_factor * neutral_font_size); @@ -1843,7 +1845,8 @@ CodeTextEditor::CodeTextEditor() { status_bar->add_child(zoom_button); zoom_button->set_flat(true); zoom_button->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); - zoom_button->set_tooltip_text(TTR("Zoom factor")); + zoom_button->set_tooltip_text( + TTR("Zoom factor") + "\n" + vformat(TTR("%sMouse wheel, %s/%s: Finetune\n%s: Reset"), keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL), ED_GET_SHORTCUT("script_editor/zoom_in")->get_as_text(), ED_GET_SHORTCUT("script_editor/zoom_out")->get_as_text(), ED_GET_SHORTCUT("script_editor/reset_zoom")->get_as_text())); zoom_button->set_text("100 %"); PopupMenu *zoom_menu = zoom_button->get_popup(); diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 0eabe53360..1613d1d62f 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -88,14 +88,9 @@ void EditorAutoloadSettings::_notification(int p_what) { } bool EditorAutoloadSettings::_autoload_name_is_valid(const String &p_name, String *r_error) { - if (!p_name.is_valid_ascii_identifier()) { + if (!p_name.is_valid_unicode_identifier()) { if (r_error) { - *r_error = TTR("Invalid name.") + " "; - if (p_name.size() > 0 && p_name.left(1).is_numeric()) { - *r_error += TTR("Cannot begin with a digit."); - } else { - *r_error += TTR("Valid characters:") + " a-z, A-Z, 0-9 or _"; - } + *r_error = TTR("Invalid name.") + " " + TTR("Must be a valid Unicode identifier."); } return false; diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index adae6599c1..2b51071b15 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1974,18 +1974,16 @@ void EditorFileSystem::_update_script_documentation() { for (int i = 0; i < ScriptServer::get_language_count(); i++) { ScriptLanguage *lang = ScriptServer::get_language(i); if (lang->supports_documentation() && efd->files[index]->type == lang->get_type()) { - // Reloading the script from disk if resource already in memory. Otherwise, the - // ResourceLoader::load will return the last loaded version of the script (without the modifications). - // The only have the script already loaded here is to edit the script outside the - // editor without being connected to the LSP server. - Ref<Resource> res = ResourceCache::get_ref(path); - if (res.is_valid()) { - res->reload_from_file(); - } + bool should_reload_script = _should_reload_script(path); Ref<Script> scr = ResourceLoader::load(path); if (scr.is_null()) { continue; } + if (should_reload_script) { + // Reloading the script from disk. Otherwise, the ResourceLoader::load will + // return the last loaded version of the script (without the modifications). + scr->reload_from_file(); + } Vector<DocData::ClassDoc> docs = scr->get_documentation(); for (int j = 0; j < docs.size(); j++) { EditorHelp::get_doc_data()->add_doc(docs[j]); @@ -2007,6 +2005,25 @@ void EditorFileSystem::_update_script_documentation() { update_script_paths_documentation.clear(); } +bool EditorFileSystem::_should_reload_script(const String &p_path) { + if (first_scan) { + return false; + } + + Ref<Script> scr = ResourceCache::get_ref(p_path); + if (scr.is_null()) { + // Not a script or not already loaded. + return false; + } + + // Scripts are reloaded via the script editor if they are currently opened. + if (ScriptEditor::get_singleton()->get_open_scripts().has(scr)) { + return false; + } + + return true; +} + void EditorFileSystem::_process_update_pending() { _update_script_classes(); // Parse documentation second, as it requires the class names to be loaded diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index e02127cb13..e53187c1d7 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -295,6 +295,7 @@ class EditorFileSystem : public Node { void _update_script_documentation(); void _process_update_pending(); void _process_removed_files(const HashSet<String> &p_processed_files); + bool _should_reload_script(const String &p_path); Mutex update_scene_mutex; HashSet<String> update_scene_paths; diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index 47ff21bc82..47f16f219f 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -530,7 +530,7 @@ bool EditorHelpSearch::Runner::_phase_fill_member_items_init() { return true; } -TreeItem *EditorHelpSearch::Runner::_create_category_item(TreeItem *p_parent, const String &p_class, const StringName &p_icon, const String &p_metatype, const String &p_text) { +TreeItem *EditorHelpSearch::Runner::_create_category_item(TreeItem *p_parent, const String &p_class, const StringName &p_icon, const String &p_text, const String &p_metatype) { const String item_meta = "class_" + p_metatype + ":" + p_class; TreeItem *item = nullptr; @@ -620,7 +620,7 @@ bool EditorHelpSearch::Runner::_phase_fill_member_items() { if ((search_flags & SEARCH_PROPERTIES) && !class_doc->properties.is_empty()) { TreeItem *parent_item = item; if (search_all) { - parent_item = _create_category_item(parent_item, class_doc->name, SNAME("MemberProperty"), TTRC("Prtoperties"), "propertiess"); + parent_item = _create_category_item(parent_item, class_doc->name, SNAME("MemberProperty"), TTRC("Properties"), "properties"); } for (const DocData::PropertyDoc &property_doc : class_doc->properties) { _create_property_item(parent_item, class_doc, &property_doc); diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h index b8b3c26b41..f4d0c6c89e 100644 --- a/editor/editor_help_search.h +++ b/editor/editor_help_search.h @@ -198,7 +198,7 @@ class EditorHelpSearch::Runner : public RefCounted { TreeItem *_create_class_hierarchy(const ClassMatch &p_match); TreeItem *_create_class_hierarchy(const DocData::ClassDoc *p_class_doc, const String &p_matching_keyword, bool p_gray); TreeItem *_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray, const String &p_matching_keyword); - TreeItem *_create_category_item(TreeItem *p_parent, const String &p_class, const StringName &p_icon, const String &p_metatype, const String &p_type); + TreeItem *_create_category_item(TreeItem *p_parent, const String &p_class, const StringName &p_icon, const String &p_text, const String &p_metatype); TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match); TreeItem *_create_constructor_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match); TreeItem *_create_operator_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 0eb566f9be..184176391a 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -926,11 +926,7 @@ void EditorNode::_resources_changed(const Vector<String> &p_resources) { } if (!res->editor_can_reload_from_file()) { - Ref<Script> scr = res; - // Scripts are reloaded via the script editor. - if (scr.is_null() || ScriptEditor::get_singleton()->get_open_scripts().has(scr)) { - continue; - } + continue; } if (!res->get_path().is_resource_file() && !res->get_path().is_absolute_path()) { continue; @@ -4956,8 +4952,10 @@ String EditorNode::_get_system_info() const { godot_version += " " + hash; } + String display_session_type; #ifdef LINUXBSD_ENABLED - const String display_server = OS::get_singleton()->get_environment("XDG_SESSION_TYPE").capitalize().replace(" ", ""); // `replace` is necessary, because `capitalize` introduces a whitespace between "x" and "11". + // `replace` is necessary, because `capitalize` introduces a whitespace between "x" and "11". + display_session_type = OS::get_singleton()->get_environment("XDG_SESSION_TYPE").capitalize().replace(" ", ""); #endif // LINUXBSD_ENABLED String driver_name = OS::get_singleton()->get_current_rendering_driver_name().to_lower(); String rendering_method = OS::get_singleton()->get_current_rendering_method().to_lower(); @@ -5018,16 +5016,33 @@ String EditorNode::_get_system_info() const { // Join info. Vector<String> info; info.push_back(godot_version); + String distribution_display_session_type = distribution_name; if (!distribution_version.is_empty()) { - info.push_back(distribution_name + " " + distribution_version); - } else { - info.push_back(distribution_name); + distribution_display_session_type += " " + distribution_version; } -#ifdef LINUXBSD_ENABLED - if (!display_server.is_empty()) { - info.push_back(display_server); + if (!display_session_type.is_empty()) { + distribution_display_session_type += " on " + display_session_type; } + info.push_back(distribution_display_session_type); + + String display_driver_window_mode; +#ifdef LINUXBSD_ENABLED + // `replace` is necessary, because `capitalize` introduces a whitespace between "x" and "11". + display_driver_window_mode = DisplayServer::get_singleton()->get_name().capitalize().replace(" ", "") + " display driver"; #endif // LINUXBSD_ENABLED + if (!display_driver_window_mode.is_empty()) { + display_driver_window_mode += ", "; + } + display_driver_window_mode += get_viewport()->is_embedding_subwindows() ? "Single-window" : "Multi-window"; + + if (DisplayServer::get_singleton()->get_screen_count() == 1) { + display_driver_window_mode += ", " + itos(DisplayServer::get_singleton()->get_screen_count()) + " monitor"; + } else { + display_driver_window_mode += ", " + itos(DisplayServer::get_singleton()->get_screen_count()) + " monitors"; + } + + info.push_back(display_driver_window_mode); + info.push_back(vformat("%s (%s)", driver_name, rendering_method)); String graphics; @@ -5046,7 +5061,7 @@ String EditorNode::_get_system_info() const { } info.push_back(graphics); - info.push_back(vformat("%s (%d Threads)", processor_name, processor_count)); + info.push_back(vformat("%s (%d threads)", processor_name, processor_count)); return String(" - ").join(info); } @@ -6677,6 +6692,8 @@ EditorNode::EditorNode() { DEV_ASSERT(!singleton); singleton = this; + set_translation_domain("godot.editor"); + Resource::_get_local_scene_func = _resource_get_edited_scene; { diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h index 2870f9a201..57b6e4cedb 100644 --- a/editor/editor_resource_preview.h +++ b/editor/editor_resource_preview.h @@ -65,7 +65,7 @@ public: virtual bool handles(const String &p_type) const; virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size, Dictionary &p_metadata) const; virtual Ref<Texture2D> generate_from_path(const String &p_path, const Size2 &p_size, Dictionary &p_metadata) const; - virtual void abort(){}; + virtual void abort() {} virtual bool generate_small_preview_automatically() const; virtual bool can_generate_small_preview() const; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 312140da67..c972a6ab27 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -668,6 +668,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/appearance/whitespace/line_spacing", 4, "0,50,1") // Behavior + // Behavior: General + _initial_set("text_editor/behavior/general/empty_selection_clipboard", true); + // Behavior: Navigation _initial_set("text_editor/behavior/navigation/move_caret_on_right_click", true, true); _initial_set("text_editor/behavior/navigation/scroll_past_end_of_file", false, true); @@ -1226,6 +1229,8 @@ fail: void EditorSettings::setup_language() { String lang = get("interface/editor/editor_language"); + TranslationServer::get_singleton()->set_locale(lang); + if (lang == "en") { return; // Default, nothing to do. } diff --git a/editor/editor_translation.cpp b/editor/editor_translation.cpp index 4654d41082..6ccde3b696 100644 --- a/editor/editor_translation.cpp +++ b/editor/editor_translation.cpp @@ -54,6 +54,8 @@ Vector<String> get_editor_locales() { } void load_editor_translations(const String &p_locale) { + const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain("godot.editor"); + EditorTranslationList *etl = _editor_translations; while (etl->data) { if (etl->lang == p_locale) { @@ -70,7 +72,7 @@ void load_editor_translations(const String &p_locale) { if (tr.is_valid()) { tr->set_locale(etl->lang); - TranslationServer::get_singleton()->set_tool_translation(tr); + domain->add_translation(tr); break; } } @@ -80,6 +82,8 @@ void load_editor_translations(const String &p_locale) { } void load_property_translations(const String &p_locale) { + const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain("godot.properties"); + PropertyTranslationList *etl = _property_translations; while (etl->data) { if (etl->lang == p_locale) { @@ -96,7 +100,7 @@ void load_property_translations(const String &p_locale) { if (tr.is_valid()) { tr->set_locale(etl->lang); - TranslationServer::get_singleton()->set_property_translation(tr); + domain->add_translation(tr); break; } } @@ -106,6 +110,8 @@ void load_property_translations(const String &p_locale) { } void load_doc_translations(const String &p_locale) { + const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain("godot.documentation"); + DocTranslationList *dtl = _doc_translations; while (dtl->data) { if (dtl->lang == p_locale) { @@ -122,7 +128,7 @@ void load_doc_translations(const String &p_locale) { if (tr.is_valid()) { tr->set_locale(dtl->lang); - TranslationServer::get_singleton()->set_doc_translation(tr); + domain->add_translation(tr); break; } } @@ -132,6 +138,8 @@ void load_doc_translations(const String &p_locale) { } void load_extractable_translations(const String &p_locale) { + const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain("godot.editor"); + ExtractableTranslationList *etl = _extractable_translations; while (etl->data) { if (etl->lang == p_locale) { @@ -148,7 +156,7 @@ void load_extractable_translations(const String &p_locale) { if (tr.is_valid()) { tr->set_locale(etl->lang); - TranslationServer::get_singleton()->set_extractable_translation(tr); + domain->add_translation(tr); break; } } diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h index a800bb95e6..95f21ceafb 100644 --- a/editor/export/editor_export_platform.h +++ b/editor/export/editor_export_platform.h @@ -308,7 +308,7 @@ public: virtual Error export_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags = 0); virtual Error export_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags = 0); virtual void get_platform_features(List<String> *r_features) const = 0; - virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features){}; + virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) {} virtual String get_debug_protocol() const { return "tcp://"; } EditorExportPlatform(); diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index ce2dbe7cb1..e0de6bbcb1 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -840,7 +840,7 @@ GroupsEditor::GroupsEditor() { add_child(hbc); add = memnew(Button); - add->set_flat(true); + add->set_theme_type_variation("FlatMenuButton"); add->set_tooltip_text(TTR("Add a new group.")); add->connect(SceneStringName(pressed), callable_mp(this, &GroupsEditor::_show_add_group_dialog)); hbc->add_child(add); diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp index b6aa3c2215..18f1f6da0c 100644 --- a/editor/gui/editor_file_dialog.cpp +++ b/editor/gui/editor_file_dialog.cpp @@ -207,6 +207,10 @@ void EditorFileDialog::_update_theme_item_cache() { void EditorFileDialog::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + set_translation_domain(SNAME("godot.editor")); + } break; + case NOTIFICATION_THEME_CHANGED: case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_TRANSLATION_CHANGED: { diff --git a/editor/gui/editor_title_bar.h b/editor/gui/editor_title_bar.h index 4055476b82..13fd5d6cdb 100644 --- a/editor/gui/editor_title_bar.h +++ b/editor/gui/editor_title_bar.h @@ -43,7 +43,7 @@ class EditorTitleBar : public HBoxContainer { protected: virtual void gui_input(const Ref<InputEvent> &p_event) override; - static void _bind_methods(){}; + static void _bind_methods() {} public: void set_can_move_window(bool p_enabled); diff --git a/editor/import/3d/resource_importer_obj.cpp b/editor/import/3d/resource_importer_obj.cpp index f3770adcb7..a579224ecd 100644 --- a/editor/import/3d/resource_importer_obj.cpp +++ b/editor/import/3d/resource_importer_obj.cpp @@ -246,6 +246,8 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, bool smoothing = true; const uint32_t no_smoothing_smooth_group = (uint32_t)-1; + bool uses_uvs = false; + while (true) { String l = f->get_line().strip_edges(); while (l.length() && l[l.length() - 1] == '\\') { @@ -320,6 +322,17 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, idx = 1 ^ idx; } + // Check UVs before faces as we may need to generate dummy tangents if there are no UVs. + if (face[idx].size() >= 2 && !face[idx][1].is_empty()) { + int uv = face[idx][1].to_int() - 1; + if (uv < 0) { + uv += uvs.size() + 1; + } + ERR_FAIL_INDEX_V(uv, uvs.size(), ERR_FILE_CORRUPT); + surf_tool->set_uv(uvs[uv]); + uses_uvs = true; + } + if (face[idx].size() == 3) { int norm = face[idx][2].to_int() - 1; if (norm < 0) { @@ -327,28 +340,19 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, } ERR_FAIL_INDEX_V(norm, normals.size(), ERR_FILE_CORRUPT); surf_tool->set_normal(normals[norm]); - if (generate_tangents && uvs.is_empty()) { + if (generate_tangents && !uses_uvs) { // We can't generate tangents without UVs, so create dummy tangents. Vector3 tan = Vector3(normals[norm].z, -normals[norm].x, normals[norm].y).cross(normals[norm].normalized()).normalized(); surf_tool->set_tangent(Plane(tan.x, tan.y, tan.z, 1.0)); } } else { // No normals, use a dummy tangent since normals and tangents will be generated. - if (generate_tangents && uvs.is_empty()) { + if (generate_tangents && !uses_uvs) { // We can't generate tangents without UVs, so create dummy tangents. surf_tool->set_tangent(Plane(1.0, 0.0, 0.0, 1.0)); } } - if (face[idx].size() >= 2 && !face[idx][1].is_empty()) { - int uv = face[idx][1].to_int() - 1; - if (uv < 0) { - uv += uvs.size() + 1; - } - ERR_FAIL_INDEX_V(uv, uvs.size(), ERR_FILE_CORRUPT); - surf_tool->set_uv(uvs[uv]); - } - int vtx = face[idx][0].to_int() - 1; if (vtx < 0) { vtx += vertices.size() + 1; @@ -407,7 +411,7 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, surf_tool->generate_normals(); } - if (generate_tangents && uvs.size()) { + if (generate_tangents && uses_uvs) { surf_tool->generate_tangents(); } @@ -426,10 +430,11 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, Array array = surf_tool->commit_to_arrays(); - if (mesh_flags & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES && generate_tangents) { - // Compression is enabled, so let's validate that the normals and tangents are correct. + if (mesh_flags & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES && generate_tangents && uses_uvs) { + // Compression is enabled, so let's validate that the normals and generated tangents are correct. Vector<Vector3> norms = array[Mesh::ARRAY_NORMAL]; Vector<float> tangents = array[Mesh::ARRAY_TANGENT]; + ERR_FAIL_COND_V(tangents.is_empty(), ERR_FILE_CORRUPT); for (int vert = 0; vert < norms.size(); vert++) { Vector3 tan = Vector3(tangents[vert * 4 + 0], tangents[vert * 4 + 1], tangents[vert * 4 + 2]); if (abs(tan.dot(norms[vert])) > 0.0001) { @@ -454,6 +459,7 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, surf_tool->clear(); surf_tool->begin(Mesh::PRIMITIVE_TRIANGLES); + uses_uvs = false; } if (l.begins_with("o ") || f->eof_reached()) { diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp index 6bc3a27a95..3c07e85758 100644 --- a/editor/localization_editor.cpp +++ b/editor/localization_editor.cpp @@ -37,7 +37,6 @@ #include "editor/filesystem_dock.h" #include "editor/gui/editor_file_dialog.h" #include "editor/pot_generator.h" -#include "editor/themes/editor_scale.h" #include "scene/gui/control.h" void LocalizationEditor::_notification(int p_what) { @@ -49,6 +48,7 @@ void LocalizationEditor::_notification(int p_what) { List<String> tfn; ResourceLoader::get_recognized_extensions_for_type("Translation", &tfn); + tfn.erase("csv"); // CSV is recognized by the resource importer to generate translation files, but it's not a translation file itself. for (const String &E : tfn) { translation_file_open->add_filter("*." + E); } diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index 860d0ed35d..eb623a147d 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -322,7 +322,7 @@ protected: public: void add_transition(const StringName &p_from, const StringName &p_to, Ref<AnimationNodeStateMachineTransition> p_transition); - EditorAnimationMultiTransitionEdit(){}; + EditorAnimationMultiTransitionEdit() {} }; #endif // ANIMATION_STATE_MACHINE_EDITOR_H diff --git a/editor/plugins/font_config_plugin.h b/editor/plugins/font_config_plugin.h index e83f29a77b..87fd3861dc 100644 --- a/editor/plugins/font_config_plugin.h +++ b/editor/plugins/font_config_plugin.h @@ -51,7 +51,7 @@ public: void set_dict(const Dictionary &p_dict); Dictionary get_dict(); - EditorPropertyFontMetaObject(){}; + EditorPropertyFontMetaObject() {} }; /*************************************************************************/ @@ -75,7 +75,7 @@ public: void set_defaults(const Dictionary &p_dict); Dictionary get_defaults(); - EditorPropertyFontOTObject(){}; + EditorPropertyFontOTObject() {} }; /*************************************************************************/ @@ -103,7 +103,7 @@ class EditorPropertyFontMetaOverride : public EditorProperty { protected: void _notification(int p_what); - static void _bind_methods(){}; + static void _bind_methods() {} void _edit_pressed(); void _page_changed(int p_page); @@ -138,7 +138,7 @@ class EditorPropertyOTVariation : public EditorProperty { EditorPaginator *paginator = nullptr; protected: - static void _bind_methods(){}; + static void _bind_methods() {} void _edit_pressed(); void _page_changed(int p_page); @@ -187,7 +187,7 @@ class EditorPropertyOTFeatures : public EditorProperty { protected: void _notification(int p_what); - static void _bind_methods(){}; + static void _bind_methods() {} void _edit_pressed(); void _page_changed(int p_page); @@ -256,7 +256,7 @@ protected: virtual void _add_element() override; void _add_font(int p_option); - static void _bind_methods(){}; + static void _bind_methods() {} public: EditorPropertyFontNamesArray(); diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.h b/editor/plugins/gpu_particles_3d_editor_plugin.h index 5f59f6dca7..1295836b5f 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.h +++ b/editor/plugins/gpu_particles_3d_editor_plugin.h @@ -59,7 +59,7 @@ protected: Vector<Face3> geometry; bool _generate(Vector<Vector3> &points, Vector<Vector3> &normals); - virtual void _generate_emission_points(){}; + virtual void _generate_emission_points() {} void _node_selected(const NodePath &p_path); public: diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 9579388d46..54730ec674 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1483,7 +1483,7 @@ void ScriptEditor::_menu_option(int p_option) { current->apply_code(); - Error err = scr->reload(false); // Always hard reload the script before running. + Error err = scr->reload(true); // Always hard reload the script before running. if (err != OK || !scr->is_valid()) { EditorToaster::get_singleton()->popup_str(TTR("Cannot run the script because it contains errors, check the output log."), EditorToaster::SEVERITY_WARNING); return; diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 1acec4e959..b6c203f2a2 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -127,8 +127,8 @@ public: virtual Variant get_navigation_state() override; virtual Vector<String> get_functions() override; virtual PackedInt32Array get_breakpoints() override; - virtual void set_breakpoint(int p_line, bool p_enabled) override{}; - virtual void clear_breakpoints() override{}; + virtual void set_breakpoint(int p_line, bool p_enabled) override {} + virtual void clear_breakpoints() override {} virtual void goto_line(int p_line, int p_column = 0) override; void goto_line_selection(int p_line, int p_begin, int p_end); virtual void set_executing_line(int p_line) override; diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index 79915012a8..12b9761fd2 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -1097,7 +1097,7 @@ void TileDataDefaultEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas_ } }; -void TileDataDefaultEditor::forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform){ +void TileDataDefaultEditor::forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) { }; diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h index 9b1eadf331..1426bb4c2f 100644 --- a/editor/plugins/tiles/tile_data_editors.h +++ b/editor/plugins/tiles/tile_data_editors.h @@ -54,7 +54,7 @@ private: protected: Ref<TileSet> tile_set; TileData *_get_tile_data(TileMapCell p_cell); - virtual void _tile_set_changed(){}; + virtual void _tile_set_changed() {} static void _bind_methods(); @@ -63,13 +63,13 @@ public: // Input to handle painting. virtual Control *get_toolbar() { return nullptr; }; - virtual void forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform){}; - virtual void forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform){}; - virtual void forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event){}; - virtual void forward_painting_alternatives_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event){}; + virtual void forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) {} + virtual void forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) {} + virtual void forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) {} + virtual void forward_painting_alternatives_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) {} // Used to draw the tile data property value over a tile. - virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false){}; + virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) {} }; class DummyObject : public Object { diff --git a/editor/plugins/tiles/tile_map_layer_editor.h b/editor/plugins/tiles/tile_map_layer_editor.h index 7d749be1ba..805af7b58e 100644 --- a/editor/plugins/tiles/tile_map_layer_editor.h +++ b/editor/plugins/tiles/tile_map_layer_editor.h @@ -66,9 +66,9 @@ public: }; virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return false; }; - virtual void forward_canvas_draw_over_viewport(Control *p_overlay){}; - virtual void tile_set_changed(){}; - virtual void edit(ObjectID p_tile_map_layer_id){}; + virtual void forward_canvas_draw_over_viewport(Control *p_overlay) {} + virtual void tile_set_changed() {} + virtual void edit(ObjectID p_tile_map_layer_id) {} }; class TileMapLayerEditorTilesPlugin : public TileMapLayerSubEditorPlugin { diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 279590563a..8411c0edea 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1081,6 +1081,8 @@ void ProjectManager::_titlebar_resized() { ProjectManager::ProjectManager() { singleton = this; + set_translation_domain("godot.editor"); + // Turn off some servers we aren't going to be using in the Project Manager. NavigationServer3D::get_singleton()->set_active(false); PhysicsServer3D::get_singleton()->set_active(false); diff --git a/editor/renames_map_3_to_4.cpp b/editor/renames_map_3_to_4.cpp index 8eab3fbea9..ae7c86a5e5 100644 --- a/editor/renames_map_3_to_4.cpp +++ b/editor/renames_map_3_to_4.cpp @@ -1518,7 +1518,6 @@ const char *RenamesMap3To4::class_renames[][2] = { { "EditorSceneImporterGLTF", "EditorSceneFormatImporterGLTF" }, { "EditorSpatialGizmo", "EditorNode3DGizmo" }, { "EditorSpatialGizmoPlugin", "EditorNode3DGizmoPlugin" }, - { "ExternalTexture", "ImageTexture" }, { "GIProbe", "VoxelGI" }, { "GIProbeData", "VoxelGIData" }, { "Generic6DOFJoint", "Generic6DOFJoint3D" }, diff --git a/main/main.cpp b/main/main.cpp index f1ee4bf2a6..439cd385c0 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -83,6 +83,7 @@ #ifndef _3D_DISABLED #include "servers/physics_server_3d.h" +#include "servers/physics_server_3d_dummy.h" #include "servers/xr_server.h" #endif // _3D_DISABLED @@ -320,7 +321,15 @@ void initialize_physics() { // Physics server not found, Use the default physics physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server(); } - ERR_FAIL_NULL(physics_server_3d); + + // Fall back to dummy if no default server has been registered. + if (!physics_server_3d) { + WARN_PRINT(vformat("Falling back to dummy PhysicsServer3D; 3D physics functionality will be disabled. If this is intended, set the %s project setting to Dummy.", PhysicsServer3DManager::setting_property_name)); + physics_server_3d = memnew(PhysicsServer3DDummy); + } + + // Should be impossible, but make sure it's not null. + ERR_FAIL_NULL_MSG(physics_server_3d, "Failed to initialize PhysicsServer3D."); physics_server_3d->init(); #endif // _3D_DISABLED @@ -1977,6 +1986,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_vulkan", true); GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_d3d12", true); + GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_opengl3", true); } { diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp index 72b540496d..1804d73a69 100644 --- a/modules/bmp/image_loader_bmp.cpp +++ b/modules/bmp/image_loader_bmp.cpp @@ -59,30 +59,6 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, size_t height = (size_t)p_header.bmp_info_header.bmp_height; size_t bits_per_pixel = (size_t)p_header.bmp_info_header.bmp_bit_count; - // Check whether we can load it - - if (bits_per_pixel == 1) { - // Requires bit unpacking... - ERR_FAIL_COND_V_MSG(width % 8 != 0, ERR_UNAVAILABLE, - vformat("1-bpp BMP images must have a width that is a multiple of 8, but the imported BMP is %d pixels wide.", int(width))); - ERR_FAIL_COND_V_MSG(height % 8 != 0, ERR_UNAVAILABLE, - vformat("1-bpp BMP images must have a height that is a multiple of 8, but the imported BMP is %d pixels tall.", int(height))); - - } else if (bits_per_pixel == 2) { - // Requires bit unpacking... - ERR_FAIL_COND_V_MSG(width % 4 != 0, ERR_UNAVAILABLE, - vformat("2-bpp BMP images must have a width that is a multiple of 4, but the imported BMP is %d pixels wide.", int(width))); - ERR_FAIL_COND_V_MSG(height % 4 != 0, ERR_UNAVAILABLE, - vformat("2-bpp BMP images must have a height that is a multiple of 4, but the imported BMP is %d pixels tall.", int(height))); - - } else if (bits_per_pixel == 4) { - // Requires bit unpacking... - ERR_FAIL_COND_V_MSG(width % 2 != 0, ERR_UNAVAILABLE, - vformat("4-bpp BMP images must have a width that is a multiple of 2, but the imported BMP is %d pixels wide.", int(width))); - ERR_FAIL_COND_V_MSG(height % 2 != 0, ERR_UNAVAILABLE, - vformat("4-bpp BMP images must have a height that is a multiple of 2, but the imported BMP is %d pixels tall.", int(height))); - } - // Image data (might be indexed) Vector<uint8_t> data; int data_len = 0; @@ -98,55 +74,32 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, uint8_t *data_w = data.ptrw(); uint8_t *write_buffer = data_w; - const uint32_t width_bytes = width * bits_per_pixel / 8; - const uint32_t line_width = (width_bytes + 3) & ~3; + const uint32_t width_bytes = (width * bits_per_pixel + 7) / 8; + const uint32_t line_width = (width_bytes + 3) & ~3; // Padded to 4 bytes. - // The actual data traversal is determined by - // the data width in case of 8/4/2/1 bit images - const uint32_t w = bits_per_pixel >= 16 ? width : width_bytes; const uint8_t *line = p_buffer + (line_width * (height - 1)); const uint8_t *end_buffer = p_buffer + p_header.bmp_file_header.bmp_file_size - p_header.bmp_file_header.bmp_file_offset; + ERR_FAIL_COND_V(line + line_width > end_buffer, ERR_FILE_CORRUPT); for (uint64_t i = 0; i < height; i++) { const uint8_t *line_ptr = line; - for (unsigned int j = 0; j < w; j++) { - ERR_FAIL_COND_V(line_ptr >= end_buffer, ERR_FILE_CORRUPT); + for (unsigned int j = 0; j < width; j++) { switch (bits_per_pixel) { case 1: { - uint8_t color_index = *line_ptr; + write_buffer[index] = (line[(j * bits_per_pixel) / 8] >> (8 - bits_per_pixel * (1 + j % 8))) & 0x01; - write_buffer[index + 0] = (color_index >> 7) & 1; - write_buffer[index + 1] = (color_index >> 6) & 1; - write_buffer[index + 2] = (color_index >> 5) & 1; - write_buffer[index + 3] = (color_index >> 4) & 1; - write_buffer[index + 4] = (color_index >> 3) & 1; - write_buffer[index + 5] = (color_index >> 2) & 1; - write_buffer[index + 6] = (color_index >> 1) & 1; - write_buffer[index + 7] = (color_index >> 0) & 1; - - index += 8; - line_ptr += 1; + index++; } break; case 2: { - uint8_t color_index = *line_ptr; + write_buffer[index] = (line[(j * bits_per_pixel) / 8] >> (8 - bits_per_pixel * (1 + j % 4))) & 0x03; - write_buffer[index + 0] = (color_index >> 6) & 3; - write_buffer[index + 1] = (color_index >> 4) & 3; - write_buffer[index + 2] = (color_index >> 2) & 3; - write_buffer[index + 3] = color_index & 3; - - index += 4; - line_ptr += 1; + index++; } break; case 4: { - uint8_t color_index = *line_ptr; - - write_buffer[index + 0] = (color_index >> 4) & 0x0f; - write_buffer[index + 1] = color_index & 0x0f; + write_buffer[index] = (line[(j * bits_per_pixel) / 8] >> (8 - bits_per_pixel * (1 + j % 2))) & 0x0f; - index += 2; - line_ptr += 1; + index++; } break; case 8: { uint8_t color_index = *line_ptr; diff --git a/modules/gdscript/language_server/gdscript_extend_parser.h b/modules/gdscript/language_server/gdscript_extend_parser.h index a808f19e5b..239f7d9f43 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.h +++ b/modules/gdscript/language_server/gdscript_extend_parser.h @@ -37,10 +37,10 @@ #include "core/variant/variant.h" #ifndef LINE_NUMBER_TO_INDEX -#define LINE_NUMBER_TO_INDEX(p_line) ((p_line)-1) +#define LINE_NUMBER_TO_INDEX(p_line) ((p_line) - 1) #endif #ifndef COLUMN_NUMBER_TO_INDEX -#define COLUMN_NUMBER_TO_INDEX(p_column) ((p_column)-1) +#define COLUMN_NUMBER_TO_INDEX(p_column) ((p_column) - 1) #endif #ifndef SYMBOL_SEPERATOR diff --git a/modules/godot_physics_3d/SCsub b/modules/godot_physics_3d/SCsub new file mode 100644 index 0000000000..41a59cd24e --- /dev/null +++ b/modules/godot_physics_3d/SCsub @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +Import('env') + +env.add_source_files(env.modules_sources, "*.cpp") + +SConscript("joints/SCsub") diff --git a/modules/godot_physics_3d/config.py b/modules/godot_physics_3d/config.py new file mode 100644 index 0000000000..a42f27fbe1 --- /dev/null +++ b/modules/godot_physics_3d/config.py @@ -0,0 +1,6 @@ +def can_build(env, platform): + return not env["disable_3d"] + + +def configure(env): + pass diff --git a/servers/physics_3d/gjk_epa.cpp b/modules/godot_physics_3d/gjk_epa.cpp index e5678914fe..e5678914fe 100644 --- a/servers/physics_3d/gjk_epa.cpp +++ b/modules/godot_physics_3d/gjk_epa.cpp diff --git a/servers/physics_3d/gjk_epa.h b/modules/godot_physics_3d/gjk_epa.h index 48fda9969f..48fda9969f 100644 --- a/servers/physics_3d/gjk_epa.h +++ b/modules/godot_physics_3d/gjk_epa.h diff --git a/servers/physics_3d/godot_area_3d.cpp b/modules/godot_physics_3d/godot_area_3d.cpp index d0b287b058..d0b287b058 100644 --- a/servers/physics_3d/godot_area_3d.cpp +++ b/modules/godot_physics_3d/godot_area_3d.cpp diff --git a/servers/physics_3d/godot_area_3d.h b/modules/godot_physics_3d/godot_area_3d.h index 2c1a782630..2c1a782630 100644 --- a/servers/physics_3d/godot_area_3d.h +++ b/modules/godot_physics_3d/godot_area_3d.h diff --git a/servers/physics_3d/godot_area_pair_3d.cpp b/modules/godot_physics_3d/godot_area_pair_3d.cpp index aaa96f5a28..aaa96f5a28 100644 --- a/servers/physics_3d/godot_area_pair_3d.cpp +++ b/modules/godot_physics_3d/godot_area_pair_3d.cpp diff --git a/servers/physics_3d/godot_area_pair_3d.h b/modules/godot_physics_3d/godot_area_pair_3d.h index a2c5df0f7a..a2c5df0f7a 100644 --- a/servers/physics_3d/godot_area_pair_3d.h +++ b/modules/godot_physics_3d/godot_area_pair_3d.h diff --git a/servers/physics_3d/godot_body_3d.cpp b/modules/godot_physics_3d/godot_body_3d.cpp index 669c4b985b..669c4b985b 100644 --- a/servers/physics_3d/godot_body_3d.cpp +++ b/modules/godot_physics_3d/godot_body_3d.cpp diff --git a/servers/physics_3d/godot_body_3d.h b/modules/godot_physics_3d/godot_body_3d.h index 81b668122a..81b668122a 100644 --- a/servers/physics_3d/godot_body_3d.h +++ b/modules/godot_physics_3d/godot_body_3d.h diff --git a/servers/physics_3d/godot_body_direct_state_3d.cpp b/modules/godot_physics_3d/godot_body_direct_state_3d.cpp index 0af746c68d..0af746c68d 100644 --- a/servers/physics_3d/godot_body_direct_state_3d.cpp +++ b/modules/godot_physics_3d/godot_body_direct_state_3d.cpp diff --git a/servers/physics_3d/godot_body_direct_state_3d.h b/modules/godot_physics_3d/godot_body_direct_state_3d.h index 8066050c9f..8066050c9f 100644 --- a/servers/physics_3d/godot_body_direct_state_3d.h +++ b/modules/godot_physics_3d/godot_body_direct_state_3d.h diff --git a/servers/physics_3d/godot_body_pair_3d.cpp b/modules/godot_physics_3d/godot_body_pair_3d.cpp index 84fae73616..84fae73616 100644 --- a/servers/physics_3d/godot_body_pair_3d.cpp +++ b/modules/godot_physics_3d/godot_body_pair_3d.cpp diff --git a/servers/physics_3d/godot_body_pair_3d.h b/modules/godot_physics_3d/godot_body_pair_3d.h index a8f5180dd5..a8f5180dd5 100644 --- a/servers/physics_3d/godot_body_pair_3d.h +++ b/modules/godot_physics_3d/godot_body_pair_3d.h diff --git a/servers/physics_3d/godot_broad_phase_3d.cpp b/modules/godot_physics_3d/godot_broad_phase_3d.cpp index ebd11fb51f..ebd11fb51f 100644 --- a/servers/physics_3d/godot_broad_phase_3d.cpp +++ b/modules/godot_physics_3d/godot_broad_phase_3d.cpp diff --git a/servers/physics_3d/godot_broad_phase_3d.h b/modules/godot_physics_3d/godot_broad_phase_3d.h index f70321be64..f70321be64 100644 --- a/servers/physics_3d/godot_broad_phase_3d.h +++ b/modules/godot_physics_3d/godot_broad_phase_3d.h diff --git a/servers/physics_3d/godot_broad_phase_3d_bvh.cpp b/modules/godot_physics_3d/godot_broad_phase_3d_bvh.cpp index 0faa56b52e..0faa56b52e 100644 --- a/servers/physics_3d/godot_broad_phase_3d_bvh.cpp +++ b/modules/godot_physics_3d/godot_broad_phase_3d_bvh.cpp diff --git a/servers/physics_3d/godot_broad_phase_3d_bvh.h b/modules/godot_physics_3d/godot_broad_phase_3d_bvh.h index 63968dea64..63968dea64 100644 --- a/servers/physics_3d/godot_broad_phase_3d_bvh.h +++ b/modules/godot_physics_3d/godot_broad_phase_3d_bvh.h diff --git a/servers/physics_3d/godot_collision_object_3d.cpp b/modules/godot_physics_3d/godot_collision_object_3d.cpp index 283614a43d..283614a43d 100644 --- a/servers/physics_3d/godot_collision_object_3d.cpp +++ b/modules/godot_physics_3d/godot_collision_object_3d.cpp diff --git a/servers/physics_3d/godot_collision_object_3d.h b/modules/godot_physics_3d/godot_collision_object_3d.h index bf28bcc45a..bf28bcc45a 100644 --- a/servers/physics_3d/godot_collision_object_3d.h +++ b/modules/godot_physics_3d/godot_collision_object_3d.h diff --git a/servers/physics_3d/godot_collision_solver_3d.cpp b/modules/godot_physics_3d/godot_collision_solver_3d.cpp index db48111eea..db48111eea 100644 --- a/servers/physics_3d/godot_collision_solver_3d.cpp +++ b/modules/godot_physics_3d/godot_collision_solver_3d.cpp diff --git a/servers/physics_3d/godot_collision_solver_3d.h b/modules/godot_physics_3d/godot_collision_solver_3d.h index 36ea79576e..36ea79576e 100644 --- a/servers/physics_3d/godot_collision_solver_3d.h +++ b/modules/godot_physics_3d/godot_collision_solver_3d.h diff --git a/servers/physics_3d/godot_collision_solver_3d_sat.cpp b/modules/godot_physics_3d/godot_collision_solver_3d_sat.cpp index c53c8481f4..c53c8481f4 100644 --- a/servers/physics_3d/godot_collision_solver_3d_sat.cpp +++ b/modules/godot_physics_3d/godot_collision_solver_3d_sat.cpp diff --git a/servers/physics_3d/godot_collision_solver_3d_sat.h b/modules/godot_physics_3d/godot_collision_solver_3d_sat.h index 49fcab3933..49fcab3933 100644 --- a/servers/physics_3d/godot_collision_solver_3d_sat.h +++ b/modules/godot_physics_3d/godot_collision_solver_3d_sat.h diff --git a/servers/physics_3d/godot_constraint_3d.h b/modules/godot_physics_3d/godot_constraint_3d.h index a833aba93f..a833aba93f 100644 --- a/servers/physics_3d/godot_constraint_3d.h +++ b/modules/godot_physics_3d/godot_constraint_3d.h diff --git a/servers/physics_3d/godot_joint_3d.h b/modules/godot_physics_3d/godot_joint_3d.h index 3207723cb4..3207723cb4 100644 --- a/servers/physics_3d/godot_joint_3d.h +++ b/modules/godot_physics_3d/godot_joint_3d.h diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/modules/godot_physics_3d/godot_physics_server_3d.cpp index 8a7b4e0f07..6d0949acbe 100644 --- a/servers/physics_3d/godot_physics_server_3d.cpp +++ b/modules/godot_physics_3d/godot_physics_server_3d.cpp @@ -1629,8 +1629,6 @@ void GodotPhysicsServer3D::init() { } void GodotPhysicsServer3D::step(real_t p_step) { -#ifndef _3D_DISABLED - if (!active) { return; } @@ -1646,7 +1644,6 @@ void GodotPhysicsServer3D::step(real_t p_step) { active_objects += E->get_active_objects(); collision_pairs += E->get_collision_pairs(); } -#endif } void GodotPhysicsServer3D::sync() { @@ -1654,8 +1651,6 @@ void GodotPhysicsServer3D::sync() { } void GodotPhysicsServer3D::flush_queries() { -#ifndef _3D_DISABLED - if (!active) { return; } @@ -1703,7 +1698,6 @@ void GodotPhysicsServer3D::flush_queries() { values.push_front("physics_3d"); EngineDebugger::profiler_add_frame_data("servers", values); } -#endif } void GodotPhysicsServer3D::end_sync() { diff --git a/servers/physics_3d/godot_physics_server_3d.h b/modules/godot_physics_3d/godot_physics_server_3d.h index 040e673dcd..040e673dcd 100644 --- a/servers/physics_3d/godot_physics_server_3d.h +++ b/modules/godot_physics_3d/godot_physics_server_3d.h diff --git a/servers/physics_3d/godot_shape_3d.cpp b/modules/godot_physics_3d/godot_shape_3d.cpp index 70b6bcf19e..70b6bcf19e 100644 --- a/servers/physics_3d/godot_shape_3d.cpp +++ b/modules/godot_physics_3d/godot_shape_3d.cpp diff --git a/servers/physics_3d/godot_shape_3d.h b/modules/godot_physics_3d/godot_shape_3d.h index dbd58ead68..dbd58ead68 100644 --- a/servers/physics_3d/godot_shape_3d.h +++ b/modules/godot_physics_3d/godot_shape_3d.h diff --git a/servers/physics_3d/godot_soft_body_3d.cpp b/modules/godot_physics_3d/godot_soft_body_3d.cpp index 7284076a47..7284076a47 100644 --- a/servers/physics_3d/godot_soft_body_3d.cpp +++ b/modules/godot_physics_3d/godot_soft_body_3d.cpp diff --git a/servers/physics_3d/godot_soft_body_3d.h b/modules/godot_physics_3d/godot_soft_body_3d.h index e23f4bb9f5..e23f4bb9f5 100644 --- a/servers/physics_3d/godot_soft_body_3d.h +++ b/modules/godot_physics_3d/godot_soft_body_3d.h diff --git a/servers/physics_3d/godot_space_3d.cpp b/modules/godot_physics_3d/godot_space_3d.cpp index 9a6ba776b4..9a6ba776b4 100644 --- a/servers/physics_3d/godot_space_3d.cpp +++ b/modules/godot_physics_3d/godot_space_3d.cpp diff --git a/servers/physics_3d/godot_space_3d.h b/modules/godot_physics_3d/godot_space_3d.h index f476be5934..f476be5934 100644 --- a/servers/physics_3d/godot_space_3d.h +++ b/modules/godot_physics_3d/godot_space_3d.h diff --git a/servers/physics_3d/godot_step_3d.cpp b/modules/godot_physics_3d/godot_step_3d.cpp index d09a3b4e6d..d09a3b4e6d 100644 --- a/servers/physics_3d/godot_step_3d.cpp +++ b/modules/godot_physics_3d/godot_step_3d.cpp diff --git a/servers/physics_3d/godot_step_3d.h b/modules/godot_physics_3d/godot_step_3d.h index 1c9b0af422..1c9b0af422 100644 --- a/servers/physics_3d/godot_step_3d.h +++ b/modules/godot_physics_3d/godot_step_3d.h diff --git a/modules/godot_physics_3d/joints/SCsub b/modules/godot_physics_3d/joints/SCsub new file mode 100644 index 0000000000..5d93da5ecf --- /dev/null +++ b/modules/godot_physics_3d/joints/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import('env') + +env.add_source_files(env.modules_sources, "*.cpp") diff --git a/servers/physics_3d/joints/godot_cone_twist_joint_3d.cpp b/modules/godot_physics_3d/joints/godot_cone_twist_joint_3d.cpp index 4091422789..4091422789 100644 --- a/servers/physics_3d/joints/godot_cone_twist_joint_3d.cpp +++ b/modules/godot_physics_3d/joints/godot_cone_twist_joint_3d.cpp diff --git a/servers/physics_3d/joints/godot_cone_twist_joint_3d.h b/modules/godot_physics_3d/joints/godot_cone_twist_joint_3d.h index 8b749e4914..f3b683a8f3 100644 --- a/servers/physics_3d/joints/godot_cone_twist_joint_3d.h +++ b/modules/godot_physics_3d/joints/godot_cone_twist_joint_3d.h @@ -52,8 +52,8 @@ subject to the following restrictions: Written by: Marcus Hennix */ -#include "servers/physics_3d/godot_joint_3d.h" -#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" +#include "../godot_joint_3d.h" +#include "godot_jacobian_entry_3d.h" // GodotConeTwistJoint3D can be used to simulate ragdoll joints (upper arm, leg etc). class GodotConeTwistJoint3D : public GodotJoint3D { diff --git a/servers/physics_3d/joints/godot_generic_6dof_joint_3d.cpp b/modules/godot_physics_3d/joints/godot_generic_6dof_joint_3d.cpp index 226f8a0f7f..226f8a0f7f 100644 --- a/servers/physics_3d/joints/godot_generic_6dof_joint_3d.cpp +++ b/modules/godot_physics_3d/joints/godot_generic_6dof_joint_3d.cpp diff --git a/servers/physics_3d/joints/godot_generic_6dof_joint_3d.h b/modules/godot_physics_3d/joints/godot_generic_6dof_joint_3d.h index 69a5266438..9ee6dd2791 100644 --- a/servers/physics_3d/joints/godot_generic_6dof_joint_3d.h +++ b/modules/godot_physics_3d/joints/godot_generic_6dof_joint_3d.h @@ -35,8 +35,8 @@ Adapted to Godot from the Bullet library. */ -#include "servers/physics_3d/godot_joint_3d.h" -#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" +#include "../godot_joint_3d.h" +#include "godot_jacobian_entry_3d.h" /* Bullet Continuous Collision Detection and Physics Library diff --git a/servers/physics_3d/joints/godot_hinge_joint_3d.cpp b/modules/godot_physics_3d/joints/godot_hinge_joint_3d.cpp index 3d423f70e2..3d423f70e2 100644 --- a/servers/physics_3d/joints/godot_hinge_joint_3d.cpp +++ b/modules/godot_physics_3d/joints/godot_hinge_joint_3d.cpp diff --git a/servers/physics_3d/joints/godot_hinge_joint_3d.h b/modules/godot_physics_3d/joints/godot_hinge_joint_3d.h index eab60c1909..7f83509468 100644 --- a/servers/physics_3d/joints/godot_hinge_joint_3d.h +++ b/modules/godot_physics_3d/joints/godot_hinge_joint_3d.h @@ -35,8 +35,8 @@ Adapted to Godot from the Bullet library. */ -#include "servers/physics_3d/godot_joint_3d.h" -#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" +#include "../godot_joint_3d.h" +#include "godot_jacobian_entry_3d.h" /* Bullet Continuous Collision Detection and Physics Library diff --git a/servers/physics_3d/joints/godot_jacobian_entry_3d.h b/modules/godot_physics_3d/joints/godot_jacobian_entry_3d.h index d0c3c48ae6..d0c3c48ae6 100644 --- a/servers/physics_3d/joints/godot_jacobian_entry_3d.h +++ b/modules/godot_physics_3d/joints/godot_jacobian_entry_3d.h diff --git a/servers/physics_3d/joints/godot_pin_joint_3d.cpp b/modules/godot_physics_3d/joints/godot_pin_joint_3d.cpp index 05ae0839e4..05ae0839e4 100644 --- a/servers/physics_3d/joints/godot_pin_joint_3d.cpp +++ b/modules/godot_physics_3d/joints/godot_pin_joint_3d.cpp diff --git a/servers/physics_3d/joints/godot_pin_joint_3d.h b/modules/godot_physics_3d/joints/godot_pin_joint_3d.h index 2d19bcb626..62d3068e09 100644 --- a/servers/physics_3d/joints/godot_pin_joint_3d.h +++ b/modules/godot_physics_3d/joints/godot_pin_joint_3d.h @@ -35,8 +35,8 @@ Adapted to Godot from the Bullet library. */ -#include "servers/physics_3d/godot_joint_3d.h" -#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" +#include "../godot_joint_3d.h" +#include "godot_jacobian_entry_3d.h" /* Bullet Continuous Collision Detection and Physics Library diff --git a/servers/physics_3d/joints/godot_slider_joint_3d.cpp b/modules/godot_physics_3d/joints/godot_slider_joint_3d.cpp index b9dca94b37..b9dca94b37 100644 --- a/servers/physics_3d/joints/godot_slider_joint_3d.cpp +++ b/modules/godot_physics_3d/joints/godot_slider_joint_3d.cpp diff --git a/servers/physics_3d/joints/godot_slider_joint_3d.h b/modules/godot_physics_3d/joints/godot_slider_joint_3d.h index ad79fc51b0..99fabf8638 100644 --- a/servers/physics_3d/joints/godot_slider_joint_3d.h +++ b/modules/godot_physics_3d/joints/godot_slider_joint_3d.h @@ -35,8 +35,8 @@ Adapted to Godot from the Bullet library. */ -#include "servers/physics_3d/godot_joint_3d.h" -#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" +#include "../godot_joint_3d.h" +#include "godot_jacobian_entry_3d.h" /* Bullet Continuous Collision Detection and Physics Library diff --git a/modules/godot_physics_3d/register_types.cpp b/modules/godot_physics_3d/register_types.cpp new file mode 100644 index 0000000000..1b1690cf59 --- /dev/null +++ b/modules/godot_physics_3d/register_types.cpp @@ -0,0 +1,61 @@ +/**************************************************************************/ +/* register_types.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "register_types.h" + +#include "godot_physics_server_3d.h" +#include "servers/physics_server_3d.h" +#include "servers/physics_server_3d_wrap_mt.h" + +static PhysicsServer3D *_createGodotPhysics3DCallback() { +#ifdef THREADS_ENABLED + bool using_threads = GLOBAL_GET("physics/3d/run_on_separate_thread"); +#else + bool using_threads = false; +#endif + + PhysicsServer3D *physics_server_3d = memnew(GodotPhysicsServer3D(using_threads)); + + return memnew(PhysicsServer3DWrapMT(physics_server_3d, using_threads)); +} + +void initialize_godot_physics_3d_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) { + return; + } + PhysicsServer3DManager::get_singleton()->register_server("GodotPhysics3D", callable_mp_static(_createGodotPhysics3DCallback)); + PhysicsServer3DManager::get_singleton()->set_default_server("GodotPhysics3D"); +} + +void uninitialize_godot_physics_3d_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) { + return; + } +} diff --git a/modules/godot_physics_3d/register_types.h b/modules/godot_physics_3d/register_types.h new file mode 100644 index 0000000000..998fb4a1ee --- /dev/null +++ b/modules/godot_physics_3d/register_types.h @@ -0,0 +1,39 @@ +/**************************************************************************/ +/* register_types.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef GODOT_PHYSICS_3D_REGISTER_TYPES_H +#define GODOT_PHYSICS_3D_REGISTER_TYPES_H + +#include "modules/register_module_types.h" + +void initialize_godot_physics_3d_module(ModuleInitializationLevel p_level); +void uninitialize_godot_physics_3d_module(ModuleInitializationLevel p_level); + +#endif // GODOT_PHYSICS_3D_REGISTER_TYPES_H diff --git a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj index f23f2b9a8c..208e6d8f41 100644 --- a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj @@ -5,7 +5,6 @@ <TargetFramework>net6.0-windows</TargetFramework> <LangVersion>10</LangVersion> <Nullable>enable</Nullable> - <RuntimeIdentifier>win-x86</RuntimeIdentifier> <SelfContained>False</SelfContained> <RollForward>LatestMajor</RollForward> </PropertyGroup> diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index d3899c809a..788b46ab9a 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Reflection; using GodotTools.Build; using GodotTools.Ides; using GodotTools.Ides.Rider; @@ -259,11 +260,12 @@ namespace GodotTools var args = new List<string> { + Path.Combine(GodotSharpDirs.DataEditorToolsDir, "GodotTools.OpenVisualStudio.dll"), GodotSharpDirs.ProjectSlnPath, line >= 0 ? $"{scriptPath};{line + 1};{col + 1}" : scriptPath }; - string command = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "GodotTools.OpenVisualStudio.exe"); + string command = DotNetFinder.FindDotNetExe() ?? "dotnet"; try { @@ -700,6 +702,23 @@ namespace GodotTools private static IntPtr InternalCreateInstance(IntPtr unmanagedCallbacks, int unmanagedCallbacksSize) { Internal.Initialize(unmanagedCallbacks, unmanagedCallbacksSize); + + var populateConstructorMethod = + AppDomain.CurrentDomain + .GetAssemblies() + .First(x => x.GetName().Name == "GodotSharpEditor") + .GetType("Godot.EditorConstructors")? + .GetMethod("AddEditorConstructors", + BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + + if (populateConstructorMethod == null) + { + throw new MissingMethodException("Godot.EditorConstructors", + "AddEditorConstructors"); + } + + populateConstructorMethod.Invoke(null, null); + return new GodotSharpEditor().NativeInstance; } } diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 3222c58c4e..a467aae2e9 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -77,6 +77,10 @@ StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) { #define BINDINGS_GLOBAL_SCOPE_CLASS "GD" #define BINDINGS_NATIVE_NAME_FIELD "NativeName" +#define BINDINGS_CLASS_CONSTRUCTOR "Constructors" +#define BINDINGS_CLASS_CONSTRUCTOR_EDITOR "EditorConstructors" +#define BINDINGS_CLASS_CONSTRUCTOR_DICTIONARY "BuiltInMethodConstructors" + #define CS_PARAM_MEMORYOWN "memoryOwn" #define CS_PARAM_METHODBIND "method" #define CS_PARAM_INSTANCE "ptr" @@ -1452,7 +1456,7 @@ Error BindingsGenerator::_populate_method_icalls_table(const TypeInterface &p_it } const TypeInterface *return_type = _get_type_or_null(imethod.return_type); - ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found + ERR_FAIL_NULL_V_MSG(return_type, ERR_BUG, "Return type '" + imethod.return_type.cname + "' was not found."); String im_unique_sig = get_ret_unique_sig(return_type) + ",CallMethodBind"; @@ -1463,7 +1467,7 @@ Error BindingsGenerator::_populate_method_icalls_table(const TypeInterface &p_it // Get arguments information for (const ArgumentInterface &iarg : imethod.arguments) { const TypeInterface *arg_type = _get_type_or_null(iarg.type); - ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found + ERR_FAIL_NULL_V_MSG(arg_type, ERR_BUG, "Argument type '" + iarg.type.cname + "' was not found."); im_unique_sig += ","; im_unique_sig += get_arg_unique_sig(*arg_type); @@ -1737,6 +1741,69 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) { compile_items.push_back(output_file); } + // Generate source file for built-in type constructor dictionary. + + { + StringBuilder cs_built_in_ctors_content; + + cs_built_in_ctors_content.append("namespace " BINDINGS_NAMESPACE ";\n\n"); + cs_built_in_ctors_content.append("using System;\n" + "using System.Collections.Generic;\n" + "\n"); + cs_built_in_ctors_content.append("internal static class " BINDINGS_CLASS_CONSTRUCTOR "\n{"); + + cs_built_in_ctors_content.append(MEMBER_BEGIN "internal static readonly Dictionary<string, Func<IntPtr, GodotObject>> " BINDINGS_CLASS_CONSTRUCTOR_DICTIONARY ";\n"); + + cs_built_in_ctors_content.append(MEMBER_BEGIN "public static GodotObject Invoke(string nativeTypeNameStr, IntPtr nativeObjectPtr)\n"); + cs_built_in_ctors_content.append(INDENT1 OPEN_BLOCK); + cs_built_in_ctors_content.append(INDENT2 "if (!" BINDINGS_CLASS_CONSTRUCTOR_DICTIONARY ".TryGetValue(nativeTypeNameStr, out var constructor))\n"); + cs_built_in_ctors_content.append(INDENT3 "throw new InvalidOperationException(\"Wrapper class not found for type: \" + nativeTypeNameStr);\n"); + cs_built_in_ctors_content.append(INDENT2 "return constructor(nativeObjectPtr);\n"); + cs_built_in_ctors_content.append(INDENT1 CLOSE_BLOCK); + + cs_built_in_ctors_content.append(MEMBER_BEGIN "static " BINDINGS_CLASS_CONSTRUCTOR "()\n"); + cs_built_in_ctors_content.append(INDENT1 OPEN_BLOCK); + cs_built_in_ctors_content.append(INDENT2 BINDINGS_CLASS_CONSTRUCTOR_DICTIONARY " = new();\n"); + + for (const KeyValue<StringName, TypeInterface> &E : obj_types) { + const TypeInterface &itype = E.value; + + if (itype.api_type != ClassDB::API_CORE || itype.is_singleton_instance) { + continue; + } + + if (itype.is_deprecated) { + cs_built_in_ctors_content.append("#pragma warning disable CS0618\n"); + } + + cs_built_in_ctors_content.append(INDENT2 BINDINGS_CLASS_CONSTRUCTOR_DICTIONARY ".Add(\""); + cs_built_in_ctors_content.append(itype.name); + cs_built_in_ctors_content.append("\", " CS_PARAM_INSTANCE " => new "); + cs_built_in_ctors_content.append(itype.proxy_name); + if (itype.is_singleton && !itype.is_compat_singleton) { + cs_built_in_ctors_content.append("Instance"); + } + cs_built_in_ctors_content.append("(" CS_PARAM_INSTANCE "));\n"); + + if (itype.is_deprecated) { + cs_built_in_ctors_content.append("#pragma warning restore CS0618\n"); + } + } + + cs_built_in_ctors_content.append(INDENT1 CLOSE_BLOCK); + + cs_built_in_ctors_content.append(CLOSE_BLOCK); + + String constructors_file = path::join(base_gen_dir, BINDINGS_CLASS_CONSTRUCTOR ".cs"); + Error err = _save_file(constructors_file, cs_built_in_ctors_content); + + if (err != OK) { + return err; + } + + compile_items.push_back(constructors_file); + } + // Generate native calls StringBuilder cs_icalls_content; @@ -1844,6 +1911,57 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) { compile_items.push_back(output_file); } + // Generate source file for editor type constructor dictionary. + + { + StringBuilder cs_built_in_ctors_content; + + cs_built_in_ctors_content.append("namespace " BINDINGS_NAMESPACE ";\n\n"); + cs_built_in_ctors_content.append("internal static class " BINDINGS_CLASS_CONSTRUCTOR_EDITOR "\n{"); + + cs_built_in_ctors_content.append(MEMBER_BEGIN "private static void AddEditorConstructors()\n"); + cs_built_in_ctors_content.append(INDENT1 OPEN_BLOCK); + cs_built_in_ctors_content.append(INDENT2 "var builtInMethodConstructors = " BINDINGS_CLASS_CONSTRUCTOR "." BINDINGS_CLASS_CONSTRUCTOR_DICTIONARY ";\n"); + + for (const KeyValue<StringName, TypeInterface> &E : obj_types) { + const TypeInterface &itype = E.value; + + if (itype.api_type != ClassDB::API_EDITOR || itype.is_singleton_instance) { + continue; + } + + if (itype.is_deprecated) { + cs_built_in_ctors_content.append("#pragma warning disable CS0618\n"); + } + + cs_built_in_ctors_content.append(INDENT2 "builtInMethodConstructors.Add(\""); + cs_built_in_ctors_content.append(itype.name); + cs_built_in_ctors_content.append("\", " CS_PARAM_INSTANCE " => new "); + cs_built_in_ctors_content.append(itype.proxy_name); + if (itype.is_singleton && !itype.is_compat_singleton) { + cs_built_in_ctors_content.append("Instance"); + } + cs_built_in_ctors_content.append("(" CS_PARAM_INSTANCE "));\n"); + + if (itype.is_deprecated) { + cs_built_in_ctors_content.append("#pragma warning restore CS0618\n"); + } + } + + cs_built_in_ctors_content.append(INDENT1 CLOSE_BLOCK); + + cs_built_in_ctors_content.append(CLOSE_BLOCK); + + String constructors_file = path::join(base_gen_dir, BINDINGS_CLASS_CONSTRUCTOR_EDITOR ".cs"); + Error err = _save_file(constructors_file, cs_built_in_ctors_content); + + if (err != OK) { + return err; + } + + compile_items.push_back(constructors_file); + } + // Generate native calls StringBuilder cs_icalls_content; @@ -2210,6 +2328,15 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str << CLOSE_BLOCK_L2 CLOSE_BLOCK_L1; } + output << MEMBER_BEGIN "internal " << itype.proxy_name << "(IntPtr " CS_PARAM_INSTANCE ") : this(" + << (itype.memory_own ? "true" : "false") << ")\n" OPEN_BLOCK_L1 + << INDENT2 "NativePtr = " CS_PARAM_INSTANCE ";\n" + << INDENT2 "unsafe\n" INDENT2 OPEN_BLOCK + << INDENT3 "ConstructAndInitialize(null, " + << BINDINGS_NATIVE_NAME_FIELD ", CachedType, refCounted: " + << (itype.is_ref_counted ? "true" : "false") << ");\n" + << CLOSE_BLOCK_L2 CLOSE_BLOCK_L1; + // Add.. em.. trick constructor. Sort of. output.append(MEMBER_BEGIN "internal "); output.append(itype.proxy_name); @@ -2313,7 +2440,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str const ArgumentInterface &iarg = *itr; const TypeInterface *arg_type = _get_type_or_null(iarg.type); - ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found + ERR_FAIL_NULL_V_MSG(arg_type, ERR_BUG, "Argument type '" + iarg.type.cname + "' was not found."); if (i != 0) { output << ", "; @@ -2333,7 +2460,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str if (imethod.return_type.cname != name_cache.type_void) { const TypeInterface *return_type = _get_type_or_null(imethod.return_type); - ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found + ERR_FAIL_NULL_V_MSG(return_type, ERR_BUG, "Return type '" + imethod.return_type.cname + "' was not found."); output << INDENT3 "ret = " << sformat(return_type->cs_managed_to_variant, "callRet", return_type->cs_type, return_type->name) @@ -2552,7 +2679,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte const TypeReference &proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type; const TypeInterface *prop_itype = _get_type_or_singleton_or_null(proptype_name); - ERR_FAIL_NULL_V(prop_itype, ERR_BUG); // Property type not found + ERR_FAIL_NULL_V_MSG(prop_itype, ERR_BUG, "Property type '" + proptype_name.cname + "' was not found."); ERR_FAIL_COND_V_MSG(prop_itype->is_singleton, ERR_BUG, "Property type is a singleton: '" + p_itype.name + "." + String(p_iprop.cname) + "'."); @@ -2651,7 +2778,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output) { const TypeInterface *return_type = _get_type_or_singleton_or_null(p_imethod.return_type); - ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found + ERR_FAIL_NULL_V_MSG(return_type, ERR_BUG, "Return type '" + p_imethod.return_type.cname + "' was not found."); ERR_FAIL_COND_V_MSG(return_type->is_singleton, ERR_BUG, "Method return type is a singleton: '" + p_itype.name + "." + p_imethod.name + "'."); @@ -2690,7 +2817,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf const ArgumentInterface &first = p_imethod.arguments.front()->get(); for (const ArgumentInterface &iarg : p_imethod.arguments) { const TypeInterface *arg_type = _get_type_or_singleton_or_null(iarg.type); - ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found + ERR_FAIL_NULL_V_MSG(arg_type, ERR_BUG, "Argument type '" + iarg.type.cname + "' was not found."); ERR_FAIL_COND_V_MSG(arg_type->is_singleton, ERR_BUG, "Argument type is a singleton: '" + iarg.name + "' of method '" + p_itype.name + "." + p_imethod.name + "'."); @@ -2934,17 +3061,12 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output) { String arguments_sig; - String delegate_type_params; - - if (!p_isignal.arguments.is_empty()) { - delegate_type_params += "<"; - } // Retrieve information from the arguments const ArgumentInterface &first = p_isignal.arguments.front()->get(); for (const ArgumentInterface &iarg : p_isignal.arguments) { const TypeInterface *arg_type = _get_type_or_singleton_or_null(iarg.type); - ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found + ERR_FAIL_NULL_V_MSG(arg_type, ERR_BUG, "Argument type '" + iarg.type.cname + "' was not found."); ERR_FAIL_COND_V_MSG(arg_type->is_singleton, ERR_BUG, "Argument type is a singleton: '" + iarg.name + "' of signal '" + p_itype.name + "." + p_isignal.name + "'."); @@ -2959,18 +3081,13 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf if (&iarg != &first) { arguments_sig += ", "; - delegate_type_params += ", "; } - arguments_sig += arg_type->cs_type; + String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters); + + arguments_sig += arg_cs_type; arguments_sig += " "; arguments_sig += iarg.name; - - delegate_type_params += arg_type->cs_type; - } - - if (!p_isignal.arguments.is_empty()) { - delegate_type_params += ">"; } // Generate signal @@ -3013,14 +3130,20 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf int idx = 0; for (const ArgumentInterface &iarg : p_isignal.arguments) { const TypeInterface *arg_type = _get_type_or_null(iarg.type); - ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found + ERR_FAIL_NULL_V_MSG(arg_type, ERR_BUG, "Argument type '" + iarg.type.cname + "' was not found."); if (idx != 0) { p_output << ", "; } - p_output << sformat(arg_type->cs_variant_to_managed, - "args[" + itos(idx) + "]", arg_type->cs_type, arg_type->name); + if (arg_type->cname == name_cache.type_Array_generic || arg_type->cname == name_cache.type_Dictionary_generic) { + String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters); + + p_output << "new " << arg_cs_type << "(" << sformat(arg_type->cs_variant_to_managed, "args[" + itos(idx) + "]", arg_type->cs_type, arg_type->name) << ")"; + } else { + p_output << sformat(arg_type->cs_variant_to_managed, + "args[" + itos(idx) + "]", arg_type->cs_type, arg_type->name); + } idx++; } @@ -3113,7 +3236,7 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall, bool ret_void = p_icall.return_type.cname == name_cache.type_void; const TypeInterface *return_type = _get_type_or_null(p_icall.return_type); - ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found + ERR_FAIL_NULL_V_MSG(return_type, ERR_BUG, "Return type '" + p_icall.return_type.cname + "' was not found."); StringBuilder c_func_sig; StringBuilder c_in_statements; @@ -3129,7 +3252,7 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall, int i = 0; for (const TypeReference &arg_type_ref : p_icall.argument_types) { const TypeInterface *arg_type = _get_type_or_null(arg_type_ref); - ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Return type not found + ERR_FAIL_NULL_V_MSG(arg_type, ERR_BUG, "Argument type '" + arg_type_ref.cname + "' was not found."); String c_param_name = "arg" + itos(i + 1); @@ -3389,7 +3512,7 @@ const String BindingsGenerator::_get_generic_type_parameters(const TypeInterface String params = "<"; for (const TypeReference ¶m_type : p_generic_type_parameters) { const TypeInterface *param_itype = _get_type_or_singleton_or_null(param_type); - ERR_FAIL_NULL_V(param_itype, ""); // Parameter type not found + ERR_FAIL_NULL_V_MSG(param_itype, "", "Parameter type '" + param_type.cname + "' was not found."); ERR_FAIL_COND_V_MSG(param_itype->is_singleton, "", "Generic type parameter is a singleton: '" + param_itype->name + "'."); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs index 901700067d..1b3062c5db 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs @@ -93,27 +93,15 @@ namespace Godot.Bridge internal static unsafe IntPtr CreateManagedForGodotObjectBinding(godot_string_name* nativeTypeName, IntPtr godotObject) { - // TODO: Optimize with source generators and delegate pointers. - try { using var stringName = StringName.CreateTakingOwnershipOfDisposableValue( NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(nativeTypeName))); string nativeTypeNameStr = stringName.ToString(); - Type nativeType = TypeGetProxyClass(nativeTypeNameStr) ?? throw new InvalidOperationException( - "Wrapper class not found for type: " + nativeTypeNameStr); - var obj = (GodotObject)FormatterServices.GetUninitializedObject(nativeType); - - var ctor = nativeType.GetConstructor( - BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, - null, Type.EmptyTypes, null); - - obj.NativePtr = godotObject; - - _ = ctor!.Invoke(obj, null); + var instance = Constructors.Invoke(nativeTypeNameStr, godotObject); - return GCHandle.ToIntPtr(CustomGCHandle.AllocStrong(obj)); + return GCHandle.ToIntPtr(CustomGCHandle.AllocStrong(instance)); } catch (Exception e) { @@ -308,66 +296,6 @@ namespace Godot.Bridge } } - private static Type? TypeGetProxyClass(string nativeTypeNameStr) - { - // Performance is not critical here as this will be replaced with a generated dictionary. - - if (nativeTypeNameStr[0] == '_') - nativeTypeNameStr = nativeTypeNameStr.Substring(1); - - Type? wrapperType = typeof(GodotObject).Assembly.GetType("Godot." + nativeTypeNameStr); - - if (wrapperType == null) - { - wrapperType = GetTypeByGodotClassAttr(typeof(GodotObject).Assembly, nativeTypeNameStr); - } - - if (wrapperType == null) - { - var editorAssembly = AppDomain.CurrentDomain.GetAssemblies() - .FirstOrDefault(a => a.GetName().Name == "GodotSharpEditor"); - - if (editorAssembly != null) - { - wrapperType = editorAssembly.GetType("Godot." + nativeTypeNameStr); - - if (wrapperType == null) - { - wrapperType = GetTypeByGodotClassAttr(editorAssembly, nativeTypeNameStr); - } - } - } - - static Type? GetTypeByGodotClassAttr(Assembly assembly, string nativeTypeNameStr) - { - var types = assembly.GetTypes(); - foreach (var type in types) - { - var attr = type.GetCustomAttribute<GodotClassNameAttribute>(); - if (attr?.Name == nativeTypeNameStr) - { - return type; - } - } - return null; - } - - static bool IsStatic(Type type) => type.IsAbstract && type.IsSealed; - - if (wrapperType != null && IsStatic(wrapperType)) - { - // A static class means this is a Godot singleton class. Try to get the Instance proxy type. - wrapperType = TypeGetProxyClass($"{wrapperType.Name}Instance"); - if (wrapperType == null) - { - // Otherwise, fallback to GodotObject. - return typeof(GodotObject); - } - } - - return wrapperType; - } - // Called from GodotPlugins // ReSharper disable once UnusedMember.Local public static void LookupScriptsInAssembly(Assembly assembly) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs index c094eaed77..a429931399 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs @@ -29,6 +29,17 @@ namespace Godot } } + internal GodotObject(IntPtr nativePtr) : this(false) + { + // NativePtr must be non-zero before calling ConstructAndInitialize to avoid invoking the constructor NativeCtor. + // We don't want to invoke the constructor, because we already have a constructed instance in nativePtr. + NativePtr = nativePtr; + unsafe + { + ConstructAndInitialize(NativeCtor, NativeName, _cachedType, refCounted: false); + } + } + internal unsafe void ConstructAndInitialize( delegate* unmanaged<godot_bool, IntPtr> nativeCtor, StringName nativeName, diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 0f534d477f..0dc143edea 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -468,8 +468,8 @@ namespace Godot { for (int j = 0; j < 3; j++) { - real_t e = transform.Basis[i][j] * min[j]; - real_t f = transform.Basis[i][j] * max[j]; + real_t e = transform.Basis[j][i] * min[j]; + real_t f = transform.Basis[j][i] * max[j]; if (e < f) { tmin[i] += e; diff --git a/modules/navigation/nav_base.h b/modules/navigation/nav_base.h index c28392acf7..d2308abfaf 100644 --- a/modules/navigation/nav_base.h +++ b/modules/navigation/nav_base.h @@ -64,7 +64,7 @@ public: void set_owner_id(ObjectID p_owner_id) { owner_id = p_owner_id; } ObjectID get_owner_id() const { return owner_id; } - virtual ~NavBase(){}; + virtual ~NavBase() {} }; #endif // NAV_BASE_H diff --git a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml index 338d632524..813c9d582e 100644 --- a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml +++ b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml @@ -178,6 +178,15 @@ [param layer] is a pointer to an [code]XrCompositionLayerBaseHeader[/code] struct. </description> </method> + <method name="_set_android_surface_swapchain_create_info_and_get_next_pointer" qualifiers="virtual"> + <return type="int" /> + <param index="0" name="property_values" type="Dictionary" /> + <param index="1" name="next_pointer" type="void*" /> + <description> + Adds additional data structures to Android surface swapchains created by [OpenXRCompositionLayer]. + [param property_values] contains the values of the properties returned by [method _get_viewport_composition_layer_extension_properties]. + </description> + </method> <method name="_set_hand_joint_locations_and_get_next_pointer" qualifiers="virtual"> <return type="int" /> <param index="0" name="hand_index" type="int" /> diff --git a/modules/openxr/extensions/openxr_composition_layer_extension.cpp b/modules/openxr/extensions/openxr_composition_layer_extension.cpp index 83e45ffe7f..dc30b95b27 100644 --- a/modules/openxr/extensions/openxr_composition_layer_extension.cpp +++ b/modules/openxr/extensions/openxr_composition_layer_extension.cpp @@ -144,7 +144,6 @@ bool OpenXRCompositionLayerExtension::create_android_surface_swapchain(XrSwapcha OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); ERR_FAIL_NULL_V(openxr_api, false); - // @todo We need a way to add to the next pointer chain. XrResult result = xrCreateSwapchainAndroidSurfaceKHR(openxr_api->get_session(), p_info, r_swapchain, r_surface); if (XR_FAILED(result)) { print_line("OpenXR: Failed to create Android surface swapchain [", openxr_api->get_error_string(result), "]"); @@ -254,11 +253,19 @@ void OpenXRViewportCompositionLayerProvider::create_android_surface() { ERR_FAIL_COND(android_surface.swapchain != XR_NULL_HANDLE || android_surface.surface.is_valid()); ERR_FAIL_COND(!openxr_api || !openxr_api->is_running()); + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *wrapper : openxr_api->get_registered_extension_wrappers()) { + void *np = wrapper->set_android_surface_swapchain_create_info_and_get_next_pointer(extension_property_values, next_pointer); + if (np != nullptr) { + next_pointer = np; + } + } + // The XR_FB_android_surface_swapchain_create extension mandates that format, sampleCount, // faceCount, arraySize, and mipCount must be zero. XrSwapchainCreateInfo info = { XR_TYPE_SWAPCHAIN_CREATE_INFO, // type - nullptr, // next + next_pointer, // next 0, // createFlags XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, // usageFlags 0, // format diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index 09a9556dfa..95b537d1b4 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -97,10 +97,11 @@ public: virtual void on_state_loss_pending() {} // `on_state_loss_pending` is called when the OpenXR session state is changed to loss pending. virtual void on_state_exiting() {} // `on_state_exiting` is called when the OpenXR session state is changed to exiting. - virtual void *set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, Dictionary p_property_values, void *p_next_pointer) { return p_next_pointer; } // Add additional data structures to composition layers created via OpenXRCompositionLayer. + virtual void *set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, const Dictionary &p_property_values, void *p_next_pointer) { return p_next_pointer; } // Add additional data structures to composition layers created via OpenXRCompositionLayer. virtual void on_viewport_composition_layer_destroyed(const XrCompositionLayerBaseHeader *p_layer) {} // `on_viewport_composition_layer_destroyed` is called when a composition layer created via OpenXRCompositionLayer is destroyed. virtual void get_viewport_composition_layer_extension_properties(List<PropertyInfo> *p_property_list) {} // Get additional property definitions for OpenXRCompositionLayer. virtual Dictionary get_viewport_composition_layer_extension_property_defaults() { return Dictionary(); } // Get the default values for the additional property definitions for OpenXRCompositionLayer. + virtual void *set_android_surface_swapchain_create_info_and_get_next_pointer(const Dictionary &p_property_values, void *p_next_pointer) { return p_next_pointer; } // `on_event_polled` is called when there is an OpenXR event to process. // Should return true if the event was handled, false otherwise. diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp index e09ca484d5..07ca476421 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp +++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp @@ -65,6 +65,7 @@ void OpenXRExtensionWrapperExtension::_bind_methods() { GDVIRTUAL_BIND(_get_viewport_composition_layer_extension_properties); GDVIRTUAL_BIND(_get_viewport_composition_layer_extension_property_defaults); GDVIRTUAL_BIND(_on_viewport_composition_layer_destroyed, "layer"); + GDVIRTUAL_BIND(_set_android_surface_swapchain_create_info_and_get_next_pointer, "property_values", "next_pointer"); ClassDB::bind_method(D_METHOD("get_openxr_api"), &OpenXRExtensionWrapperExtension::get_openxr_api); ClassDB::bind_method(D_METHOD("register_extension_wrapper"), &OpenXRExtensionWrapperExtension::register_extension_wrapper); @@ -249,7 +250,7 @@ bool OpenXRExtensionWrapperExtension::on_event_polled(const XrEventDataBuffer &p return false; } -void *OpenXRExtensionWrapperExtension::set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, Dictionary p_property_values, void *p_next_pointer) { +void *OpenXRExtensionWrapperExtension::set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, const Dictionary &p_property_values, void *p_next_pointer) { uint64_t pointer = 0; if (GDVIRTUAL_CALL(_set_viewport_composition_layer_and_get_next_pointer, GDExtensionConstPtr<void>(p_layer), p_property_values, GDExtensionPtr<void>(p_next_pointer), pointer)) { @@ -279,6 +280,16 @@ Dictionary OpenXRExtensionWrapperExtension::get_viewport_composition_layer_exten return property_defaults; } +void *OpenXRExtensionWrapperExtension::set_android_surface_swapchain_create_info_and_get_next_pointer(const Dictionary &p_property_values, void *p_next_pointer) { + uint64_t pointer = 0; + + if (GDVIRTUAL_CALL(_set_android_surface_swapchain_create_info_and_get_next_pointer, p_property_values, GDExtensionPtr<void>(p_next_pointer), pointer)) { + return reinterpret_cast<void *>(pointer); + } + + return p_next_pointer; +} + Ref<OpenXRAPIExtension> OpenXRExtensionWrapperExtension::get_openxr_api() { return openxr_api; } diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.h b/modules/openxr/extensions/openxr_extension_wrapper_extension.h index e37853903b..5cdf288c93 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper_extension.h +++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.h @@ -121,15 +121,17 @@ public: GDVIRTUAL1R(bool, _on_event_polled, GDExtensionConstPtr<void>); - virtual void *set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, Dictionary p_property_values, void *p_next_pointer) override; + virtual void *set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, const Dictionary &p_property_values, void *p_next_pointer) override; virtual void on_viewport_composition_layer_destroyed(const XrCompositionLayerBaseHeader *p_layer) override; virtual void get_viewport_composition_layer_extension_properties(List<PropertyInfo> *p_property_list) override; virtual Dictionary get_viewport_composition_layer_extension_property_defaults() override; + virtual void *set_android_surface_swapchain_create_info_and_get_next_pointer(const Dictionary &p_property_values, void *p_next_pointer) override; GDVIRTUAL3R(uint64_t, _set_viewport_composition_layer_and_get_next_pointer, GDExtensionConstPtr<void>, Dictionary, GDExtensionPtr<void>); GDVIRTUAL1(_on_viewport_composition_layer_destroyed, GDExtensionConstPtr<void>); GDVIRTUAL0R(TypedArray<Dictionary>, _get_viewport_composition_layer_extension_properties); GDVIRTUAL0R(Dictionary, _get_viewport_composition_layer_extension_property_defaults); + GDVIRTUAL2R(uint64_t, _set_android_surface_swapchain_create_info_and_get_next_pointer, Dictionary, GDExtensionPtr<void>); Ref<OpenXRAPIExtension> get_openxr_api(); diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 73b6f6c1c9..c67be5a2b3 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -1247,7 +1247,7 @@ bool OpenXRAPI::create_main_swapchains(Size2i p_size) { return false; } - set_object_name(XR_OBJECT_TYPE_SWAPCHAIN, uint64_t(render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_swapchain()), "Main depth swapchain"); + set_object_name(XR_OBJECT_TYPE_SWAPCHAIN, uint64_t(render_state.main_swapchains[OPENXR_SWAPCHAIN_DEPTH].get_swapchain()), "Main depth swapchain"); } // We create our velocity swapchain if: diff --git a/modules/raycast/godot_update_embree.py b/modules/raycast/godot_update_embree.py index c179060365..c4fff330c9 100644 --- a/modules/raycast/godot_update_embree.py +++ b/modules/raycast/godot_update_embree.py @@ -4,8 +4,8 @@ import re import shutil import stat import subprocess -from types import TracebackType -from typing import Any, Callable, Tuple, Type +import sys +from typing import Any, Callable git_tag = "v4.3.1" @@ -100,9 +100,7 @@ subprocess.run(["git", "checkout", git_tag]) commit_hash = str(subprocess.check_output(["git", "rev-parse", "HEAD"], universal_newlines=True)).strip() -def on_rm_error( - function: Callable[..., Any], path: str, excinfo: Tuple[Type[Exception], Exception, TracebackType] -) -> None: +def on_rm_error(function: Callable[..., Any], path: str, excinfo: Exception) -> None: """ Error handler for `shutil.rmtree()`. @@ -113,10 +111,12 @@ def on_rm_error( os.unlink(path) -# 3.12 Python and beyond should replace `onerror` with `onexc`. # We remove the .git directory because it contains # a lot of read-only files that are problematic on Windows. -shutil.rmtree(".git", onerror=on_rm_error) +if sys.version_info >= (3, 12): + shutil.rmtree(".git", onexc=on_rm_error) +else: + shutil.rmtree(".git", onerror=on_rm_error) # type: ignore all_files = set(cpp_files) diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 448be9ebe4..c63389b1c6 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -705,7 +705,7 @@ class TextServerAdvanced : public TextServerExtension { }; protected: - static void _bind_methods(){}; + static void _bind_methods() {} void full_copy(ShapedTextDataAdvanced *p_shaped); void invalidate(ShapedTextDataAdvanced *p_shaped, bool p_text = false); diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index ee1f72401f..7f12ad593b 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -574,7 +574,7 @@ class TextServerFallback : public TextServerExtension { Mutex ft_mutex; protected: - static void _bind_methods(){}; + static void _bind_methods() {} void full_copy(ShapedTextDataFallback *p_shaped); void invalidate(ShapedTextDataFallback *p_shaped); diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp index 6bdb261b50..4305bf842a 100644 --- a/modules/upnp/upnp.cpp +++ b/modules/upnp/upnp.cpp @@ -131,7 +131,11 @@ void UPNP::parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist) { GetUPNPUrls(&urls, &data, dev->get_description_url().utf8().get_data(), 0); char addr[16]; +#if MINIUPNPC_API_VERSION >= 18 + int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16, nullptr, 0); +#else int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16); +#endif if (i != 1) { FreeUPNPUrls(&urls); diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index b88d887af5..c1053215c6 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -607,11 +607,19 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis if (rendering_context) { if (rendering_context->initialize() != OK) { - ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver)); memdelete(rendering_context); rendering_context = nullptr; - r_error = ERR_UNAVAILABLE; - return; + bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); + if (fallback_to_opengl3 && rendering_driver != "opengl3") { + WARN_PRINT("Your device seem not to support Vulkan, switching to OpenGL 3."); + rendering_driver = "opengl3"; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + } else { + ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver)); + r_error = ERR_UNAVAILABLE; + return; + } } union { diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java index 4a166112ab..be5a7a2962 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java +++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java @@ -50,7 +50,7 @@ public final class SignalInfo { } this.name = signalName; - this.paramTypes = paramTypes == null ? new Class<?>[ 0 ] : paramTypes; + this.paramTypes = paramTypes == null ? new Class<?>[0] : paramTypes; this.paramTypesNames = new String[this.paramTypes.length]; for (int i = 0; i < this.paramTypes.length; i++) { this.paramTypesNames[i] = this.paramTypes[i].getName(); diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index 5a027e0196..e51d43bd89 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -107,11 +107,19 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode #endif if (rendering_context) { if (rendering_context->initialize() != OK) { - ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver)); memdelete(rendering_context); rendering_context = nullptr; - r_error = ERR_UNAVAILABLE; - return; + bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); + if (fallback_to_opengl3 && rendering_driver != "opengl3") { + WARN_PRINT("Your device seem not to support MoltenVK or Metal, switching to OpenGL 3."); + rendering_driver = "opengl3"; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + } else { + ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver)); + r_error = ERR_UNAVAILABLE; + return; + } } if (rendering_context->window_create(MAIN_WINDOW_ID, &wpd) != OK) { diff --git a/platform/linuxbsd/export/export_plugin.h b/platform/linuxbsd/export/export_plugin.h index 1d9ef01d1a..9e016bd4c3 100644 --- a/platform/linuxbsd/export/export_plugin.h +++ b/platform/linuxbsd/export/export_plugin.h @@ -48,7 +48,7 @@ class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC { String cmd_args; bool wait = false; - SSHCleanupCommand(){}; + SSHCleanupCommand() {} SSHCleanupCommand(const String &p_host, const String &p_port, const Vector<String> &p_ssh_arg, const String &p_cmd_args, bool p_wait = false) { host = p_host; port = p_port; diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index a67428b9a4..49f2690e61 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -50,7 +50,7 @@ #define LONG_BITS (sizeof(long) * 8) #define test_bit(nr, addr) (((1UL << ((nr) % LONG_BITS)) & ((addr)[(nr) / LONG_BITS])) != 0) -#define NBITS(x) ((((x)-1) / LONG_BITS) + 1) +#define NBITS(x) ((((x) - 1) / LONG_BITS) + 1) #ifdef UDEV_ENABLED static const char *ignore_str = "/dev/input/js"; diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index a36748efc1..3fbbc263a0 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -1344,20 +1344,28 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win if (rendering_context->initialize() != OK) { memdelete(rendering_context); rendering_context = nullptr; - r_error = ERR_CANT_CREATE; + bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); + if (fallback_to_opengl3 && rendering_driver != "opengl3") { + WARN_PRINT("Your video card drivers seem not to support the required Vulkan version, switching to OpenGL 3."); + rendering_driver = "opengl3"; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + } else { + r_error = ERR_CANT_CREATE; - if (p_rendering_driver == "vulkan") { - OS::get_singleton()->alert( - vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" - "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" - "You can enable the OpenGL 3 driver by starting the engine from the\n" - "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n" - "If you recently updated your video card drivers, try rebooting.", - executable_name), - "Unable to initialize Vulkan video driver"); - } + if (p_rendering_driver == "vulkan") { + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" + "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" + "You can enable the OpenGL 3 driver by starting the engine from the\n" + "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n" + "If you recently updated your video card drivers, try rebooting.", + executable_name), + "Unable to initialize Vulkan video driver"); + } - ERR_FAIL_MSG(vformat("Could not initialize %s", rendering_driver)); + ERR_FAIL_MSG(vformat("Could not initialize %s", rendering_driver)); + } } driver_found = true; diff --git a/platform/linuxbsd/wayland/key_mapping_xkb.h b/platform/linuxbsd/wayland/key_mapping_xkb.h index 306a8f25b5..9b8c90a445 100644 --- a/platform/linuxbsd/wayland/key_mapping_xkb.h +++ b/platform/linuxbsd/wayland/key_mapping_xkb.h @@ -51,7 +51,7 @@ class KeyMappingXKB { static inline HashMap<Key, unsigned int, HashMapHasherKeys> scancode_map_inv; static inline HashMap<unsigned int, KeyLocation, HashMapHasherKeys> location_map; - KeyMappingXKB(){}; + KeyMappingXKB() {} public: static void initialize(); diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index a12c935273..7949f80f24 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -6160,20 +6160,28 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode if (rendering_context->initialize() != OK) { memdelete(rendering_context); rendering_context = nullptr; - r_error = ERR_CANT_CREATE; + bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); + if (fallback_to_opengl3 && rendering_driver != "opengl3") { + WARN_PRINT("Your video card drivers seem not to support the required Vulkan version, switching to OpenGL 3."); + rendering_driver = "opengl3"; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + } else { + r_error = ERR_CANT_CREATE; + + if (p_rendering_driver == "vulkan") { + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" + "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" + "You can enable the OpenGL 3 driver by starting the engine from the\n" + "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n" + "If you recently updated your video card drivers, try rebooting.", + executable_name), + "Unable to initialize Vulkan video driver"); + } - if (p_rendering_driver == "vulkan") { - OS::get_singleton()->alert( - vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" - "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" - "You can enable the OpenGL 3 driver by starting the engine from the\n" - "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n" - "If you recently updated your video card drivers, try rebooting.", - executable_name), - "Unable to initialize Vulkan video driver"); + ERR_FAIL_MSG(vformat("Could not initialize %s", rendering_driver)); } - - ERR_FAIL_MSG(vformat("Could not initialize %s", rendering_driver)); } driver_found = true; } diff --git a/platform/linuxbsd/x11/gl_manager_x11_egl.h b/platform/linuxbsd/x11/gl_manager_x11_egl.h index b9c96619c4..405dda3d83 100644 --- a/platform/linuxbsd/x11/gl_manager_x11_egl.h +++ b/platform/linuxbsd/x11/gl_manager_x11_egl.h @@ -52,8 +52,8 @@ private: public: void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {} - GLManagerEGL_X11(){}; - ~GLManagerEGL_X11(){}; + GLManagerEGL_X11() {} + ~GLManagerEGL_X11() {} }; #endif // X11_ENABLED && GLES3_ENABLED diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 52dc51bc96..f6c1d11028 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -3649,8 +3649,16 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM if (rendering_context->initialize() != OK) { memdelete(rendering_context); rendering_context = nullptr; - r_error = ERR_CANT_CREATE; - ERR_FAIL_MSG("Could not initialize " + rendering_driver); + bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); + if (fallback_to_opengl3 && rendering_driver != "opengl3") { + WARN_PRINT("Your device seem not to support MoltenVK or Metal, switching to OpenGL 3."); + rendering_driver = "opengl3"; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + } else { + r_error = ERR_CANT_CREATE; + ERR_FAIL_MSG("Could not initialize " + rendering_driver); + } } } #endif diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h index 5457c687d3..d88d347359 100644 --- a/platform/macos/export/export_plugin.h +++ b/platform/macos/export/export_plugin.h @@ -68,7 +68,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform { String cmd_args; bool wait = false; - SSHCleanupCommand(){}; + SSHCleanupCommand() {} SSHCleanupCommand(const String &p_host, const String &p_port, const Vector<String> &p_ssh_arg, const String &p_cmd_args, bool p_wait = false) { host = p_host; port = p_port; diff --git a/platform/windows/detect.py b/platform/windows/detect.py index db4c743595..9adab7284c 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -620,18 +620,16 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.") sys.exit(255) - env.Append(CCFLAGS=["-flto=thin"]) - env.Append(LINKFLAGS=["-flto=thin"]) + env.AppendUnique(CCFLAGS=["-flto=thin"]) elif env["use_llvm"]: - env.Append(CCFLAGS=["-flto"]) - env.Append(LINKFLAGS=["-flto"]) + env.AppendUnique(CCFLAGS=["-flto"]) else: env.AppendUnique(CCFLAGS=["/GL"]) - env.AppendUnique(ARFLAGS=["/LTCG"]) - if env["progress"]: - env.AppendUnique(LINKFLAGS=["/LTCG:STATUS"]) - else: - env.AppendUnique(LINKFLAGS=["/LTCG"]) + if env["progress"]: + env.AppendUnique(LINKFLAGS=["/LTCG:STATUS"]) + else: + env.AppendUnique(LINKFLAGS=["/LTCG"]) + env.AppendUnique(ARFLAGS=["/LTCG"]) if vcvars_msvc_config: env.Prepend(CPPPATH=[p for p in str(os.getenv("INCLUDE")).split(";")]) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 50ebe7077f..ed9d5244a3 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -381,7 +381,7 @@ public: ctls[cid] = p_name; } - virtual ~FileDialogEventHandler(){}; + virtual ~FileDialogEventHandler() {} }; #if defined(__GNUC__) && !defined(__clang__) @@ -6177,6 +6177,17 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win } } #endif + bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); + if (failed && fallback_to_opengl3 && rendering_driver != "opengl3") { + memdelete(rendering_context); + rendering_context = nullptr; + tested_drivers.set_flag(DRIVER_ID_COMPAT_OPENGL3); + WARN_PRINT("Your video card drivers seem not to support Direct3D 12 or Vulkan, switching to OpenGL 3."); + rendering_driver = "opengl3"; + OS::get_singleton()->set_current_rendering_method("gl_compatibility"); + OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + failed = false; + } if (failed) { memdelete(rendering_context); rendering_context = nullptr; diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h index e86aac83d4..1972b36845 100644 --- a/platform/windows/export/export_plugin.h +++ b/platform/windows/export/export_plugin.h @@ -52,7 +52,7 @@ class EditorExportPlatformWindows : public EditorExportPlatformPC { String cmd_args; bool wait = false; - SSHCleanupCommand(){}; + SSHCleanupCommand() {} SSHCleanupCommand(const String &p_host, const String &p_port, const Vector<String> &p_ssh_arg, const String &p_cmd_args, bool p_wait = false) { host = p_host; port = p_port; diff --git a/platform/windows/gl_manager_windows_angle.h b/platform/windows/gl_manager_windows_angle.h index f43a6fbe02..9c02912b86 100644 --- a/platform/windows/gl_manager_windows_angle.h +++ b/platform/windows/gl_manager_windows_angle.h @@ -52,8 +52,8 @@ private: public: void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height); - GLManagerANGLE_Windows(){}; - ~GLManagerANGLE_Windows(){}; + GLManagerANGLE_Windows() {} + ~GLManagerANGLE_Windows() {} }; #endif // WINDOWS_ENABLED && GLES3_ENABLED diff --git a/pyproject.toml b/pyproject.toml index 59b6d09a03..1cf789b460 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,6 +10,7 @@ warn_unreachable = true namespace_packages = true explicit_package_bases = true exclude = ["thirdparty/"] +python_version = "3.8" [tool.ruff] extend-exclude = ["thirdparty"] diff --git a/scene/2d/tile_map_layer.h b/scene/2d/tile_map_layer.h index cc0a5b49fb..6cb481849c 100644 --- a/scene/2d/tile_map_layer.h +++ b/scene/2d/tile_map_layer.h @@ -90,7 +90,7 @@ public: TerrainConstraint(Ref<TileSet> p_tile_set, const Vector2i &p_position, int p_terrain); // For the center terrain bit TerrainConstraint(Ref<TileSet> p_tile_set, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain); // For peering bits - TerrainConstraint(){}; + TerrainConstraint() {} }; #ifdef DEBUG_ENABLED diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 591528b915..98bee2115c 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -401,10 +401,19 @@ Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() { if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) { total_max = MAX(total_max, listener_area_pos.length()); } - if (total_max > max_distance) { + if (dist > total_max || total_max > max_distance) { + if (!was_further_than_max_distance_last_frame) { + HashMap<StringName, Vector<AudioFrame>> bus_volumes; + for (Ref<AudioStreamPlayback> &playback : internal->stream_playbacks) { + // So the player gets muted and mostly stops mixing when out of range. + AudioServer::get_singleton()->set_playback_bus_volumes_linear(playback, bus_volumes); + } + was_further_than_max_distance_last_frame = true; // Cache so we don't set the volume over and over. + } continue; //can't hear this sound in this listener } } + was_further_than_max_distance_last_frame = false; float multiplier = Math::db_to_linear(_get_attenuation_db(dist)); if (max_distance > 0) { diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index 72356faad7..91104a06c7 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -105,6 +105,7 @@ private: float linear_attenuation = 0; float max_distance = 0.0; + bool was_further_than_max_distance_last_frame = false; Ref<VelocityTracker3D> velocity_tracker; diff --git a/scene/3d/physics/character_body_3d.cpp b/scene/3d/physics/character_body_3d.cpp index dda3ea9cca..e3815e8219 100644 --- a/scene/3d/physics/character_body_3d.cpp +++ b/scene/3d/physics/character_body_3d.cpp @@ -60,8 +60,13 @@ bool CharacterBody3D::move_and_slide() { // We need to check the platform_rid object still exists before accessing. // A valid RID is no guarantee that the object has not been deleted. - if (ObjectDB::get_instance(platform_object_id)) { - //this approach makes sure there is less delay between the actual body velocity and the one we saved + + // We can only perform the ObjectDB lifetime check on Object derived objects. + // Note that physics also creates RIDs for non-Object derived objects, these cannot + // be lifetime checked through ObjectDB, and therefore there is a still a vulnerability + // to dangling RIDs (access after free) in this scenario. + if (platform_object_id.is_null() || ObjectDB::get_instance(platform_object_id)) { + // This approach makes sure there is less delay between the actual body velocity and the one we saved. bs = PhysicsServer3D::get_singleton()->body_get_direct_state(platform_rid); } diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index cdc85d2b2d..a96417738f 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -1139,7 +1139,11 @@ void AnimationNodeTransition::remove_input(int p_index) { bool AnimationNodeTransition::set_input_name(int p_input, const String &p_name) { pending_update = true; - return AnimationNode::set_input_name(p_input, p_name); + if (!AnimationNode::set_input_name(p_input, p_name)) { + return false; + } + emit_signal(SNAME("tree_changed")); // For updating enum options. + return true; } void AnimationNodeTransition::set_input_as_auto_advance(int p_input, bool p_enable) { diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index c3287035ff..635228670d 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -831,6 +831,9 @@ void CodeEdit::_cut_internal(int p_caret) { delete_selection(p_caret); return; } + if (!is_empty_selection_clipboard_enabled()) { + return; + } if (p_caret == -1) { delete_lines(); } else { diff --git a/scene/gui/color_mode.h b/scene/gui/color_mode.h index 84e9d4542d..94193ccf74 100644 --- a/scene/gui/color_mode.h +++ b/scene/gui/color_mode.h @@ -50,14 +50,14 @@ public: virtual Color get_color() const = 0; - virtual void _value_changed(){}; + virtual void _value_changed() {} virtual void slider_draw(int p_which) = 0; virtual bool apply_theme() const { return false; } virtual ColorPicker::PickerShapeType get_shape_override() const { return ColorPicker::SHAPE_MAX; } ColorMode(ColorPicker *p_color_picker); - virtual ~ColorMode(){}; + virtual ~ColorMode() {} }; class ColorModeHSV : public ColorMode { @@ -81,7 +81,7 @@ public: virtual void slider_draw(int p_which) override; ColorModeHSV(ColorPicker *p_color_picker) : - ColorMode(p_color_picker){}; + ColorMode(p_color_picker) {} }; class ColorModeRGB : public ColorMode { @@ -100,7 +100,7 @@ public: virtual void slider_draw(int p_which) override; ColorModeRGB(ColorPicker *p_color_picker) : - ColorMode(p_color_picker){}; + ColorMode(p_color_picker) {} }; class ColorModeRAW : public ColorMode { @@ -122,7 +122,7 @@ public: virtual bool apply_theme() const override; ColorModeRAW(ColorPicker *p_color_picker) : - ColorMode(p_color_picker){}; + ColorMode(p_color_picker) {} }; class ColorModeOKHSL : public ColorMode { @@ -147,9 +147,9 @@ public: virtual ColorPicker::PickerShapeType get_shape_override() const override { return ColorPicker::SHAPE_OKHSL_CIRCLE; } ColorModeOKHSL(ColorPicker *p_color_picker) : - ColorMode(p_color_picker){}; + ColorMode(p_color_picker) {} - ~ColorModeOKHSL(){}; + ~ColorModeOKHSL() {} }; #endif // COLOR_MODE_H diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index ae709cf7a4..43782409a8 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -2764,6 +2764,8 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("select", "from", "to"), &LineEdit::select, DEFVAL(0), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("select_all"), &LineEdit::select_all); ClassDB::bind_method(D_METHOD("deselect"), &LineEdit::deselect); + ClassDB::bind_method(D_METHOD("has_undo"), &LineEdit::has_undo); + ClassDB::bind_method(D_METHOD("has_redo"), &LineEdit::has_redo); ClassDB::bind_method(D_METHOD("has_selection"), &LineEdit::has_selection); ClassDB::bind_method(D_METHOD("get_selected_text"), &LineEdit::get_selected_text); ClassDB::bind_method(D_METHOD("get_selection_from_column"), &LineEdit::get_selection_from_column); diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index f1902bade4..2211bd76fc 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -58,7 +58,7 @@ Size2 ScrollContainer::get_minimum_size() const { if (horizontal_scroll_mode == SCROLL_MODE_DISABLED) { min_size.x = largest_child_min_size.x; - bool v_scroll_show = vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (vertical_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.y > size.y); + bool v_scroll_show = vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || vertical_scroll_mode == SCROLL_MODE_RESERVE || (vertical_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.y > size.y); if (v_scroll_show && v_scroll->get_parent() == this) { min_size.x += v_scroll->get_minimum_size().x; } @@ -66,7 +66,7 @@ Size2 ScrollContainer::get_minimum_size() const { if (vertical_scroll_mode == SCROLL_MODE_DISABLED) { min_size.y = largest_child_min_size.y; - bool h_scroll_show = horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (horizontal_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.x > size.x); + bool h_scroll_show = horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || horizontal_scroll_mode == SCROLL_MODE_RESERVE || (horizontal_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.x > size.x); if (h_scroll_show && h_scroll->get_parent() == this) { min_size.y += h_scroll->get_minimum_size().y; } @@ -92,6 +92,15 @@ void ScrollContainer::_cancel_drag() { } } +bool ScrollContainer::_is_h_scroll_visible() const { + // Scrolls may have been moved out for reasons. + return h_scroll->is_visible() && h_scroll->get_parent() == this; +} + +bool ScrollContainer::_is_v_scroll_visible() const { + return v_scroll->is_visible() && v_scroll->get_parent() == this; +} + void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) { ERR_FAIL_COND(p_gui_input.is_null()); @@ -298,11 +307,11 @@ void ScrollContainer::_reposition_children() { ofs += theme_cache.panel_style->get_offset(); bool rtl = is_layout_rtl(); - if (h_scroll->is_visible_in_tree() && h_scroll->get_parent() == this) { //scrolls may have been moved out for reasons + if (_is_h_scroll_visible() || horizontal_scroll_mode == SCROLL_MODE_RESERVE) { size.y -= h_scroll->get_minimum_size().y; } - if (v_scroll->is_visible_in_tree() && v_scroll->get_parent() == this) { //scrolls may have been moved out for reasons + if (_is_v_scroll_visible() || vertical_scroll_mode == SCROLL_MODE_RESERVE) { size.x -= v_scroll->get_minimum_size().x; } @@ -324,7 +333,7 @@ void ScrollContainer::_reposition_children() { r.size.height = MAX(size.height, minsize.height); } r.position += ofs; - if (rtl && v_scroll->is_visible_in_tree() && v_scroll->get_parent() == this) { + if (rtl && _is_v_scroll_visible()) { r.position.x += v_scroll->get_minimum_size().x; } r.position = r.position.floor(); @@ -436,14 +445,14 @@ void ScrollContainer::update_scrollbars() { Size2 hmin = h_scroll->get_combined_minimum_size(); Size2 vmin = v_scroll->get_combined_minimum_size(); - h_scroll->set_visible(horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (horizontal_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.width > size.width)); - v_scroll->set_visible(vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (vertical_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.height > size.height)); + h_scroll->set_visible(horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || ((horizontal_scroll_mode == SCROLL_MODE_AUTO || horizontal_scroll_mode == SCROLL_MODE_RESERVE) && largest_child_min_size.width > size.width)); + v_scroll->set_visible(vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || ((vertical_scroll_mode == SCROLL_MODE_AUTO || vertical_scroll_mode == SCROLL_MODE_RESERVE) && largest_child_min_size.height > size.height)); h_scroll->set_max(largest_child_min_size.width); - h_scroll->set_page((v_scroll->is_visible() && v_scroll->get_parent() == this) ? size.width - vmin.width : size.width); + h_scroll->set_page(_is_v_scroll_visible() ? size.width - vmin.width : size.width); v_scroll->set_max(largest_child_min_size.height); - v_scroll->set_page((h_scroll->is_visible() && h_scroll->get_parent() == this) ? size.height - hmin.height : size.height); + v_scroll->set_page(_is_h_scroll_visible() ? size.height - hmin.height : size.height); // Avoid scrollbar overlapping. _updating_scrollbars = true; @@ -603,14 +612,15 @@ void ScrollContainer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_vertical", PROPERTY_HINT_NONE, "suffix:px"), "set_v_scroll", "get_v_scroll"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scroll_horizontal_custom_step", PROPERTY_HINT_RANGE, "-1,4096,suffix:px"), "set_horizontal_custom_step", "get_horizontal_custom_step"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scroll_vertical_custom_step", PROPERTY_HINT_RANGE, "-1,4096,suffix:px"), "set_vertical_custom_step", "get_vertical_custom_step"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "horizontal_scroll_mode", PROPERTY_HINT_ENUM, "Disabled,Auto,Always Show,Never Show"), "set_horizontal_scroll_mode", "get_horizontal_scroll_mode"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "vertical_scroll_mode", PROPERTY_HINT_ENUM, "Disabled,Auto,Always Show,Never Show"), "set_vertical_scroll_mode", "get_vertical_scroll_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "horizontal_scroll_mode", PROPERTY_HINT_ENUM, "Disabled,Auto,Always Show,Never Show,Reserve"), "set_horizontal_scroll_mode", "get_horizontal_scroll_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "vertical_scroll_mode", PROPERTY_HINT_ENUM, "Disabled,Auto,Always Show,Never Show,Reserve"), "set_vertical_scroll_mode", "get_vertical_scroll_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_deadzone"), "set_deadzone", "get_deadzone"); BIND_ENUM_CONSTANT(SCROLL_MODE_DISABLED); BIND_ENUM_CONSTANT(SCROLL_MODE_AUTO); BIND_ENUM_CONSTANT(SCROLL_MODE_SHOW_ALWAYS); BIND_ENUM_CONSTANT(SCROLL_MODE_SHOW_NEVER); + BIND_ENUM_CONSTANT(SCROLL_MODE_RESERVE); BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ScrollContainer, panel_style, "panel"); diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h index 02146618cd..afd3c8bd57 100644 --- a/scene/gui/scroll_container.h +++ b/scene/gui/scroll_container.h @@ -44,6 +44,7 @@ public: SCROLL_MODE_AUTO, SCROLL_MODE_SHOW_ALWAYS, SCROLL_MODE_SHOW_NEVER, + SCROLL_MODE_RESERVE, }; private: @@ -75,6 +76,9 @@ private: void _cancel_drag(); + bool _is_h_scroll_visible() const; + bool _is_v_scroll_visible() const; + protected: Size2 get_minimum_size() const override; diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 6e533aa5ab..eb9616c939 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -267,10 +267,14 @@ void TabContainer::_repaint() { Vector<Control *> controls = _get_tab_controls(); int current = get_current_tab(); + // Move the TabBar to the top or bottom. + // Don't change the left and right offsets since the TabBar will resize and may change tab offset. if (tabs_position == POSITION_BOTTOM) { - tab_bar->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE); + tab_bar->set_anchor_and_offset(SIDE_BOTTOM, 1.0, 0.0); + tab_bar->set_anchor_and_offset(SIDE_TOP, 1.0, -_get_tab_height()); } else { - tab_bar->set_anchors_and_offsets_preset(PRESET_TOP_WIDE); + tab_bar->set_anchor_and_offset(SIDE_BOTTOM, 0.0, _get_tab_height()); + tab_bar->set_anchor_and_offset(SIDE_TOP, 0.0, 0.0); } updating_visibility = true; @@ -299,7 +303,6 @@ void TabContainer::_repaint() { } updating_visibility = false; - _update_margins(); update_minimum_size(); } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 888e680219..0e8d76d294 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1265,7 +1265,7 @@ void TextEdit::_notification(int p_what) { } if (!clipped && lookup_symbol_word.length() != 0) { // Highlight word - if (is_ascii_alphabet_char(lookup_symbol_word[0]) || lookup_symbol_word[0] == '_' || lookup_symbol_word[0] == '.') { + if (is_unicode_identifier_start(lookup_symbol_word[0]) || lookup_symbol_word[0] == '.') { Color highlight_underline_color = !editable ? theme_cache.font_readonly_color : theme_cache.font_color; int lookup_symbol_word_col = _get_column_pos_of_word(lookup_symbol_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0); int lookup_symbol_word_len = lookup_symbol_word.length(); @@ -3367,6 +3367,14 @@ bool TextEdit::is_middle_mouse_paste_enabled() const { return middle_mouse_paste_enabled; } +void TextEdit::set_empty_selection_clipboard_enabled(bool p_enabled) { + empty_selection_clipboard_enabled = p_enabled; +} + +bool TextEdit::is_empty_selection_clipboard_enabled() const { + return empty_selection_clipboard_enabled; +} + // Text manipulation void TextEdit::clear() { setting_text = true; @@ -6569,6 +6577,9 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_middle_mouse_paste_enabled", "enabled"), &TextEdit::set_middle_mouse_paste_enabled); ClassDB::bind_method(D_METHOD("is_middle_mouse_paste_enabled"), &TextEdit::is_middle_mouse_paste_enabled); + ClassDB::bind_method(D_METHOD("set_empty_selection_clipboard_enabled", "enabled"), &TextEdit::set_empty_selection_clipboard_enabled); + ClassDB::bind_method(D_METHOD("is_empty_selection_clipboard_enabled"), &TextEdit::is_empty_selection_clipboard_enabled); + // Text manipulation ClassDB::bind_method(D_METHOD("clear"), &TextEdit::clear); @@ -6962,6 +6973,7 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_and_drop_selection_enabled"), "set_drag_and_drop_selection_enabled", "is_drag_and_drop_selection_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled"), "set_middle_mouse_paste_enabled", "is_middle_mouse_paste_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "empty_selection_clipboard_enabled"), "set_empty_selection_clipboard_enabled", "is_empty_selection_clipboard_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_mode", PROPERTY_HINT_ENUM, "None,Boundary"), "set_line_wrapping_mode", "get_line_wrapping_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Arbitrary:1,Word:2,Word (Smart):3"), "set_autowrap_mode", "get_autowrap_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "indent_wrapped_lines"), "set_indent_wrapped_lines", "is_indent_wrapped_lines"); @@ -7216,6 +7228,10 @@ void TextEdit::_cut_internal(int p_caret) { return; } + if (!empty_selection_clipboard_enabled) { + return; + } + // Remove full lines. begin_complex_operation(); begin_multicaret_edit(); @@ -7246,6 +7262,10 @@ void TextEdit::_copy_internal(int p_caret) { return; } + if (!empty_selection_clipboard_enabled) { + return; + } + // Copy full lines. StringBuilder clipboard; Vector<Point2i> line_ranges; diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index c5f838020b..94b105d486 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -319,6 +319,7 @@ private: bool shortcut_keys_enabled = true; bool virtual_keyboard_enabled = true; bool middle_mouse_paste_enabled = true; + bool empty_selection_clipboard_enabled = true; // Overridable actions. String cut_copy_line = ""; @@ -770,6 +771,9 @@ public: void set_middle_mouse_paste_enabled(bool p_enabled); bool is_middle_mouse_paste_enabled() const; + void set_empty_selection_clipboard_enabled(bool p_enabled); + bool is_empty_selection_clipboard_enabled() const; + // Text manipulation void clear(); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 858fc2246b..d921cc5b67 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -111,6 +111,7 @@ void Node::_notification(int p_notification) { data.auto_translate_mode = AUTO_TRANSLATE_MODE_ALWAYS; } data.is_auto_translate_dirty = true; + data.is_translation_domain_dirty = true; #ifdef TOOLS_ENABLED // Don't translate UI elements when they're being edited. @@ -1320,6 +1321,51 @@ bool Node::can_auto_translate() const { return data.is_auto_translating; } +StringName Node::get_translation_domain() const { + ERR_READ_THREAD_GUARD_V(StringName()); + + if (data.is_translation_domain_inherited && data.is_translation_domain_dirty) { + const_cast<Node *>(this)->_translation_domain = data.parent ? data.parent->get_translation_domain() : StringName(); + data.is_translation_domain_dirty = false; + } + return _translation_domain; +} + +void Node::set_translation_domain(const StringName &p_domain) { + ERR_THREAD_GUARD + + if (!data.is_translation_domain_inherited && _translation_domain == p_domain) { + return; + } + + _translation_domain = p_domain; + data.is_translation_domain_inherited = false; + data.is_translation_domain_dirty = false; + _propagate_translation_domain_dirty(); +} + +void Node::set_translation_domain_inherited() { + ERR_THREAD_GUARD + + if (data.is_translation_domain_inherited) { + return; + } + data.is_translation_domain_inherited = true; + data.is_translation_domain_dirty = true; + _propagate_translation_domain_dirty(); +} + +void Node::_propagate_translation_domain_dirty() { + for (KeyValue<StringName, Node *> &K : data.children) { + Node *child = K.value; + if (child->data.is_translation_domain_inherited) { + child->data.is_translation_domain_dirty = true; + child->_propagate_translation_domain_dirty(); + } + } + notification(NOTIFICATION_TRANSLATION_CHANGED); +} + StringName Node::get_name() const { return data.name; } @@ -3610,6 +3656,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("set_auto_translate_mode", "mode"), &Node::set_auto_translate_mode); ClassDB::bind_method(D_METHOD("get_auto_translate_mode"), &Node::get_auto_translate_mode); + ClassDB::bind_method(D_METHOD("set_translation_domain_inherited"), &Node::set_translation_domain_inherited); ClassDB::bind_method(D_METHOD("get_window"), &Node::get_window); ClassDB::bind_method(D_METHOD("get_last_exclusive_window"), &Node::get_last_exclusive_window); @@ -3972,4 +4019,9 @@ bool Node::is_connected(const StringName &p_signal, const Callable &p_callable) return Object::is_connected(p_signal, p_callable); } +bool Node::has_connections(const StringName &p_signal) const { + ERR_THREAD_GUARD_V(false); + return Object::has_connections(p_signal); +} + #endif diff --git a/scene/main/node.h b/scene/main/node.h index dc65513fca..298cbc7e59 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -255,6 +255,9 @@ private: mutable bool is_auto_translating = true; mutable bool is_auto_translate_dirty = true; + mutable bool is_translation_domain_inherited = true; + mutable bool is_translation_domain_dirty = true; + mutable NodePath *path_cache = nullptr; } data; @@ -281,6 +284,7 @@ private: void _propagate_physics_interpolation_reset_requested(bool p_requested); void _propagate_process_owner(Node *p_owner, int p_pause_notification, int p_enabled_notification); void _propagate_groups_dirty(); + void _propagate_translation_domain_dirty(); Array _get_node_and_resource(const NodePath &p_path); void _duplicate_properties(const Node *p_root, const Node *p_original, Node *p_copy, int p_flags) const; @@ -735,6 +739,10 @@ public: AutoTranslateMode get_auto_translate_mode() const; bool can_auto_translate() const; + virtual StringName get_translation_domain() const override; + virtual void set_translation_domain(const StringName &p_domain) override; + void set_translation_domain_inherited(); + _FORCE_INLINE_ String atr(const String p_message, const StringName p_context = "") const { return can_auto_translate() ? tr(p_message, p_context) : p_message; } _FORCE_INLINE_ String atr_n(const String p_message, const StringName &p_message_plural, int p_n, const StringName p_context = "") const { return can_auto_translate() ? tr_n(p_message, p_message_plural, p_n, p_context) : p_message; } @@ -789,6 +797,7 @@ public: virtual Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0) override; virtual void disconnect(const StringName &p_signal, const Callable &p_callable) override; virtual bool is_connected(const StringName &p_signal, const Callable &p_callable) const override; + virtual bool has_connections(const StringName &p_signal) const override; #endif Node(); ~Node(); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index acf4f67673..ba69f8cc45 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -4671,6 +4671,7 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d); ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d); + ClassDB::bind_method(D_METHOD("get_audio_listener_2d"), &Viewport::get_audio_listener_2d); ClassDB::bind_method(D_METHOD("get_camera_2d"), &Viewport::get_camera_2d); #ifndef _3D_DISABLED @@ -4681,6 +4682,7 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_own_world_3d", "enable"), &Viewport::set_use_own_world_3d); ClassDB::bind_method(D_METHOD("is_using_own_world_3d"), &Viewport::is_using_own_world_3d); + ClassDB::bind_method(D_METHOD("get_audio_listener_3d"), &Viewport::get_audio_listener_3d); ClassDB::bind_method(D_METHOD("get_camera_3d"), &Viewport::get_camera_3d); ClassDB::bind_method(D_METHOD("set_as_audio_listener_3d", "enable"), &Viewport::set_as_audio_listener_3d); ClassDB::bind_method(D_METHOD("is_audio_listener_3d"), &Viewport::is_audio_listener_3d); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 76678e609a..09227e260f 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -117,6 +117,7 @@ #include "scene/resources/compressed_texture.h" #include "scene/resources/curve_texture.h" #include "scene/resources/environment.h" +#include "scene/resources/external_texture.h" #include "scene/resources/font.h" #include "scene/resources/gradient.h" #include "scene/resources/gradient_texture.h" @@ -926,6 +927,7 @@ void register_scene_types() { GDREGISTER_CLASS(GradientTexture2D); GDREGISTER_CLASS(AnimatedTexture); GDREGISTER_CLASS(CameraTexture); + GDREGISTER_CLASS(ExternalTexture); GDREGISTER_VIRTUAL_CLASS(TextureLayered); GDREGISTER_ABSTRACT_CLASS(ImageTextureLayered); GDREGISTER_VIRTUAL_CLASS(Texture3D); diff --git a/scene/resources/2d/tile_set.h b/scene/resources/2d/tile_set.h index 931495d020..15e1a16359 100644 --- a/scene/resources/2d/tile_set.h +++ b/scene/resources/2d/tile_set.h @@ -571,25 +571,25 @@ public: // Not exposed. virtual void set_tile_set(const TileSet *p_tile_set); TileSet *get_tile_set() const; - virtual void notify_tile_data_properties_should_change(){}; - virtual void add_occlusion_layer(int p_index){}; - virtual void move_occlusion_layer(int p_from_index, int p_to_pos){}; - virtual void remove_occlusion_layer(int p_index){}; - virtual void add_physics_layer(int p_index){}; - virtual void move_physics_layer(int p_from_index, int p_to_pos){}; - virtual void remove_physics_layer(int p_index){}; - virtual void add_terrain_set(int p_index){}; - virtual void move_terrain_set(int p_from_index, int p_to_pos){}; - virtual void remove_terrain_set(int p_index){}; - virtual void add_terrain(int p_terrain_set, int p_index){}; - virtual void move_terrain(int p_terrain_set, int p_from_index, int p_to_pos){}; - virtual void remove_terrain(int p_terrain_set, int p_index){}; - virtual void add_navigation_layer(int p_index){}; - virtual void move_navigation_layer(int p_from_index, int p_to_pos){}; - virtual void remove_navigation_layer(int p_index){}; - virtual void add_custom_data_layer(int p_index){}; - virtual void move_custom_data_layer(int p_from_index, int p_to_pos){}; - virtual void remove_custom_data_layer(int p_index){}; + virtual void notify_tile_data_properties_should_change() {} + virtual void add_occlusion_layer(int p_index) {} + virtual void move_occlusion_layer(int p_from_index, int p_to_pos) {} + virtual void remove_occlusion_layer(int p_index) {} + virtual void add_physics_layer(int p_index) {} + virtual void move_physics_layer(int p_from_index, int p_to_pos) {} + virtual void remove_physics_layer(int p_index) {} + virtual void add_terrain_set(int p_index) {} + virtual void move_terrain_set(int p_from_index, int p_to_pos) {} + virtual void remove_terrain_set(int p_index) {} + virtual void add_terrain(int p_terrain_set, int p_index) {} + virtual void move_terrain(int p_terrain_set, int p_from_index, int p_to_pos) {} + virtual void remove_terrain(int p_terrain_set, int p_index) {} + virtual void add_navigation_layer(int p_index) {} + virtual void move_navigation_layer(int p_from_index, int p_to_pos) {} + virtual void remove_navigation_layer(int p_index) {} + virtual void add_custom_data_layer(int p_index) {} + virtual void move_custom_data_layer(int p_from_index, int p_to_pos) {} + virtual void remove_custom_data_layer(int p_index) {} virtual void reset_state() override; // Tiles. diff --git a/scene/resources/3d/primitive_meshes.h b/scene/resources/3d/primitive_meshes.h index fc2489923a..85f46a482a 100644 --- a/scene/resources/3d/primitive_meshes.h +++ b/scene/resources/3d/primitive_meshes.h @@ -77,7 +77,7 @@ protected: Vector2 get_uv2_scale(Vector2 p_margin_scale = Vector2(1.0, 1.0)) const; float get_lightmap_texel_size() const; - virtual void _update_lightmap_size(){}; + virtual void _update_lightmap_size() {} void _on_settings_changed(); @@ -541,7 +541,7 @@ private: Vector2 point; bool sharp = false; - ContourPoint(){}; + ContourPoint() {} ContourPoint(const Vector2 &p_pt, bool p_sharp) { point = p_pt; sharp = p_sharp; @@ -551,7 +551,7 @@ private: struct ContourInfo { real_t length = 0.0; bool ccw = true; - ContourInfo(){}; + ContourInfo() {} ContourInfo(real_t p_len, bool p_ccw) { length = p_len; ccw = p_ccw; diff --git a/scene/resources/camera_attributes.h b/scene/resources/camera_attributes.h index 0f819134e2..de57b0ce8f 100644 --- a/scene/resources/camera_attributes.h +++ b/scene/resources/camera_attributes.h @@ -53,7 +53,7 @@ protected: float auto_exposure_max = 64.0; float auto_exposure_speed = 0.5; float auto_exposure_scale = 0.4; - virtual void _update_auto_exposure(){}; + virtual void _update_auto_exposure() {} public: virtual RID get_rid() const override; diff --git a/scene/resources/external_texture.cpp b/scene/resources/external_texture.cpp new file mode 100644 index 0000000000..0552bbd081 --- /dev/null +++ b/scene/resources/external_texture.cpp @@ -0,0 +1,89 @@ +/**************************************************************************/ +/* external_texture.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "external_texture.h" + +void ExternalTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &ExternalTexture::set_size); + ClassDB::bind_method(D_METHOD("get_external_texture_id"), &ExternalTexture::get_external_texture_id); + ClassDB::bind_method(D_METHOD("set_external_buffer_id", "external_buffer_id"), &ExternalTexture::set_external_buffer_id); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); +} + +uint64_t ExternalTexture::get_external_texture_id() const { + return RenderingServer::get_singleton()->texture_get_native_handle(texture); +} + +void ExternalTexture::set_size(const Size2 &p_size) { + if (p_size.width > 0 && p_size.height > 0 && p_size != size) { + size = p_size; + RenderingServer::get_singleton()->texture_external_update(texture, size.width, size.height, external_buffer); + emit_changed(); + } +} + +Size2 ExternalTexture::get_size() const { + return size; +} + +void ExternalTexture::set_external_buffer_id(uint64_t p_external_buffer) { + if (p_external_buffer != external_buffer) { + external_buffer = p_external_buffer; + RenderingServer::get_singleton()->texture_external_update(texture, size.width, size.height, external_buffer); + } +} + +int ExternalTexture::get_width() const { + return size.width; +} + +int ExternalTexture::get_height() const { + return size.height; +} + +bool ExternalTexture::has_alpha() const { + return false; +} + +RID ExternalTexture::get_rid() const { + return texture; +} + +ExternalTexture::ExternalTexture() { + texture = RenderingServer::get_singleton()->texture_external_create(size.width, size.height); +} + +ExternalTexture::~ExternalTexture() { + if (texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); + RenderingServer::get_singleton()->free(texture); + } +} diff --git a/scene/resources/external_texture.h b/scene/resources/external_texture.h new file mode 100644 index 0000000000..96bcd8d0fe --- /dev/null +++ b/scene/resources/external_texture.h @@ -0,0 +1,66 @@ +/**************************************************************************/ +/* external_texture.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 EXTERNAL_TEXTURE_H +#define EXTERNAL_TEXTURE_H + +#include "scene/resources/texture.h" + +// External textures as defined by OES_EGL_image_external (GLES) or VK_ANDROID_external_memory_android_hardware_buffer (Vulkan). +class ExternalTexture : public Texture2D { + GDCLASS(ExternalTexture, Texture2D); + +private: + RID texture; + Size2 size = Size2(256, 256); + uint64_t external_buffer = 0; + +protected: + static void _bind_methods(); + +public: + uint64_t get_external_texture_id() const; + + virtual Size2 get_size() const override; + void set_size(const Size2 &p_size); + + void set_external_buffer_id(uint64_t p_external_buffer); + + virtual int get_width() const override; + virtual int get_height() const override; + + virtual RID get_rid() const override; + virtual bool has_alpha() const override; + + ExternalTexture(); + ~ExternalTexture(); +}; + +#endif // EXTERNAL_TEXTURE_H diff --git a/scu_builders.py b/scu_builders.py index fc5461196f..7fc0c15b2d 100644 --- a/scu_builders.py +++ b/scu_builders.py @@ -322,6 +322,8 @@ def generate_scu_files(max_includes_per_scu): process_folder(["modules/openxr"], ["register_types"]) process_folder(["modules/openxr/action_map"]) process_folder(["modules/openxr/editor"]) + process_folder(["modules/godot_physics_3d"]) + process_folder(["modules/godot_physics_3d/joints"]) process_folder(["modules/csg"]) process_folder(["modules/gdscript"]) @@ -349,8 +351,6 @@ def generate_scu_files(max_includes_per_scu): process_folder(["servers/rendering/renderer_rd/environment"]) process_folder(["servers/rendering/renderer_rd/storage_rd"]) process_folder(["servers/physics_2d"]) - process_folder(["servers/physics_3d"]) - process_folder(["servers/physics_3d/joints"]) process_folder(["servers/audio"]) process_folder(["servers/audio/effects"]) diff --git a/servers/SCsub b/servers/SCsub index 736bed68ec..472cb096ab 100644 --- a/servers/SCsub +++ b/servers/SCsub @@ -28,7 +28,6 @@ SConscript("text/SCsub") SConscript("physics_2d/SCsub") if not env["disable_3d"]: - SConscript("physics_3d/SCsub") env.add_source_files(env.servers_sources, "physics_server_3d.cpp") env.add_source_files(env.servers_sources, "physics_server_3d_wrap_mt.cpp") SConscript("xr/SCsub") diff --git a/servers/physics_3d/SCsub b/servers/physics_3d/SCsub deleted file mode 100644 index df7b521693..0000000000 --- a/servers/physics_3d/SCsub +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python - -Import("env") - -env.add_source_files(env.servers_sources, "*.cpp") - -SConscript("joints/SCsub") diff --git a/servers/physics_3d/joints/SCsub b/servers/physics_3d/joints/SCsub deleted file mode 100644 index 86681f9c74..0000000000 --- a/servers/physics_3d/joints/SCsub +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env python - -Import("env") - -env.add_source_files(env.servers_sources, "*.cpp") diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index 698805bbdd..ee48151863 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -1201,7 +1201,9 @@ String PhysicsServer3DManager::get_server_name(int p_id) { } PhysicsServer3D *PhysicsServer3DManager::new_default_server() { - ERR_FAIL_COND_V(default_server_id == -1, nullptr); + if (default_server_id == -1) { + return nullptr; + } Variant ret; Callable::CallError ce; physics_servers[default_server_id].create_callback.callp(nullptr, 0, ret, ce); diff --git a/servers/physics_server_3d_dummy.h b/servers/physics_server_3d_dummy.h new file mode 100644 index 0000000000..209a541fea --- /dev/null +++ b/servers/physics_server_3d_dummy.h @@ -0,0 +1,436 @@ +/**************************************************************************/ +/* physics_server_3d_dummy.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 PHYSICS_SERVER_3D_DUMMY_H +#define PHYSICS_SERVER_3D_DUMMY_H + +#include "servers/physics_server_3d.h" + +class PhysicsDirectBodyState3DDummy : public PhysicsDirectBodyState3D { + GDCLASS(PhysicsDirectBodyState3DDummy, PhysicsDirectBodyState3D); + + PhysicsDirectSpaceState3D *space_state_dummy = nullptr; + +public: + virtual Vector3 get_total_gravity() const override { return Vector3(); } + virtual real_t get_total_angular_damp() const override { return 0; } + virtual real_t get_total_linear_damp() const override { return 0; } + + virtual Vector3 get_center_of_mass() const override { return Vector3(); } + virtual Vector3 get_center_of_mass_local() const override { return Vector3(); } + virtual Basis get_principal_inertia_axes() const override { return Basis(); } + virtual real_t get_inverse_mass() const override { return 0; } + virtual Vector3 get_inverse_inertia() const override { return Vector3(); } + virtual Basis get_inverse_inertia_tensor() const override { return Basis(); } + + virtual void set_linear_velocity(const Vector3 &p_velocity) override {} + virtual Vector3 get_linear_velocity() const override { return Vector3(); } + + virtual void set_angular_velocity(const Vector3 &p_velocity) override {} + virtual Vector3 get_angular_velocity() const override { return Vector3(); } + + virtual void set_transform(const Transform3D &p_transform) override {} + virtual Transform3D get_transform() const override { return Transform3D(); } + + virtual Vector3 get_velocity_at_local_position(const Vector3 &p_position) const override { return Vector3(); } + + virtual void apply_central_impulse(const Vector3 &p_impulse) override {} + virtual void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3()) override {} + virtual void apply_torque_impulse(const Vector3 &p_impulse) override {} + + virtual void apply_central_force(const Vector3 &p_force) override {} + virtual void apply_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override {} + virtual void apply_torque(const Vector3 &p_torque) override {} + + virtual void add_constant_central_force(const Vector3 &p_force) override {} + virtual void add_constant_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override {} + virtual void add_constant_torque(const Vector3 &p_torque) override {} + + virtual void set_constant_force(const Vector3 &p_force) override {} + virtual Vector3 get_constant_force() const override { return Vector3(); } + + virtual void set_constant_torque(const Vector3 &p_torque) override {} + virtual Vector3 get_constant_torque() const override { return Vector3(); } + + virtual void set_sleep_state(bool p_sleep) override {} + virtual bool is_sleeping() const override { return false; } + + virtual int get_contact_count() const override { return 0; } + + virtual Vector3 get_contact_local_position(int p_contact_idx) const override { return Vector3(); } + virtual Vector3 get_contact_local_normal(int p_contact_idx) const override { return Vector3(); } + virtual Vector3 get_contact_impulse(int p_contact_idx) const override { return Vector3(); } + virtual int get_contact_local_shape(int p_contact_idx) const override { return 0; } + virtual Vector3 get_contact_local_velocity_at_position(int p_contact_idx) const override { return Vector3(); } + + virtual RID get_contact_collider(int p_contact_idx) const override { return RID(); } + virtual Vector3 get_contact_collider_position(int p_contact_idx) const override { return Vector3(); } + virtual ObjectID get_contact_collider_id(int p_contact_idx) const override { return ObjectID(); } + virtual Object *get_contact_collider_object(int p_contact_idx) const override { return nullptr; } + virtual int get_contact_collider_shape(int p_contact_idx) const override { return 0; } + virtual Vector3 get_contact_collider_velocity_at_position(int p_contact_idx) const override { return Vector3(); } + + virtual real_t get_step() const override { return 0; } + virtual void integrate_forces() override {} + + virtual PhysicsDirectSpaceState3D *get_space_state() override { return space_state_dummy; } + + PhysicsDirectBodyState3DDummy(PhysicsDirectSpaceState3D *p_space_state_dummy) { + space_state_dummy = p_space_state_dummy; + } +}; + +class PhysicsDirectSpaceState3DDummy : public PhysicsDirectSpaceState3D { + GDCLASS(PhysicsDirectSpaceState3DDummy, PhysicsDirectSpaceState3D); + +public: + virtual bool intersect_ray(const RayParameters &p_parameters, RayResult &r_result) override { return false; } + + virtual int intersect_point(const PointParameters &p_parameters, ShapeResult *r_results, int p_result_max) override { return 0; } + + virtual int intersect_shape(const ShapeParameters &p_parameters, ShapeResult *r_results, int p_result_max) override { return 0; } + virtual bool cast_motion(const ShapeParameters &p_parameters, real_t &p_closest_safe, real_t &p_closest_unsafe, ShapeRestInfo *r_info = nullptr) override { return false; } + virtual bool collide_shape(const ShapeParameters &p_parameters, Vector3 *r_results, int p_result_max, int &r_result_count) override { return false; } + virtual bool rest_info(const ShapeParameters &p_parameters, ShapeRestInfo *r_info) override { return false; } + + virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const override { return Vector3(); } +}; + +class PhysicsServer3DDummy : public PhysicsServer3D { + GDCLASS(PhysicsServer3DDummy, PhysicsServer3D); + + PhysicsDirectBodyState3DDummy *body_state_dummy = nullptr; + PhysicsDirectSpaceState3DDummy *space_state_dummy = nullptr; + +public: + virtual RID world_boundary_shape_create() override { return RID(); } + virtual RID separation_ray_shape_create() override { return RID(); } + virtual RID sphere_shape_create() override { return RID(); } + virtual RID box_shape_create() override { return RID(); } + virtual RID capsule_shape_create() override { return RID(); } + virtual RID cylinder_shape_create() override { return RID(); } + virtual RID convex_polygon_shape_create() override { return RID(); } + virtual RID concave_polygon_shape_create() override { return RID(); } + virtual RID heightmap_shape_create() override { return RID(); } + virtual RID custom_shape_create() override { return RID(); } + + virtual void shape_set_data(RID p_shape, const Variant &p_data) override {} + virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias) override {} + + virtual ShapeType shape_get_type(RID p_shape) const override { return SHAPE_SPHERE; } + virtual Variant shape_get_data(RID p_shape) const override { return Variant(); } + + virtual void shape_set_margin(RID p_shape, real_t p_margin) override {} + virtual real_t shape_get_margin(RID p_shape) const override { return 0; } + + virtual real_t shape_get_custom_solver_bias(RID p_shape) const override { return 0; } + + /* SPACE API */ + + virtual RID space_create() override { return RID(); } + virtual void space_set_active(RID p_space, bool p_active) override {} + virtual bool space_is_active(RID p_space) const override { return false; } + + virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) override {} + virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const override { return 0; } + + virtual PhysicsDirectSpaceState3D *space_get_direct_state(RID p_space) override { return space_state_dummy; } + + virtual void space_set_debug_contacts(RID p_space, int p_max_contacts) override {} + virtual Vector<Vector3> space_get_contacts(RID p_space) const override { return Vector<Vector3>(); } + virtual int space_get_contact_count(RID p_space) const override { return 0; } + + /* AREA API */ + + virtual RID area_create() override { return RID(); } + + virtual void area_set_space(RID p_area, RID p_space) override {} + virtual RID area_get_space(RID p_area) const override { return RID(); } + + virtual void area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) override {} + virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) override {} + virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) override {} + + virtual int area_get_shape_count(RID p_area) const override { return 0; } + virtual RID area_get_shape(RID p_area, int p_shape_idx) const override { return RID(); } + virtual Transform3D area_get_shape_transform(RID p_area, int p_shape_idx) const override { return Transform3D(); } + + virtual void area_remove_shape(RID p_area, int p_shape_idx) override {} + virtual void area_clear_shapes(RID p_area) override {} + + virtual void area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) override {} + + virtual void area_attach_object_instance_id(RID p_area, ObjectID p_id) override {} + virtual ObjectID area_get_object_instance_id(RID p_area) const override { return ObjectID(); } + + virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) override {} + virtual void area_set_transform(RID p_area, const Transform3D &p_transform) override {} + + virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const override { return Variant(); } + virtual Transform3D area_get_transform(RID p_area) const override { return Transform3D(); } + + virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) override {} + virtual uint32_t area_get_collision_layer(RID p_area) const override { return 0; } + + virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override {} + virtual uint32_t area_get_collision_mask(RID p_area) const override { return 0; } + + virtual void area_set_monitorable(RID p_area, bool p_monitorable) override {} + + virtual void area_set_monitor_callback(RID p_area, const Callable &p_callback) override {} + virtual void area_set_area_monitor_callback(RID p_area, const Callable &p_callback) override {} + + virtual void area_set_ray_pickable(RID p_area, bool p_enable) override {} + + /* BODY API */ + + virtual RID body_create() override { return RID(); } + + virtual void body_set_space(RID p_body, RID p_space) override {} + virtual RID body_get_space(RID p_body) const override { return RID(); } + + virtual void body_set_mode(RID p_body, BodyMode p_mode) override {} + virtual BodyMode body_get_mode(RID p_body) const override { return BodyMode::BODY_MODE_STATIC; } + + virtual void body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) override {} + virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) override {} + virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) override {} + + virtual int body_get_shape_count(RID p_body) const override { return 0; } + virtual RID body_get_shape(RID p_body, int p_shape_idx) const override { return RID(); } + virtual Transform3D body_get_shape_transform(RID p_body, int p_shape_idx) const override { return Transform3D(); } + + virtual void body_remove_shape(RID p_body, int p_shape_idx) override {} + virtual void body_clear_shapes(RID p_body) override {} + + virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) override {} + + virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id) override {} + virtual ObjectID body_get_object_instance_id(RID p_body) const override { return ObjectID(); } + + virtual void body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) override {} + virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const override { return false; } + + virtual void body_set_collision_layer(RID p_body, uint32_t p_layer) override {} + virtual uint32_t body_get_collision_layer(RID p_body) const override { return 0; } + + virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override {} + virtual uint32_t body_get_collision_mask(RID p_body) const override { return 0; } + + virtual void body_set_collision_priority(RID p_body, real_t p_priority) override {} + virtual real_t body_get_collision_priority(RID p_body) const override { return 0; } + + virtual void body_set_user_flags(RID p_body, uint32_t p_flags) override {} + virtual uint32_t body_get_user_flags(RID p_body) const override { return 0; } + + virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) override {} + virtual Variant body_get_param(RID p_body, BodyParameter p_param) const override { return Variant(); } + + virtual void body_reset_mass_properties(RID p_body) override {} + + virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override {} + virtual Variant body_get_state(RID p_body, BodyState p_state) const override { return Variant(); } + + virtual void body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) override {} + virtual void body_apply_impulse(RID p_body, const Vector3 &p_impulse, const Vector3 &p_position = Vector3()) override {} + virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) override {} + + virtual void body_apply_central_force(RID p_body, const Vector3 &p_force) override {} + virtual void body_apply_force(RID p_body, const Vector3 &p_force, const Vector3 &p_position = Vector3()) override {} + virtual void body_apply_torque(RID p_body, const Vector3 &p_torque) override {} + + virtual void body_add_constant_central_force(RID p_body, const Vector3 &p_force) override {} + virtual void body_add_constant_force(RID p_body, const Vector3 &p_force, const Vector3 &p_position = Vector3()) override {} + virtual void body_add_constant_torque(RID p_body, const Vector3 &p_torque) override {} + + virtual void body_set_constant_force(RID p_body, const Vector3 &p_force) override {} + virtual Vector3 body_get_constant_force(RID p_body) const override { return Vector3(); } + + virtual void body_set_constant_torque(RID p_body, const Vector3 &p_torque) override {} + virtual Vector3 body_get_constant_torque(RID p_body) const override { return Vector3(); } + + virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) override {} + + virtual void body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock) override {} + virtual bool body_is_axis_locked(RID p_body, BodyAxis p_axis) const override { return false; } + + virtual void body_add_collision_exception(RID p_body, RID p_body_b) override {} + virtual void body_remove_collision_exception(RID p_body, RID p_body_b) override {} + virtual void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) override {} + + virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override {} + virtual int body_get_max_contacts_reported(RID p_body) const override { return 0; } + + virtual void body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) override {} + virtual real_t body_get_contacts_reported_depth_threshold(RID p_body) const override { return 0; } + + virtual void body_set_omit_force_integration(RID p_body, bool p_omit) override {} + virtual bool body_is_omitting_force_integration(RID p_body) const override { return false; } + + virtual void body_set_state_sync_callback(RID p_body, const Callable &p_callable) override {} + virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override {} + + virtual void body_set_ray_pickable(RID p_body, bool p_enable) override {} + + virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override { return body_state_dummy; } + + virtual bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override { return false; } + + /* SOFT BODY */ + + virtual RID soft_body_create() override { return RID(); } + + virtual void soft_body_update_rendering_server(RID p_body, PhysicsServer3DRenderingServerHandler *p_rendering_server_handler) override {} + + virtual void soft_body_set_space(RID p_body, RID p_space) override {} + virtual RID soft_body_get_space(RID p_body) const override { return RID(); } + + virtual void soft_body_set_mesh(RID p_body, RID p_mesh) override {} + + virtual AABB soft_body_get_bounds(RID p_body) const override { return AABB(); } + + virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) override {} + virtual uint32_t soft_body_get_collision_layer(RID p_body) const override { return 0; } + + virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) override {} + virtual uint32_t soft_body_get_collision_mask(RID p_body) const override { return 0; } + + virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) override {} + virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) override {} + virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) override {} + + virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override {} + virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const override { return Variant(); } + + virtual void soft_body_set_transform(RID p_body, const Transform3D &p_transform) override {} + + virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override {} + + virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) override {} + virtual int soft_body_get_simulation_precision(RID p_body) const override { return 0; } + + virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) override {} + virtual real_t soft_body_get_total_mass(RID p_body) const override { return 0; } + + virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) override {} + virtual real_t soft_body_get_linear_stiffness(RID p_body) const override { return 0; } + + virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) override {} + virtual real_t soft_body_get_pressure_coefficient(RID p_body) const override { return 0; } + + virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) override {} + virtual real_t soft_body_get_damping_coefficient(RID p_body) const override { return 0; } + + virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) override {} + virtual real_t soft_body_get_drag_coefficient(RID p_body) const override { return 0; } + + virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) override {} + virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const override { return Vector3(); } + + virtual void soft_body_remove_all_pinned_points(RID p_body) override {} + virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) override {} + virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const override { return false; } + + /* JOINT API */ + + virtual RID joint_create() override { return RID(); } + + virtual void joint_clear(RID p_joint) override {} + + virtual JointType joint_get_type(RID p_joint) const override { return JointType::JOINT_TYPE_PIN; } + + virtual void joint_set_solver_priority(RID p_joint, int p_priority) override {} + virtual int joint_get_solver_priority(RID p_joint) const override { return 0; } + + virtual void joint_disable_collisions_between_bodies(RID p_joint, bool p_disable) override {} + virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const override { return false; } + + virtual void joint_make_pin(RID p_joint, RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) override {} + + virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) override {} + virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const override { return 0; } + + virtual void pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) override {} + virtual Vector3 pin_joint_get_local_a(RID p_joint) const override { return Vector3(); } + + virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) override {} + virtual Vector3 pin_joint_get_local_b(RID p_joint) const override { return Vector3(); } + + virtual void joint_make_hinge(RID p_joint, RID p_body_A, const Transform3D &p_hinge_A, RID p_body_B, const Transform3D &p_hinge_B) override {} + virtual void joint_make_hinge_simple(RID p_joint, RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) override {} + + virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) override {} + virtual real_t hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const override { return 0; } + + virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_enabled) override {} + virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const override { return false; } + + virtual void joint_make_slider(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override {} + + virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) override {} + virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const override { return 0; } + + virtual void joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override {} + + virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) override {} + virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const override { return 0; } + + virtual void joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override {} + + virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, real_t p_value) override {} + virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) const override { return 0; } + + virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable) override {} + virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) const override { return false; } + + /* MISC */ + + virtual void free(RID p_rid) override {} + + virtual void set_active(bool p_active) override {} + virtual void init() override { + space_state_dummy = memnew(PhysicsDirectSpaceState3DDummy); + body_state_dummy = memnew(PhysicsDirectBodyState3DDummy(space_state_dummy)); + } + virtual void step(real_t p_step) override {} + virtual void sync() override {} + virtual void flush_queries() override {} + virtual void end_sync() override {} + virtual void finish() override { + memdelete(body_state_dummy); + memdelete(space_state_dummy); + } + + virtual bool is_flushing_queries() const override { return false; } + + virtual int get_process_info(ProcessInfo p_info) override { return 0; } +}; + +#endif // PHYSICS_SERVER_3D_DUMMY_H diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index fc2aae10c7..b23c77aa0a 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -89,8 +89,8 @@ // 3D physics and navigation (3D navigation is needed for 2D). #include "navigation_server_3d.h" #ifndef _3D_DISABLED -#include "physics_3d/godot_physics_server_3d.h" #include "physics_server_3d.h" +#include "physics_server_3d_dummy.h" #include "physics_server_3d_wrap_mt.h" #include "servers/extensions/physics_server_3d_extension.h" #include "xr/xr_body_tracker.h" @@ -106,16 +106,8 @@ ShaderTypes *shader_types = nullptr; #ifndef _3D_DISABLED -static PhysicsServer3D *_createGodotPhysics3DCallback() { -#ifdef THREADS_ENABLED - bool using_threads = GLOBAL_GET("physics/3d/run_on_separate_thread"); -#else - bool using_threads = false; -#endif - - PhysicsServer3D *physics_server_3d = memnew(GodotPhysicsServer3D(using_threads)); - - return memnew(PhysicsServer3DWrapMT(physics_server_3d, using_threads)); +static PhysicsServer3D *_create_dummy_physics_server_3d() { + return memnew(PhysicsServer3DDummy); } #endif // _3D_DISABLED @@ -323,8 +315,7 @@ void register_server_types() { GLOBAL_DEF(PropertyInfo(Variant::STRING, PhysicsServer3DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"), "DEFAULT"); - PhysicsServer3DManager::get_singleton()->register_server("GodotPhysics3D", callable_mp_static(_createGodotPhysics3DCallback)); - PhysicsServer3DManager::get_singleton()->set_default_server("GodotPhysics3D"); + PhysicsServer3DManager::get_singleton()->register_server("Dummy", callable_mp_static(_create_dummy_physics_server_3d)); GDREGISTER_ABSTRACT_CLASS(XRInterface); GDREGISTER_CLASS(XRVRS); diff --git a/servers/rendering/dummy/storage/material_storage.h b/servers/rendering/dummy/storage/material_storage.h index 4a956cd25d..e4c58474e2 100644 --- a/servers/rendering/dummy/storage/material_storage.h +++ b/servers/rendering/dummy/storage/material_storage.h @@ -97,7 +97,7 @@ public: /* MATERIAL API */ virtual RID material_allocate() override { return RID(); } virtual void material_initialize(RID p_rid) override {} - virtual void material_free(RID p_rid) override{}; + virtual void material_free(RID p_rid) override {} virtual void material_set_render_priority(RID p_material, int priority) override {} virtual void material_set_shader(RID p_shader_material, RID p_shader) override {} diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index 609f19589f..6da7446e69 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -56,14 +56,14 @@ public: /* Canvas Texture API */ virtual RID canvas_texture_allocate() override { return RID(); }; - virtual void canvas_texture_initialize(RID p_rid) override{}; - virtual void canvas_texture_free(RID p_rid) override{}; + virtual void canvas_texture_initialize(RID p_rid) override {} + virtual void canvas_texture_free(RID p_rid) override {} - virtual void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) override{}; - virtual void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) override{}; + virtual void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) override {} + virtual void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) override {} - virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override{}; - virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override{}; + virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override {} + virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override {} /* Texture API */ @@ -88,20 +88,22 @@ public: ERR_FAIL_NULL(t); t->image = p_image->duplicate(); }; - virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override{}; - virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override{}; - virtual void texture_proxy_initialize(RID p_texture, RID p_base) override{}; //all slices, then all the mipmaps, must be coherent + virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override {} + virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override {} + virtual void texture_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override {} + virtual void texture_proxy_initialize(RID p_texture, RID p_base) override {} //all slices, then all the mipmaps, must be coherent virtual RID texture_create_from_native_handle(RS::TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers = 1, RS::TextureLayeredType p_layered_type = RS::TEXTURE_LAYERED_2D_ARRAY) override { return RID(); } - virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override{}; - virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override{}; - virtual void texture_proxy_update(RID p_proxy, RID p_base) override{}; + virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override {} + virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override {} + virtual void texture_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override {} + virtual void texture_proxy_update(RID p_proxy, RID p_base) override {} //these two APIs can be used together or in combination with the others. - virtual void texture_2d_placeholder_initialize(RID p_texture) override{}; - virtual void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) override{}; - virtual void texture_3d_placeholder_initialize(RID p_texture) override{}; + virtual void texture_2d_placeholder_initialize(RID p_texture) override {} + virtual void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) override {} + virtual void texture_3d_placeholder_initialize(RID p_texture) override {} virtual Ref<Image> texture_2d_get(RID p_texture) const override { DummyTexture *t = texture_owner.get_or_null(p_texture); @@ -112,31 +114,31 @@ public: virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const override { return Vector<Ref<Image>>(); }; virtual void texture_replace(RID p_texture, RID p_by_texture) override { texture_free(p_by_texture); }; - virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) override{}; + virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) override {} - virtual void texture_set_path(RID p_texture, const String &p_path) override{}; + virtual void texture_set_path(RID p_texture, const String &p_path) override {} virtual String texture_get_path(RID p_texture) const override { return String(); }; virtual Image::Format texture_get_format(RID p_texture) const override { return Image::FORMAT_MAX; } - virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override{}; - virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override{}; - virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) override{}; + virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override {} + virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override {} + virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) override {} - virtual void texture_debug_usage(List<RS::TextureInfo> *r_info) override{}; + virtual void texture_debug_usage(List<RS::TextureInfo> *r_info) override {} - virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override{}; + virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override {} virtual Size2 texture_size_with_proxy(RID p_proxy) override { return Size2(); }; - virtual void texture_rd_initialize(RID p_texture, const RID &p_rd_texture, const RS::TextureLayeredType p_layer_type = RS::TEXTURE_LAYERED_2D_ARRAY) override{}; + virtual void texture_rd_initialize(RID p_texture, const RID &p_rd_texture, const RS::TextureLayeredType p_layer_type = RS::TEXTURE_LAYERED_2D_ARRAY) override {} virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const override { return RID(); }; virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const override { return 0; }; /* DECAL API */ virtual RID decal_allocate() override { return RID(); } virtual void decal_initialize(RID p_rid) override {} - virtual void decal_free(RID p_rid) override{}; + virtual void decal_free(RID p_rid) override {} virtual void decal_set_size(RID p_decal, const Vector3 &p_size) override {} virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) override {} diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h index 25fb190f44..75b9c563f7 100644 --- a/servers/rendering/renderer_rd/environment/fog.h +++ b/servers/rendering/renderer_rd/environment/fog.h @@ -316,8 +316,8 @@ public: int last_shadow_filter = -1; - virtual void configure(RenderSceneBuffersRD *p_render_buffers) override{}; - virtual void free_data() override{}; + virtual void configure(RenderSceneBuffersRD *p_render_buffers) override {} + virtual void free_data() override {} bool sync_gi_dependent_sets_validity(bool p_ensure_freed = false); diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h index 6169d386b5..f6f9ab4f75 100644 --- a/servers/rendering/renderer_rd/environment/gi.h +++ b/servers/rendering/renderer_rd/environment/gi.h @@ -461,7 +461,7 @@ public: RID get_voxel_gi_buffer(); - virtual void configure(RenderSceneBuffersRD *p_render_buffers) override{}; + virtual void configure(RenderSceneBuffersRD *p_render_buffers) override {} virtual void free_data() override; }; @@ -675,7 +675,7 @@ public: int32_t cascade_dynamic_light_count[SDFGI::MAX_CASCADES]; //used dynamically RID integrate_sky_uniform_set; - virtual void configure(RenderSceneBuffersRD *p_render_buffers) override{}; + virtual void configure(RenderSceneBuffersRD *p_render_buffers) override {} virtual void free_data() override; ~SDFGI(); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index fc60c770e8..9e429d598a 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -366,12 +366,12 @@ protected: virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override; virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override; - virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override{}; - virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override{}; - virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override{}; + virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {} + virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {} + virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override {} - virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override{}; - virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override{}; + virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override {} + virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override {} /* Geometry instance */ diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 738bcd4832..57497eb207 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -2479,6 +2479,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch = _new_batch(r_batch_broken); r_current_batch->command_type = Item::Command::TYPE_NINEPATCH; r_current_batch->command = c; + r_current_batch->has_blend = false; r_current_batch->pipeline_variant = PipelineVariant::PIPELINE_VARIANT_NINEPATCH; } @@ -2548,6 +2549,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch = _new_batch(r_batch_broken); r_current_batch->command_type = Item::Command::TYPE_POLYGON; + r_current_batch->has_blend = false; r_current_batch->command = c; TextureState tex_state(polygon->texture, texture_filter, texture_repeat, false, use_linear_colors); @@ -2585,6 +2587,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar if (primitive->point_count != r_current_batch->primitive_points || r_current_batch->command_type != Item::Command::TYPE_PRIMITIVE) { r_current_batch = _new_batch(r_batch_broken); r_current_batch->command_type = Item::Command::TYPE_PRIMITIVE; + r_current_batch->has_blend = false; r_current_batch->command = c; r_current_batch->primitive_points = primitive->point_count; @@ -2646,6 +2649,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar r_current_batch = _new_batch(r_batch_broken); r_current_batch->command = c; r_current_batch->command_type = c->type; + r_current_batch->has_blend = false; InstanceData *instance_data = nullptr; @@ -2799,6 +2803,7 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV RID pipeline = p_pipeline_variants->variants[p_batch->light_mode][p_batch->pipeline_variant].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format); RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); if (p_batch->has_blend) { + DEV_ASSERT(p_batch->pipeline_variant == PIPELINE_VARIANT_QUAD_LCD_BLEND); RD::get_singleton()->draw_list_set_blend_constants(p_draw_list, p_batch->modulate); } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 022a4560f8..b82d50378e 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -165,9 +165,9 @@ public: /* LIGHTING */ - virtual void setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_size){}; - virtual void setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture){}; - virtual void setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_size){}; + virtual void setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_size) {} + virtual void setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture) {} + virtual void setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_size) {} /* GI */ diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index e6a745d3b4..39c3e9b168 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -200,6 +200,8 @@ void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, c #endif builder.append(String("#define RENDER_DRIVER_") + OS::get_singleton()->get_current_rendering_driver_name().to_upper() + "\n"); + builder.append("#define samplerExternalOES sampler2D\n"); + builder.append("#define textureExternalOES texture2D\n"); } break; case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: { builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment) diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h index 22a21086af..688092d604 100644 --- a/servers/rendering/renderer_rd/shader_rd.h +++ b/servers/rendering/renderer_rd/shader_rd.h @@ -46,7 +46,7 @@ public: int group = 0; CharString text; bool default_enabled = true; - VariantDefine(){}; + VariantDefine() {} VariantDefine(int p_group, const String &p_text, bool p_default_enabled) { group = p_group; default_enabled = p_default_enabled; diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index 2154d56faf..704aafdfa5 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -41,11 +41,11 @@ layout(location = 3) out vec2 pixel_size_interp; #endif #ifdef MATERIAL_UNIFORMS_USED -layout(set = 1, binding = 0, std140) uniform MaterialUniforms{ - +/* clang-format off */ +layout(set = 1, binding = 0, std140) uniform MaterialUniforms { #MATERIAL_UNIFORMS - } material; +/* clang-format on */ #endif #GLOBALS @@ -214,6 +214,8 @@ void main() { color_interp = color; + vertex = (canvas_data.canvas_transform * vec4(vertex, 0.0, 1.0)).xy; + if (canvas_data.use_pixel_snap) { vertex = floor(vertex + 0.5); // precision issue on some hardware creates artifacts within texture @@ -221,8 +223,6 @@ void main() { uv += 1e-5; } - vertex = (canvas_data.canvas_transform * vec4(vertex, 0.0, 1.0)).xy; - vertex_interp = vertex; uv_interp = uv; @@ -258,11 +258,11 @@ layout(location = 3) in vec2 pixel_size_interp; layout(location = 0) out vec4 frag_color; #ifdef MATERIAL_UNIFORMS_USED -layout(set = 1, binding = 0, std140) uniform MaterialUniforms{ - +/* clang-format off */ +layout(set = 1, binding = 0, std140) uniform MaterialUniforms { #MATERIAL_UNIFORMS - } material; +/* clang-format on */ #endif vec2 screen_uv_to_sdf(vec2 p_uv) { diff --git a/servers/rendering/renderer_rd/shaders/environment/sky.glsl b/servers/rendering/renderer_rd/shaders/environment/sky.glsl index 5aa3735494..cc1c40cad1 100644 --- a/servers/rendering/renderer_rd/shaders/environment/sky.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/sky.glsl @@ -106,9 +106,11 @@ layout(set = 0, binding = 3, std140) uniform DirectionalLights { directional_lights; #ifdef MATERIAL_UNIFORMS_USED -layout(set = 1, binding = 0, std140) uniform MaterialUniforms{ +/* clang-format off */ +layout(set = 1, binding = 0, std140) uniform MaterialUniforms { #MATERIAL_UNIFORMS } material; +/* clang-format on */ #endif layout(set = 2, binding = 0) uniform textureCube radiance; @@ -247,9 +249,7 @@ void main() { #endif //USE_CUBEMAP_PASS { - #CODE : SKY - } frag_color.rgb = color; diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl index 2360375c23..929f1e34df 100644 --- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl @@ -77,9 +77,11 @@ layout(r32ui, set = 1, binding = 4) uniform volatile uimage3D light_only_map; #endif #ifdef MATERIAL_UNIFORMS_USED -layout(set = 2, binding = 0, std140) uniform MaterialUniforms{ +/* clang-format off */ +layout(set = 2, binding = 0, std140) uniform MaterialUniforms { #MATERIAL_UNIFORMS } material; +/* clang-format on */ #endif #GLOBALS diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index cfde97af95..a441b1667d 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -116,9 +116,11 @@ layout(location = 8) out vec4 prev_screen_position; #endif #ifdef MATERIAL_UNIFORMS_USED -layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ +/* clang-format off */ +layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms { #MATERIAL_UNIFORMS } material; +/* clang-format on */ #endif float global_time; @@ -808,11 +810,11 @@ ivec2 multiview_uv(ivec2 uv) { #endif #ifdef MATERIAL_UNIFORMS_USED -layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ - +/* clang-format off */ +layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms { #MATERIAL_UNIFORMS - } material; +/* clang-format on */ #endif #GLOBALS diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index b21769f207..92a8e2be32 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -107,11 +107,11 @@ layout(location = 6) mediump out vec3 binormal_interp; #endif #ifdef MATERIAL_UNIFORMS_USED -layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ - +/* clang-format off */ +layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms { #MATERIAL_UNIFORMS - } material; +/* clang-format on */ #endif #ifdef MODE_DUAL_PARABOLOID @@ -671,11 +671,11 @@ ivec2 multiview_uv(ivec2 uv) { #endif #ifdef MATERIAL_UNIFORMS_USED -layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ - +/* clang-format off */ +layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms { #MATERIAL_UNIFORMS - } material; +/* clang-format on */ #endif #GLOBALS diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl index 7c5291038f..a8f27ba726 100644 --- a/servers/rendering/renderer_rd/shaders/particles.glsl +++ b/servers/rendering/renderer_rd/shaders/particles.glsl @@ -168,11 +168,11 @@ layout(set = 2, binding = 1) uniform texture2D height_field_texture; /* SET 3: MATERIAL */ #ifdef MATERIAL_UNIFORMS_USED -layout(set = 3, binding = 0, std140) uniform MaterialUniforms{ - +/* clang-format off */ +layout(set = 3, binding = 0, std140) uniform MaterialUniforms { #MATERIAL_UNIFORMS - } material; +/* clang-format on */ #endif layout(push_constant, std430) uniform Params { diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index 9f390c99f9..3bfc1bd15c 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -1639,6 +1639,7 @@ void MaterialStorage::global_shader_parameters_load_settings(bool p_load_texture "sampler2DArray", "sampler3D", "samplerCube", + "samplerExternalOES", }; RS::GlobalShaderParameterType gvtype = RS::GLOBAL_VAR_TYPE_MAX; diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h index c885ad52d1..0025fc5ab7 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h @@ -128,7 +128,7 @@ private: h = hash_murmur3_one_32(p_val.layers, h); h = hash_murmur3_one_32(p_val.mipmap, h); h = hash_murmur3_one_32(p_val.mipmaps, h); - h = hash_murmur3_one_32(p_val.texture_view.format_override); + h = hash_murmur3_one_32(p_val.texture_view.format_override, h); h = hash_murmur3_one_32(p_val.texture_view.swizzle_r, h); h = hash_murmur3_one_32(p_val.texture_view.swizzle_g, h); h = hash_murmur3_one_32(p_val.texture_view.swizzle_b, h); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 81ab384edc..e5a8dbb9b2 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -1087,6 +1087,9 @@ void TextureStorage::texture_3d_initialize(RID p_texture, Image::Format p_format texture_owner.initialize_rid(p_texture, texture); } +void TextureStorage::texture_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) { +} + void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) { Texture *tex = texture_owner.get_or_null(p_base); ERR_FAIL_NULL(tex); @@ -1361,6 +1364,9 @@ void TextureStorage::texture_3d_update(RID p_texture, const Vector<Ref<Image>> & RD::get_singleton()->texture_update(tex->rd_texture, 0, all_data); } +void TextureStorage::texture_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) { +} + void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) { Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_NULL(tex); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index d352690fff..9de4ff7b6b 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -491,12 +491,14 @@ public: virtual void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) override; virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override; virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override; + virtual void texture_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override; virtual void texture_proxy_initialize(RID p_texture, RID p_base) override; //all slices, then all the mipmaps, must be coherent virtual RID texture_create_from_native_handle(RS::TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers = 1, RS::TextureLayeredType p_layered_type = RS::TEXTURE_LAYERED_2D_ARRAY) override; virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override; virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override; + virtual void texture_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override; virtual void texture_proxy_update(RID p_proxy, RID p_base) override; //these two APIs can be used together or in combination with the others. diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h index a848c86bd2..df403c5484 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.h +++ b/servers/rendering/renderer_scene_occlusion_cull.h @@ -192,7 +192,7 @@ public: RID get_debug_texture(); const Size2i &get_occlusion_buffer_size() const { return occlusion_buffer_size; } - virtual ~HZBuffer(){}; + virtual ~HZBuffer() {} }; static RendererSceneOcclusionCull *get_singleton() { return singleton; } diff --git a/servers/rendering/rendering_device_commons.h b/servers/rendering/rendering_device_commons.h index 8c3996bd80..d72265958c 100644 --- a/servers/rendering/rendering_device_commons.h +++ b/servers/rendering/rendering_device_commons.h @@ -34,7 +34,7 @@ #include "core/object/object.h" #include "core/variant/type_info.h" -#define STEPIFY(m_number, m_alignment) ((((m_number) + ((m_alignment)-1)) / (m_alignment)) * (m_alignment)) +#define STEPIFY(m_number, m_alignment) ((((m_number) + ((m_alignment) - 1)) / (m_alignment)) * (m_alignment)) class RenderingDeviceCommons : public Object { //////////////////////////////////////////// diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index fb4f4aa756..2dcdc3f254 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -162,6 +162,17 @@ public: return ret; \ } +#define FUNCRIDTEX3(m_type, m_type1, m_type2, m_type3) \ + virtual RID m_type##_create(m_type1 p1, m_type2 p2, m_type3 p3) override { \ + RID ret = RSG::texture_storage->texture_allocate(); \ + if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) { \ + RSG::texture_storage->m_type##_initialize(ret, p1, p2, p3); \ + } else { \ + command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1, p2, p3); \ + } \ + return ret; \ + } + #define FUNCRIDTEX6(m_type, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \ virtual RID m_type##_create(m_type1 p1, m_type2 p2, m_type3 p3, m_type4 p4, m_type5 p5, m_type6 p6) override { \ RID ret = RSG::texture_storage->texture_allocate(); \ @@ -177,6 +188,7 @@ public: FUNCRIDTEX1(texture_2d, const Ref<Image> &) FUNCRIDTEX2(texture_2d_layered, const Vector<Ref<Image>> &, TextureLayeredType) FUNCRIDTEX6(texture_3d, Image::Format, int, int, int, bool, const Vector<Ref<Image>> &) + FUNCRIDTEX3(texture_external, int, int, uint64_t) FUNCRIDTEX1(texture_proxy, RID) // Called directly, not through the command queue. @@ -187,6 +199,7 @@ public: //these go through command queue if they are in another thread FUNC3(texture_2d_update, RID, const Ref<Image> &, int) FUNC2(texture_3d_update, RID, const Vector<Ref<Image>> &) + FUNC4(texture_external_update, RID, int, int, uint64_t) FUNC2(texture_proxy_update, RID, RID) //these also go pass-through diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index 5f97fa0c9b..3a0b9cf158 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -113,6 +113,8 @@ static int _get_datatype_alignment(SL::DataType p_type) { return 16; case SL::TYPE_SAMPLERCUBEARRAY: return 16; + case SL::TYPE_SAMPLEREXT: + return 16; case SL::TYPE_STRUCT: return 0; case SL::TYPE_MAX: { diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 5a3c5d2fd0..14bd3841df 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -315,6 +315,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_TYPE_USAMPLER3D, "usampler3D", KCF_SAMPLER_DATATYPE, {}, {} }, { TK_TYPE_SAMPLERCUBE, "samplerCube", KCF_SAMPLER_DATATYPE, {}, {} }, { TK_TYPE_SAMPLERCUBEARRAY, "samplerCubeArray", KCF_SAMPLER_DATATYPE, {}, {} }, + { TK_TYPE_SAMPLEREXT, "samplerExternalOES", KCF_SAMPLER_DATATYPE, {}, {} }, // interpolation qualifiers @@ -1027,7 +1028,8 @@ bool ShaderLanguage::is_token_datatype(TokenType p_type) { p_type == TK_TYPE_ISAMPLER3D || p_type == TK_TYPE_USAMPLER3D || p_type == TK_TYPE_SAMPLERCUBE || - p_type == TK_TYPE_SAMPLERCUBEARRAY); + p_type == TK_TYPE_SAMPLERCUBEARRAY || + p_type == TK_TYPE_SAMPLEREXT); } ShaderLanguage::DataType ShaderLanguage::get_token_datatype(TokenType p_type) { @@ -1162,6 +1164,8 @@ String ShaderLanguage::get_datatype_name(DataType p_type) { return "samplerCube"; case TYPE_SAMPLERCUBEARRAY: return "samplerCubeArray"; + case TYPE_SAMPLEREXT: + return "samplerExternalOES"; case TYPE_STRUCT: return "struct"; case TYPE_MAX: @@ -3169,6 +3173,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false }, { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false }, { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false }, + { "texture", TYPE_VEC4, { TYPE_SAMPLEREXT, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false }, + { "texture", TYPE_VEC4, { TYPE_SAMPLEREXT, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false }, // textureProj @@ -4482,7 +4488,8 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<Scalar> &p_value, case ShaderLanguage::TYPE_USAMPLER2D: case ShaderLanguage::TYPE_USAMPLER3D: case ShaderLanguage::TYPE_SAMPLERCUBE: - case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: { + case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: + case ShaderLanguage::TYPE_SAMPLEREXT: { // Texture types, likely not relevant here. break; } @@ -4707,6 +4714,17 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform pi.hint_string = "Texture3D"; } } break; + case ShaderLanguage::TYPE_SAMPLEREXT: { + if (p_uniform.array_size > 0) { + pi.type = Variant::ARRAY; + pi.hint = PROPERTY_HINT_ARRAY_TYPE; + pi.hint_string = MAKE_RESOURCE_TYPE_HINT("ExternalTexture"); + } else { + pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "ExternalTexture"; + } + } break; case ShaderLanguage::TYPE_STRUCT: { // FIXME: Implement this. } break; @@ -4780,6 +4798,8 @@ uint32_t ShaderLanguage::get_datatype_size(ShaderLanguage::DataType p_type) { return 16; case TYPE_SAMPLERCUBEARRAY: return 16; + case TYPE_SAMPLEREXT: + return 16; case TYPE_STRUCT: return 0; case TYPE_MAX: { @@ -4921,6 +4941,7 @@ ShaderLanguage::DataType ShaderLanguage::get_scalar_type(DataType p_type) { TYPE_UINT, TYPE_FLOAT, TYPE_FLOAT, + TYPE_FLOAT, TYPE_VOID, }; @@ -4963,6 +4984,7 @@ int ShaderLanguage::get_cardinality(DataType p_type) { 1, 1, 1, + 1, }; static_assert(sizeof(cardinality_table) / sizeof(*cardinality_table) == TYPE_MAX); diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index b0d579dfe7..48df77f6bb 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -91,6 +91,7 @@ public: TK_TYPE_USAMPLER3D, TK_TYPE_SAMPLERCUBE, TK_TYPE_SAMPLERCUBEARRAY, + TK_TYPE_SAMPLEREXT, TK_INTERPOLATION_FLAT, TK_INTERPOLATION_SMOOTH, TK_CONST, @@ -235,6 +236,7 @@ public: TYPE_USAMPLER3D, TYPE_SAMPLERCUBE, TYPE_SAMPLERCUBEARRAY, + TYPE_SAMPLEREXT, TYPE_STRUCT, TYPE_MAX }; diff --git a/servers/rendering/storage/material_storage.h b/servers/rendering/storage/material_storage.h index 03feda8abb..a5935cc90f 100644 --- a/servers/rendering/storage/material_storage.h +++ b/servers/rendering/storage/material_storage.h @@ -36,7 +36,7 @@ class RendererMaterialStorage { public: - virtual ~RendererMaterialStorage(){}; + virtual ~RendererMaterialStorage() {} /* GLOBAL SHADER UNIFORM API */ virtual void global_shader_parameter_add(const StringName &p_name, RS::GlobalShaderParameterType p_type, const Variant &p_value) = 0; diff --git a/servers/rendering/storage/render_scene_buffers.h b/servers/rendering/storage/render_scene_buffers.h index 6c82d47799..b860af7640 100644 --- a/servers/rendering/storage/render_scene_buffers.h +++ b/servers/rendering/storage/render_scene_buffers.h @@ -91,7 +91,7 @@ public: void set_use_debanding(bool p_use_debanding) { use_debanding = p_use_debanding; } RenderSceneBuffersConfiguration() {} - virtual ~RenderSceneBuffersConfiguration(){}; + virtual ~RenderSceneBuffersConfiguration() {} }; class RenderSceneBuffers : public RefCounted { @@ -101,8 +101,8 @@ protected: static void _bind_methods(); public: - RenderSceneBuffers(){}; - virtual ~RenderSceneBuffers(){}; + RenderSceneBuffers() {} + virtual ~RenderSceneBuffers() {} virtual void configure(const RenderSceneBuffersConfiguration *p_config) = 0; @@ -124,7 +124,7 @@ protected: GDVIRTUAL1(_set_use_debanding, bool) public: - virtual ~RenderSceneBuffersExtension(){}; + virtual ~RenderSceneBuffersExtension() {} virtual void configure(const RenderSceneBuffersConfiguration *p_config) override; diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h index 7388307ac0..fd17b052ee 100644 --- a/servers/rendering/storage/texture_storage.h +++ b/servers/rendering/storage/texture_storage.h @@ -61,7 +61,7 @@ public: /* Texture API */ virtual bool can_create_resources_async() const = 0; - virtual ~RendererTextureStorage(){}; + virtual ~RendererTextureStorage() {} virtual RID texture_allocate() = 0; virtual void texture_free(RID p_rid) = 0; @@ -69,12 +69,14 @@ public: virtual void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) = 0; virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) = 0; virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) = 0; + virtual void texture_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) = 0; virtual void texture_proxy_initialize(RID p_texture, RID p_base) = 0; //all slices, then all the mipmaps, must be coherent virtual RID texture_create_from_native_handle(RS::TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers = 1, RS::TextureLayeredType p_layered_type = RS::TEXTURE_LAYERED_2D_ARRAY) = 0; virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) = 0; + virtual void texture_external_update(RID p_proxy, int p_width, int p_height, uint64_t p_external_buffer) = 0; virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0; //these two APIs can be used together or in combination with the others. diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index a1c05fa2e7..0ad56961c0 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -3405,6 +3405,7 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_SAMPLER2DARRAY); BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_SAMPLER3D); BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_SAMPLERCUBE); + BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_SAMPLEREXT); BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_MAX); /* Free */ diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 2b45b73f09..a130ae0ba2 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -137,12 +137,14 @@ public: virtual RID texture_2d_create(const Ref<Image> &p_image) = 0; virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, TextureLayeredType p_layered_type) = 0; virtual RID texture_3d_create(Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) = 0; //all slices, then all the mipmaps, must be coherent + virtual RID texture_external_create(int p_width, int p_height, uint64_t p_external_buffer = 0) = 0; virtual RID texture_proxy_create(RID p_base) = 0; virtual RID texture_create_from_native_handle(TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers = 1, TextureLayeredType p_layered_type = TEXTURE_LAYERED_2D_ARRAY) = 0; virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) = 0; + virtual void texture_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer = 0) = 0; virtual void texture_proxy_update(RID p_texture, RID p_proxy_to) = 0; // These two APIs can be used together or in combination with the others. @@ -1647,6 +1649,7 @@ public: GLOBAL_VAR_TYPE_SAMPLER2DARRAY, GLOBAL_VAR_TYPE_SAMPLER3D, GLOBAL_VAR_TYPE_SAMPLERCUBE, + GLOBAL_VAR_TYPE_SAMPLEREXT, GLOBAL_VAR_TYPE_MAX }; diff --git a/servers/xr/xr_controller_tracker.cpp b/servers/xr/xr_controller_tracker.cpp index df85e86b7e..2d6cf44ce8 100644 --- a/servers/xr/xr_controller_tracker.cpp +++ b/servers/xr/xr_controller_tracker.cpp @@ -32,7 +32,7 @@ #include "core/input/input.h" -void XRControllerTracker::_bind_methods(){}; +void XRControllerTracker::_bind_methods() {} XRControllerTracker::XRControllerTracker() { type = XRServer::TRACKER_CONTROLLER; diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h index 6b6a67a04c..55495731c5 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -137,10 +137,10 @@ public: virtual RID get_color_texture(); /* obtain color output texture (if applicable) */ virtual RID get_depth_texture(); /* obtain depth output texture (if applicable, used for reprojection) */ virtual RID get_velocity_texture(); /* obtain velocity output texture (if applicable, used for spacewarp) */ - virtual void pre_render(){}; + virtual void pre_render() {} virtual bool pre_draw_viewport(RID p_render_target) { return true; }; /* inform XR interface we are about to start our viewport draw process */ virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) = 0; /* inform XR interface we finished our viewport draw process */ - virtual void end_frame(){}; + virtual void end_frame() {} /** passthrough **/ diff --git a/tests/core/variant/test_array.h b/tests/core/variant/test_array.h index 787b8f39d9..15e2cebe09 100644 --- a/tests/core/variant/test_array.h +++ b/tests/core/variant/test_array.h @@ -634,6 +634,24 @@ TEST_CASE("[Array] Typed copying") { a6.clear(); } +static bool _find_custom_callable(const Variant &p_val) { + return (int)p_val % 2 == 0; +} + +TEST_CASE("[Array] Test find_custom") { + Array a1 = build_array(1, 3, 4, 5, 8, 9); + // Find first even number. + int index = a1.find_custom(callable_mp_static(_find_custom_callable)); + CHECK_EQ(index, 2); +} + +TEST_CASE("[Array] Test rfind_custom") { + Array a1 = build_array(1, 3, 4, 5, 8, 9); + // Find last even number. + int index = a1.rfind_custom(callable_mp_static(_find_custom_callable)); + CHECK_EQ(index, 4); +} + } // namespace TestArray #endif // TEST_ARRAY_H diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h index 9ec1b812df..ef630ad4f7 100644 --- a/tests/scene/test_code_edit.h +++ b/tests/scene/test_code_edit.h @@ -4779,6 +4779,31 @@ TEST_CASE("[SceneTree][CodeEdit] text manipulation") { CHECK(code_edit->get_caret_column(3) == 0); } + SUBCASE("[SceneTree][CodeEdit] cut when empty selection clipboard disabled") { + DisplayServerMock *DS = (DisplayServerMock *)(DisplayServer::get_singleton()); + code_edit->set_empty_selection_clipboard_enabled(false); + DS->clipboard_set(""); + + code_edit->set_text("this is\nsome\n"); + code_edit->set_caret_line(0); + code_edit->set_caret_column(6); + MessageQueue::get_singleton()->flush(); + SIGNAL_DISCARD("text_set"); + SIGNAL_DISCARD("text_changed"); + SIGNAL_DISCARD("lines_edited_from"); + SIGNAL_DISCARD("caret_changed"); + + code_edit->cut(); + MessageQueue::get_singleton()->flush(); + CHECK(DS->clipboard_get() == ""); + CHECK(code_edit->get_text() == "this is\nsome\n"); + CHECK(code_edit->get_caret_line() == 0); + CHECK(code_edit->get_caret_column() == 6); + SIGNAL_CHECK_FALSE("caret_changed"); + SIGNAL_CHECK_FALSE("text_changed"); + SIGNAL_CHECK_FALSE("lines_edited_from"); + } + SUBCASE("[SceneTree][CodeEdit] new line") { // Add a new line. code_edit->set_text("test new line"); diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h index 46a5046b21..c41eebdf3a 100644 --- a/tests/scene/test_text_edit.h +++ b/tests/scene/test_text_edit.h @@ -3585,6 +3585,54 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_CHECK_FALSE("lines_edited_from"); } + SUBCASE("[TextEdit] cut when empty selection clipboard disabled") { + text_edit->set_empty_selection_clipboard_enabled(false); + DS->clipboard_set(""); + + text_edit->set_text("this is\nsome\n"); + text_edit->set_caret_line(0); + text_edit->set_caret_column(6); + MessageQueue::get_singleton()->flush(); + SIGNAL_DISCARD("text_set"); + SIGNAL_DISCARD("text_changed"); + SIGNAL_DISCARD("lines_edited_from"); + SIGNAL_DISCARD("caret_changed"); + + text_edit->cut(); + MessageQueue::get_singleton()->flush(); + CHECK(DS->clipboard_get() == ""); + CHECK(text_edit->get_text() == "this is\nsome\n"); + CHECK(text_edit->get_caret_line() == 0); + CHECK(text_edit->get_caret_column() == 6); + SIGNAL_CHECK_FALSE("caret_changed"); + SIGNAL_CHECK_FALSE("text_changed"); + SIGNAL_CHECK_FALSE("lines_edited_from"); + } + + SUBCASE("[TextEdit] copy when empty selection clipboard disabled") { + text_edit->set_empty_selection_clipboard_enabled(false); + DS->clipboard_set(""); + + text_edit->set_text("this is\nsome\n"); + text_edit->set_caret_line(0); + text_edit->set_caret_column(6); + MessageQueue::get_singleton()->flush(); + SIGNAL_DISCARD("text_set"); + SIGNAL_DISCARD("text_changed"); + SIGNAL_DISCARD("lines_edited_from"); + SIGNAL_DISCARD("caret_changed"); + + text_edit->copy(); + MessageQueue::get_singleton()->flush(); + CHECK(DS->clipboard_get() == ""); + CHECK(text_edit->get_text() == "this is\nsome\n"); + CHECK(text_edit->get_caret_line() == 0); + CHECK(text_edit->get_caret_column() == 6); + SIGNAL_CHECK_FALSE("caret_changed"); + SIGNAL_CHECK_FALSE("text_changed"); + SIGNAL_CHECK_FALSE("lines_edited_from"); + } + SIGNAL_UNWATCH(text_edit, "text_set"); SIGNAL_UNWATCH(text_edit, "text_changed"); SIGNAL_UNWATCH(text_edit, "lines_edited_from"); diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 949e4f0b33..3c184ccc5d 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -176,6 +176,7 @@ #include "servers/physics_server_2d.h" #ifndef _3D_DISABLED #include "servers/physics_server_3d.h" +#include "servers/physics_server_3d_dummy.h" #endif // _3D_DISABLED #include "servers/rendering/rendering_server_default.h" @@ -290,6 +291,9 @@ struct GodotTestCaseListener : public doctest::IReporter { #ifndef _3D_DISABLED physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server(); + if (!physics_server_3d) { + physics_server_3d = memnew(PhysicsServer3DDummy); + } physics_server_3d->init(); #endif // _3D_DISABLED diff --git a/thirdparty/README.md b/thirdparty/README.md index a6686c539a..4c47b91c8c 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -614,7 +614,7 @@ to solve some MSVC warnings. See the patches in the `patches` directory. ## miniupnpc - Upstream: https://github.com/miniupnp/miniupnp -- Version: 2.2.7 (d4d5ec7d48c093b37b2ea5d7171ede21ce9d7ff2, 2024) +- Version: 2.2.8 (b55145ec095652289a59c33603f3abafee898273, 2024) - License: BSD-3-Clause Files extracted from upstream source: diff --git a/thirdparty/miniupnpc/include/miniupnpc.h b/thirdparty/miniupnpc/include/miniupnpc.h index 808c6ad975..fd951a0836 100644 --- a/thirdparty/miniupnpc/include/miniupnpc.h +++ b/thirdparty/miniupnpc/include/miniupnpc.h @@ -1,9 +1,9 @@ -/* $Id: miniupnpc.h,v 1.63 2024/01/04 00:45:17 nanard Exp $ */ +/* $Id: miniupnpc.h,v 1.66 2024/06/08 22:13:14 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project: miniupnp * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author: Thomas Bernard - * Copyright (c) 2005-2022 Thomas Bernard + * Copyright (c) 2005-2024 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ #ifndef MINIUPNPC_H_INCLUDED @@ -20,8 +20,8 @@ #define UPNPDISCOVER_MEMORY_ERROR (-102) /* versions : */ -#define MINIUPNPC_VERSION "2.2.6" -#define MINIUPNPC_API_VERSION 17 +#define MINIUPNPC_VERSION "2.2.8" +#define MINIUPNPC_API_VERSION 18 /* Source port: Using "1" as an alias for 1900 for backwards compatibility @@ -108,9 +108,11 @@ struct UPNPUrls { * return values : * 0 = NO IGD found * 1 = A valid connected IGD has been found - * 2 = A valid IGD has been found but it reported as + * 2 = A valid connected IGD has been found but its + * IP address is reserved (non routable) + * 3 = A valid IGD has been found but it reported as * not connected - * 3 = an UPnP device has been found but was not recognized as an IGD + * 4 = an UPnP device has been found but was not recognized as an IGD * * In any non zero return case, the urls and data structures * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to @@ -119,8 +121,9 @@ struct UPNPUrls { MINIUPNP_LIBSPEC int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, - struct IGDdatas * data, - char * lanaddr, int lanaddrlen); + struct IGDdatas * data, + char * lanaddr, int lanaddrlen, + char * wanaddr, int wanaddrlen); /* UPNP_GetIGDFromUrl() * Used when skipping the discovery process. diff --git a/thirdparty/miniupnpc/src/addr_is_reserved.c b/thirdparty/miniupnpc/src/addr_is_reserved.c index 18c6424201..145b504823 100644 --- a/thirdparty/miniupnpc/src/addr_is_reserved.c +++ b/thirdparty/miniupnpc/src/addr_is_reserved.c @@ -3,7 +3,7 @@ * Project : miniupnp * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author : Thomas BERNARD - * copyright (c) 2005-2021 Thomas Bernard + * copyright (c) 2005-2024 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENSE file. */ #ifdef _WIN32 @@ -21,6 +21,9 @@ typedef unsigned long uint32_t; #include <netinet/in.h> #include <arpa/inet.h> #endif /* _WIN32 */ +#ifdef DEBUG +#include <stdio.h> +#endif /* List of IP address blocks which are private / reserved and therefore not suitable for public external IP addresses */ #define IP(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) @@ -71,8 +74,12 @@ int addr_is_reserved(const char * addr_str) address = ntohl(addr_n); for (i = 0; i < sizeof(reserved)/sizeof(reserved[0]); ++i) { - if ((address >> reserved[i].rmask) == (reserved[i].address >> reserved[i].rmask)) + if ((address >> reserved[i].rmask) == (reserved[i].address >> reserved[i].rmask)) { +#ifdef DEBUG + printf("IP address %s is reserved\n", addr_str); +#endif return 1; + } } return 0; diff --git a/thirdparty/miniupnpc/src/minisoap.c b/thirdparty/miniupnpc/src/minisoap.c index 903ac5ffc6..5c6bf01684 100644 --- a/thirdparty/miniupnpc/src/minisoap.c +++ b/thirdparty/miniupnpc/src/minisoap.c @@ -2,7 +2,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Author : Thomas Bernard - * Copyright (c) 2005-2023 Thomas Bernard + * Copyright (c) 2005-2024 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * @@ -83,7 +83,7 @@ int soapPostSubmit(SOCKET fd, * Using HTTP/1.1 means we need to support chunked transfer-encoding : * When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked * transfer encoding. */ - /* Connection: Close is normally there only in HTTP/1.1 but who knows */ + /* Connection: close is normally there only in HTTP/1.1 but who knows */ portstr[0] = '\0'; if(port != 80) snprintf(portstr, sizeof(portstr), ":%hu", port); @@ -98,9 +98,8 @@ int soapPostSubmit(SOCKET fd, "Content-Type: text/xml; charset=\"utf-8\"\r\n" #endif "SOAPAction: \"%s\"\r\n" - "Connection: Close\r\n" + "Connection: close\r\n" "Cache-Control: no-cache\r\n" /* ??? */ - "Pragma: no-cache\r\n" "\r\n", url, httpversion, host, portstr, bodysize, action); if ((unsigned int)headerssize >= sizeof(headerbuf)) diff --git a/thirdparty/miniupnpc/src/minissdpc.c b/thirdparty/miniupnpc/src/minissdpc.c index 98c5b37463..57cb99962e 100644 --- a/thirdparty/miniupnpc/src/minissdpc.c +++ b/thirdparty/miniupnpc/src/minissdpc.c @@ -1,9 +1,9 @@ -/* $Id: minissdpc.c,v 1.49 2021/05/13 11:00:36 nanard Exp $ */ +/* $Id: minissdpc.c,v 1.51 2024/05/16 00:12:05 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author : Thomas BERNARD - * copyright (c) 2005-2021 Thomas Bernard + * copyright (c) 2005-2024 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #include <stdio.h> @@ -548,7 +548,7 @@ ssdpDiscoverDevices(const char * const deviceTypes[], #ifdef _WIN32 unsigned long _ttl = (unsigned long)ttl; #endif - int linklocal = 1; + int linklocal = 0; /* try first with site-local multicast */ int sentok; if(error) @@ -1007,9 +1007,10 @@ ssdpDiscoverDevices(const char * const deviceTypes[], /* switch linklocal flag */ if(linklocal) { linklocal = 0; - --deviceIndex; } else { + /* try again with linklocal multicast */ linklocal = 1; + --deviceIndex; } } } diff --git a/thirdparty/miniupnpc/src/miniupnpc.c b/thirdparty/miniupnpc/src/miniupnpc.c index 696af93237..9da1496b37 100644 --- a/thirdparty/miniupnpc/src/miniupnpc.c +++ b/thirdparty/miniupnpc/src/miniupnpc.c @@ -3,7 +3,7 @@ * Project : miniupnp * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author : Thomas BERNARD - * copyright (c) 2005-2021 Thomas Bernard + * copyright (c) 2005-2024 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENSE file. */ #include <stdlib.h> @@ -92,15 +92,15 @@ MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGD #endif } -/* simpleUPnPcommand2 : +/* simpleUPnPcommand : * not so simple ! * return values : * pointer - OK * NULL - error */ -static char * -simpleUPnPcommand2(SOCKET s, const char * url, const char * service, - const char * action, struct UPNParg * args, - int * bufsize, const char * httpversion) +char * +simpleUPnPcommand(int s, const char * url, const char * service, + const char * action, struct UPNParg * args, + int * bufsize) { char hostname[MAXHOSTNAMELEN+1]; unsigned short port = 0; @@ -197,15 +197,15 @@ simpleUPnPcommand2(SOCKET s, const char * url, const char * service, return NULL; } if(!parseURL(url, hostname, &port, &path, NULL)) return NULL; - if(ISINVALID(s)) { + if(ISINVALID((SOCKET)s)) { s = connecthostport(hostname, port, 0); - if(ISINVALID(s)) { + if(ISINVALID((SOCKET)s)) { /* failed to connect */ return NULL; } } - n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); + n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, "1.1"); if(n<=0) { #ifdef DEBUG printf("Error sending SOAP request\n"); @@ -229,33 +229,6 @@ simpleUPnPcommand2(SOCKET s, const char * url, const char * service, return buf; } -/* simpleUPnPcommand : - * not so simple ! - * return values : - * pointer - OK - * NULL - error */ -char * -simpleUPnPcommand(int s, const char * url, const char * service, - const char * action, struct UPNParg * args, - int * bufsize) -{ - char * buf; - -#if 1 - buf = simpleUPnPcommand2((SOCKET)s, url, service, action, args, bufsize, "1.1"); -#else - buf = simpleUPnPcommand2((SOCKET)s, url, service, action, args, bufsize, "1.0"); - if (!buf || *bufsize == 0) - { -#if DEBUG - printf("Error or no result from SOAP request; retrying with HTTP/1.1\n"); -#endif - buf = simpleUPnPcommand2((SOCKET)s, url, service, action, args, bufsize, "1.1"); - } -#endif - return buf; -} - /* upnpDiscoverDevices() : * return a chained list of all devices found or NULL if * no devices was found. @@ -534,9 +507,11 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) * -1 = Internal error * 0 = NO IGD found * 1 = A valid connected IGD has been found - * 2 = A valid IGD has been found but it reported as + * 2 = A valid connected IGD has been found but its + * IP address is reserved (non routable) + * 3 = A valid IGD has been found but it reported as * not connected - * 3 = an UPnP device has been found but was not recognized as an IGD + * 4 = an UPnP device has been found but was not recognized as an IGD * * In any positive non zero return case, the urls and data structures * passed as parameters are set. Don't forget to call FreeUPNPUrls(urls) to @@ -545,11 +520,13 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) MINIUPNP_LIBSPEC int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, - struct IGDdatas * data, - char * lanaddr, int lanaddrlen) + struct IGDdatas * data, + char * lanaddr, int lanaddrlen, + char * wanaddr, int wanaddrlen) { struct xml_desc { char lanaddr[40]; + char wanaddr[40]; char * xml; int size; int is_igd; @@ -557,8 +534,8 @@ UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPDev * dev; int ndev = 0; int i; - int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ - char extIpAddr[16]; + int state = -1; /* state 1 : IGD connected. State 2 : connected with reserved IP. + * State 3 : IGD. State 4 : anything */ int status_code = -1; if(!devlist) @@ -602,7 +579,7 @@ UPNP_GetValidIGD(struct UPNPDev * devlist, } } /* iterate the list to find a device depending on state */ - for(state = 1; state <= 3; state++) + for(state = 1; state <= 4; state++) { for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { @@ -611,14 +588,14 @@ UPNP_GetValidIGD(struct UPNPDev * devlist, memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(desc[i].xml, desc[i].size, data); - if(desc[i].is_igd || state >= 3 ) + if(desc[i].is_igd || state >= 4 ) { int is_connected; GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); - /* in state 2 and 3 we don't test if device is connected ! */ - if(state >= 2) + /* in state 3 and 4 we don't test if device is connected ! */ + if(state >= 3) goto free_and_return; is_connected = UPNPIGD_IsConnected(urls, data); #ifdef DEBUG @@ -626,9 +603,11 @@ UPNP_GetValidIGD(struct UPNPDev * devlist, urls->controlURL, is_connected); #endif /* checks that status is connected AND there is a external IP address assigned */ - if(is_connected && - (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) { - if(!addr_is_reserved(extIpAddr)) + if(is_connected) { + if(state >= 2) + goto free_and_return; + if(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, desc[i].wanaddr) == 0 + && !addr_is_reserved(desc[i].wanaddr)) goto free_and_return; } FreeUPNPUrls(urls); @@ -647,9 +626,11 @@ UPNP_GetValidIGD(struct UPNPDev * devlist, printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, is_connected); #endif - if(is_connected && - (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) { - if(!addr_is_reserved(extIpAddr)) + if(is_connected) { + if(state >= 2) + goto free_and_return; + if(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, desc[i].wanaddr) == 0 + && !addr_is_reserved(desc[i].wanaddr)) goto free_and_return; } FreeUPNPUrls(urls); @@ -661,8 +642,12 @@ UPNP_GetValidIGD(struct UPNPDev * devlist, } state = 0; free_and_return: - if (lanaddr != NULL && state >= 1 && state <= 3 && i < ndev) - strncpy(lanaddr, desc[i].lanaddr, lanaddrlen); + if (state >= 1 && state <= 4 && i < ndev) { + if (lanaddr != NULL) + strncpy(lanaddr, desc[i].lanaddr, lanaddrlen); + if (wanaddr != NULL) + strncpy(wanaddr, desc[i].wanaddr, wanaddrlen); + } for(i = 0; i < ndev; i++) free(desc[i].xml); free(desc); diff --git a/thirdparty/miniupnpc/src/miniupnpcstrings.h b/thirdparty/miniupnpc/src/miniupnpcstrings.h index f5730111af..d40c2455ba 100644 --- a/thirdparty/miniupnpc/src/miniupnpcstrings.h +++ b/thirdparty/miniupnpc/src/miniupnpcstrings.h @@ -2,7 +2,7 @@ #define MINIUPNPCSTRINGS_H_INCLUDED #define OS_STRING "Godot Engine/1.0" -#define MINIUPNPC_VERSION_STRING "2.2.7" +#define MINIUPNPC_VERSION_STRING "2.2.8" #if 0 /* according to "UPnP Device Architecture 1.0" */ diff --git a/thirdparty/miniupnpc/src/miniwget.c b/thirdparty/miniupnpc/src/miniwget.c index e76a5e516b..a7a32dfdba 100644 --- a/thirdparty/miniupnpc/src/miniwget.c +++ b/thirdparty/miniupnpc/src/miniwget.c @@ -2,7 +2,7 @@ /* Project : miniupnp * Website : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author : Thomas Bernard - * Copyright (c) 2005-2023 Thomas Bernard + * Copyright (c) 2005-2024 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ @@ -443,9 +443,8 @@ miniwget3(const char * host, len = snprintf(buf, sizeof(buf), "GET %s HTTP/%s\r\n" "Host: %s:%d\r\n" - "Connection: Close\r\n" + "Connection: close\r\n" "User-Agent: " OS_STRING " " UPNP_VERSION_STRING " MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" - "\r\n", path, httpversion, host, port); if ((unsigned int)len >= sizeof(buf)) @@ -474,41 +473,6 @@ miniwget3(const char * host, return content; } -/* miniwget2() : - * Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */ -static void * -miniwget2(const char * host, - unsigned short port, const char * path, - int * size, char * addr_str, int addr_str_len, - unsigned int scope_id, int * status_code) -{ - char * respbuffer; - -#if 1 - respbuffer = miniwget3(host, port, path, size, - addr_str, addr_str_len, "1.1", - scope_id, status_code); -#else - respbuffer = miniwget3(host, port, path, size, - addr_str, addr_str_len, "1.0", - scope_id, status_code); - if (*size == 0) - { -#ifdef DEBUG - printf("Retrying with HTTP/1.1\n"); -#endif - free(respbuffer); - respbuffer = miniwget3(host, port, path, size, - addr_str, addr_str_len, "1.1", - scope_id, status_code); - } -#endif - return respbuffer; -} - - - - /* parseURL() * arguments : * url : source string not modified @@ -639,7 +603,7 @@ miniwget(const char * url, int * size, printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", hostname, port, path, scope_id); #endif - return miniwget2(hostname, port, path, size, 0, 0, scope_id, status_code); + return miniwget3(hostname, port, path, size, 0, 0, "1.1", scope_id, status_code); } void * @@ -660,5 +624,5 @@ miniwget_getaddr(const char * url, int * size, printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", hostname, port, path, scope_id); #endif - return miniwget2(hostname, port, path, size, addr, addrlen, scope_id, status_code); + return miniwget3(hostname, port, path, size, addr, addrlen, "1.1", scope_id, status_code); } diff --git a/thirdparty/miniupnpc/src/win32_snprintf.h b/thirdparty/miniupnpc/src/win32_snprintf.h index 1fc284ecff..5064df63bc 100644 --- a/thirdparty/miniupnpc/src/win32_snprintf.h +++ b/thirdparty/miniupnpc/src/win32_snprintf.h @@ -23,9 +23,9 @@ (defined(_MSC_VER) && _MSC_VER < 1900) /* Visual Studio older than 2015 */ || \ (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && defined(__NO_ISOCEXT)) /* mingw32 without iso c ext */ || \ (defined(__MINGW64_VERSION_MAJOR) && /* mingw-w64 not ... */ !( \ - (defined (__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO != 0)) /* ... with ansi stdio */ || \ + (defined (__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO != 0) /* ... with ansi stdio */ || \ (__MINGW64_VERSION_MAJOR >= 6 && defined(_UCRT)) /* ... at least 6.0.0 with ucrt */ || \ - (__MINGW64_VERSION_MAJOR >= 8 && !defined(__NO_ISOCEXT)) /* ... at least 8.0.0 with iso c ext */ || \ + (__MINGW64_VERSION_MAJOR >= 8 && !defined(__NO_ISOCEXT))) /* ... at least 8.0.0 with iso c ext */ || \ 0) || \ 0) |