summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format22
-rw-r--r--core/core_bind.cpp2
-rw-r--r--core/io/dir_access.cpp42
-rw-r--r--core/io/file_access.cpp2
-rw-r--r--core/io/file_access.h1
-rw-r--r--core/io/file_access_compressed.cpp19
-rw-r--r--core/io/file_access_compressed.h3
-rw-r--r--core/io/file_access_encrypted.cpp26
-rw-r--r--core/io/file_access_encrypted.h4
-rw-r--r--core/io/file_access_memory.cpp4
-rw-r--r--core/io/file_access_memory.h1
-rw-r--r--core/io/file_access_network.cpp9
-rw-r--r--core/io/file_access_network.h2
-rw-r--r--core/io/file_access_pack.cpp16
-rw-r--r--core/io/file_access_pack.h1
-rw-r--r--core/io/file_access_zip.cpp6
-rw-r--r--core/io/file_access_zip.h3
-rw-r--r--core/io/logger.cpp2
-rw-r--r--core/io/pck_packer.cpp9
-rw-r--r--core/io/resource_format_binary.cpp15
-rw-r--r--core/io/resource_uid.cpp2
-rw-r--r--core/os/os.cpp4
-rw-r--r--core/templates/cowdata.h25
-rw-r--r--doc/classes/@GlobalScope.xml4
-rw-r--r--doc/classes/CanvasItem.xml7
-rw-r--r--doc/classes/EditorInspector.xml10
-rw-r--r--doc/classes/RenderingServer.xml5
-rw-r--r--doc/classes/Viewport.xml4
-rw-r--r--drivers/unix/file_access_unix.cpp9
-rw-r--r--drivers/unix/file_access_unix.h2
-rw-r--r--drivers/windows/file_access_windows.cpp9
-rw-r--r--drivers/windows/file_access_windows.h3
-rw-r--r--editor/create_dialog.cpp48
-rw-r--r--editor/editor_export.cpp12
-rw-r--r--editor/editor_file_system.cpp372
-rw-r--r--editor/editor_resource_preview.cpp17
-rw-r--r--editor/export_template_manager.cpp3
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp11
-rw-r--r--editor/plugins/ot_features_plugin.cpp6
-rw-r--r--editor/plugins/script_editor_plugin.cpp22
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp267
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h21
-rw-r--r--editor/plugins/texture_editor_plugin.cpp2
-rw-r--r--modules/gdscript/gdscript.cpp14
-rw-r--r--modules/mono/csharp_script.cpp14
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp10
-rw-r--r--modules/theora/video_stream_theora.cpp2
-rw-r--r--modules/visual_script/editor/visual_script_editor.cpp2
-rw-r--r--platform/android/file_access_android.cpp6
-rw-r--r--platform/android/file_access_android.h3
-rw-r--r--platform/iphone/export/export_plugin.cpp30
-rw-r--r--platform/javascript/api/javascript_tools_editor_plugin.cpp14
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp8
-rw-r--r--platform/osx/export/export_plugin.cpp30
-rw-r--r--platform/uwp/export/app_packager.cpp2
-rw-r--r--platform/uwp/export/export_plugin.h22
-rw-r--r--scene/gui/tree.cpp120
-rw-r--r--scene/main/canvas_item.cpp6
-rw-r--r--scene/main/canvas_item.h2
-rw-r--r--scene/main/http_request.cpp2
-rw-r--r--scene/main/viewport.cpp2
-rw-r--r--scene/resources/convex_polygon_shape_2d.cpp2
-rw-r--r--scene/resources/resource_format_text.cpp207
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp175
-rw-r--r--servers/rendering/renderer_canvas_cull.h2
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl22
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl22
-rw-r--r--servers/rendering/renderer_viewport.cpp14
-rw-r--r--servers/rendering/rendering_server_default.h2
-rw-r--r--servers/rendering/shader_language.cpp7
-rw-r--r--servers/rendering/shader_language.h8
-rw-r--r--servers/rendering_server.cpp2
-rw-r--r--servers/rendering_server.h2
73 files changed, 1101 insertions, 707 deletions
diff --git a/.clang-format b/.clang-format
index e011f060b7..f7527b8927 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,6 +1,6 @@
# 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 13.0).
+# chosen value in case the base style changes (last sync: Clang 14.0).
---
### General config, applies to all languages ###
BasedOnStyle: LLVM
@@ -15,7 +15,6 @@ AlignAfterOpenBracket: DontAlign
AlignOperands: DontAlign
AlignTrailingComments: false
# AllowAllArgumentsOnNextLine: true
-# AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
# AllowShortEnumsOnASingleLine: true
# AllowShortBlocksOnASingleLine: Never
@@ -62,8 +61,8 @@ BreakConstructorInitializers: AfterColon
# BreakStringLiterals: true
ColumnLimit: 0
# CommentPragmas: '^ IWYU pragma:'
+# QualifierAlignment: Leave
# CompactNamespaces: false
-ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
@@ -73,6 +72,9 @@ Cpp11BracedListStyle: false
# EmptyLineAfterAccessModifier: Never
# EmptyLineBeforeAccessModifier: LogicalBlock
# ExperimentalAutoDetectBinPacking: false
+# PackConstructorInitializers: BinPack
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+# AllowAllConstructorInitializersOnNextLine: true
# FixNamespaceComments: true
# ForEachMacros:
# - foreach
@@ -112,6 +114,7 @@ KeepEmptyLinesAtTheStartOfBlocks: false
# PenaltyBreakBeforeFirstCallParameter: 19
# PenaltyBreakComment: 300
# PenaltyBreakFirstLessLess: 120
+# PenaltyBreakOpenParenthesis: 0
# PenaltyBreakString: 1000
# PenaltyBreakTemplateDeclaration: 10
# PenaltyExcessCharacter: 1000000
@@ -121,6 +124,8 @@ KeepEmptyLinesAtTheStartOfBlocks: false
# PPIndentWidth: -1
# ReferenceAlignment: Pointer
# ReflowComments: true
+# RemoveBracesLLVM: false
+# SeparateDefinitionBlocks: Leave
# ShortNamespaceLines: 1
# SortIncludes: CaseSensitive
# SortJavaStaticImport: Before
@@ -134,15 +139,20 @@ KeepEmptyLinesAtTheStartOfBlocks: false
# SpaceBeforeCtorInitializerColon: true
# SpaceBeforeInheritanceColon: true
# SpaceBeforeParens: ControlStatements
+# SpaceBeforeParensOptions:
+# AfterControlStatements: true
+# AfterForeachMacros: true
+# AfterFunctionDefinitionName: false
+# AfterFunctionDeclarationName: false
+# AfterIfMacros: true
+# AfterOverloadedOperator: false
+# BeforeNonEmptyParentheses: false
# SpaceAroundPointerQualifiers: Default
# SpaceBeforeRangeBasedForLoopColon: true
-# SpaceInEmptyParentheses: false
-# SpacesBeforeTrailingComments: 1
# SpaceInEmptyBlock: false
# SpaceInEmptyParentheses: false
# SpacesBeforeTrailingComments: 1
# SpacesInAngles: Never
-# SpacesInContainerLiterals: true
# SpacesInConditionalStatement: false
# SpacesInContainerLiterals: true
# SpacesInCStyleCastParentheses: false
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 7d8ec6064d..53c58084ac 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -1088,7 +1088,7 @@ void File::flush() {
void File::close() {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened.");
- f = Ref<FileAccess>();
+ f.unref();
}
bool File::is_open() const {
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index dd994fe2fb..433a7efb21 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -275,27 +275,29 @@ String DirAccess::get_full_path(const String &p_path, AccessType p_access) {
Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) {
//printf("copy %s -> %s\n",p_from.ascii().get_data(),p_to.ascii().get_data());
Error err;
- Ref<FileAccess> fsrc = FileAccess::open(p_from, FileAccess::READ, &err);
- ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_from);
-
- Ref<FileAccess> fdst = FileAccess::open(p_to, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_to);
-
- fsrc->seek_end(0);
- int size = fsrc->get_position();
- fsrc->seek(0);
- err = OK;
- while (size--) {
- if (fsrc->get_error() != OK) {
- err = fsrc->get_error();
- break;
- }
- if (fdst->get_error() != OK) {
- err = fdst->get_error();
- break;
- }
+ {
+ Ref<FileAccess> fsrc = FileAccess::open(p_from, FileAccess::READ, &err);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_from);
+
+ Ref<FileAccess> fdst = FileAccess::open(p_to, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_to);
+
+ fsrc->seek_end(0);
+ int size = fsrc->get_position();
+ fsrc->seek(0);
+ err = OK;
+ while (size--) {
+ if (fsrc->get_error() != OK) {
+ err = fsrc->get_error();
+ break;
+ }
+ if (fdst->get_error() != OK) {
+ err = fdst->get_error();
+ break;
+ }
- fdst->store_8(fsrc->get_8());
+ fdst->store_8(fsrc->get_8());
+ }
}
if (err == OK && p_chmod_flags != -1) {
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index 87c10074af..7d8da1b11c 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -105,7 +105,7 @@ Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *
*r_error = err;
}
if (err != OK) {
- ret = Ref<FileAccess>();
+ ret.unref();
}
return ret;
diff --git a/core/io/file_access.h b/core/io/file_access.h
index 60abfe3c5e..e2c11142d7 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -88,7 +88,6 @@ public:
WRITE_READ = 7,
};
- virtual void close() = 0; ///< close a file
virtual bool is_open() const = 0; ///< true when file is open
virtual String get_path() const { return ""; } /// returns the path for the current open file
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 0c961ba8fb..1d0a718166 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -63,7 +63,7 @@ Error FileAccessCompressed::open_after_magic(Ref<FileAccess> p_base) {
cmode = (Compression::Mode)f->get_32();
block_size = f->get_32();
if (block_size == 0) {
- f = Ref<FileAccess>();
+ f.unref();
ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Can't open compressed file '" + p_base->get_path() + "' with block size 0, it is corrupted.");
}
read_total = f->get_32();
@@ -97,16 +97,13 @@ Error FileAccessCompressed::open_after_magic(Ref<FileAccess> p_base) {
Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(p_mode_flags == READ_WRITE, ERR_UNAVAILABLE);
-
- if (f.is_valid()) {
- close();
- }
+ _close();
Error err;
f = FileAccess::open(p_path, p_mode_flags, &err);
if (err != OK) {
//not openable
- f = Ref<FileAccess>();
+ f.unref();
return err;
}
@@ -126,7 +123,7 @@ Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) {
rmagic[4] = 0;
err = ERR_FILE_UNRECOGNIZED;
if (magic != rmagic || (err = open_after_magic(f)) != OK) {
- f = Ref<FileAccess>();
+ f.unref();
return err;
}
}
@@ -134,7 +131,7 @@ Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) {
return OK;
}
-void FileAccessCompressed::close() {
+void FileAccessCompressed::_close() {
if (f.is_null()) {
return;
}
@@ -180,7 +177,7 @@ void FileAccessCompressed::close() {
buffer.clear();
read_blocks.clear();
}
- f = Ref<FileAccess>();
+ f.unref();
}
bool FileAccessCompressed::is_open() const {
@@ -373,7 +370,5 @@ Error FileAccessCompressed::_set_unix_permissions(const String &p_file, uint32_t
}
FileAccessCompressed::~FileAccessCompressed() {
- if (f.is_valid()) {
- close();
- }
+ _close();
}
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index cd28c576cf..b8382e61d9 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -63,13 +63,14 @@ class FileAccessCompressed : public FileAccess {
mutable Vector<uint8_t> buffer;
Ref<FileAccess> f;
+ void _close();
+
public:
void configure(const String &p_magic, Compression::Mode p_mode = Compression::MODE_ZSTD, uint32_t p_block_size = 4096);
Error open_after_magic(Ref<FileAccess> p_base);
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
virtual void seek(uint64_t p_position); ///< seek to a given position
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 2443e2bea0..d1b014a0be 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -115,29 +115,11 @@ Error FileAccessEncrypted::_open(const String &p_path, int p_mode_flags) {
return OK;
}
-void FileAccessEncrypted::close() {
+void FileAccessEncrypted::_close() {
if (file.is_null()) {
return;
}
- _release();
-
- file->close();
-
- file = Ref<FileAccess>();
-}
-
-void FileAccessEncrypted::release() {
- if (file.is_null()) {
- return;
- }
-
- _release();
-
- file = Ref<FileAccess>();
-}
-
-void FileAccessEncrypted::_release() {
if (writing) {
Vector<uint8_t> compressed;
uint64_t len = data.size();
@@ -175,6 +157,8 @@ void FileAccessEncrypted::_release() {
file->store_buffer(compressed.ptr(), compressed.size());
data.clear();
}
+
+ file.unref();
}
bool FileAccessEncrypted::is_open() const {
@@ -311,7 +295,5 @@ Error FileAccessEncrypted::_set_unix_permissions(const String &p_file, uint32_t
}
FileAccessEncrypted::~FileAccessEncrypted() {
- if (file.is_valid()) {
- close();
- }
+ _close();
}
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index 5d0b369fbf..0d1ee6a4d8 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -54,15 +54,13 @@ private:
mutable bool eofed = false;
bool use_magic = true;
- void _release();
+ void _close();
public:
Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true);
Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
- virtual void release(); ///< finish and keep base file open
virtual bool is_open() const; ///< true when file is open
virtual String get_path() const; /// returns the path for the current open file
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index 62da51b09f..943dc72307 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -94,10 +94,6 @@ Error FileAccessMemory::_open(const String &p_path, int p_mode_flags) {
return OK;
}
-void FileAccessMemory::close() {
- data = nullptr;
-}
-
bool FileAccessMemory::is_open() const {
return data != nullptr;
}
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index baaad5f086..868b8ed481 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -46,7 +46,6 @@ public:
virtual Error open_custom(const uint8_t *p_data, uint64_t p_len); ///< open a file
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
virtual void seek(uint64_t p_position); ///< seek to a given position
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 612181f8d5..1365b4b593 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -254,9 +254,8 @@ void FileAccessNetwork::_respond(uint64_t p_len, Error p_status) {
Error FileAccessNetwork::_open(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(p_mode_flags != READ, ERR_UNAVAILABLE);
- if (opened) {
- close();
- }
+ _close();
+
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
DEBUG_PRINT("open: " + p_path);
@@ -287,7 +286,7 @@ Error FileAccessNetwork::_open(const String &p_path, int p_mode_flags) {
return response;
}
-void FileAccessNetwork::close() {
+void FileAccessNetwork::_close() {
if (!opened) {
return;
}
@@ -483,7 +482,7 @@ FileAccessNetwork::FileAccessNetwork() {
}
FileAccessNetwork::~FileAccessNetwork() {
- close();
+ _close();
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
nc->lock_mutex();
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index 6cae49b540..6afbf6adf5 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -113,6 +113,7 @@ class FileAccessNetwork : public FileAccess {
void _queue_page(int32_t p_page) const;
void _respond(uint64_t p_len, Error p_status);
void _set_block(uint64_t p_offset, const Vector<uint8_t> &p_block);
+ void _close();
public:
enum Command {
@@ -131,7 +132,6 @@ public:
};
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
virtual void seek(uint64_t p_position); ///< seek to a given position
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index 0b8deb8ec2..c6e14ffee7 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -226,15 +226,17 @@ Error FileAccessPack::_open(const String &p_path, int p_mode_flags) {
return ERR_UNAVAILABLE;
}
-void FileAccessPack::close() {
- f->close();
-}
-
bool FileAccessPack::is_open() const {
- return f->is_open();
+ if (f.is_valid()) {
+ return f->is_open();
+ } else {
+ return false;
+ }
}
void FileAccessPack::seek(uint64_t p_position) {
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use.");
+
if (p_position > pf.size) {
eof = true;
} else {
@@ -262,6 +264,7 @@ bool FileAccessPack::eof_reached() const {
}
uint8_t FileAccessPack::get_8() const {
+ ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use.");
if (pos >= pf.size) {
eof = true;
return 0;
@@ -272,6 +275,7 @@ uint8_t FileAccessPack::get_8() const {
}
uint64_t FileAccessPack::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
+ ERR_FAIL_COND_V_MSG(f.is_null(), -1, "File must be opened before use.");
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
if (eof) {
@@ -295,6 +299,8 @@ uint64_t FileAccessPack::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
}
void FileAccessPack::set_big_endian(bool p_big_endian) {
+ ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use.");
+
FileAccess::set_big_endian(p_big_endian);
f->set_big_endian(p_big_endian);
}
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 399b345b35..44df2029bd 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -157,7 +157,6 @@ class FileAccessPack : public FileAccess {
virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
public:
- virtual void close();
virtual bool is_open() const;
virtual void seek(uint64_t p_position);
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 1caff2dc02..17f2335a8e 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -235,7 +235,7 @@ ZipArchive::~ZipArchive() {
}
Error FileAccessZip::_open(const String &p_path, int p_mode_flags) {
- close();
+ _close();
ERR_FAIL_COND_V(p_mode_flags & FileAccess::WRITE, FAILED);
ZipArchive *arch = ZipArchive::get_singleton();
@@ -249,7 +249,7 @@ Error FileAccessZip::_open(const String &p_path, int p_mode_flags) {
return OK;
}
-void FileAccessZip::close() {
+void FileAccessZip::_close() {
if (!zfile) {
return;
}
@@ -341,7 +341,7 @@ FileAccessZip::FileAccessZip(const String &p_path, const PackedData::PackedFile
}
FileAccessZip::~FileAccessZip() {
- close();
+ _close();
}
#endif // MINIZIP_ENABLED
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index f6249add4b..2504aeedc4 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -82,9 +82,10 @@ class FileAccessZip : public FileAccess {
mutable bool at_eof;
+ void _close();
+
public:
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
virtual void seek(uint64_t p_position); ///< seek to a given position
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index 0caa2af5c4..c19fc2820b 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -148,7 +148,7 @@ void RotatedFileLogger::clear_old_backups() {
}
void RotatedFileLogger::rotate_file() {
- file = Ref<FileAccess>();
+ file.unref();
if (FileAccess::exists(base_path)) {
if (max_files > 1) {
diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp
index d1a305e836..aa1b323db2 100644
--- a/core/io/pck_packer.cpp
+++ b/core/io/pck_packer.cpp
@@ -195,7 +195,8 @@ Error PCKPacker::flush(bool p_verbose) {
}
if (fae.is_valid()) {
- fae->release();
+ fhead.unref();
+ fae.unref();
}
int header_padding = _get_pad(alignment, file->get_position());
@@ -216,7 +217,6 @@ Error PCKPacker::flush(bool p_verbose) {
Ref<FileAccess> src = FileAccess::open(files[i].src_path, FileAccess::READ);
uint64_t to_write = files[i].size;
- fae = Ref<FileAccess>();
Ref<FileAccess> ftmp = file;
if (files[i].encrypted) {
fae.instantiate();
@@ -234,7 +234,8 @@ Error PCKPacker::flush(bool p_verbose) {
}
if (fae.is_valid()) {
- fae->release();
+ ftmp.unref();
+ fae.unref();
}
int pad = _get_pad(alignment, file->get_position());
@@ -253,7 +254,7 @@ Error PCKPacker::flush(bool p_verbose) {
printf("\n");
}
- file = Ref<FileAccess>();
+ file.unref();
memdelete_arr(buf);
return OK;
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 87e4a01819..8d4dbc3f73 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -789,7 +789,7 @@ Error ResourceLoaderBinary::load() {
resource_cache.push_back(res);
if (main) {
- f = Ref<FileAccess>();
+ f.unref();
resource = res;
resource->set_as_translation_remapped(translation_remapped);
error = OK;
@@ -868,7 +868,7 @@ void ResourceLoaderBinary::open(Ref<FileAccess> p_f, bool p_no_resources, bool p
fac.instantiate();
error = fac->open_after_magic(f);
if (error != OK) {
- f = Ref<FileAccess>();
+ f.unref();
ERR_FAIL_MSG("Failed to open binary resource file: " + local_path + ".");
}
f = fac;
@@ -876,7 +876,7 @@ void ResourceLoaderBinary::open(Ref<FileAccess> p_f, bool p_no_resources, bool p
} else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') {
// Not normal.
error = ERR_FILE_UNRECOGNIZED;
- f = Ref<FileAccess>();
+ f.unref();
ERR_FAIL_MSG("Unrecognized binary resource file: " + local_path + ".");
}
@@ -901,7 +901,7 @@ void ResourceLoaderBinary::open(Ref<FileAccess> p_f, bool p_no_resources, bool p
print_bl("format: " + itos(ver_format));
if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) {
- f = Ref<FileAccess>();
+ f.unref();
ERR_FAIL_MSG(vformat("File '%s' can't be loaded, as it uses a format version (%d) or engine version (%d.%d) which are not supported by your engine version (%s).",
local_path, ver_format, ver_major, ver_minor, VERSION_BRANCH));
}
@@ -978,6 +978,7 @@ void ResourceLoaderBinary::open(Ref<FileAccess> p_f, bool p_no_resources, bool p
if (f->eof_reached()) {
error = ERR_FILE_CORRUPT;
+ f.unref();
ERR_FAIL_MSG("Premature end of file (EOF): " + local_path + ".");
}
}
@@ -994,7 +995,7 @@ String ResourceLoaderBinary::recognize(Ref<FileAccess> p_f) {
fac.instantiate();
error = fac->open_after_magic(f);
if (error != OK) {
- f = Ref<FileAccess>();
+ f.unref();
return "";
}
f = fac;
@@ -1002,7 +1003,7 @@ String ResourceLoaderBinary::recognize(Ref<FileAccess> p_f) {
} else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') {
// Not normal.
error = ERR_FILE_UNRECOGNIZED;
- f = Ref<FileAccess>();
+ f.unref();
return "";
}
@@ -1016,7 +1017,7 @@ String ResourceLoaderBinary::recognize(Ref<FileAccess> p_f) {
uint32_t ver_format = f->get_32();
if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) {
- f = Ref<FileAccess>();
+ f.unref();
return "";
}
diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp
index 8f1f354e90..515b7c710e 100644
--- a/core/io/resource_uid.cpp
+++ b/core/io/resource_uid.cpp
@@ -220,7 +220,7 @@ Error ResourceUID::update_cache() {
}
}
- if (f != nullptr) {
+ if (f.is_valid()) {
f->seek(0);
f->store_32(cache_entries); //update amount of entries
}
diff --git a/core/os/os.cpp b/core/os/os.cpp
index bf6cd4c9ab..846aeb16c5 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -201,14 +201,14 @@ void OS::print_all_resources(String p_to_file) {
Error err;
_OSPRF = FileAccess::open(p_to_file, FileAccess::WRITE, &err);
if (err != OK) {
- _OSPRF = Ref<FileAccess>();
+ _OSPRF.unref();
ERR_FAIL_MSG("Can't print all resources to file: " + String(p_to_file) + ".");
}
}
ObjectDB::debug_objects(_OS_printres);
- _OSPRF = Ref<FileAccess>();
+ _OSPRF.unref();
}
void OS::print_resources_in_use(bool p_short) {
diff --git a/core/templates/cowdata.h b/core/templates/cowdata.h
index 326616b607..f1ac32928f 100644
--- a/core/templates/cowdata.h
+++ b/core/templates/cowdata.h
@@ -86,13 +86,6 @@ private:
return reinterpret_cast<uint32_t *>(_ptr) - 1;
}
- _FORCE_INLINE_ T *_get_data() const {
- if (!_ptr) {
- return nullptr;
- }
- return reinterpret_cast<T *>(_ptr);
- }
-
_FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const {
return next_power_of_2(p_elements * sizeof(T));
}
@@ -128,11 +121,11 @@ public:
_FORCE_INLINE_ T *ptrw() {
_copy_on_write();
- return (T *)_get_data();
+ return _ptr;
}
_FORCE_INLINE_ const T *ptr() const {
- return _get_data();
+ return _ptr;
}
_FORCE_INLINE_ int size() const {
@@ -150,19 +143,19 @@ public:
_FORCE_INLINE_ void set(int p_index, const T &p_elem) {
ERR_FAIL_INDEX(p_index, size());
_copy_on_write();
- _get_data()[p_index] = p_elem;
+ _ptr[p_index] = p_elem;
}
_FORCE_INLINE_ T &get_m(int p_index) {
CRASH_BAD_INDEX(p_index, size());
_copy_on_write();
- return _get_data()[p_index];
+ return _ptr[p_index];
}
_FORCE_INLINE_ const T &get(int p_index) const {
CRASH_BAD_INDEX(p_index, size());
- return _get_data()[p_index];
+ return _ptr[p_index];
}
Error resize(int p_size);
@@ -249,7 +242,7 @@ uint32_t CowData<T>::_copy_on_write() {
} else {
for (uint32_t i = 0; i < current_size; i++) {
- memnew_placement(&_data[i], T(_get_data()[i]));
+ memnew_placement(&_data[i], T(_ptr[i]));
}
}
@@ -308,10 +301,8 @@ Error CowData<T>::resize(int p_size) {
// construct the newly created elements
if (!__has_trivial_constructor(T)) {
- T *elems = _get_data();
-
for (int i = *_get_size(); i < p_size; i++) {
- memnew_placement(&elems[i], T);
+ memnew_placement(&_ptr[i], T);
}
}
@@ -321,7 +312,7 @@ Error CowData<T>::resize(int p_size) {
if (!__has_trivial_destructor(T)) {
// deinitialize no longer needed elements
for (uint32_t i = p_size; i < *_get_size(); i++) {
- T *t = &_get_data()[i];
+ T *t = &_ptr[i];
t->~T();
}
}
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index a2b310ca82..da6513a08b 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -2546,13 +2546,13 @@
The property is a translatable string.
</constant>
<constant name="PROPERTY_USAGE_GROUP" value="128" enum="PropertyUsageFlags">
- Used to group properties together in the editor.
+ Used to group properties together in the editor. See [EditorInspector].
</constant>
<constant name="PROPERTY_USAGE_CATEGORY" value="256" enum="PropertyUsageFlags">
Used to categorize properties together in the editor.
</constant>
<constant name="PROPERTY_USAGE_SUBGROUP" value="512" enum="PropertyUsageFlags">
- Used to group properties together in the editor in a subgroup (under a group).
+ Used to group properties together in the editor in a subgroup (under a group). See [EditorInspector].
</constant>
<constant name="PROPERTY_USAGE_NO_INSTANCE_STATE" value="2048" enum="PropertyUsageFlags">
The property does not save its state in [PackedScene].
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index baaf33956f..6cd2da520f 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -103,8 +103,9 @@
<argument index="1" name="to" type="Vector2" />
<argument index="2" name="color" type="Color" />
<argument index="3" name="width" type="float" default="1.0" />
+ <argument index="4" name="antialiased" type="bool" default="false" />
<description>
- Draws a line from a 2D point to another, with a given color and width. See also [method draw_multiline] and [method draw_polyline].
+ Draws a line from a 2D point to another, with a given color and width. It can be optionally antialiased. See also [method draw_multiline] and [method draw_polyline].
</description>
</method>
<method name="draw_mesh">
@@ -191,7 +192,7 @@
<argument index="2" name="width" type="float" default="1.0" />
<argument index="3" name="antialiased" type="bool" default="false" />
<description>
- Draws interconnected line segments with a uniform [code]color[/code] and [code]width[/code]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline] instead. See also [method draw_polygon].
+ Draws interconnected line segments with a uniform [code]color[/code] and [code]width[/code] and optional antialiasing. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline] instead. See also [method draw_polygon].
</description>
</method>
<method name="draw_polyline_colors">
@@ -201,7 +202,7 @@
<argument index="2" name="width" type="float" default="1.0" />
<argument index="3" name="antialiased" type="bool" default="false" />
<description>
- Draws interconnected line segments with a uniform [code]width[/code] and segment-by-segment coloring. Colors assigned to line segments match by index between [code]points[/code] and [code]colors[/code]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline_colors] instead. See also [method draw_polygon].
+ Draws interconnected line segments with a uniform [code]width[/code] and segment-by-segment coloring, and optional antialiasing. Colors assigned to line segments match by index between [code]points[/code] and [code]colors[/code]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline_colors] instead. See also [method draw_polygon].
</description>
</method>
<method name="draw_primitive">
diff --git a/doc/classes/EditorInspector.xml b/doc/classes/EditorInspector.xml
index cd249ed319..365e1f13a9 100644
--- a/doc/classes/EditorInspector.xml
+++ b/doc/classes/EditorInspector.xml
@@ -1,11 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorInspector" inherits="ScrollContainer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A tab used to edit properties of the selected node.
+ A control used to edit properties of an object.
</brief_description>
<description>
- The editor inspector is by default located on the right-hand side of the editor. It's used to edit the properties of the selected node. For example, you can select a node such as the Sprite2D then edit its transform through the inspector tool. The editor inspector is an essential tool in the game development workflow.
- [b]Note:[/b] This class shouldn't be instantiated directly. Instead, access the singleton using [method EditorInterface.get_inspector].
+ This is the control that implements property editing in the editor's Settings dialogs, the Inspector dock, etc. To get the [EditorInspector] used in the editor's Inspector dock, use [method EditorInterface.get_inspector].
+ [EditorInspector] will show properties in the same order as the array returned by [method Object.get_property_list].
+ If a property's name is path-like (i.e. if it contains forward slashes), [EditorInspector] will create nested sections for "directories" along the path. For example, if a property is named [code]highlighting/gdscript/node_path_color[/code], it will be shown as "Node Path Color" inside the "GDScript" section nested inside the "Highlighting" section.
+ If a property has [constant @GlobalScope.PROPERTY_USAGE_GROUP] usage, it will group subsequent properties whose name starts with the property's hint string. The group ends when a property does not start with that hint string or when a new group starts. An empty group name effectively ends the current group. [EditorInspector] will create a top-level section for each group. For example, if a property with group usage is named [code]Collide With[/code] and its hint string is [code]collide_with_[/code], a subsequent [code]collide_with_area[/code] property will be shown as "Area" inside the "Collide With" section.
+ If a property has [constant @GlobalScope.PROPERTY_USAGE_SUBGROUP] usage, a subgroup will be created in the same way as a group, and a second-level section will be created for each subgroup.
+ [b]Note:[/b] Unlike sections created from path-like property names, [EditorInspector] won't capitalize the name for sections created from groups. So properties with group usage usually use capitalized names instead of snake_cased names.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index f1a15a08dd..5bb83c8ffd 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -183,6 +183,7 @@
<argument index="2" name="to" type="Vector2" />
<argument index="3" name="color" type="Color" />
<argument index="4" name="width" type="float" default="1.0" />
+ <argument index="5" name="antialiased" type="bool" default="false" />
<description>
</description>
</method>
@@ -3932,10 +3933,10 @@
[FogVolume] will have no shape, will cover the whole world and will not be culled.
</constant>
<constant name="VIEWPORT_SCALING_3D_MODE_BILINEAR" value="0" enum="ViewportScaling3DMode">
- Enables bilinear scaling on 3D viewports. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less then [code]1.0[/code] will result in undersampling while values greater than [code]1.0[/code] will result in supersampling. A value of [code]1.0[/code] disables scaling.
+ Use bilinear scaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less then [code]1.0[/code] will result in undersampling while values greater than [code]1.0[/code] will result in supersampling. A value of [code]1.0[/code] disables scaling.
</constant>
<constant name="VIEWPORT_SCALING_3D_MODE_FSR" value="1" enum="ViewportScaling3DMode">
- Enables FSR upscaling on 3D viewports. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less then [code]1.0[/code] will be result in the viewport being upscaled using FSR. Values greater than [code]1.0[/code] are not supported and bilinear supersampling will be used instead. A value of [code]1.0[/code] disables scaling.
+ Use AMD FidelityFX Super Resolution 1.0 upscaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less then [code]1.0[/code] will be result in the viewport being upscaled using FSR. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] disables scaling.
</constant>
<constant name="VIEWPORT_SCALING_3D_MODE_MAX" value="2" enum="ViewportScaling3DMode">
</constant>
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index b5916f8c17..6f4720491d 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -332,10 +332,10 @@
Represents the size of the [enum ShadowAtlasQuadrantSubdiv] enum.
</constant>
<constant name="SCALING_3D_MODE_BILINEAR" value="0" enum="Scaling3DMode">
- Enables bilinear scaling on 3D viewports. The amount of scaling can be set using [member scaling_3d_scale]. Values less then [code]1.0[/code] will result in undersampling while values greater than [code]1.0[/code] will result in supersampling. A value of [code]1.0[/code] disables scaling.
+ Use bilinear scaling for the viewport's 3D buffer. The amount of scaling can be set using [member scaling_3d_scale]. Values less then [code]1.0[/code] will result in undersampling while values greater than [code]1.0[/code] will result in supersampling. A value of [code]1.0[/code] disables scaling.
</constant>
<constant name="SCALING_3D_MODE_FSR" value="1" enum="Scaling3DMode">
- Enables FSR upscaling on 3D viewports. The amount of scaling can be set using [member scaling_3d_scale]. Values less then [code]1.0[/code] will be result in the viewport being upscaled using FSR. Values greater than [code]1.0[/code] are not supported and bilinear supersampling will be used instead. A value of [code]1.0[/code] disables scaling.
+ Use AMD FidelityFX Super Resolution 1.0 upscaling for the viewport's 3D buffer. The amount of scaling can be set using [member scaling_3d_scale]. Values less then [code]1.0[/code] will be result in the viewport being upscaled using FSR. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] disables scaling.
</constant>
<constant name="SCALING_3D_MODE_MAX" value="2" enum="Scaling3DMode">
Represents the size of the [enum Scaling3DMode] enum.
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 99da292e12..e0b2994b63 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -71,10 +71,7 @@ void FileAccessUnix::check_errors() const {
}
Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) {
- if (f) {
- fclose(f);
- }
- f = nullptr;
+ _close();
path_src = p_path;
path = fix_path(p_path);
@@ -148,7 +145,7 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) {
return OK;
}
-void FileAccessUnix::close() {
+void FileAccessUnix::_close() {
if (!f) {
return;
}
@@ -343,7 +340,7 @@ Ref<FileAccess> FileAccessUnix::create_libc() {
CloseNotificationFunc FileAccessUnix::close_notification_func = nullptr;
FileAccessUnix::~FileAccessUnix() {
- close();
+ _close();
}
#endif
diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h
index 692776915c..4340bbbc82 100644
--- a/drivers/unix/file_access_unix.h
+++ b/drivers/unix/file_access_unix.h
@@ -50,12 +50,12 @@ class FileAccessUnix : public FileAccess {
String path_src;
static Ref<FileAccess> create_libc();
+ void _close();
public:
static CloseNotificationFunc close_notification_func;
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
virtual String get_path() const; /// returns the path for the current open file
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index 59dc1d8e77..1a66d19373 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -59,11 +59,10 @@ void FileAccessWindows::check_errors() const {
}
Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
+ _close();
+
path_src = p_path;
path = fix_path(p_path);
- if (f) {
- close();
- }
const WCHAR *mode_string;
@@ -134,7 +133,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
}
}
-void FileAccessWindows::close() {
+void FileAccessWindows::_close() {
if (!f) {
return;
}
@@ -350,7 +349,7 @@ Error FileAccessWindows::_set_unix_permissions(const String &p_file, uint32_t p_
}
FileAccessWindows::~FileAccessWindows() {
- close();
+ _close();
}
#endif // WINDOWS_ENABLED
diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h
index 93d37c3b5a..5d67b6ca4f 100644
--- a/drivers/windows/file_access_windows.h
+++ b/drivers/windows/file_access_windows.h
@@ -48,9 +48,10 @@ class FileAccessWindows : public FileAccess {
String path_src;
String save_path;
+ void _close();
+
public:
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
virtual String get_path() const; /// returns the path for the current open file
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 50e1d03663..fbb61a1614 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -377,13 +377,15 @@ void CreateDialog::_confirmed() {
return;
}
- Ref<FileAccess> f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::WRITE);
- if (f.is_valid()) {
- f->store_line(selected_item);
-
- for (int i = 0; i < MIN(32, recent->get_item_count()); i++) {
- if (recent->get_item_text(i) != selected_item) {
- f->store_line(recent->get_item_text(i));
+ {
+ Ref<FileAccess> f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::WRITE);
+ if (f.is_valid()) {
+ f->store_line(selected_item);
+
+ for (int i = 0; i < MIN(32, recent->get_item_count()); i++) {
+ if (recent->get_item_text(i) != selected_item) {
+ f->store_line(recent->get_item_text(i));
+ }
}
}
}
@@ -645,23 +647,25 @@ void CreateDialog::_save_and_update_favorite_list() {
favorites->clear();
TreeItem *root = favorites->create_item();
- Ref<FileAccess> f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE);
- if (f.is_valid()) {
- for (int i = 0; i < favorite_list.size(); i++) {
- String l = favorite_list[i];
- String name = l.get_slicec(' ', 0);
- if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) {
- continue;
- }
- f->store_line(l);
+ {
+ Ref<FileAccess> f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE);
+ if (f.is_valid()) {
+ for (int i = 0; i < favorite_list.size(); i++) {
+ String l = favorite_list[i];
+ String name = l.get_slicec(' ', 0);
+ if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) {
+ continue;
+ }
+ f->store_line(l);
- if (_is_class_disabled_by_feature_profile(name)) {
- continue;
- }
+ if (_is_class_disabled_by_feature_profile(name)) {
+ continue;
+ }
- TreeItem *ti = favorites->create_item(root);
- ti->set_text(0, l);
- ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(name, icon_fallback));
+ TreeItem *ti = favorites->create_item(root);
+ ti->set_text(0, l);
+ ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(name, icon_fallback));
+ }
}
}
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index 40b850cace..58a9175df1 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -343,7 +343,8 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa
ftmp->store_buffer(p_data.ptr(), p_data.size());
if (fae.is_valid()) {
- fae->release();
+ ftmp.unref();
+ fae.unref();
}
int pad = _get_pad(PCK_PADDING, pd->f->get_position());
@@ -1142,6 +1143,10 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
Error err = export_project_files(p_preset, p_debug, _save_pack_file, &pd, _add_shared_object);
+ // Close temp file.
+ pd.f.unref();
+ ftmp.unref();
+
if (err != OK) {
DirAccess::remove_file_or_error(tmppath);
ERR_PRINT("Failed to export project files");
@@ -1269,7 +1274,8 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
}
if (fae.is_valid()) {
- fae->release();
+ fhead.unref();
+ fae.unref();
}
int header_padding = _get_pad(PCK_PADDING, f->get_position());
@@ -1301,6 +1307,8 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
f->store_buffer(buf, got);
}
+ ftmp.unref(); // Close temp file.
+
if (p_embed) {
// Ensure embedded data ends at a 64-bit multiple
uint64_t embed_end = f->get_position() - embed_pos + 12;
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 98bf5d3234..099dfe69d5 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -218,69 +218,71 @@ void EditorFileSystem::_scan_filesystem() {
String project = ProjectSettings::get_singleton()->get_resource_path();
String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME);
- Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::READ);
-
- bool first = true;
- if (f.is_valid()) {
- //read the disk cache
- while (!f->eof_reached()) {
- String l = f->get_line().strip_edges();
- if (first) {
- if (first_scan) {
- // only use this on first scan, afterwards it gets ignored
- // this is so on first reimport we synchronize versions, then
- // we don't care until editor restart. This is for usability mainly so
- // your workflow is not killed after changing a setting by forceful reimporting
- // everything there is.
- filesystem_settings_version_for_import = l.strip_edges();
- if (filesystem_settings_version_for_import != ResourceFormatImporter::get_singleton()->get_import_settings_hash()) {
- revalidate_import_files = true;
+ {
+ Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::READ);
+
+ bool first = true;
+ if (f.is_valid()) {
+ //read the disk cache
+ while (!f->eof_reached()) {
+ String l = f->get_line().strip_edges();
+ if (first) {
+ if (first_scan) {
+ // only use this on first scan, afterwards it gets ignored
+ // this is so on first reimport we synchronize versions, then
+ // we don't care until editor restart. This is for usability mainly so
+ // your workflow is not killed after changing a setting by forceful reimporting
+ // everything there is.
+ filesystem_settings_version_for_import = l.strip_edges();
+ if (filesystem_settings_version_for_import != ResourceFormatImporter::get_singleton()->get_import_settings_hash()) {
+ revalidate_import_files = true;
+ }
}
+ first = false;
+ continue;
+ }
+ if (l.is_empty()) {
+ continue;
}
- first = false;
- continue;
- }
- if (l.is_empty()) {
- continue;
- }
- if (l.begins_with("::")) {
- Vector<String> split = l.split("::");
- ERR_CONTINUE(split.size() != 3);
- String name = split[1];
+ if (l.begins_with("::")) {
+ Vector<String> split = l.split("::");
+ ERR_CONTINUE(split.size() != 3);
+ String name = split[1];
- cpath = name;
+ cpath = name;
- } else {
- Vector<String> split = l.split("::");
- ERR_CONTINUE(split.size() != 9);
- String name = split[0];
- String file;
-
- file = name;
- name = cpath.plus_file(name);
-
- FileCache fc;
- fc.type = split[1];
- fc.uid = split[2].to_int();
- fc.modification_time = split[3].to_int();
- fc.import_modification_time = split[4].to_int();
- fc.import_valid = split[5].to_int() != 0;
- fc.import_group_file = split[6].strip_edges();
- fc.script_class_name = split[7].get_slice("<>", 0);
- fc.script_class_extends = split[7].get_slice("<>", 1);
- fc.script_class_icon_path = split[7].get_slice("<>", 2);
-
- String deps = split[8].strip_edges();
- if (deps.length()) {
- Vector<String> dp = deps.split("<>");
- for (int i = 0; i < dp.size(); i++) {
- String path = dp[i];
- fc.deps.push_back(path);
+ } else {
+ Vector<String> split = l.split("::");
+ ERR_CONTINUE(split.size() != 9);
+ String name = split[0];
+ String file;
+
+ file = name;
+ name = cpath.plus_file(name);
+
+ FileCache fc;
+ fc.type = split[1];
+ fc.uid = split[2].to_int();
+ fc.modification_time = split[3].to_int();
+ fc.import_modification_time = split[4].to_int();
+ fc.import_valid = split[5].to_int() != 0;
+ fc.import_group_file = split[6].strip_edges();
+ fc.script_class_name = split[7].get_slice("<>", 0);
+ fc.script_class_extends = split[7].get_slice("<>", 1);
+ fc.script_class_icon_path = split[7].get_slice("<>", 2);
+
+ String deps = split[8].strip_edges();
+ if (deps.length()) {
+ Vector<String> dp = deps.split("<>");
+ for (int i = 0; i < dp.size(); i++) {
+ String path = dp[i];
+ fc.deps.push_back(path);
+ }
}
- }
- file_cache[name] = fc;
+ file_cache[name] = fc;
+ }
}
}
}
@@ -1700,74 +1702,77 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
for (const KeyValue<String, Map<StringName, Variant>> &E : source_file_options) {
const String &file = E.key;
String base_path = ResourceFormatImporter::get_singleton()->get_import_base_path(file);
- Ref<FileAccess> f = FileAccess::open(file + ".import", FileAccess::WRITE);
- ERR_FAIL_COND_V_MSG(f.is_null(), ERR_FILE_CANT_OPEN, "Cannot open import file '" + file + ".import'.");
-
- //write manually, as order matters ([remap] has to go first for performance).
- f->store_line("[remap]");
- f->store_line("");
- f->store_line("importer=\"" + importer->get_importer_name() + "\"");
- int version = importer->get_format_version();
- if (version > 0) {
- f->store_line("importer_version=" + itos(version));
- }
- if (!importer->get_resource_type().is_empty()) {
- f->store_line("type=\"" + importer->get_resource_type() + "\"");
- }
-
Vector<String> dest_paths;
+ {
+ Ref<FileAccess> f = FileAccess::open(file + ".import", FileAccess::WRITE);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_FILE_CANT_OPEN, "Cannot open import file '" + file + ".import'.");
+
+ //write manually, as order matters ([remap] has to go first for performance).
+ f->store_line("[remap]");
+ f->store_line("");
+ f->store_line("importer=\"" + importer->get_importer_name() + "\"");
+ int version = importer->get_format_version();
+ if (version > 0) {
+ f->store_line("importer_version=" + itos(version));
+ }
+ if (!importer->get_resource_type().is_empty()) {
+ f->store_line("type=\"" + importer->get_resource_type() + "\"");
+ }
- if (err == OK) {
- String path = base_path + "." + importer->get_save_extension();
- f->store_line("path=\"" + path + "\"");
- dest_paths.push_back(path);
- }
-
- f->store_line("group_file=" + Variant(p_group_file).get_construct_string());
-
- if (err == OK) {
- f->store_line("valid=true");
- } else {
- f->store_line("valid=false");
- }
- f->store_line("[deps]\n");
+ if (err == OK) {
+ String path = base_path + "." + importer->get_save_extension();
+ f->store_line("path=\"" + path + "\"");
+ dest_paths.push_back(path);
+ }
- f->store_line("");
+ f->store_line("group_file=" + Variant(p_group_file).get_construct_string());
- f->store_line("source_file=" + Variant(file).get_construct_string());
- if (dest_paths.size()) {
- Array dp;
- for (int i = 0; i < dest_paths.size(); i++) {
- dp.push_back(dest_paths[i]);
+ if (err == OK) {
+ f->store_line("valid=true");
+ } else {
+ f->store_line("valid=false");
}
- f->store_line("dest_files=" + Variant(dp).get_construct_string() + "\n");
- }
- f->store_line("[params]");
- f->store_line("");
+ f->store_line("[deps]\n");
- //store options in provided order, to avoid file changing. Order is also important because first match is accepted first.
+ f->store_line("");
- List<ResourceImporter::ImportOption> options;
- importer->get_import_options(file, &options);
- //set default values
- for (const ResourceImporter::ImportOption &F : options) {
- String base = F.option.name;
- Variant v = F.default_value;
- if (source_file_options[file].has(base)) {
- v = source_file_options[file][base];
+ f->store_line("source_file=" + Variant(file).get_construct_string());
+ if (dest_paths.size()) {
+ Array dp;
+ for (int i = 0; i < dest_paths.size(); i++) {
+ dp.push_back(dest_paths[i]);
+ }
+ f->store_line("dest_files=" + Variant(dp).get_construct_string() + "\n");
+ }
+ f->store_line("[params]");
+ f->store_line("");
+
+ //store options in provided order, to avoid file changing. Order is also important because first match is accepted first.
+
+ List<ResourceImporter::ImportOption> options;
+ importer->get_import_options(file, &options);
+ //set default values
+ for (const ResourceImporter::ImportOption &F : options) {
+ String base = F.option.name;
+ Variant v = F.default_value;
+ if (source_file_options[file].has(base)) {
+ v = source_file_options[file][base];
+ }
+ String value;
+ VariantWriter::write_to_string(v, value);
+ f->store_line(base + "=" + value);
}
- String value;
- VariantWriter::write_to_string(v, value);
- f->store_line(base + "=" + value);
}
// Store the md5's of the various files. These are stored separately so that the .import files can be version controlled.
- Ref<FileAccess> md5s = FileAccess::open(base_path + ".md5", FileAccess::WRITE);
- ERR_FAIL_COND_V_MSG(md5s.is_null(), ERR_FILE_CANT_OPEN, "Cannot open MD5 file '" + base_path + ".md5'.");
+ {
+ Ref<FileAccess> md5s = FileAccess::open(base_path + ".md5", FileAccess::WRITE);
+ ERR_FAIL_COND_V_MSG(md5s.is_null(), ERR_FILE_CANT_OPEN, "Cannot open MD5 file '" + base_path + ".md5'.");
- md5s->store_line("source_md5=\"" + FileAccess::get_md5(file) + "\"");
- if (dest_paths.size()) {
- md5s->store_line("dest_md5=\"" + FileAccess::get_multiple_md5(dest_paths) + "\"\n");
+ md5s->store_line("source_md5=\"" + FileAccess::get_md5(file) + "\"");
+ if (dest_paths.size()) {
+ md5s->store_line("dest_md5=\"" + FileAccess::get_multiple_md5(dest_paths) + "\"\n");
+ }
}
EditorFileSystemDirectory *fs = nullptr;
@@ -1914,100 +1919,103 @@ void EditorFileSystem::_reimport_file(const String &p_file, const Map<StringName
//as import is complete, save the .import file
- Ref<FileAccess> f = FileAccess::open(p_file + ".import", FileAccess::WRITE);
- ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file from path '" + p_file + ".import'.");
-
- //write manually, as order matters ([remap] has to go first for performance).
- f->store_line("[remap]");
- f->store_line("");
- f->store_line("importer=\"" + importer->get_importer_name() + "\"");
- int version = importer->get_format_version();
- if (version > 0) {
- f->store_line("importer_version=" + itos(version));
- }
- if (!importer->get_resource_type().is_empty()) {
- f->store_line("type=\"" + importer->get_resource_type() + "\"");
- }
-
- if (uid == ResourceUID::INVALID_ID) {
- uid = ResourceUID::get_singleton()->create_id();
- }
+ Vector<String> dest_paths;
+ {
+ Ref<FileAccess> f = FileAccess::open(p_file + ".import", FileAccess::WRITE);
+ ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file from path '" + p_file + ".import'.");
- f->store_line("uid=\"" + ResourceUID::get_singleton()->id_to_text(uid) + "\""); //store in readable format
+ //write manually, as order matters ([remap] has to go first for performance).
+ f->store_line("[remap]");
+ f->store_line("");
+ f->store_line("importer=\"" + importer->get_importer_name() + "\"");
+ int version = importer->get_format_version();
+ if (version > 0) {
+ f->store_line("importer_version=" + itos(version));
+ }
+ if (!importer->get_resource_type().is_empty()) {
+ f->store_line("type=\"" + importer->get_resource_type() + "\"");
+ }
- Vector<String> dest_paths;
+ if (uid == ResourceUID::INVALID_ID) {
+ uid = ResourceUID::get_singleton()->create_id();
+ }
- if (err == OK) {
- if (importer->get_save_extension().is_empty()) {
- //no path
- } else if (import_variants.size()) {
- //import with variants
- for (const String &E : import_variants) {
- String path = base_path.c_escape() + "." + E + "." + importer->get_save_extension();
+ f->store_line("uid=\"" + ResourceUID::get_singleton()->id_to_text(uid) + "\""); //store in readable format
- f->store_line("path." + E + "=\"" + path + "\"");
+ if (err == OK) {
+ if (importer->get_save_extension().is_empty()) {
+ //no path
+ } else if (import_variants.size()) {
+ //import with variants
+ for (const String &E : import_variants) {
+ String path = base_path.c_escape() + "." + E + "." + importer->get_save_extension();
+
+ f->store_line("path." + E + "=\"" + path + "\"");
+ dest_paths.push_back(path);
+ }
+ } else {
+ String path = base_path + "." + importer->get_save_extension();
+ f->store_line("path=\"" + path + "\"");
dest_paths.push_back(path);
}
+
} else {
- String path = base_path + "." + importer->get_save_extension();
- f->store_line("path=\"" + path + "\"");
- dest_paths.push_back(path);
+ f->store_line("valid=false");
}
- } else {
- f->store_line("valid=false");
- }
+ if (metadata != Variant()) {
+ f->store_line("metadata=" + metadata.get_construct_string());
+ }
- if (metadata != Variant()) {
- f->store_line("metadata=" + metadata.get_construct_string());
- }
+ f->store_line("");
- f->store_line("");
+ f->store_line("[deps]\n");
- f->store_line("[deps]\n");
+ if (gen_files.size()) {
+ Array genf;
+ for (const String &E : gen_files) {
+ genf.push_back(E);
+ dest_paths.push_back(E);
+ }
- if (gen_files.size()) {
- Array genf;
- for (const String &E : gen_files) {
- genf.push_back(E);
- dest_paths.push_back(E);
+ String value;
+ VariantWriter::write_to_string(genf, value);
+ f->store_line("files=" + value);
+ f->store_line("");
}
- String value;
- VariantWriter::write_to_string(genf, value);
- f->store_line("files=" + value);
- f->store_line("");
- }
+ f->store_line("source_file=" + Variant(p_file).get_construct_string());
- f->store_line("source_file=" + Variant(p_file).get_construct_string());
-
- if (dest_paths.size()) {
- Array dp;
- for (int i = 0; i < dest_paths.size(); i++) {
- dp.push_back(dest_paths[i]);
+ if (dest_paths.size()) {
+ Array dp;
+ for (int i = 0; i < dest_paths.size(); i++) {
+ dp.push_back(dest_paths[i]);
+ }
+ f->store_line("dest_files=" + Variant(dp).get_construct_string() + "\n");
}
- f->store_line("dest_files=" + Variant(dp).get_construct_string() + "\n");
- }
- f->store_line("[params]");
- f->store_line("");
+ f->store_line("[params]");
+ f->store_line("");
- //store options in provided order, to avoid file changing. Order is also important because first match is accepted first.
+ //store options in provided order, to avoid file changing. Order is also important because first match is accepted first.
- for (const ResourceImporter::ImportOption &E : opts) {
- String base = E.option.name;
- String value;
- VariantWriter::write_to_string(params[base], value);
- f->store_line(base + "=" + value);
+ for (const ResourceImporter::ImportOption &E : opts) {
+ String base = E.option.name;
+ String value;
+ VariantWriter::write_to_string(params[base], value);
+ f->store_line(base + "=" + value);
+ }
}
// Store the md5's of the various files. These are stored separately so that the .import files can be version controlled.
- Ref<FileAccess> md5s = FileAccess::open(base_path + ".md5", FileAccess::WRITE);
- ERR_FAIL_COND_MSG(md5s.is_null(), "Cannot open MD5 file '" + base_path + ".md5'.");
+ {
+ Ref<FileAccess> md5s = FileAccess::open(base_path + ".md5", FileAccess::WRITE);
+ ERR_FAIL_COND_MSG(md5s.is_null(), "Cannot open MD5 file '" + base_path + ".md5'.");
- md5s->store_line("source_md5=\"" + FileAccess::get_md5(p_file) + "\"");
- if (dest_paths.size()) {
- md5s->store_line("dest_md5=\"" + FileAccess::get_multiple_md5(dest_paths) + "\"\n");
+ md5s->store_line("source_md5=\"" + FileAccess::get_md5(p_file) + "\"");
+ if (dest_paths.size()) {
+ md5s->store_line("dest_md5=\"" + FileAccess::get_multiple_md5(dest_paths) + "\"\n");
+ }
}
//update modified times, to avoid reimport
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index aa10d7e68e..8541918e88 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -263,28 +263,31 @@ void EditorResourcePreview::_iterate() {
if (tsize != thumbnail_size) {
cache_valid = false;
+ f.unref();
} else if (last_modtime != modtime) {
String last_md5 = f->get_line();
String md5 = FileAccess::get_md5(item.path);
+ f.unref();
if (last_md5 != md5) {
cache_valid = false;
-
} else {
//update modified time
- f = FileAccess::open(file, FileAccess::WRITE);
- if (f.is_null()) {
+ Ref<FileAccess> f2 = FileAccess::open(file, FileAccess::WRITE);
+ if (f2.is_null()) {
// Not returning as this would leave the thread hanging and would require
// some proper cleanup/disabling of resource preview generation.
ERR_PRINT("Cannot create file '" + file + "'. Check user write permissions.");
} else {
- f->store_line(itos(thumbnail_size));
- f->store_line(itos(has_small_texture));
- f->store_line(itos(modtime));
- f->store_line(md5);
+ f2->store_line(itos(thumbnail_size));
+ f2->store_line(itos(has_small_texture));
+ f2->store_line(itos(modtime));
+ f2->store_line(md5);
}
}
+ } else {
+ f.unref();
}
if (cache_valid) {
diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp
index a1fd2d9049..06c179e77c 100644
--- a/editor/export_template_manager.cpp
+++ b/editor/export_template_manager.cpp
@@ -514,7 +514,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
}
f->store_buffer(data.ptr(), data.size());
-
+ f.unref(); // close file.
#ifndef WINDOWS_ENABLED
FileAccess::set_unix_permissions(to_write, (info.external_fa >> 16) & 0x01FF);
#endif
@@ -728,6 +728,7 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_
Ref<FileAccess> f = FileAccess::open(to_write, FileAccess::WRITE);
if (f.is_valid()) {
f->store_buffer(data.ptr(), data.size());
+ f.unref(); // close file.
#ifndef WINDOWS_ENABLED
FileAccess::set_unix_permissions(to_write, (info.external_fa >> 16) & 0x01FF);
#endif
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 2081edca25..17a1bd1048 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -783,6 +783,7 @@ void AnimationPlayerEditor::_update_player() {
ITEM_CHECK_DISABLED(TOOL_RENAME_ANIM);
ITEM_CHECK_DISABLED(TOOL_EDIT_TRANSITIONS);
ITEM_CHECK_DISABLED(TOOL_REMOVE_ANIM);
+ ITEM_CHECK_DISABLED(TOOL_EDIT_RESOURCE);
#undef ITEM_CHECK_DISABLED
@@ -1079,15 +1080,9 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
_animation_remove();
} break;
case TOOL_EDIT_RESOURCE: {
- if (!animation->has_selectable_items()) {
- error_dialog->set_text(TTR("No animation to edit!"));
- error_dialog->popup_centered();
- return;
+ if (anim.is_valid()) {
+ EditorNode::get_singleton()->edit_resource(anim);
}
-
- String current2 = animation->get_item_text(animation->get_selected());
- Ref<Animation> anim2 = player->get_animation(current2);
- EditorNode::get_singleton()->edit_resource(anim2);
} break;
}
}
diff --git a/editor/plugins/ot_features_plugin.cpp b/editor/plugins/ot_features_plugin.cpp
index 27b35d803c..936eb747b0 100644
--- a/editor/plugins/ot_features_plugin.cpp
+++ b/editor/plugins/ot_features_plugin.cpp
@@ -145,8 +145,11 @@ void OpenTypeFeaturesAdd::setup(Object *p_object) {
void OpenTypeFeaturesAdd::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_ENTER_TREE: {
+ connect("pressed", callable_mp(this, &OpenTypeFeaturesAdd::_features_menu));
+ [[fallthrough]];
+ }
+ case NOTIFICATION_THEME_CHANGED: {
set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
} break;
}
@@ -173,7 +176,6 @@ OpenTypeFeaturesAdd::OpenTypeFeaturesAdd() {
menu_cu->set_name("CUMenu");
menu->add_child(menu_cu);
- connect("pressed", callable_mp(this, &OpenTypeFeaturesAdd::_features_menu));
menu->connect("id_pressed", callable_mp(this, &OpenTypeFeaturesAdd::_add_feature));
menu_cv->connect("id_pressed", callable_mp(this, &OpenTypeFeaturesAdd::_add_feature));
menu_ss->connect("id_pressed", callable_mp(this, &OpenTypeFeaturesAdd::_add_feature));
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 09bff7c00b..906edb006c 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -1091,10 +1091,12 @@ void ScriptEditor::_file_dialog_action(String p_file) {
switch (file_dialog_option) {
case FILE_NEW_TEXTFILE: {
Error err;
- Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err);
- if (err) {
- EditorNode::get_singleton()->show_warning(TTR("Error writing TextFile:") + "\n" + p_file, TTR("Error!"));
- break;
+ {
+ Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err);
+ if (err) {
+ EditorNode::get_singleton()->show_warning(TTR("Error writing TextFile:") + "\n" + p_file, TTR("Error!"));
+ break;
+ }
}
if (EditorFileSystem::get_singleton()) {
@@ -2209,13 +2211,15 @@ Error ScriptEditor::_save_text_file(Ref<TextFile> p_text_file, const String &p_p
String source = sqscr->get_text();
Error err;
- Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ {
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err, err, "Cannot save text file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err, err, "Cannot save text file '" + p_path + "'.");
- file->store_string(source);
- if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
- return ERR_CANT_CREATE;
+ file->store_string(source);
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ return ERR_CANT_CREATE;
+ }
}
if (ResourceSaver::get_timestamp_on_save()) {
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 87b5b829e0..27160f8c86 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -43,6 +43,11 @@
#include "scene/gui/margin_container.h"
#include "scene/gui/panel_container.h"
+static void _draw_shadowed_line(Control *p_control, const Point2 &p_from, const Size2 &p_size, const Size2 &p_shadow_offset, Color p_color, Color p_shadow_color) {
+ p_control->draw_line(p_from, p_from + p_size, p_color);
+ p_control->draw_line(p_from + p_shadow_offset, p_from + p_size + p_shadow_offset, p_shadow_color);
+}
+
void SpriteFramesEditor::gui_input(const Ref<InputEvent> &p_event) {
}
@@ -58,46 +63,62 @@ void SpriteFramesEditor::_open_sprite_sheet() {
}
int SpriteFramesEditor::_sheet_preview_position_to_frame_index(const Point2 &p_position) {
- if (p_position.x < 0 || p_position.y < 0) {
- return -1;
- }
+ const Size2i offset = _get_offset();
+ const Size2i frame_size = _get_frame_size();
+ const Size2i separation = _get_separation();
+ const Size2i block_size = frame_size + separation;
+ const Point2i position = p_position / sheet_zoom - offset;
- Size2i texture_size = split_sheet_preview->get_texture()->get_size();
- int h = split_sheet_h->get_value();
- int v = split_sheet_v->get_value();
- if (h > texture_size.width || v > texture_size.height) {
- return -1;
+ if (position.x % block_size.x > frame_size.x || position.y % block_size.y > frame_size.y) {
+ return -1; // Gap between frames.
}
- int x = int(p_position.x / sheet_zoom) / (texture_size.width / h);
- int y = int(p_position.y / sheet_zoom) / (texture_size.height / v);
- if (x >= h || y >= v) {
- return -1;
+ const Point2i frame = position / block_size;
+ const Size2i frame_count = _get_frame_count();
+ if (frame.x < 0 || frame.y < 0 || frame.x >= frame_count.x || frame.y >= frame_count.y) {
+ return -1; // Out of bound.
}
- return h * y + x;
+
+ return frame_count.x * frame.y + frame.x;
}
void SpriteFramesEditor::_sheet_preview_draw() {
- Size2i texture_size = split_sheet_preview->get_texture()->get_size();
- int h = split_sheet_h->get_value();
- int v = split_sheet_v->get_value();
-
- real_t width = (texture_size.width / h) * sheet_zoom;
- real_t height = (texture_size.height / v) * sheet_zoom;
- const float a = 0.3;
-
- real_t y_end = v * height;
- for (int i = 0; i <= h; i++) {
- real_t x = i * width;
- split_sheet_preview->draw_line(Point2(x, 0), Point2(x, y_end), Color(1, 1, 1, a));
- split_sheet_preview->draw_line(Point2(x + 1, 0), Point2(x + 1, y_end), Color(0, 0, 0, a));
+ const Size2i frame_count = _get_frame_count();
+ const Size2i separation = _get_separation();
+
+ const Size2 draw_offset = Size2(_get_offset()) * sheet_zoom;
+ const Size2 draw_sep = Size2(separation) * sheet_zoom;
+ const Size2 draw_frame_size = Size2(_get_frame_size()) * sheet_zoom;
+ const Size2 draw_size = draw_frame_size * frame_count + draw_sep * (frame_count - Size2i(1, 1));
+
+ const Color line_color = Color(1, 1, 1, 0.3);
+ const Color shadow_color = Color(0, 0, 0, 0.3);
+
+ // Vertical lines.
+ _draw_shadowed_line(split_sheet_preview, draw_offset, Vector2(0, draw_size.y), Vector2(1, 0), line_color, shadow_color);
+ for (int i = 0; i < frame_count.x - 1; i++) {
+ const Point2 start = draw_offset + Vector2(i * draw_sep.x + (i + 1) * draw_frame_size.x, 0);
+ if (separation.x == 0) {
+ _draw_shadowed_line(split_sheet_preview, start, Vector2(0, draw_size.y), Vector2(1, 0), line_color, shadow_color);
+ } else {
+ const Size2 size = Size2(draw_sep.x, draw_size.y);
+ split_sheet_preview->draw_rect(Rect2(start, size), line_color);
+ }
}
- real_t x_end = h * width;
- for (int i = 0; i <= v; i++) {
- real_t y = i * height;
- split_sheet_preview->draw_line(Point2(0, y), Point2(x_end, y), Color(1, 1, 1, a));
- split_sheet_preview->draw_line(Point2(0, y + 1), Point2(x_end, y + 1), Color(0, 0, 0, a));
+ _draw_shadowed_line(split_sheet_preview, draw_offset + Vector2(draw_size.x, 0), Vector2(0, draw_size.y), Vector2(1, 0), line_color, shadow_color);
+
+ // Horizontal lines.
+ _draw_shadowed_line(split_sheet_preview, draw_offset, Vector2(draw_size.x, 0), Vector2(0, 1), line_color, shadow_color);
+ for (int i = 0; i < frame_count.y - 1; i++) {
+ const Point2 start = draw_offset + Vector2(0, i * draw_sep.y + (i + 1) * draw_frame_size.y);
+ if (separation.y == 0) {
+ _draw_shadowed_line(split_sheet_preview, start, Vector2(draw_size.x, 0), Vector2(0, 1), line_color, shadow_color);
+ } else {
+ const Size2 size = Size2(draw_size.x, draw_sep.y);
+ split_sheet_preview->draw_rect(Rect2(start, size), line_color);
+ }
}
+ _draw_shadowed_line(split_sheet_preview, draw_offset + Vector2(0, draw_size.y), Vector2(draw_size.x, 0), Vector2(0, 1), line_color, shadow_color);
if (frames_selected.size() == 0) {
split_sheet_dialog->get_ok_button()->set_disabled(true);
@@ -105,22 +126,20 @@ void SpriteFramesEditor::_sheet_preview_draw() {
return;
}
- Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ Color accent = get_theme_color("accent_color", "Editor");
for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) {
- int idx = E->get();
- int xp = idx % h;
- int yp = idx / h;
- real_t x = xp * width;
- real_t y = yp * height;
-
- split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 0.35), true);
- split_sheet_preview->draw_rect(Rect2(x + 0, y + 0, width - 0, height - 0), Color(0, 0, 0, 1), false);
- split_sheet_preview->draw_rect(Rect2(x + 1, y + 1, width - 2, height - 2), Color(0, 0, 0, 1), false);
- split_sheet_preview->draw_rect(Rect2(x + 2, y + 2, width - 4, height - 4), accent, false);
- split_sheet_preview->draw_rect(Rect2(x + 3, y + 3, width - 6, height - 6), accent, false);
- split_sheet_preview->draw_rect(Rect2(x + 4, y + 4, width - 8, height - 8), Color(0, 0, 0, 1), false);
- split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 1), false);
+ const int idx = E->get();
+ const int x = idx % frame_count.x;
+ const int y = idx / frame_count.x;
+ const Point2 pos = draw_offset + Point2(x, y) * (draw_frame_size + draw_sep);
+ split_sheet_preview->draw_rect(Rect2(pos + Size2(5, 5), draw_frame_size - Size2(10, 10)), Color(0, 0, 0, 0.35), true);
+ split_sheet_preview->draw_rect(Rect2(pos, draw_frame_size), Color(0, 0, 0, 1), false);
+ split_sheet_preview->draw_rect(Rect2(pos + Size2(1, 1), draw_frame_size - Size2(2, 2)), Color(0, 0, 0, 1), false);
+ split_sheet_preview->draw_rect(Rect2(pos + Size2(2, 2), draw_frame_size - Size2(4, 4)), accent, false);
+ split_sheet_preview->draw_rect(Rect2(pos + Size2(3, 3), draw_frame_size - Size2(6, 6)), accent, false);
+ split_sheet_preview->draw_rect(Rect2(pos + Size2(4, 4), draw_frame_size - Size2(8, 8)), Color(0, 0, 0, 1), false);
+ split_sheet_preview->draw_rect(Rect2(pos + Size2(5, 5), draw_frame_size - Size2(10, 10)), Color(0, 0, 0, 1), false);
}
split_sheet_dialog->get_ok_button()->set_disabled(false);
@@ -223,10 +242,10 @@ void SpriteFramesEditor::_sheet_scroll_input(const Ref<InputEvent> &p_event) {
}
void SpriteFramesEditor::_sheet_add_frames() {
- Size2i texture_size = split_sheet_preview->get_texture()->get_size();
- int frame_count_x = split_sheet_h->get_value();
- int frame_count_y = split_sheet_v->get_value();
- Size2 frame_size(texture_size.width / frame_count_x, texture_size.height / frame_count_y);
+ const Size2i frame_count = _get_frame_count();
+ const Size2i frame_size = _get_frame_size();
+ const Size2i offset = _get_offset();
+ const Size2i separation = _get_separation();
undo_redo->create_action(TTR("Add Frame"));
@@ -234,12 +253,12 @@ void SpriteFramesEditor::_sheet_add_frames() {
for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) {
int idx = E->get();
- Point2 frame_coords(idx % frame_count_x, idx / frame_count_x);
+ const Point2 frame_coords(idx % frame_count.x, idx / frame_count.x);
Ref<AtlasTexture> at;
at.instantiate();
at->set_atlas(split_sheet_preview->get_texture());
- at->set_region(Rect2(frame_coords * frame_size, frame_size));
+ at->set_region(Rect2(offset + frame_coords * (frame_size + separation), frame_size));
undo_redo->add_do_method(frames, "add_frame", edited_anim, at, -1);
undo_redo->add_undo_method(frames, "remove_frame", edited_anim, fc);
@@ -293,7 +312,57 @@ void SpriteFramesEditor::_sheet_select_clear_all_frames() {
split_sheet_preview->update();
}
-void SpriteFramesEditor::_sheet_spin_changed(double) {
+void SpriteFramesEditor::_sheet_spin_changed(double p_value, int p_dominant_param) {
+ if (updating_split_settings) {
+ return;
+ }
+ updating_split_settings = true;
+
+ if (p_dominant_param != PARAM_USE_CURRENT) {
+ dominant_param = p_dominant_param;
+ }
+
+ const Size2i texture_size = split_sheet_preview->get_texture()->get_size();
+ const Size2i size = texture_size - _get_offset();
+
+ switch (dominant_param) {
+ case PARAM_SIZE: {
+ const Size2i frame_size = _get_frame_size();
+
+ const Size2i offset_max = texture_size - frame_size;
+ split_sheet_offset_x->set_max(offset_max.x);
+ split_sheet_offset_y->set_max(offset_max.y);
+
+ const Size2i sep_max = size - frame_size * 2;
+ split_sheet_sep_x->set_max(sep_max.x);
+ split_sheet_sep_y->set_max(sep_max.y);
+
+ const Size2i separation = _get_separation();
+ const Size2i count = (size + separation) / (frame_size + separation);
+ split_sheet_h->set_value(count.x);
+ split_sheet_v->set_value(count.y);
+ } break;
+
+ case PARAM_FRAME_COUNT: {
+ const Size2i count = _get_frame_count();
+
+ const Size2i offset_max = texture_size - count;
+ split_sheet_offset_x->set_max(offset_max.x);
+ split_sheet_offset_y->set_max(offset_max.y);
+
+ const Size2i gap_count = count - Size2i(1, 1);
+ split_sheet_sep_x->set_max(gap_count.x == 0 ? size.x : (size.x - count.x) / gap_count.x);
+ split_sheet_sep_y->set_max(gap_count.y == 0 ? size.y : (size.y - count.y) / gap_count.y);
+
+ const Size2i separation = _get_separation();
+ const Size2i frame_size = (size - separation * gap_count) / count;
+ split_sheet_size_x->set_value(frame_size.x);
+ split_sheet_size_y->set_value(frame_size.y);
+ } break;
+ }
+
+ updating_split_settings = false;
+
frames_selected.clear();
last_frame_selected = -1;
split_sheet_preview->update();
@@ -311,10 +380,29 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
bool new_texture = texture != split_sheet_preview->get_texture();
split_sheet_preview->set_texture(texture);
if (new_texture) {
- //different texture, reset to 4x4
+ // Reset spin max.
+ const Size2i size = texture->get_size();
+ split_sheet_size_x->set_max(size.x);
+ split_sheet_size_y->set_max(size.y);
+ split_sheet_sep_x->set_max(size.x);
+ split_sheet_sep_y->set_max(size.y);
+ split_sheet_offset_x->set_max(size.x);
+ split_sheet_offset_y->set_max(size.y);
+
+ // Different texture, reset to 4x4.
+ dominant_param = PARAM_FRAME_COUNT;
+ updating_split_settings = true;
split_sheet_h->set_value(4);
split_sheet_v->set_value(4);
- //reset zoom
+ split_sheet_size_x->set_value(size.x / 4);
+ split_sheet_size_y->set_value(size.y / 4);
+ split_sheet_sep_x->set_value(0);
+ split_sheet_sep_y->set_value(0);
+ split_sheet_offset_x->set_value(0);
+ split_sheet_offset_y->set_value(0);
+ updating_split_settings = false;
+
+ // Reset zoom.
_sheet_zoom_reset();
}
split_sheet_dialog->popup_centered_ratio(0.65);
@@ -392,6 +480,22 @@ void SpriteFramesEditor::_file_load_request(const Vector<String> &p_path, int p_
undo_redo->commit_action();
}
+Size2i SpriteFramesEditor::_get_frame_count() const {
+ return Size2i(split_sheet_h->get_value(), split_sheet_v->get_value());
+}
+
+Size2i SpriteFramesEditor::_get_frame_size() const {
+ return Size2i(split_sheet_size_x->get_value(), split_sheet_size_y->get_value());
+}
+
+Size2i SpriteFramesEditor::_get_offset() const {
+ return Size2i(split_sheet_offset_x->get_value(), split_sheet_offset_y->get_value());
+}
+
+Size2i SpriteFramesEditor::_get_separation() const {
+ return Size2i(split_sheet_sep_x->get_value(), split_sheet_sep_y->get_value());
+}
+
void SpriteFramesEditor::_load_pressed() {
ERR_FAIL_COND(!frames->has_animation(edited_anim));
loading_scene = false;
@@ -1210,23 +1314,66 @@ SpriteFramesEditor::SpriteFramesEditor() {
HBoxContainer *split_sheet_hb = memnew(HBoxContainer);
- Label *ss_label = memnew(Label(TTR("Horizontal:")));
- split_sheet_hb->add_child(ss_label);
+ split_sheet_hb->add_child(memnew(Label(TTR("Horizontal:"))));
split_sheet_h = memnew(SpinBox);
split_sheet_h->set_min(1);
split_sheet_h->set_max(128);
split_sheet_h->set_step(1);
split_sheet_hb->add_child(split_sheet_h);
- split_sheet_h->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed));
+ split_sheet_h->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_FRAME_COUNT));
- ss_label = memnew(Label(TTR("Vertical:")));
- split_sheet_hb->add_child(ss_label);
+ split_sheet_hb->add_child(memnew(Label(TTR("Vertical:"))));
split_sheet_v = memnew(SpinBox);
split_sheet_v->set_min(1);
split_sheet_v->set_max(128);
split_sheet_v->set_step(1);
split_sheet_hb->add_child(split_sheet_v);
- split_sheet_v->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed));
+ split_sheet_v->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_FRAME_COUNT));
+
+ split_sheet_hb->add_child(memnew(VSeparator));
+ split_sheet_hb->add_child(memnew(Label(TTR("Size:"))));
+ split_sheet_size_x = memnew(SpinBox);
+ split_sheet_size_x->set_min(1);
+ split_sheet_size_x->set_step(1);
+ split_sheet_size_x->set_suffix("px");
+ split_sheet_size_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_SIZE));
+ split_sheet_hb->add_child(split_sheet_size_x);
+ split_sheet_size_y = memnew(SpinBox);
+ split_sheet_size_y->set_min(1);
+ split_sheet_size_y->set_step(1);
+ split_sheet_size_y->set_suffix("px");
+ split_sheet_size_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_SIZE));
+ split_sheet_hb->add_child(split_sheet_size_y);
+
+ split_sheet_hb->add_child(memnew(VSeparator));
+ split_sheet_hb->add_child(memnew(Label(TTR("Separation:"))));
+ split_sheet_sep_x = memnew(SpinBox);
+ split_sheet_sep_x->set_min(0);
+ split_sheet_sep_x->set_step(1);
+ split_sheet_sep_x->set_suffix("px");
+ split_sheet_sep_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_USE_CURRENT));
+ split_sheet_hb->add_child(split_sheet_sep_x);
+ split_sheet_sep_y = memnew(SpinBox);
+ split_sheet_sep_y->set_min(0);
+ split_sheet_sep_y->set_step(1);
+ split_sheet_sep_y->set_suffix("px");
+ split_sheet_sep_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_USE_CURRENT));
+ split_sheet_hb->add_child(split_sheet_sep_y);
+
+ split_sheet_hb->add_child(memnew(VSeparator));
+ split_sheet_hb->add_child(memnew(Label(TTR("Offset:"))));
+ split_sheet_offset_x = memnew(SpinBox);
+ split_sheet_offset_x->set_min(0);
+ split_sheet_offset_x->set_step(1);
+ split_sheet_offset_x->set_suffix("px");
+ split_sheet_offset_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_USE_CURRENT));
+ split_sheet_hb->add_child(split_sheet_offset_x);
+ split_sheet_offset_y = memnew(SpinBox);
+ split_sheet_offset_y->set_min(0);
+ split_sheet_offset_y->set_step(1);
+ split_sheet_offset_y->set_suffix("px");
+ split_sheet_offset_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_USE_CURRENT));
+ split_sheet_hb->add_child(split_sheet_offset_y);
split_sheet_hb->add_spacer();
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index b0213012a2..9a00fe5771 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -48,6 +48,13 @@ class EditorFileDialog;
class SpriteFramesEditor : public HSplitContainer {
GDCLASS(SpriteFramesEditor, HSplitContainer);
+ enum {
+ PARAM_USE_CURRENT, // Used in callbacks to indicate `dominant_param` should be not updated.
+ PARAM_FRAME_COUNT, // Keep "Horizontal" & "Vertial" values.
+ PARAM_SIZE, // Keep "Size" values.
+ };
+ int dominant_param = PARAM_FRAME_COUNT;
+
Button *load = nullptr;
Button *load_sheet = nullptr;
Button *_delete = nullptr;
@@ -86,6 +93,12 @@ class SpriteFramesEditor : public HSplitContainer {
TextureRect *split_sheet_preview = nullptr;
SpinBox *split_sheet_h = nullptr;
SpinBox *split_sheet_v = nullptr;
+ SpinBox *split_sheet_size_x = nullptr;
+ SpinBox *split_sheet_size_y = nullptr;
+ SpinBox *split_sheet_sep_x = nullptr;
+ SpinBox *split_sheet_sep_y = nullptr;
+ SpinBox *split_sheet_offset_x = nullptr;
+ SpinBox *split_sheet_offset_y = nullptr;
Button *split_sheet_zoom_out = nullptr;
Button *split_sheet_zoom_reset = nullptr;
Button *split_sheet_zoom_in = nullptr;
@@ -103,6 +116,11 @@ class SpriteFramesEditor : public HSplitContainer {
float max_sheet_zoom;
float min_sheet_zoom;
+ Size2i _get_frame_count() const;
+ Size2i _get_frame_size() const;
+ Size2i _get_offset() const;
+ Size2i _get_separation() const;
+
void _load_pressed();
void _file_load_request(const Vector<String> &p_path, int p_at_pos = -1);
void _copy_pressed();
@@ -128,6 +146,7 @@ class SpriteFramesEditor : public HSplitContainer {
void _zoom_reset();
bool updating;
+ bool updating_split_settings = false; // Skip SpinBox/Range callback when setting value by code.
UndoRedo *undo_redo = nullptr;
@@ -139,7 +158,7 @@ class SpriteFramesEditor : public HSplitContainer {
void _prepare_sprite_sheet(const String &p_file);
int _sheet_preview_position_to_frame_index(const Vector2 &p_position);
void _sheet_preview_draw();
- void _sheet_spin_changed(double);
+ void _sheet_spin_changed(double p_value, int p_dominant_param);
void _sheet_preview_input(const Ref<InputEvent> &p_event);
void _sheet_scroll_input(const Ref<InputEvent> &p_event);
void _sheet_add_frames();
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index a7c06ada5c..15f03fd46d 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -70,7 +70,7 @@ void TexturePreview::_update_metadata_label_text() {
format = texture->get_class();
}
- metadata_label->set_text(itos(texture->get_width()) + "x" + itos(texture->get_height()) + " " + format);
+ metadata_label->set_text(vformat(String::utf8("%s×%s %s"), itos(texture->get_width()), itos(texture->get_height()), format));
}
TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) {
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 269e6f0580..59254fc3ad 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -2353,14 +2353,16 @@ Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resou
String source = sqscr->get_source_code();
- Error err;
- Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ {
+ Error err;
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'.");
- file->store_string(source);
- if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
- return ERR_CANT_CREATE;
+ file->store_string(source);
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ return ERR_CANT_CREATE;
+ }
}
if (ScriptServer::is_reload_scripts_on_save_enabled()) {
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 2a8f7c17c7..02aebb3805 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -3641,14 +3641,16 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r
}
#endif
- Error err;
- Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save C# script file '" + p_path + "'.");
+ {
+ Error err;
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save C# script file '" + p_path + "'.");
- file->store_string(source);
+ file->store_string(source);
- if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
- return ERR_CANT_CREATE;
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ return ERR_CANT_CREATE;
+ }
}
#ifdef TOOLS_ENABLED
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index 1fbacca5bf..6ea3c5539e 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -77,22 +77,20 @@ static String make_text(const char *log_domain, const char *log_level, const cha
}
void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *) {
- Ref<FileAccess> f = GDMonoLog::get_singleton()->log_file;
-
if (GDMonoLog::get_singleton()->log_level_id >= get_log_level_id(log_level)) {
String text = make_text(log_domain, log_level, message);
text += "\n";
- f->seek_end();
- f->store_string(text);
+ GDMonoLog::get_singleton()->log_file->seek_end();
+ GDMonoLog::get_singleton()->log_file->store_string(text);
}
if (fatal) {
String text = make_text(log_domain, log_level, message);
ERR_PRINT("Mono: FATAL ERROR '" + text + "', ABORTING! Logfile: '" + GDMonoLog::get_singleton()->log_file_path + "'.");
// Make sure to flush before aborting
- f->flush();
- f->close();
+ GDMonoLog::get_singleton()->log_file->flush();
+ GDMonoLog::get_singleton()->log_file.unref();
abort();
}
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index 441fc8edbd..3f5140cc8c 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -152,7 +152,7 @@ void VideoStreamPlaybackTheora::clear() {
theora_eos = false;
vorbis_eos = false;
- file = Ref<FileAccess>();
+ file.unref();
playing = false;
};
diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp
index a2e59c9cdf..495303d6c4 100644
--- a/modules/visual_script/editor/visual_script_editor.cpp
+++ b/modules/visual_script/editor/visual_script_editor.cpp
@@ -2727,7 +2727,7 @@ void VisualScriptEditor::_center_on_node(int p_id) {
if (gn) {
gn->set_selected(true);
- Vector2 new_scroll = gn->get_position_offset() - graph->get_size() * 0.5 + gn->get_size() * 0.5;
+ Vector2 new_scroll = gn->get_position_offset() * graph->get_zoom() - graph->get_size() * 0.5 + gn->get_size() * 0.5;
graph->set_scroll_ofs(new_scroll);
script->set_scroll(new_scroll / EDSCALE);
script->set_edited(true);
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
index ee6eeaa849..d7ba31e3c9 100644
--- a/platform/android/file_access_android.cpp
+++ b/platform/android/file_access_android.cpp
@@ -39,6 +39,8 @@ Ref<FileAccess> FileAccessAndroid::create_android() {
}
Error FileAccessAndroid::_open(const String &p_path, int p_mode_flags) {
+ _close();
+
String path = fix_path(p_path).simplify_path();
if (path.begins_with("/")) {
path = path.substr(1, path.length());
@@ -58,7 +60,7 @@ Error FileAccessAndroid::_open(const String &p_path, int p_mode_flags) {
return OK;
}
-void FileAccessAndroid::close() {
+void FileAccessAndroid::_close() {
if (!a) {
return;
}
@@ -162,5 +164,5 @@ bool FileAccessAndroid::file_exists(const String &p_path) {
}
FileAccessAndroid::~FileAccessAndroid() {
- close();
+ _close();
}
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
index ea7531e9ad..33b692da20 100644
--- a/platform/android/file_access_android.h
+++ b/platform/android/file_access_android.h
@@ -44,11 +44,12 @@ class FileAccessAndroid : public FileAccess {
mutable uint64_t pos = 0;
mutable bool eof = false;
+ void _close();
+
public:
static AAssetManager *asset_manager;
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
virtual void seek(uint64_t p_position); ///< seek to a given position
diff --git a/platform/iphone/export/export_plugin.cpp b/platform/iphone/export/export_plugin.cpp
index a540a7658c..57bee59523 100644
--- a/platform/iphone/export/export_plugin.cpp
+++ b/platform/iphone/export/export_plugin.cpp
@@ -1570,13 +1570,15 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
}
/* write the file */
- Ref<FileAccess> f = FileAccess::open(file, FileAccess::WRITE);
- if (f.is_null()) {
- ERR_PRINT("Can't write '" + file + "'.");
- unzClose(src_pkg_zip);
- return ERR_CANT_CREATE;
- };
- f->store_buffer(data.ptr(), data.size());
+ {
+ Ref<FileAccess> f = FileAccess::open(file, FileAccess::WRITE);
+ if (f.is_null()) {
+ ERR_PRINT("Can't write '" + file + "'.");
+ unzClose(src_pkg_zip);
+ return ERR_CANT_CREATE;
+ };
+ f->store_buffer(data.ptr(), data.size());
+ }
#if defined(OSX_ENABLED) || defined(X11_ENABLED)
if (is_execute) {
@@ -1714,12 +1716,14 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
_export_additional_assets(dest_dir + binary_name, libraries, assets);
_add_assets_to_project(p_preset, project_file_data, assets);
String project_file_name = dest_dir + binary_name + ".xcodeproj/project.pbxproj";
- Ref<FileAccess> f = FileAccess::open(project_file_name, FileAccess::WRITE);
- if (f.is_null()) {
- ERR_PRINT("Can't write '" + project_file_name + "'.");
- return ERR_CANT_CREATE;
- };
- f->store_buffer(project_file_data.ptr(), project_file_data.size());
+ {
+ Ref<FileAccess> f = FileAccess::open(project_file_name, FileAccess::WRITE);
+ if (f.is_null()) {
+ ERR_PRINT("Can't write '" + project_file_name + "'.");
+ return ERR_CANT_CREATE;
+ };
+ f->store_buffer(project_file_data.ptr(), project_file_data.size());
+ }
#ifdef OSX_ENABLED
{
diff --git a/platform/javascript/api/javascript_tools_editor_plugin.cpp b/platform/javascript/api/javascript_tools_editor_plugin.cpp
index 46eec8eda2..31ce71127d 100644
--- a/platform/javascript/api/javascript_tools_editor_plugin.cpp
+++ b/platform/javascript/api/javascript_tools_editor_plugin.cpp
@@ -81,12 +81,14 @@ void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) {
const String base_path = resource_path.substr(0, resource_path.rfind("/")) + "/";
_zip_recursive(resource_path, base_path, zip);
zipClose(zip, nullptr);
- Ref<FileAccess> f = FileAccess::open(output_path, FileAccess::READ);
- ERR_FAIL_COND_MSG(f.is_null(), "Unable to create ZIP file.");
- Vector<uint8_t> buf;
- buf.resize(f->get_length());
- f->get_buffer(buf.ptrw(), buf.size());
- godot_js_os_download_buffer(buf.ptr(), buf.size(), output_name.utf8().get_data(), "application/zip");
+ {
+ Ref<FileAccess> f = FileAccess::open(output_path, FileAccess::READ);
+ ERR_FAIL_COND_MSG(f.is_null(), "Unable to create ZIP file.");
+ Vector<uint8_t> buf;
+ buf.resize(f->get_length());
+ f->get_buffer(buf.ptrw(), buf.size());
+ godot_js_os_download_buffer(buf.ptr(), buf.size(), output_name.utf8().get_data(), "application/zip");
+ }
// Remove the temporary file since it was sent to the user's native filesystem as a download.
DirAccess::remove_file_or_error(output_path);
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index 62e9aaed45..bf142f8804 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -511,9 +511,11 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
String trash_info = "[Trash Info]\nPath=" + path.uri_encode() + "\nDeletionDate=" + timestamp + "\n";
{
Error err;
- Ref<FileAccess> file = FileAccess::open(trash_path + "/info/" + file_name + ".trashinfo", FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err != OK, err, "Can't create trashinfo file: \"" + trash_path + "/info/" + file_name + ".trashinfo\"");
- file->store_string(trash_info);
+ {
+ Ref<FileAccess> file = FileAccess::open(trash_path + "/info/" + file_name + ".trashinfo", FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Can't create trashinfo file: \"" + trash_path + "/info/" + file_name + ".trashinfo\"");
+ file->store_string(trash_info);
+ }
// Rename our resource before moving it to the trash can.
Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp
index 580cd81583..94ef875072 100644
--- a/platform/osx/export/export_plugin.cpp
+++ b/platform/osx/export/export_plugin.cpp
@@ -256,21 +256,23 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_
String path = EditorPaths::get_singleton()->get_cache_dir().plus_file("icon.png");
ResourceSaver::save(path, it);
- Ref<FileAccess> f = FileAccess::open(path, FileAccess::READ);
- if (f.is_null()) {
- // Clean up generated file.
- DirAccess::remove_file_or_error(path);
- ERR_FAIL();
- }
+ {
+ Ref<FileAccess> f = FileAccess::open(path, FileAccess::READ);
+ if (f.is_null()) {
+ // Clean up generated file.
+ DirAccess::remove_file_or_error(path);
+ ERR_FAIL();
+ }
- int ofs = data.size();
- uint64_t len = f->get_length();
- data.resize(data.size() + len + 8);
- f->get_buffer(&data.write[ofs + 8], len);
- len += 8;
- len = BSWAP32(len);
- memcpy(&data.write[ofs], icon_infos[i].name, 4);
- encode_uint32(len, &data.write[ofs + 4]);
+ int ofs = data.size();
+ uint64_t len = f->get_length();
+ data.resize(data.size() + len + 8);
+ f->get_buffer(&data.write[ofs + 8], len);
+ len += 8;
+ len = BSWAP32(len);
+ memcpy(&data.write[ofs], icon_infos[i].name, 4);
+ encode_uint32(len, &data.write[ofs + 4]);
+ }
// Clean up generated file.
DirAccess::remove_file_or_error(path);
diff --git a/platform/uwp/export/app_packager.cpp b/platform/uwp/export/app_packager.cpp
index 8d09a16653..2f70c3e74c 100644
--- a/platform/uwp/export/app_packager.cpp
+++ b/platform/uwp/export/app_packager.cpp
@@ -457,7 +457,7 @@ void AppxPackager::finish() {
Vector<uint8_t> end_record = make_end_of_central_record();
package->store_buffer(end_record.ptr(), end_record.size());
- package = Ref<FileAccess>();
+ package.unref();
}
AppxPackager::AppxPackager() {}
diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h
index 7f10b00dc1..ceb6d613b3 100644
--- a/platform/uwp/export/export_plugin.h
+++ b/platform/uwp/export/export_plugin.h
@@ -346,19 +346,21 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
ERR_FAIL_V_MSG(data, err_string);
}
- Ref<FileAccess> f = FileAccess::open(tmp_path, FileAccess::READ, &err);
+ {
+ Ref<FileAccess> f = FileAccess::open(tmp_path, FileAccess::READ, &err);
+
+ if (err != OK) {
+ String err_string = "Couldn't open temp logo file.";
+ // Cleanup generated file.
+ DirAccess::remove_file_or_error(tmp_path);
+ EditorNode::add_io_error(err_string);
+ ERR_FAIL_V_MSG(data, err_string);
+ }
- if (err != OK) {
- String err_string = "Couldn't open temp logo file.";
- // Cleanup generated file.
- DirAccess::remove_file_or_error(tmp_path);
- EditorNode::add_io_error(err_string);
- ERR_FAIL_V_MSG(data, err_string);
+ data.resize(f->get_length());
+ f->get_buffer(data.ptrw(), data.size());
}
- data.resize(f->get_length());
- f->get_buffer(data.ptrw(), data.size());
-
DirAccess::remove_file_or_error(tmp_path);
return data;
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 24cd485e1b..3c8ea4d6df 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -2089,7 +2089,6 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
if (!p_item->collapsed) { /* if not collapsed, check the children */
-
TreeItem *c = p_item->first_child;
int base_ofs = children_pos.y - cache.offset.y + p_draw_ofs.y;
@@ -2097,82 +2096,97 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
int prev_hl_ofs = base_ofs;
while (c) {
+ int child_h = -1;
if (htotal >= 0) {
- int child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c);
+ child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c);
+ }
- // Draw relationship lines.
- if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root)) {
- int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
- int parent_ofs = p_pos.x + cache.item_margin;
- Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs;
+ // Draw relationship lines.
+ if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root)) {
+ int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
+ int parent_ofs = p_pos.x + cache.item_margin;
+ Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs;
- if (c->get_first_child() != nullptr) {
- root_pos -= Point2i(cache.arrow->get_width(), 0);
- }
+ if (c->get_first_child() != nullptr) {
+ root_pos -= Point2i(cache.arrow->get_width(), 0);
+ }
- float line_width = cache.relationship_line_width * Math::round(cache.base_scale);
- float parent_line_width = cache.parent_hl_line_width * Math::round(cache.base_scale);
- float children_line_width = cache.children_hl_line_width * Math::round(cache.base_scale);
+ float line_width = cache.relationship_line_width * Math::round(cache.base_scale);
+ float parent_line_width = cache.parent_hl_line_width * Math::round(cache.base_scale);
+ float children_line_width = cache.children_hl_line_width * Math::round(cache.base_scale);
- Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs;
+ Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs;
- int more_prev_ofs = 0;
+ int more_prev_ofs = 0;
- if (root_pos.y + line_width >= 0) {
- if (rtl) {
- root_pos.x = get_size().width - root_pos.x;
- parent_pos.x = get_size().width - parent_pos.x;
- }
+ if (root_pos.y + line_width >= 0) {
+ if (rtl) {
+ root_pos.x = get_size().width - root_pos.x;
+ parent_pos.x = get_size().width - parent_pos.x;
+ }
- // Order of parts on this bend: the horizontal line first, then the vertical line.
- if (_is_branch_selected(c)) {
- // If this item or one of its children is selected, we draw the line using parent highlight style.
+ // Order of parts on this bend: the horizontal line first, then the vertical line.
+ if (_is_branch_selected(c)) {
+ // If this item or one of its children is selected, we draw the line using parent highlight style.
+ if (htotal >= 0) {
RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.parent_hl_line_color, parent_line_width);
+ }
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width);
+
+ more_prev_ofs = cache.parent_hl_line_margin;
+ prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2);
+ } else if (p_item->is_selected(0)) {
+ // If parent item is selected (but this item is not), we draw the line using children highlight style.
+ // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted.
+ if (_is_sibling_branch_selected(c)) {
+ if (htotal >= 0) {
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width);
+ }
RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width);
- more_prev_ofs = cache.parent_hl_line_margin;
prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2);
- } else if (p_item->is_selected(0)) {
- // If parent item is selected (but this item is not), we draw the line using children highlight style.
- // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted.
- if (_is_sibling_branch_selected(c)) {
- RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width);
- RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width);
-
- prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2);
- } else {
+ } else {
+ if (htotal >= 0) {
RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(children_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width);
- RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(children_line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(children_line_width / 2)), cache.children_hl_line_color, children_line_width);
}
- } else {
- // If nothing of the above is true, we draw the line using normal style.
- // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted.
- if (_is_sibling_branch_selected(c)) {
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(children_line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(children_line_width / 2)), cache.children_hl_line_color, children_line_width);
+ }
+ } else {
+ // If nothing of the above is true, we draw the line using normal style.
+ // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted.
+ if (_is_sibling_branch_selected(c)) {
+ if (htotal >= 0) {
RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + cache.parent_hl_line_margin, root_pos.y), cache.relationship_line_color, line_width);
- RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width);
+ }
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width);
- prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2);
- } else {
+ prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2);
+ } else {
+ if (htotal >= 0) {
RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width);
- RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(line_width / 2)), cache.relationship_line_color, line_width);
}
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(line_width / 2)), cache.relationship_line_color, line_width);
}
}
-
- prev_ofs = root_pos.y + more_prev_ofs;
}
- if (child_h < 0) {
- if (cache.draw_relationship_lines == 0) {
- return -1; // break, stop drawing, no need to anymore
- }
+ prev_ofs = root_pos.y + more_prev_ofs;
+ }
- htotal = -1;
- children_pos.y = cache.offset.y + p_draw_size.height;
- } else {
- htotal += child_h;
- children_pos.y += child_h;
+ if (child_h < 0) {
+ if (htotal == -1) {
+ break; // Last loop done, stop.
}
+
+ if (cache.draw_relationship_lines == 0) {
+ return -1; // No need to draw anymore, full stop.
+ }
+
+ htotal = -1;
+ children_pos.y = cache.offset.y + p_draw_size.height;
+ } else {
+ htotal += child_h;
+ children_pos.y += child_h;
}
c = c->next;
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index f5fe87c808..708359f106 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -463,10 +463,10 @@ void CanvasItem::draw_dashed_line(const Point2 &p_from, const Point2 &p_to, cons
RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, off, p_to, p_color, p_width);
}
-void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width) {
+void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width, bool p_antialiased) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
- RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width, p_antialiased);
}
void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width, bool p_antialiased) {
@@ -883,7 +883,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_draw_behind_parent", "enable"), &CanvasItem::set_draw_behind_parent);
ClassDB::bind_method(D_METHOD("is_draw_behind_parent_enabled"), &CanvasItem::is_draw_behind_parent_enabled);
- ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width"), &CanvasItem::draw_line, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_dashed_line", "from", "to", "color", "width", "dash"), &CanvasItem::draw_dashed_line, DEFVAL(1.0), DEFVAL(2.0));
ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0), DEFVAL(false));
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index 95fae0fda7..ad64f1ab5e 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -215,7 +215,7 @@ public:
/* DRAWING API */
void draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0, real_t p_dash = 2.0);
- void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0);
+ void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false);
void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false);
void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0, bool p_antialiased = false);
void draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false);
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 43cdbc7f1d..34b0e19d31 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -197,7 +197,7 @@ void HTTPRequest::cancel_request() {
thread.wait_to_finish();
}
- file = Ref<FileAccess>();
+ file.unref();
client->close();
body.clear();
got_response = false;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index e20287c875..d93e7b4b0b 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -3744,7 +3744,7 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
#ifndef _3D_DISABLED
ADD_GROUP("Scaling 3D", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "scaling_3d_mode", PROPERTY_HINT_ENUM, "Disabled (Slowest),Bilinear (Fastest),FSR (Fast)"), "set_scaling_3d_mode", "get_scaling_3d_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "scaling_3d_mode", PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast)"), "set_scaling_3d_mode", "get_scaling_3d_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scaling_3d_scale", PROPERTY_HINT_RANGE, "0.25,2.0,0.01"), "set_scaling_3d_scale", "get_scaling_3d_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fsr_mipmap_bias", PROPERTY_HINT_RANGE, "-2,2,0.1"), "set_fsr_mipmap_bias", "get_fsr_mipmap_bias");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fsr_sharpness", PROPERTY_HINT_RANGE, "0,2,0.1"), "set_fsr_sharpness", "get_fsr_sharpness");
diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp
index 667399ee75..c416a03f38 100644
--- a/scene/resources/convex_polygon_shape_2d.cpp
+++ b/scene/resources/convex_polygon_shape_2d.cpp
@@ -82,7 +82,7 @@ void ConvexPolygonShape2D::draw(const RID &p_to_rid, const Color &p_color) {
if (is_collision_outline_enabled()) {
RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col);
// Draw the last segment as it's not drawn by `canvas_item_add_polyline()`.
- RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color);
+ RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color, 1.0, true);
}
}
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index ce7007f257..4b0456681b 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -890,7 +890,7 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String
fw->store_8(c);
c = f->get_8();
}
- f = Ref<FileAccess>();
+ f.unref();
bool all_ok = fw->get_error() == OK;
@@ -1098,142 +1098,143 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
wf->store_32(0); //zero sub resources, still parsing them
String temp_file = p_path + ".temp";
- Ref<FileAccess> wf2 = FileAccess::open(temp_file, FileAccess::WRITE);
- if (wf2.is_null()) {
- return ERR_CANT_OPEN;
- }
-
Vector<uint64_t> local_offsets;
Vector<uint64_t> local_pointers_pos;
+ {
+ Ref<FileAccess> wf2 = FileAccess::open(temp_file, FileAccess::WRITE);
+ if (wf2.is_null()) {
+ return ERR_CANT_OPEN;
+ }
- while (next_tag.name == "sub_resource" || next_tag.name == "resource") {
- String type;
- int id = -1;
- bool main_res;
+ while (next_tag.name == "sub_resource" || next_tag.name == "resource") {
+ String type;
+ int id = -1;
+ bool main_res;
- if (next_tag.name == "sub_resource") {
- if (!next_tag.fields.has("type")) {
- error = ERR_FILE_CORRUPT;
- error_text = "Missing 'type' in external resource tag";
- _printerr();
- return error;
- }
+ if (next_tag.name == "sub_resource") {
+ if (!next_tag.fields.has("type")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Missing 'type' in external resource tag";
+ _printerr();
+ return error;
+ }
- if (!next_tag.fields.has("id")) {
- error = ERR_FILE_CORRUPT;
- error_text = "Missing 'id' in external resource tag";
- _printerr();
- return error;
+ if (!next_tag.fields.has("id")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Missing 'id' in external resource tag";
+ _printerr();
+ return error;
+ }
+
+ type = next_tag.fields["type"];
+ id = next_tag.fields["id"];
+ main_res = false;
+ } else {
+ type = res_type;
+ id = 0; //used for last anyway
+ main_res = true;
}
- type = next_tag.fields["type"];
- id = next_tag.fields["id"];
- main_res = false;
- } else {
- type = res_type;
- id = 0; //used for last anyway
- main_res = true;
- }
+ local_offsets.push_back(wf2->get_position());
- local_offsets.push_back(wf2->get_position());
+ bs_save_unicode_string(wf, "local://" + itos(id));
+ local_pointers_pos.push_back(wf->get_position());
+ wf->store_64(0); //temp local offset
- bs_save_unicode_string(wf, "local://" + itos(id));
- local_pointers_pos.push_back(wf->get_position());
- wf->store_64(0); //temp local offset
+ bs_save_unicode_string(wf2, type);
+ uint64_t propcount_ofs = wf2->get_position();
+ wf2->store_32(0);
- bs_save_unicode_string(wf2, type);
- uint64_t propcount_ofs = wf2->get_position();
- wf2->store_32(0);
+ int prop_count = 0;
- int prop_count = 0;
+ while (true) {
+ String assign;
+ Variant value;
- while (true) {
- String assign;
- Variant value;
+ error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
- error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
+ if (error) {
+ if (main_res && error == ERR_FILE_EOF) {
+ next_tag.name = ""; //exit
+ break;
+ }
- if (error) {
- if (main_res && error == ERR_FILE_EOF) {
- next_tag.name = ""; //exit
- break;
+ _printerr();
+ return error;
}
- _printerr();
- return error;
+ if (!assign.is_empty()) {
+ Map<StringName, int> empty_string_map; //unused
+ bs_save_unicode_string(wf2, assign, true);
+ ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map);
+ prop_count++;
+
+ } else if (!next_tag.name.is_empty()) {
+ error = OK;
+ break;
+ } else {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Premature end of file while parsing [sub_resource]";
+ _printerr();
+ return error;
+ }
}
- if (!assign.is_empty()) {
- Map<StringName, int> empty_string_map; //unused
- bs_save_unicode_string(wf2, assign, true);
- ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map);
- prop_count++;
+ wf2->seek(propcount_ofs);
+ wf2->store_32(prop_count);
+ wf2->seek_end();
+ }
- } else if (!next_tag.name.is_empty()) {
- error = OK;
- break;
- } else {
- error = ERR_FILE_CORRUPT;
- error_text = "Premature end of file while parsing [sub_resource]";
+ if (next_tag.name == "node") {
+ //this is a node, must save one more!
+
+ if (!is_scene) {
+ error_text += "found the 'node' tag on a resource file!";
_printerr();
+ error = ERR_FILE_CORRUPT;
return error;
}
- }
- wf2->seek(propcount_ofs);
- wf2->store_32(prop_count);
- wf2->seek_end();
- }
-
- if (next_tag.name == "node") {
- //this is a node, must save one more!
+ Ref<PackedScene> packed_scene = _parse_node_tag(rp);
- if (!is_scene) {
- error_text += "found the 'node' tag on a resource file!";
- _printerr();
- error = ERR_FILE_CORRUPT;
- return error;
- }
+ if (!packed_scene.is_valid()) {
+ return error;
+ }
- Ref<PackedScene> packed_scene = _parse_node_tag(rp);
+ error = OK;
+ //get it here
+ List<PropertyInfo> props;
+ packed_scene->get_property_list(&props);
- if (!packed_scene.is_valid()) {
- return error;
- }
+ bs_save_unicode_string(wf, "local://0");
+ local_pointers_pos.push_back(wf->get_position());
+ wf->store_64(0); //temp local offset
- error = OK;
- //get it here
- List<PropertyInfo> props;
- packed_scene->get_property_list(&props);
+ local_offsets.push_back(wf2->get_position());
+ bs_save_unicode_string(wf2, "PackedScene");
+ uint64_t propcount_ofs = wf2->get_position();
+ wf2->store_32(0);
- bs_save_unicode_string(wf, "local://0");
- local_pointers_pos.push_back(wf->get_position());
- wf->store_64(0); //temp local offset
+ int prop_count = 0;
- local_offsets.push_back(wf2->get_position());
- bs_save_unicode_string(wf2, "PackedScene");
- uint64_t propcount_ofs = wf2->get_position();
- wf2->store_32(0);
+ for (const PropertyInfo &E : props) {
+ if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
+ continue;
+ }
- int prop_count = 0;
+ String name = E.name;
+ Variant value = packed_scene->get(name);
- for (const PropertyInfo &E : props) {
- if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
- continue;
+ Map<StringName, int> empty_string_map; //unused
+ bs_save_unicode_string(wf2, name, true);
+ ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map);
+ prop_count++;
}
- String name = E.name;
- Variant value = packed_scene->get(name);
-
- Map<StringName, int> empty_string_map; //unused
- bs_save_unicode_string(wf2, name, true);
- ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map);
- prop_count++;
+ wf2->seek(propcount_ofs);
+ wf2->store_32(prop_count);
+ wf2->seek_end();
}
-
- wf2->seek(propcount_ofs);
- wf2->store_32(prop_count);
- wf2->seek_end();
}
uint64_t offset_from = wf->get_position();
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 8ad2d42e5f..41034d4a02 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -552,27 +552,188 @@ void RendererCanvasCull::canvas_item_set_update_when_visible(RID p_item, bool p_
canvas_item->update_when_visible = p_update;
}
-void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) {
+void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width, bool p_antialiased) {
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandPrimitive *line = canvas_item->alloc_command<Item::CommandPrimitive>();
ERR_FAIL_COND(!line);
+
+ Vector2 diff = (p_from - p_to);
+ Vector2 dir = diff.orthogonal().normalized();
+ Vector2 t = dir * p_width * 0.5;
+
+ Vector2 begin_left;
+ Vector2 begin_right;
+ Vector2 end_left;
+ Vector2 end_right;
+
if (p_width > 1.001) {
- Vector2 t = (p_from - p_to).orthogonal().normalized() * p_width * 0.5;
- line->points[0] = p_from + t;
- line->points[1] = p_from - t;
- line->points[2] = p_to - t;
- line->points[3] = p_to + t;
+ begin_left = p_from + t;
+ begin_right = p_from - t;
+ end_left = p_to + t;
+ end_right = p_to - t;
+
+ line->points[0] = begin_left;
+ line->points[1] = begin_right;
+ line->points[2] = end_right;
+ line->points[3] = end_left;
line->point_count = 4;
} else {
- line->point_count = 2;
+ begin_left = p_from;
+ begin_right = p_from;
+ end_left = p_to;
+ end_right = p_to;
+
line->points[0] = p_from;
line->points[1] = p_to;
+ line->point_count = 2;
}
for (uint32_t i = 0; i < line->point_count; i++) {
line->colors[i] = p_color;
}
+
+ if (p_antialiased) {
+ float border_size = 2.0;
+ if (p_width < border_size) {
+ border_size = p_width;
+ }
+ Vector2 dir2 = diff.normalized();
+
+ Vector2 border = dir * border_size;
+ Vector2 border2 = dir2 * border_size;
+
+ Color transparent = Color(p_color.r, p_color.g, p_color.b, 0.0);
+
+ {
+ Item::CommandPrimitive *left_border = canvas_item->alloc_command<Item::CommandPrimitive>();
+ ERR_FAIL_COND(!left_border);
+
+ left_border->points[0] = begin_left;
+ left_border->points[1] = begin_left + border;
+ left_border->points[2] = end_left + border;
+ left_border->points[3] = end_left;
+
+ left_border->colors[0] = p_color;
+ left_border->colors[1] = transparent;
+ left_border->colors[2] = transparent;
+ left_border->colors[3] = p_color;
+
+ left_border->point_count = 4;
+ }
+ {
+ Item::CommandPrimitive *right_border = canvas_item->alloc_command<Item::CommandPrimitive>();
+ ERR_FAIL_COND(!right_border);
+
+ right_border->points[0] = begin_right;
+ right_border->points[1] = begin_right - border;
+ right_border->points[2] = end_right - border;
+ right_border->points[3] = end_right;
+
+ right_border->colors[0] = p_color;
+ right_border->colors[1] = transparent;
+ right_border->colors[2] = transparent;
+ right_border->colors[3] = p_color;
+
+ right_border->point_count = 4;
+ }
+ {
+ Item::CommandPrimitive *top_border = canvas_item->alloc_command<Item::CommandPrimitive>();
+ ERR_FAIL_COND(!top_border);
+
+ top_border->points[0] = begin_left;
+ top_border->points[1] = begin_left + border2;
+ top_border->points[2] = begin_right + border2;
+ top_border->points[3] = begin_right;
+
+ top_border->colors[0] = p_color;
+ top_border->colors[1] = transparent;
+ top_border->colors[2] = transparent;
+ top_border->colors[3] = p_color;
+
+ top_border->point_count = 4;
+ }
+ {
+ Item::CommandPrimitive *bottom_border = canvas_item->alloc_command<Item::CommandPrimitive>();
+ ERR_FAIL_COND(!bottom_border);
+
+ bottom_border->points[0] = end_left;
+ bottom_border->points[1] = end_left - border2;
+ bottom_border->points[2] = end_right - border2;
+ bottom_border->points[3] = end_right;
+
+ bottom_border->colors[0] = p_color;
+ bottom_border->colors[1] = transparent;
+ bottom_border->colors[2] = transparent;
+ bottom_border->colors[3] = p_color;
+
+ bottom_border->point_count = 4;
+ }
+ {
+ Item::CommandPrimitive *top_left_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
+ ERR_FAIL_COND(!top_left_corner);
+
+ top_left_corner->points[0] = begin_left;
+ top_left_corner->points[1] = begin_left + border2;
+ top_left_corner->points[2] = begin_left + border + border2;
+ top_left_corner->points[3] = begin_left + border;
+
+ top_left_corner->colors[0] = p_color;
+ top_left_corner->colors[1] = transparent;
+ top_left_corner->colors[2] = transparent;
+ top_left_corner->colors[3] = transparent;
+
+ top_left_corner->point_count = 4;
+ }
+ {
+ Item::CommandPrimitive *top_right_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
+ ERR_FAIL_COND(!top_right_corner);
+
+ top_right_corner->points[0] = begin_right;
+ top_right_corner->points[1] = begin_right + border2;
+ top_right_corner->points[2] = begin_right - border + border2;
+ top_right_corner->points[3] = begin_right - border;
+
+ top_right_corner->colors[0] = p_color;
+ top_right_corner->colors[1] = transparent;
+ top_right_corner->colors[2] = transparent;
+ top_right_corner->colors[3] = transparent;
+
+ top_right_corner->point_count = 4;
+ }
+ {
+ Item::CommandPrimitive *bottom_left_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
+ ERR_FAIL_COND(!bottom_left_corner);
+
+ bottom_left_corner->points[0] = end_left;
+ bottom_left_corner->points[1] = end_left - border2;
+ bottom_left_corner->points[2] = end_left + border - border2;
+ bottom_left_corner->points[3] = end_left + border;
+
+ bottom_left_corner->colors[0] = p_color;
+ bottom_left_corner->colors[1] = transparent;
+ bottom_left_corner->colors[2] = transparent;
+ bottom_left_corner->colors[3] = transparent;
+
+ bottom_left_corner->point_count = 4;
+ }
+ {
+ Item::CommandPrimitive *bottom_right_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
+ ERR_FAIL_COND(!bottom_right_corner);
+
+ bottom_right_corner->points[0] = end_right;
+ bottom_right_corner->points[1] = end_right - border2;
+ bottom_right_corner->points[2] = end_right - border - border2;
+ bottom_right_corner->points[3] = end_right - border;
+
+ bottom_right_corner->colors[0] = p_color;
+ bottom_right_corner->colors[1] = transparent;
+ bottom_right_corner->colors[2] = transparent;
+ bottom_right_corner->colors[3] = transparent;
+
+ bottom_right_corner->point_count = 4;
+ }
+ }
}
void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index 94bae30ae0..637245502d 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -215,7 +215,7 @@ public:
void canvas_item_set_update_when_visible(RID p_item, bool p_update);
- void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0);
+ void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color);
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index abe1a09b06..58b4ded9f4 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -1479,62 +1479,78 @@ void main() {
} else { //no soft shadows
vec4 pssm_coord;
+ float blur_factor;
+
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 0)
pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ blur_factor = 1.0;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 1)
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ // Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
+ blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.y;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 2)
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
-
+ // Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
+ blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.z;
} else {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 3)
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ // Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
+ blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.w;
}
pssm_coord /= pssm_coord.w;
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * blur_factor, pssm_coord);
if (directional_lights.data[i].blend_splits) {
float pssm_blend;
+ float blur_factor2;
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 1)
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
+ // Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
+ blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.y;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 2)
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+ // Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
+ blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.z;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 3)
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
+ // Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
+ blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.w;
} else {
pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
+ blur_factor2 = 1.0;
}
pssm_coord /= pssm_coord.w;
- float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * blur_factor2, pssm_coord);
shadow = mix(shadow, shadow2, pssm_blend);
}
}
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
index 6911cab27b..b6ba244665 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
@@ -1282,6 +1282,7 @@ void main() {
float depth_z = -vertex.z;
vec4 pssm_coord;
+ float blur_factor;
vec3 light_dir = directional_lights.data[i].direction;
vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
@@ -1297,56 +1298,71 @@ void main() {
BIAS_FUNC(v, 0)
pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ blur_factor = 1.0;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 1)
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ // Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
+ blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.y;
+ ;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 2)
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
-
+ // Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
+ blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.z;
} else {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 3)
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ // Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
+ blur_factor = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.w;
}
pssm_coord /= pssm_coord.w;
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * blur_factor, pssm_coord);
if (directional_lights.data[i].blend_splits) {
float pssm_blend;
+ float blur_factor2;
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 1)
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
+ // Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
+ blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.y;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 2)
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+ // Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
+ blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.z;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
vec4 v = vec4(vertex, 1.0);
BIAS_FUNC(v, 3)
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
+ // Adjust shadow blur with reference to the first split to reduce discrepancy between shadow splits.
+ blur_factor2 = directional_lights.data[i].shadow_split_offsets.x / directional_lights.data[i].shadow_split_offsets.w;
} else {
pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
+ blur_factor2 = 1.0;
}
pssm_coord /= pssm_coord.w;
- float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale * blur_factor2, pssm_coord);
shadow = mix(shadow, shadow2, pssm_blend);
}
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index f492c5e9bd..07d413b095 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -77,23 +77,21 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
RSG::scene->free(p_viewport->render_buffers);
p_viewport->render_buffers = RID();
} else {
- float scaling_3d_scale = p_viewport->scaling_3d_scale;
-
+ const float scaling_3d_scale = p_viewport->scaling_3d_scale;
RS::ViewportScaling3DMode scaling_3d_mode = p_viewport->scaling_3d_mode;
bool scaling_enabled = true;
if ((scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && (scaling_3d_scale > 1.0)) {
- // FSR is not design for downsampling.
- // Throw a warning and fallback to VIEWPORT_SCALING_3D_MODE_BILINEAR
- WARN_PRINT_ONCE("FSR 3D resolution scaling does not support supersampling. Falling back to bilinear scaling.");
+ // FSR is not designed for downsampling.
+ // Fall back to bilinear scaling.
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
}
if ((scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && !p_viewport->fsr_enabled) {
// FSR is not actually available.
- // Throw a warning and fallback to disable scaling
- WARN_PRINT_ONCE("FSR 3D resolution scaling is not available. Disabling 3D resolution scaling.");
- scaling_enabled = false;
+ // Fall back to bilinear scaling.
+ WARN_PRINT_ONCE("FSR 1.0 3D resolution scaling is not available. Falling back to bilinear 3D resolution scaling.");
+ scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
}
if (scaling_3d_scale == 1.0) {
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index cc1edc728a..21e11c6d71 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -799,7 +799,7 @@ public:
FUNC2(canvas_item_set_draw_behind_parent, RID, bool)
- FUNC5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float)
+ FUNC6(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float, bool)
FUNC5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
FUNC4(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float)
FUNC3(canvas_item_add_rect, RID, const Rect2 &, const Color &)
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index a0769ef106..816a02761d 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -5144,7 +5144,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (!call_expression) {
return nullptr;
}
- data_type = call_expression->get_datatype();
} else if (tk.type == TK_BRACKET_OPEN) { // indexing
index_expression = _parse_and_reduce_expression(p_block, p_function_info);
if (!index_expression) {
@@ -5598,15 +5597,13 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (p_block != nullptr) {
p_block->block_tag = SubClassTag::TAG_ARRAY;
}
- Node *call_expression = _parse_and_reduce_expression(p_block, p_function_info);
+ mn->call_expression = _parse_and_reduce_expression(p_block, p_function_info);
if (p_block != nullptr) {
p_block->block_tag = SubClassTag::TAG_GLOBAL;
}
- if (!call_expression) {
+ if (!mn->call_expression) {
return nullptr;
}
- mn->datatype = call_expression->get_datatype();
- mn->call_expression = call_expression;
} else if (tk.type == TK_BRACKET_OPEN) {
Node *index_expression = _parse_and_reduce_expression(p_block, p_function_info);
if (!index_expression) {
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 25ec8760af..66ae220edf 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -451,8 +451,8 @@ public:
int array_size = 0;
bool is_local = false;
- virtual DataType get_datatype() const override { return datatype_cache; }
- virtual String get_datatype_name() const override { return String(struct_name); }
+ virtual DataType get_datatype() const override { return call_expression ? call_expression->get_datatype() : datatype_cache; }
+ virtual String get_datatype_name() const override { return call_expression ? call_expression->get_datatype_name() : String(struct_name); }
virtual int get_array_size() const override { return (index_expression || call_expression) ? 0 : array_size; }
virtual bool is_indexed() const override { return index_expression != nullptr; }
@@ -558,8 +558,8 @@ public:
Node *call_expression = nullptr;
bool has_swizzling_duplicates = false;
- virtual DataType get_datatype() const override { return datatype; }
- virtual String get_datatype_name() const override { return String(struct_name); }
+ virtual DataType get_datatype() const override { return call_expression ? call_expression->get_datatype() : datatype; }
+ virtual String get_datatype_name() const override { return call_expression ? call_expression->get_datatype_name() : String(struct_name); }
virtual int get_array_size() const override { return (index_expression || call_expression) ? 0 : array_size; }
virtual bool is_indexed() const override { return index_expression != nullptr || call_expression != nullptr; }
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index fa6c3fac68..b58e6138eb 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2566,7 +2566,7 @@ void RenderingServer::_bind_methods() {
/* Primitives */
- ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width"), &RenderingServer::canvas_item_add_line, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width", "antialiased"), &RenderingServer::canvas_item_add_line, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("canvas_item_add_polyline", "item", "points", "colors", "width", "antialiased"), &RenderingServer::canvas_item_add_polyline, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &RenderingServer::canvas_item_add_rect);
ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 94692ba68d..71896e9d11 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -1293,7 +1293,7 @@ public:
NINE_PATCH_TILE_FIT,
};
- virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0) = 0;
+ virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false) = 0;
virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0;
virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0;
virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0;