Compare commits

...

66 Commits

Author SHA1 Message Date
Alex
de6002fabd
Android bindings for OS::get_tmp_dir() 2024-10-22 16:26:21 -04:00
Adam Scott
152e24c7de
Windows prototype using GetTempPathW() 2024-10-22 11:57:12 -04:00
Adam Scott
ca7840073c
Add tmp utilities 2024-10-22 11:57:12 -04:00
Thaddeus Crews
b3bcb2dc14
Merge pull request #98299 from timothyqiu/tree-coordinate
Some checks are pending
🔗 GHA / 📊 Static checks (push) Waiting to run
🔗 GHA / 🤖 Android (push) Blocked by required conditions
🔗 GHA / 🍏 iOS (push) Blocked by required conditions
🔗 GHA / 🐧 Linux (push) Blocked by required conditions
🔗 GHA / 🍎 macOS (push) Blocked by required conditions
🔗 GHA / 🏁 Windows (push) Blocked by required conditions
🔗 GHA / 🌐 Web (push) Blocked by required conditions
🔗 GHA / 🪲 Godot CPP (push) Blocked by required conditions
Fix button click detection when `Tree` is rotated
2024-10-21 16:39:31 -05:00
Thaddeus Crews
a4ed24acef
Merge pull request #98041 from Hilderin/fix-lost-gdextensions-on-startup
Fix loss of gdextension on editor startup
2024-10-21 16:39:30 -05:00
Thaddeus Crews
7815ccbdd5
Merge pull request #98294 from Calinou/texture-placeholders-use-shared-copy
Use a shared copy of placeholder textures, tweak placeholder appearance
2024-10-21 16:39:29 -05:00
Thaddeus Crews
66d19abdfa
Merge pull request #96629 from ditiem-games/path2d
Fix Animated Path2D doesn't update PathFollow2D progress when scene is running.
2024-10-21 16:39:28 -05:00
Thaddeus Crews
22822f71ac
Merge pull request #97905 from 0x53A/patch-1
Update Node.xml: specify that normal processing happens in tree order
2024-10-21 16:39:27 -05:00
Thaddeus Crews
6ec3dc1fb5
Merge pull request #97649 from ohboh/literally-unusable-on-mobile-without-this
Fix `emulate_mouse_from_touch` setting affecting editor
2024-10-21 16:39:26 -05:00
Thaddeus Crews
7dbea98c49
Merge pull request #97005 from Repiteo/core/window-corner-style
Core: Add `DisplayServer` flag for sharp corners
2024-10-21 16:39:25 -05:00
Thaddeus Crews
8b5c20e2b0
Merge pull request #98283 from tetrapod00/canvasmodulate-link
Docs: Add link to 2D lights and shadows from CanvasModulate
2024-10-21 16:39:24 -05:00
Thaddeus Crews
55aeff19dc
Merge pull request #98146 from HolonProduction/this-error-does-not-apply-to-unrecognized-annotations
GDScript: Fix annotation parsing adding new annotation entries
2024-10-21 16:39:24 -05:00
Thaddeus Crews
1a9628f937
Merge pull request #98267 from Chaosus/shader_pp_error
Add `#error` preprocessor directive to shading language
2024-10-21 16:39:23 -05:00
Thaddeus Crews
677ebad7fc
Merge pull request #97626 from Repiteo/scons/c17
SCons: Bump C standard: `C11`→`C17`
2024-10-21 16:39:22 -05:00
Thaddeus Crews
a14e9e99e5
Merge pull request #98388 from DarioSamo/sync-fixes
Improve synchronization of rendering after changes from transfer queues.
2024-10-21 16:39:21 -05:00
Thaddeus Crews
178342b058
Merge pull request #98258 from LainAmongYou/fix-bgra
Add support for BGRA textures with Texture*RD
2024-10-21 16:39:20 -05:00
Thaddeus Crews
77da16ce69
Merge pull request #88530 from davthedev/tree-hover-items
Add hover state to Tree items display
2024-10-21 16:39:16 -05:00
Thaddeus Crews
291e4b78e2
Merge pull request #98237 from dustdfg/os_transitive_image_headers_refactor
Don't include `core/io/image.h` in `core/os/os.h`
2024-10-21 16:39:15 -05:00
Thaddeus Crews
b6547b0d06
Merge pull request #98236 from timothyqiu/locale-compare-cache-4.x
Cache results for `TranslationServer.compare_locales()`
2024-10-21 16:39:14 -05:00
Thaddeus Crews
7a438dc72e
Merge pull request #97205 from tetrapod00/inspect-native-shader-code
Add "Inspect Native Shader Code" to shader inspector and shader editor
2024-10-21 16:39:13 -05:00
Thaddeus Crews
cb3c01a5fe
Merge pull request #97588 from TML233/generated-raise-signal
[C#] Change generated On{SignalName} to EmitSignal{SignalName}
2024-10-21 16:39:12 -05:00
Thaddeus Crews
c145e85011
Merge pull request #98226 from m-pranav-r/fix-volumetric-shadows
Fix incorrect depth comparison used to calculate volumetric fog shadowing
2024-10-21 16:39:11 -05:00
Thaddeus Crews
ecc2eb73fc
Merge pull request #97707 from Sauermann/fix-input-device-clash
Fix `InputEvent` device id clash
2024-10-21 16:39:10 -05:00
Thaddeus Crews
975f42227f
Merge pull request #97706 from lalitshankarchowdhury/fix-create-folder
Display proper message on invalid folder path
2024-10-21 16:39:10 -05:00
Thaddeus Crews
4630cbc487
Merge pull request #98212 from stuartcarnie/sgc/metal_improvements
Metal: Performance improvements and bug fixes
2024-10-21 16:39:09 -05:00
Thaddeus Crews
8be0061458
Merge pull request #98340 from juanjp600/dotnet-typed-dictionary-hint-fix
Fix exported typed dictionaries in .NET having an incorrect hint
2024-10-21 16:39:08 -05:00
Thaddeus Crews
4ce5235fbd
Merge pull request #98203 from timothyqiu/layout-dir-created-equal
Add System Locale layout direction for `Control` and `Window`
2024-10-21 16:39:07 -05:00
Thaddeus Crews
16d68c6be4
Merge pull request #98201 from AThousandShips/lightmap_compile_fix
Fix unreachable code in `lightmap_gi.cpp`
2024-10-21 16:39:06 -05:00
Thaddeus Crews
29fa4b18f1
Merge pull request #97807 from syntaxerror247/colorPicker_kb_fix
Fix `ColorPicker` virtual keyboard popup on mobile
2024-10-21 16:39:06 -05:00
Thaddeus Crews
5fb22327ee
Merge pull request #97542 from AThousandShips/dict_sort_fix
[Core] Fix sorting of `Dictionary` keys
2024-10-21 16:39:05 -05:00
Thaddeus Crews
5e65747d90
Merge pull request #97925 from huwpascoe/lightmap_dynamic_bugfix
Fix updating dynamic objects in LightmapGI
2024-10-21 16:39:04 -05:00
Dario
4ad424234f Improve synchronization of rendering commands after changes from transfer queues.
Fix an error where barriers are expected to be inserted for the swap chain textures.
Add the relevant synchronization stages and accesses to resources between frames.
Fix an error where debug labels weren't finished correctly between frames.
Breadcrumbs are now behind an optional macro as they currently lead to synchronization errors which are harmless.
2024-10-21 11:27:56 -03:00
Hilderin
fbd1643176 Fix lost of gdextension on editor startup.
Co-authored-by: NetroScript <noreply@enostrion.com>"
2024-10-20 18:39:31 -04:00
Markus Sauermann
916d480686 Fix InputEvent device id clash
`InputMap::ALL_DEVICES` and `InputEvent::DEVICE_ID_EMULATION` have the
same value `-1`.

Change value of `InputMap::All_DEVICES` so that it's different from
`InputEvent::DEVICE_ID_EMULATION`. `InputEvent::DEVICE_ID_EMULATION`
is part of the API and can't be changed without potentially breaking
projects.

Gather all special device constants in a single location inside
`InputEvent`.

Add a converter to project settings, that takes care of adjusting
project files during loading.
2024-10-20 21:56:41 +02:00
Lukas Rieger
5c65f80199 Update Node.xml: specify that normal processing happens in tree order 2024-10-20 18:41:54 +02:00
Stuart Carnie
83ac274e25
Metal: Performance improvements and bug fixes 2024-10-20 11:15:13 +11:00
Clay John
44fa552343
Merge pull request #83863 from Calinou/editor-lightmap-probe-gizmo-improve-display
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
🔗 GHA / 🪲 Godot CPP (push) Has been cancelled
Improve display for lightmap probes in the editor
2024-10-18 16:57:45 -07:00
Clay John
80f0b33313
Merge pull request #97977 from syntaxerror247/menu_bar_refresh_bug
Refresh `MenuBar` scene after child renamed in editor
2024-10-18 13:54:27 -07:00
Hugo Locurcio
8e0c0d7837 Improve display for lightmap probes in the editor
- Use the default Back cull mode to improve performance slightly
  and prevent obstructing the camera.
- Fade probes when the camera gets close as to be less intrusive.
2024-10-18 22:52:50 +02:00
Clay John
58a7f9b4d8
Merge pull request #98271 from DarioSamo/d3d12-enhanced-barrier-fix
Some checks are pending
🔗 GHA / 📊 Static checks (push) Waiting to run
🔗 GHA / 🤖 Android (push) Blocked by required conditions
🔗 GHA / 🍏 iOS (push) Blocked by required conditions
🔗 GHA / 🐧 Linux (push) Blocked by required conditions
🔗 GHA / 🍎 macOS (push) Blocked by required conditions
🔗 GHA / 🏁 Windows (push) Blocked by required conditions
🔗 GHA / 🌐 Web (push) Blocked by required conditions
🔗 GHA / 🪲 Godot CPP (push) Blocked by required conditions
Move transitions of textures from transfer workers to the graphics queue.
2024-10-18 12:03:50 -07:00
Thaddeus Crews
f8c4a683d7
Core: Add DisplayServer flag for sharp corners 2024-10-18 11:20:21 -05:00
Yevhen Babiichuk (DustDFG)
af6d260c17 Don't include core/io/image.h in core/os/os.h
`core/os/os.h` doesn't use `core/io/image.h`. It just brings
transitive dependencies. Lots of dependencies because `core/os/os.h`
is transitively included in almost every file of godot

Also added `core/io/image.h` into files^1 where `Ref<Image>` and `core/os/os.h`
were used to prevent obscure errors involving `Ref<Image>`

^1 except those which include `core/io/image_loader.h` or `core/io/image.h` by
corresponding .h file with the same name

Signed-off-by: Yevhen Babiichuk (DustDFG) <dfgdust@gmail.com>
Co-authored-by: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com>
2024-10-18 19:04:19 +03:00
Haoyu Qiu
17642692c5 Fix button click detection when Tree is rotated 2024-10-18 22:43:48 +08:00
Hugo Locurcio
35a20fa96a Use a shared copy of placeholder textures, tweak placeholder appearance
This reduces memory usage a bit in case multiple placeholders were
requested, e.g. when using multiple NoiseTextures with no noise property
defined.

The placeholder texture's appearance was also changed from a plain magenta
color to a checkerboard alternating between magenta and black pixels.
This makes it easier to spot when the placeholder texture ends up
being used in a complex scene (usually by accident).
The texture's dimensions remain identical to keep the physical size
identical in 2D.
2024-10-18 14:51:51 +02:00
Dario
8c3e46b13b Move transitions of textures initialized by transfer workers to the main graphics queue.
Also adds a new possible texture layout and API trait to support a particular behavior in D3D12 where only the COMMON layout is supported in copy queues. Fixes #98158.
2024-10-18 09:15:25 -03:00
Chaosus
155cf6a5b6 Add #error preprocessor directive to shading language 2024-10-18 10:56:58 +03:00
A Thousand Ships
610635e1c8
Add test 2024-10-18 08:47:29 +02:00
A Thousand Ships
79f654ced5
[Core] Fix sorting of Dictionary keys
`StringName` keys were sorted as `StringName` which is unstable.
2024-10-18 08:47:05 +02:00
Juan Pablo Arce
e3790de461 Fix exported typed dictionaries in .NET having an incorrect hint, which led to incorrect scene serialization 2024-10-18 00:55:24 -03:00
tetrapod00
4b37fb3f88 Docs: Add link to 2D lights and shadows from CanvasModulate 2024-10-17 19:53:41 -07:00
yesfish
274076c5be Lightmap Dynamic Bugfix 2024-10-17 16:27:30 +01:00
Lalit Shankar Chowdhury
25687c5b99
Display proper message on invalid folder path 2024-10-17 13:06:48 +05:30
Lain
4e6d9813b2 Add support for BGRA textures with Texture*RD
This adds the ability to use BGRA textures created with RenderingDevice
with classes such as Texture2DRD.
2024-10-16 22:31:43 -07:00
Haoyu Qiu
009446a277 Add System Locale layout direction for Control and Window 2024-10-17 07:52:07 +08:00
David Giardi
ebe1a2d7ec Add hover state to Tree items display 2024-10-17 00:21:52 +02:00
Haoyu Qiu
acab2d6c1c Cache results for TranslationServer.compare_locales() 2024-10-16 20:54:56 +08:00
m-pranav-r
c12001a9dc Fix incorrect depth comparison used to calculate volumetric fog shadowing 2024-10-16 14:55:41 +05:30
A Thousand Ships
de128812f3
Fix unreachable code in lightmap_gi.cpp 2024-10-15 13:17:15 +02:00
HolonProduction
140c6a612e GDScript: Fix annotation parsing adding new annotation entries 2024-10-13 22:43:06 +02:00
tetrapod00
12d2c05936 Add "Inspect Native Shader Code" to shader resource and shader editor 2024-10-08 11:02:45 -07:00
Anish Mishra
9f6c88de89 update MenuBar after child renamed in editor 2024-10-08 20:19:02 +05:30
Anish Mishra
8f9ed35f8b Fix ColorPicker virtual keyboard popup on mobile 2024-10-05 19:03:29 +05:30
obo
4ef07cb9a5 Fix "emulate mouse from touch" setting affecting editor
Make "emulate mouse from touch" always true in the editor
2024-10-01 02:23:32 +08:00
Thaddeus Crews
705f51f97e
SCons: Bump C standard: C11C17 2024-09-29 11:23:24 -05:00
TML
fa48ed9945 Change generated On{SignalName} to EmitSignal{SignalName} 2024-09-28 22:10:33 +08:00
David Trallero
1b376b32cd Update FollowPath2D children of Path2D when a curve_changed event occurs 2024-09-06 07:54:22 +08:00
128 changed files with 1358 additions and 388 deletions

View File

@ -799,8 +799,8 @@ if env["lto"] != "none":
# This needs to come after `configure`, otherwise we don't have env.msvc.
if not env.msvc:
# Specifying GNU extensions support explicitly, which are supported by
# both GCC and Clang. Both currently default to gnu11 and gnu++17.
env.Prepend(CFLAGS=["-std=gnu11"])
# both GCC and Clang. Both currently default to gnu17 and gnu++17.
env.Prepend(CFLAGS=["-std=gnu17"])
env.Prepend(CXXFLAGS=["-std=gnu++17"])
else:
# MSVC started offering C standard support with Visual Studio 2019 16.8, which covers all
@ -809,7 +809,7 @@ else:
if cc_version_major < 16:
print_warning("Visual Studio 2017 cannot specify a C-Standard.")
else:
env.Prepend(CFLAGS=["/std:c11"])
env.Prepend(CFLAGS=["/std:c17"])
# MSVC is non-conforming with the C++ standard by default, so we enable more conformance.
# Note that this is still not complete conformance, as certain Windows-related headers
# don't compile under complete conformance.

View File

@ -494,6 +494,7 @@ bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_f
}
void ProjectSettings::_convert_to_last_version(int p_from_version) {
#ifndef DISABLE_DEPRECATED
if (p_from_version <= 3) {
// Converts the actions from array to dictionary (array of events to dictionary with deadzone + events)
for (KeyValue<StringName, ProjectSettings::VariantContainer> &E : props) {
@ -507,6 +508,22 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) {
}
}
}
if (p_from_version <= 5) {
// Converts the device in events from -1 (emulated events) to -3 (all events).
for (KeyValue<StringName, ProjectSettings::VariantContainer> &E : props) {
if (String(E.key).begins_with("input/")) {
Dictionary action = E.value.variant;
Array events = action["events"];
for (int i = 0; i < events.size(); i++) {
Ref<InputEvent> x = events[i];
if (x->get_device() == -1) { // -1 was the previous value (GH-97707).
x->set_device(InputEvent::DEVICE_ID_ALL_DEVICES);
}
}
}
}
}
#endif // DISABLE_DEPRECATED
}
/*
@ -1460,6 +1477,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("display/window/size/transparent", false);
GLOBAL_DEF("display/window/size/extend_to_title", false);
GLOBAL_DEF("display/window/size/no_focus", false);
GLOBAL_DEF("display/window/size/sharp_corners", false);
GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"), 0); // 8K resolution
GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution

View File

@ -556,6 +556,11 @@ String OS::get_cache_dir() const {
return ::OS::get_singleton()->get_cache_path();
}
String OS::get_tmp_dir() const {
// Exposed as `get_tmp_dir()` instead of `get_tmp_path()` for consistency with other exposed OS methods.
return ::OS::get_singleton()->get_tmp_path();
}
bool OS::is_debug_build() const {
#ifdef DEBUG_ENABLED
return true;
@ -678,6 +683,7 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_config_dir"), &OS::get_config_dir);
ClassDB::bind_method(D_METHOD("get_data_dir"), &OS::get_data_dir);
ClassDB::bind_method(D_METHOD("get_cache_dir"), &OS::get_cache_dir);
ClassDB::bind_method(D_METHOD("get_tmp_dir"), &OS::get_tmp_dir);
ClassDB::bind_method(D_METHOD("get_unique_id"), &OS::get_unique_id);
ClassDB::bind_method(D_METHOD("get_keycode_string", "code"), &OS::get_keycode_string);

View File

@ -32,7 +32,6 @@
#define CORE_BIND_H
#include "core/debugger/engine_profiler.h"
#include "core/io/image.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/object/script_language.h"
@ -246,6 +245,7 @@ public:
String get_config_dir() const;
String get_data_dir() const;
String get_cache_dir() const;
String get_tmp_dir() const;
Error set_thread_name(const String &p_name);
::Thread::ID get_thread_caller_id() const;

View File

@ -34,6 +34,7 @@
#include "core/extension/gdextension.h"
#include "core/extension/gdextension_compat_hashes.h"
#include "core/io/file_access.h"
#include "core/io/image.h"
#include "core/io/xml_parser.h"
#include "core/object/class_db.h"
#include "core/object/script_language_extension.h"

View File

@ -35,9 +35,6 @@
#include "core/os/keyboard.h"
#include "core/os/os.h"
const int InputEvent::DEVICE_ID_EMULATION = -1;
const int InputEvent::DEVICE_ID_INTERNAL = -2;
void InputEvent::set_device(int p_device) {
device = p_device;
emit_changed();

View File

@ -62,8 +62,9 @@ protected:
static void _bind_methods();
public:
static const int DEVICE_ID_EMULATION;
static const int DEVICE_ID_INTERNAL;
inline static constexpr int DEVICE_ID_EMULATION = -1;
inline static constexpr int DEVICE_ID_INTERNAL = -2;
inline static constexpr int DEVICE_ID_ALL_DEVICES = -3; // Signify that a given Action can be triggered by any device.
void set_device(int p_device);
int get_device() const;

View File

@ -39,8 +39,6 @@
InputMap *InputMap::singleton = nullptr;
int InputMap::ALL_DEVICES = -1;
void InputMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_action", "action"), &InputMap::has_action);
ClassDB::bind_method(D_METHOD("get_actions"), &InputMap::_get_actions);
@ -163,7 +161,7 @@ List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Re
int i = 0;
for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
int device = E->get()->get_device();
if (device == ALL_DEVICES || device == p_event->get_device()) {
if (device == InputEvent::DEVICE_ID_ALL_DEVICES || device == p_event->get_device()) {
if (E->get()->action_match(p_event, p_exact_match, p_action.deadzone, r_pressed, r_strength, r_raw_strength)) {
if (r_event_index) {
*r_event_index = i;

View File

@ -43,11 +43,6 @@ class InputMap : public Object {
GDCLASS(InputMap, Object);
public:
/**
* A special value used to signify that a given Action can be triggered by any device
*/
static int ALL_DEVICES;
struct Action {
int id;
float deadzone;

View File

@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/io/file_access.h"
#include "core/object/class_db.h"
#include "core/os/memory.h"
#include "core/os/os.h"
#include "core/templates/local_vector.h"
@ -323,6 +324,33 @@ Ref<DirAccess> DirAccess::create(AccessType p_access) {
return da;
}
Ref<DirAccess> DirAccess::create_tmp(const String &p_prefix, bool p_keep) {
Ref<DirAccess> dir_access = DirAccess::open(OS::get_singleton()->get_tmp_path());
String hash;
while (true) {
hash = itos(Math::rand()).sha256_text().substr(0, 10);
if (!DirAccess::exists(hash)) {
break;
}
}
String path = (p_prefix.is_empty()
? ""
: p_prefix + "-") +
hash;
Error err = dir_access->make_dir(path);
if (err != OK) {
return Ref<DirAccess>();
}
err = dir_access->change_dir(path);
if (err != OK) {
return Ref<DirAccess>();
}
dir_access->_is_tmp = true;
dir_access->_tmp_keep_after_free = p_keep;
dir_access->_tmp_path = dir_access->get_current_dir();
return dir_access;
}
Error DirAccess::get_open_error() {
return last_dir_open_error;
}
@ -552,9 +580,35 @@ bool DirAccess::is_case_sensitive(const String &p_path) const {
return true;
}
void DirAccess::_delete_tmp() {
// Remove created tmp directory.
if (!_is_tmp || _tmp_keep_after_free) {
return;
}
if (!DirAccess::exists(_tmp_path)) {
return;
}
Error err;
{
Ref<DirAccess> dir_access = DirAccess::open(_tmp_path, &err);
if (err != OK) {
return;
}
err = dir_access->erase_contents_recursive();
if (err != OK) {
return;
}
}
DirAccess::remove_absolute(_tmp_path);
}
void DirAccess::_bind_methods() {
ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open);
ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error);
ClassDB::bind_static_method("DirAccess", D_METHOD("create_tmp", "prefix", "keep"), &DirAccess::create_tmp, DEFVAL(""), DEFVAL(false));
ClassDB::bind_method(D_METHOD("list_dir_begin"), &DirAccess::list_dir_begin, DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_next"), &DirAccess::_get_next);
@ -598,3 +652,7 @@ void DirAccess::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");
}
DirAccess::~DirAccess() {
_delete_tmp();
}

