Merge pull request #76405 from YuriSizov/4.0-cherrypicks
Cherry-picks for the 4.0 branch (future 4.0.3) - 2nd batch
This commit is contained in:
commit
d78691d44f
79
CHANGELOG.md
79
CHANGELOG.md
@ -16,6 +16,10 @@ See the [release announcement](https://godotengine.org/article/maintenance-relea
|
||||
- Remember directory when installing templates file ([GH-74735](https://github.com/godotengine/godot/pull/74735)).
|
||||
- Improve editor state initialization ([GH-75563](https://github.com/godotengine/godot/pull/75563)).
|
||||
|
||||
#### GUI
|
||||
|
||||
- Allow entering named colors in ColorPicker's hex field ([GH-75905](https://github.com/godotengine/godot/pull/75905)).
|
||||
|
||||
#### Navigation
|
||||
|
||||
- Navigation: Expose NavigationAgent path postprocessing and pathfinding algorithm options ([GH-75326](https://github.com/godotengine/godot/pull/75326)).
|
||||
@ -40,21 +44,49 @@ See the [release announcement](https://godotengine.org/article/maintenance-relea
|
||||
|
||||
- Truncate instead of round in Vector2/3/4 to Vector2I/3I/4I conversion ([GH-75477](https://github.com/godotengine/godot/pull/75477)).
|
||||
|
||||
#### Core
|
||||
|
||||
- Lift restriction that resource load thread requester has to be the initiator ([GH-73862](https://github.com/godotengine/godot/pull/73862)).
|
||||
- Use HashMap instead of RBMap for ids in Windows TTS ([GH-75933](https://github.com/godotengine/godot/pull/75933)).
|
||||
- Rename internal root canvas group to start with underscore ([GH-76149](https://github.com/godotengine/godot/pull/76149)).
|
||||
|
||||
#### Editor
|
||||
|
||||
- Make EditorToaster's handler thread-safe ([GH-71670](https://github.com/godotengine/godot/pull/71670)).
|
||||
- Prevent off-screen controls in editor ([GH-73646](https://github.com/godotengine/godot/pull/73646)).
|
||||
- Re-enable script editor File menu shortcuts when the menu is hidden ([GH-74319](https://github.com/godotengine/godot/pull/74319)).
|
||||
- Prevent color conversion of the big Godot logo ([GH-75653](https://github.com/godotengine/godot/pull/75653)).
|
||||
- Set font sizes for various styles in editor output panel ([GH-75780](https://github.com/godotengine/godot/pull/75780)).
|
||||
- Remove unnecessary zero multiplications ([GH-75822](https://github.com/godotengine/godot/pull/75822)).
|
||||
- Adjust size of some dialogs ([GH-75895](https://github.com/godotengine/godot/pull/75895)).
|
||||
- Change cursor consistently when panning in the 2D Editor ([GH-75997](https://github.com/godotengine/godot/pull/75997)).
|
||||
|
||||
#### GUI
|
||||
|
||||
- Ignore invisible children of GraphNode for minimum size ([GH-72240](https://github.com/godotengine/godot/pull/72240)).
|
||||
- Update `TextureProgressBar` upon texture changes ([GH-75532](https://github.com/godotengine/godot/pull/75532)).
|
||||
- Keep a copy of UTF-8 XML source string during the SVG font processing ([GH-75675](https://github.com/godotengine/godot/pull/75675)).
|
||||
- Always cache parent visibility in `CanvasItem` ([GH-75890](https://github.com/godotengine/godot/pull/75890)).
|
||||
- Improve BiDi error handling in TextServer ([GH-75922](https://github.com/godotengine/godot/pull/75922)).
|
||||
- Use dedicated flag for object replacement characters in TextServer ([GH-75974](https://github.com/godotengine/godot/pull/75974)).
|
||||
- Improve line BiDi handling, prevent crash on recursive log updates ([GH-75975](https://github.com/godotengine/godot/pull/75975)).
|
||||
- Don't apply scale to autohide theme property ([GH-75993](https://github.com/godotengine/godot/pull/75993)).
|
||||
- Use Point2 consistently in Control methods ([GH-76029](https://github.com/godotengine/godot/pull/76029)).
|
||||
|
||||
#### Import
|
||||
|
||||
- gltf: Remove obsolete hack to embed gltf textures in advanced import ([GH-75636](https://github.com/godotengine/godot/pull/75636)).
|
||||
- Expose more compression formats in Image and fix compress check ([GH-76014](https://github.com/godotengine/godot/pull/76014)).
|
||||
|
||||
#### Network
|
||||
|
||||
- Poll LSP/DAP clients for connection status updates ([GH-75850](https://github.com/godotengine/godot/pull/75850)).
|
||||
|
||||
#### Particles
|
||||
|
||||
- Translate inactive GPUParticles3D particles to -INF ([GH-75162](https://github.com/godotengine/godot/pull/75162)).
|
||||
- Use angle_rand to calculate base_angle in particles process material ([GH-75999](https://github.com/godotengine/godot/pull/75999)).
|
||||
- Don't store instance transform origin in RD 3D renderer unless requested ([GH-76003](https://github.com/godotengine/godot/pull/76003)).
|
||||
|
||||
#### Physics
|
||||
|
||||
@ -63,6 +95,12 @@ See the [release announcement](https://godotengine.org/article/maintenance-relea
|
||||
#### Rendering
|
||||
|
||||
- Recreate swap chain when suboptimal to avoid error spam ([GH-72859](https://github.com/godotengine/godot/pull/72859)).
|
||||
- Use MODELVIEW_MATRIX when on double precision ([GH-75462](https://github.com/godotengine/godot/pull/75462)).
|
||||
- Check for instancing without relying on instance_count when drawing 2D meshes ([GH-75954](https://github.com/godotengine/godot/pull/75954)).
|
||||
|
||||
#### Shaders
|
||||
|
||||
- Write out render_mode even when mode is set to default in VisualShaders ([GH-75957](https://github.com/godotengine/godot/pull/75957)).
|
||||
|
||||
#### Thirdparty
|
||||
|
||||
@ -74,6 +112,10 @@ See the [release announcement](https://godotengine.org/article/maintenance-relea
|
||||
|
||||
- Fix RemoteTransform2D could fail to update AnimatableBody2D's position or rotation ([GH-75487](https://github.com/godotengine/godot/pull/75487)).
|
||||
|
||||
#### Animation
|
||||
|
||||
- Fix blend_shape (shapekey) empty name import ([GH-75990](https://github.com/godotengine/godot/pull/75990)).
|
||||
|
||||
#### Audio
|
||||
|
||||
- Fix AudioStreamPlayer2D crash when PhysicsServer2D runs on thread ([GH-75728](https://github.com/godotengine/godot/pull/75728)).
|
||||
@ -81,6 +123,7 @@ See the [release announcement](https://godotengine.org/article/maintenance-relea
|
||||
#### Buildsystem
|
||||
|
||||
- Fix the Python type error when creating the .sln file ([GH-75309](https://github.com/godotengine/godot/pull/75309)).
|
||||
- Fix forced optimization in dev_build ([GH-75909](https://github.com/godotengine/godot/pull/75909)).
|
||||
|
||||
#### Core
|
||||
|
||||
@ -89,36 +132,72 @@ See the [release announcement](https://godotengine.org/article/maintenance-relea
|
||||
#### Editor
|
||||
|
||||
- Fix off-by-one issue where "Go to Line" dialog shows the incorrect line number ([GH-75523](https://github.com/godotengine/godot/pull/75523)).
|
||||
- Fix deserializing resource usage debug data ([GH-75782](https://github.com/godotengine/godot/pull/75782)).
|
||||
- Initialize editor values on first launch ([GH-75799](https://github.com/godotengine/godot/pull/75799)).
|
||||
- Fix connect signal dialog not allowing Unicode method name ([GH-75814](https://github.com/godotengine/godot/pull/75814)).
|
||||
- Fix method dialog label ([GH-75844](https://github.com/godotengine/godot/pull/75844)).
|
||||
|
||||
#### Export
|
||||
|
||||
- Fix validation of codesigning certificate password on macOS ([GH-74326](https://github.com/godotengine/godot/pull/74326)).
|
||||
|
||||
#### GDScript
|
||||
|
||||
- Add missing member type check when resolving `extends` ([GH-75879](https://github.com/godotengine/godot/pull/75879)).
|
||||
- Fix typo in LSP parse function parameters ([GH-76090](https://github.com/godotengine/godot/pull/76090)).
|
||||
|
||||
#### GUI
|
||||
|
||||
- Fixed RichTextLabel wrong selection offset in padded table cell ([GH-71742](https://github.com/godotengine/godot/pull/71742)).
|
||||
- Fix commenting collapsed function issue ([GH-75070](https://github.com/godotengine/godot/pull/75070)).
|
||||
- Fix fill align and trim with enabled dropcap in `RichTextLabel` ([GH-75504](https://github.com/godotengine/godot/pull/75504)).
|
||||
- Fix descriptions not showing for theme properties ([GH-75559](https://github.com/godotengine/godot/pull/75559)).
|
||||
- Fix some theme values affect the editor by setting a default value for them ([GH-75566](https://github.com/godotengine/godot/pull/75566)).
|
||||
- Fix several GraphEdit operations at zoom levels other than 100% ([GH-75595](https://github.com/godotengine/godot/pull/75595)).
|
||||
- Fix uninitialized member in CodeEdit ([GH-75829](https://github.com/godotengine/godot/pull/75829)).
|
||||
- Fix offset calculation in Tree when there are hidden items ([GH-75977](https://github.com/godotengine/godot/pull/75977)).
|
||||
- Add missing LineEdit constants in editor theme ([GH-76123](https://github.com/godotengine/godot/pull/76123)).
|
||||
- Fix blurry borders on antialiased StyleBoxFlat ([GH-76132](https://github.com/godotengine/godot/pull/76132)).
|
||||
|
||||
#### Import
|
||||
|
||||
- SVG: fix tvg::Picture->size() and scale based errors. ([GH-75034](https://github.com/godotengine/godot/pull/75034)).
|
||||
- Fix OBJ mesh importer smoothing handling ([GH-75315](https://github.com/godotengine/godot/pull/75315)).
|
||||
|
||||
#### Input
|
||||
|
||||
- Fix guide button detection with XInput and Xbox Series controllers ([GH-73200](https://github.com/godotengine/godot/pull/73200)).
|
||||
- Fix the issue preventing dragging in the 2D editor ([GH-75113](https://github.com/godotengine/godot/pull/75113)).
|
||||
- Fix keycode/physical keycode mix up on web ([GH-75738](https://github.com/godotengine/godot/pull/75738)).
|
||||
- Fix potential null in android text entry system ([GH-75991](https://github.com/godotengine/godot/pull/75991)).
|
||||
|
||||
#### Navigation
|
||||
|
||||
- Navigation: Fix NavigationObstacles not being added to avoidance simulation ([GH-75756](https://github.com/godotengine/godot/pull/75756)).
|
||||
|
||||
#### Particles
|
||||
|
||||
- Properly calculate lifetime_split for particles ([GH-73313](https://github.com/godotengine/godot/pull/73313)).
|
||||
- Fix "error X3708: continue cannot be used in a switch" in HTML export ([GH-75795](https://github.com/godotengine/godot/pull/75795)).
|
||||
|
||||
#### Physics
|
||||
|
||||
- Fix typo bug in convex-convex separating axis test ([GH-75835](https://github.com/godotengine/godot/pull/75835)).
|
||||
|
||||
#### Porting
|
||||
|
||||
- Windows: Fix clipboard relying on focused window ([GH-73878](https://github.com/godotengine/godot/pull/73878)).
|
||||
- Windows: Fix StringFileInfo structure ([GH-76001](https://github.com/godotengine/godot/pull/76001)).
|
||||
|
||||
#### Rendering
|
||||
|
||||
- Fix interpolation of R0 for metallic and calculation of the Fresnel Shlick term in SSR ([GH-75368](https://github.com/godotengine/godot/pull/75368)).
|
||||
- Fix `get_test_texture()` returning an almost fully white texture ([GH-75632](https://github.com/godotengine/godot/pull/75632)).
|
||||
- Ensure that depth write state is updated before transparent pass in OpenGL3 renderer ([GH-75968](https://github.com/godotengine/godot/pull/75968)).
|
||||
|
||||
#### Shaders
|
||||
|
||||
- Fix crashes caused due to missing type specifier on visual shader editor ([GH-75809](https://github.com/godotengine/godot/pull/75809)).
|
||||
|
||||
|
||||
## [4.0.2] - 2023-04-04
|
||||
|
@ -2649,7 +2649,7 @@ Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels
|
||||
_image_compress_bptc_func(this, p_channels);
|
||||
} break;
|
||||
case COMPRESS_ASTC: {
|
||||
ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE);
|
||||
ERR_FAIL_COND_V(!_image_compress_astc_func, ERR_UNAVAILABLE);
|
||||
_image_compress_astc_func(this, p_astc_format);
|
||||
} break;
|
||||
case COMPRESS_MAX: {
|
||||
@ -3535,6 +3535,8 @@ void Image::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(COMPRESS_ETC);
|
||||
BIND_ENUM_CONSTANT(COMPRESS_ETC2);
|
||||
BIND_ENUM_CONSTANT(COMPRESS_BPTC);
|
||||
BIND_ENUM_CONSTANT(COMPRESS_ASTC);
|
||||
BIND_ENUM_CONSTANT(COMPRESS_MAX);
|
||||
|
||||
BIND_ENUM_CONSTANT(USED_CHANNELS_L);
|
||||
BIND_ENUM_CONSTANT(USED_CHANNELS_LA);
|
||||
|
@ -310,12 +310,6 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String &
|
||||
thread_load_mutex->unlock();
|
||||
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "There is no thread loading source resource '" + p_source_resource + "'.");
|
||||
}
|
||||
//must be loading from this thread
|
||||
if (thread_load_tasks[p_source_resource].loader_id != Thread::get_caller_id()) {
|
||||
thread_load_mutex->unlock();
|
||||
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Threading loading resource'" + local_path + " failed: Source specified: '" + p_source_resource + "' but was not called by it.");
|
||||
}
|
||||
|
||||
//must not be already added as s sub tasks
|
||||
if (thread_load_tasks[p_source_resource].sub_tasks.has(local_path)) {
|
||||
thread_load_mutex->unlock();
|
||||
|
@ -1906,7 +1906,7 @@ static void _register_variant_builtin_methods() {
|
||||
bind_method(Vector4, distance_squared_to, sarray("to"), varray());
|
||||
bind_method(Vector4, dot, sarray("with"), varray());
|
||||
bind_method(Vector4, inverse, sarray(), varray());
|
||||
bind_method(Vector4, is_equal_approx, sarray("with"), varray());
|
||||
bind_method(Vector4, is_equal_approx, sarray("to"), varray());
|
||||
bind_method(Vector4, is_zero_approx, sarray(), varray());
|
||||
bind_method(Vector4, is_finite, sarray(), varray());
|
||||
|
||||
|
@ -40,13 +40,13 @@
|
||||
// Defines the main "branch" version. Patch versions in this branch should be
|
||||
// forward-compatible.
|
||||
// Example: "3.1"
|
||||
#define VERSION_BRANCH "" _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR)
|
||||
#define VERSION_BRANCH _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR)
|
||||
#if VERSION_PATCH
|
||||
// Example: "3.1.4"
|
||||
#define VERSION_NUMBER "" VERSION_BRANCH "." _MKSTR(VERSION_PATCH)
|
||||
#define VERSION_NUMBER VERSION_BRANCH "." _MKSTR(VERSION_PATCH)
|
||||
#else // patch is 0, we don't include it in the "pretty" version number.
|
||||
// Example: "3.1" instead of "3.1.0"
|
||||
#define VERSION_NUMBER "" VERSION_BRANCH
|
||||
#define VERSION_NUMBER VERSION_BRANCH
|
||||
#endif // VERSION_PATCH
|
||||
|
||||
// Version number encoded as hexadecimal int with one byte for each number,
|
||||
@ -57,16 +57,16 @@
|
||||
// Describes the full configuration of that Godot version, including the version number,
|
||||
// the status (beta, stable, etc.) and potential module-specific features (e.g. mono).
|
||||
// Example: "3.1.4.stable.mono"
|
||||
#define VERSION_FULL_CONFIG "" VERSION_NUMBER "." VERSION_STATUS VERSION_MODULE_CONFIG
|
||||
#define VERSION_FULL_CONFIG VERSION_NUMBER "." VERSION_STATUS VERSION_MODULE_CONFIG
|
||||
|
||||
// Similar to VERSION_FULL_CONFIG, but also includes the (potentially custom) VERSION_BUILD
|
||||
// description (e.g. official, custom_build, etc.).
|
||||
// Example: "3.1.4.stable.mono.official"
|
||||
#define VERSION_FULL_BUILD "" VERSION_FULL_CONFIG "." VERSION_BUILD
|
||||
#define VERSION_FULL_BUILD VERSION_FULL_CONFIG "." VERSION_BUILD
|
||||
|
||||
// Same as above, but prepended with Godot's name and a cosmetic "v" for "version".
|
||||
// Example: "Godot v3.1.4.stable.official.mono"
|
||||
#define VERSION_FULL_NAME "" VERSION_NAME " v" VERSION_FULL_BUILD
|
||||
#define VERSION_FULL_NAME VERSION_NAME " v" VERSION_FULL_BUILD
|
||||
|
||||
// Git commit hash, generated at build time in `core/version_hash.gen.cpp`.
|
||||
extern const char *const VERSION_HASH;
|
||||
|
@ -826,17 +826,21 @@
|
||||
</method>
|
||||
<method name="print_rich" qualifiers="vararg">
|
||||
<description>
|
||||
Converts one or more arguments of any type to string in the best way possible and prints them to the console. The following BBCode tags are supported: b, i, u, s, indent, code, url, center, right, color, bgcolor, fgcolor. Color tags only support named colors such as [code]red[/code], [i]not[/i] hexadecimal color codes. Unsupported tags will be left as-is in standard output.
|
||||
When printing to standard output, the supported subset of BBCode is converted to ANSI escape codes for the terminal emulator to display. Displaying ANSI escape codes is currently only supported on Linux and macOS. Support for ANSI escape codes may vary across terminal emulators, especially for italic and strikethrough.
|
||||
Converts one or more arguments of any type to string in the best way possible and prints them to the console.
|
||||
The following BBCode tags are supported: [code]b[/code], [code]i[/code], [code]u[/code], [code]s[/code], [code]indent[/code], [code]code[/code], [code]url[/code], [code]center[/code], [code]right[/code], [code]color[/code], [code]bgcolor[/code], [code]fgcolor[/code].
|
||||
Color tags only support the following named colors: [code]black[/code], [code]red[/code], [code]green[/code], [code]yellow[/code], [code]blue[/code], [code]magenta[/code], [code]pink[/code], [code]purple[/code], [code]cyan[/code], [code]white[/code], [code]orange[/code], [code]gray[/code]. Hexadecimal color codes are not supported.
|
||||
URL tags only support URLs wrapped by an URL tag, not URLs with a different title.
|
||||
When printing to standard output, the supported subset of BBCode is converted to ANSI escape codes for the terminal emulator to display. Support for ANSI escape codes varies across terminal emulators, especially for italic and strikethrough. In standard output, [code]code[/code] is represented with faint text but without any font change. Unsupported tags are left as-is in standard output.
|
||||
[codeblocks]
|
||||
[gdscript]
|
||||
print_rich("[code][b]Hello world![/b][/code]") # Prints out: [b]Hello world![/b]
|
||||
print_rich("[color=green][b]Hello world![/b][/color]") # Prints out "Hello world!" in green with a bold font
|
||||
[/gdscript]
|
||||
[csharp]
|
||||
GD.PrintRich("[code][b]Hello world![/b][/code]"); // Prints out: [b]Hello world![/b]
|
||||
GD.PrintRich("[color=green][b]Hello world![/b][/color]"); // Prints out "Hello world!" in green with a bold font
|
||||
[/csharp]
|
||||
[/codeblocks]
|
||||
[b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print] or [method print_rich]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed.
|
||||
[b]Note:[/b] On Windows, only Windows 10 and later correctly displays ANSI escape codes in standard output.
|
||||
</description>
|
||||
</method>
|
||||
<method name="print_verbose" qualifiers="vararg">
|
||||
|
@ -15,27 +15,27 @@
|
||||
var key = "My secret key!!!" # Key must be either 16 or 32 bytes.
|
||||
var data = "My secret text!!" # Data size must be multiple of 16 bytes, apply padding if needed.
|
||||
# Encrypt ECB
|
||||
aes.start(AESContext.MODE_ECB_ENCRYPT, key.to_utf8())
|
||||
var encrypted = aes.update(data.to_utf8())
|
||||
aes.start(AESContext.MODE_ECB_ENCRYPT, key.to_utf8_buffer())
|
||||
var encrypted = aes.update(data.to_utf8_buffer())
|
||||
aes.finish()
|
||||
# Decrypt ECB
|
||||
aes.start(AESContext.MODE_ECB_DECRYPT, key.to_utf8())
|
||||
aes.start(AESContext.MODE_ECB_DECRYPT, key.to_utf8_buffer())
|
||||
var decrypted = aes.update(encrypted)
|
||||
aes.finish()
|
||||
# Check ECB
|
||||
assert(decrypted == data.to_utf8())
|
||||
assert(decrypted == data.to_utf8_buffer())
|
||||
|
||||
var iv = "My secret iv!!!!" # IV must be of exactly 16 bytes.
|
||||
# Encrypt CBC
|
||||
aes.start(AESContext.MODE_CBC_ENCRYPT, key.to_utf8(), iv.to_utf8())
|
||||
encrypted = aes.update(data.to_utf8())
|
||||
aes.start(AESContext.MODE_CBC_ENCRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer())
|
||||
encrypted = aes.update(data.to_utf8_buffer())
|
||||
aes.finish()
|
||||
# Decrypt CBC
|
||||
aes.start(AESContext.MODE_CBC_DECRYPT, key.to_utf8(), iv.to_utf8())
|
||||
aes.start(AESContext.MODE_CBC_DECRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer())
|
||||
decrypted = aes.update(encrypted)
|
||||
aes.finish()
|
||||
# Check CBC
|
||||
assert(decrypted == data.to_utf8())
|
||||
assert(decrypted == data.to_utf8_buffer())
|
||||
[/gdscript]
|
||||
[csharp]
|
||||
using Godot;
|
||||
@ -50,27 +50,27 @@
|
||||
string key = "My secret key!!!"; // Key must be either 16 or 32 bytes.
|
||||
string data = "My secret text!!"; // Data size must be multiple of 16 bytes, apply padding if needed.
|
||||
// Encrypt ECB
|
||||
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8());
|
||||
byte[] encrypted = _aes.Update(data.ToUtf8());
|
||||
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer());
|
||||
byte[] encrypted = _aes.Update(data.ToUtf8Buffer());
|
||||
_aes.Finish();
|
||||
// Decrypt ECB
|
||||
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8());
|
||||
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer());
|
||||
byte[] decrypted = _aes.Update(encrypted);
|
||||
_aes.Finish();
|
||||
// Check ECB
|
||||
Debug.Assert(decrypted == data.ToUtf8());
|
||||
Debug.Assert(decrypted == data.ToUtf8Buffer());
|
||||
|
||||
string iv = "My secret iv!!!!"; // IV must be of exactly 16 bytes.
|
||||
// Encrypt CBC
|
||||
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8(), iv.ToUtf8());
|
||||
encrypted = _aes.Update(data.ToUtf8());
|
||||
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer());
|
||||
encrypted = _aes.Update(data.ToUtf8Buffer());
|
||||
_aes.Finish();
|
||||
// Decrypt CBC
|
||||
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8(), iv.ToUtf8());
|
||||
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer());
|
||||
decrypted = _aes.Update(encrypted);
|
||||
_aes.Finish();
|
||||
// Check CBC
|
||||
Debug.Assert(decrypted == data.ToUtf8());
|
||||
Debug.Assert(decrypted == data.ToUtf8Buffer());
|
||||
}
|
||||
}
|
||||
[/csharp]
|
||||
|
@ -230,7 +230,7 @@
|
||||
</methods>
|
||||
<members>
|
||||
<member name="assigned_animation" type="String" setter="set_assigned_animation" getter="get_assigned_animation">
|
||||
If playing, the the current animation's key, otherwise, the animation last played. When set, this changes the animation, but will not play it unless already playing. See also [member current_animation].
|
||||
If playing, the current animation's key, otherwise, the animation last played. When set, this changes the animation, but will not play it unless already playing. See also [member current_animation].
|
||||
</member>
|
||||
<member name="audio_max_polyphony" type="int" setter="set_audio_max_polyphony" getter="get_audio_max_polyphony" default="32">
|
||||
The number of possible simultaneous sounds for each of the assigned AudioStreamPlayers.
|
||||
|
@ -128,7 +128,7 @@
|
||||
The magnitude of area-specific wind force.
|
||||
</member>
|
||||
<member name="wind_source_path" type="NodePath" setter="set_wind_source_path" getter="get_wind_source_path" default="NodePath("")">
|
||||
The [Node3D] which is used to specify the the direction and origin of an area-specific wind force. The direction is opposite to the z-axis of the [Node3D]'s local transform, and its origin is the origin of the [Node3D]'s local transform.
|
||||
The [Node3D] which is used to specify the direction and origin of an area-specific wind force. The direction is opposite to the z-axis of the [Node3D]'s local transform, and its origin is the origin of the [Node3D]'s local transform.
|
||||
</member>
|
||||
</members>
|
||||
<signals>
|
||||
|
@ -441,12 +441,23 @@
|
||||
<return type="Variant" />
|
||||
<description>
|
||||
Returns the maximum value contained in the array if all elements are of comparable types. If the elements can't be compared, [code]null[/code] is returned.
|
||||
To find the maximum value using a custom comparator, you can use [method reduce]. In this example every array element is checked and the first maximum value is returned:
|
||||
[codeblock]
|
||||
func _ready():
|
||||
var arr = [Vector2(0, 1), Vector2(2, 0), Vector2(1, 1), Vector2(1, 0), Vector2(0, 2)]
|
||||
# In this example we compare the lengths.
|
||||
print(arr.reduce(func(max, val): return val if is_length_greater(val, max) else max))
|
||||
|
||||
func is_length_greater(a, b):
|
||||
return a.length() > b.length()
|
||||
[/codeblock]
|
||||
</description>
|
||||
</method>
|
||||
<method name="min" qualifiers="const">
|
||||
<return type="Variant" />
|
||||
<description>
|
||||
Returns the minimum value contained in the array if all elements are of comparable types. If the elements can't be compared, [code]null[/code] is returned.
|
||||
See also [method max] for an example of using a custom comparator.
|
||||
</description>
|
||||
</method>
|
||||
<method name="pick_random" qualifiers="const">
|
||||
|
@ -76,14 +76,16 @@
|
||||
<method name="bind" qualifiers="vararg const">
|
||||
<return type="Callable" />
|
||||
<description>
|
||||
Returns a copy of this [Callable] with one or more arguments bound. When called, the bound arguments are passed [i]after[/i] the arguments supplied by [method call].
|
||||
Returns a copy of this [Callable] with one or more arguments bound. When called, the bound arguments are passed [i]after[/i] the arguments supplied by [method call]. See also [method unbind].
|
||||
[b]Note:[/b] When this method is chained with other similar methods, the order in which the argument list is modified is read from right to left.
|
||||
</description>
|
||||
</method>
|
||||
<method name="bindv">
|
||||
<return type="Callable" />
|
||||
<param index="0" name="arguments" type="Array" />
|
||||
<description>
|
||||
Returns a copy of this [Callable] with one or more arguments bound, reading them from an array. When called, the bound arguments are passed [i]after[/i] the arguments supplied by [method call].
|
||||
Returns a copy of this [Callable] with one or more arguments bound, reading them from an array. When called, the bound arguments are passed [i]after[/i] the arguments supplied by [method call]. See also [method unbind].
|
||||
[b]Note:[/b] When this method is chained with other similar methods, the order in which the argument list is modified is read from right to left.
|
||||
</description>
|
||||
</method>
|
||||
<method name="call" qualifiers="vararg const">
|
||||
@ -187,7 +189,13 @@
|
||||
<return type="Callable" />
|
||||
<param index="0" name="argcount" type="int" />
|
||||
<description>
|
||||
Returns a copy of this [Callable] with the arguments unbound, as defined by [param argcount]. Calling the returned [Callable] will call the method without the extra arguments that are supplied in the [Callable] on which you are calling this method.
|
||||
Returns a copy of this [Callable] with a number of arguments unbound. In other words, when the new callable is called the last few arguments supplied by the user are ignored, according to [param argcount]. The remaining arguments are passed to the callable. This allows to use the original callable in a context that attempts to pass more arguments than this callable can handle, e.g. a signal with a fixed number of arguments. See also [method bind].
|
||||
[b]Note:[/b] When this method is chained with other similar methods, the order in which the argument list is modified is read from right to left.
|
||||
[codeblock]
|
||||
func _ready():
|
||||
foo.unbind(1).call(1, 2) # Calls foo(1).
|
||||
foo.bind(3, 4).unbind(1).call(1, 2) # Calls foo(1, 3, 4), note that it does not change the arguments from bind.
|
||||
[/codeblock]
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
|
@ -937,10 +937,10 @@
|
||||
Tells Godot which node it should give focus to if the user presses the left arrow on the keyboard or left on a gamepad by default. You can change the key by editing the [member ProjectSettings.input/ui_left] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the left of this one.
|
||||
</member>
|
||||
<member name="focus_neighbor_right" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath("")">
|
||||
Tells Godot which node it should give focus to if the user presses the right arrow on the keyboard or right on a gamepad by default. You can change the key by editing the [member ProjectSettings.input/ui_right] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one.
|
||||
Tells Godot which node it should give focus to if the user presses the right arrow on the keyboard or right on a gamepad by default. You can change the key by editing the [member ProjectSettings.input/ui_right] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the right of this one.
|
||||
</member>
|
||||
<member name="focus_neighbor_top" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath("")">
|
||||
Tells Godot which node it should give focus to if the user presses the top arrow on the keyboard or top on a gamepad by default. You can change the key by editing the [member ProjectSettings.input/ui_up] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one.
|
||||
Tells Godot which node it should give focus to if the user presses the top arrow on the keyboard or top on a gamepad by default. You can change the key by editing the [member ProjectSettings.input/ui_up] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the top of this one.
|
||||
</member>
|
||||
<member name="focus_next" type="NodePath" setter="set_focus_next" getter="get_focus_next" default="NodePath("")">
|
||||
Tells Godot which node it should give focus to if the user presses [kbd]Tab[/kbd] on a keyboard by default. You can change the key by editing the [member ProjectSettings.input/ui_focus_next] input action.
|
||||
|
@ -24,7 +24,7 @@
|
||||
cert.save("user://generated.crt")
|
||||
# Encryption
|
||||
var data = "Some data"
|
||||
var encrypted = crypto.encrypt(key, data.to_utf8())
|
||||
var encrypted = crypto.encrypt(key, data.to_utf8_buffer())
|
||||
# Decryption
|
||||
var decrypted = crypto.decrypt(key, encrypted)
|
||||
# Signing
|
||||
@ -33,7 +33,7 @@
|
||||
var verified = crypto.verify(HashingContext.HASH_SHA256, data.sha256_buffer(), signature, key)
|
||||
# Checks
|
||||
assert(verified)
|
||||
assert(data.to_utf8() == decrypted)
|
||||
assert(data.to_utf8_buffer() == decrypted)
|
||||
[/gdscript]
|
||||
[csharp]
|
||||
using Godot;
|
||||
@ -56,7 +56,7 @@
|
||||
_cert.Save("user://generated.crt");
|
||||
// Encryption
|
||||
string data = "Some data";
|
||||
byte[] encrypted = _crypto.Encrypt(_key, data.ToUtf8());
|
||||
byte[] encrypted = _crypto.Encrypt(_key, data.ToUtf8Buffer());
|
||||
// Decryption
|
||||
byte[] decrypted = _crypto.Decrypt(_key, encrypted);
|
||||
// Signing
|
||||
@ -65,7 +65,7 @@
|
||||
bool verified = _crypto.Verify(HashingContext.HashType.Sha256, Data.Sha256Buffer(), signature, _key);
|
||||
// Checks
|
||||
Debug.Assert(verified);
|
||||
Debug.Assert(data.ToUtf8() == decrypted);
|
||||
Debug.Assert(data.ToUtf8Buffer() == decrypted);
|
||||
}
|
||||
}
|
||||
[/csharp]
|
||||
|
@ -138,7 +138,7 @@
|
||||
<param index="1" name="cubic" type="bool" default="false" />
|
||||
<param index="2" name="apply_tilt" type="bool" default="false" />
|
||||
<description>
|
||||
Similar with [code]interpolate_baked()[/code]. The the return value is [code]Transform3D[/code], with [code]origin[/code] as point position, [code]basis.x[/code] as sideway vector, [code]basis.y[/code] as up vector, [code]basis.z[/code] as forward vector. When the curve length is 0, there is no reasonable way to calculate the rotation, all vectors aligned with global space axes.
|
||||
Similar with [code]interpolate_baked()[/code]. The return value is [code]Transform3D[/code], with [code]origin[/code] as point position, [code]basis.x[/code] as sideway vector, [code]basis.y[/code] as up vector, [code]basis.z[/code] as forward vector. When the curve length is 0, there is no reasonable way to calculate the rotation, all vectors aligned with global space axes.
|
||||
</description>
|
||||
</method>
|
||||
<method name="samplef" qualifiers="const">
|
||||
|
@ -35,7 +35,7 @@
|
||||
if p.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
|
||||
while p.get_available_packet_count() > 0:
|
||||
print("Received message from client: %s" % p.get_packet().get_string_from_utf8())
|
||||
p.put_packet("Hello DTLS client".to_utf8())
|
||||
p.put_packet("Hello DTLS client".to_utf8_buffer())
|
||||
[/gdscript]
|
||||
[csharp]
|
||||
// ServerNode.cs
|
||||
@ -77,7 +77,7 @@
|
||||
while (p.GetAvailablePacketCount() > 0)
|
||||
{
|
||||
GD.Print($"Received Message From Client: {p.GetPacket().GetStringFromUtf8()}");
|
||||
p.PutPacket("Hello DTLS Client".ToUtf8());
|
||||
p.PutPacket("Hello DTLS Client".ToUtf8Buffer());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,7 +103,7 @@
|
||||
if dtls.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
|
||||
if !connected:
|
||||
# Try to contact server
|
||||
dtls.put_packet("The answer is... 42!".to_utf8())
|
||||
dtls.put_packet("The answer is... 42!".to_utf8_buffer())
|
||||
while dtls.get_available_packet_count() > 0:
|
||||
print("Connected: %s" % dtls.get_packet().get_string_from_utf8())
|
||||
connected = true
|
||||
@ -133,7 +133,7 @@
|
||||
if (!_connected)
|
||||
{
|
||||
// Try to contact server
|
||||
_dtls.PutPacket("The Answer Is..42!".ToUtf8());
|
||||
_dtls.PutPacket("The Answer Is..42!".ToUtf8Buffer());
|
||||
}
|
||||
while (_dtls.GetAvailablePacketCount() > 0)
|
||||
{
|
||||
|
@ -1575,7 +1575,7 @@
|
||||
Default landscape orientation.
|
||||
</constant>
|
||||
<constant name="SCREEN_PORTRAIT" value="1" enum="ScreenOrientation">
|
||||
Default portrait orienstation.
|
||||
Default portrait orientation.
|
||||
</constant>
|
||||
<constant name="SCREEN_REVERSE_LANDSCAPE" value="2" enum="ScreenOrientation">
|
||||
Reverse landscape orientation (upside down).
|
||||
@ -1711,7 +1711,7 @@
|
||||
The window can't be focused. No-focus window will ignore all input, except mouse clicks.
|
||||
</constant>
|
||||
<constant name="WINDOW_FLAG_POPUP" value="5" enum="WindowFlags">
|
||||
Window is part of menu or [OptionButton] dropdown. This flag can't be changed when the window is visible. An active popup window will exclusively receive all input, without stealing focus from its parent. Popup windows are automatically closed when uses click outside it, or when an application is switched. Popup window must have [code]transient parent[/code] set (see [method window_set_transient]).
|
||||
Window is part of menu or [OptionButton] dropdown. This flag can't be changed when the window is visible. An active popup window will exclusively receive all input, without stealing focus from its parent. Popup windows are automatically closed when uses click outside it, or when an application is switched. Popup window must have transient parent set (see [method window_set_transient]).
|
||||
</constant>
|
||||
<constant name="WINDOW_FLAG_EXTEND_TO_TITLE" value="6" enum="WindowFlags">
|
||||
Window content is expanded to the full size of the window. Unlike borderless window, the frame is left intact and can be used to resize the window, title bar is transparent, but have minimize/maximize/close buttons.
|
||||
|
@ -54,7 +54,7 @@
|
||||
</methods>
|
||||
<members>
|
||||
<member name="access" type="int" setter="set_access" getter="get_access" enum="FileDialog.Access" default="0">
|
||||
The file system access scope. See enum [code]Access[/code] constants.
|
||||
The file system access scope. See [enum Access] constants.
|
||||
[b]Warning:[/b] Currently, in sandboxed environments such as Web builds or sandboxed macOS apps, FileDialog cannot access the host file system. See [url=https://github.com/godotengine/godot-proposals/issues/1123]godot-proposals#1123[/url].
|
||||
</member>
|
||||
<member name="current_dir" type="String" setter="set_current_dir" getter="get_current_dir">
|
||||
@ -74,7 +74,7 @@
|
||||
The available file type filters. For example, this shows only [code].png[/code] and [code].gd[/code] files: [code]set_filters(PackedStringArray(["*.png ; PNG Images","*.gd ; GDScript Files"]))[/code]. Multiple file types can also be specified in a single filter. [code]"*.png, *.jpg, *.jpeg ; Supported Images"[/code] will show both PNG and JPEG files when selected.
|
||||
</member>
|
||||
<member name="mode_overrides_title" type="bool" setter="set_mode_overrides_title" getter="is_mode_overriding_title" default="true">
|
||||
If [code]true[/code], changing the [code]Mode[/code] property will set the window title accordingly (e.g. setting mode to [constant FILE_MODE_OPEN_FILE] will change the window title to "Open a File").
|
||||
If [code]true[/code], changing the [member file_mode] property will set the window title accordingly (e.g. setting [member file_mode] to [constant FILE_MODE_OPEN_FILE] will change the window title to "Open a File").
|
||||
</member>
|
||||
<member name="root_subfolder" type="String" setter="set_root_subfolder" getter="get_root_subfolder" default="""">
|
||||
If non-empty, the given sub-folder will be "root" of this [FileDialog], i.e. user won't be able to go to its parent directory.
|
||||
|
@ -11,11 +11,11 @@
|
||||
var ctx = HMACContext.new()
|
||||
|
||||
func _ready():
|
||||
var key = "supersecret".to_utf8()
|
||||
var key = "supersecret".to_utf8_buffer()
|
||||
var err = ctx.start(HashingContext.HASH_SHA256, key)
|
||||
assert(err == OK)
|
||||
var msg1 = "this is ".to_utf8()
|
||||
var msg2 = "super duper secret".to_utf8()
|
||||
var msg1 = "this is ".to_utf8_buffer()
|
||||
var msg2 = "super duper secret".to_utf8_buffer()
|
||||
err = ctx.update(msg1)
|
||||
assert(err == OK)
|
||||
err = ctx.update(msg2)
|
||||
@ -34,11 +34,11 @@
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
byte[] key = "supersecret".ToUtf8();
|
||||
byte[] key = "supersecret".ToUtf8Buffer();
|
||||
Error err = _ctx.Start(HashingContext.HashType.Sha256, key);
|
||||
Debug.Assert(err == Error.Ok);
|
||||
byte[] msg1 = "this is ".ToUtf8();
|
||||
byte[] msg2 = "super duper secret".ToUtf8();
|
||||
byte[] msg1 = "this is ".ToUtf8Buffer();
|
||||
byte[] msg2 = "super duper secret".ToUtf8Buffer();
|
||||
err = _ctx.Update(msg1);
|
||||
Debug.Assert(err == Error.Ok);
|
||||
err = _ctx.Update(msg2);
|
||||
|
@ -78,7 +78,7 @@
|
||||
<param index="2" name="astc_format" type="int" enum="Image.ASTCFormat" default="0" />
|
||||
<description>
|
||||
Compresses the image to use less memory. Can not directly access pixel data while the image is compressed. Returns error if the chosen compression mode is not available.
|
||||
The [param mode] parameter helps to pick the best compression method for DXT and ETC2 formats. It is ignored for ASTC compression.
|
||||
The [param source] parameter helps to pick the best compression method for DXT and ETC2 formats. It is ignored for ASTC compression.
|
||||
For ASTC compression, the [param astc_format] parameter must be supplied.
|
||||
</description>
|
||||
</method>
|
||||
@ -714,6 +714,12 @@
|
||||
<constant name="COMPRESS_BPTC" value="3" enum="CompressMode">
|
||||
Use BPTC compression.
|
||||
</constant>
|
||||
<constant name="COMPRESS_ASTC" value="4" enum="CompressMode">
|
||||
Use ASTC compression.
|
||||
</constant>
|
||||
<constant name="COMPRESS_MAX" value="5" enum="CompressMode">
|
||||
Represents the size of the [enum CompressMode] enum.
|
||||
</constant>
|
||||
<constant name="USED_CHANNELS_L" value="0" enum="UsedChannels">
|
||||
</constant>
|
||||
<constant name="USED_CHANNELS_LA" value="1" enum="UsedChannels">
|
||||
|
@ -10,7 +10,7 @@
|
||||
For two regions to be connected to each other, they must share a similar edge. An edge is considered connected to another if both of its two vertices are at a distance less than [code]edge_connection_margin[/code] to the respective other edge's vertex.
|
||||
You may assign navigation layers to regions with [method NavigationServer2D.region_set_navigation_layers], which then can be checked upon when requesting a path with [method NavigationServer2D.map_get_path]. This allows allowing or forbidding some areas to 2D objects.
|
||||
To use the collision avoidance system, you may use agents. You can set an agent's target velocity, then the servers will emit a callback with a modified velocity.
|
||||
[b]Note:[/b] The collision avoidance system ignores regions. Using the modified velocity as-is might lead to pushing and agent outside of a navigable area. This is a limitation of the collision avoidance system, any more complex situation may require the use of the physics engine.
|
||||
[b]Note:[/b] The collision avoidance system ignores regions. Using the modified velocity as-is might lead to pushing an agent outside of a navigable area. This is a limitation of the collision avoidance system, any more complex situation may require the use of the physics engine.
|
||||
This server keeps tracks of any call and executes them during the sync phase. This means that you can request any change to the map, using any thread, without worrying.
|
||||
</description>
|
||||
<tutorials>
|
||||
|
@ -662,7 +662,7 @@
|
||||
<return type="bool" />
|
||||
<param index="0" name="method" type="StringName" />
|
||||
<description>
|
||||
Returns [code]true[/code] if the the given [param method] name exists in the object.
|
||||
Returns [code]true[/code] if the given [param method] name exists in the object.
|
||||
[b]Note:[/b] In C#, [param method] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]MethodName[/code] class to avoid allocating a new [StringName] on each call.
|
||||
</description>
|
||||
</method>
|
||||
|
@ -112,7 +112,7 @@
|
||||
socket = PacketPeerUDP.new()
|
||||
# Server
|
||||
socket.set_dest_address("127.0.0.1", 789)
|
||||
socket.put_packet("Time to stop".to_ascii())
|
||||
socket.put_packet("Time to stop".to_ascii_buffer())
|
||||
|
||||
# Client
|
||||
while socket.wait() == OK:
|
||||
@ -124,7 +124,7 @@
|
||||
var socket = new PacketPeerUDP();
|
||||
// Server
|
||||
socket.SetDestAddress("127.0.0.1", 789);
|
||||
socket.PutPacket("Time to stop".ToAscii());
|
||||
socket.PutPacket("Time to stop".ToAsciiBuffer());
|
||||
|
||||
// Client
|
||||
while (socket.Wait() == OK)
|
||||
|
@ -1004,7 +1004,7 @@
|
||||
macOS specific override for the shortcut to add a caret below every caret.
|
||||
</member>
|
||||
<member name="input/ui_text_caret_document_end" type="Dictionary" setter="" getter="">
|
||||
Default [InputEventAction] to move the text cursor the the end of the text.
|
||||
Default [InputEventAction] to move the text cursor to the end of the text.
|
||||
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
|
||||
</member>
|
||||
<member name="input/ui_text_caret_document_end.macos" type="Dictionary" setter="" getter="">
|
||||
@ -2384,7 +2384,7 @@
|
||||
[b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor (see [member application/config/use_hidden_project_data_directory]).
|
||||
</member>
|
||||
<member name="rendering/textures/vram_compression/import_s3tc_bptc" type="bool" setter="" getter="">
|
||||
If [code]true[/code], the texture importer will import VRAM-compressed textures using the S3 Texture Compression algorithm (DXT1-5) for lower quality textures and the the BPTC algorithm (BC6H and BC7) for high quality textures. This algorithm is only supported on PC desktop platforms and consoles.
|
||||
If [code]true[/code], the texture importer will import VRAM-compressed textures using the S3 Texture Compression algorithm (DXT1-5) for lower quality textures and the BPTC algorithm (BC6H and BC7) for high quality textures. This algorithm is only supported on PC desktop platforms and consoles.
|
||||
[b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor (see [member application/config/use_hidden_project_data_directory]).
|
||||
</member>
|
||||
<member name="rendering/textures/webp_compression/compression_method" type="int" setter="" getter="" default="2">
|
||||
|
@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="Quaternion" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
Quaternion.
|
||||
A unit quaternion used for representing 3D rotations.
|
||||
</brief_description>
|
||||
<description>
|
||||
A unit quaternion used for representing 3D rotations. Quaternions need to be normalized to be used for rotation.
|
||||
It is similar to Basis, which implements matrix representation of rotations, and can be parametrized using both an axis-angle pair or Euler angles. Basis stores rotation, scale, and shearing, while Quaternion only stores rotation.
|
||||
Due to its compactness and the way it is stored in memory, certain operations (obtaining axis-angle and performing SLERP, in particular) are more efficient and robust against floating-point errors.
|
||||
Quaternions are similar to [Basis], which implements the matrix representation of rotations. Unlike [Basis], which stores rotation, scale, and shearing, quaternions only store rotation.
|
||||
Quaternions can be parametrized using both an axis-angle pair or Euler angles. Due to their compactness and the way they are stored in memory, certain operations (obtaining axis-angle and performing SLERP, in particular) are more efficient and robust against floating-point errors.
|
||||
[b]Note:[/b] Quaternions need to be normalized before being used for rotation.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Using 3D transforms">$DOCS_URL/tutorials/3d/using_transforms.html#interpolating-with-quaternions</link>
|
||||
|
@ -1852,7 +1852,7 @@
|
||||
<method name="lightmap_create">
|
||||
<return type="RID" />
|
||||
<description>
|
||||
Creates a lightmap GI and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]instance_*[/code] RenderingServer functions.
|
||||
Creates a lightmap GI and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]lightmap_*[/code] RenderingServer functions.
|
||||
Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
|
||||
This is the internal equivalent of the [LightmapGI] node.
|
||||
</description>
|
||||
@ -4171,10 +4171,10 @@
|
||||
<constant name="FOG_VOLUME_SHAPE_MAX" value="5" enum="FogVolumeShape">
|
||||
</constant>
|
||||
<constant name="VIEWPORT_SCALING_3D_MODE_BILINEAR" value="0" enum="ViewportScaling3DMode">
|
||||
Use bilinear scaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less then [code]1.0[/code] will result in undersampling while values greater than [code]1.0[/code] will result in supersampling. A value of [code]1.0[/code] disables scaling.
|
||||
Use bilinear scaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less than [code]1.0[/code] will result in undersampling while values greater than [code]1.0[/code] will result in supersampling. A value of [code]1.0[/code] disables scaling.
|
||||
</constant>
|
||||
<constant name="VIEWPORT_SCALING_3D_MODE_FSR" value="1" enum="ViewportScaling3DMode">
|
||||
Use AMD FidelityFX Super Resolution 1.0 upscaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less then [code]1.0[/code] will be result in the viewport being upscaled using FSR. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] disables scaling.
|
||||
Use AMD FidelityFX Super Resolution 1.0 upscaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less than [code]1.0[/code] will be result in the viewport being upscaled using FSR. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] disables scaling.
|
||||
</constant>
|
||||
<constant name="VIEWPORT_SCALING_3D_MODE_MAX" value="2" enum="ViewportScaling3DMode">
|
||||
</constant>
|
||||
|
@ -361,7 +361,7 @@
|
||||
The option is local to the location of the code completion query - e.g. a local variable.
|
||||
</constant>
|
||||
<constant name="LOCATION_PARENT_MASK" value="256" enum="CodeCompletionLocation">
|
||||
The option is from the containing class or a parent class, relative to the location of the code completion query. Perform a bitwise OR with the class depth (e.g. 0 for the local class, 1 for the parent, 2 for the grandparent, etc) to store the depth of an option in a the class or a parent class.
|
||||
The option is from the containing class or a parent class, relative to the location of the code completion query. Perform a bitwise OR with the class depth (e.g. 0 for the local class, 1 for the parent, 2 for the grandparent, etc) to store the depth of an option in the class or a parent class.
|
||||
</constant>
|
||||
<constant name="LOCATION_OTHER_USER_CODE" value="512" enum="CodeCompletionLocation">
|
||||
The option is from user code which is not local and not in a derived class (e.g. Autoload Singletons).
|
||||
|
@ -5,7 +5,7 @@
|
||||
</brief_description>
|
||||
<description>
|
||||
Shape casting allows to detect collision objects by sweeping the [member shape] along the cast direction determined by [member target_position] (useful for things like beam weapons).
|
||||
Immediate collision overlaps can be done with the [member target_position] set to [code]Vector2(0, 0)[/code] and by calling [method force_shapecast_update] within the same [b]physics_frame[/b]. This also helps to overcome some limitations of [Area2D] when used as a continuous detection area, often requiring waiting a couple of frames before collision information is available to [Area2D] nodes, and when using the signals creates unnecessary complexity.
|
||||
Immediate collision overlaps can be done with the [member target_position] set to [code]Vector2(0, 0)[/code] and by calling [method force_shapecast_update] within the same [b]physics frame[/b]. This also helps to overcome some limitations of [Area2D] when used as a continuous detection area, often requiring waiting a couple of frames before collision information is available to [Area2D] nodes, and when using the signals creates unnecessary complexity.
|
||||
The node can detect multiple collision objects, but it's usually used to detect the first collision.
|
||||
[b]Note:[/b] shape casting is more computationally expensive compared to ray casting.
|
||||
</description>
|
||||
|
@ -5,7 +5,7 @@
|
||||
</brief_description>
|
||||
<description>
|
||||
Shape casting allows to detect collision objects by sweeping the [member shape] along the cast direction determined by [member target_position] (useful for things like beam weapons).
|
||||
Immediate collision overlaps can be done with the [member target_position] set to [code]Vector3(0, 0, 0)[/code] and by calling [method force_shapecast_update] within the same [b]physics_frame[/b]. This also helps to overcome some limitations of [Area3D] when used as a continuous detection area, often requiring waiting a couple of frames before collision information is available to [Area3D] nodes, and when using the signals creates unnecessary complexity.
|
||||
Immediate collision overlaps can be done with the [member target_position] set to [code]Vector3(0, 0, 0)[/code] and by calling [method force_shapecast_update] within the same [b]physics frame[/b]. This also helps to overcome some limitations of [Area3D] when used as a continuous detection area, often requiring waiting a couple of frames before collision information is available to [Area3D] nodes, and when using the signals creates unnecessary complexity.
|
||||
The node can detect multiple collision objects, but it's usually used to detect the first collision.
|
||||
[b]Note:[/b] Shape casting is more computationally expensive compared to ray casting.
|
||||
</description>
|
||||
|
@ -5,7 +5,7 @@
|
||||
</brief_description>
|
||||
<description>
|
||||
This [SkeletonModification2D] uses an algorithm called Forward And Backward Reaching Inverse Kinematics, or FABRIK, to rotate a bone chain so that it reaches a target.
|
||||
FABRIK works by knowing the positions and lengths of a series of bones, typically called a "bone chain". It first starts by running a forward pass, which places the final bone at the target's position. Then all other bones are moved towards the tip bone, so they stay at the defined bone length away. Then a backwards pass is performed, where the root/first bone in the FABRIK chain is placed back at the origin. then all other bones are moved so they stay at the defined bone length away. This positions the bone chain so that it reaches the target when possible, but all of the bones stay the correct length away from each other.
|
||||
FABRIK works by knowing the positions and lengths of a series of bones, typically called a "bone chain". It first starts by running a forward pass, which places the final bone at the target's position. Then all other bones are moved towards the tip bone, so they stay at the defined bone length away. Then a backwards pass is performed, where the root/first bone in the FABRIK chain is placed back at the origin. Then all other bones are moved so they stay at the defined bone length away. This positions the bone chain so that it reaches the target when possible, but all of the bones stay the correct length away from each other.
|
||||
Because of how FABRIK works, it often gives more natural results than those seen in [SkeletonModification2DCCDIK]. FABRIK also supports angle constraints, which are fully taken into account when solving.
|
||||
[b]Note:[/b] The FABRIK modifier has [code]fabrik_joints[/code], which are the data objects that hold the data for each joint in the FABRIK chain. This is different from [Bone2D] nodes! FABRIK joints hold the data needed for each [Bone2D] in the bone chain used by FABRIK.
|
||||
To help control how the FABRIK joints move, a magnet vector can be passed, which can nudge the bones in a certain direction prior to solving, giving a level of control over the final result.
|
||||
|
@ -13,7 +13,7 @@
|
||||
<method name="fetch_physical_bones">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Empties the list of [PhysicalBone2D] nodes and populates it will all [PhysicalBone2D] nodes that are children of the [Skeleton2D].
|
||||
Empties the list of [PhysicalBone2D] nodes and populates it with all [PhysicalBone2D] nodes that are children of the [Skeleton2D].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_physical_bone_node" qualifiers="const">
|
||||
|
@ -177,10 +177,10 @@
|
||||
[b]Note:[/b] To put an ASCII string without prepending its size, you can use [method put_data]:
|
||||
[codeblocks]
|
||||
[gdscript]
|
||||
put_data("Hello world".to_ascii())
|
||||
put_data("Hello world".to_ascii_buffer())
|
||||
[/gdscript]
|
||||
[csharp]
|
||||
PutData("Hello World".ToAscii());
|
||||
PutData("Hello World".ToAsciiBuffer());
|
||||
[/csharp]
|
||||
[/codeblocks]
|
||||
</description>
|
||||
@ -221,10 +221,10 @@
|
||||
[b]Note:[/b] To put an UTF-8 string without prepending its size, you can use [method put_data]:
|
||||
[codeblocks]
|
||||
[gdscript]
|
||||
put_data("Hello world".to_utf8())
|
||||
put_data("Hello world".to_utf8_buffer())
|
||||
[/gdscript]
|
||||
[csharp]
|
||||
PutData("Hello World".ToUtf8());
|
||||
PutData("Hello World".ToUtf8Buffer());
|
||||
[/csharp]
|
||||
[/codeblocks]
|
||||
</description>
|
||||
|
@ -103,8 +103,9 @@
|
||||
Antialiasing draws a small ring around the edges, which fades to transparency. As a result, edges look much smoother. This is only noticeable when using rounded corners or [member skew].
|
||||
[b]Note:[/b] When using beveled corners with 45-degree angles ([member corner_detail] = 1), it is recommended to set [member anti_aliasing] to [code]false[/code] to ensure crisp visuals and avoid possible visual glitches.
|
||||
</member>
|
||||
<member name="anti_aliasing_size" type="float" setter="set_aa_size" getter="get_aa_size" default="0.625">
|
||||
This changes the size of the faded ring. Higher values can be used to achieve a "blurry" effect.
|
||||
<member name="anti_aliasing_size" type="float" setter="set_aa_size" getter="get_aa_size" default="1.0">
|
||||
This changes the size of the antialiasing effect. [code]1.0[/code] is recommended for an optimal result at 100% scale, identical to how rounded rectangles are rendered in web browsers and most vector drawing software.
|
||||
[b]Note:[/b] Higher values may produce a blur effect but can also create undesired artifacts on small boxes with large-radius corners.
|
||||
</member>
|
||||
<member name="bg_color" type="Color" setter="set_bg_color" getter="get_bg_color" default="Color(0.6, 0.6, 0.6, 1)">
|
||||
The background color of the stylebox.
|
||||
|
@ -242,6 +242,7 @@
|
||||
<param index="0" name="index" type="int" />
|
||||
<description>
|
||||
Specifies the smooth group to use for the [i]next[/i] vertex. If this is never called, all vertices will have the default smooth group of [code]0[/code] and will be smoothed with adjacent vertices of the same group. To produce a mesh with flat normals, set the smooth group to [code]-1[/code].
|
||||
[b]Note:[/b] This function actually takes an [code]uint32_t[/code], so C# users should use [code]uint32.MaxValue[/code] instead of [code]-1[/code] to produce a mesh with flat normals.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_tangent">
|
||||
|
@ -197,7 +197,7 @@
|
||||
Sets the maximum width which all tabs should be limited to. Unlimited if set to [code]0[/code].
|
||||
</member>
|
||||
<member name="scroll_to_selected" type="bool" setter="set_scroll_to_selected" getter="get_scroll_to_selected" default="true">
|
||||
If [code]true[/code], the tab offset will be changed to keep the the currently selected tab visible.
|
||||
If [code]true[/code], the tab offset will be changed to keep the currently selected tab visible.
|
||||
</member>
|
||||
<member name="scrolling_enabled" type="bool" setter="set_scrolling_enabled" getter="get_scrolling_enabled" default="true">
|
||||
if [code]true[/code], the mouse's scroll wheel can be used to navigate the scroll view.
|
||||
|
@ -1007,7 +1007,7 @@
|
||||
<return type="bool" />
|
||||
<param index="0" name="string" type="String" />
|
||||
<description>
|
||||
Returns [code]true[/code] is [param string] is a valid identifier.
|
||||
Returns [code]true[/code] if [param string] is a valid identifier.
|
||||
If the text server supports the [constant FEATURE_UNICODE_IDENTIFIERS] feature, a valid identifier must:
|
||||
- Conform to normalization form C.
|
||||
- Begin with a Unicode character of class XID_Start or [code]"_"[/code].
|
||||
@ -1775,6 +1775,9 @@
|
||||
<constant name="GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL" value="2048" enum="GraphemeFlag" is_bitfield="true">
|
||||
It is safe to insert a U+0640 before this grapheme for elongation.
|
||||
</constant>
|
||||
<constant name="GRAPHEME_IS_EMBEDDED_OBJECT" value="4096" enum="GraphemeFlag" is_bitfield="true">
|
||||
Grapheme is an object replacement character for the embedded object.
|
||||
</constant>
|
||||
<constant name="HINTING_NONE" value="0" enum="Hinting">
|
||||
Disables font hinting (smoother but less crisp).
|
||||
</constant>
|
||||
|
@ -22,7 +22,7 @@
|
||||
<method name="_get_height" qualifiers="virtual const">
|
||||
<return type="int" />
|
||||
<description>
|
||||
Called when the the [TextureLayered]'s height is queried.
|
||||
Called when the [TextureLayered]'s height is queried.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_layer_data" qualifiers="virtual const">
|
||||
|
@ -67,7 +67,7 @@
|
||||
<param index="1" name="atlas_source_id_override" type="int" default="-1" />
|
||||
<description>
|
||||
Adds a [TileSetSource] to the TileSet. If [param atlas_source_id_override] is not -1, also set its source ID. Otherwise, a unique identifier is automatically generated.
|
||||
The function returns the added source source ID or -1 if the source could not be added.
|
||||
The function returns the added source ID or -1 if the source could not be added.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_terrain">
|
||||
@ -578,7 +578,7 @@
|
||||
<param index="0" name="source_from" type="int" />
|
||||
<param index="1" name="source_to" type="int" />
|
||||
<description>
|
||||
Creates a source-level proxy for the given source ID. A proxy will map set of tile identifiers to another set of identifiers. Both the atlac coordinates ID and the alternative tile ID are kept the same when using source-level proxies.
|
||||
Creates a source-level proxy for the given source ID. A proxy will map set of tile identifiers to another set of identifiers. Both the atlas coordinates ID and the alternative tile ID are kept the same when using source-level proxies.
|
||||
This can be used to replace a source in all TileMaps using this TileSet, as TileMap nodes will find and use the proxy's target source when one is available.
|
||||
Proxied tiles can be automatically replaced in TileMap nodes using the editor.
|
||||
</description>
|
||||
|
@ -86,7 +86,7 @@
|
||||
func _process(delta):
|
||||
if !connected:
|
||||
# Try to contact server
|
||||
udp.put_packet("The answer is... 42!".to_utf8())
|
||||
udp.put_packet("The answer is... 42!".to_utf8_buffer())
|
||||
if udp.get_available_packet_count() > 0:
|
||||
print("Connected: %s" % udp.get_packet().get_string_from_utf8())
|
||||
connected = true
|
||||
@ -110,7 +110,7 @@
|
||||
if (!_connected)
|
||||
{
|
||||
// Try to contact server
|
||||
_udp.PutPacket("The Answer Is..42!".ToUtf8());
|
||||
_udp.PutPacket("The Answer Is..42!".ToUtf8Buffer());
|
||||
}
|
||||
if (_udp.GetAvailablePacketCount() > 0)
|
||||
{
|
||||
|
@ -214,7 +214,7 @@
|
||||
<return type="bool" />
|
||||
<param index="0" name="to" type="Vector2" />
|
||||
<description>
|
||||
Returns [code]true[/code] if this vector and [code]v[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
|
||||
Returns [code]true[/code] if this vector and [param to] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_finite" qualifiers="const">
|
||||
@ -288,7 +288,7 @@
|
||||
<return type="Vector2" />
|
||||
<description>
|
||||
Returns the result of scaling the vector to unit length. Equivalent to [code]v / v.length()[/code]. See also [method is_normalized].
|
||||
[b]Note:[/b] This function may return incorrect values if the initial vector length is near zero.
|
||||
[b]Note:[/b] This function may return incorrect values if the input vector length is near zero.
|
||||
</description>
|
||||
</method>
|
||||
<method name="orthogonal" qualifiers="const">
|
||||
|
@ -159,7 +159,7 @@
|
||||
<return type="Vector2i" />
|
||||
<param index="0" name="right" type="int" />
|
||||
<description>
|
||||
Gets the remainder of each component of the [Vector2i] with the the given [int]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
|
||||
Gets the remainder of each component of the [Vector2i] with the given [int]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
|
||||
[codeblock]
|
||||
print(Vector2i(10, -20) % 7) # Prints "(3, -6)"
|
||||
[/codeblock]
|
||||
|
@ -166,7 +166,7 @@
|
||||
<return type="Vector3i" />
|
||||
<param index="0" name="right" type="int" />
|
||||
<description>
|
||||
Gets the remainder of each component of the [Vector3i] with the the given [int]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
|
||||
Gets the remainder of each component of the [Vector3i] with the given [int]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
|
||||
[codeblock]
|
||||
print(Vector3i(10, -20, 30) % 7) # Prints "(3, -6, 2)"
|
||||
[/codeblock]
|
||||
|
@ -131,9 +131,9 @@
|
||||
</method>
|
||||
<method name="is_equal_approx" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<param index="0" name="with" type="Vector4" />
|
||||
<param index="0" name="to" type="Vector4" />
|
||||
<description>
|
||||
Returns [code]true[/code] if this vector and [param with] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
|
||||
Returns [code]true[/code] if this vector and [param to] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_finite" qualifiers="const">
|
||||
@ -164,7 +164,8 @@
|
||||
<method name="length_squared" qualifiers="const">
|
||||
<return type="float" />
|
||||
<description>
|
||||
Returns the squared length (squared magnitude) of this vector. This method runs faster than [method length].
|
||||
Returns the squared length (squared magnitude) of this vector.
|
||||
This method runs faster than [method length], so prefer it if you need to compare vectors or need the squared distance for some formula.
|
||||
</description>
|
||||
</method>
|
||||
<method name="lerp" qualifiers="const">
|
||||
@ -198,14 +199,14 @@
|
||||
<return type="Vector4" />
|
||||
<param index="0" name="mod" type="float" />
|
||||
<description>
|
||||
Returns a new vector composed of the [method @GlobalScope.fposmod] of this vector's components and [param mod].
|
||||
Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [param mod].
|
||||
</description>
|
||||
</method>
|
||||
<method name="posmodv" qualifiers="const">
|
||||
<return type="Vector4" />
|
||||
<param index="0" name="modv" type="Vector4" />
|
||||
<description>
|
||||
Returns a new vector composed of the [method @GlobalScope.fposmod] of this vector's components and [param modv]'s components.
|
||||
Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [param modv]'s components.
|
||||
</description>
|
||||
</method>
|
||||
<method name="round" qualifiers="const">
|
||||
|
@ -65,7 +65,8 @@
|
||||
<method name="length_squared" qualifiers="const">
|
||||
<return type="int" />
|
||||
<description>
|
||||
Returns the squared length (squared magnitude) of this vector. This method runs faster than [method length].
|
||||
Returns the squared length (squared magnitude) of this vector.
|
||||
This method runs faster than [method length], so prefer it if you need to compare vectors or need the squared distance for some formula.
|
||||
</description>
|
||||
</method>
|
||||
<method name="max_axis_index" qualifiers="const">
|
||||
|
@ -258,7 +258,7 @@
|
||||
If [code]true[/code], the GUI controls on the viewport will lay pixel perfectly.
|
||||
</member>
|
||||
<member name="handle_input_locally" type="bool" setter="set_handle_input_locally" getter="is_handling_input_locally" default="true">
|
||||
If [code]true[/code], this viewport will mark incoming input events as handled by itself. If [code]false[/code], this is instead done by the the first parent viewport that is set to handle input locally.
|
||||
If [code]true[/code], this viewport will mark incoming input events as handled by itself. If [code]false[/code], this is instead done by the first parent viewport that is set to handle input locally.
|
||||
A [SubViewportContainer] will automatically set this property to [code]false[/code] for the [Viewport] contained inside of it.
|
||||
See also [method set_input_as_handled] and [method is_input_handled].
|
||||
</member>
|
||||
@ -410,10 +410,10 @@
|
||||
Represents the size of the [enum PositionalShadowAtlasQuadrantSubdiv] enum.
|
||||
</constant>
|
||||
<constant name="SCALING_3D_MODE_BILINEAR" value="0" enum="Scaling3DMode">
|
||||
Use bilinear scaling for the viewport's 3D buffer. The amount of scaling can be set using [member scaling_3d_scale]. Values less then [code]1.0[/code] will result in undersampling while values greater than [code]1.0[/code] will result in supersampling. A value of [code]1.0[/code] disables scaling.
|
||||
Use bilinear scaling for the viewport's 3D buffer. The amount of scaling can be set using [member scaling_3d_scale]. Values less than [code]1.0[/code] will result in undersampling while values greater than [code]1.0[/code] will result in supersampling. A value of [code]1.0[/code] disables scaling.
|
||||
</constant>
|
||||
<constant name="SCALING_3D_MODE_FSR" value="1" enum="Scaling3DMode">
|
||||
Use AMD FidelityFX Super Resolution 1.0 upscaling for the viewport's 3D buffer. The amount of scaling can be set using [member scaling_3d_scale]. Values less then [code]1.0[/code] will be result in the viewport being upscaled using FSR. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] disables scaling.
|
||||
Use AMD FidelityFX Super Resolution 1.0 upscaling for the viewport's 3D buffer. The amount of scaling can be set using [member scaling_3d_scale]. Values less than [code]1.0[/code] will be result in the viewport being upscaled using FSR. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] disables scaling.
|
||||
</constant>
|
||||
<constant name="SCALING_3D_MODE_MAX" value="2" enum="Scaling3DMode">
|
||||
Represents the size of the [enum Scaling3DMode] enum.
|
||||
|
@ -58,7 +58,7 @@
|
||||
<members>
|
||||
<member name="layers" type="int" setter="set_layer_mask" getter="get_layer_mask" default="1">
|
||||
The render layer(s) this [VisualInstance3D] is drawn on.
|
||||
This object will only be visible for [Camera3D]s whose cull mask includes the render object this [VisualInstance3D] is set to.
|
||||
This object will only be visible for [Camera3D]s whose cull mask includes any of the render layers this [VisualInstance3D] is set to.
|
||||
For [Light3D]s, this can be used to control which [VisualInstance3D]s are affected by a specific light. For [GPUParticles3D], this can be used to control which particles are effected by a specific attractor. For [Decal]s, this can be used to control which [VisualInstance3D]s are affected by a specific decal.
|
||||
</member>
|
||||
<member name="sorting_offset" type="float" setter="set_sorting_offset" getter="get_sorting_offset" default="0.0">
|
||||
|
@ -19,7 +19,7 @@
|
||||
Sets the texture repeating mode. See [enum TextureRepeat] for options.
|
||||
</member>
|
||||
<member name="texture_source" type="int" setter="set_texture_source" getter="get_texture_source" enum="VisualShaderNodeTextureParameter.TextureSource" default="0">
|
||||
Sets the texture source mode. Used for reading from the screen, depth, or normal_roughness texture. see [enum TextureSource] for options.
|
||||
Sets the texture source mode. Used for reading from the screen, depth, or normal_roughness texture. See [enum TextureSource] for options.
|
||||
</member>
|
||||
<member name="texture_type" type="int" setter="set_texture_type" getter="get_texture_type" enum="VisualShaderNodeTextureParameter.TextureType" default="0">
|
||||
Defines the type of data provided by the source texture. See [enum TextureType] for options.
|
||||
|
@ -730,7 +730,7 @@
|
||||
The window can't be focused. No-focus window will ignore all input, except mouse clicks. Set with [member unfocusable].
|
||||
</constant>
|
||||
<constant name="FLAG_POPUP" value="5" enum="Flags">
|
||||
Window is part of menu or [OptionButton] dropdown. This flag can't be changed when the window is visible. An active popup window will exclusively receive all input, without stealing focus from its parent. Popup windows are automatically closed when uses click outside it, or when an application is switched. Popup window must have [code]transient parent[/code] set (see [member transient]).
|
||||
Window is part of menu or [OptionButton] dropdown. This flag can't be changed when the window is visible. An active popup window will exclusively receive all input, without stealing focus from its parent. Popup windows are automatically closed when uses click outside it, or when an application is switched. Popup window must have transient parent set (see [member transient]).
|
||||
</constant>
|
||||
<constant name="FLAG_EXTEND_TO_TITLE" value="6" enum="Flags">
|
||||
Window content is expanded to the full size of the window. Unlike borderless window, the frame is left intact and can be used to resize the window, title bar is transparent, but have minimize/maximize/close buttons. Set with [member extend_to_title].
|
||||
|
@ -70,7 +70,7 @@
|
||||
<description>
|
||||
Returns the transform for a view/eye.
|
||||
[param view] is the view/eye index.
|
||||
[param cam_transform] is the transform that maps device coordinates to scene coordinates, typically the global_transform of the current XROrigin3D.
|
||||
[param cam_transform] is the transform that maps device coordinates to scene coordinates, typically the [member Node3D.global_transform] of the current XROrigin3D.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_view_count">
|
||||
@ -246,7 +246,7 @@
|
||||
Player is free to move around, full positional tracking.
|
||||
</constant>
|
||||
<constant name="XR_PLAY_AREA_STAGE" value="4" enum="PlayAreaMode">
|
||||
Same as roomscale but origin point is fixed to the center of the physical space, XRServer.center_on_hmd disabled.
|
||||
Same as [constant XR_PLAY_AREA_ROOMSCALE] but origin point is fixed to the center of the physical space, [method XRServer.center_on_hmd] disabled.
|
||||
</constant>
|
||||
<constant name="XR_ENV_BLEND_MODE_OPAQUE" value="0" enum="EnvironmentBlendMode">
|
||||
Opaque blend mode. This is typically used for VR devices.
|
||||
|
@ -159,13 +159,13 @@
|
||||
<method name="_pre_render" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called if this [XRInterfaceExtension] is active before rendering starts, most XR interfaces will sync tracking at this point in time.
|
||||
Called if this [XRInterfaceExtension] is active before rendering starts. Most XR interfaces will sync tracking at this point in time.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_process" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Called if this [XRInterfaceExtension] is active before our physics and game process is called. most XR interfaces will update its [XRPositionalTracker]s at this point in time.
|
||||
Called if this [XRInterfaceExtension] is active before our physics and game process is called. Most XR interfaces will update its [XRPositionalTracker]s at this point in time.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_set_anchor_detection_is_enabled" qualifiers="virtual">
|
||||
|
@ -1310,6 +1310,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
|
||||
uint32_t instance_color_offset = 0;
|
||||
bool instance_uses_color = false;
|
||||
bool instance_uses_custom_data = false;
|
||||
bool use_instancing = false;
|
||||
|
||||
if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_MESH) {
|
||||
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(state.canvas_instance_batches[p_index].command);
|
||||
@ -1336,6 +1337,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
|
||||
instance_color_offset = mesh_storage->multimesh_get_color_offset(multimesh);
|
||||
instance_uses_color = mesh_storage->multimesh_uses_colors(multimesh);
|
||||
instance_uses_custom_data = mesh_storage->multimesh_uses_custom_data(multimesh);
|
||||
use_instancing = true;
|
||||
|
||||
} else if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_PARTICLES) {
|
||||
const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(state.canvas_instance_batches[p_index].command);
|
||||
@ -1362,6 +1364,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
|
||||
instance_color_offset = 8; // 8 bytes for instance transform.
|
||||
instance_uses_color = true;
|
||||
instance_uses_custom_data = true;
|
||||
use_instancing = true;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(mesh.is_null());
|
||||
@ -1397,7 +1400,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
|
||||
use_index_buffer = true;
|
||||
}
|
||||
|
||||
if (instance_count > 1) {
|
||||
if (use_instancing) {
|
||||
if (instance_buffer == 0) {
|
||||
break;
|
||||
}
|
||||
@ -1426,7 +1429,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
if (instance_count > 1) {
|
||||
if (use_instancing) {
|
||||
glDisableVertexAttribArray(5);
|
||||
glDisableVertexAttribArray(6);
|
||||
glDisableVertexAttribArray(7);
|
||||
|
@ -1948,7 +1948,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glDepthMask(GL_TRUE);
|
||||
scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
|
||||
scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE;
|
||||
scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS;
|
||||
|
||||
if (!fb_cleared) {
|
||||
glClearDepth(1.0f);
|
||||
@ -1976,19 +1976,17 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
||||
|
||||
_render_list_template<PASS_MODE_COLOR>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size());
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_DISABLED;
|
||||
|
||||
if (draw_sky) {
|
||||
RENDER_TIMESTAMP("Render Sky");
|
||||
if (scene_state.current_depth_test != GLES3::SceneShaderData::DEPTH_TEST_ENABLED) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
|
||||
}
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
|
||||
scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_DISABLED;
|
||||
scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
|
||||
|
||||
_draw_sky(render_data.environment, render_data.cam_projection, render_data.cam_transform, sky_energy_multiplier, p_camera_data->view_count > 1, flip_y);
|
||||
|
@ -300,28 +300,23 @@ void main() {
|
||||
vec3 rel_vec = xform[3].xyz - attractors[i].transform[3].xyz;
|
||||
vec3 local_pos = rel_vec * mat3(attractors[i].transform);
|
||||
|
||||
switch (attractors[i].type) {
|
||||
case ATTRACTOR_TYPE_SPHERE: {
|
||||
dir = safe_normalize(rel_vec);
|
||||
float d = length(local_pos) / attractors[i].extents.x;
|
||||
if (d > 1.0) {
|
||||
continue;
|
||||
}
|
||||
amount = max(0.0, 1.0 - d);
|
||||
} break;
|
||||
case ATTRACTOR_TYPE_BOX: {
|
||||
dir = safe_normalize(rel_vec);
|
||||
if (attractors[i].type == ATTRACTOR_TYPE_SPHERE) {
|
||||
dir = safe_normalize(rel_vec);
|
||||
float d = length(local_pos) / attractors[i].extents.x;
|
||||
if (d > 1.0) {
|
||||
continue;
|
||||
}
|
||||
amount = max(0.0, 1.0 - d);
|
||||
} else if (attractors[i].type == ATTRACTOR_TYPE_BOX) {
|
||||
dir = safe_normalize(rel_vec);
|
||||
|
||||
vec3 abs_pos = abs(local_pos / attractors[i].extents.xyz);
|
||||
float d = max(abs_pos.x, max(abs_pos.y, abs_pos.z));
|
||||
if (d > 1.0) {
|
||||
continue;
|
||||
}
|
||||
amount = max(0.0, 1.0 - d);
|
||||
|
||||
} break;
|
||||
case ATTRACTOR_TYPE_VECTOR_FIELD: {
|
||||
} break;
|
||||
vec3 abs_pos = abs(local_pos / attractors[i].extents.xyz);
|
||||
float d = max(abs_pos.x, max(abs_pos.y, abs_pos.z));
|
||||
if (d > 1.0) {
|
||||
continue;
|
||||
}
|
||||
amount = max(0.0, 1.0 - d);
|
||||
} else if (attractors[i].type == ATTRACTOR_TYPE_VECTOR_FIELD) {
|
||||
}
|
||||
amount = pow(amount, attractors[i].attenuation);
|
||||
dir = safe_normalize(mix(dir, attractors[i].transform[2].xyz, attractors[i].directionality));
|
||||
@ -383,80 +378,72 @@ void main() {
|
||||
vec3 rel_vec = xform[3].xyz - colliders[i].transform[3].xyz;
|
||||
vec3 local_pos = rel_vec * mat3(colliders[i].transform);
|
||||
|
||||
switch (colliders[i].type) {
|
||||
case COLLIDER_TYPE_SPHERE: {
|
||||
float d = length(rel_vec) - (particle_size + colliders[i].extents.x);
|
||||
if (colliders[i].type == COLLIDER_TYPE_SPHERE) {
|
||||
float d = length(rel_vec) - (particle_size + colliders[i].extents.x);
|
||||
|
||||
if (d < 0.0) {
|
||||
if (d < 0.0) {
|
||||
col = true;
|
||||
depth = -d;
|
||||
normal = normalize(rel_vec);
|
||||
}
|
||||
} else if (colliders[i].type == COLLIDER_TYPE_BOX) {
|
||||
vec3 abs_pos = abs(local_pos);
|
||||
vec3 sgn_pos = sign(local_pos);
|
||||
|
||||
if (any(greaterThan(abs_pos, colliders[i].extents.xyz))) {
|
||||
//point outside box
|
||||
|
||||
vec3 closest = min(abs_pos, colliders[i].extents.xyz);
|
||||
vec3 rel = abs_pos - closest;
|
||||
depth = length(rel) - particle_size;
|
||||
if (depth < 0.0) {
|
||||
col = true;
|
||||
depth = -d;
|
||||
normal = normalize(rel_vec);
|
||||
normal = mat3(colliders[i].transform) * (normalize(rel) * sgn_pos);
|
||||
depth = -depth;
|
||||
}
|
||||
|
||||
} break;
|
||||
case COLLIDER_TYPE_BOX: {
|
||||
vec3 abs_pos = abs(local_pos);
|
||||
vec3 sgn_pos = sign(local_pos);
|
||||
|
||||
if (any(greaterThan(abs_pos, colliders[i].extents.xyz))) {
|
||||
//point outside box
|
||||
|
||||
vec3 closest = min(abs_pos, colliders[i].extents.xyz);
|
||||
vec3 rel = abs_pos - closest;
|
||||
depth = length(rel) - particle_size;
|
||||
if (depth < 0.0) {
|
||||
col = true;
|
||||
normal = mat3(colliders[i].transform) * (normalize(rel) * sgn_pos);
|
||||
depth = -depth;
|
||||
}
|
||||
} else {
|
||||
//point inside box
|
||||
vec3 axis_len = colliders[i].extents.xyz - abs_pos;
|
||||
// there has to be a faster way to do this?
|
||||
if (all(lessThan(axis_len.xx, axis_len.yz))) {
|
||||
normal = vec3(1, 0, 0);
|
||||
} else if (all(lessThan(axis_len.yy, axis_len.xz))) {
|
||||
normal = vec3(0, 1, 0);
|
||||
} else {
|
||||
//point inside box
|
||||
vec3 axis_len = colliders[i].extents.xyz - abs_pos;
|
||||
// there has to be a faster way to do this?
|
||||
if (all(lessThan(axis_len.xx, axis_len.yz))) {
|
||||
normal = vec3(1, 0, 0);
|
||||
} else if (all(lessThan(axis_len.yy, axis_len.xz))) {
|
||||
normal = vec3(0, 1, 0);
|
||||
} else {
|
||||
normal = vec3(0, 0, 1);
|
||||
}
|
||||
|
||||
col = true;
|
||||
depth = dot(normal * axis_len, vec3(1)) + particle_size;
|
||||
normal = mat3(colliders[i].transform) * (normal * sgn_pos);
|
||||
normal = vec3(0, 0, 1);
|
||||
}
|
||||
|
||||
} break;
|
||||
case COLLIDER_TYPE_SDF: {
|
||||
} break;
|
||||
case COLLIDER_TYPE_HEIGHT_FIELD: {
|
||||
vec3 local_pos_bottom = local_pos;
|
||||
local_pos_bottom.y -= particle_size;
|
||||
col = true;
|
||||
depth = dot(normal * axis_len, vec3(1)) + particle_size;
|
||||
normal = mat3(colliders[i].transform) * (normal * sgn_pos);
|
||||
}
|
||||
} else if (colliders[i].type == COLLIDER_TYPE_SDF) {
|
||||
} else if (colliders[i].type == COLLIDER_TYPE_HEIGHT_FIELD) {
|
||||
vec3 local_pos_bottom = local_pos;
|
||||
local_pos_bottom.y -= particle_size;
|
||||
|
||||
if (any(greaterThan(abs(local_pos_bottom), colliders[i].extents.xyz))) {
|
||||
continue;
|
||||
}
|
||||
const float DELTA = 1.0 / 8192.0;
|
||||
if (any(greaterThan(abs(local_pos_bottom), colliders[i].extents.xyz))) {
|
||||
continue;
|
||||
}
|
||||
const float DELTA = 1.0 / 8192.0;
|
||||
|
||||
vec3 uvw_pos = vec3(local_pos_bottom / colliders[i].extents.xyz) * 0.5 + 0.5;
|
||||
vec3 uvw_pos = vec3(local_pos_bottom / colliders[i].extents.xyz) * 0.5 + 0.5;
|
||||
|
||||
float y = 1.0 - texture(height_field_texture, uvw_pos.xz).r;
|
||||
float y = 1.0 - texture(height_field_texture, uvw_pos.xz).r;
|
||||
|
||||
if (y > uvw_pos.y) {
|
||||
//inside heightfield
|
||||
if (y > uvw_pos.y) {
|
||||
//inside heightfield
|
||||
|
||||
vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
|
||||
vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
|
||||
vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * colliders[i].extents.xyz;
|
||||
vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
|
||||
vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
|
||||
vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * colliders[i].extents.xyz;
|
||||
|
||||
normal = normalize(cross(pos1 - pos2, pos1 - pos3));
|
||||
float local_y = (vec3(local_pos / colliders[i].extents.xyz) * 0.5 + 0.5).y;
|
||||
normal = normalize(cross(pos1 - pos2, pos1 - pos3));
|
||||
float local_y = (vec3(local_pos / colliders[i].extents.xyz) * 0.5 + 0.5).y;
|
||||
|
||||
col = true;
|
||||
depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
|
||||
}
|
||||
|
||||
} break;
|
||||
col = true;
|
||||
depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
|
||||
}
|
||||
}
|
||||
|
||||
if (col) {
|
||||
|
@ -44,8 +44,12 @@ uniform highp mat4 inv_emission_transform;
|
||||
|
||||
#define PARTICLE_FLAG_ACTIVE uint(1)
|
||||
|
||||
#define FLT_MAX float(3.402823466e+38)
|
||||
|
||||
void main() {
|
||||
mat4 txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); // zero scale, becomes invisible.
|
||||
// Set scale to zero and translate to -INF so particle will be invisible
|
||||
// even for materials that ignore rotation/scale (i.e. billboards).
|
||||
mat4 txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(-FLT_MAX, -FLT_MAX, -FLT_MAX, 0.0));
|
||||
if (bool(floatBitsToUint(velocity_flags.w) & PARTICLE_FLAG_ACTIVE)) {
|
||||
#ifdef MODE_3D
|
||||
txform = transpose(mat4(xform_1, xform_2, xform_3, vec4(0.0, 0.0, 0.0, 1.0)));
|
||||
@ -102,9 +106,8 @@ void main() {
|
||||
// as they will be drawn with the node position as origin.
|
||||
txform = inv_emission_transform * txform;
|
||||
#endif
|
||||
|
||||
txform = transpose(txform);
|
||||
}
|
||||
txform = transpose(txform);
|
||||
|
||||
instance_color_custom_data = uvec4(packHalf2x16(color.xy), packHalf2x16(color.zw), packHalf2x16(custom.xy), packHalf2x16(custom.zw));
|
||||
out_xform_1 = txform[0];
|
||||
|
@ -919,7 +919,7 @@ void ParticlesStorage::_particles_update_instance_buffer(Particles *particles, c
|
||||
glBeginTransformFeedback(GL_POINTS);
|
||||
|
||||
if (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME) {
|
||||
uint32_t lifetime_split = MIN(particles->amount * particles->phase, particles->amount - 1);
|
||||
uint32_t lifetime_split = (MIN(int(particles->amount * particles->phase), particles->amount - 1) + 1) % particles->amount;
|
||||
uint32_t stride = particles->process_buffer_stride_cache;
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, particles->back_process_buffer);
|
||||
@ -1135,14 +1135,13 @@ void ParticlesStorage::_particles_reverse_lifetime_sort(Particles *particles) {
|
||||
glGetBufferSubData(GL_ARRAY_BUFFER, 0, buffer_size, particle_array);
|
||||
#endif
|
||||
|
||||
uint32_t lifetime_split = MIN(particles->amount * particles->sort_buffer_phase, particles->amount - 1);
|
||||
|
||||
uint32_t lifetime_split = (MIN(int(particles->amount * particles->sort_buffer_phase), particles->amount - 1) + 1) % particles->amount;
|
||||
for (uint32_t i = 0; i < lifetime_split / 2; i++) {
|
||||
SWAP(particle_array[i], particle_array[lifetime_split - i]);
|
||||
SWAP(particle_array[i], particle_array[lifetime_split - i - 1]);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < (particles->amount - lifetime_split) / 2; i++) {
|
||||
SWAP(particle_array[lifetime_split + i + 1], particle_array[particles->amount - 1 - i]);
|
||||
SWAP(particle_array[lifetime_split + i], particle_array[particles->amount - 1 - i]);
|
||||
}
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
|
@ -119,7 +119,7 @@ void ConnectDialog::ok_pressed() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!method_name.strip_edges().is_valid_identifier()) {
|
||||
if (!TS->is_valid_identifier(method_name.strip_edges())) {
|
||||
error->set_text(TTR("Method name must be a valid identifier."));
|
||||
error->popup_centered();
|
||||
return;
|
||||
@ -228,7 +228,7 @@ StringName ConnectDialog::generate_method_callback_name(Node *p_source, String p
|
||||
String node_name = p_source->get_name();
|
||||
for (int i = 0; i < node_name.length(); i++) { // TODO: Regex filter may be cleaner.
|
||||
char32_t c = node_name[i];
|
||||
if (!is_ascii_identifier_char(c)) {
|
||||
if ((i == 0 && !is_unicode_identifier_start(c)) || (i > 0 && !is_unicode_identifier_continue(c))) {
|
||||
if (c == ' ') {
|
||||
// Replace spaces with underlines.
|
||||
c = '_';
|
||||
@ -338,11 +338,6 @@ void ConnectDialog::_update_method_tree() {
|
||||
// If a script is attached, get methods from it.
|
||||
ScriptInstance *si = target->get_script_instance();
|
||||
if (si) {
|
||||
TreeItem *si_item = method_tree->create_item(root_item);
|
||||
si_item->set_text(0, TTR("Attached Script"));
|
||||
si_item->set_icon(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")));
|
||||
si_item->set_selectable(0, false);
|
||||
|
||||
if (si->get_script()->is_built_in()) {
|
||||
si->get_script()->reload();
|
||||
}
|
||||
@ -350,9 +345,12 @@ void ConnectDialog::_update_method_tree() {
|
||||
si->get_method_list(&methods);
|
||||
methods = _filter_method_list(methods, signal_info, search_string);
|
||||
|
||||
if (methods.is_empty()) {
|
||||
si_item->set_custom_color(0, disabled_color);
|
||||
} else {
|
||||
if (!methods.is_empty()) {
|
||||
TreeItem *si_item = method_tree->create_item(root_item);
|
||||
si_item->set_text(0, TTR("Attached Script"));
|
||||
si_item->set_icon(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")));
|
||||
si_item->set_selectable(0, false);
|
||||
|
||||
_create_method_tree_items(methods, si_item);
|
||||
}
|
||||
}
|
||||
@ -687,8 +685,10 @@ ConnectDialog::ConnectDialog() {
|
||||
method_tree->connect("item_activated", callable_mp((Window *)method_popup, &Window::hide));
|
||||
|
||||
empty_tree_label = memnew(Label(TTR("No method found matching given filters.")));
|
||||
method_tree->add_child(empty_tree_label);
|
||||
empty_tree_label->set_anchors_and_offsets_preset(Control::PRESET_CENTER);
|
||||
method_popup->add_child(empty_tree_label);
|
||||
empty_tree_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
|
||||
empty_tree_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
|
||||
empty_tree_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
|
||||
|
||||
script_methods_only = memnew(CheckButton(TTR("Script Methods Only")));
|
||||
method_vbc->add_child(script_methods_only);
|
||||
|
@ -970,6 +970,7 @@ void DebugAdapterProtocol::poll() {
|
||||
List<Ref<DAPeer>> to_delete;
|
||||
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
|
||||
Ref<DAPeer> peer = E->get();
|
||||
peer->connection->poll();
|
||||
StreamPeerTCP::Status status = peer->connection->get_status();
|
||||
if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) {
|
||||
to_delete.push_back(peer);
|
||||
|
@ -91,7 +91,12 @@ void EditorLog::_update_theme() {
|
||||
log->add_theme_font_override("mono_font", mono_font);
|
||||
}
|
||||
|
||||
log->add_theme_font_size_override("normal_font_size", get_theme_font_size(SNAME("output_source_size"), SNAME("EditorFonts")));
|
||||
const int font_size = get_theme_font_size(SNAME("output_source_size"), SNAME("EditorFonts"));
|
||||
log->add_theme_font_size_override("normal_font_size", font_size);
|
||||
log->add_theme_font_size_override("bold_font_size", font_size);
|
||||
log->add_theme_font_size_override("italics_font_size", font_size);
|
||||
log->add_theme_font_size_override("mono_font_size", font_size);
|
||||
|
||||
log->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), SNAME("Editor")) * Color(1, 1, 1, 0.4));
|
||||
|
||||
type_filter_map[MSG_TYPE_STD]->toggle_button->set_icon(get_theme_icon(SNAME("Popup"), SNAME("EditorIcons")));
|
||||
@ -273,6 +278,11 @@ void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(log->is_updating())) {
|
||||
// The new message arrived during log RTL text processing/redraw (invalid BiDi control characters / font error), ignore it to avoid RTL data corruption.
|
||||
return;
|
||||
}
|
||||
|
||||
// Only add the message to the log if it passes the filters.
|
||||
bool filter_active = type_filter_map[p_message.type]->is_active();
|
||||
String search_text = search_box->get_text();
|
||||
|
@ -1145,7 +1145,7 @@ void EditorNode::_scan_external_changes() {
|
||||
}
|
||||
|
||||
if (need_reload) {
|
||||
disk_changed->call_deferred(SNAME("popup_centered_ratio"), 0.5);
|
||||
disk_changed->call_deferred(SNAME("popup_centered_ratio"), 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2761,6 +2761,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
|
||||
}
|
||||
}
|
||||
}
|
||||
save_confirmation->reset_size();
|
||||
save_confirmation->popup_centered();
|
||||
break;
|
||||
}
|
||||
@ -3074,6 +3075,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
|
||||
save_confirmation->set_ok_button_text(TTR("Save & Quit"));
|
||||
save_confirmation->set_text((p_option == FILE_QUIT ? TTR("Save changes to the following scene(s) before quitting?") : TTR("Save changes to the following scene(s) before opening Project Manager?")) + unsaved_scenes);
|
||||
}
|
||||
save_confirmation->reset_size();
|
||||
save_confirmation->popup_centered();
|
||||
}
|
||||
}
|
||||
@ -5534,6 +5536,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) {
|
||||
if (unsaved) {
|
||||
save_confirmation->set_ok_button_text(TTR("Save & Close"));
|
||||
save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), !scene->get_scene_file_path().is_empty() ? scene->get_scene_file_path() : "unsaved scene"));
|
||||
save_confirmation->reset_size();
|
||||
save_confirmation->popup_centered();
|
||||
} else {
|
||||
_discard_changes();
|
||||
@ -7830,6 +7833,7 @@ EditorNode::EditorNode() {
|
||||
save_confirmation = memnew(ConfirmationDialog);
|
||||
save_confirmation->add_button(TTR("Don't Save"), DisplayServer::get_singleton()->get_swap_cancel_ok(), "discard");
|
||||
gui_base->add_child(save_confirmation);
|
||||
save_confirmation->set_min_size(Vector2(450.0 * EDSCALE, 0));
|
||||
save_confirmation->connect("confirmed", callable_mp(this, &EditorNode::_menu_confirm_current));
|
||||
save_confirmation->connect("custom_action", callable_mp(this, &EditorNode::_discard_changes));
|
||||
|
||||
|
@ -834,7 +834,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_color("font_focus_color", "MenuButton", font_focus_color);
|
||||
theme->set_color("font_outline_color", "MenuButton", font_outline_color);
|
||||
|
||||
theme->set_constant("outline_size", "MenuButton", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "MenuButton", 0);
|
||||
|
||||
theme->set_stylebox("MenuHover", "EditorStyles", style_widget_hover);
|
||||
|
||||
@ -860,7 +860,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_color("icon_disabled_color", "Button", icon_disabled_color);
|
||||
|
||||
theme->set_constant("h_separation", "Button", 2 * EDSCALE);
|
||||
theme->set_constant("outline_size", "Button", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "Button", 0);
|
||||
|
||||
const float ACTION_BUTTON_EXTRA_MARGIN = 32 * EDSCALE;
|
||||
|
||||
@ -917,7 +917,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_color("icon_disabled_color", "MenuBar", icon_disabled_color);
|
||||
|
||||
theme->set_constant("h_separation", "MenuBar", 4 * EDSCALE);
|
||||
theme->set_constant("outline_size", "MenuBar", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "MenuBar", 0);
|
||||
|
||||
// OptionButton
|
||||
Ref<StyleBoxFlat> style_option_button_focus = style_widget_focus->duplicate();
|
||||
@ -961,7 +961,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_constant("arrow_margin", "OptionButton", widget_default_margin.x - 2 * EDSCALE);
|
||||
theme->set_constant("modulate_arrow", "OptionButton", true);
|
||||
theme->set_constant("h_separation", "OptionButton", 4 * EDSCALE);
|
||||
theme->set_constant("outline_size", "OptionButton", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "OptionButton", 0);
|
||||
|
||||
// CheckButton
|
||||
theme->set_stylebox("normal", "CheckButton", style_menu);
|
||||
@ -995,8 +995,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_color("icon_disabled_color", "CheckButton", icon_disabled_color);
|
||||
|
||||
theme->set_constant("h_separation", "CheckButton", 8 * EDSCALE);
|
||||
theme->set_constant("check_v_offset", "CheckButton", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "CheckButton", 0 * EDSCALE);
|
||||
theme->set_constant("check_v_offset", "CheckButton", 0);
|
||||
theme->set_constant("outline_size", "CheckButton", 0);
|
||||
|
||||
// Checkbox
|
||||
Ref<StyleBoxFlat> sb_checkbox = style_menu->duplicate();
|
||||
@ -1031,8 +1031,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_color("icon_disabled_color", "CheckBox", icon_disabled_color);
|
||||
|
||||
theme->set_constant("h_separation", "CheckBox", 8 * EDSCALE);
|
||||
theme->set_constant("check_v_offset", "CheckBox", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "CheckBox", 0 * EDSCALE);
|
||||
theme->set_constant("check_v_offset", "CheckBox", 0);
|
||||
theme->set_constant("outline_size", "CheckBox", 0);
|
||||
|
||||
// PopupDialog
|
||||
theme->set_stylebox("panel", "PopupDialog", style_popup);
|
||||
@ -1087,7 +1087,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
const int vsep_base = extra_spacing + default_margin_size + 6;
|
||||
const int force_even_vsep = vsep_base + (vsep_base % 2);
|
||||
theme->set_constant("v_separation", "PopupMenu", force_even_vsep * EDSCALE);
|
||||
theme->set_constant("outline_size", "PopupMenu", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "PopupMenu", 0);
|
||||
theme->set_constant("item_start_padding", "PopupMenu", default_margin_size * 1.5 * EDSCALE);
|
||||
theme->set_constant("item_end_padding", "PopupMenu", default_margin_size * 1.5 * EDSCALE);
|
||||
|
||||
@ -1206,7 +1206,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_constant("button_margin", "Tree", default_margin_size * EDSCALE);
|
||||
theme->set_constant("scroll_border", "Tree", 40 * EDSCALE);
|
||||
theme->set_constant("scroll_speed", "Tree", 12);
|
||||
theme->set_constant("outline_size", "Tree", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "Tree", 0);
|
||||
|
||||
const Color guide_color = mono_color * Color(1, 1, 1, 0.05);
|
||||
Color relationship_line_color = mono_color * Color(1, 1, 1, relationship_line_opacity);
|
||||
@ -1302,7 +1302,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_constant("h_separation", "ItemList", 6 * EDSCALE);
|
||||
theme->set_constant("icon_margin", "ItemList", 6 * EDSCALE);
|
||||
theme->set_constant("line_separation", "ItemList", 3 * EDSCALE);
|
||||
theme->set_constant("outline_size", "ItemList", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "ItemList", 0);
|
||||
|
||||
// TabBar & TabContainer
|
||||
Ref<StyleBoxFlat> style_tabbar_background = make_flat_stylebox(dark_color_1, 0, 0, 0, 0, corner_radius * EDSCALE);
|
||||
@ -1340,9 +1340,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_icon("drop_mark", "TabContainer", theme->get_icon(SNAME("GuiTabDropMark"), SNAME("EditorIcons")));
|
||||
theme->set_icon("drop_mark", "TabBar", theme->get_icon(SNAME("GuiTabDropMark"), SNAME("EditorIcons")));
|
||||
theme->set_constant("side_margin", "TabContainer", 0);
|
||||
theme->set_constant("outline_size", "TabContainer", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "TabContainer", 0);
|
||||
theme->set_constant("h_separation", "TabBar", 4 * EDSCALE);
|
||||
theme->set_constant("outline_size", "TabBar", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "TabBar", 0);
|
||||
|
||||
// Content of each tab.
|
||||
Ref<StyleBoxFlat> style_content_panel = style_default->duplicate();
|
||||
@ -1438,7 +1438,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_color("selection_color", "LineEdit", selection_color);
|
||||
theme->set_color("clear_button_color", "LineEdit", font_color);
|
||||
theme->set_color("clear_button_color_pressed", "LineEdit", accent_color);
|
||||
theme->set_constant("outline_size", "LineEdit", 0 * EDSCALE);
|
||||
|
||||
theme->set_constant("minimum_character_width", "LineEdit", 4);
|
||||
theme->set_constant("outline_size", "LineEdit", 0);
|
||||
theme->set_constant("caret_width", "LineEdit", 1);
|
||||
|
||||
// TextEdit
|
||||
theme->set_stylebox("normal", "TextEdit", style_line_edit);
|
||||
@ -1455,7 +1458,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_color("background_color", "TextEdit", Color(0, 0, 0, 0));
|
||||
|
||||
theme->set_constant("line_spacing", "TextEdit", 4 * EDSCALE);
|
||||
theme->set_constant("outline_size", "TextEdit", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "TextEdit", 0);
|
||||
theme->set_constant("caret_width", "TextEdit", 1);
|
||||
|
||||
theme->set_icon("h_grabber", "SplitContainer", theme->get_icon(SNAME("GuiHsplitter"), SNAME("EditorIcons")));
|
||||
theme->set_icon("v_grabber", "SplitContainer", theme->get_icon(SNAME("GuiVsplitter"), SNAME("EditorIcons")));
|
||||
@ -1592,7 +1596,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_constant("shadow_offset_x", "RichTextLabel", 1 * EDSCALE);
|
||||
theme->set_constant("shadow_offset_y", "RichTextLabel", 1 * EDSCALE);
|
||||
theme->set_constant("shadow_outline_size", "RichTextLabel", 1 * EDSCALE);
|
||||
theme->set_constant("outline_size", "RichTextLabel", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "RichTextLabel", 0);
|
||||
theme->set_stylebox("focus", "RichTextLabel", make_empty_stylebox());
|
||||
theme->set_stylebox("normal", "RichTextLabel", style_tree_bg);
|
||||
|
||||
@ -1636,7 +1640,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_constant("shadow_offset_y", "Label", 1 * EDSCALE);
|
||||
theme->set_constant("shadow_outline_size", "Label", 1 * EDSCALE);
|
||||
theme->set_constant("line_spacing", "Label", 3 * EDSCALE);
|
||||
theme->set_constant("outline_size", "Label", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "Label", 0);
|
||||
|
||||
// LinkButton
|
||||
theme->set_stylebox("focus", "LinkButton", style_empty);
|
||||
@ -1648,7 +1652,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_color("font_disabled_color", "LinkButton", font_disabled_color);
|
||||
theme->set_color("font_outline_color", "LinkButton", font_outline_color);
|
||||
|
||||
theme->set_constant("outline_size", "LinkButton", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "LinkButton", 0);
|
||||
|
||||
// TooltipPanel + TooltipLabel
|
||||
// TooltipPanel is also used for custom tooltips, while TooltipLabel
|
||||
@ -1685,7 +1689,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
||||
theme->set_stylebox("fill", "ProgressBar", make_stylebox(theme->get_icon(SNAME("GuiProgressFill"), SNAME("EditorIcons")), 6, 6, 6, 6, 2, 1, 2, 1));
|
||||
theme->set_color("font_color", "ProgressBar", font_color);
|
||||
theme->set_color("font_outline_color", "ProgressBar", font_outline_color);
|
||||
theme->set_constant("outline_size", "ProgressBar", 0 * EDSCALE);
|
||||
theme->set_constant("outline_size", "ProgressBar", 0);
|
||||
|
||||
// GraphEdit
|
||||
theme->set_stylebox("bg", "GraphEdit", style_tree_bg);
|
||||
|
@ -145,6 +145,12 @@ void EditorToaster::_notification(int p_what) {
|
||||
}
|
||||
|
||||
void EditorToaster::_error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||
// This may be called from a thread. Since we will deal with non-thread-safe elements,
|
||||
// we have to put it in the queue for safety.
|
||||
callable_mp_static(&EditorToaster::_error_handler_impl).bind(p_file, p_line, p_error, p_errorexp, p_editor_notify, p_type).call_deferred();
|
||||
}
|
||||
|
||||
void EditorToaster::_error_handler_impl(const String &p_file, int p_line, const String &p_error, const String &p_errorexp, bool p_editor_notify, int p_type) {
|
||||
if (!EditorToaster::get_singleton() || !EditorToaster::get_singleton()->is_inside_tree()) {
|
||||
return;
|
||||
}
|
||||
@ -158,13 +164,8 @@ void EditorToaster::_error_handler(void *p_self, const char *p_func, const char
|
||||
int show_all_setting = EDITOR_GET("interface/editor/show_internal_errors_in_toast_notifications");
|
||||
|
||||
if (p_editor_notify || (show_all_setting == 0 && in_dev) || show_all_setting == 1) {
|
||||
String err_str;
|
||||
if (p_errorexp && p_errorexp[0]) {
|
||||
err_str = String::utf8(p_errorexp);
|
||||
} else {
|
||||
err_str = String::utf8(p_error);
|
||||
}
|
||||
String tooltip_str = String::utf8(p_file) + ":" + itos(p_line);
|
||||
String err_str = !p_errorexp.is_empty() ? p_errorexp : p_error;
|
||||
String tooltip_str = p_file + ":" + itos(p_line);
|
||||
|
||||
if (!p_editor_notify) {
|
||||
if (p_type == ERR_HANDLER_WARNING) {
|
||||
@ -174,7 +175,7 @@ void EditorToaster::_error_handler(void *p_self, const char *p_func, const char
|
||||
}
|
||||
}
|
||||
|
||||
Severity severity = (p_type == ERR_HANDLER_WARNING) ? SEVERITY_WARNING : SEVERITY_ERROR;
|
||||
Severity severity = ((ErrorHandlerType)p_type == ERR_HANDLER_WARNING) ? SEVERITY_WARNING : SEVERITY_ERROR;
|
||||
EditorToaster::get_singleton()->popup_str(err_str, severity, tooltip_str);
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ private:
|
||||
const double default_message_duration = 5.0;
|
||||
|
||||
static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type);
|
||||
static void _error_handler_impl(const String &p_file, int p_line, const String &p_error, const String &p_errorexp, bool p_editor_notify, int p_type);
|
||||
void _update_vbox_position();
|
||||
void _update_disable_notifications_button();
|
||||
void _auto_hide_or_free_toasts();
|
||||
|
@ -245,6 +245,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
|
||||
String current_group;
|
||||
uint32_t smooth_group = 0;
|
||||
bool smoothing = true;
|
||||
const uint32_t no_smoothing_smooth_group = (uint32_t)-1;
|
||||
|
||||
while (true) {
|
||||
String l = f->get_line().strip_edges();
|
||||
@ -349,10 +350,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
|
||||
if (!colors.is_empty()) {
|
||||
surf_tool->set_color(colors[vtx]);
|
||||
}
|
||||
if (!smoothing) {
|
||||
smooth_group++;
|
||||
}
|
||||
surf_tool->set_smooth_group(smooth_group);
|
||||
surf_tool->set_smooth_group(smoothing ? smooth_group : no_smoothing_smooth_group);
|
||||
surf_tool->add_vertex(vertex);
|
||||
}
|
||||
|
||||
@ -367,8 +365,10 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
|
||||
do_smooth = true;
|
||||
}
|
||||
if (do_smooth != smoothing) {
|
||||
smooth_group++;
|
||||
smoothing = do_smooth;
|
||||
if (smoothing) {
|
||||
smooth_group++;
|
||||
}
|
||||
}
|
||||
} else if (/*l.begins_with("g ") ||*/ l.begins_with("usemtl ") || (l.begins_with("o ") || f->eof_reached())) { //commit group to mesh
|
||||
//groups are too annoying
|
||||
|
@ -1239,6 +1239,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
|
||||
bool panner_active = panner->gui_input(p_event, warped_panning ? viewport->get_global_rect() : Rect2());
|
||||
if (panner->is_panning() != pan_pressed) {
|
||||
pan_pressed = panner->is_panning();
|
||||
_update_cursor();
|
||||
}
|
||||
|
||||
if (panner_active) {
|
||||
|
@ -5162,10 +5162,10 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
|
||||
position_control->set_navigation_mode(Node3DEditorViewport::NAVIGATION_MOVE);
|
||||
position_control->set_custom_minimum_size(Size2(navigation_control_size, navigation_control_size) * EDSCALE);
|
||||
position_control->set_h_size_flags(SIZE_SHRINK_END);
|
||||
position_control->set_anchor_and_offset(SIDE_LEFT, ANCHOR_BEGIN, 0 * EDSCALE);
|
||||
position_control->set_anchor_and_offset(SIDE_LEFT, ANCHOR_BEGIN, 0);
|
||||
position_control->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -navigation_control_size * EDSCALE);
|
||||
position_control->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_BEGIN, navigation_control_size * EDSCALE);
|
||||
position_control->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0 * EDSCALE);
|
||||
position_control->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0);
|
||||
position_control->set_viewport(this);
|
||||
surface->add_child(position_control);
|
||||
|
||||
@ -5175,8 +5175,8 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
|
||||
look_control->set_h_size_flags(SIZE_SHRINK_END);
|
||||
look_control->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -navigation_control_size * EDSCALE);
|
||||
look_control->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -navigation_control_size * EDSCALE);
|
||||
look_control->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0 * EDSCALE);
|
||||
look_control->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0 * EDSCALE);
|
||||
look_control->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0);
|
||||
look_control->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0);
|
||||
look_control->set_viewport(this);
|
||||
surface->add_child(look_control);
|
||||
|
||||
|
@ -1060,7 +1060,7 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Resource> p_for_script) {
|
||||
script_editor->reload_scripts();
|
||||
need_reload = false;
|
||||
} else {
|
||||
disk_changed->call_deferred(SNAME("popup_centered_ratio"), 0.5);
|
||||
disk_changed->call_deferred(SNAME("popup_centered_ratio"), 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5931,7 +5931,7 @@ VisualShaderEditor::VisualShaderEditor() {
|
||||
add_options.push_back(AddOption("ATanH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
|
||||
add_options.push_back(AddOption("ATanH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
|
||||
add_options.push_back(AddOption("ATanH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
|
||||
add_options.push_back(AddOption("Ceil", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_CEIL }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
|
||||
add_options.push_back(AddOption("Ceil", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_CEIL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
|
||||
add_options.push_back(AddOption("Ceil", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_CEIL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
|
||||
add_options.push_back(AddOption("Ceil", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_CEIL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
|
||||
add_options.push_back(AddOption("Clamp", "Vector/Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), { VisualShaderNodeClamp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
|
||||
|
@ -2256,7 +2256,7 @@ void ProjectManager::_open_selected_projects_ask() {
|
||||
return;
|
||||
}
|
||||
|
||||
const Size2i popup_min_size = Size2i(600.0 * EDSCALE, 400.0 * EDSCALE);
|
||||
const Size2i popup_min_size = Size2i(600.0 * EDSCALE, 0);
|
||||
|
||||
if (selected_list.size() > 1) {
|
||||
multi_open_ask->set_text(vformat(TTR("You requested to open %d projects in parallel. Do you confirm?\nNote that usual checks for engine version compatibility will be bypassed."), selected_list.size()));
|
||||
@ -2341,7 +2341,7 @@ void ProjectManager::_open_selected_projects_ask() {
|
||||
|
||||
void ProjectManager::_full_convert_button_pressed() {
|
||||
ask_update_settings->hide();
|
||||
ask_full_convert_dialog->popup_centered(Size2i(600.0 * EDSCALE, 400.0 * EDSCALE));
|
||||
ask_full_convert_dialog->popup_centered(Size2i(600.0 * EDSCALE, 0));
|
||||
ask_full_convert_dialog->get_cancel_button()->grab_focus();
|
||||
}
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 25 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 41 KiB |
@ -50,7 +50,7 @@ def disable_warnings(self):
|
||||
|
||||
def force_optimization_on_debug(self):
|
||||
# 'self' is the environment
|
||||
if self["target"] != "template-release":
|
||||
if self["target"] == "template_release":
|
||||
return
|
||||
|
||||
if self.msvc:
|
||||
|
@ -478,7 +478,24 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
|
||||
}
|
||||
if (look_class->has_member(name)) {
|
||||
resolve_class_member(look_class, name, p_class);
|
||||
base = look_class->get_member(name).get_datatype();
|
||||
GDScriptParser::ClassNode::Member member = look_class->get_member(name);
|
||||
GDScriptParser::DataType member_datatype = member.get_datatype();
|
||||
|
||||
switch (member.type) {
|
||||
case GDScriptParser::ClassNode::Member::CLASS:
|
||||
break; // OK.
|
||||
case GDScriptParser::ClassNode::Member::CONSTANT:
|
||||
if (member_datatype.kind != GDScriptParser::DataType::SCRIPT && member_datatype.kind != GDScriptParser::DataType::CLASS) {
|
||||
push_error(vformat(R"(Constant "%s" is not a preloaded script or class.)", name), p_class);
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
push_error(vformat(R"(Cannot use %s "%s" in extends chain.)", member.get_type_name(), name), p_class);
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
base = member_datatype;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@ -506,6 +523,10 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
|
||||
GDScriptParser::DataType id_type = id->get_datatype();
|
||||
if (!id_type.is_set()) {
|
||||
push_error(vformat(R"(Could not find type "%s" under base "%s".)", id->name, base.to_string()), p_class);
|
||||
return ERR_PARSE_ERROR;
|
||||
} else if (id_type.kind != GDScriptParser::DataType::SCRIPT && id_type.kind != GDScriptParser::DataType::CLASS) {
|
||||
push_error(vformat(R"(Identifier "%s" is not a preloaded script or class.)", id->name), p_class);
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
base = id_type;
|
||||
|
@ -337,7 +337,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
|
||||
symbol.kind = lsp::SymbolKind::Variable;
|
||||
symbol.name = parameter->identifier->name;
|
||||
symbol.range.start.line = LINE_NUMBER_TO_INDEX(parameter->start_line);
|
||||
symbol.range.start.character = LINE_NUMBER_TO_INDEX(parameter->start_line);
|
||||
symbol.range.start.character = LINE_NUMBER_TO_INDEX(parameter->start_column);
|
||||
symbol.range.end.line = LINE_NUMBER_TO_INDEX(parameter->end_line);
|
||||
symbol.range.end.character = LINE_NUMBER_TO_INDEX(parameter->end_column);
|
||||
symbol.uri = uri;
|
||||
|
@ -237,6 +237,7 @@ void GDScriptLanguageProtocol::poll() {
|
||||
HashMap<int, Ref<LSPeer>>::Iterator E = clients.begin();
|
||||
while (E != clients.end()) {
|
||||
Ref<LSPeer> peer = E->value;
|
||||
peer->connection->poll();
|
||||
StreamPeerTCP::Status status = peer->connection->get_status();
|
||||
if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) {
|
||||
on_client_disconnected(E->key);
|
||||
|
@ -0,0 +1,9 @@
|
||||
# GH-75870
|
||||
|
||||
const A = 1
|
||||
|
||||
class B extends A:
|
||||
pass
|
||||
|
||||
func test():
|
||||
pass
|
@ -0,0 +1,2 @@
|
||||
GDTEST_ANALYZER_ERROR
|
||||
Constant "A" is not a preloaded script or class.
|
@ -0,0 +1,12 @@
|
||||
# GH-75870
|
||||
|
||||
class A:
|
||||
const X = 1
|
||||
|
||||
const Y = A.X # A.X is now resolved.
|
||||
|
||||
class B extends A.X:
|
||||
pass
|
||||
|
||||
func test():
|
||||
pass
|
@ -0,0 +1,2 @@
|
||||
GDTEST_ANALYZER_ERROR
|
||||
Identifier "X" is not a preloaded script or class.
|
@ -0,0 +1,9 @@
|
||||
# GH-75870
|
||||
|
||||
var A = 1
|
||||
|
||||
class B extends A:
|
||||
pass
|
||||
|
||||
func test():
|
||||
pass
|
@ -0,0 +1,2 @@
|
||||
GDTEST_ANALYZER_ERROR
|
||||
Cannot use variable "A" in extends chain.
|
@ -2820,7 +2820,13 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
|
||||
if (j == 0) {
|
||||
const Array &target_names = extras.has("targetNames") ? (Array)extras["targetNames"] : Array();
|
||||
for (int k = 0; k < targets.size(); k++) {
|
||||
import_mesh->add_blend_shape(k < target_names.size() ? (String)target_names[k] : String("morph_") + itos(k));
|
||||
String bs_name;
|
||||
if (k < target_names.size() && ((String)target_names[k]).size() != 0) {
|
||||
bs_name = (String)target_names[k];
|
||||
} else {
|
||||
bs_name = String("morph_") + itos(k);
|
||||
}
|
||||
import_mesh->add_blend_shape(bs_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4105,6 +4105,7 @@ RID TextServerAdvanced::_shaped_text_substr(const RID &p_shaped, int64_t p_start
|
||||
new_sd->direction = sd->direction;
|
||||
new_sd->custom_punct = sd->custom_punct;
|
||||
new_sd->para_direction = sd->para_direction;
|
||||
new_sd->base_para_direction = sd->base_para_direction;
|
||||
for (int i = 0; i < TextServer::SPACING_MAX; i++) {
|
||||
new_sd->extra_spacing[i] = sd->extra_spacing[i];
|
||||
}
|
||||
@ -4149,22 +4150,61 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S
|
||||
ERR_FAIL_COND_V_MSG((start < 0 || end - start > p_new_sd->utf16.length()), false, "Invalid BiDi override range.");
|
||||
|
||||
// Create temporary line bidi & shape.
|
||||
UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err);
|
||||
ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
|
||||
ubidi_setLine(p_sd->bidi_iter[ov], start, end, bidi_iter, &err);
|
||||
if (U_FAILURE(err)) {
|
||||
ubidi_close(bidi_iter);
|
||||
ERR_FAIL_V_MSG(false, u_errorName(err));
|
||||
UBiDi *bidi_iter = nullptr;
|
||||
if (p_sd->bidi_iter[ov]) {
|
||||
bidi_iter = ubidi_openSized(end - start, 0, &err);
|
||||
if (U_SUCCESS(err)) {
|
||||
ubidi_setLine(p_sd->bidi_iter[ov], start, end, bidi_iter, &err);
|
||||
if (U_FAILURE(err)) {
|
||||
// Line BiDi failed (string contains incompatible control characters), try full paragraph BiDi instead.
|
||||
err = U_ZERO_ERROR;
|
||||
const UChar *data = p_sd->utf16.get_data();
|
||||
switch (static_cast<TextServer::Direction>(p_sd->bidi_override[ov].z)) {
|
||||
case DIRECTION_LTR: {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);
|
||||
} break;
|
||||
case DIRECTION_RTL: {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);
|
||||
} break;
|
||||
case DIRECTION_INHERITED: {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, p_sd->base_para_direction, nullptr, &err);
|
||||
} break;
|
||||
case DIRECTION_AUTO: {
|
||||
UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);
|
||||
if (direction != UBIDI_NEUTRAL) {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);
|
||||
} else {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, p_sd->base_para_direction, nullptr, &err);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
if (U_FAILURE(err)) {
|
||||
ubidi_close(bidi_iter);
|
||||
bidi_iter = nullptr;
|
||||
ERR_PRINT(vformat("BiDi reordering for the line failed: %s", u_errorName(err)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bidi_iter = nullptr;
|
||||
ERR_PRINT(vformat("BiDi iterator allocation for the line failed: %s", u_errorName(err)));
|
||||
}
|
||||
}
|
||||
p_new_sd->bidi_iter.push_back(bidi_iter);
|
||||
|
||||
err = U_ZERO_ERROR;
|
||||
int bidi_run_count = ubidi_countRuns(bidi_iter, &err);
|
||||
ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
|
||||
int bidi_run_count = 1;
|
||||
if (bidi_iter) {
|
||||
bidi_run_count = ubidi_countRuns(bidi_iter, &err);
|
||||
if (U_FAILURE(err)) {
|
||||
ERR_PRINT(u_errorName(err));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < bidi_run_count; i++) {
|
||||
int32_t _bidi_run_start = 0;
|
||||
int32_t _bidi_run_length = 0;
|
||||
ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length);
|
||||
int32_t _bidi_run_length = end - start;
|
||||
if (bidi_iter) {
|
||||
ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length);
|
||||
}
|
||||
|
||||
int32_t bidi_run_start = _convert_pos(p_sd, ov_start + start + _bidi_run_start);
|
||||
int32_t bidi_run_end = _convert_pos(p_sd, ov_start + start + _bidi_run_start + _bidi_run_length);
|
||||
@ -5571,25 +5611,25 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
|
||||
sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length()));
|
||||
}
|
||||
|
||||
int base_para_direction = UBIDI_DEFAULT_LTR;
|
||||
sd->base_para_direction = UBIDI_DEFAULT_LTR;
|
||||
switch (sd->direction) {
|
||||
case DIRECTION_LTR: {
|
||||
sd->para_direction = DIRECTION_LTR;
|
||||
base_para_direction = UBIDI_LTR;
|
||||
sd->base_para_direction = UBIDI_LTR;
|
||||
} break;
|
||||
case DIRECTION_RTL: {
|
||||
sd->para_direction = DIRECTION_RTL;
|
||||
base_para_direction = UBIDI_RTL;
|
||||
sd->base_para_direction = UBIDI_RTL;
|
||||
} break;
|
||||
case DIRECTION_INHERITED:
|
||||
case DIRECTION_AUTO: {
|
||||
UBiDiDirection direction = ubidi_getBaseDirection(data, sd->utf16.length());
|
||||
if (direction != UBIDI_NEUTRAL) {
|
||||
sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;
|
||||
base_para_direction = direction;
|
||||
sd->base_para_direction = direction;
|
||||
} else {
|
||||
sd->para_direction = DIRECTION_LTR;
|
||||
base_para_direction = UBIDI_DEFAULT_LTR;
|
||||
sd->base_para_direction = UBIDI_DEFAULT_LTR;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@ -5609,38 +5649,53 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
|
||||
|
||||
UErrorCode err = U_ZERO_ERROR;
|
||||
UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err);
|
||||
ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
|
||||
|
||||
switch (static_cast<TextServer::Direction>(sd->bidi_override[ov].z)) {
|
||||
case DIRECTION_LTR: {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);
|
||||
} break;
|
||||
case DIRECTION_RTL: {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);
|
||||
} break;
|
||||
case DIRECTION_INHERITED: {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, base_para_direction, nullptr, &err);
|
||||
} break;
|
||||
case DIRECTION_AUTO: {
|
||||
UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);
|
||||
if (direction != UBIDI_NEUTRAL) {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);
|
||||
} else {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, base_para_direction, nullptr, &err);
|
||||
}
|
||||
} break;
|
||||
if (U_SUCCESS(err)) {
|
||||
switch (static_cast<TextServer::Direction>(sd->bidi_override[ov].z)) {
|
||||
case DIRECTION_LTR: {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);
|
||||
} break;
|
||||
case DIRECTION_RTL: {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);
|
||||
} break;
|
||||
case DIRECTION_INHERITED: {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, sd->base_para_direction, nullptr, &err);
|
||||
} break;
|
||||
case DIRECTION_AUTO: {
|
||||
UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);
|
||||
if (direction != UBIDI_NEUTRAL) {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);
|
||||
} else {
|
||||
ubidi_setPara(bidi_iter, data + start, end - start, sd->base_para_direction, nullptr, &err);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
if (U_FAILURE(err)) {
|
||||
ubidi_close(bidi_iter);
|
||||
bidi_iter = nullptr;
|
||||
ERR_PRINT(vformat("BiDi reordering for the paragraph failed: %s", u_errorName(err)));
|
||||
}
|
||||
} else {
|
||||
bidi_iter = nullptr;
|
||||
ERR_PRINT(vformat("BiDi iterator allocation for the paragraph failed: %s", u_errorName(err)));
|
||||
}
|
||||
ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
|
||||
sd->bidi_iter.push_back(bidi_iter);
|
||||
|
||||
err = U_ZERO_ERROR;
|
||||
int bidi_run_count = ubidi_countRuns(bidi_iter, &err);
|
||||
ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
|
||||
int bidi_run_count = 1;
|
||||
if (bidi_iter) {
|
||||
bidi_run_count = ubidi_countRuns(bidi_iter, &err);
|
||||
if (U_FAILURE(err)) {
|
||||
ERR_PRINT(u_errorName(err));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < bidi_run_count; i++) {
|
||||
int32_t _bidi_run_start = 0;
|
||||
int32_t _bidi_run_length = 0;
|
||||
int32_t _bidi_run_length = end - start;
|
||||
bool is_rtl = false;
|
||||
hb_direction_t bidi_run_direction = HB_DIRECTION_INVALID;
|
||||
bool is_rtl = (ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length) == UBIDI_LTR);
|
||||
if (bidi_iter) {
|
||||
is_rtl = (ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length) == UBIDI_LTR);
|
||||
}
|
||||
switch (sd->orientation) {
|
||||
case ORIENTATION_HORIZONTAL: {
|
||||
if (is_rtl) {
|
||||
@ -5697,7 +5752,7 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
|
||||
gl.start = span.start;
|
||||
gl.end = span.end;
|
||||
gl.count = 1;
|
||||
gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_VIRTUAL;
|
||||
gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_EMBEDDED_OBJECT;
|
||||
if (sd->orientation == ORIENTATION_HORIZONTAL) {
|
||||
gl.advance = sd->objects[span.embedded_key].rect.size.x;
|
||||
} else {
|
||||
|
@ -475,6 +475,7 @@ class TextServerAdvanced : public TextServerExtension {
|
||||
|
||||
/* Shaped data */
|
||||
TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction.
|
||||
int base_para_direction = UBIDI_DEFAULT_LTR;
|
||||
bool valid = false; // String is shaped.
|
||||
bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted).
|
||||
bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string.
|
||||
@ -514,7 +515,9 @@ class TextServerAdvanced : public TextServerExtension {
|
||||
|
||||
~ShapedTextDataAdvanced() {
|
||||
for (int i = 0; i < bidi_iter.size(); i++) {
|
||||
ubidi_close(bidi_iter[i]);
|
||||
if (bidi_iter[i]) {
|
||||
ubidi_close(bidi_iter[i]);
|
||||
}
|
||||
}
|
||||
if (script_iter) {
|
||||
memdelete(script_iter);
|
||||
|
@ -3664,7 +3664,7 @@ bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) {
|
||||
gl.end = span.end;
|
||||
gl.count = 1;
|
||||
gl.index = 0;
|
||||
gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_VIRTUAL;
|
||||
gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_EMBEDDED_OBJECT;
|
||||
if (sd->orientation == ORIENTATION_HORIZONTAL) {
|
||||
gl.advance = sd->objects[span.embedded_key].rect.size.x;
|
||||
} else {
|
||||
|
@ -124,11 +124,12 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
|
||||
public boolean onEditorAction(final TextView pTextView, final int pActionID, final KeyEvent pKeyEvent) {
|
||||
if (mEdit == pTextView && isFullScreenEdit() && pKeyEvent != null) {
|
||||
final String characters = pKeyEvent.getCharacters();
|
||||
|
||||
for (int i = 0; i < characters.length(); i++) {
|
||||
final int character = characters.codePointAt(i);
|
||||
GodotLib.key(0, character, 0, true);
|
||||
GodotLib.key(0, character, 0, false);
|
||||
if (characters != null) {
|
||||
for (int i = 0; i < characters.length(); i++) {
|
||||
final int character = characters.codePointAt(i);
|
||||
GodotLib.key(0, character, 0, true);
|
||||
GodotLib.key(0, character, 0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define TTS_ANDROID_H
|
||||
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "core/variant/array.h"
|
||||
#include "servers/display_server.h"
|
||||
|
||||
|
@ -38,8 +38,8 @@
|
||||
#endif
|
||||
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "core/templates/list.h"
|
||||
#include "core/templates/rb_map.h"
|
||||
#include "core/variant/array.h"
|
||||
#include "servers/display_server.h"
|
||||
|
||||
|
@ -34,8 +34,8 @@
|
||||
#include "core/os/thread.h"
|
||||
#include "core/os/thread_safe.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "core/templates/list.h"
|
||||
#include "core/templates/rb_map.h"
|
||||
#include "core/variant/array.h"
|
||||
#include "servers/display_server.h"
|
||||
|
||||
|
@ -768,7 +768,7 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
|
||||
|
||||
String certificate_file = p_preset->get("codesign/certificate_file");
|
||||
String certificate_pass = p_preset->get("codesign/certificate_password");
|
||||
if (!certificate_file.is_empty() && !certificate_file.is_empty()) {
|
||||
if (!certificate_file.is_empty() && !certificate_pass.is_empty()) {
|
||||
args.push_back("--p12-file");
|
||||
args.push_back(certificate_file);
|
||||
args.push_back("--p12-password");
|
||||
|
@ -32,8 +32,8 @@
|
||||
#define TTS_MACOS_H
|
||||
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "core/templates/list.h"
|
||||
#include "core/templates/rb_map.h"
|
||||
#include "core/variant/array.h"
|
||||
#include "servers/display_server.h"
|
||||
|
||||
|
@ -36,15 +36,16 @@ void __stdcall TTS_Windows::speech_event_callback(WPARAM wParam, LPARAM lParam)
|
||||
TTS_Windows *tts = TTS_Windows::get_singleton();
|
||||
SPEVENT event;
|
||||
while (tts->synth->GetEvents(1, &event, NULL) == S_OK) {
|
||||
if (tts->ids.has(event.ulStreamNum)) {
|
||||
uint32_t stream_num = (uint32_t)event.ulStreamNum;
|
||||
if (tts->ids.has(stream_num)) {
|
||||
if (event.eEventId == SPEI_START_INPUT_STREAM) {
|
||||
DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_STARTED, tts->ids[event.ulStreamNum].id);
|
||||
DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_STARTED, tts->ids[stream_num].id);
|
||||
} else if (event.eEventId == SPEI_END_INPUT_STREAM) {
|
||||
DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_ENDED, tts->ids[event.ulStreamNum].id);
|
||||
tts->ids.erase(event.ulStreamNum);
|
||||
DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_ENDED, tts->ids[stream_num].id);
|
||||
tts->ids.erase(stream_num);
|
||||
tts->_update_tts();
|
||||
} else if (event.eEventId == SPEI_WORD_BOUNDARY) {
|
||||
const Char16String &string = tts->ids[event.ulStreamNum].string;
|
||||
const Char16String &string = tts->ids[stream_num].string;
|
||||
int pos = 0;
|
||||
for (int i = 0; i < MIN(event.lParam, string.length()); i++) {
|
||||
char16_t c = string[i];
|
||||
@ -53,7 +54,7 @@ void __stdcall TTS_Windows::speech_event_callback(WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_BOUNDARY, tts->ids[event.ulStreamNum].id, pos - tts->ids[event.ulStreamNum].offset);
|
||||
DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_BOUNDARY, tts->ids[stream_num].id, pos - tts->ids[stream_num].offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -106,7 +107,7 @@ void TTS_Windows::_update_tts() {
|
||||
synth->SetRate(10.f * log10(message.rate) / log10(3.f));
|
||||
synth->Speak((LPCWSTR)ut.string.get_data(), flags, &stream_number);
|
||||
|
||||
ids[stream_number] = ut;
|
||||
ids[(uint32_t)stream_number] = ut;
|
||||
|
||||
queue.pop_front();
|
||||
}
|
||||
@ -230,9 +231,10 @@ void TTS_Windows::stop() {
|
||||
|
||||
SPVOICESTATUS status;
|
||||
synth->GetStatus(&status, nullptr);
|
||||
if (ids.has(status.ulCurrentStream)) {
|
||||
DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, ids[status.ulCurrentStream].id);
|
||||
ids.erase(status.ulCurrentStream);
|
||||
uint32_t current_stream = (uint32_t)status.ulCurrentStream;
|
||||
if (ids.has(current_stream)) {
|
||||
DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, ids[current_stream].id);
|
||||
ids.erase(current_stream);
|
||||
}
|
||||
for (DisplayServer::TTSUtterance &message : queue) {
|
||||
DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, message.id);
|
||||
|
@ -32,8 +32,8 @@
|
||||
#define TTS_WINDOWS_H
|
||||
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "core/templates/list.h"
|
||||
#include "core/templates/rb_map.h"
|
||||
#include "core/variant/array.h"
|
||||
#include "servers/display_server.h"
|
||||
|
||||
@ -54,7 +54,7 @@ class TTS_Windows {
|
||||
int offset;
|
||||
int id;
|
||||
};
|
||||
RBMap<ULONG, UTData> ids;
|
||||
HashMap<uint32_t, UTData> ids;
|
||||
|
||||
static void __stdcall speech_event_callback(WPARAM wParam, LPARAM lParam);
|
||||
void _update_tts();
|
||||
|
@ -722,12 +722,12 @@ void CPUParticles2D::_particles_process(double p_delta) {
|
||||
tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(0);
|
||||
}*/
|
||||
|
||||
real_t tex_angle = 0.0;
|
||||
real_t tex_angle = 1.0;
|
||||
if (curve_parameters[PARAM_ANGLE].is_valid()) {
|
||||
tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv);
|
||||
}
|
||||
|
||||
real_t tex_anim_offset = 0.0;
|
||||
real_t tex_anim_offset = 1.0;
|
||||
if (curve_parameters[PARAM_ANGLE].is_valid()) {
|
||||
tex_anim_offset = curve_parameters[PARAM_ANGLE]->sample(tv);
|
||||
}
|
||||
|
@ -742,12 +742,12 @@ void CPUParticles3D::_particles_process(double p_delta) {
|
||||
tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(0);
|
||||
}*/
|
||||
|
||||
real_t tex_angle = 0.0;
|
||||
real_t tex_angle = 1.0;
|
||||
if (curve_parameters[PARAM_ANGLE].is_valid()) {
|
||||
tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv);
|
||||
}
|
||||
|
||||
real_t tex_anim_offset = 0.0;
|
||||
real_t tex_anim_offset = 1.0;
|
||||
if (curve_parameters[PARAM_ANGLE].is_valid()) {
|
||||
tex_anim_offset = curve_parameters[PARAM_ANGLE]->sample(tv);
|
||||
}
|
||||
|
@ -1968,7 +1968,7 @@ void CodeEdit::confirm_code_completion(bool p_replace) {
|
||||
return;
|
||||
}
|
||||
|
||||
char32_t caret_last_completion_char;
|
||||
char32_t caret_last_completion_char = 0;
|
||||
begin_complex_operation();
|
||||
Vector<int> caret_edit_order = get_caret_index_edit_order();
|
||||
for (const int &i : caret_edit_order) {
|
||||
|
@ -500,8 +500,9 @@ void ColorPicker::_html_submitted(const String &p_html) {
|
||||
return;
|
||||
}
|
||||
|
||||
Color previous_color = color;
|
||||
color = Color::html(p_html);
|
||||
const Color previous_color = color;
|
||||
color = Color::from_string(p_html, previous_color);
|
||||
|
||||
if (!is_editing_alpha()) {
|
||||
color.a = previous_color.a;
|
||||
}
|
||||
@ -601,13 +602,13 @@ void ColorPicker::_text_type_toggled() {
|
||||
text_type->set_icon(get_theme_icon(SNAME("Script"), SNAME("EditorIcons")));
|
||||
|
||||
c_text->set_editable(false);
|
||||
c_text->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
c_text->set_tooltip_text(RTR("Copy this constructor in a script."));
|
||||
} else {
|
||||
text_type->set_text("#");
|
||||
text_type->set_icon(nullptr);
|
||||
|
||||
c_text->set_editable(true);
|
||||
c_text->set_h_size_flags(SIZE_FILL);
|
||||
c_text->set_tooltip_text(RTR("Enter a hex code (\"#ff0000\") or named color (\"red\")."));
|
||||
}
|
||||
_update_color();
|
||||
}
|
||||
@ -1754,7 +1755,10 @@ ColorPicker::ColorPicker() {
|
||||
|
||||
c_text = memnew(LineEdit);
|
||||
hex_hbc->add_child(c_text);
|
||||
c_text->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
c_text->set_select_all_on_focus(true);
|
||||
c_text->set_tooltip_text(RTR("Enter a hex code (\"#ff0000\") or named color (\"red\")."));
|
||||
c_text->set_placeholder(RTR("Hex code or named color"));
|
||||
c_text->connect("text_submitted", callable_mp(this, &ColorPicker::_html_submitted));
|
||||
c_text->connect("text_changed", callable_mp(this, &ColorPicker::_text_changed));
|
||||
c_text->connect("focus_exited", callable_mp(this, &ColorPicker::_html_focus_exit));
|
||||
|
@ -765,7 +765,7 @@ void Control::set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos,
|
||||
set_offset(p_side, p_pos);
|
||||
}
|
||||
|
||||
void Control::set_begin(const Size2 &p_point) {
|
||||
void Control::set_begin(const Point2 &p_point) {
|
||||
ERR_FAIL_COND(!isfinite(p_point.x) || !isfinite(p_point.y));
|
||||
if (data.offset[0] == p_point.x && data.offset[1] == p_point.y) {
|
||||
return;
|
||||
@ -776,11 +776,11 @@ void Control::set_begin(const Size2 &p_point) {
|
||||
_size_changed();
|
||||
}
|
||||
|
||||
Size2 Control::get_begin() const {
|
||||
return Size2(data.offset[0], data.offset[1]);
|
||||
Point2 Control::get_begin() const {
|
||||
return Point2(data.offset[0], data.offset[1]);
|
||||
}
|
||||
|
||||
void Control::set_end(const Size2 &p_point) {
|
||||
void Control::set_end(const Point2 &p_point) {
|
||||
if (data.offset[2] == p_point.x && data.offset[3] == p_point.y) {
|
||||
return;
|
||||
}
|
||||
@ -790,8 +790,8 @@ void Control::set_end(const Size2 &p_point) {
|
||||
_size_changed();
|
||||
}
|
||||
|
||||
Size2 Control::get_end() const {
|
||||
return Size2(data.offset[2], data.offset[3]);
|
||||
Point2 Control::get_end() const {
|
||||
return Point2(data.offset[2], data.offset[3]);
|
||||
}
|
||||
|
||||
void Control::set_h_grow_direction(GrowDirection p_direction) {
|
||||
@ -1358,11 +1358,11 @@ void Control::set_grow_direction_preset(LayoutPreset p_preset) {
|
||||
|
||||
/// Manual positioning.
|
||||
|
||||
void Control::_set_position(const Size2 &p_point) {
|
||||
void Control::_set_position(const Point2 &p_point) {
|
||||
set_position(p_point);
|
||||
}
|
||||
|
||||
void Control::set_position(const Size2 &p_point, bool p_keep_offsets) {
|
||||
void Control::set_position(const Point2 &p_point, bool p_keep_offsets) {
|
||||
if (p_keep_offsets) {
|
||||
_compute_anchors(Rect2(p_point, data.size_cache), data.offset, data.anchor);
|
||||
} else {
|
||||
|
@ -952,7 +952,7 @@ void LineEdit::_notification(int p_what) {
|
||||
if (ceil(ofs.x) >= x_ofs && (ofs.x + glyphs[i].advance) <= ofs_max) {
|
||||
if (glyphs[i].font_rid != RID()) {
|
||||
TS->font_draw_glyph(glyphs[i].font_rid, ci, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_selected_color : font_color);
|
||||
} else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
|
||||
} else if (((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) && ((glyphs[i].flags & TextServer::GRAPHEME_IS_EMBEDDED_OBJECT) != TextServer::GRAPHEME_IS_EMBEDDED_OBJECT)) {
|
||||
TS->draw_hex_code_box(ci, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_selected_color : font_color);
|
||||
}
|
||||
}
|
||||
|
@ -1323,7 +1323,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
|
||||
if (!skip) {
|
||||
if (frid != RID()) {
|
||||
TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, font_color);
|
||||
} else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
|
||||
} else if (((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) && ((glyphs[i].flags & TextServer::GRAPHEME_IS_EMBEDDED_OBJECT) != TextServer::GRAPHEME_IS_EMBEDDED_OBJECT)) {
|
||||
TS->draw_hex_code_box(ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, font_color);
|
||||
}
|
||||
}
|
||||
@ -1510,7 +1510,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
|
||||
}
|
||||
if (crect.has_point(p_click)) {
|
||||
for (int j = 0; j < (int)frame->lines.size(); j++) {
|
||||
_find_click_in_line(frame, j, rect.position + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_click, &table_click_frame, &table_click_line, &table_click_item, &table_click_char, true, p_meta);
|
||||
_find_click_in_line(frame, j, rect.position + Vector2(frame->padding.position.x, frame->lines[j].offset.y), rect.size.x, p_click, &table_click_frame, &table_click_line, &table_click_item, &table_click_char, true, p_meta);
|
||||
if (table_click_frame && table_click_item) {
|
||||
// Save cell detected cell hit data.
|
||||
table_range = Vector2i(INT32_MAX, 0);
|
||||
@ -2697,6 +2697,10 @@ bool RichTextLabel::is_ready() const {
|
||||
return (main->first_invalid_line.load() == (int)main->lines.size() && main->first_resized_line.load() == (int)main->lines.size() && main->first_invalid_font_line.load() == (int)main->lines.size());
|
||||
}
|
||||
|
||||
bool RichTextLabel::is_updating() const {
|
||||
return updating.load() || validating.load();
|
||||
}
|
||||
|
||||
void RichTextLabel::set_threaded(bool p_threaded) {
|
||||
if (threaded != p_threaded) {
|
||||
_stop_thread();
|
||||
@ -2721,6 +2725,7 @@ bool RichTextLabel::_validate_line_caches() {
|
||||
if (updating.load()) {
|
||||
return false;
|
||||
}
|
||||
validating.store(true);
|
||||
if (main->first_invalid_line.load() == (int)main->lines.size()) {
|
||||
MutexLock data_lock(data_mutex);
|
||||
Rect2 text_rect = _get_text_rect();
|
||||
@ -2739,6 +2744,7 @@ bool RichTextLabel::_validate_line_caches() {
|
||||
|
||||
if (main->first_resized_line.load() == (int)main->lines.size()) {
|
||||
vscroll->set_value(old_scroll);
|
||||
validating.store(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2790,8 +2796,10 @@ bool RichTextLabel::_validate_line_caches() {
|
||||
if (fit_content) {
|
||||
update_minimum_size();
|
||||
}
|
||||
validating.store(false);
|
||||
return true;
|
||||
}
|
||||
validating.store(false);
|
||||
stop_thread.store(false);
|
||||
if (threaded) {
|
||||
updating.store(true);
|
||||
@ -2801,7 +2809,9 @@ bool RichTextLabel::_validate_line_caches() {
|
||||
loading_started = OS::get_singleton()->get_ticks_msec();
|
||||
return false;
|
||||
} else {
|
||||
updating.store(true);
|
||||
_process_line_caches();
|
||||
updating.store(false);
|
||||
queue_redraw();
|
||||
return true;
|
||||
}
|
||||
@ -5882,6 +5892,7 @@ RichTextLabel::RichTextLabel(const String &p_text) {
|
||||
|
||||
set_text(p_text);
|
||||
updating.store(false);
|
||||
validating.store(false);
|
||||
stop_thread.store(false);
|
||||
|
||||
set_clip_contents(true);
|
||||
|
@ -376,6 +376,7 @@ private:
|
||||
bool threaded = false;
|
||||
std::atomic<bool> stop_thread;
|
||||
std::atomic<bool> updating;
|
||||
std::atomic<bool> validating;
|
||||
std::atomic<double> loaded;
|
||||
|
||||
uint64_t loading_started = 0;
|
||||
@ -679,6 +680,7 @@ public:
|
||||
void deselect();
|
||||
|
||||
bool is_ready() const;
|
||||
bool is_updating() const;
|
||||
|
||||
void set_threaded(bool p_threaded);
|
||||
bool is_threaded() const;
|
||||
|
@ -1276,7 +1276,7 @@ void TextEdit::_notification(int p_what) {
|
||||
if (glyphs[j].font_rid != RID()) {
|
||||
TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color);
|
||||
had_glyphs_drawn = true;
|
||||
} else if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
|
||||
} else if (((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) && ((glyphs[j].flags & TextServer::GRAPHEME_IS_EMBEDDED_OBJECT) != TextServer::GRAPHEME_IS_EMBEDDED_OBJECT)) {
|
||||
TS->draw_hex_code_box(ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color);
|
||||
had_glyphs_drawn = true;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user