summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore29
-rw-r--r--core/bind/core_bind.cpp6
-rw-r--r--core/bind/core_bind.h2
-rw-r--r--core/ustring.cpp39
-rw-r--r--core/ustring.h1
-rw-r--r--doc/classes/@GlobalScope.xml2
-rw-r--r--doc/classes/Camera.xml18
-rw-r--r--doc/classes/Color.xml2
-rw-r--r--doc/classes/EditorNavigationMeshGenerator.xml31
-rw-r--r--doc/classes/NavigationMesh.xml28
-rw-r--r--doc/classes/OS.xml24
-rw-r--r--doc/classes/Popup.xml11
-rw-r--r--doc/classes/ProjectSettings.xml4
-rw-r--r--doc/classes/SceneTree.xml6
-rw-r--r--doc/classes/SpatialMaterial.xml6
-rw-r--r--doc/classes/SurfaceTool.xml18
-rw-r--r--doc/classes/Tree.xml6
-rw-r--r--doc/classes/VehicleWheel.xml6
-rw-r--r--doc/classes/VisualServer.xml2
-rw-r--r--doc/classes/VisualShader.xml22
-rw-r--r--doc/classes/VisualShaderNodeExpression.xml23
-rw-r--r--doc/classes/VisualShaderNodeGroupBase.xml205
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h1
-rw-r--r--editor/create_dialog.cpp47
-rw-r--r--editor/create_dialog.h5
-rw-r--r--editor/editor_fonts.cpp2
-rw-r--r--editor/editor_node.cpp17
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/editor_plugin.cpp20
-rw-r--r--editor/editor_plugin.h4
-rw-r--r--editor/editor_settings.cpp2
-rw-r--r--editor/filesystem_dock.cpp14
-rw-r--r--editor/filesystem_dock.h1
-rw-r--r--editor/plugins/sprite_editor_plugin.cpp36
-rw-r--r--editor/plugins/sprite_editor_plugin.h2
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp53
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp9
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp1
-rw-r--r--editor/project_export.cpp9
-rw-r--r--editor/project_settings_editor.cpp10
-rw-r--r--editor/scene_tree_dock.cpp74
-rw-r--r--editor/scene_tree_dock.h5
-rw-r--r--editor/settings_config_dialog.cpp9
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp19
-rw-r--r--modules/gdscript/gdscript_parser.cpp8
-rw-r--r--modules/gdscript/gdscript_parser.h2
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp27
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.cpp1
-rw-r--r--platform/android/java/src/org/godotengine/godot/Godot.java3
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotView.java72
-rw-r--r--platform/android/java_godot_wrapper.cpp8
-rw-r--r--platform/android/java_godot_wrapper.h2
-rw-r--r--platform/android/os_android.cpp4
-rw-r--r--platform/windows/os_windows.cpp8
-rw-r--r--platform/x11/context_gl_x11.cpp1
-rw-r--r--scene/2d/tile_map.cpp97
-rw-r--r--scene/3d/arvr_nodes.cpp6
-rw-r--r--scene/3d/arvr_nodes.h2
-rw-r--r--scene/3d/camera.cpp10
-rw-r--r--scene/3d/camera.h2
-rw-r--r--scene/3d/proximity_group.cpp1
-rw-r--r--scene/3d/vehicle_body.cpp14
-rw-r--r--scene/3d/vehicle_body.h3
-rw-r--r--scene/animation/animation_tree.cpp1
-rw-r--r--scene/gui/popup.cpp13
-rw-r--r--scene/gui/popup.h1
-rw-r--r--scene/gui/slider.cpp1
-rw-r--r--scene/gui/tree.cpp4
-rw-r--r--scene/main/node.cpp4
-rw-r--r--scene/resources/font.cpp8
-rw-r--r--scene/resources/material.cpp7
-rw-r--r--scene/resources/surface_tool.cpp22
-rw-r--r--scene/resources/surface_tool.h1
-rw-r--r--servers/visual/visual_server_raster.cpp4
74 files changed, 872 insertions, 297 deletions
diff --git a/.gitignore b/.gitignore
index cd6785a8ec..4ef5603f52 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,7 +14,6 @@ platform/android/java/local.properties
platform/android/java/project.properties
platform/android/java/libs/*
platform/android/java/assets
-platform/android/java/.idea/*
platform/android/java/*.iml
# General c++ generated files
@@ -52,13 +51,19 @@ gmon.out
# Eclipse CDT files
.cproject
.settings/
+*.pydevproject
+*.launch
# Geany/geany-plugins files
*.geany
.geanyprj
+# Jetbrains IDEs
+.idea/
+
# Misc
.DS_Store
+__MACOSX
logs/
# for projects that use SCons for building: http://http://www.scons.org/
@@ -66,7 +71,6 @@ logs/
.sconsign.dblite
*.pyc
-
# https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
@@ -123,6 +127,7 @@ TestResult.xml
*.tlh
*.tmp
*.tmp_proj
+*.bak
*.log
*.vspscc
*.vssscc
@@ -130,6 +135,7 @@ TestResult.xml
*.pidb
*.svclog
*.scc
+*.nib
# Chutzpah Test files
_Chutzpah*
@@ -245,8 +251,11 @@ __pycache__/
#Kdevelop project files
*.kdev4
-# xCode
-xcuserdata
+# Xcode
+xcuserdata/
+*.xcscmblueprint
+*.xccheckout
+*.xcodeproj/*
# RIA/Silverlight projects
Generated_Code/
@@ -275,11 +284,19 @@ FakesAssemblies/
# =========================
# Windows image file caches
-Thumbs.db
+[Tt]humbs.db
+[Tt]humbs.db:encryptable
ehthumbs.db
+ehthumbs_vista.db
+
+# Windows stackdumps
+*.stackdump
+
+# Windows shortcuts
+*.lnk
# Folder config file
-Desktop.ini
+[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 27b33d942b..dbfa04be4d 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -442,14 +442,14 @@ Error _OS::shell_open(String p_uri) {
return OS::get_singleton()->shell_open(p_uri);
};
-int _OS::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output) {
+int _OS::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output, bool p_read_stderr) {
OS::ProcessID pid = -2;
List<String> args;
for (int i = 0; i < p_arguments.size(); i++)
args.push_back(p_arguments[i]);
String pipe;
- Error err = OS::get_singleton()->execute(p_path, args, p_blocking, &pid, &pipe);
+ Error err = OS::get_singleton()->execute(p_path, args, p_blocking, &pid, &pipe, NULL, p_read_stderr);
p_output.clear();
p_output.push_back(pipe);
if (err != OK)
@@ -1183,7 +1183,7 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_processor_count"), &_OS::get_processor_count);
ClassDB::bind_method(D_METHOD("get_executable_path"), &_OS::get_executable_path);
- ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "blocking", "output"), &_OS::execute, DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "blocking", "output", "read_stderr"), &_OS::execute, DEFVAL(Array()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("kill", "pid"), &_OS::kill);
ClassDB::bind_method(D_METHOD("shell_open", "uri"), &_OS::shell_open);
ClassDB::bind_method(D_METHOD("get_process_id"), &_OS::get_process_id);
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index 3e46d24627..8f74d88be5 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -214,7 +214,7 @@ public:
bool is_in_low_processor_usage_mode() const;
String get_executable_path() const;
- int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output = Array());
+ int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output = Array(), bool p_read_stderr = false);
Error kill(int p_pid);
Error shell_open(String p_uri);
diff --git a/core/ustring.cpp b/core/ustring.cpp
index 78feddb229..954c39c150 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -1725,6 +1725,45 @@ int64_t String::hex_to_int64(bool p_with_prefix) const {
return hex * sign;
}
+int64_t String::bin_to_int64(bool p_with_prefix) const {
+
+ if (p_with_prefix && length() < 3)
+ return 0;
+
+ const CharType *s = ptr();
+
+ int64_t sign = s[0] == '-' ? -1 : 1;
+
+ if (sign < 0) {
+ s++;
+ }
+
+ if (p_with_prefix) {
+ if (s[0] != '0' || s[1] != 'b')
+ return 0;
+ s += 2;
+ }
+
+ int64_t binary = 0;
+
+ while (*s) {
+
+ CharType c = LOWERCASE(*s);
+ int64_t n;
+ if (c == '0' || c == '1') {
+ n = c - '0';
+ } else {
+ return 0;
+ }
+
+ binary *= 2;
+ binary += n;
+ s++;
+ }
+
+ return binary * sign;
+}
+
int String::to_int() const {
if (length() == 0)
diff --git a/core/ustring.h b/core/ustring.h
index e2e62874d6..be6300ac5b 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -251,6 +251,7 @@ public:
int to_int() const;
int64_t hex_to_int64(bool p_with_prefix = true) const;
+ int64_t bin_to_int64(bool p_with_prefix = true) const;
int64_t to_int64() const;
static int to_int(const char *p_str, int p_len = -1);
static double to_double(const char *p_str);
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index d1e2a9c910..760287e1b8 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -45,6 +45,8 @@
<member name="Marshalls" type="Reference" setter="" getter="">
[Marshalls] singleton
</member>
+ <member name="NavigationMeshGenerator" type="EditorNavigationMeshGenerator" setter="" getter="">
+ </member>
<member name="OS" type="OS" setter="" getter="">
[OS] singleton
</member>
diff --git a/doc/classes/Camera.xml b/doc/classes/Camera.xml
index 0b7021b4a1..cc869d28a2 100644
--- a/doc/classes/Camera.xml
+++ b/doc/classes/Camera.xml
@@ -18,6 +18,13 @@
If this is the current Camera, remove it from being current. If [code]enable_next[/code] is [code]true[/code], request to make the next Camera current, if any.
</description>
</method>
+ <method name="get_camera_rid" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ Returns the camera's RID from the [VisualServer].
+ </description>
+ </method>
<method name="get_camera_transform" qualifiers="const">
<return type="Transform">
</return>
@@ -39,13 +46,6 @@
<description>
</description>
</method>
- <method name="get_camera_rid" qualifiers="const">
- <return type="RID">
- </return>
- <description>
- Returns the camera's RID from the [VisualServer].
- </description>
- </method>
<method name="is_position_behind" qualifiers="const">
<return type="bool">
</return>
@@ -76,8 +76,10 @@
</return>
<argument index="0" name="screen_point" type="Vector2">
</argument>
+ <argument index="1" name="z_depth" type="float" default="0">
+ </argument>
<description>
- Returns the 3D point in worldspace that maps to the given 2D coordinate in the [Viewport] rectangle.
+ Returns the 3D point in worldspace that maps to the given 2D coordinate in the [Viewport] rectangle on a plane that is the given distance into the scene away from the camera.
</description>
</method>
<method name="project_ray_normal" qualifiers="const">
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index 9f48f6e018..ab5d7a0a5d 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -566,6 +566,8 @@
</constant>
<constant name="tomato" value="Color( 1, 0.39, 0.28, 1 )">
</constant>
+ <constant name="transparent" value="Color( 1, 1, 1, 0 )">
+ </constant>
<constant name="turquoise" value="Color( 0.25, 0.88, 0.82, 1 )">
</constant>
<constant name="violet" value="Color( 0.93, 0.51, 0.93, 1 )">
diff --git a/doc/classes/EditorNavigationMeshGenerator.xml b/doc/classes/EditorNavigationMeshGenerator.xml
new file mode 100644
index 0000000000..3956e12509
--- /dev/null
+++ b/doc/classes/EditorNavigationMeshGenerator.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorNavigationMeshGenerator" inherits="Object" category="Core" version="3.2">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="bake">
+ <return type="void">
+ </return>
+ <argument index="0" name="nav_mesh" type="NavigationMesh">
+ </argument>
+ <argument index="1" name="root_node" type="Node">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="clear">
+ <return type="void">
+ </return>
+ <argument index="0" name="nav_mesh" type="NavigationMesh">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/NavigationMesh.xml b/doc/classes/NavigationMesh.xml
index 2788eb053a..79ad7f63ae 100644
--- a/doc/classes/NavigationMesh.xml
+++ b/doc/classes/NavigationMesh.xml
@@ -29,6 +29,14 @@
<description>
</description>
</method>
+ <method name="get_collision_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="get_polygon">
<return type="PoolIntArray">
</return>
@@ -49,6 +57,16 @@
<description>
</description>
</method>
+ <method name="set_collision_mask_bit">
+ <return type="void">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_vertices">
<return type="void">
</return>
@@ -85,6 +103,10 @@
</member>
<member name="filter/low_hanging_obstacles" type="bool" setter="set_filter_low_hanging_obstacles" getter="get_filter_low_hanging_obstacles">
</member>
+ <member name="geometry/collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask">
+ </member>
+ <member name="geometry/parsed_geometry_type" type="int" setter="set_parsed_geometry_type" getter="get_parsed_geometry_type">
+ </member>
<member name="polygon/verts_per_poly" type="float" setter="set_verts_per_poly" getter="get_verts_per_poly">
</member>
<member name="region/merge_size" type="float" setter="set_region_merge_size" getter="get_region_merge_size">
@@ -101,5 +123,11 @@
</constant>
<constant name="SAMPLE_PARTITION_LAYERS" value="2">
</constant>
+ <constant name="PARSED_GEOMETRY_MESH_INSTANCES" value="0">
+ </constant>
+ <constant name="PARSED_GEOMETRY_STATIC_COLLIDERS" value="1">
+ </constant>
+ <constant name="PARSED_GEOMETRY_BOTH" value="2">
+ </constant>
</constants>
</class>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index ec2ee78701..dd0fcd63e7 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -97,6 +97,8 @@
</argument>
<argument index="3" name="output" type="Array" default="[ ]">
</argument>
+ <argument index="4" name="read_stderr" type="bool" default="false">
+ </argument>
<description>
Execute the file at the given path with the arguments passed as an array of strings. Platform path resolution will take place. The resolved file must exist and be executable.
The arguments are used in the given order and separated by a space, so [code]OS.execute('ping', ['-w', '3', 'godotengine.org'], false)[/code] will resolve to [code]ping -w 3 godotengine.org[/code] in the system's shell.
@@ -701,17 +703,6 @@
The same image is used for window caption, taskbar/dock and window selection dialog. Image is scaled as needed.
</description>
</method>
- <method name="set_native_icon">
- <return type="void">
- </return>
- <argument index="0" name="filename" type="String">
- </argument>
- <description>
- Sets the game's icon using a multi-size platform-specific icon file ([code]*.ico[/code] on Windows and [code]*.icns[/code] on macOS).
- Appropriate size sub-icons are used for window caption, taskbar/dock and window selection dialog.
- Note: This method is only implemented on macOS and Windows.
- </description>
- </method>
<method name="set_ime_active">
<return type="void">
</return>
@@ -730,6 +721,17 @@
Sets position of IME suggestion list popup (in window coordinates).
</description>
</method>
+ <method name="set_native_icon">
+ <return type="void">
+ </return>
+ <argument index="0" name="filename" type="String">
+ </argument>
+ <description>
+ Sets the game's icon using a multi-size platform-specific icon file ([code]*.ico[/code] on Windows and [code]*.icns[/code] on macOS).
+ Appropriate size sub-icons are used for window caption, taskbar/dock and window selection dialog.
+ Note: This method is only implemented on macOS and Windows.
+ </description>
+ </method>
<method name="set_thread_name">
<return type="int" enum="Error">
</return>
diff --git a/doc/classes/Popup.xml b/doc/classes/Popup.xml
index c3256f2f5b..e1b51463b2 100644
--- a/doc/classes/Popup.xml
+++ b/doc/classes/Popup.xml
@@ -27,6 +27,17 @@
Popup (show the control in modal form) in the center of the screen relative to its current canvas transform, at the current size, or at a size determined by "size".
</description>
</method>
+ <method name="popup_centered_clamped">
+ <return type="void">
+ </return>
+ <argument index="0" name="size" type="Vector2" default="Vector2( 0, 0 )">
+ </argument>
+ <argument index="1" name="fallback_ratio" type="float" default="0.75">
+ </argument>
+ <description>
+ Popup (show the control in modal form) in the center of the screen relative to the current canvas transform, clamping the size to [code]size[/code], then ensuring the popup is no larger than the viewport size multiplied by [code]fallback_ratio[/code].
+ </description>
+ </method>
<method name="popup_centered_minsize">
<return type="void">
</return>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 4b5500d077..ff8b702859 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -180,6 +180,8 @@
<member name="application/config/icon" type="String" setter="" getter="">
Icon used for the project, set when project loads. Exporters will also use this icon when possible.
</member>
+ <member name="application/config/macos_native_icon" type="String" setter="" getter="">
+ </member>
<member name="application/config/name" type="String" setter="" getter="">
The project's name. It is used both by the Project Manager and by exporters. The project name can be translated by translating its value in localization files.
</member>
@@ -189,6 +191,8 @@
<member name="application/config/use_custom_user_dir" type="bool" setter="" getter="">
If [code]true[/code], the project will save user data to its own user directory (see [member application/config/custom_user_dir_name]). This setting is only effective on desktop platforms. A name must be set in the [member application/config/custom_user_dir_name] setting for this to take effect. If [code]false[/code], the project will save user data to [code](OS user data directory)/Godot/app_userdata/(project name)[/code].
</member>
+ <member name="application/config/windows_native_icon" type="String" setter="" getter="">
+ </member>
<member name="application/run/disable_stderr" type="bool" setter="" getter="">
If [code]true[/code], disables printing to standard error in an exported build.
</member>
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index 0b1f659da3..a236d776c7 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -359,6 +359,12 @@
Emitted whenever a node is removed from the SceneTree.
</description>
</signal>
+ <signal name="node_renamed">
+ <argument index="0" name="node" type="Node">
+ </argument>
+ <description>
+ </description>
+ </signal>
<signal name="physics_frame">
<description>
Emitted immediately before [method Node._physics_process] is called on every node in the SceneTree.
diff --git a/doc/classes/SpatialMaterial.xml b/doc/classes/SpatialMaterial.xml
index 8e93160af9..f0df5fac4a 100644
--- a/doc/classes/SpatialMaterial.xml
+++ b/doc/classes/SpatialMaterial.xml
@@ -120,6 +120,8 @@
<member name="flags_use_point_size" type="bool" setter="set_flag" getter="get_flag">
If [code]true[/code], render point size can be changed. Note: this is only effective for objects whose geometry is point-based rather than triangle-based. See also [member params_point_size].
</member>
+ <member name="flags_use_shadow_to_opacity" type="bool" setter="set_flag" getter="get_flag">
+ </member>
<member name="flags_vertex_lighting" type="bool" setter="set_flag" getter="get_flag">
If [code]true[/code], lighting is calculated per vertex rather than per pixel. This may increase performance on low-end devices. Default value: [code]false[/code].
</member>
@@ -390,7 +392,9 @@
</constant>
<constant name="FLAG_ENSURE_CORRECT_NORMALS" value="16" enum="Flags">
</constant>
- <constant name="FLAG_MAX" value="18" enum="Flags">
+ <constant name="FLAG_USE_SHADOW_TO_OPACITY" value="18" enum="Flags">
+ </constant>
+ <constant name="FLAG_MAX" value="19" enum="Flags">
</constant>
<constant name="DIFFUSE_BURLEY" value="0" enum="DiffuseMode">
Default diffuse scattering algorithm.
diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml
index 25188a80db..e97f9995ee 100644
--- a/doc/classes/SurfaceTool.xml
+++ b/doc/classes/SurfaceTool.xml
@@ -169,6 +169,12 @@
Returns a constructed [ArrayMesh] from current information passed in. If an existing [ArrayMesh] is passed in as an argument, will add an extra surface to the existing [ArrayMesh].
</description>
</method>
+ <method name="commit_to_arrays">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="create_from">
<return type="void">
</return>
@@ -180,6 +186,18 @@
Creates a vertex array from an existing [Mesh].
</description>
</method>
+ <method name="create_from_blend_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="existing" type="Mesh">
+ </argument>
+ <argument index="1" name="surface" type="int">
+ </argument>
+ <argument index="2" name="blend_shape" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="deindex">
<return type="void">
</return>
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index b60673bb5b..0272efeecb 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -271,6 +271,12 @@
Emitted when a cell with the [code]CELL_MODE_CUSTOM[/code] is clicked to be edited.
</description>
</signal>
+ <signal name="empty_rmb">
+ <argument index="0" name="position" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </signal>
<signal name="empty_tree_rmb_selected">
<argument index="0" name="position" type="Vector2">
</argument>
diff --git a/doc/classes/VehicleWheel.xml b/doc/classes/VehicleWheel.xml
index f8dac82cb5..c3b668c170 100644
--- a/doc/classes/VehicleWheel.xml
+++ b/doc/classes/VehicleWheel.xml
@@ -9,6 +9,12 @@
<tutorials>
</tutorials>
<methods>
+ <method name="get_rpm" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_skidinfo" qualifiers="const">
<return type="float">
</return>
diff --git a/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml
index 3563120f0f..3997798cca 100644
--- a/doc/classes/VisualServer.xml
+++ b/doc/classes/VisualServer.xml
@@ -3597,7 +3597,7 @@
get_viewport().set_attach_to_screen_rect(Rect2())
$Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))
[/codeblock]
- Using this can result in significant optimization, especially on lower-end devices. However, it comes at the cost of having to manage your viewports manually. For a further optimization see, [method set_render_direct_to_screen].
+ Using this can result in significant optimization, especially on lower-end devices. However, it comes at the cost of having to manage your viewports manually. For a further optimization see, [method viewport_set_render_direct_to_screen].
</description>
</method>
<method name="viewport_create">
diff --git a/doc/classes/VisualShader.xml b/doc/classes/VisualShader.xml
index d399f69c96..6d5f53d992 100644
--- a/doc/classes/VisualShader.xml
+++ b/doc/classes/VisualShader.xml
@@ -53,6 +53,22 @@
<description>
</description>
</method>
+ <method name="connect_nodes_forced">
+ <return type="void">
+ </return>
+ <argument index="0" name="type" type="int" enum="VisualShader.Type">
+ </argument>
+ <argument index="1" name="from_node" type="int">
+ </argument>
+ <argument index="2" name="from_port" type="int">
+ </argument>
+ <argument index="3" name="to_node" type="int">
+ </argument>
+ <argument index="4" name="to_port" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="disconnect_nodes">
<return type="void">
</return>
@@ -129,6 +145,12 @@
<description>
</description>
</method>
+ <method name="rebuild">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="remove_node">
<return type="void">
</return>
diff --git a/doc/classes/VisualShaderNodeExpression.xml b/doc/classes/VisualShaderNodeExpression.xml
new file mode 100644
index 0000000000..8a5477280f
--- /dev/null
+++ b/doc/classes/VisualShaderNodeExpression.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeExpression" inherits="VisualShaderNodeGroupBase" category="Core" version="3.2">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="build">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="expression" type="String" setter="set_expression" getter="get_expression">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeGroupBase.xml b/doc/classes/VisualShaderNodeGroupBase.xml
new file mode 100644
index 0000000000..37d48956f6
--- /dev/null
+++ b/doc/classes/VisualShaderNodeGroupBase.xml
@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeGroupBase" inherits="VisualShaderNode" category="Core" version="3.2">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_input_port">
+ <return type="void">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="type" type="int">
+ </argument>
+ <argument index="2" name="name" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_output_port">
+ <return type="void">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="type" type="int">
+ </argument>
+ <argument index="2" name="name" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="clear_input_ports">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="clear_output_ports">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_control">
+ <return type="Control">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_free_input_port_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_free_output_port_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_input_port_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_inputs" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_output_port_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_outputs" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_size" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="has_input_port" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_output_port" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_input_port">
+ <return type="void">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_output_port">
+ <return type="void">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_control">
+ <return type="void">
+ </return>
+ <argument index="0" name="control" type="Control">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_input_port_name">
+ <return type="void">
+ </return>
+ <argument index="0" name="arg0" type="int">
+ </argument>
+ <argument index="1" name="arg1" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_input_port_type">
+ <return type="void">
+ </return>
+ <argument index="0" name="arg0" type="int">
+ </argument>
+ <argument index="1" name="arg1" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_inputs">
+ <return type="void">
+ </return>
+ <argument index="0" name="inputs" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_output_port_name">
+ <return type="void">
+ </return>
+ <argument index="0" name="arg0" type="int">
+ </argument>
+ <argument index="1" name="arg1" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_output_port_type">
+ <return type="void">
+ </return>
+ <argument index="0" name="arg0" type="int">
+ </argument>
+ <argument index="1" name="arg1" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_outputs">
+ <return type="void">
+ </return>
+ <argument index="0" name="outputs" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_size">
+ <return type="void">
+ </return>
+ <argument index="0" name="size" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index 99aa34e1ce..3d86558407 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -297,6 +297,7 @@ public:
target(GL_TEXTURE_2D),
data_size(0),
compressed(false),
+ srgb(false),
total_data_size(0),
ignore_mipmaps(false),
mipmaps(0),
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index ac42f15f7f..604a050fcd 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -38,7 +38,7 @@
#include "editor_settings.h"
#include "scene/gui/box_container.h"
-void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode) {
+void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const String &p_select_type) {
type_list.clear();
ClassDB::get_class_list(&type_list);
@@ -93,14 +93,7 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode) {
if (saved_size != Rect2()) {
popup(saved_size);
} else {
-
- Size2 popup_size = Size2(900, 700) * editor_get_scale();
- Size2 window_size = get_viewport_rect().size;
-
- popup_size.x = MIN(window_size.x * 0.8, popup_size.x);
- popup_size.y = MIN(window_size.y * 0.8, popup_size.y);
-
- popup_centered(popup_size);
+ popup_centered_clamped(Size2(900, 700) * EDSCALE, 0.8);
}
if (p_dont_clear) {
@@ -116,6 +109,7 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode) {
is_replace_mode = p_replace_mode;
if (p_replace_mode) {
+ select_type(p_select_type);
set_title(vformat(TTR("Change %s Type"), base_type));
get_ok()->set_text(TTR("Change"));
} else {
@@ -258,6 +252,27 @@ bool CreateDialog::_is_class_disabled_by_feature_profile(const StringName &p_cla
return false;
}
+void CreateDialog::select_type(const String &p_type) {
+ TreeItem *to_select;
+ if (search_options_types.has(p_type)) {
+ to_select = search_options_types[p_type];
+ } else {
+ to_select = search_options->get_root();
+ }
+
+ // uncollapse from selected type to top level
+ // TODO: should this be in tree?
+ TreeItem *cur = to_select;
+ while (cur) {
+ cur->set_collapsed(false);
+ cur = cur->get_parent();
+ }
+
+ to_select->select(0);
+
+ search_options->scroll_to_item(to_select);
+}
+
void CreateDialog::_update_search() {
search_options->clear();
@@ -269,7 +284,7 @@ void CreateDialog::_update_search() {
_parse_fs(EditorFileSystem::get_singleton()->get_filesystem());
*/
- HashMap<String, TreeItem *> types;
+ search_options_types.clear();
TreeItem *root = search_options->create_item();
EditorData &ed = EditorNode::get_editor_data();
@@ -307,7 +322,7 @@ void CreateDialog::_update_search() {
}
if (search_box->get_text() == "") {
- add_type(type, types, root, &to_select);
+ add_type(type, search_options_types, root, &to_select);
} else {
bool found = false;
@@ -323,7 +338,7 @@ void CreateDialog::_update_search() {
}
if (found)
- add_type(I->get(), types, root, &to_select);
+ add_type(I->get(), search_options_types, root, &to_select);
}
if (EditorNode::get_editor_data().get_custom_types().has(type) && ClassDB::is_parent_class(type, base_type)) {
@@ -337,12 +352,12 @@ void CreateDialog::_update_search() {
if (!show)
continue;
- if (!types.has(type))
- add_type(type, types, root, &to_select);
+ if (!search_options_types.has(type))
+ add_type(type, search_options_types, root, &to_select);
TreeItem *ti;
- if (types.has(type))
- ti = types[type];
+ if (search_options_types.has(type))
+ ti = search_options_types[type];
else
ti = search_options->get_root();
diff --git a/editor/create_dialog.h b/editor/create_dialog.h
index d859f7cbe4..03c4b25f5c 100644
--- a/editor/create_dialog.h
+++ b/editor/create_dialog.h
@@ -53,6 +53,7 @@ class CreateDialog : public ConfirmationDialog {
Button *favorite;
LineEdit *search_box;
Tree *search_options;
+ HashMap<String, TreeItem *> search_options_types;
bool is_replace_mode;
String base_type;
String preferred_search_result_type;
@@ -82,6 +83,8 @@ class CreateDialog : public ConfirmationDialog {
void add_type(const String &p_type, HashMap<String, TreeItem *> &p_types, TreeItem *p_root, TreeItem **to_select);
+ void select_type(const String &p_type);
+
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
@@ -104,7 +107,7 @@ public:
void set_preferred_search_result_type(const String &p_preferred_type);
String get_preferred_search_result_type();
- void popup_create(bool p_dont_clear, bool p_replace_mode = false);
+ void popup_create(bool p_dont_clear, bool p_replace_mode = false, const String &p_select_type = "Node");
CreateDialog();
};
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index 5b16b8f6d5..cddabbc4e4 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -228,7 +228,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
p_theme->set_font("doc", "EditorFonts", df_doc);
p_theme->set_font("doc_title", "EditorFonts", df_doc_title);
- MAKE_SOURCE_FONT(df_doc_code, int(EDITOR_DEF("text_editor/help/help_source_font_size", 14)) * EDSCALE);
+ MAKE_SOURCE_FONT(df_doc_code, int(EDITOR_GET("text_editor/help/help_source_font_size")) * EDSCALE);
p_theme->set_font("doc_source", "EditorFonts", df_doc_code);
// Ruler font
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 82e7a37f19..90604a36f1 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -1921,6 +1921,12 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
file->popup_centered_ratio();
} break;
+ case FILE_QUICK_OPEN: {
+
+ quick_open->popup_dialog("Resource", true);
+ quick_open->set_title(TTR("Quick Open..."));
+
+ } break;
case FILE_QUICK_OPEN_SCENE: {
quick_open->popup_dialog("PackedScene", true);
@@ -2454,14 +2460,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case SETTINGS_MANAGE_FEATURE_PROFILES: {
- Size2 popup_size = Size2(900, 800) * editor_get_scale();
- Size2 window_size = get_viewport()->get_size();
-
- popup_size.x = MIN(window_size.x * 0.8, popup_size.x);
- popup_size.y = MIN(window_size.y * 0.8, popup_size.y);
-
- feature_profile_manager->popup_centered(popup_size);
-
+ feature_profile_manager->popup_centered_clamped(Size2(900, 800) * EDSCALE, 0.8);
} break;
case SETTINGS_TOGGLE_FULLSCREEN: {
@@ -5702,6 +5701,7 @@ EditorNode::EditorNode() {
p->add_separator();
p->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT);
p->add_separator();
+ p->add_shortcut(ED_SHORTCUT("editor/quick_open", TTR("Quick Open..."), KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_O), FILE_QUICK_OPEN);
p->add_shortcut(ED_SHORTCUT("editor/quick_open_scene", TTR("Quick Open Scene..."), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_O), FILE_QUICK_OPEN_SCENE);
p->add_shortcut(ED_SHORTCUT("editor/quick_open_script", TTR("Quick Open Script..."), KEY_MASK_ALT + KEY_MASK_CMD + KEY_O), FILE_QUICK_OPEN_SCRIPT);
p->add_separator();
@@ -6242,7 +6242,6 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(TextureEditorPlugin(this)));
add_editor_plugin(memnew(AudioStreamEditorPlugin(this)));
add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor)));
- add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor)));
add_editor_plugin(memnew(SkeletonEditorPlugin(this)));
add_editor_plugin(memnew(SkeletonIKEditorPlugin(this)));
add_editor_plugin(memnew(PhysicalBonePlugin(this)));
diff --git a/editor/editor_node.h b/editor/editor_node.h
index cfe8bf9ec4..6e7b2b2443 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -146,6 +146,7 @@ private:
FILE_SAVE_OPTIMIZED,
FILE_OPEN_RECENT,
FILE_OPEN_OLD_SCENE,
+ FILE_QUICK_OPEN,
FILE_QUICK_OPEN_SCENE,
FILE_QUICK_OPEN_SCRIPT,
FILE_OPEN_PREV,
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 8af4ee8017..56fc1f87a5 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -400,6 +400,18 @@ void EditorPlugin::add_control_to_container(CustomControlContainer p_location, C
EditorNode::get_singleton()->get_inspector_dock_addon_area()->add_child(p_control);
} break;
+ case CONTAINER_PROJECT_SETTING_TAB_LEFT: {
+
+ ProjectSettingsEditor::get_singleton()->get_tabs()->add_child(p_control);
+ ProjectSettingsEditor::get_singleton()->get_tabs()->move_child(p_control, 0);
+
+ } break;
+ case CONTAINER_PROJECT_SETTING_TAB_RIGHT: {
+
+ ProjectSettingsEditor::get_singleton()->get_tabs()->add_child(p_control);
+ ProjectSettingsEditor::get_singleton()->get_tabs()->move_child(p_control, 1);
+
+ } break;
}
}
@@ -450,6 +462,12 @@ void EditorPlugin::remove_control_from_container(CustomControlContainer p_locati
EditorNode::get_singleton()->get_inspector_dock_addon_area()->remove_child(p_control);
} break;
+ case CONTAINER_PROJECT_SETTING_TAB_LEFT:
+ case CONTAINER_PROJECT_SETTING_TAB_RIGHT: {
+
+ ProjectSettingsEditor::get_singleton()->get_tabs()->remove_child(p_control);
+
+ } break;
}
}
@@ -863,6 +881,8 @@ void EditorPlugin::_bind_methods() {
BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_SIDE_RIGHT);
BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_BOTTOM);
BIND_ENUM_CONSTANT(CONTAINER_PROPERTY_EDITOR_BOTTOM);
+ BIND_ENUM_CONSTANT(CONTAINER_PROJECT_SETTING_TAB_LEFT);
+ BIND_ENUM_CONSTANT(CONTAINER_PROJECT_SETTING_TAB_RIGHT);
BIND_ENUM_CONSTANT(DOCK_SLOT_LEFT_UL);
BIND_ENUM_CONSTANT(DOCK_SLOT_LEFT_BL);
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 2fcc487377..ba4df35e66 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -137,7 +137,9 @@ public:
CONTAINER_CANVAS_EDITOR_SIDE_LEFT,
CONTAINER_CANVAS_EDITOR_SIDE_RIGHT,
CONTAINER_CANVAS_EDITOR_BOTTOM,
- CONTAINER_PROPERTY_EDITOR_BOTTOM
+ CONTAINER_PROPERTY_EDITOR_BOTTOM,
+ CONTAINER_PROJECT_SETTING_TAB_LEFT,
+ CONTAINER_PROJECT_SETTING_TAB_RIGHT,
};
enum DockSlot {
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 79dcbca7a2..c0dc231ea9 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -487,6 +487,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Help
_initial_set("text_editor/help/show_help_index", true);
+ _initial_set("text_editor/help_source_font_size", 14);
+ hints["text_editor/help/help_source_font_size"] = PropertyInfo(Variant::REAL, "text_editor/help/help_source_font_size", PROPERTY_HINT_RANGE, "10, 50, 1");
/* Editors */
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 52ed94e428..194a131095 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -2160,6 +2160,18 @@ void FileSystemDock::_tree_rmb_select(const Vector2 &p_pos) {
}
}
+void FileSystemDock::_tree_rmb_empty(const Vector2 &p_pos) {
+ // Right click is pressed in the empty space of the tree
+ path = "res://";
+ tree_popup->clear();
+ tree_popup->set_size(Size2(1, 1));
+ tree_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER);
+ tree_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT);
+ tree_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE);
+ tree_popup->set_position(tree->get_global_position() + p_pos);
+ tree_popup->popup();
+}
+
void FileSystemDock::_tree_empty_selected() {
tree->deselect_all();
}
@@ -2353,6 +2365,7 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_file_list_rmb_option", "option"), &FileSystemDock::_file_list_rmb_option);
ClassDB::bind_method(D_METHOD("_file_list_rmb_select"), &FileSystemDock::_file_list_rmb_select);
ClassDB::bind_method(D_METHOD("_file_list_rmb_pressed"), &FileSystemDock::_file_list_rmb_pressed);
+ ClassDB::bind_method(D_METHOD("_tree_rmb_empty"), &FileSystemDock::_tree_rmb_empty);
ClassDB::bind_method(D_METHOD("_file_deleted"), &FileSystemDock::_file_deleted);
ClassDB::bind_method(D_METHOD("_folder_deleted"), &FileSystemDock::_folder_deleted);
@@ -2485,6 +2498,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
tree->connect("item_activated", this, "_tree_activate_file");
tree->connect("multi_selected", this, "_tree_multi_selected");
tree->connect("item_rmb_selected", this, "_tree_rmb_select");
+ tree->connect("empty_rmb", this, "_tree_rmb_empty");
tree->connect("nothing_selected", this, "_tree_empty_selected");
tree->connect("gui_input", this, "_tree_gui_input");
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 9d20544ac2..978235b328 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -236,6 +236,7 @@ private:
void _file_and_folders_fill_popup(PopupMenu *p_popup, Vector<String> p_paths, bool p_display_path_dependent_options = true);
void _tree_rmb_select(const Vector2 &p_pos);
+ void _tree_rmb_empty(const Vector2 &p_pos);
void _file_list_rmb_select(int p_item, const Vector2 &p_pos);
void _file_list_rmb_pressed(const Vector2 &p_pos);
void _tree_empty_selected();
diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp
index 7642bfaf04..2deb2090e2 100644
--- a/editor/plugins/sprite_editor_plugin.cpp
+++ b/editor/plugins/sprite_editor_plugin.cpp
@@ -327,7 +327,14 @@ void SpriteEditor::_convert_to_mesh_2d_node() {
MeshInstance2D *mesh_instance = memnew(MeshInstance2D);
mesh_instance->set_mesh(mesh);
- EditorNode::get_singleton()->get_scene_tree_dock()->replace_node(node, mesh_instance);
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Convert to Mesh2D"));
+ ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, mesh_instance, true, false);
+ ur->add_do_reference(mesh_instance);
+ ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", mesh_instance, node, false, false);
+ ur->add_undo_reference(node);
+ ur->commit_action();
}
void SpriteEditor::_convert_to_polygon_2d_node() {
@@ -379,7 +386,13 @@ void SpriteEditor::_convert_to_polygon_2d_node() {
polygon_2d_instance->set_polygon(polygon);
polygon_2d_instance->set_polygons(polys);
- EditorNode::get_singleton()->get_scene_tree_dock()->replace_node(node, polygon_2d_instance);
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Convert to Polygon2D"));
+ ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, polygon_2d_instance, true, false);
+ ur->add_do_reference(polygon_2d_instance);
+ ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", polygon_2d_instance, node, false, false);
+ ur->add_undo_reference(node);
+ ur->commit_action();
}
void SpriteEditor::_create_collision_polygon_2d_node() {
@@ -396,7 +409,12 @@ void SpriteEditor::_create_collision_polygon_2d_node() {
CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D);
collision_polygon_2d_instance->set_polygon(outline);
- _add_as_sibling_or_child(node, collision_polygon_2d_instance);
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Create CollisionPolygon2D Sibling"));
+ ur->add_do_method(this, "_add_as_sibling_or_child", node, collision_polygon_2d_instance);
+ ur->add_do_reference(collision_polygon_2d_instance);
+ ur->add_undo_method(node != this->get_tree()->get_edited_scene_root() ? node->get_parent() : this->get_tree()->get_edited_scene_root(), "remove_child", collision_polygon_2d_instance);
+ ur->commit_action();
}
}
@@ -425,15 +443,20 @@ void SpriteEditor::_create_light_occluder_2d_node() {
LightOccluder2D *light_occluder_2d_instance = memnew(LightOccluder2D);
light_occluder_2d_instance->set_occluder_polygon(polygon);
- _add_as_sibling_or_child(node, light_occluder_2d_instance);
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Create LightOccluder2D Sibling"));
+ ur->add_do_method(this, "_add_as_sibling_or_child", node, light_occluder_2d_instance);
+ ur->add_do_reference(light_occluder_2d_instance);
+ ur->add_undo_method(node != this->get_tree()->get_edited_scene_root() ? node->get_parent() : this->get_tree()->get_edited_scene_root(), "remove_child", light_occluder_2d_instance);
+ ur->commit_action();
}
}
-void SpriteEditor::_add_as_sibling_or_child(Node2D *p_own_node, Node2D *p_new_node) {
+void SpriteEditor::_add_as_sibling_or_child(Node *p_own_node, Node *p_new_node) {
// Can't make sibling if own node is scene root
if (p_own_node != this->get_tree()->get_edited_scene_root()) {
p_own_node->get_parent()->add_child(p_new_node, true);
- p_new_node->set_transform(p_own_node->get_transform());
+ Object::cast_to<Node2D>(p_new_node)->set_transform(Object::cast_to<Node2D>(p_own_node)->get_transform());
} else {
p_own_node->add_child(p_new_node, true);
}
@@ -534,6 +557,7 @@ void SpriteEditor::_bind_methods() {
ClassDB::bind_method("_debug_uv_draw", &SpriteEditor::_debug_uv_draw);
ClassDB::bind_method("_update_mesh_data", &SpriteEditor::_update_mesh_data);
ClassDB::bind_method("_create_node", &SpriteEditor::_create_node);
+ ClassDB::bind_method("_add_as_sibling_or_child", &SpriteEditor::_add_as_sibling_or_child);
}
SpriteEditor::SpriteEditor() {
diff --git a/editor/plugins/sprite_editor_plugin.h b/editor/plugins/sprite_editor_plugin.h
index 460f5a5707..81be4a19e9 100644
--- a/editor/plugins/sprite_editor_plugin.h
+++ b/editor/plugins/sprite_editor_plugin.h
@@ -84,7 +84,7 @@ class SpriteEditor : public Control {
void _create_collision_polygon_2d_node();
void _create_light_occluder_2d_node();
- void _add_as_sibling_or_child(Node2D *p_own_node, Node2D *p_new_node);
+ void _add_as_sibling_or_child(Node *p_own_node, Node *p_new_node);
protected:
void _node_removed(Node *p_node);
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 29a54f815d..772e47ac3a 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -760,7 +760,7 @@ void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p
r.position += (r.size + Vector2(spacing, spacing)) * offset;
}
Size2 sc = p_xform.get_scale();
-
+ Size2 cell_size = node->get_cell_size();
Rect2 rect = Rect2();
rect.position = node->map_to_world(p_point) + node->get_cell_draw_offset();
@@ -770,62 +770,25 @@ void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p
rect.size = r.size;
}
- if (rect.size.y > rect.size.x) {
- if ((p_flip_h && (p_flip_v || p_transpose)) || (p_flip_v && !p_transpose))
- tile_ofs.y += rect.size.y - rect.size.x;
- } else if (rect.size.y < rect.size.x) {
- if ((p_flip_v && (p_flip_h || p_transpose)) || (p_flip_h && !p_transpose))
- tile_ofs.x += rect.size.x - rect.size.y;
- }
-
if (p_transpose) {
SWAP(tile_ofs.x, tile_ofs.y);
+ rect.position.x += cell_size.x / 2 - rect.size.y / 2;
+ rect.position.y += cell_size.y / 2 - rect.size.x / 2;
+ } else {
+ rect.position += cell_size / 2 - rect.size / 2;
}
+
if (p_flip_h) {
sc.x *= -1.0;
tile_ofs.x *= -1.0;
}
+
if (p_flip_v) {
sc.y *= -1.0;
tile_ofs.y *= -1.0;
}
- if (node->get_tile_origin() == TileMap::TILE_ORIGIN_TOP_LEFT) {
-
- rect.position += tile_ofs;
- } else if (node->get_tile_origin() == TileMap::TILE_ORIGIN_BOTTOM_LEFT) {
- Size2 cell_size = node->get_cell_size();
-
- rect.position += tile_ofs;
-
- if (p_transpose) {
- if (p_flip_h)
- rect.position.x -= cell_size.x;
- else
- rect.position.x += cell_size.x;
- } else {
- if (p_flip_v)
- rect.position.y -= cell_size.y;
- else
- rect.position.y += cell_size.y;
- }
-
- } else if (node->get_tile_origin() == TileMap::TILE_ORIGIN_CENTER) {
- Size2 cell_size = node->get_cell_size();
-
- rect.position += tile_ofs;
-
- if (p_flip_h)
- rect.position.x -= cell_size.x / 2;
- else
- rect.position.x += cell_size.x / 2;
-
- if (p_flip_v)
- rect.position.y -= cell_size.y / 2;
- else
- rect.position.y += cell_size.y / 2;
- }
-
+ rect.position += tile_ofs;
rect.position = p_xform.xform(rect.position);
rect.size *= sc;
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index 93c6614841..a00be3c0ce 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -372,6 +372,15 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
tool_editmode[EDITMODE_COLLISION]->set_pressed(true);
edit_mode = EDITMODE_COLLISION;
+ tool_editmode[EDITMODE_REGION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_region", TTR("Region Mode"), KEY_1));
+ tool_editmode[EDITMODE_COLLISION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_collision", TTR("Collision Mode"), KEY_2));
+ tool_editmode[EDITMODE_OCCLUSION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_occlusion", TTR("Occlusion Mode"), KEY_3));
+ tool_editmode[EDITMODE_NAVIGATION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_navigation", TTR("Navigation Mode"), KEY_4));
+ tool_editmode[EDITMODE_BITMASK]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_bitmask", TTR("Bitmask Mode"), KEY_5));
+ tool_editmode[EDITMODE_PRIORITY]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_priority", TTR("Priority Mode"), KEY_6));
+ tool_editmode[EDITMODE_ICON]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_icon", TTR("Icon Mode"), KEY_7));
+ tool_editmode[EDITMODE_Z_INDEX]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_z_index", TTR("Z Index Mode"), KEY_8));
+
main_vb->add_child(tool_hb);
separator_editmode = memnew(HSeparator);
main_vb->add_child(separator_editmode);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index c2e847f211..a1b903576e 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -69,6 +69,7 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) {
}
}
visual_shader = Ref<VisualShader>(p_visual_shader);
+ visual_shader->set_graph_offset(graph->get_scroll_ofs() / EDSCALE);
} else {
visual_shader.unref();
}
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index cc110f309c..ee78b240a4 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -88,14 +88,7 @@ void ProjectExportDialog::popup_export() {
if (saved_size != Rect2()) {
popup(saved_size);
} else {
-
- Size2 popup_size = Size2(900, 700) * editor_get_scale();
- Size2 window_size = get_viewport_rect().size;
-
- popup_size.x = MIN(window_size.x * 0.8, popup_size.x);
- popup_size.y = MIN(window_size.y * 0.8, popup_size.y);
-
- popup_centered(popup_size);
+ popup_centered_clamped(Size2(900, 700) * EDSCALE, 0.8);
}
}
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 71bddebcf5..872f8fcd2c 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -793,15 +793,9 @@ void ProjectSettingsEditor::popup_project_settings() {
if (saved_size != Rect2()) {
popup(saved_size);
} else {
-
- Size2 popup_size = Size2(900, 700) * editor_get_scale();
- Size2 window_size = get_viewport_rect().size;
-
- popup_size.x = MIN(window_size.x * 0.8, popup_size.x);
- popup_size.y = MIN(window_size.y * 0.8, popup_size.y);
-
- popup_centered(popup_size);
+ popup_centered_clamped(Size2(900, 700) * EDSCALE, 0.8);
}
+
globals_editor->update_category_list();
_update_translations();
autoload_settings->update_autoload();
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 1f5300e351..ce2795f37b 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -31,6 +31,7 @@
#include "scene_tree_dock.h"
#include "core/io/resource_saver.h"
+#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/project_settings.h"
@@ -347,7 +348,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!profile_allow_editing) {
break;
}
- create_dialog->popup_create(false, true);
+ create_dialog->popup_create(false, true, scene_tree->get_selected()->get_class());
} break;
case TOOL_ATTACH_SCRIPT: {
@@ -517,6 +518,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
Node *dupsingle = NULL;
+ List<Node *> editable_children;
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
@@ -529,6 +531,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Map<const Node *, Node *> duplimap;
Node *dup = node->duplicate_from_editor(duplimap);
+ if (EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node))
+ editable_children.push_back(dup);
+
ERR_CONTINUE(!dup);
if (selection.size() == 1)
@@ -561,6 +566,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (dupsingle)
editor->push_item(dupsingle);
+ for (List<Node *>::Element *E = editable_children.front(); E; E = E->next())
+ _toggle_editable_children(E->get());
+
} break;
case TOOL_REPARENT: {
@@ -796,7 +804,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
editable_instance_remove_dialog->popup_centered_minsize();
break;
}
- _toggle_editable_children();
+ _toggle_editable_children(node);
}
}
} break;
@@ -1612,30 +1620,27 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) {
_update_script_button();
}
-void SceneTreeDock::_toggle_editable_children() {
+void SceneTreeDock::_toggle_editable_children_from_selection() {
+
List<Node *> selection = editor_selection->get_selected_node_list();
List<Node *>::Element *e = selection.front();
- if (e) {
- Node *node = e->get();
- if (node) {
- bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node);
- int editable_item_idx = menu->get_item_idx_from_text(TTR("Editable Children"));
- int placeholder_item_idx = menu->get_item_idx_from_text(TTR("Load As Placeholder"));
- editable = !editable;
+ if (e) {
+ _toggle_editable_children(e->get());
+ }
+}
- EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node, editable);
+void SceneTreeDock::_toggle_editable_children(Node *p_node) {
- menu->set_item_checked(editable_item_idx, editable);
- if (editable) {
- node->set_scene_instance_load_placeholder(false);
- menu->set_item_checked(placeholder_item_idx, false);
- }
+ if (p_node) {
+ bool editable = !EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node);
+ EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(p_node, editable);
+ if (editable)
+ p_node->set_scene_instance_load_placeholder(false);
- SpatialEditor::get_singleton()->update_all_gizmos(node);
+ SpatialEditor::get_singleton()->update_all_gizmos(p_node);
- scene_tree->update_tree();
- }
+ scene_tree->update_tree();
}
}
@@ -1853,7 +1858,7 @@ void SceneTreeDock::_create() {
scene_tree->get_scene_tree()->call_deferred("grab_focus");
}
-void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_properties) {
+void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_properties, bool p_remove_old) {
Node *n = p_node;
Node *newnode = p_by_node;
@@ -1917,16 +1922,20 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop
Node *c = newnode->get_child(i);
c->call("set_transform", c->call("get_transform"));
}
- editor_data->get_undo_redo().clear_history();
+ //p_remove_old was added to support undo
+ if (p_remove_old)
+ editor_data->get_undo_redo().clear_history();
newnode->set_name(newname);
editor->push_item(newnode);
- memdelete(n);
+ if (p_remove_old) {
+ memdelete(n);
- while (to_erase.front()) {
- memdelete(to_erase.front()->get());
- to_erase.pop_front();
+ while (to_erase.front()) {
+ memdelete(to_erase.front()->get());
+ to_erase.pop_front();
+ }
}
}
@@ -1942,13 +1951,7 @@ void SceneTreeDock::set_selected(Node *p_node, bool p_emit_selected) {
void SceneTreeDock::import_subscene() {
- Size2 popup_size = Size2(500, 800) * editor_get_scale();
- Size2 window_size = get_viewport_rect().size;
-
- popup_size.x = MIN(window_size.x * 0.8, popup_size.x);
- popup_size.y = MIN(window_size.y * 0.8, popup_size.y);
-
- import_subscene_dialog->popup_centered(popup_size);
+ import_subscene_dialog->popup_centered_clamped(Size2(500, 800) * EDSCALE, 0.8);
}
void SceneTreeDock::_import_subscene() {
@@ -2132,7 +2135,7 @@ void SceneTreeDock::_nodes_dragged(Array p_nodes, NodePath p_to, int p_type) {
int to_pos = -1;
_normalize_drop(to_node, to_pos, p_type);
- _do_reparent(to_node, to_pos, nodes, true);
+ _do_reparent(to_node, to_pos, nodes, !Input::get_singleton()->is_key_pressed(KEY_SHIFT));
}
void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) {
@@ -2481,7 +2484,7 @@ void SceneTreeDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_input"), &SceneTreeDock::_input);
ClassDB::bind_method(D_METHOD("_nodes_drag_begin"), &SceneTreeDock::_nodes_drag_begin);
ClassDB::bind_method(D_METHOD("_delete_confirm"), &SceneTreeDock::_delete_confirm);
- ClassDB::bind_method(D_METHOD("_toggle_editable_children"), &SceneTreeDock::_toggle_editable_children);
+ ClassDB::bind_method(D_METHOD("_toggle_editable_children_from_selection"), &SceneTreeDock::_toggle_editable_children_from_selection);
ClassDB::bind_method(D_METHOD("_node_prerenamed"), &SceneTreeDock::_node_prerenamed);
ClassDB::bind_method(D_METHOD("_import_subscene"), &SceneTreeDock::_import_subscene);
ClassDB::bind_method(D_METHOD("_selection_changed"), &SceneTreeDock::_selection_changed);
@@ -2501,6 +2504,7 @@ void SceneTreeDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_feature_profile_changed"), &SceneTreeDock::_feature_profile_changed);
ClassDB::bind_method(D_METHOD("instance"), &SceneTreeDock::instance);
+ ClassDB::bind_method(D_METHOD("replace_node"), &SceneTreeDock::replace_node);
ADD_SIGNAL(MethodInfo("remote_tree_selected"));
}
@@ -2649,7 +2653,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
editable_instance_remove_dialog = memnew(ConfirmationDialog);
add_child(editable_instance_remove_dialog);
- editable_instance_remove_dialog->connect("confirmed", this, "_toggle_editable_children");
+ editable_instance_remove_dialog->connect("confirmed", this, "_toggle_editable_children_from_selection");
import_subscene_dialog = memnew(EditorSubScene);
add_child(import_subscene_dialog);
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index e66525d721..9f9e93f2df 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -172,7 +172,8 @@ class SceneTreeDock : public VBoxContainer {
void _delete_confirm();
- void _toggle_editable_children();
+ void _toggle_editable_children_from_selection();
+ void _toggle_editable_children(Node *p_node);
void _node_prerenamed(Node *p_node, const String &p_new_name);
@@ -243,7 +244,7 @@ public:
void show_tab_buttons();
void hide_tab_buttons();
- void replace_node(Node *p_node, Node *p_by_node, bool p_keep_properties = true);
+ void replace_node(Node *p_node, Node *p_by_node, bool p_keep_properties = true, bool p_remove_old = true);
void open_script_dialog(Node *p_for_node);
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index 68a1117364..b4643231d7 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -98,14 +98,7 @@ void EditorSettingsDialog::popup_edit_settings() {
if (saved_size != Rect2()) {
popup(saved_size);
} else {
-
- Size2 popup_size = Size2(900, 700) * editor_get_scale();
- Size2 window_size = get_viewport_rect().size;
-
- popup_size.x = MIN(window_size.x * 0.8, popup_size.x);
- popup_size.y = MIN(window_size.y * 0.8, popup_size.y);
-
- popup_centered(popup_size);
+ popup_centered_clamped(Size2(900, 700) * EDSCALE, 0.8);
}
_focus_current_search_box();
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 060a9d6c91..62b65fe96b 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -56,6 +56,10 @@ static bool _is_hex_symbol(CharType c) {
return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}
+static bool _is_bin_symbol(CharType c) {
+ return (c == '0' || c == '1');
+}
+
Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line) {
Map<int, TextEdit::HighlighterInfo> color_map;
@@ -76,6 +80,7 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_
bool in_member_variable = false;
bool in_node_path = false;
bool is_hex_notation = false;
+ bool is_bin_notation = false;
bool expect_type = false;
Color keyword_color;
Color color;
@@ -118,14 +123,26 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_
is_hex_notation = false;
}
+ // disallow anything not a 0 or 1
+ if (is_bin_notation && (_is_bin_symbol(str[j]))) {
+ is_number = true;
+ } else if (is_bin_notation) {
+ is_bin_notation = false;
+ is_number = false;
+ } else {
+ is_bin_notation = false;
+ }
+
// check for dot or underscore or 'x' for hex notation in floating point number or 'e' for scientific notation
- if ((str[j] == '.' || str[j] == 'x' || str[j] == '_' || str[j] == 'e') && !in_word && prev_is_number && !is_number) {
+ if ((str[j] == '.' || str[j] == 'x' || str[j] == 'b' || str[j] == '_' || str[j] == 'e') && !in_word && prev_is_number && !is_number) {
is_number = true;
is_symbol = false;
is_char = false;
if (str[j] == 'x' && str[j - 1] == '0') {
is_hex_notation = true;
+ } else if (str[j] == 'b' && str[j - 1] == '0') {
+ is_bin_notation = true;
}
}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 1c22c4af3c..9590009a54 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -3369,7 +3369,7 @@ void GDScriptParser::_parse_extends(ClassNode *p_class) {
return;
}
- if (!p_class->constant_expressions.empty() || !p_class->subclasses.empty() || !p_class->functions.empty() || !p_class->variables.empty()) {
+ if (!p_class->constant_expressions.empty() || !p_class->subclasses.empty() || !p_class->functions.empty() || !p_class->variables.empty() || p_class->classname_used) {
_set_error("'extends' must be used before anything else.");
return;
@@ -3506,6 +3506,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
_set_error("'class_name' syntax: 'class_name <UniqueName>'");
return;
}
+ if (p_class->classname_used) {
+ _set_error("'class_name' already used for this class.");
+ return;
+ }
+
+ p_class->classname_used = true;
p_class->name = tokenizer->get_token_identifier(1);
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 809bff8f20..5e4de11357 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -149,6 +149,7 @@ public:
bool tool;
StringName name;
bool extends_used;
+ bool classname_used;
StringName extends_file;
Vector<StringName> extends_class;
DataType base_type;
@@ -198,6 +199,7 @@ public:
tool = false;
type = TYPE_CLASS;
extends_used = false;
+ classname_used = false;
end_line = -1;
owner = NULL;
}
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index b8048fb5dd..a93d1ceebb 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -376,6 +376,11 @@ static bool _is_hex(CharType c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
+static bool _is_bin(CharType c) {
+
+ return (c == '0' || c == '1');
+}
+
void GDScriptTokenizerText::_make_token(Token p_type) {
TokenData &tk = tk_rb[tk_rb_pos];
@@ -877,6 +882,7 @@ void GDScriptTokenizerText::_advance() {
bool period_found = false;
bool exponent_found = false;
bool hexa_found = false;
+ bool bin_found = false;
bool sign_found = false;
String str;
@@ -887,16 +893,28 @@ void GDScriptTokenizerText::_advance() {
if (period_found || exponent_found) {
_make_error("Invalid numeric constant at '.'");
return;
+ } else if (bin_found) {
+ _make_error("Invalid binary constant at '.'");
+ return;
+ } else if (hexa_found) {
+ _make_error("Invalid hexadecimal constant at '.'");
+ return;
}
period_found = true;
} else if (GETCHAR(i) == 'x') {
- if (hexa_found || str.length() != 1 || !((i == 1 && str[0] == '0') || (i == 2 && str[1] == '0' && str[0] == '-'))) {
+ if (hexa_found || bin_found || str.length() != 1 || !((i == 1 && str[0] == '0') || (i == 2 && str[1] == '0' && str[0] == '-'))) {
_make_error("Invalid numeric constant at 'x'");
return;
}
hexa_found = true;
+ } else if (GETCHAR(i) == 'b') {
+ if (hexa_found || bin_found || str.length() != 1 || !((i == 1 && str[0] == '0') || (i == 2 && str[1] == '0' && str[0] == '-'))) {
+ _make_error("Invalid numeric constant at 'b'");
+ return;
+ }
+ bin_found = true;
} else if (!hexa_found && GETCHAR(i) == 'e') {
- if (exponent_found) {
+ if (exponent_found || bin_found) {
_make_error("Invalid numeric constant at 'e'");
return;
}
@@ -905,6 +923,8 @@ void GDScriptTokenizerText::_advance() {
//all ok
} else if (hexa_found && _is_hex(GETCHAR(i))) {
+ } else if (bin_found && _is_bin(GETCHAR(i))) {
+
} else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) {
if (sign_found) {
_make_error("Invalid numeric constant at '-'");
@@ -930,6 +950,9 @@ void GDScriptTokenizerText::_advance() {
if (hexa_found) {
int64_t val = str.hex_to_int64();
_make_constant(val);
+ } else if (bin_found) {
+ int64_t val = str.bin_to_int64();
+ _make_constant(val);
} else if (period_found || exponent_found) {
double val = str.to_double();
_make_constant(val);
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
index 292ac5e97e..b5f4718c72 100644
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
@@ -273,6 +273,7 @@ void AudioStreamOGGVorbis::_bind_methods() {
AudioStreamOGGVorbis::AudioStreamOGGVorbis() {
data = NULL;
+ data_len = 0;
length = 0;
sample_rate = 1;
channels = 1;
diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java
index 374d40463a..0eeaf0701c 100644
--- a/platform/android/java/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/src/org/godotengine/godot/Godot.java
@@ -1059,4 +1059,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
mProgressFraction.setText(Helpers.getDownloadProgressString(progress.mOverallProgress,
progress.mOverallTotal));
}
+ public void initInputDevices() {
+ mView.initInputDevices();
+ }
}
diff --git a/platform/android/java/src/org/godotengine/godot/GodotView.java b/platform/android/java/src/org/godotengine/godot/GodotView.java
index d7cd5b4360..ab28d9ec33 100644
--- a/platform/android/java/src/org/godotengine/godot/GodotView.java
+++ b/platform/android/java/src/org/godotengine/godot/GodotView.java
@@ -111,6 +111,18 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
init(translucent, depth, stencil);
}
+ public void initInputDevices() {
+ /* initially add input devices*/
+ int[] deviceIds = mInputManager.getInputDeviceIds();
+ for (int deviceId : deviceIds) {
+ InputDevice device = mInputManager.getInputDevice(deviceId);
+ if (DEBUG) {
+ Log.v("GodotView", String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName()));
+ }
+ onInputDeviceAdded(deviceId);
+ }
+ }
+
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
@@ -217,36 +229,42 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
// Check if the device has not been already added
if (id < 0) {
InputDevice device = mInputManager.getInputDevice(deviceId);
+ //device can be null if deviceId is not found
+ if (device != null) {
+ int sources = device.getSources();
+ if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) ||
+ ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) {
+ id = joy_devices.size();
+
+ joystick joy = new joystick();
+ joy.device_id = deviceId;
+ joy.name = device.getName();
+ joy.axes = new ArrayList<InputDevice.MotionRange>();
+ joy.hats = new ArrayList<InputDevice.MotionRange>();
+
+ List<InputDevice.MotionRange> ranges = device.getMotionRanges();
+ Collections.sort(ranges, new RangeComparator());
+
+ for (InputDevice.MotionRange range : ranges) {
+ if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) {
+ joy.hats.add(range);
+ } else {
+ joy.axes.add(range);
+ }
+ }
- id = joy_devices.size();
-
- joystick joy = new joystick();
- joy.device_id = deviceId;
- joy.name = device.getName();
- joy.axes = new ArrayList<InputDevice.MotionRange>();
- joy.hats = new ArrayList<InputDevice.MotionRange>();
-
- List<InputDevice.MotionRange> ranges = device.getMotionRanges();
- Collections.sort(ranges, new RangeComparator());
+ joy_devices.add(joy);
- for (InputDevice.MotionRange range : ranges) {
- if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) {
- joy.hats.add(range);
- } else {
- joy.axes.add(range);
+ final int device_id = id;
+ final String name = joy.name;
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.joyconnectionchanged(device_id, true, name);
+ }
+ });
}
}
-
- joy_devices.add(joy);
-
- final int device_id = id;
- final String name = joy.name;
- queueEvent(new Runnable() {
- @Override
- public void run() {
- GodotLib.joyconnectionchanged(device_id, true, name);
- }
- });
}
}
@@ -269,6 +287,8 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
@Override
public void onInputDeviceChanged(int deviceId) {
+ onInputDeviceRemoved(deviceId);
+ onInputDeviceAdded(deviceId);
}
@Override
public boolean onKeyUp(final int keyCode, KeyEvent event) {
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
index 101a1d76c6..e92d4437b1 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -59,6 +59,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance) {
_get_clipboard = p_env->GetMethodID(cls, "getClipboard", "()Ljava/lang/String;");
_set_clipboard = p_env->GetMethodID(cls, "setClipboard", "(Ljava/lang/String;)V");
_request_permission = p_env->GetMethodID(cls, "requestPermission", "(Ljava/lang/String;)Z");
+ _init_input_devices = p_env->GetMethodID(cls, "initInputDevices", "()V");
}
GodotJavaWrapper::~GodotJavaWrapper() {
@@ -183,3 +184,10 @@ bool GodotJavaWrapper::request_permission(const String &p_name) {
return false;
}
}
+
+void GodotJavaWrapper::init_input_devices() {
+ if (_init_input_devices) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallVoidMethod(godot_instance, _init_input_devices);
+ }
+}
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
index 438aee019b..be4f109d8c 100644
--- a/platform/android/java_godot_wrapper.h
+++ b/platform/android/java_godot_wrapper.h
@@ -54,6 +54,7 @@ private:
jmethodID _get_clipboard = 0;
jmethodID _set_clipboard = 0;
jmethodID _request_permission = 0;
+ jmethodID _init_input_devices = 0;
public:
GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance);
@@ -76,6 +77,7 @@ public:
bool has_set_clipboard();
void set_clipboard(const String &p_text);
bool request_permission(const String &p_name);
+ void init_input_devices();
};
#endif /* !JAVA_GODOT_WRAPPER_H */
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index ff1632cba8..f8076dfd2d 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -251,6 +251,10 @@ int OS_Android::get_mouse_button_state() const {
}
void OS_Android::set_window_title(const String &p_title) {
+ //This queries/updates the currently connected devices/joypads
+ //Set_window_title is called when initializing the main loop (main.cpp)
+ //therefore this place is found to be suitable (I found no better).
+ godot_java->init_input_devices();
}
void OS_Android::set_video_mode(const VideoMode &p_video_mode, int p_screen) {
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index e3494a1dbf..6df2ad4821 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -2475,7 +2475,13 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) {
- argss += String(" \"") + E->get() + "\"";
+ argss += " \"" + E->get() + "\"";
+ }
+
+ argss += "\"";
+
+ if (read_stderr) {
+ argss += " 2>&1"; // Read stderr too
}
FILE *f = _wpopen(argss.c_str(), L"r");
diff --git a/platform/x11/context_gl_x11.cpp b/platform/x11/context_gl_x11.cpp
index aadf7ee36d..9718b03164 100644
--- a/platform/x11/context_gl_x11.cpp
+++ b/platform/x11/context_gl_x11.cpp
@@ -191,6 +191,7 @@ Error ContextGL_X11::initialize() {
swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa);
+ XStoreName(x11_display, x11_window, "Godot Engine");
ERR_FAIL_COND_V(!x11_window, ERR_UNCONFIGURED);
set_class_hint(x11_display, x11_window);
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 3dc0f46676..86be8762d4 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -202,47 +202,27 @@ void TileMap::_fix_cell_transform(Transform2D &xform, const Cell &p_cell, const
Size2 s = p_sc;
Vector2 offset = p_offset;
- if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT)
- offset.y += cell_size.y;
- else if (tile_origin == TILE_ORIGIN_CENTER) {
- offset += cell_size / 2;
- }
-
- if (s.y > s.x) {
- if ((p_cell.flip_h && (p_cell.flip_v || p_cell.transpose)) || (p_cell.flip_v && !p_cell.transpose))
- offset.y += s.y - s.x;
- } else if (s.y < s.x) {
- if ((p_cell.flip_v && (p_cell.flip_h || p_cell.transpose)) || (p_cell.flip_h && !p_cell.transpose))
- offset.x += s.x - s.y;
- }
-
if (p_cell.transpose) {
SWAP(xform.elements[0].x, xform.elements[0].y);
SWAP(xform.elements[1].x, xform.elements[1].y);
SWAP(offset.x, offset.y);
SWAP(s.x, s.y);
}
+
if (p_cell.flip_h) {
xform.elements[0].x = -xform.elements[0].x;
xform.elements[1].x = -xform.elements[1].x;
- if (tile_origin == TILE_ORIGIN_TOP_LEFT || tile_origin == TILE_ORIGIN_BOTTOM_LEFT)
- offset.x = s.x - offset.x;
- else if (tile_origin == TILE_ORIGIN_CENTER)
- offset.x = s.x - offset.x / 2;
+ offset.x = s.x - offset.x;
}
+
if (p_cell.flip_v) {
xform.elements[0].y = -xform.elements[0].y;
xform.elements[1].y = -xform.elements[1].y;
- if (tile_origin == TILE_ORIGIN_TOP_LEFT)
- offset.y = s.y - offset.y;
- else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) {
- offset.y += s.y;
- } else if (tile_origin == TILE_ORIGIN_CENTER) {
- offset.y += s.y;
- }
+ offset.y = s.y - offset.y;
}
- xform.elements[2].x += offset.x;
- xform.elements[2].y += offset.y;
+
+ offset += cell_size / 2 - s / 2;
+ xform.elements[2] += offset;
}
void TileMap::update_dirty_quadrants() {
@@ -390,64 +370,25 @@ void TileMap::update_dirty_quadrants() {
rect.size.x += fp_adjust;
rect.size.y += fp_adjust;
- if (rect.size.y > rect.size.x) {
- if ((c.flip_h && (c.flip_v || c.transpose)) || (c.flip_v && !c.transpose))
- tile_ofs.y += rect.size.y - rect.size.x;
- } else if (rect.size.y < rect.size.x) {
- if ((c.flip_v && (c.flip_h || c.transpose)) || (c.flip_h && !c.transpose))
- tile_ofs.x += rect.size.x - rect.size.y;
- }
-
- /* rect.size.x+=fp_adjust;
- rect.size.y+=fp_adjust;*/
-
- if (c.transpose)
+ if (c.transpose) {
SWAP(tile_ofs.x, tile_ofs.y);
+ rect.position.x += cell_size.x / 2 - rect.size.y / 2;
+ rect.position.y += cell_size.y / 2 - rect.size.x / 2;
+ } else {
+ rect.position += cell_size / 2 - rect.size / 2;
+ }
if (c.flip_h) {
rect.size.x = -rect.size.x;
tile_ofs.x = -tile_ofs.x;
}
+
if (c.flip_v) {
rect.size.y = -rect.size.y;
tile_ofs.y = -tile_ofs.y;
}
- Vector2 center_ofs;
-
- if (tile_origin == TILE_ORIGIN_TOP_LEFT) {
- rect.position += tile_ofs;
-
- } else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) {
-
- rect.position += tile_ofs;
-
- if (c.transpose) {
- if (c.flip_h)
- rect.position.x -= cell_size.x;
- else
- rect.position.x += cell_size.x;
- } else {
- if (c.flip_v)
- rect.position.y -= cell_size.y;
- else
- rect.position.y += cell_size.y;
- }
-
- } else if (tile_origin == TILE_ORIGIN_CENTER) {
-
- rect.position += tile_ofs;
-
- if (c.flip_h)
- rect.position.x -= cell_size.x / 2;
- else
- rect.position.x += cell_size.x / 2;
-
- if (c.flip_v)
- rect.position.y -= cell_size.y / 2;
- else
- rect.position.y += cell_size.y / 2;
- }
+ rect.position += tile_ofs;
Ref<Texture> normal_map = tile_set->tile_get_normal_map(c.id);
Color modulate = tile_set->tile_get_modulate(c.id);
@@ -471,7 +412,7 @@ void TileMap::update_dirty_quadrants() {
Vector2 shape_ofs = shapes[j].shape_transform.get_origin();
- _fix_cell_transform(xform, c, shape_ofs + center_ofs, s);
+ _fix_cell_transform(xform, c, shape_ofs, s);
xform *= shapes[j].shape_transform.untranslated();
@@ -523,7 +464,7 @@ void TileMap::update_dirty_quadrants() {
if (navpoly.is_valid()) {
Transform2D xform;
xform.set_origin(offset.floor() + q.pos);
- _fix_cell_transform(xform, c, npoly_ofs + center_ofs, s);
+ _fix_cell_transform(xform, c, npoly_ofs, s);
int pid = navigation->navpoly_add(navpoly, nav_rel * xform);
@@ -573,7 +514,7 @@ void TileMap::update_dirty_quadrants() {
}
Transform2D navxform;
navxform.set_origin(offset.floor());
- _fix_cell_transform(navxform, c, npoly_ofs + center_ofs, s);
+ _fix_cell_transform(navxform, c, npoly_ofs, s);
vs->canvas_item_set_transform(debug_navigation_item, navxform);
vs->canvas_item_add_triangle_array(debug_navigation_item, indices, vertices, colors);
@@ -593,7 +534,7 @@ void TileMap::update_dirty_quadrants() {
Vector2 occluder_ofs = tile_set->tile_get_occluder_offset(c.id);
Transform2D xform;
xform.set_origin(offset.floor() + q.pos);
- _fix_cell_transform(xform, c, occluder_ofs + center_ofs, s);
+ _fix_cell_transform(xform, c, occluder_ofs, s);
RID orid = VS::get_singleton()->canvas_light_occluder_create();
VS::get_singleton()->canvas_light_occluder_set_transform(orid, get_global_transform() * xform);
diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp
index 52fa96ee4a..4e88948ce2 100644
--- a/scene/3d/arvr_nodes.cpp
+++ b/scene/3d/arvr_nodes.cpp
@@ -127,7 +127,7 @@ Point2 ARVRCamera::unproject_position(const Vector3 &p_pos) const {
return res;
};
-Vector3 ARVRCamera::project_position(const Point2 &p_point) const {
+Vector3 ARVRCamera::project_position(const Point2 &p_point, float p_z_depth) const {
// get our ARVRServer
ARVRServer *arvr_server = ARVRServer::get_singleton();
ERR_FAIL_NULL_V(arvr_server, Vector3());
@@ -135,7 +135,7 @@ Vector3 ARVRCamera::project_position(const Point2 &p_point) const {
Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface();
if (arvr_interface.is_null()) {
// we might be in the editor or have VR turned off, just call superclass
- return Camera::project_position(p_point);
+ return Camera::project_position(p_point, p_z_depth);
}
if (!is_inside_tree()) {
@@ -155,7 +155,7 @@ Vector3 ARVRCamera::project_position(const Point2 &p_point) const {
point.y = (1.0 - (p_point.y / viewport_size.y)) * 2.0 - 1.0;
point *= vp_size;
- Vector3 p(point.x, point.y, -get_znear());
+ Vector3 p(point.x, point.y, -p_z_depth);
return get_camera_transform().xform(p);
};
diff --git a/scene/3d/arvr_nodes.h b/scene/3d/arvr_nodes.h
index 0833e18d48..8e735f7110 100644
--- a/scene/3d/arvr_nodes.h
+++ b/scene/3d/arvr_nodes.h
@@ -55,7 +55,7 @@ public:
virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const;
virtual Point2 unproject_position(const Vector3 &p_pos) const;
- virtual Vector3 project_position(const Point2 &p_point) const;
+ virtual Vector3 project_position(const Point2 &p_point, float p_z_depth = 0) const;
virtual Vector<Plane> get_frustum() const;
ARVRCamera();
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index e360de5b8e..29002c6701 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -391,13 +391,17 @@ Point2 Camera::unproject_position(const Vector3 &p_pos) const {
return res;
}
-Vector3 Camera::project_position(const Point2 &p_point) const {
+Vector3 Camera::project_position(const Point2 &p_point, float p_z_depth) const {
if (!is_inside_tree()) {
ERR_EXPLAIN("Camera is not inside scene.");
ERR_FAIL_COND_V(!is_inside_tree(), Vector3());
}
+ if (p_z_depth == 0) {
+ return get_global_transform().origin;
+ }
+
Size2 viewport_size = get_viewport()->get_visible_rect().size;
CameraMatrix cm;
@@ -415,7 +419,7 @@ Vector3 Camera::project_position(const Point2 &p_point) const {
point.y = (1.0 - (p_point.y / viewport_size.y)) * 2.0 - 1.0;
point *= vp_size;
- Vector3 p(point.x, point.y, -near);
+ Vector3 p(point.x, point.y, -p_z_depth);
return get_camera_transform().xform(p);
}
@@ -490,7 +494,7 @@ void Camera::_bind_methods() {
ClassDB::bind_method(D_METHOD("project_ray_origin", "screen_point"), &Camera::project_ray_origin);
ClassDB::bind_method(D_METHOD("unproject_position", "world_point"), &Camera::unproject_position);
ClassDB::bind_method(D_METHOD("is_position_behind", "world_point"), &Camera::is_position_behind);
- ClassDB::bind_method(D_METHOD("project_position", "screen_point"), &Camera::project_position);
+ ClassDB::bind_method(D_METHOD("project_position", "screen_point", "z_depth"), &Camera::project_position, DEFVAL(0));
ClassDB::bind_method(D_METHOD("set_perspective", "fov", "z_near", "z_far"), &Camera::set_perspective);
ClassDB::bind_method(D_METHOD("set_orthogonal", "size", "z_near", "z_far"), &Camera::set_orthogonal);
ClassDB::bind_method(D_METHOD("set_frustum", "size", "offset", "z_near", "z_far"), &Camera::set_frustum);
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
index fe8cb84f0d..cbcefbb0ae 100644
--- a/scene/3d/camera.h
+++ b/scene/3d/camera.h
@@ -143,7 +143,7 @@ public:
virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const;
virtual Point2 unproject_position(const Vector3 &p_pos) const;
bool is_position_behind(const Vector3 &p_pos) const;
- virtual Vector3 project_position(const Point2 &p_point) const;
+ virtual Vector3 project_position(const Point2 &p_point, float p_z_depth = 0) const;
Vector<Vector3> get_near_plane_points() const;
diff --git a/scene/3d/proximity_group.cpp b/scene/3d/proximity_group.cpp
index 12eab2e4e8..96dc3304f2 100644
--- a/scene/3d/proximity_group.cpp
+++ b/scene/3d/proximity_group.cpp
@@ -204,6 +204,7 @@ ProximityGroup::ProximityGroup() {
group_version = 0;
dispatch_mode = MODE_PROXY;
+ cell_size = 1.0;
grid_radius = Vector3(1, 1, 1);
set_notify_transform(true);
};
diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp
index fde135c972..32b8219ee0 100644
--- a/scene/3d/vehicle_body.cpp
+++ b/scene/3d/vehicle_body.cpp
@@ -270,6 +270,8 @@ void VehicleWheel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_skidinfo"), &VehicleWheel::get_skidinfo);
+ ClassDB::bind_method(D_METHOD("get_rpm"), &VehicleWheel::get_rpm);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_traction"), "set_use_as_traction", "is_used_as_traction");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_steering"), "set_use_as_steering", "is_used_as_steering");
ADD_GROUP("Wheel", "wheel_");
@@ -311,6 +313,11 @@ float VehicleWheel::get_skidinfo() const {
return m_skidInfo;
}
+float VehicleWheel::get_rpm() const {
+
+ return m_rpm;
+}
+
VehicleWheel::VehicleWheel() {
steers = false;
@@ -865,12 +872,11 @@ void VehicleBody::_direct_state_changed(Object *p_state) {
real_t proj2 = fwd.dot(vel);
wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelRadius);
- wheel.m_rotation += wheel.m_deltaRotation;
-
- } else {
- wheel.m_rotation += wheel.m_deltaRotation;
}
+ wheel.m_rotation += wheel.m_deltaRotation;
+ wheel.m_rpm = ((wheel.m_deltaRotation / step) * 60) / Math_TAU;
+
wheel.m_deltaRotation *= real_t(0.99); //damping of rotation when not in contact
}
diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h
index 7e7571df4d..9e3fe72282 100644
--- a/scene/3d/vehicle_body.h
+++ b/scene/3d/vehicle_body.h
@@ -68,6 +68,7 @@ class VehicleWheel : public Spatial {
real_t m_steering;
real_t m_rotation;
real_t m_deltaRotation;
+ real_t m_rpm;
real_t m_rollInfluence;
//real_t m_engineForce;
real_t m_brake;
@@ -134,6 +135,8 @@ public:
float get_skidinfo() const;
+ float get_rpm() const;
+
String get_configuration_warning() const;
VehicleWheel();
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index d1d3582c9d..8247728b9d 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -1580,6 +1580,7 @@ AnimationTree::AnimationTree() {
active = false;
cache_valid = false;
setup_pass = 1;
+ process_pass = 1;
started = true;
properties_dirty = true;
last_animation_player = 0;
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index b7601bdd3e..fdb1b65f77 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -115,6 +115,18 @@ void Popup::set_as_minsize() {
set_size(total_minsize);
}
+void Popup::popup_centered_clamped(const Size2 &p_size, float p_fallback_ratio) {
+
+ Size2 popup_size = p_size;
+ Size2 window_size = get_viewport_rect().size;
+
+ // clamp popup size in each dimension if window size is too small (using fallback ratio)
+ popup_size.x = MIN(window_size.x * p_fallback_ratio, popup_size.x);
+ popup_size.y = MIN(window_size.y * p_fallback_ratio, popup_size.y);
+
+ popup_centered(popup_size);
+}
+
void Popup::popup_centered_minsize(const Size2 &p_minsize) {
set_custom_minimum_size(p_minsize);
@@ -179,6 +191,7 @@ void Popup::_bind_methods() {
ClassDB::bind_method(D_METHOD("popup_centered", "size"), &Popup::popup_centered, DEFVAL(Size2()));
ClassDB::bind_method(D_METHOD("popup_centered_ratio", "ratio"), &Popup::popup_centered_ratio, DEFVAL(0.75));
ClassDB::bind_method(D_METHOD("popup_centered_minsize", "minsize"), &Popup::popup_centered_minsize, DEFVAL(Size2()));
+ ClassDB::bind_method(D_METHOD("popup_centered_clamped", "size", "fallback_ratio"), &Popup::popup_centered_clamped, DEFVAL(Size2()), DEFVAL(0.75));
ClassDB::bind_method(D_METHOD("popup", "bounds"), &Popup::popup, DEFVAL(Rect2()));
ClassDB::bind_method(D_METHOD("set_exclusive", "enable"), &Popup::set_exclusive);
ClassDB::bind_method(D_METHOD("is_exclusive"), &Popup::is_exclusive);
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index 7ccefe1d75..6615c51ec5 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -64,6 +64,7 @@ public:
void popup_centered(const Size2 &p_size = Size2());
void popup_centered_minsize(const Size2 &p_minsize = Size2());
void set_as_minsize();
+ void popup_centered_clamped(const Size2 &p_size = Size2(), float p_fallback_ratio = 0.75);
virtual void popup(const Rect2 &p_bounds = Rect2());
virtual String get_configuration_warning() const;
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 028ca41cbf..b777e77bc3 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -295,6 +295,7 @@ Slider::Slider(Orientation p_orientation) {
mouse_inside = false;
grab.active = false;
ticks = 0;
+ ticks_on_borders = false;
custom_step = -1;
editable = true;
scrollable = true;
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 049cae9dd9..e5313061da 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1970,6 +1970,9 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
item_h += child_h;
}
}
+ if (p_item == root && p_button == BUTTON_RIGHT) {
+ emit_signal("empty_rmb", get_local_mouse_position());
+ }
}
return item_h; // nothing found
@@ -3853,6 +3856,7 @@ void Tree::_bind_methods() {
ADD_SIGNAL(MethodInfo("cell_selected"));
ADD_SIGNAL(MethodInfo("multi_selected", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::BOOL, "selected")));
ADD_SIGNAL(MethodInfo("item_rmb_selected", PropertyInfo(Variant::VECTOR2, "position")));
+ ADD_SIGNAL(MethodInfo("empty_rmb", PropertyInfo(Variant::VECTOR2, "position")));
ADD_SIGNAL(MethodInfo("empty_tree_rmb_selected", PropertyInfo(Variant::VECTOR2, "position")));
ADD_SIGNAL(MethodInfo("item_edited"));
ADD_SIGNAL(MethodInfo("item_rmb_edited"));
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 368dea7649..2f23c11748 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2077,7 +2077,9 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
}
}
- node->set_name(get_name());
+ if (get_name() != String()) {
+ node->set_name(get_name());
+ }
#ifdef TOOLS_ENABLED
if ((p_flags & DUPLICATE_FROM_EDITOR) && r_duplimap)
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 128db3f109..627397f0ab 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -530,7 +530,13 @@ Size2 Font::get_wordwrap_string_size(const String &p_string, float p_width) cons
void BitmapFont::set_fallback(const Ref<BitmapFont> &p_fallback) {
- ERR_FAIL_COND(p_fallback == this);
+ for (Ref<BitmapFont> fallback_child = p_fallback; fallback_child != NULL; fallback_child = fallback_child->get_fallback()) {
+ if (fallback_child == this) {
+ ERR_EXPLAIN("Can't set as fallback one of its parents to prevent crashes due to recursive loop.");
+ ERR_FAIL_COND(fallback_child == this);
+ }
+ }
+
fallback = p_fallback;
}
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 2e035bbd1f..ada0ac07a3 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -38,7 +38,12 @@
void Material::set_next_pass(const Ref<Material> &p_pass) {
- ERR_FAIL_COND(p_pass == this);
+ for (Ref<Material> pass_child = p_pass; pass_child != NULL; pass_child = pass_child->get_next_pass()) {
+ if (pass_child == this) {
+ ERR_EXPLAIN("Can't set as next_pass one of its parents to prevent crashes due to recursive loop.");
+ ERR_FAIL_COND(pass_child == this);
+ }
+ }
if (next_pass == p_pass)
return;
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 8c0497e91a..496b1b2bdc 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -769,6 +769,26 @@ void SurfaceTool::create_from(const Ref<Mesh> &p_existing, int p_surface) {
material = p_existing->surface_get_material(p_surface);
}
+void SurfaceTool::create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String p_blend_shape_name) {
+ clear();
+ primitive = p_existing->surface_get_primitive_type(p_surface);
+ Array arr = p_existing->surface_get_blend_shape_arrays(p_surface);
+ Array blend_shape_names;
+ int32_t shape_idx = -1;
+ for (int32_t i = 0; i < p_existing->get_blend_shape_count(); i++) {
+ String name = p_existing->get_blend_shape_name(i);
+ if (name == p_blend_shape_name) {
+ shape_idx = i;
+ break;
+ }
+ }
+ ERR_FAIL_COND(shape_idx == -1);
+ ERR_FAIL_COND(shape_idx >= arr.size());
+ Array mesh = arr[shape_idx];
+ ERR_FAIL_COND(mesh.size() != VS::ARRAY_MAX);
+ _create_list_from_arrays(arr[shape_idx], &vertex_array, &index_array, format);
+}
+
void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform) {
if (vertex_array.size() == 0) {
@@ -1071,8 +1091,10 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear);
ClassDB::bind_method(D_METHOD("create_from", "existing", "surface"), &SurfaceTool::create_from);
+ ClassDB::bind_method(D_METHOD("create_from_blend_shape", "existing", "surface", "blend_shape"), &SurfaceTool::create_from_blend_shape);
ClassDB::bind_method(D_METHOD("append_from", "existing", "surface", "transform"), &SurfaceTool::append_from);
ClassDB::bind_method(D_METHOD("commit", "existing", "flags"), &SurfaceTool::commit, DEFVAL(Variant()), DEFVAL(Mesh::ARRAY_COMPRESS_DEFAULT));
+ ClassDB::bind_method(D_METHOD("commit_to_arrays"), &SurfaceTool::commit_to_arrays);
}
SurfaceTool::SurfaceTool() {
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index c55cade813..c4c71dca13 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -136,6 +136,7 @@ public:
static Vector<Vertex> create_vertex_array_from_triangle_arrays(const Array &p_arrays);
Array commit_to_arrays();
void create_from(const Ref<Mesh> &p_existing, int p_surface);
+ void create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String p_blend_shape_name);
void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform);
Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = Mesh::ARRAY_COMPRESS_DEFAULT);
diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp
index a9ca920178..310aa16130 100644
--- a/servers/visual/visual_server_raster.cpp
+++ b/servers/visual/visual_server_raster.cpp
@@ -201,8 +201,10 @@ VisualServerRaster::VisualServerRaster() {
VSG::canvas_render = VSG::rasterizer->get_canvas();
VSG::scene_render = VSG::rasterizer->get_scene();
- for (int i = 0; i < 4; i++)
+ for (int i = 0; i < 4; i++) {
black_margin[i] = 0;
+ black_image[i] = RID();
+ }
}
VisualServerRaster::~VisualServerRaster() {