View File

@ -61,6 +61,11 @@ private:
bool include_navigational = false;
bool include_hidden = false;
bool _is_tmp = false;
bool _tmp_keep_after_free = false;
String _tmp_path;
void _delete_tmp();
protected:
static void _bind_methods();
@ -128,6 +133,7 @@ public:
static Ref<DirAccess> create_for_path(const String &p_path);
static Ref<DirAccess> create(AccessType p_access);
static Ref<DirAccess> create_tmp(const String &p_prefix = "", bool p_keep = false);
static Error get_open_error();
template <typename T>
@ -162,7 +168,7 @@ public:
virtual bool is_case_sensitive(const String &p_path) const;
DirAccess() {}
virtual ~DirAccess() {}
virtual ~DirAccess();
};
#endif // DIR_ACCESS_H

View File

@ -68,6 +68,19 @@ void FileAccess::_set_access_type(AccessType p_access) {
_access_type = p_access;
}
void FileAccess::_delete_tmp() {
// Remove created tmp file.
if (!_is_tmp_file || _tmp_keep_after_use) {
return;
}
if (!FileAccess::exists(_tmp_path)) {
return;
}
DirAccess::remove_absolute(_tmp_path);
}
Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
Ref<FileAccess> ret;
if (p_path.begins_with("res://")) {
@ -83,6 +96,42 @@ Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
return ret;
}
Ref<FileAccess> FileAccess::create_tmp(int p_mode_flags, const String &p_extension, bool p_keep, Error *r_error) {
const String TMP_DIR = OS::get_singleton()->get_tmp_path();
String extension = p_extension;
if (extension.begins_with(".")) {
extension = extension.replace_first(".", "");
}
String hash;
String tmp_file_path;
while (true) {
hash = itos(Math::rand()).sha256_text().substr(0, 10);
tmp_file_path = TMP_DIR.path_join(hash + (extension.is_empty() ? "" : "." + extension));
if (!DirAccess::exists(tmp_file_path)) {
break;
}
}
Error err;
{
// Create file first with WRITE mode.
// Otherwise, it would fail to open with a READ mode.
Ref<FileAccess> ret = FileAccess::open(tmp_file_path, FileAccess::ModeFlags::WRITE, &err);
if (err != OK) {
*r_error = err;
return Ref<FileAccess>();
}
ret->flush();
}
// Open then the tmp file with the correct mode flag.
Ref<FileAccess> ret = FileAccess::open(tmp_file_path, p_mode_flags, &err);
if (ret.is_valid()) {
ret->_is_tmp_file = true;
ret->_tmp_keep_after_use = p_keep;
ret->_tmp_path = ret->get_path_absolute();
}
return ret;
}
Error FileAccess::reopen(const String &p_path, int p_mode_flags) {
return open_internal(p_path, p_mode_flags);
}
@ -810,6 +859,7 @@ void FileAccess::_bind_methods() {
ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &FileAccess::open_encrypted_pass);
ClassDB::bind_static_method("FileAccess", D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &FileAccess::open_compressed, DEFVAL(0));
ClassDB::bind_static_method("FileAccess", D_METHOD("get_open_error"), &FileAccess::get_open_error);
ClassDB::bind_static_method("FileAccess", D_METHOD("create_tmp", "mode_flags", "extension", "keep"), &FileAccess::_create_tmp, DEFVAL(""), DEFVAL(false));
ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_bytes", "path"), &FileAccess::_get_file_as_bytes);
ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_string", "path"), &FileAccess::_get_file_as_string);
@ -897,3 +947,7 @@ void FileAccess::_bind_methods() {
BIND_BITFIELD_FLAG(UNIX_SET_GROUP_ID);
BIND_BITFIELD_FLAG(UNIX_RESTRICTED_DELETE);
}
FileAccess::~FileAccess() {
_delete_tmp();
}

View File

@ -122,6 +122,11 @@ private:
static Ref<FileAccess> _open(const String &p_path, ModeFlags p_mode_flags);
bool _is_tmp_file = false;
bool _tmp_keep_after_use = false;
String _tmp_path;
void _delete_tmp();
public:
static void set_file_close_fail_notify_callback(FileCloseFailNotify p_cbk) { close_fail_notify = p_cbk; }
@ -228,13 +233,18 @@ public:
static PackedByteArray _get_file_as_bytes(const String &p_path) { return get_file_as_bytes(p_path, &last_file_open_error); }
static String _get_file_as_string(const String &p_path) { return get_file_as_string(p_path, &last_file_open_error); }
static Ref<FileAccess> create_tmp(int p_mode_flags, const String &p_extension = "", bool p_keep = false, Error *r_error = nullptr);
static Ref<FileAccess> _create_tmp(int p_mode_flags, const String &p_extension = "", bool p_keep = false) {
return create_tmp(p_mode_flags, p_extension, p_keep, &last_file_open_error);
}
template <typename T>
static void make_default(AccessType p_access) {
create_func[p_access] = _create_builtin<T>;
}
FileAccess() {}
virtual ~FileAccess() {}
virtual ~FileAccess();
};
VARIANT_ENUM_CAST(FileAccess::CompressionMode);

View File

@ -121,7 +121,7 @@ String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_
d.get_key_list(&keys);
if (p_sort_keys) {
keys.sort();
keys.sort_custom<StringLikeVariantOrder>();
}
bool first_key = true;

View File

@ -1268,6 +1268,11 @@ void ResourceFormatLoaderBinary::get_recognized_extensions_for_type(const String
return;
}
// res files not supported for GDExtension.
if (p_type == "GDExtension") {
return;
}
List<String> extensions;
ClassDB::get_extensions_for_type(p_type, &extensions);

View File

@ -276,6 +276,10 @@ String OS::get_cache_path() const {
return ".";
}
String OS::get_tmp_path() const {
return ".";
}
// Path to macOS .app bundle resources
String OS::get_bundle_resource_dir() const {
return ".";

View File

@ -32,7 +32,6 @@
#define OS_H
#include "core/config/engine.h"
#include "core/io/image.h"
#include "core/io/logger.h"
#include "core/io/remote_filesystem_client.h"
#include "core/os/time_enums.h"
@ -275,6 +274,7 @@ public:
virtual String get_data_path() const;
virtual String get_config_path() const;
virtual String get_cache_path() const;
virtual String get_tmp_path() const;
virtual String get_bundle_resource_dir() const;
virtual String get_bundle_icon_path() const;

View File

@ -228,32 +228,41 @@ int TranslationServer::compare_locales(const String &p_locale_a, const String &p
return 10;
}
const String cache_key = p_locale_a + "|" + p_locale_b;
const int *cached_result = locale_compare_cache.getptr(cache_key);
if (cached_result) {
return *cached_result;
}
String locale_a = _standardize_locale(p_locale_a, true);
String locale_b = _standardize_locale(p_locale_b, true);
if (locale_a == locale_b) {
// Exact match.
locale_compare_cache.insert(cache_key, 10);
return 10;
}
Vector<String> locale_a_elements = locale_a.split("_");
Vector<String> locale_b_elements = locale_b.split("_");
if (locale_a_elements[0] == locale_b_elements[0]) {
// Matching language, both locales have extra parts.
// Return number of matching elements.
int matching_elements = 1;
for (int i = 1; i < locale_a_elements.size(); i++) {
for (int j = 1; j < locale_b_elements.size(); j++) {
if (locale_a_elements[i] == locale_b_elements[j]) {
matching_elements++;
}
}
}
return matching_elements;
} else {
if (locale_a_elements[0] != locale_b_elements[0]) {
// No match.
locale_compare_cache.insert(cache_key, 0);
return 0;
}
// Matching language, both locales have extra parts.
// Return number of matching elements.
int matching_elements = 1;
for (int i = 1; i < locale_a_elements.size(); i++) {
for (int j = 1; j < locale_b_elements.size(); j++) {
if (locale_a_elements[i] == locale_b_elements[j]) {
matching_elements++;
}
}
}
locale_compare_cache.insert(cache_key, matching_elements);
return matching_elements;
}
String TranslationServer::get_locale_name(const String &p_locale) const {

View File

@ -46,6 +46,8 @@ class TranslationServer : public Object {
Ref<TranslationDomain> doc_domain;
HashMap<StringName, Ref<TranslationDomain>> custom_domains;
mutable HashMap<String, int> locale_compare_cache;
bool enabled = true;
static TranslationServer *singleton;

View File

@ -854,6 +854,19 @@ struct StringLikeVariantComparator {
static bool compare(const Variant &p_lhs, const Variant &p_rhs);
};
struct StringLikeVariantOrder {
static _ALWAYS_INLINE_ bool compare(const Variant &p_lhs, const Variant &p_rhs) {
if (p_lhs.is_string() && p_rhs.is_string()) {
return p_lhs.operator String() < p_rhs.operator String();
}
return p_lhs < p_rhs;
}
_ALWAYS_INLINE_ bool operator()(const Variant &p_lhs, const Variant &p_rhs) const {
return compare(p_lhs, p_rhs);
}
};
Variant::ObjData &Variant::_get_obj() {
return *reinterpret_cast<ObjData *>(&_data._mem[0]);
}

View File

@ -2245,7 +2245,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
} else {
List<Variant> keys;
dict.get_key_list(&keys);
keys.sort();
keys.sort_custom<StringLikeVariantOrder>();
if (keys.is_empty()) {
// Avoid unnecessary line break.

View File

@ -7,6 +7,7 @@
[CanvasModulate] applies a color tint to all nodes on a canvas. Only one can be used to tint a canvas, but [CanvasLayer]s can be used to render things independently.
</description>
<tutorials>
<link title="2D lights and shadows">$DOCS_URL/tutorials/2d/2d_lights_and_shadows.html</link>
</tutorials>
<members>
<member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)" keywords="colour">

View File

@ -1365,7 +1365,7 @@
<constant name="LAYOUT_DIRECTION_INHERITED" value="0" enum="LayoutDirection">
Automatic layout direction, determined from the parent control layout direction.
</constant>
<constant name="LAYOUT_DIRECTION_LOCALE" value="1" enum="LayoutDirection">
<constant name="LAYOUT_DIRECTION_APPLICATION_LOCALE" value="1" enum="LayoutDirection">
Automatic layout direction, determined from the current locale.
</constant>
<constant name="LAYOUT_DIRECTION_LTR" value="2" enum="LayoutDirection">
@ -1374,6 +1374,14 @@
<constant name="LAYOUT_DIRECTION_RTL" value="3" enum="LayoutDirection">
Right-to-left layout direction.
</constant>
<constant name="LAYOUT_DIRECTION_SYSTEM_LOCALE" value="4" enum="LayoutDirection">
Automatic layout direction, determined from the system locale.
</constant>
<constant name="LAYOUT_DIRECTION_MAX" value="5" enum="LayoutDirection">
Represents the size of the [enum LayoutDirection] enum.
</constant>
<constant name="LAYOUT_DIRECTION_LOCALE" value="1" enum="LayoutDirection" deprecated="Use [constant LAYOUT_DIRECTION_APPLICATION_LOCALE] instead.">
</constant>
<constant name="TEXT_DIRECTION_INHERITED" value="3" enum="TextDirection">
Text writing direction is the same as layout direction.
</constant>

View File

@ -104,6 +104,16 @@
[b]Note:[/b] This method is implemented on macOS, Linux, and Windows.
</description>
</method>
<method name="create_tmp" qualifiers="static">
<return type="DirAccess" />
<param index="0" name="prefix" type="String" default="&quot;&quot;" />
<param index="1" name="keep" type="bool" default="false" />
<description>
Creates a temporary directory.
If [param keep] is [code]true[/code], the directory will outlive the [DirAccess] instance. When [code]false[/code], the directory will be deleted, including all its files.
If the returned value is [code]null[/code], use [method get_open_error] to get some context.
</description>
</method>
<method name="current_is_dir" qualifiers="const">
<return type="bool" />
<description>

View File

@ -2099,7 +2099,11 @@
<constant name="WINDOW_FLAG_MOUSE_PASSTHROUGH" value="7" enum="WindowFlags">
All mouse events are passed to the underlying window of the same application.
</constant>
<constant name="WINDOW_FLAG_MAX" value="8" enum="WindowFlags">
<constant name="WINDOW_FLAG_SHARP_CORNERS" value="8" enum="WindowFlags">
Window style is overridden, forcing sharp corners.
[b]Note:[/b] This flag is implemented only on Windows (11).
</constant>
<constant name="WINDOW_FLAG_MAX" value="9" enum="WindowFlags">
Max value of the [enum WindowFlags].
</constant>
<constant name="WINDOW_EVENT_MOUSE_ENTER" value="0" enum="WindowEvent">

View File

@ -50,6 +50,17 @@
[b]Note:[/b] [FileAccess] will automatically close when it's freed, which happens when it goes out of scope or when it gets assigned with [code]null[/code]. In C# the reference must be disposed after we are done using it, this can be done with the [code]using[/code] statement or calling the [code]Dispose[/code] method directly.
</description>
</method>
<method name="create_tmp" qualifiers="static">
<return type="FileAccess" />
<param index="0" name="mode_flags" type="int" />
<param index="1" name="extension" type="String" default="&quot;&quot;" />
<param index="2" name="keep" type="bool" default="false" />
<description>
Creates a temporary file.
If [param extension] is not empty, it will be appended to the temporary file name.
If [param keep] is [code]true[/code], the file will outlive the [FileAccess] instance.
</description>
</method>
<method name="eof_reached" qualifiers="const">
<return type="bool" />
<description>

View File

@ -45,7 +45,7 @@
<method name="inspect_native_shader_code">
<return type="void" />
<description>
Only available when running in the editor. Opens a popup that visualizes the generated shader code, including all variants and internal shader code.
Only available when running in the editor. Opens a popup that visualizes the generated shader code, including all variants and internal shader code. See also [method Shader.inspect_native_shader_code].
</description>
</method>
</methods>

View File

@ -73,6 +73,7 @@
<description>
Called during the physics processing step of the main loop. Physics processing means that the frame rate is synced to the physics, i.e. the [param delta] variable should be constant. [param delta] is in seconds.
It is only called if physics processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_physics_process].
Processing happens in order of [member process_physics_priority], lower priority values are called first. Nodes with the same priority are processed in tree order, or top to bottom as seen in the editor (also known as pre-order traversal).
Corresponds to the [constant NOTIFICATION_PHYSICS_PROCESS] notification in [method Object._notification].
[b]Note:[/b] This method is only called if the node is present in the scene tree (i.e. if it's not an orphan).
</description>
@ -83,6 +84,7 @@
<description>
Called during the processing step of the main loop. Processing happens at every frame and as fast as possible, so the [param delta] time since the previous frame is not constant. [param delta] is in seconds.
It is only called if processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process].
Processing happens in order of [member process_priority], lower priority values are called first. Nodes with the same priority are processed in tree order, or top to bottom as seen in the editor (also known as pre-order traversal).
Corresponds to the [constant NOTIFICATION_PROCESS] notification in [method Object._notification].
[b]Note:[/b] This method is only called if the node is present in the scene tree (i.e. if it's not an orphan).
</description>
@ -1015,10 +1017,10 @@
The node's processing behavior (see [enum ProcessMode]). To check if the node can process in its current mode, use [method can_process].
</member>
<member name="process_physics_priority" type="int" setter="set_physics_process_priority" getter="get_physics_process_priority" default="0">
Similar to [member process_priority] but for [constant NOTIFICATION_PHYSICS_PROCESS], [method _physics_process] or the internal version.
Similar to [member process_priority] but for [constant NOTIFICATION_PHYSICS_PROCESS], [method _physics_process], or [constant NOTIFICATION_INTERNAL_PHYSICS_PROCESS].
</member>
<member name="process_priority" type="int" setter="set_process_priority" getter="get_process_priority" default="0">
The node's execution order of the process callbacks ([method _process], [method _physics_process], and internal processing). Nodes whose priority value is [i]lower[/i] call their process callbacks first, regardless of tree order.
The node's execution order of the process callbacks ([method _process], [constant NOTIFICATION_PROCESS], and [constant NOTIFICATION_INTERNAL_PROCESS]). Nodes whose priority value is [i]lower[/i] call their process callbacks first, regardless of tree order.
</member>
<member name="process_thread_group" type="int" setter="set_process_thread_group" getter="get_process_thread_group" enum="Node.ProcessThreadGroup" default="0">
Set the process thread group for this node (basically, whether it receives [constant NOTIFICATION_PROCESS], [constant NOTIFICATION_PHYSICS_PROCESS], [method _process] or [method _physics_process] (and the internal versions) on the main thread or in a sub-thread.

View File

@ -526,6 +526,12 @@
[b]Note:[/b] Thread IDs are not deterministic and may be reused across application restarts.
</description>
</method>
<method name="get_tmp_dir" qualifiers="const">
<return type="String" />
<description>
Returns the [i]global[/i] temporary data directory according to the operating system's standards.
</description>
</method>
<method name="get_unique_id" qualifiers="const">
<return type="String" />
<description>

View File

@ -875,6 +875,10 @@
[b]Note:[/b] Certain window managers can be configured to ignore the non-resizable status of a window. Do not rely on this setting as a guarantee that the window will [i]never[/i] be resizable.
[b]Note:[/b] This setting is ignored on iOS.
</member>
<member name="display/window/size/sharp_corners" type="bool" setter="" getter="" default="false">
If [code]true[/code], the main window uses sharp corners by default.
[b]Note:[/b] This property is implemented only on Windows (11).
</member>
<member name="display/window/size/transparent" type="bool" setter="" getter="" default="false">
If [code]true[/code], enables a window manager hint that the main window background [i]can[/i] be transparent. This does not make the background actually transparent. For the background to be transparent, the root viewport must also be made transparent by enabling [member rendering/viewport/transparent_background].
[b]Note:[/b] To use a transparent splash screen, set [member application/boot_splash/bg_color] to [code]Color(0, 0, 0, 0)[/code].

View File

@ -35,6 +35,12 @@
If argument [param get_groups] is true, parameter grouping hints will be provided.
</description>
</method>
<method name="inspect_native_shader_code">
<return type="void" />
<description>
Only available when running in the editor. Opens a popup that visualizes the generated shader code, including all variants and internal shader code. See also [method Material.inspect_native_shader_code].
</description>
</method>
<method name="set_default_texture_parameter">
<return type="void" />
<param index="0" name="name" type="StringName" />

View File

@ -509,6 +509,12 @@
<theme_item name="font_disabled_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 0.5)">
Text [Color] for a [constant TreeItem.CELL_MODE_CHECK] mode cell when it's non-editable (see [method TreeItem.set_editable]).
</theme_item>
<theme_item name="font_hovered_color" data_type="color" type="Color" default="Color(0.95, 0.95, 0.95, 1)">
Text [Color] used when the item is hovered.
</theme_item>
<theme_item name="font_hovered_dimmed_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)">
Text [Color] used when the item is hovered, while a button of the same item is hovered as the same time.
</theme_item>
<theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)">
The tint of text outline of the item.
</theme_item>
@ -645,6 +651,9 @@
<theme_item name="updown" data_type="icon" type="Texture2D">
The updown arrow icon to display for the [constant TreeItem.CELL_MODE_RANGE] mode cell.
</theme_item>
<theme_item name="button_hover" data_type="style" type="StyleBox">
[StyleBox] used when a button in the tree is hovered.
</theme_item>
<theme_item name="button_pressed" data_type="style" type="StyleBox">
[StyleBox] used when a button in the tree is pressed.
</theme_item>
@ -666,6 +675,12 @@
<theme_item name="focus" data_type="style" type="StyleBox">
The focused style for the [Tree], drawn on top of everything.
</theme_item>
<theme_item name="hovered" data_type="style" type="StyleBox">
[StyleBox] for the item being hovered.
</theme_item>
<theme_item name="hovered_dimmed" data_type="style" type="StyleBox">
[StyleBox] for the item being hovered, while a button of the same item is hovered as the same time.
</theme_item>
<theme_item name="panel" data_type="style" type="StyleBox">
The background style for the [Tree].
</theme_item>

View File

@ -659,6 +659,11 @@
If [member ProjectSettings.display/window/subwindows/embed_subwindows] is [code]false[/code], the position is in absolute screen coordinates. This typically applies to editor plugins. If the setting is [code]true[/code], the window's position is in the coordinates of its parent [Viewport].
[b]Note:[/b] This property only works if [member initial_position] is set to [constant WINDOW_INITIAL_POSITION_ABSOLUTE].
</member>
<member name="sharp_corners" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], the [Window] will override the OS window style to display sharp corners.
[b]Note:[/b] This property is implemented only on Windows (11).
[b]Note:[/b] This property only works with native windows.
</member>
<member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i(100, 100)">
The window's size in pixels.
</member>
@ -842,7 +847,12 @@
All mouse events are passed to the underlying window of the same application.
[b]Note:[/b] This flag has no effect in embedded windows.
</constant>
<constant name="FLAG_MAX" value="8" enum="Flags">
<constant name="FLAG_SHARP_CORNERS" value="8" enum="Flags">
Window style is overridden, forcing sharp corners.
[b]Note:[/b] This flag has no effect in embedded windows.
[b]Note:[/b] This flag is implemented only on Windows (11).
</constant>
<constant name="FLAG_MAX" value="9" enum="Flags">
Max value of the [enum Flags].
</constant>
<constant name="CONTENT_SCALE_MODE_DISABLED" value="0" enum="ContentScaleMode">
@ -878,7 +888,7 @@
<constant name="LAYOUT_DIRECTION_INHERITED" value="0" enum="LayoutDirection">
Automatic layout direction, determined from the parent window layout direction.
</constant>
<constant name="LAYOUT_DIRECTION_LOCALE" value="1" enum="LayoutDirection">
<constant name="LAYOUT_DIRECTION_APPLICATION_LOCALE" value="1" enum="LayoutDirection">
Automatic layout direction, determined from the current locale.
</constant>
<constant name="LAYOUT_DIRECTION_LTR" value="2" enum="LayoutDirection">
@ -887,6 +897,14 @@
<constant name="LAYOUT_DIRECTION_RTL" value="3" enum="LayoutDirection">
Right-to-left layout direction.
</constant>
<constant name="LAYOUT_DIRECTION_SYSTEM_LOCALE" value="4" enum="LayoutDirection">
Automatic layout direction, determined from the system locale.
</constant>
<constant name="LAYOUT_DIRECTION_MAX" value="5" enum="LayoutDirection">
Represents the size of the [enum LayoutDirection] enum.
</constant>
<constant name="LAYOUT_DIRECTION_LOCALE" value="1" enum="LayoutDirection" deprecated="Use [constant LAYOUT_DIRECTION_APPLICATION_LOCALE] instead.">
</constant>
<constant name="WINDOW_INITIAL_POSITION_ABSOLUTE" value="0" enum="WindowInitialPosition">
Initial window position is determined by [member position].
</constant>

View File

@ -2003,6 +2003,8 @@ static D3D12_BARRIER_LAYOUT _rd_texture_layout_to_d3d12_barrier_layout(RDD::Text
switch (p_texture_layout) {
case RDD::TEXTURE_LAYOUT_UNDEFINED:
return D3D12_BARRIER_LAYOUT_UNDEFINED;
case RDD::TEXTURE_LAYOUT_GENERAL:
return D3D12_BARRIER_LAYOUT_COMMON;
case RDD::TEXTURE_LAYOUT_STORAGE_OPTIMAL:
return D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS;
case RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
@ -6175,6 +6177,8 @@ uint64_t RenderingDeviceDriverD3D12::api_trait_get(ApiTrait p_trait) {
return false;
case API_TRAIT_CLEARS_WITH_COPY_ENGINE:
return false;
case API_TRAIT_USE_GENERAL_IN_COPY_QUEUES:
return true;
default:
return RenderingDeviceDriver::api_trait_get(p_trait);
}

View File

@ -35,6 +35,7 @@
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "core/io/image.h"
#include "core/os/os.h"
#include "storage/texture_storage.h"

View File

@ -230,6 +230,32 @@ TextureStorage::TextureStorage() {
sdf_shader.shader_version = sdf_shader.shader.version_create();
}
// Initialize texture placeholder data for the `texture_*_placeholder_initialize()` methods.
constexpr int placeholder_size = 4;
texture_2d_placeholder = Image::create_empty(placeholder_size, placeholder_size, false, Image::FORMAT_RGBA8);
// Draw a magenta/black checkerboard pattern.
for (int i = 0; i < placeholder_size * placeholder_size; i++) {
const int x = i % placeholder_size;
const int y = i / placeholder_size;
texture_2d_placeholder->set_pixel(x, y, (x + y) % 2 == 0 ? Color(1, 0, 1) : Color(0, 0, 0));
}
texture_2d_array_placeholder.push_back(texture_2d_placeholder);
for (int i = 0; i < 6; i++) {
cubemap_placeholder.push_back(texture_2d_placeholder);
}
Ref<Image> texture_2d_placeholder_rotated;
texture_2d_placeholder_rotated.instantiate();
texture_2d_placeholder_rotated->copy_from(texture_2d_placeholder);
texture_2d_placeholder_rotated->rotate_90(CLOCKWISE);
for (int i = 0; i < 4; i++) {
// Alternate checkerboard pattern on odd layers (by using a copy that is rotated 90 degrees).
texture_3d_placeholder.push_back(i % 2 == 0 ? texture_2d_placeholder : texture_2d_placeholder_rotated);
}
#ifdef GL_API_ENABLED
if (RasterizerGLES3::is_gles_over_gl()) {
glEnable(GL_PROGRAM_POINT_SIZE);
@ -1014,46 +1040,19 @@ void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) {
}
void TextureStorage::texture_2d_placeholder_initialize(RID p_texture) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
image->fill(Color(1, 0, 1, 1));
texture_2d_initialize(p_texture, image);
texture_2d_initialize(p_texture, texture_2d_placeholder);
}
void TextureStorage::texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
image->fill(Color(1, 0, 1, 1));
Vector<Ref<Image>> images;
void TextureStorage::texture_2d_layered_placeholder_initialize(RID p_texture, RS::TextureLayeredType p_layered_type) {
if (p_layered_type == RS::TEXTURE_LAYERED_2D_ARRAY) {
images.push_back(image);
texture_2d_layered_initialize(p_texture, texture_2d_array_placeholder, p_layered_type);
} else {
//cube
for (int i = 0; i < 6; i++) {
images.push_back(image);
}
texture_2d_layered_initialize(p_texture, cubemap_placeholder, p_layered_type);
}
texture_2d_layered_initialize(p_texture, images, p_layered_type);
}
void TextureStorage::texture_3d_placeholder_initialize(RID p_texture) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
image->fill(Color(1, 0, 1, 1));
Vector<Ref<Image>> images;
//cube
for (int i = 0; i < 4; i++) {
images.push_back(image);
}
texture_3d_initialize(p_texture, Image::FORMAT_RGBA8, 4, 4, 4, false, images);
texture_3d_initialize(p_texture, Image::FORMAT_RGBA8, 4, 4, 4, false, texture_3d_placeholder);
}
Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {

View File

@ -36,6 +36,7 @@
#include "platform_gl.h"
#include "config.h"
#include "core/io/image.h"
#include "core/os/os.h"
#include "core/templates/rid_owner.h"
#include "servers/rendering/renderer_compositor.h"
@ -521,6 +522,11 @@ public:
virtual void texture_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override;
virtual void texture_proxy_update(RID p_proxy, RID p_base) override;
Ref<Image> texture_2d_placeholder;
Vector<Ref<Image>> texture_2d_array_placeholder;
Vector<Ref<Image>> cubemap_placeholder;
Vector<Ref<Image>> texture_3d_placeholder;
//these two APIs can be used together or in combination with the others.
virtual void texture_2d_placeholder_initialize(RID p_texture) override;
virtual void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) override;

View File

@ -96,6 +96,22 @@ _FORCE_INLINE_ ShaderStageUsage &operator|=(ShaderStageUsage &p_a, int p_b) {
return p_a;
}
enum StageResourceUsage : uint32_t {
VertexRead = (MTLResourceUsageRead << RDD::SHADER_STAGE_VERTEX * 2),
VertexWrite = (MTLResourceUsageWrite << RDD::SHADER_STAGE_VERTEX * 2),
FragmentRead = (MTLResourceUsageRead << RDD::SHADER_STAGE_FRAGMENT * 2),
FragmentWrite = (MTLResourceUsageWrite << RDD::SHADER_STAGE_FRAGMENT * 2),
TesselationControlRead = (MTLResourceUsageRead << RDD::SHADER_STAGE_TESSELATION_CONTROL * 2),
TesselationControlWrite = (MTLResourceUsageWrite << RDD::SHADER_STAGE_TESSELATION_CONTROL * 2),
TesselationEvaluationRead = (MTLResourceUsageRead << RDD::SHADER_STAGE_TESSELATION_EVALUATION * 2),
TesselationEvaluationWrite = (MTLResourceUsageWrite << RDD::SHADER_STAGE_TESSELATION_EVALUATION * 2),
ComputeRead = (MTLResourceUsageRead << RDD::SHADER_STAGE_COMPUTE * 2),
ComputeWrite = (MTLResourceUsageWrite << RDD::SHADER_STAGE_COMPUTE * 2),
};
typedef LocalVector<__unsafe_unretained id<MTLResource>> ResourceVector;
typedef HashMap<StageResourceUsage, ResourceVector> ResourceUsageMap;
enum class MDCommandBufferStateType {
None,
Render,
@ -230,6 +246,7 @@ public:
uint32_t index_offset = 0;
LocalVector<id<MTLBuffer> __unsafe_unretained> vertex_buffers;
LocalVector<NSUInteger> vertex_offsets;
ResourceUsageMap resource_usage;
// clang-format off
enum DirtyFlag: uint8_t {
DIRTY_NONE = 0b0000'0000,
@ -271,8 +288,14 @@ public:
blend_constants.reset();
vertex_buffers.clear();
vertex_offsets.clear();
// Keep the keys, as they are likely to be used again.
for (KeyValue<StageResourceUsage, LocalVector<__unsafe_unretained id<MTLResource>>> &kv : resource_usage) {
kv.value.clear();
}
}
void end_encoding();
_FORCE_INLINE_ void mark_viewport_dirty() {
if (viewports.is_empty()) {
return;
@ -356,13 +379,20 @@ public:
} render;
// State specific for a compute pass.
struct {
struct ComputeState {
MDComputePipeline *pipeline = nullptr;
id<MTLComputeCommandEncoder> encoder = nil;
ResourceUsageMap resource_usage;
_FORCE_INLINE_ void reset() {
pipeline = nil;
encoder = nil;
// Keep the keys, as they are likely to be used again.
for (KeyValue<StageResourceUsage, LocalVector<__unsafe_unretained id<MTLResource>>> &kv : resource_usage) {
kv.value.clear();
}
}
void end_encoding();
} compute;
// State specific to a blit pass.
@ -632,19 +662,6 @@ public:
MDRenderShader(CharString p_name, Vector<UniformSet> p_sets, MDLibrary *p_vert, MDLibrary *p_frag);
};
enum StageResourceUsage : uint32_t {
VertexRead = (MTLResourceUsageRead << RDD::SHADER_STAGE_VERTEX * 2),
VertexWrite = (MTLResourceUsageWrite << RDD::SHADER_STAGE_VERTEX * 2),
FragmentRead = (MTLResourceUsageRead << RDD::SHADER_STAGE_FRAGMENT * 2),
FragmentWrite = (MTLResourceUsageWrite << RDD::SHADER_STAGE_FRAGMENT * 2),
TesselationControlRead = (MTLResourceUsageRead << RDD::SHADER_STAGE_TESSELATION_CONTROL * 2),
TesselationControlWrite = (MTLResourceUsageWrite << RDD::SHADER_STAGE_TESSELATION_CONTROL * 2),
TesselationEvaluationRead = (MTLResourceUsageRead << RDD::SHADER_STAGE_TESSELATION_EVALUATION * 2),
TesselationEvaluationWrite = (MTLResourceUsageWrite << RDD::SHADER_STAGE_TESSELATION_EVALUATION * 2),
ComputeRead = (MTLResourceUsageRead << RDD::SHADER_STAGE_COMPUTE * 2),
ComputeWrite = (MTLResourceUsageWrite << RDD::SHADER_STAGE_COMPUTE * 2),
};
_FORCE_INLINE_ StageResourceUsage &operator|=(StageResourceUsage &p_a, uint32_t p_b) {
p_a = StageResourceUsage(uint32_t(p_a) | p_b);
return p_a;
@ -667,7 +684,13 @@ struct HashMapComparatorDefault<RDD::ShaderID> {
struct BoundUniformSet {
id<MTLBuffer> buffer;
HashMap<id<MTLResource>, StageResourceUsage> bound_resources;
ResourceUsageMap usage_to_resources;
/// Perform a 2-way merge each key of `ResourceVector` resources from this set into the
/// destination set.
///
/// Assumes the vectors of resources are sorted.
void merge_into(ResourceUsageMap &p_dst) const;
};
class API_AVAILABLE(macos(11.0), ios(14.0)) MDUniformSet {

View File

@ -58,7 +58,7 @@
void MDCommandBuffer::begin() {
DEV_ASSERT(commandBuffer == nil);
commandBuffer = queue.commandBuffer;
commandBuffer = queue.commandBufferWithUnretainedReferences;
}
void MDCommandBuffer::end() {
@ -390,6 +390,38 @@ void MDCommandBuffer::render_set_blend_constants(const Color &p_constants) {
}
}
void BoundUniformSet::merge_into(ResourceUsageMap &p_dst) const {
for (KeyValue<StageResourceUsage, ResourceVector> const &keyval : usage_to_resources) {
ResourceVector *resources = p_dst.getptr(keyval.key);
if (resources == nullptr) {
resources = &p_dst.insert(keyval.key, ResourceVector())->value;
}
// Reserve space for the new resources, assuming they are all added.
resources->reserve(resources->size() + keyval.value.size());
uint32_t i = 0, j = 0;
__unsafe_unretained id<MTLResource> *resources_ptr = resources->ptr();
const __unsafe_unretained id<MTLResource> *keyval_ptr = keyval.value.ptr();
// 2-way merge.
while (i < resources->size() && j < keyval.value.size()) {
if (resources_ptr[i] < keyval_ptr[j]) {
i++;
} else if (resources_ptr[i] > keyval_ptr[j]) {
resources->insert(i, keyval_ptr[j]);
i++;
j++;
} else {
i++;
j++;
}
}
// Append the remaining resources.
for (; j < keyval.value.size(); j++) {
resources->push_back(keyval_ptr[j]);
}
}
}
void MDCommandBuffer::_render_bind_uniform_sets() {
DEV_ASSERT(type == MDCommandBufferStateType::Render);
if (!render.dirty.has_flag(RenderState::DIRTY_UNIFORMS)) {
@ -408,7 +440,7 @@ void MDCommandBuffer::_render_bind_uniform_sets() {
// Find the index of the next set bit.
int index = __builtin_ctzll(set_uniforms);
// Clear the set bit.
set_uniforms &= ~(1ULL << index);
set_uniforms &= (set_uniforms - 1);
MDUniformSet *set = render.uniform_sets[index];
if (set == nullptr || set->index >= (uint32_t)shader->sets.size()) {
continue;
@ -416,17 +448,7 @@ void MDCommandBuffer::_render_bind_uniform_sets() {
UniformSet const &set_info = shader->sets[set->index];
BoundUniformSet &bus = set->boundUniformSetForShader(shader, device);
for (KeyValue<id<MTLResource>, StageResourceUsage> const &keyval : bus.bound_resources) {
MTLResourceUsage usage = resource_usage_for_stage(keyval.value, RDD::ShaderStage::SHADER_STAGE_VERTEX);
if (usage != 0) {
[enc useResource:keyval.key usage:usage stages:MTLRenderStageVertex];
}
usage = resource_usage_for_stage(keyval.value, RDD::ShaderStage::SHADER_STAGE_FRAGMENT);
if (usage != 0) {
[enc useResource:keyval.key usage:usage stages:MTLRenderStageFragment];
}
}
bus.merge_into(render.resource_usage);
// Set the buffer for the vertex stage.
{
@ -545,8 +567,7 @@ void MDCommandBuffer::_end_render_pass() {
// see: https://github.com/KhronosGroup/MoltenVK/blob/d20d13fe2735adb845636a81522df1b9d89c0fba/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm#L407
}
[render.encoder endEncoding];
render.encoder = nil;
render.end_encoding();
}
void MDCommandBuffer::_render_clear_render_area() {
@ -792,10 +813,59 @@ void MDCommandBuffer::render_draw_indirect_count(RDD::BufferID p_indirect_buffer
ERR_FAIL_MSG("not implemented");
}
void MDCommandBuffer::RenderState::end_encoding() {
if (encoder == nil) {
return;
}
// Bind all resources.
for (KeyValue<StageResourceUsage, ResourceVector> const &keyval : resource_usage) {
if (keyval.value.is_empty()) {
continue;
}
MTLResourceUsage vert_usage = resource_usage_for_stage(keyval.key, RDD::ShaderStage::SHADER_STAGE_VERTEX);
MTLResourceUsage frag_usage = resource_usage_for_stage(keyval.key, RDD::ShaderStage::SHADER_STAGE_FRAGMENT);
if (vert_usage == frag_usage) {
[encoder useResources:keyval.value.ptr() count:keyval.value.size() usage:vert_usage stages:MTLRenderStageVertex | MTLRenderStageFragment];
} else {
if (vert_usage != 0) {
[encoder useResources:keyval.value.ptr() count:keyval.value.size() usage:vert_usage stages:MTLRenderStageVertex];
}
if (frag_usage != 0) {
[encoder useResources:keyval.value.ptr() count:keyval.value.size() usage:frag_usage stages:MTLRenderStageFragment];
}
}
}
[encoder endEncoding];
encoder = nil;
}
void MDCommandBuffer::ComputeState::end_encoding() {
if (encoder == nil) {
return;
}
// Bind all resources.
for (KeyValue<StageResourceUsage, ResourceVector> const &keyval : resource_usage) {
if (keyval.value.is_empty()) {
continue;
}
MTLResourceUsage usage = resource_usage_for_stage(keyval.key, RDD::ShaderStage::SHADER_STAGE_COMPUTE);
if (usage != 0) {
[encoder useResources:keyval.value.ptr() count:keyval.value.size() usage:usage];
}
}
[encoder endEncoding];
encoder = nil;
}
void MDCommandBuffer::render_end_pass() {
DEV_ASSERT(type == MDCommandBufferStateType::Render);
[render.encoder endEncoding];
render.end_encoding();
render.reset();
type = MDCommandBufferStateType::None;
}
@ -813,13 +883,7 @@ void MDCommandBuffer::compute_bind_uniform_set(RDD::UniformSetID p_uniform_set,
MDUniformSet *set = (MDUniformSet *)(p_uniform_set.id);
BoundUniformSet &bus = set->boundUniformSetForShader(shader, device);
for (KeyValue<id<MTLResource>, StageResourceUsage> &keyval : bus.bound_resources) {
MTLResourceUsage usage = resource_usage_for_stage(keyval.value, RDD::ShaderStage::SHADER_STAGE_COMPUTE);
if (usage != 0) {
[enc useResource:keyval.key usage:usage];
}
}
bus.merge_into(compute.resource_usage);
uint32_t const *offset = set_info.offsets.getptr(RDD::SHADER_STAGE_COMPUTE);
if (offset) {
@ -848,7 +912,7 @@ void MDCommandBuffer::compute_dispatch_indirect(RDD::BufferID p_indirect_buffer,
void MDCommandBuffer::_end_compute_dispatch() {
DEV_ASSERT(type == MDCommandBufferStateType::Compute);
[compute.encoder endEncoding];
compute.end_encoding();
compute.reset();
type = MDCommandBufferStateType::None;
}
@ -1052,7 +1116,20 @@ BoundUniformSet &MDUniformSet::boundUniformSetForShader(MDShader *p_shader, id<M
}
}
BoundUniformSet bs = { .buffer = enc_buffer, .bound_resources = bound_resources };
SearchArray<__unsafe_unretained id<MTLResource>> search;
ResourceUsageMap usage_to_resources;
for (KeyValue<id<MTLResource>, StageResourceUsage> const &keyval : bound_resources) {
ResourceVector *resources = usage_to_resources.getptr(keyval.value);
if (resources == nullptr) {
resources = &usage_to_resources.insert(keyval.value, ResourceVector())->value;
}
int64_t pos = search.bisect(resources->ptr(), resources->size(), keyval.key, true);
if (pos == resources->size() || (*resources)[pos] != keyval.key) {
resources->insert(pos, keyval.key);
}
}
BoundUniformSet bs = { .buffer = enc_buffer, .usage_to_resources = usage_to_resources };
bound_uniforms.insert(p_shader, bs);
return bound_uniforms.get(p_shader);
}
@ -1211,8 +1288,7 @@ vertex VaryingsPos vertClear(AttributesPos attributes [[stage_in]], constant Cle
varyings.layer = uint(attributes.a_position.w);
return varyings;
}
)",
ClearAttKey::DEPTH_INDEX];
)", ClearAttKey::DEPTH_INDEX];
return new_func(msl, @"vertClear", nil);
}

View File

@ -2060,6 +2060,10 @@ Vector<uint8_t> RenderingDeviceDriverMetal::shader_compile_binary_from_spirv(Vec
case BT::Sampler: {
primary.dataType = MTLDataTypeSampler;
primary.arrayLength = 1;
for (uint32_t const &a : a_type.array) {
primary.arrayLength *= a;
}
} break;
default: {
@ -2067,7 +2071,7 @@ Vector<uint8_t> RenderingDeviceDriverMetal::shader_compile_binary_from_spirv(Vec
} break;
}
// Find array length.
// Find array length of image.
if (basetype == BT::Image || basetype == BT::SampledImage) {
primary.arrayLength = 1;
for (uint32_t const &a : a_type.array) {

View File

@ -225,6 +225,10 @@ String OS_Unix::get_version() const {
return "";
}
String OS_Unix::get_tmp_path() const {
return "/tmp";
}
double OS_Unix::get_unix_time() const {
struct timeval tv_now;
gettimeofday(&tv_now, nullptr);

View File

@ -72,6 +72,8 @@ public:
virtual String get_distribution_name() const override;
virtual String get_version() const override;
virtual String get_tmp_path() const override;
virtual DateTime get_datetime(bool p_utc) const override;
virtual TimeZoneInfo get_time_zone_info() const override;

View File

@ -266,6 +266,7 @@ static const VkFormat RD_TO_VK_FORMAT[RDD::DATA_FORMAT_MAX] = {
static VkImageLayout RD_TO_VK_LAYOUT[RDD::TEXTURE_LAYOUT_MAX] = {
VK_IMAGE_LAYOUT_UNDEFINED, // TEXTURE_LAYOUT_UNDEFINED
VK_IMAGE_LAYOUT_GENERAL, // TEXTURE_LAYOUT_GENERAL
VK_IMAGE_LAYOUT_GENERAL, // TEXTURE_LAYOUT_STORAGE_OPTIMAL
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
@ -2636,11 +2637,13 @@ bool RenderingDeviceDriverVulkan::command_buffer_begin(CommandBufferID p_cmd_buf
bool RenderingDeviceDriverVulkan::command_buffer_begin_secondary(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, uint32_t p_subpass, FramebufferID p_framebuffer) {
// Reset is implicit (VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT).
Framebuffer *framebuffer = (Framebuffer *)(p_framebuffer.id);
VkCommandBufferInheritanceInfo inheritance_info = {};
inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
inheritance_info.renderPass = (VkRenderPass)p_render_pass.id;
inheritance_info.subpass = p_subpass;
inheritance_info.framebuffer = (VkFramebuffer)p_framebuffer.id;
inheritance_info.framebuffer = framebuffer->vk_framebuffer;
VkCommandBufferBeginInfo cmd_buf_begin_info = {};
cmd_buf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
@ -2950,12 +2953,16 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue,
fb_create_info.height = surface->height;
fb_create_info.layers = 1;
VkFramebuffer framebuffer;
VkFramebuffer vk_framebuffer;
for (uint32_t i = 0; i < image_count; i++) {
fb_create_info.pAttachments = &swap_chain->image_views[i];
err = vkCreateFramebuffer(vk_device, &fb_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_FRAMEBUFFER), &framebuffer);
err = vkCreateFramebuffer(vk_device, &fb_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_FRAMEBUFFER), &vk_framebuffer);
ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE);
Framebuffer *framebuffer = memnew(Framebuffer);
framebuffer->vk_framebuffer = vk_framebuffer;
framebuffer->swap_chain_image = swap_chain->images[i];
framebuffer->swap_chain_image_subresource_range = view_create_info.subresourceRange;
swap_chain->framebuffers.push_back(RDD::FramebufferID(framebuffer));
}
@ -3024,7 +3031,10 @@ RDD::FramebufferID RenderingDeviceDriverVulkan::swap_chain_acquire_framebuffer(C
command_queue->pending_semaphores_for_fence.push_back(semaphore_index);
// Return the corresponding framebuffer to the new current image.
return swap_chain->framebuffers[swap_chain->image_index];
FramebufferID framebuffer_id = swap_chain->framebuffers[swap_chain->image_index];
Framebuffer *framebuffer = (Framebuffer *)(framebuffer_id.id);
framebuffer->swap_chain_acquired = true;
return framebuffer_id;
}
RDD::RenderPassID RenderingDeviceDriverVulkan::swap_chain_get_render_pass(SwapChainID p_swap_chain) {
@ -3093,11 +3103,15 @@ RDD::FramebufferID RenderingDeviceDriverVulkan::framebuffer_create(RenderPassID
}
#endif
return FramebufferID(vk_framebuffer);
Framebuffer *framebuffer = memnew(Framebuffer);
framebuffer->vk_framebuffer = vk_framebuffer;
return FramebufferID(framebuffer);
}
void RenderingDeviceDriverVulkan::framebuffer_free(FramebufferID p_framebuffer) {
vkDestroyFramebuffer(vk_device, (VkFramebuffer)p_framebuffer.id, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_FRAMEBUFFER));
Framebuffer *framebuffer = (Framebuffer *)(p_framebuffer.id);
vkDestroyFramebuffer(vk_device, framebuffer->vk_framebuffer, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_FRAMEBUFFER));
memdelete(framebuffer);
}
/****************/
@ -4315,10 +4329,25 @@ void RenderingDeviceDriverVulkan::render_pass_free(RenderPassID p_render_pass) {
static_assert(ARRAYS_COMPATIBLE_FIELDWISE(RDD::RenderPassClearValue, VkClearValue));
void RenderingDeviceDriverVulkan::command_begin_render_pass(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, FramebufferID p_framebuffer, CommandBufferType p_cmd_buffer_type, const Rect2i &p_rect, VectorView<RenderPassClearValue> p_clear_values) {
Framebuffer *framebuffer = (Framebuffer *)(p_framebuffer.id);
if (framebuffer->swap_chain_acquired) {
// Insert a barrier to wait for the acquisition of the framebuffer before the render pass begins.
VkImageMemoryBarrier image_barrier = {};
image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
image_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
image_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_barrier.image = framebuffer->swap_chain_image;
image_barrier.subresourceRange = framebuffer->swap_chain_image_subresource_range;
vkCmdPipelineBarrier((VkCommandBuffer)p_cmd_buffer.id, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_barrier);
framebuffer->swap_chain_acquired = false;
}
VkRenderPassBeginInfo render_pass_begin = {};
render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_begin.renderPass = (VkRenderPass)p_render_pass.id;
render_pass_begin.framebuffer = (VkFramebuffer)p_framebuffer.id;
render_pass_begin.framebuffer = framebuffer->vk_framebuffer;
render_pass_begin.renderArea.offset.x = p_rect.position.x;
render_pass_begin.renderArea.offset.y = p_rect.position.y;

View File

@ -366,6 +366,15 @@ public:
/**** FRAMEBUFFER ****/
/*********************/
struct Framebuffer {
VkFramebuffer vk_framebuffer = VK_NULL_HANDLE;
// Only filled in by a framebuffer created by a swap chain. Unused otherwise.
VkImage swap_chain_image = VK_NULL_HANDLE;
VkImageSubresourceRange swap_chain_image_subresource_range = {};
bool swap_chain_acquired = false;
};
virtual FramebufferID framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height) override final;
virtual void framebuffer_free(FramebufferID p_framebuffer) override final;

View File

@ -30,6 +30,7 @@
#include "editor_profiler.h"
#include "core/io/image.h"
#include "core/os/os.h"
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"

View File

@ -30,6 +30,7 @@
#include "editor_visual_profiler.h"
#include "core/io/image.h"
#include "core/os/os.h"
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"

View File

@ -248,11 +248,16 @@ void EditorFileSystem::_first_scan_filesystem() {
ep.step(TTR("Scanning file structure..."), 0, true);
nb_files_total = _scan_new_dir(first_scan_root_dir, d);
// Preloading GDExtensions file extensions to prevent looping on all the resource loaders
// for each files in _first_scan_process_scripts.
List<String> gdextension_extensions;
ResourceLoader::get_recognized_extensions_for_type("GDExtension", &gdextension_extensions);
// This loads the global class names from the scripts and ensures that even if the
// global_script_class_cache.cfg was missing or invalid, the global class names are valid in ScriptServer.
// At the same time, to prevent looping multiple times in all files, it looks for extensions.
ep.step(TTR("Loading global class names..."), 1, true);
_first_scan_process_scripts(first_scan_root_dir, existing_class_names, extensions);
_first_scan_process_scripts(first_scan_root_dir, gdextension_extensions, existing_class_names, extensions);
// Removing invalid global class to prevent having invalid paths in ScriptServer.
_remove_invalid_global_class_names(existing_class_names);
@ -276,16 +281,16 @@ void EditorFileSystem::_first_scan_filesystem() {
ep.step(TTR("Starting file scan..."), 5, true);
}
void EditorFileSystem::_first_scan_process_scripts(const ScannedDirectory *p_scan_dir, HashSet<String> &p_existing_class_names, HashSet<String> &p_extensions) {
void EditorFileSystem::_first_scan_process_scripts(const ScannedDirectory *p_scan_dir, List<String> &p_gdextension_extensions, HashSet<String> &p_existing_class_names, HashSet<String> &p_extensions) {
for (ScannedDirectory *scan_sub_dir : p_scan_dir->subdirs) {
_first_scan_process_scripts(scan_sub_dir, p_existing_class_names, p_extensions);
_first_scan_process_scripts(scan_sub_dir, p_gdextension_extensions, p_existing_class_names, p_extensions);
}
for (const String &scan_file : p_scan_dir->files) {
// Optimization to skip the ResourceLoader::get_resource_type for files
// that are not scripts. Some loader get_resource_type methods read the file
// which can be very slow on large projects.
String ext = scan_file.get_extension().to_lower();
const String ext = scan_file.get_extension().to_lower();
bool is_script = false;
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
if (ScriptServer::get_language(i)->get_extension() == ext) {
@ -293,24 +298,29 @@ void EditorFileSystem::_first_scan_process_scripts(const ScannedDirectory *p_sca
break;
}
}
if (!is_script) {
continue; // Not a script.
if (is_script) {
const String path = p_scan_dir->full_path.path_join(scan_file);
const String type = ResourceLoader::get_resource_type(path);
if (ClassDB::is_parent_class(type, SNAME("Script"))) {
String script_class_extends;
String script_class_icon_path;
String script_class_name = _get_global_script_class(type, path, &script_class_extends, &script_class_icon_path);
_register_global_class_script(path, path, type, script_class_name, script_class_extends, script_class_icon_path);
if (!script_class_name.is_empty()) {
p_existing_class_names.insert(script_class_name);
}
}
}
String path = p_scan_dir->full_path.path_join(scan_file);
String type = ResourceLoader::get_resource_type(path);
if (ClassDB::is_parent_class(type, SNAME("Script"))) {
String script_class_extends;
String script_class_icon_path;
String script_class_name = _get_global_script_class(type, path, &script_class_extends, &script_class_icon_path);
_register_global_class_script(path, path, type, script_class_name, script_class_extends, script_class_icon_path);
if (!script_class_name.is_empty()) {
p_existing_class_names.insert(script_class_name);
// Check for GDExtensions.
if (p_gdextension_extensions.find(ext)) {
const String path = p_scan_dir->full_path.path_join(scan_file);
const String type = ResourceLoader::get_resource_type(path);
if (type == SNAME("GDExtension")) {
p_extensions.insert(path);
}
} else if (type == SNAME("GDExtension")) {
p_extensions.insert(path);
}
}
}

View File

@ -191,7 +191,7 @@ class EditorFileSystem : public Node {
void _scan_filesystem();
void _first_scan_filesystem();
void _first_scan_process_scripts(const ScannedDirectory *p_scan_dir, HashSet<String> &p_existing_class_names, HashSet<String> &p_extensions);
void _first_scan_process_scripts(const ScannedDirectory *p_scan_dir, List<String> &p_gdextension_extensions, HashSet<String> &p_existing_class_names, HashSet<String> &p_extensions);
HashSet<String> late_update_files;

View File

@ -35,6 +35,7 @@
#include "core/input/input.h"
#include "core/io/config_file.h"
#include "core/io/file_access.h"
#include "core/io/image.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/object/class_db.h"

View File

@ -54,6 +54,10 @@ String EditorPaths::get_cache_dir() const {
return cache_dir;
}
String EditorPaths::get_tmp_dir() const {
return tmp_dir;
}
String EditorPaths::get_project_data_dir() const {
return project_data_dir;
}
@ -160,6 +164,7 @@ EditorPaths::EditorPaths() {
config_dir = data_dir;
cache_path = exe_path;
cache_dir = data_dir.path_join("cache");
tmp_dir = data_dir.path_join("tmp");
} else {
// Typically XDG_DATA_HOME or %APPDATA%.
data_path = OS::get_singleton()->get_data_path();
@ -174,6 +179,7 @@ EditorPaths::EditorPaths() {
} else {
cache_dir = cache_path.path_join(OS::get_singleton()->get_godot_dir_name());
}
tmp_dir = OS::get_singleton()->get_tmp_path();
}
paths_valid = (!data_path.is_empty() && !config_path.is_empty() && !cache_path.is_empty());

View File

@ -42,6 +42,7 @@ class EditorPaths : public Object {
String data_dir; // Editor data (templates, shader cache, etc.).
String config_dir; // Editor config (settings, profiles, themes, etc.).
String cache_dir; // Editor cache (thumbnails, tmp generated files).
String tmp_dir; // Editor temporary directory.
String project_data_dir; // Project-specific data (metadata, shader cache, etc.).
bool self_contained = false; // Self-contained means everything goes to `editor_data` dir.
String self_contained_file; // Self-contained file with configuration.
@ -61,6 +62,7 @@ public:
String get_data_dir() const;
String get_config_dir() const;
String get_cache_dir() const;
String get_tmp_dir() const;
String get_project_data_dir() const;
String get_export_templates_dir() const;
String get_debug_keystore_path() const;

View File

@ -121,7 +121,7 @@ String EventListenerLineEdit::get_event_text(const Ref<InputEvent> &p_event, boo
}
String EventListenerLineEdit::get_device_string(int p_device) {
if (p_device == InputMap::ALL_DEVICES) {
if (p_device == InputEvent::DEVICE_ID_ALL_DEVICES) {
return TTR("All Devices");
}
return TTR("Device") + " " + itos(p_device);

View File

@ -1355,6 +1355,13 @@ EditorFileDialog::Access EditorFileDialog::get_access() const {
void EditorFileDialog::_make_dir_confirm() {
const String stripped_dirname = makedirname->get_text().strip_edges();
if (stripped_dirname.is_empty()) {
error_dialog->set_text(TTR("The path specified is invalid."));
error_dialog->popup_centered(Size2(250, 50) * EDSCALE);
makedirname->set_text(""); // Reset label.
return;
}
if (dir_access->dir_exists(stripped_dirname)) {
error_dialog->set_text(TTR("Could not create folder. File with that name already exists."));
error_dialog->popup_centered(Size2(250, 50) * EDSCALE);

View File

@ -551,18 +551,18 @@ void InputEventConfigurationDialog::_input_list_item_selected() {
}
void InputEventConfigurationDialog::_device_selection_changed(int p_option_button_index) {
// Subtract 1 as option index 0 corresponds to "All Devices" (value of -1)
// and option index 1 corresponds to device 0, etc...
event->set_device(p_option_button_index - 1);
// Option index 0 corresponds to "All Devices" (value of -3).
// Otherwise subtract 1 as option index 1 corresponds to device 0, etc...
event->set_device(p_option_button_index == 0 ? InputEvent::DEVICE_ID_ALL_DEVICES : p_option_button_index - 1);
event_as_text->set_text(EventListenerLineEdit::get_event_text(event, true));
}
void InputEventConfigurationDialog::_set_current_device(int p_device) {
device_id_option->select(p_device + 1);
device_id_option->select(p_device == InputEvent::DEVICE_ID_ALL_DEVICES ? 0 : p_device + 1);
}
int InputEventConfigurationDialog::_get_current_device() const {
return device_id_option->get_selected() - 1;
return device_id_option->get_selected() == 0 ? InputEvent::DEVICE_ID_ALL_DEVICES : device_id_option->get_selected() - 1;
}
void InputEventConfigurationDialog::_notification(int p_what) {
@ -705,11 +705,12 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() {
device_id_option = memnew(OptionButton);
device_id_option->set_h_size_flags(Control::SIZE_EXPAND_FILL);
for (int i = -1; i < 8; i++) {
device_id_option->add_item(EventListenerLineEdit::get_device_string(InputEvent::DEVICE_ID_ALL_DEVICES));
for (int i = 0; i < 8; i++) {
device_id_option->add_item(EventListenerLineEdit::get_device_string(i));
}
device_id_option->connect(SceneStringName(item_selected), callable_mp(this, &InputEventConfigurationDialog::_device_selection_changed));
_set_current_device(InputMap::ALL_DEVICES);
_set_current_device(InputEvent::DEVICE_ID_ALL_DEVICES);
device_container->add_child(device_id_option);
device_container->hide();

View File

@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/io/file_access_memory.h"
#include "core/io/image.h"
#include "core/io/resource_loader.h"
#include "core/object/script_language.h"
#include "core/os/os.h"

View File

@ -44,7 +44,10 @@ LightmapGIGizmoPlugin::LightmapGIGizmoPlugin() {
Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
// Fade out probes when camera gets too close to them.
mat->set_distance_fade(StandardMaterial3D::DISTANCE_FADE_PIXEL_DITHER);
mat->set_distance_fade_min_distance(0.5);
mat->set_distance_fade_max_distance(1.5);
mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, false);
mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);

View File

@ -396,6 +396,7 @@ void ShaderEditorPlugin::_setup_popup_menu(PopupMenuType p_type, PopupMenu *p_me
if (p_type == FILE) {
p_menu->add_separator();
p_menu->add_item(TTR("Open File in Inspector"), FILE_INSPECT);
p_menu->add_item(TTR("Inspect Native Shader Code..."), FILE_INSPECT_NATIVE_SHADER_CODE);
p_menu->add_separator();
p_menu->add_shortcut(ED_SHORTCUT("shader_editor/close_file", TTR("Close File"), KeyModifierMask::CMD_OR_CTRL | Key::W), FILE_CLOSE);
} else {
@ -554,6 +555,12 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) {
EditorNode::get_singleton()->push_item(edited_shaders[index].shader_inc.ptr());
}
} break;
case FILE_INSPECT_NATIVE_SHADER_CODE: {
int index = shader_tabs->get_current_tab();
if (edited_shaders[index].shader.is_valid()) {
edited_shaders[index].shader->inspect_native_shader_code();
}
} break;
case FILE_CLOSE: {
_close_shader(shader_tabs->get_current_tab());
} break;
@ -754,6 +761,7 @@ void ShaderEditorPlugin::_set_file_specific_items_disabled(bool p_disabled) {
file_popup_menu->set_item_disabled(file_popup_menu->get_item_index(FILE_SAVE), p_disabled);
file_popup_menu->set_item_disabled(file_popup_menu->get_item_index(FILE_SAVE_AS), p_disabled);
file_popup_menu->set_item_disabled(file_popup_menu->get_item_index(FILE_INSPECT), p_disabled);
file_popup_menu->set_item_disabled(file_popup_menu->get_item_index(FILE_INSPECT_NATIVE_SHADER_CODE), p_disabled);
file_popup_menu->set_item_disabled(file_popup_menu->get_item_index(FILE_CLOSE), p_disabled);
}

View File

@ -69,6 +69,7 @@ class ShaderEditorPlugin : public EditorPlugin {
FILE_SAVE,
FILE_SAVE_AS,
FILE_INSPECT,
FILE_INSPECT_NATIVE_SHADER_CODE,
FILE_CLOSE,
CLOSE_ALL,
CLOSE_OTHER_TABS,

View File

@ -2128,12 +2128,11 @@ void VisualShaderEditor::_update_nodes() {
}
}
Array keys = added.keys();
keys.sort();
for (int i = 0; i < keys.size(); i++) {
const Variant &key = keys.get(i);
List<Variant> keys;
added.get_key_list(&keys);
keys.sort_custom<StringLikeVariantOrder>();
for (const Variant &key : keys) {
const Dictionary &value = (Dictionary)added[key];
add_custom_type(value["name"], value["type"], value["script"], value["description"], value["return_icon_type"], value["category"], value["highend"]);

View File

@ -88,7 +88,7 @@ void ProjectListItemControl::_notification(int p_what) {
draw_style_box(get_theme_stylebox(SNAME("selected"), SNAME("Tree")), Rect2(Point2(), get_size()));
}
if (is_hovering) {
draw_style_box(get_theme_stylebox(SNAME("hover"), SNAME("Tree")), Rect2(Point2(), get_size()));
draw_style_box(get_theme_stylebox(SNAME("hovered"), SNAME("Tree")), Rect2(Point2(), get_size()));
}
draw_line(Point2(0, get_size().y + 1), Point2(get_size().x, get_size().y + 1), get_theme_color(SNAME("guide_color"), SNAME("Tree")));

View File

@ -945,6 +945,8 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the
p_theme->set_color("custom_button_font_highlight", "Tree", p_config.font_hover_color);
p_theme->set_color(SceneStringName(font_color), "Tree", p_config.font_color);
p_theme->set_color("font_hovered_color", "Tree", p_config.mono_color);
p_theme->set_color("font_hovered_dimmed_color", "Tree", p_config.font_color);
p_theme->set_color("font_selected_color", "Tree", p_config.mono_color);
p_theme->set_color("font_disabled_color", "Tree", p_config.font_disabled_color);
p_theme->set_color("font_outline_color", "Tree", p_config.font_outline_color);
@ -997,7 +999,13 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the
Ref<StyleBoxFlat> style_tree_hover = p_config.base_style->duplicate();
style_tree_hover->set_bg_color(p_config.highlight_color * Color(1, 1, 1, 0.4));
style_tree_hover->set_border_width_all(0);
p_theme->set_stylebox("hover", "Tree", style_tree_hover);
p_theme->set_stylebox("hovered", "Tree", style_tree_hover);
p_theme->set_stylebox("button_hover", "Tree", style_tree_hover);
Ref<StyleBoxFlat> style_tree_hover_dimmed = p_config.base_style->duplicate();
style_tree_hover_dimmed->set_bg_color(p_config.highlight_color * Color(1, 1, 1, 0.2));
style_tree_hover_dimmed->set_border_width_all(0);
p_theme->set_stylebox("hovered_dimmed", "Tree", style_tree_hover_dimmed);
p_theme->set_stylebox("selected_focus", "Tree", style_tree_focus);
p_theme->set_stylebox("selected", "Tree", style_tree_selected);

View File

@ -42,6 +42,7 @@
#include "core/io/dir_access.h"
#include "core/io/file_access_pack.h"
#include "core/io/file_access_zip.h"
#include "core/io/image.h"
#include "core/io/image_loader.h"
#include "core/io/ip.h"
#include "core/io/resource_loader.h"
@ -2412,6 +2413,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (bool(GLOBAL_GET("display/window/size/no_focus"))) {
window_flags |= DisplayServer::WINDOW_FLAG_NO_FOCUS_BIT;
}
if (bool(GLOBAL_GET("display/window/size/sharp_corners"))) {
window_flags |= DisplayServer::WINDOW_FLAG_SHARP_CORNERS_BIT;
}
window_mode = (DisplayServer::WindowMode)(GLOBAL_GET("display/window/size/mode").operator int());
int initial_position_type = GLOBAL_GET("display/window/size/initial_position_type").operator int();
if (initial_position_type == 0) { // Absolute.
@ -3197,6 +3201,10 @@ Error Main::setup2(bool p_show_boot_logo) {
}
id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_mouse_from_touch", true)));
if (editor) {
id->set_emulate_mouse_from_touch(true);
}
}
OS::get_singleton()->benchmark_end_measure("Startup", "Setup Window and Boot");

View File

@ -30,6 +30,7 @@
#include "image_compress_basisu.h"
#include "core/io/image.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "servers/rendering_server.h"

View File

@ -217,7 +217,7 @@ String GDScriptDocGen::_docvalue_from_variant(const Variant &p_variant, int p_re
List<Variant> keys;
dict.get_key_list(&keys);
keys.sort();
keys.sort_custom<StringLikeVariantOrder>();
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
if (E->prev()) {

View File

@ -1624,15 +1624,17 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali
valid = false;
}
annotation->info = &valid_annotations[annotation->name];
if (valid) {
annotation->info = &valid_annotations[annotation->name];
if (!annotation->applies_to(p_valid_targets)) {
if (annotation->applies_to(AnnotationInfo::SCRIPT)) {
push_error(vformat(R"(Annotation "%s" must be at the top of the script, before "extends" and "class_name".)", annotation->name));
} else {
push_error(vformat(R"(Annotation "%s" is not allowed in this level.)", annotation->name));
if (!annotation->applies_to(p_valid_targets)) {
if (annotation->applies_to(AnnotationInfo::SCRIPT)) {
push_error(vformat(R"(Annotation "%s" must be at the top of the script, before "extends" and "class_name".)", annotation->name));
} else {
push_error(vformat(R"(Annotation "%s" is not allowed in this level.)", annotation->name));
}
valid = false;
}
valid = false;
}
if (check(GDScriptTokenizer::Token::PARENTHESIS_OPEN)) {

View File

@ -0,0 +1,3 @@
@export
func test():
pass

View File

@ -0,0 +1,2 @@
GDTEST_PARSER_ERROR
Annotation "@export" cannot be applied to a function.

View File

@ -0,0 +1,3 @@
@hello_world
func test():
pass

View File

@ -0,0 +1,2 @@
GDTEST_PARSER_ERROR
Unrecognized annotation: "@hello_world".

View File

@ -32,7 +32,7 @@ partial class EventSignals
add => backing_MySignal += value;
remove => backing_MySignal -= value;
}
protected void OnMySignal(string str, int num)
protected void EmitSignalMySignal(string str, int num)
{
EmitSignal(SignalName.MySignal, str, num);
}

View File

@ -807,7 +807,7 @@ partial class ExportedFields
properties.Add(new(type: (global::Godot.Variant.Type)23, name: PropertyName.@_fieldRid, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.@_fieldGodotDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.@_fieldGodotArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.@_fieldGodotGenericDictionary, hint: (global::Godot.PropertyHint)38, hintString: "4/0:;1/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.@_fieldGodotGenericDictionary, hint: (global::Godot.PropertyHint)23, hintString: "4/0:;1/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.@_fieldGodotGenericArray, hint: (global::Godot.PropertyHint)23, hintString: "2/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
properties.Add(new(type: (global::Godot.Variant.Type)31, name: PropertyName.@_fieldEmptyInt64Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
return properties;

View File

@ -925,7 +925,7 @@ partial class ExportedProperties
properties.Add(new(type: (global::Godot.Variant.Type)23, name: PropertyName.@PropertyRid, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.@PropertyGodotDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.@PropertyGodotArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.@PropertyGodotGenericDictionary, hint: (global::Godot.PropertyHint)38, hintString: "4/0:;1/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.@PropertyGodotGenericDictionary, hint: (global::Godot.PropertyHint)23, hintString: "4/0:;1/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.@PropertyGodotGenericArray, hint: (global::Godot.PropertyHint)23, hintString: "2/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
return properties;
}

View File

@ -791,7 +791,7 @@ namespace Godot.SourceGenerators
}
}
hint = PropertyHint.DictionaryType;
hint = PropertyHint.TypeString;
hintString = keyHintString != null && valueHintString != null ? $"{keyHintString};{valueHintString}" : null;
return hintString != null;

View File

@ -282,7 +282,7 @@ namespace Godot.SourceGenerators
.Append(" -= value;\n")
.Append("}\n");
// Generate On{EventName} method to raise the event
// Generate EmitSignal{EventName} method to raise the event
var invokeMethodSymbol = signalDelegate.InvokeMethodData.Method;
int paramCount = invokeMethodSymbol.Parameters.Length;
@ -291,7 +291,7 @@ namespace Godot.SourceGenerators
"private" :
"protected";
source.Append($" {raiseMethodModifiers} void On{signalName}(");
source.Append($" {raiseMethodModifiers} void EmitSignal{signalName}(");
for (int i = 0; i < paramCount; i++)
{
var paramSymbol = invokeMethodSymbol.Parameters[i];

View File

@ -3275,10 +3275,10 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append(CLOSE_BLOCK_L1);
// Generate On{EventName} method to raise the event.
// Generate EmitSignal{EventName} method to raise the event.
if (!p_itype.is_singleton) {
p_output.append(MEMBER_BEGIN "protected void ");
p_output << "On" << p_isignal.proxy_name;
p_output << "EmitSignal" << p_isignal.proxy_name;
if (is_parameterless) {
p_output.append("()\n" OPEN_BLOCK_L1 INDENT2);
p_output << "EmitSignal(SignalName." << p_isignal.proxy_name << ");\n";

View File

@ -32,6 +32,7 @@
#include "core/error/error_macros.h"
#include "core/io/file_access_memory.h"
#include "core/io/image.h"
#include "core/os/os.h"
#include "core/string/print_string.h"

View File

@ -31,6 +31,7 @@
#include "video_stream_theora.h"
#include "core/config/project_settings.h"
#include "core/io/image.h"
#include "core/os/os.h"
#include "scene/resources/image_texture.h"

View File

@ -31,6 +31,7 @@
#include "image_saver_tinyexr.h"
#include "core/math/math_funcs.h"
#include "core/os/os.h"
#include <zlib.h> // Should come before including tinyexr.

View File

@ -31,7 +31,7 @@
#ifndef IMAGE_SAVER_TINYEXR_H
#define IMAGE_SAVER_TINYEXR_H
#include "core/os/os.h"
#include "core/io/image.h"
Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale);
Vector<uint8_t> save_exr_buffer(const Ref<Image> &p_img, bool p_grayscale);

View File

@ -35,6 +35,7 @@
#include "godot_plugin_config.h"
#endif // DISABLE_DEPRECATED
#include "core/io/image.h"
#include "core/io/zip_io.h"
#include "core/os/os.h"
#include "editor/export/editor_export_platform.h"

View File

@ -131,6 +131,18 @@ public class GodotIO {
return activity.getCacheDir().getAbsolutePath();
}
public String getTmpDir() {
File tmpDir = new File(getCacheDir() + "/tmp");
if (!tmpDir.exists()) {
if (!tmpDir.mkdirs()) {
Log.e(TAG, "Unable to create tmp dir");
}
}
return tmpDir.getAbsolutePath();
}
public String getDataDir() {
return activity.getFilesDir().getAbsolutePath();
}

View File

@ -52,6 +52,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
_open_URI = p_env->GetMethodID(cls, "openURI", "(Ljava/lang/String;)I");
_get_cache_dir = p_env->GetMethodID(cls, "getCacheDir", "()Ljava/lang/String;");
_get_tmp_dir = p_env->GetMethodID(cls, "getTmpDir", "()Ljava/lang/String;");
_get_data_dir = p_env->GetMethodID(cls, "getDataDir", "()Ljava/lang/String;");
_get_display_cutouts = p_env->GetMethodID(cls, "getDisplayCutouts", "()[I"),
_get_display_safe_area = p_env->GetMethodID(cls, "getDisplaySafeArea", "()[I"),
@ -106,6 +107,17 @@ String GodotIOJavaWrapper::get_cache_dir() {
}
}
String GodotIOJavaWrapper::get_tmp_dir() {
if (_get_tmp_dir) {
JNIEnv *env = get_jni_env();
ERR_FAIL_NULL_V(env, String());
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_tmp_dir);
return jstring_to_string(s, env);
} else {
return String();
}
}
String GodotIOJavaWrapper::get_user_data_dir() {
if (_get_data_dir) {
JNIEnv *env = get_jni_env();

View File

@ -48,6 +48,7 @@ private:
jmethodID _open_URI = 0;
jmethodID _get_cache_dir = 0;
jmethodID _get_data_dir = 0;
jmethodID _get_tmp_dir = 0;
jmethodID _get_display_cutouts = 0;
jmethodID _get_display_safe_area = 0;
jmethodID _get_locale = 0;
@ -71,6 +72,7 @@ public:
Error open_uri(const String &p_uri);
String get_cache_dir();
String get_tmp_dir();
String get_user_data_dir();
String get_locale();
String get_model();

View File

@ -677,6 +677,19 @@ String OS_Android::get_cache_path() const {
return ".";
}
String OS_Android::get_tmp_path() const {
if (!tmp_dir_cache.is_empty()) {
return tmp_dir_cache;
}
String tmp_dir = godot_io_java->get_tmp_dir();
if (!tmp_dir.is_empty()) {
tmp_dir_cache = _remove_symlink(tmp_dir);
return tmp_dir_cache;
}
return ".";
}
String OS_Android::get_unique_id() const {
String unique_id = godot_io_java->get_unique_id();
if (!unique_id.is_empty()) {

View File

@ -58,6 +58,7 @@ private:
mutable String data_dir_cache;
mutable String cache_dir_cache;
mutable String tmp_dir_cache;
mutable String remote_fs_dir;
AudioDriverOpenSL audio_driver_android;
@ -148,6 +149,7 @@ public:
virtual String get_user_data_dir() const override;
virtual String get_data_path() const override;
virtual String get_cache_path() const override;
virtual String get_tmp_path() const override;
virtual String get_resource_dir() const override;
virtual String get_locale() const override;
virtual String get_model_name() const override;

View File

@ -117,6 +117,7 @@ public:
virtual String get_user_data_dir() const override;
virtual String get_cache_path() const override;
virtual String get_tmp_path() const override;
virtual String get_locale() const override;

View File

@ -336,6 +336,22 @@ String OS_IOS::get_cache_path() const {
return ret;
}
String OS_IOS::get_tmp_path() const {
static String ret;
if (ret.is_empty()) {
NSURL *url = [NSURL fileURLWithPath:NSTemporaryDirectory()
isDirectory:YES];
if (url) {
NSString *url_path = [url absoluteString];
ret.parse_utf8([url_path UTF8String]);
if (ret.begins_with("file://")) {
ret = ret.replace_first("file://", "");
}
}
}
return ret;
}
String OS_IOS::get_locale() const {
NSString *preferedLanguage = [NSLocale preferredLanguages].firstObject;

View File

@ -34,6 +34,7 @@
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/image.h"
#include "core/io/marshalls.h"
#include "core/io/resource_saver.h"
#include "core/os/os.h"

View File

@ -92,6 +92,7 @@ public:
virtual String get_config_path() const override;
virtual String get_data_path() const override;
virtual String get_cache_path() const override;
virtual String get_tmp_path() const override;
virtual String get_bundle_resource_dir() const override;
virtual String get_bundle_icon_path() const override;
virtual String get_godot_dir_name() const override;

View File

@ -267,6 +267,22 @@ String OS_MacOS::get_cache_path() const {
return get_config_path();
}
String OS_MacOS::get_tmp_path() const {
static String ret;
if (ret.is_empty()) {
NSURL *url = [NSURL fileURLWithPath:NSTemporaryDirectory()
isDirectory:YES];
if (url) {
NSString *url_path = [url absoluteString];
ret.parse_utf8([url_path UTF8String]);
if (ret.begins_with("file://")) {
ret = ret.replace_first("file://", "");
}
}
}
return ret;
}
String OS_MacOS::get_bundle_resource_dir() const {
String ret;

View File

@ -67,6 +67,18 @@
#define DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 19
#endif
#ifndef DWMWA_WINDOW_CORNER_PREFERENCE
#define DWMWA_WINDOW_CORNER_PREFERENCE 33
#endif
#ifndef DWMWCP_DEFAULT
#define DWMWCP_DEFAULT 0
#endif
#ifndef DWMWCP_DONOTROUND
#define DWMWCP_DONOTROUND 1
#endif
#define WM_INDICATOR_CALLBACK_MESSAGE (WM_USER + 1)
#if defined(__GNUC__)
@ -1483,6 +1495,9 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
if (p_flags & WINDOW_FLAG_ALWAYS_ON_TOP_BIT && p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
wd.always_on_top = true;
}
if (p_flags & WINDOW_FLAG_SHARP_CORNERS_BIT) {
wd.sharp_corners = true;
}
if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
wd.no_focus = true;
}
@ -2297,6 +2312,12 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
wd.always_on_top = p_enabled;
_update_window_style(p_window);
} break;
case WINDOW_FLAG_SHARP_CORNERS: {
wd.sharp_corners = p_enabled;
DWORD value = wd.sharp_corners ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT;
::DwmSetWindowAttribute(wd.hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &value, sizeof(value));
_update_window_style(p_window);
} break;
case WINDOW_FLAG_TRANSPARENT: {
if (p_enabled) {
// Enable per-pixel alpha.
@ -3994,6 +4015,10 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
native_menu->_menu_activate(HMENU(lParam), (int)wParam);
} break;
case WM_CREATE: {
{
DWORD value = windows[window_id].sharp_corners ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT;
::DwmSetWindowAttribute(windows[window_id].hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &value, sizeof(value));
}
if (is_dark_mode_supported() && dark_title_available) {
BOOL value = is_dark_mode();
@ -5645,6 +5670,12 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
wd_transient_parent->transient_children.insert(id);
}
wd.sharp_corners = p_flags & WINDOW_FLAG_SHARP_CORNERS_BIT;
{
DWORD value = wd.sharp_corners ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT;
::DwmSetWindowAttribute(wd.hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &value, sizeof(value));
}
if (is_dark_mode_supported() && dark_title_available) {
BOOL value = is_dark_mode();
::DwmSetWindowAttribute(wd.hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));

View File

@ -38,6 +38,7 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/io/image.h"
#include "core/os/os.h"
#include "drivers/unix/ip_unix.h"
#include "drivers/wasapi/audio_driver_wasapi.h"
@ -473,6 +474,7 @@ class DisplayServerWindows : public DisplayServer {
bool exclusive = false;
bool context_created = false;
bool mpass = false;
bool sharp_corners = false;
// Used to transfer data between events using timer.
WPARAM saved_wparam;

View File

@ -31,6 +31,7 @@
#ifndef NATIVE_MENU_WINDOWS_H
#define NATIVE_MENU_WINDOWS_H
#include "core/io/image.h"
#include "core/templates/hash_map.h"
#include "core/templates/rid_owner.h"
#include "servers/display/native_menu.h"

View File

@ -1850,16 +1850,35 @@ String OS_Windows::get_cache_path() const {
if (has_environment("LOCALAPPDATA")) {
cache_path_cache = get_environment("LOCALAPPDATA").replace("\\", "/");
}
if (cache_path_cache.is_empty() && has_environment("TEMP")) {
cache_path_cache = get_environment("TEMP").replace("\\", "/");
}
if (cache_path_cache.is_empty()) {
cache_path_cache = get_config_path();
cache_path_cache = get_tmp_path();
}
}
return cache_path_cache;
}
String OS_Windows::get_tmp_path() const {
static String tmp_path_cache;
if (tmp_path_cache.is_empty()) {
{
// Get the tmp path from the Windows API.
void *get_temp_path = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetTempPathW");
if (get_temp_path) {
Vector<WCHAR> tmp_path;
tmp_path.resize(MAX_PATH);
DWORD tmp_path_length = GetTempPathW(MAX_PATH, (LPWSTR)tmp_path.ptrw());
if (tmp_path_length > 0 && tmp_path_length < MAX_PATH) {
tmp_path_cache = String::utf16((const char16_t *)tmp_path.ptr(), tmp_path_length / sizeof(WCHAR));
}
}
}
if (tmp_path_cache.is_empty()) {
tmp_path_cache = get_config_path();
}
}
return tmp_path_cache;
}
// Get properly capitalized engine name for system paths
String OS_Windows::get_godot_dir_name() const {
return String(VERSION_SHORT_NAME).capitalize();

View File

@ -215,6 +215,7 @@ public:
virtual String get_config_path() const override;
virtual String get_data_path() const override;
virtual String get_cache_path() const override;
virtual String get_tmp_path() const override;
virtual String get_godot_dir_name() const override;
virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const override;

View File

@ -167,17 +167,16 @@ void Path2D::_curve_changed() {
return;
}
if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_paths_hint()) {
return;
}
queue_redraw();
for (int i = 0; i < get_child_count(); i++) {
PathFollow2D *follow = Object::cast_to<PathFollow2D>(get_child(i));
if (follow) {
follow->path_changed();
}
}
if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_paths_hint()) {
queue_redraw();
}
}
void Path2D::set_curve(const Ref<Curve2D> &p_curve) {

View File

@ -1602,19 +1602,16 @@ Ref<CameraAttributes> LightmapGI::get_camera_attributes() const {
PackedStringArray LightmapGI::get_configuration_warnings() const {
PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
#ifndef MODULE_LIGHTMAPPER_RD_ENABLED
#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
warnings.push_back(vformat(RTR("Lightmaps cannot be baked on %s. Rendering existing baked lightmaps will still work."), OS::get_singleton()->get_name()));
#else
warnings.push_back(RTR("Lightmaps cannot be baked, as the `lightmapper_rd` module was disabled at compile-time. Rendering existing baked lightmaps will still work."));
#endif
return warnings;
#endif
#ifdef MODULE_LIGHTMAPPER_RD_ENABLED
if (!DisplayServer::get_singleton()->can_create_rendering_device()) {
warnings.push_back(vformat(RTR("Lightmaps can only be baked from a GPU that supports the RenderingDevice backends.\nYour GPU (%s) does not support RenderingDevice, as it does not support Vulkan, Direct3D 12, or Metal.\nLightmap baking will not be available on this device, although rendering existing baked lightmaps will work."), RenderingServer::get_singleton()->get_video_adapter_name()));
return warnings;
}
#elif defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
warnings.push_back(vformat(RTR("Lightmaps cannot be baked on %s. Rendering existing baked lightmaps will still work."), OS::get_singleton()->get_name()));
#else
warnings.push_back(RTR("Lightmaps cannot be baked, as the `lightmapper_rd` module was disabled at compile-time. Rendering existing baked lightmaps will still work."));
#endif
return warnings;
}

View File

@ -245,21 +245,7 @@ void ColorPicker::finish_shaders() {
}
void ColorPicker::set_focus_on_line_edit() {
bool has_hardware_keyboard = true;
#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
has_hardware_keyboard = DisplayServer::get_singleton()->has_hardware_keyboard();
#endif // ANDROID_ENABLED || IOS_ENABLED
if (has_hardware_keyboard) {
callable_mp((Control *)c_text, &Control::grab_focus).call_deferred();
} else {
// A hack to avoid showing the virtual keyboard when the ColorPicker window popups and
// no hardware keyboard is detected on Android and IOS.
// This will only focus the LineEdit without editing, the virtual keyboard will only be visible when
// we touch the LineEdit to enter edit mode.
callable_mp(c_text, &LineEdit::set_editable).call_deferred(false);
callable_mp((Control *)c_text, &Control::grab_focus).call_deferred();
callable_mp(c_text, &LineEdit::set_editable).call_deferred(true);
}
callable_mp((Control *)c_text, &Control::grab_focus).call_deferred();
}
void ColorPicker::_update_controls() {
@ -2103,7 +2089,9 @@ void ColorPickerButton::pressed() {
float v_offset = show_above ? -minsize.y : get_size().y;
popup->set_position(get_screen_position() + Vector2(h_offset, v_offset));
popup->popup();
picker->set_focus_on_line_edit();
if (DisplayServer::get_singleton()->has_hardware_keyboard()) {
picker->set_focus_on_line_edit();
}
}
void ColorPickerButton::_notification(int p_what) {

View File

@ -3042,7 +3042,7 @@ void Control::set_layout_direction(Control::LayoutDirection p_direction) {
if (data.layout_dir == p_direction) {
return;
}
ERR_FAIL_INDEX((int)p_direction, 4);
ERR_FAIL_INDEX(p_direction, LAYOUT_DIRECTION_MAX);
data.layout_dir = p_direction;
@ -3115,13 +3115,20 @@ bool Control::is_layout_rtl() const {
String locale = TranslationServer::get_singleton()->get_tool_locale();
const_cast<Control *>(this)->data.is_rtl = TS->is_locale_right_to_left(locale);
}
} else if (data.layout_dir == LAYOUT_DIRECTION_LOCALE) {
} else if (data.layout_dir == LAYOUT_DIRECTION_APPLICATION_LOCALE) {
if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) {
const_cast<Control *>(this)->data.is_rtl = true;
} else {
String locale = TranslationServer::get_singleton()->get_tool_locale();
const_cast<Control *>(this)->data.is_rtl = TS->is_locale_right_to_left(locale);
}
} else if (data.layout_dir == LAYOUT_DIRECTION_SYSTEM_LOCALE) {
if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) {
const_cast<Control *>(this)->data.is_rtl = true;
} else {
String locale = OS::get_singleton()->get_locale();
const_cast<Control *>(this)->data.is_rtl = TS->is_locale_right_to_left(locale);
}
} else {
const_cast<Control *>(this)->data.is_rtl = (data.layout_dir == LAYOUT_DIRECTION_RTL);
}
@ -3574,7 +3581,7 @@ void Control::_bind_methods() {
ADD_GROUP("Layout", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Based on Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Based on Application Locale,Left-to-Right,Right-to-Left,Based on System Locale"), "set_layout_direction", "get_layout_direction");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION);
@ -3723,9 +3730,14 @@ void Control::_bind_methods() {
BIND_ENUM_CONSTANT(ANCHOR_END);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_INHERITED);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LOCALE);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_APPLICATION_LOCALE);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LTR);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_RTL);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_SYSTEM_LOCALE);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_MAX);
#ifndef DISABLE_DEPRECATED
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LOCALE);
#endif // DISABLE_DEPRECATED
BIND_ENUM_CONSTANT(TEXT_DIRECTION_INHERITED);
BIND_ENUM_CONSTANT(TEXT_DIRECTION_AUTO);

View File

@ -140,9 +140,14 @@ public:
enum LayoutDirection {
LAYOUT_DIRECTION_INHERITED,
LAYOUT_DIRECTION_LOCALE,
LAYOUT_DIRECTION_APPLICATION_LOCALE,
LAYOUT_DIRECTION_LTR,
LAYOUT_DIRECTION_RTL
LAYOUT_DIRECTION_RTL,
LAYOUT_DIRECTION_SYSTEM_LOCALE,
LAYOUT_DIRECTION_MAX,
#ifndef DISABLE_DEPRECATED
LAYOUT_DIRECTION_LOCALE = LAYOUT_DIRECTION_APPLICATION_LOCALE,
#endif // DISABLE_DEPRECATED
};
enum TextDirection {

Some files were not shown because too many files have changed in this diff Show More