summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/bind/core_bind.cpp5
-rw-r--r--core/bind/core_bind.h1
-rw-r--r--core/color.h4
-rw-r--r--core/input/input_map.cpp2
-rw-r--r--core/io/resource_importer.cpp3
-rw-r--r--core/math/quat.h4
-rw-r--r--core/math/vector2.h30
-rw-r--r--core/os/os.cpp4
-rw-r--r--core/os/os.h2
-rw-r--r--core/project_settings.cpp2
-rw-r--r--core/project_settings.h1
-rw-r--r--core/variant_op.cpp63
-rw-r--r--doc/classes/BaseMaterial3D.xml7
-rw-r--r--doc/classes/DynamicFont.xml10
-rw-r--r--doc/classes/EditorImportPlugin.xml4
-rw-r--r--doc/classes/EditorInterface.xml4
-rw-r--r--doc/classes/KinematicBody2D.xml14
-rw-r--r--doc/classes/KinematicBody3D.xml14
-rw-r--r--doc/classes/OS.xml7
-rw-r--r--doc/classes/VisualShaderNodeMultiplyAdd.xml10
-rw-r--r--editor/editor_export.cpp14
-rw-r--r--editor/editor_export.h1
-rw-r--r--editor/editor_file_dialog.cpp2
-rw-r--r--editor/editor_file_system.cpp15
-rw-r--r--editor/editor_plugin.cpp6
-rw-r--r--editor/editor_plugin.h2
-rw-r--r--editor/editor_settings.h1
-rw-r--r--editor/editor_spin_slider.cpp7
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp7
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp167
-rw-r--r--editor/plugins/node_3d_editor_plugin.h6
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp6
-rw-r--r--editor/project_manager.cpp3
-rw-r--r--main/main.cpp1
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props14
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs2
-rw-r--r--modules/mono/godotsharp_dirs.cpp2
-rw-r--r--modules/pvr/texture_loader_pvr.cpp8
-rw-r--r--platform/android/export/export.cpp91
-rw-r--r--platform/android/java/app/AndroidManifest.xml2
-rw-r--r--platform/android/java/app/res/drawable/splash.pngbin0 -> 14766 bytes
-rw-r--r--platform/android/java/app/res/drawable/splash_bg_color.pngbin0 -> 1360 bytes
-rw-r--r--platform/android/java/app/res/drawable/splash_drawable.xml12
-rw-r--r--platform/android/java/app/res/values/themes.xml9
-rw-r--r--platform/android/java/app/src/com/godot/game/GodotApp.java7
-rw-r--r--platform/iphone/export/export.cpp7
-rw-r--r--platform/osx/display_server_osx.mm6
-rw-r--r--scene/gui/control.cpp2
-rw-r--r--scene/gui/tree.cpp5
-rw-r--r--scene/main/viewport.cpp2
-rw-r--r--scene/main/viewport.h2
-rw-r--r--scene/resources/visual_shader_nodes.cpp32
-rw-r--r--scene/resources/visual_shader_nodes.h16
53 files changed, 492 insertions, 156 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 489ff762c9..c68222c767 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -519,10 +519,6 @@ uint64_t _OS::get_ticks_usec() const {
return OS::get_singleton()->get_ticks_usec();
}
-uint32_t _OS::get_splash_tick_msec() const {
- return OS::get_singleton()->get_splash_tick_msec();
-}
-
bool _OS::can_use_threads() const {
return OS::get_singleton()->can_use_threads();
}
@@ -730,7 +726,6 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("delay_msec", "msec"), &_OS::delay_msec);
ClassDB::bind_method(D_METHOD("get_ticks_msec"), &_OS::get_ticks_msec);
ClassDB::bind_method(D_METHOD("get_ticks_usec"), &_OS::get_ticks_usec);
- ClassDB::bind_method(D_METHOD("get_splash_tick_msec"), &_OS::get_splash_tick_msec);
ClassDB::bind_method(D_METHOD("get_locale"), &_OS::get_locale);
ClassDB::bind_method(D_METHOD("get_model_name"), &_OS::get_model_name);
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index a59fcda60c..5c9520d7fe 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -208,7 +208,6 @@ public:
void delay_msec(uint32_t p_msec) const;
uint32_t get_ticks_msec() const;
uint64_t get_ticks_usec() const;
- uint32_t get_splash_tick_msec() const;
bool can_use_threads() const;
diff --git a/core/color.h b/core/color.h
index 096e97e9ae..2dbbc52905 100644
--- a/core/color.h
+++ b/core/color.h
@@ -234,4 +234,8 @@ bool Color::operator<(const Color &p_color) const {
}
}
+_FORCE_INLINE_ Color operator*(const real_t &p_real, const Color &p_color) {
+ return p_color * p_real;
+}
+
#endif // COLOR_H
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 2bf8792421..6319ffc8f1 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -128,7 +128,7 @@ void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent
ERR_FAIL_COND_MSG(p_event.is_null(), "It's not a reference to a valid InputEvent object.");
ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
if (_find_event(input_map[p_action], p_event)) {
- return; //already gots
+ return; // Already addded.
}
input_map[p_action].inputs.push_back(p_event);
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index 9ed159bd20..4d980bcf1a 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -31,6 +31,7 @@
#include "resource_importer.h"
#include "core/os/os.h"
+#include "core/project_settings.h"
#include "core/variant_parser.h"
bool ResourceFormatImporter::SortImporterByName::operator()(const Ref<ResourceImporter> &p_a, const Ref<ResourceImporter> &p_b) const {
@@ -374,7 +375,7 @@ Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_extension(const St
}
String ResourceFormatImporter::get_import_base_path(const String &p_for_file) const {
- return "res://.import/" + p_for_file.get_file() + "-" + p_for_file.md5_text();
+ return ProjectSettings::IMPORTED_FILES_PATH.plus_file(p_for_file.get_file() + "-" + p_for_file.md5_text());
}
bool ResourceFormatImporter::are_import_settings_valid(const String &p_path) const {
diff --git a/core/math/quat.h b/core/math/quat.h
index 8619ea3c5c..3152b7d233 100644
--- a/core/math/quat.h
+++ b/core/math/quat.h
@@ -224,4 +224,8 @@ bool Quat::operator!=(const Quat &p_quat) const {
return x != p_quat.x || y != p_quat.y || z != p_quat.z || w != p_quat.w;
}
+_FORCE_INLINE_ Quat operator*(const real_t &p_real, const Quat &p_quat) {
+ return p_quat * p_real;
+}
+
#endif // QUAT_H
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 0966d3392f..f41bcc15bc 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -150,7 +150,19 @@ _FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2 &p_vec)
return p_vec - *this * (dot(p_vec) - p_d);
}
-_FORCE_INLINE_ Vector2 operator*(real_t p_scalar, const Vector2 &p_vec) {
+_FORCE_INLINE_ Vector2 operator*(float p_scalar, const Vector2 &p_vec) {
+ return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2 operator*(double p_scalar, const Vector2 &p_vec) {
+ return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2 operator*(int32_t p_scalar, const Vector2 &p_vec) {
+ return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2 operator*(int64_t p_scalar, const Vector2 &p_vec) {
return p_vec * p_scalar;
}
@@ -304,6 +316,22 @@ struct Vector2i {
}
};
+_FORCE_INLINE_ Vector2i operator*(const int32_t &p_scalar, const Vector2i &p_vector) {
+ return p_vector * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2i operator*(const int64_t &p_scalar, const Vector2i &p_vector) {
+ return p_vector * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2i operator*(const float &p_scalar, const Vector2i &p_vector) {
+ return p_vector * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2i operator*(const double &p_scalar, const Vector2i &p_vector) {
+ return p_vector * p_scalar;
+}
+
typedef Vector2i Size2i;
typedef Vector2i Point2i;
diff --git a/core/os/os.cpp b/core/os/os.cpp
index dc8bd5ee69..3a398316bd 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -80,10 +80,6 @@ String OS::get_iso_date_time(bool local) const {
timezone;
}
-uint64_t OS::get_splash_tick_msec() const {
- return _msec_splash;
-}
-
double OS::get_unix_time() const {
return 0;
}
diff --git a/core/os/os.h b/core/os/os.h
index 8e5c0c26e0..4c1d930107 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -52,7 +52,6 @@ class OS {
bool _verbose_stdout = false;
bool _debug_stdout = false;
String _local_clipboard;
- uint64_t _msec_splash;
bool _no_window = false;
int _exit_code = 0;
int _orientation;
@@ -220,7 +219,6 @@ public:
virtual uint64_t get_ticks_usec() const = 0;
uint32_t get_ticks_msec() const;
- uint64_t get_splash_tick_msec() const;
virtual bool is_userfs_persistent() const { return true; }
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index efe13e740d..90f56694c2 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -53,6 +53,8 @@ String ProjectSettings::get_resource_path() const {
return resource_path;
}
+const String ProjectSettings::IMPORTED_FILES_PATH("res://.godot/imported");
+
String ProjectSettings::localize_path(const String &p_path) const {
if (resource_path == "") {
return p_path; //not initialized yet
diff --git a/core/project_settings.h b/core/project_settings.h
index 29b2406dd2..6cbb02d30e 100644
--- a/core/project_settings.h
+++ b/core/project_settings.h
@@ -41,6 +41,7 @@ class ProjectSettings : public Object {
public:
typedef Map<String, Variant> CustomMap;
+ static const String IMPORTED_FILES_PATH;
enum {
//properties that are not for built in values begin from this value, so builtin ones are displayed first
diff --git a/core/variant_op.cpp b/core/variant_op.cpp
index ec4eea05bf..533b056f91 100644
--- a/core/variant_op.cpp
+++ b/core/variant_op.cpp
@@ -1031,6 +1031,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a,
case FLOAT: {
_RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) * p_b._data._float);
}
+ case INT: {
+ _RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) * p_b._data._int);
+ }
default:
_RETURN_FAIL;
}
@@ -1062,8 +1065,64 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a,
}
}
- DEFAULT_OP_NUM_VEC(math, OP_MULTIPLY, INT, *, _int);
- DEFAULT_OP_NUM_VEC(math, OP_MULTIPLY, FLOAT, *, _float);
+ CASE_TYPE(math, OP_MULTIPLY, INT) {
+ if (p_b.type == INT) {
+ _RETURN(p_a._data._int * p_b._data._int);
+ }
+ if (p_b.type == FLOAT) {
+ _RETURN(p_a._data._int * p_b._data._float);
+ }
+ if (p_b.type == VECTOR2) {
+ _RETURN(p_a._data._int * *reinterpret_cast<const Vector2 *>(p_b._data._mem));
+ }
+ if (p_b.type == VECTOR3) {
+ _RETURN(p_a._data._int * *reinterpret_cast<const Vector3 *>(p_b._data._mem));
+ }
+ if (p_b.type == VECTOR2I) {
+ _RETURN(p_a._data._int * *reinterpret_cast<const Vector2i *>(p_b._data._mem));
+ }
+ if (p_b.type == VECTOR3I) {
+ _RETURN(p_a._data._int * *reinterpret_cast<const Vector3i *>(p_b._data._mem));
+ }
+ if (p_b.type == QUAT) {
+ _RETURN(p_a._data._int * *reinterpret_cast<const Quat *>(p_b._data._mem));
+ }
+ if (p_b.type == COLOR) {
+ _RETURN(p_a._data._int * *reinterpret_cast<const Color *>(p_b._data._mem));
+ }
+
+ _RETURN_FAIL
+ }
+
+ CASE_TYPE(math, OP_MULTIPLY, FLOAT) {
+ if (p_b.type == INT) {
+ _RETURN(p_a._data._float * p_b._data._int);
+ }
+ if (p_b.type == FLOAT) {
+ _RETURN(p_a._data._float * p_b._data._float);
+ }
+ if (p_b.type == VECTOR2) {
+ _RETURN(p_a._data._float * *reinterpret_cast<const Vector2 *>(p_b._data._mem));
+ }
+ if (p_b.type == VECTOR3) {
+ _RETURN(p_a._data._float * *reinterpret_cast<const Vector3 *>(p_b._data._mem));
+ }
+ if (p_b.type == VECTOR2I) {
+ _RETURN(p_a._data._float * *reinterpret_cast<const Vector2i *>(p_b._data._mem));
+ }
+ if (p_b.type == VECTOR3I) {
+ _RETURN(p_a._data._float * *reinterpret_cast<const Vector3i *>(p_b._data._mem));
+ }
+ if (p_b.type == QUAT) {
+ _RETURN(p_a._data._float * *reinterpret_cast<const Quat *>(p_b._data._mem));
+ }
+ if (p_b.type == COLOR) {
+ _RETURN(p_a._data._float * *reinterpret_cast<const Color *>(p_b._data._mem));
+ }
+
+ _RETURN_FAIL
+ }
+
DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR2, *, Vector2);
DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR2I, *, Vector2i);
DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR3, *, Vector3);
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index 0cb0b7e57e..8c92975b9c 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -122,6 +122,7 @@
</member>
<member name="billboard_mode" type="int" setter="set_billboard_mode" getter="get_billboard_mode" enum="BaseMaterial3D.BillboardMode" default="0">
Controls how the object faces the camera. See [enum BillboardMode].
+ [b]Note:[/b] Billboard mode is not suitable for VR because the left-right vector of the camera is not horizontal when the screen is attached to your head instead of on the table. See [url=https://github.com/godotengine/godot/issues/41567]GitHub issue #41567[/url] for details.
</member>
<member name="blend_mode" type="int" setter="set_blend_mode" getter="get_blend_mode" enum="BaseMaterial3D.BlendMode" default="0">
The material's blend mode.
@@ -174,10 +175,12 @@
If [code]true[/code], the object receives no shadow that would otherwise be cast onto it.
</member>
<member name="distance_fade_max_distance" type="float" setter="set_distance_fade_max_distance" getter="get_distance_fade_max_distance">
- Distance at which the object fades fully and is no longer visible.
+ Distance at which the object appears fully opaque.
+ [b]Note:[/b] If [code]distance_fade_max_distance[/code] is less than [code]distance_fade_min_distance[/code], the behavior will be reversed. The object will start to fade away at [code]distance_fade_max_distance[/code] and will fully disappear once it reaches [code]distance_fade_min_distance[/code].
</member>
<member name="distance_fade_min_distance" type="float" setter="set_distance_fade_min_distance" getter="get_distance_fade_min_distance">
- Distance at which the object starts to fade. If the object is less than this distance away it will appear normal.
+ Distance at which the object starts to become visible. If the object is less than this distance away, it will be invisible.
+ [b]Note:[/b] If [code]distance_fade_min_distance[/code] is greater than [code]distance_fade_max_distance[/code], the behavior will be reversed. The object will start to fade away at [code]distance_fade_max_distance[/code] and will fully disappear once it reaches [code]distance_fade_min_distance[/code].
</member>
<member name="distance_fade_mode" type="int" setter="set_distance_fade" getter="get_distance_fade" enum="BaseMaterial3D.DistanceFadeMode" default="0">
Specifies which type of fade to use. Can be any of the [enum DistanceFadeMode]s.
diff --git a/doc/classes/DynamicFont.xml b/doc/classes/DynamicFont.xml
index b0635892be..0b9b97f54a 100644
--- a/doc/classes/DynamicFont.xml
+++ b/doc/classes/DynamicFont.xml
@@ -96,10 +96,12 @@
Extra spacing at the bottom in pixels.
</member>
<member name="extra_spacing_char" type="int" setter="set_spacing" getter="get_spacing" default="0">
- Extra character spacing in pixels.
+ Extra spacing for each character in pixels.
+ This can be a negative number to make the distance between characters smaller.
</member>
<member name="extra_spacing_space" type="int" setter="set_spacing" getter="get_spacing" default="0">
- Extra space spacing in pixels.
+ Extra spacing for the space character (in addition to [member extra_spacing_char]) in pixels.
+ This can be a negative number to make the distance between words smaller.
</member>
<member name="extra_spacing_top" type="int" setter="set_spacing" getter="get_spacing" default="0">
Extra spacing at the top in pixels.
@@ -126,10 +128,10 @@
Spacing at the bottom.
</constant>
<constant name="SPACING_CHAR" value="2" enum="SpacingType">
- Character spacing.
+ Spacing for each character.
</constant>
<constant name="SPACING_SPACE" value="3" enum="SpacingType">
- Space spacing.
+ Spacing for the space character.
</constant>
</constants>
</class>
diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml
index b290557336..2a7f27ef55 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
EditorImportPlugins provide a way to extend the editor's resource import functionality. Use them to import resources from custom files or to provide alternatives to the editor's existing importers. Register your [EditorPlugin] with [method EditorPlugin.add_import_plugin].
- EditorImportPlugins work by associating with specific file extensions and a resource type. See [method get_recognized_extensions] and [method get_resource_type]. They may optionally specify some import presets that affect the import process. EditorImportPlugins are responsible for creating the resources and saving them in the [code].import[/code] directory.
+ EditorImportPlugins work by associating with specific file extensions and a resource type. See [method get_recognized_extensions] and [method get_resource_type]. They may optionally specify some import presets that affect the import process. EditorImportPlugins are responsible for creating the resources and saving them in the [code].godot/imported[/code] directory.
Below is an example EditorImportPlugin that imports a [Mesh] from a file with the extension ".special" or ".spec":
[codeblock]
tool
@@ -136,7 +136,7 @@
<return type="String">
</return>
<description>
- Gets the extension used to save this resource in the [code].import[/code] directory.
+ Gets the extension used to save this resource in the [code].godot/imported[/code] directory.
</description>
</method>
<method name="get_visible_name" qualifiers="virtual">
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index 9da36b51f9..c7561449b9 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -125,8 +125,10 @@
</argument>
<argument index="1" name="for_property" type="String" default="&quot;&quot;">
</argument>
+ <argument index="2" name="inspector_only" type="bool" default="false">
+ </argument>
<description>
- Shows the given property on the given [code]object[/code] in the editor's Inspector dock.
+ Shows the given property on the given [code]object[/code] in the editor's Inspector dock. If [code]inspector_only[/code] is [code]true[/code], plugins will not attempt to edit [code]object[/code].
</description>
</method>
<method name="is_playing_scene" qualifiers="const">
diff --git a/doc/classes/KinematicBody2D.xml b/doc/classes/KinematicBody2D.xml
index 5a1b4630d0..bc7a7c0d0d 100644
--- a/doc/classes/KinematicBody2D.xml
+++ b/doc/classes/KinematicBody2D.xml
@@ -6,7 +6,7 @@
<description>
Kinematic bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a character or a rigid body, these are the same as a static body. However, they have two main uses:
[b]Simulated motion:[/b] When these bodies are moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to "physics"), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc).
- [b]Kinematic characters:[/b] KinematicBody2D also has an API for moving objects (the [method move_and_collide] and [method move_and_slide] methods) while performing collision tests. This makes them really useful to implement characters that collide against a world, but that don't require advanced physics.
+ [b]Kinematic characters:[/b] KinematicBody2D also has an API for moving objects (the [method move_and_collide] and [method move_and_slide] methods) while performing collision tests. This makes them really useful to implement characters that collide against a world, but don't require advanced physics.
</description>
<tutorials>
<link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link>
@@ -33,7 +33,7 @@
<argument index="0" name="slide_idx" type="int">
</argument>
<description>
- Returns a [KinematicCollision2D], which contains information about a collision that occurred during the last [method move_and_slide] call. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count] - 1).
+ Returns a [KinematicCollision2D], which contains information about a collision that occurred during the last call to [method move_and_slide] or [method move_and_slide_with_snap]. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count] - 1).
[b]Example usage:[/b]
[codeblock]
for i in get_slide_count():
@@ -46,28 +46,28 @@
<return type="int">
</return>
<description>
- Returns the number of times the body collided and changed direction during the last call to [method move_and_slide].
+ Returns the number of times the body collided and changed direction during the last call to [method move_and_slide] or [method move_and_slide_with_snap].
</description>
</method>
<method name="is_on_ceiling" qualifiers="const">
<return type="bool">
</return>
<description>
- Returns [code]true[/code] if the body is on the ceiling. Only updates when calling [method move_and_slide].
+ Returns [code]true[/code] if the body is on the ceiling. Only updates when calling [method move_and_slide] or [method move_and_slide_with_snap].
</description>
</method>
<method name="is_on_floor" qualifiers="const">
<return type="bool">
</return>
<description>
- Returns [code]true[/code] if the body is on the floor. Only updates when calling [method move_and_slide].
+ Returns [code]true[/code] if the body is on the floor. Only updates when calling [method move_and_slide] or [method move_and_slide_with_snap].
</description>
</method>
<method name="is_on_wall" qualifiers="const">
<return type="bool">
</return>
<description>
- Returns [code]true[/code] if the body is on a wall. Only updates when calling [method move_and_slide].
+ Returns [code]true[/code] if the body is on a wall. Only updates when calling [method move_and_slide] or [method move_and_slide_with_snap].
</description>
</method>
<method name="move_and_collide">
@@ -102,7 +102,7 @@
<argument index="5" name="infinite_inertia" type="bool" default="true">
</argument>
<description>
- Moves the body along a vector. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [KinematicBody2D] or [RigidBody2D], it will also be affected by the motion of the other body. You can use this to make moving or rotating platforms, or to make nodes push other nodes.
+ Moves the body along a vector. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [KinematicBody2D] or [RigidBody2D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes.
This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed.
[code]linear_velocity[/code] is the velocity vector in pixels per second. Unlike in [method move_and_collide], you should [i]not[/i] multiply it by [code]delta[/code] — the physics engine handles applying the velocity.
[code]up_direction[/code] is the up direction, used to determine what is a wall and what is a floor or a ceiling. If set to the default value of [code]Vector2(0, 0)[/code], everything is considered a wall. This is useful for topdown games.
diff --git a/doc/classes/KinematicBody3D.xml b/doc/classes/KinematicBody3D.xml
index 5d9c7fd896..897b2c6280 100644
--- a/doc/classes/KinematicBody3D.xml
+++ b/doc/classes/KinematicBody3D.xml
@@ -6,7 +6,7 @@
<description>
Kinematic bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a character or a rigid body, these are the same as a static body. However, they have two main uses:
[b]Simulated motion:[/b] When these bodies are moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to "physics"), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc).
- [b]Kinematic characters:[/b] KinematicBody3D also has an API for moving objects (the [method move_and_collide] and [method move_and_slide] methods) while performing collision tests. This makes them really useful to implement characters that collide against a world, but that don't require advanced physics.
+ [b]Kinematic characters:[/b] KinematicBody3D also has an API for moving objects (the [method move_and_collide] and [method move_and_slide] methods) while performing collision tests. This makes them really useful to implement characters that collide against a world, but don't require advanced physics.
</description>
<tutorials>
<link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link>
@@ -41,35 +41,35 @@
<argument index="0" name="slide_idx" type="int">
</argument>
<description>
- Returns a [KinematicCollision3D], which contains information about a collision that occurred during the last [method move_and_slide] call. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count] - 1).
+ Returns a [KinematicCollision3D], which contains information about a collision that occurred during the last call to [method move_and_slide] or [method move_and_slide_with_snap]. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count] - 1).
</description>
</method>
<method name="get_slide_count" qualifiers="const">
<return type="int">
</return>
<description>
- Returns the number of times the body collided and changed direction during the last call to [method move_and_slide].
+ Returns the number of times the body collided and changed direction during the last call to [method move_and_slide] or [method move_and_slide_with_snap].
</description>
</method>
<method name="is_on_ceiling" qualifiers="const">
<return type="bool">
</return>
<description>
- Returns [code]true[/code] if the body is on the ceiling. Only updates when calling [method move_and_slide].
+ Returns [code]true[/code] if the body is on the ceiling. Only updates when calling [method move_and_slide] or [method move_and_slide_with_snap].
</description>
</method>
<method name="is_on_floor" qualifiers="const">
<return type="bool">
</return>
<description>
- Returns [code]true[/code] if the body is on the floor. Only updates when calling [method move_and_slide].
+ Returns [code]true[/code] if the body is on the floor. Only updates when calling [method move_and_slide] or [method move_and_slide_with_snap].
</description>
</method>
<method name="is_on_wall" qualifiers="const">
<return type="bool">
</return>
<description>
- Returns [code]true[/code] if the body is on a wall. Only updates when calling [method move_and_slide].
+ Returns [code]true[/code] if the body is on a wall. Only updates when calling [method move_and_slide] or [method move_and_slide_with_snap].
</description>
</method>
<method name="move_and_collide">
@@ -104,7 +104,7 @@
<argument index="5" name="infinite_inertia" type="bool" default="true">
</argument>
<description>
- Moves the body along a vector. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [KinematicBody3D] or [RigidBody3D], it will also be affected by the motion of the other body. You can use this to make moving or rotating platforms, or to make nodes push other nodes.
+ Moves the body along a vector. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [KinematicBody3D] or [RigidBody3D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes.
This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed.
[code]linear_velocity[/code] is the velocity vector (typically meters per second). Unlike in [method move_and_collide], you should [i]not[/i] multiply it by [code]delta[/code] — the physics engine handles applying the velocity.
[code]up_direction[/code] is the up direction, used to determine what is a wall and what is a floor or a ceiling. If set to the default value of [code]Vector3(0, 0, 0)[/code], everything is considered a wall.
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 26110df335..a1f12e1a31 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -234,13 +234,6 @@
Returns the number of threads available on the host machine.
</description>
</method>
- <method name="get_splash_tick_msec" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the amount of time in milliseconds it took for the boot logo to appear.
- </description>
- </method>
<method name="get_static_memory_peak_usage" qualifiers="const">
<return type="int">
</return>
diff --git a/doc/classes/VisualShaderNodeMultiplyAdd.xml b/doc/classes/VisualShaderNodeMultiplyAdd.xml
index ba79b3fe8f..daa9e02753 100644
--- a/doc/classes/VisualShaderNodeMultiplyAdd.xml
+++ b/doc/classes/VisualShaderNodeMultiplyAdd.xml
@@ -11,19 +11,19 @@
<methods>
</methods>
<members>
- <member name="type" type="int" setter="set_type" getter="get_type" enum="VisualShaderNodeMultiplyAdd.Type" default="0">
+ <member name="op_type" type="int" setter="set_op_type" getter="get_op_type" enum="VisualShaderNodeMultiplyAdd.OpType" default="0">
A type of operands and returned value.
</member>
</members>
<constants>
- <constant name="TYPE_SCALAR" value="0" enum="Type">
+ <constant name="OP_TYPE_SCALAR" value="0" enum="OpType">
A scalar type.
</constant>
- <constant name="TYPE_VECTOR" value="1" enum="Type">
+ <constant name="OP_TYPE_VECTOR" value="1" enum="OpType">
A vector type.
</constant>
- <constant name="TYPE_MAX" value="2" enum="Type">
- Represents the size of the [enum Type] enum.
+ <constant name="OP_TYPE_MAX" value="2" enum="OpType">
+ Represents the size of the [enum OpType] enum.
</constant>
</constants>
</class>
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index 1d7429eb64..d3a4dbb6e7 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -1406,6 +1406,20 @@ String EditorExportPlatform::test_etc2() const {
return String();
}
+String EditorExportPlatform::test_etc2_or_pvrtc() const {
+ String driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name");
+ bool etc2_supported = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2");
+ bool pvrtc_supported = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc");
+
+ if (driver == "GLES2" && !pvrtc_supported) {
+ return TTR("Target platform requires 'PVRTC' texture compression for GLES2. Enable 'Import Pvrtc' in Project Settings.");
+ } else if (driver == "Vulkan" && !etc2_supported && !pvrtc_supported) {
+ // FIXME: Review if this is true for Vulkan.
+ return TTR("Target platform requires 'ETC2' or 'PVRTC' texture compression for Vulkan. Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings.");
+ }
+ return String();
+}
+
int EditorExport::get_export_preset_count() const {
return export_presets.size();
}
diff --git a/editor/editor_export.h b/editor/editor_export.h
index ac1051571c..fa6be88302 100644
--- a/editor/editor_export.h
+++ b/editor/editor_export.h
@@ -277,6 +277,7 @@ public:
virtual Ref<Texture2D> get_run_icon() const { return get_logo(); }
String test_etc2() const; //generic test for etc2 since most platforms use it
+ String test_etc2_or_pvrtc() const; // test for etc2 or pvrtc support for iOS
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const = 0;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const = 0;
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 0e851734a7..ba9f27f65f 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -559,7 +559,7 @@ void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p
continue;
}
Dictionary item_meta = item_list->get_item_metadata(i);
- if (item_meta["path"] == "res://.import") {
+ if (String(item_meta["path"]).begins_with("res://.godot")) {
allow_delete = false;
break;
}
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index a5edcf5c22..5607bb3f17 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -1865,13 +1865,14 @@ void EditorFileSystem::_find_group_files(EditorFileSystemDirectory *efd, Map<Str
}
void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
- { //check that .import folder exists
+ {
+ // Ensure that ProjectSettings::IMPORTED_FILES_PATH exists.
DirAccess *da = DirAccess::open("res://");
- if (da->change_dir(".import") != OK) {
- Error err = da->make_dir(".import");
- if (err) {
+ if (da->change_dir(ProjectSettings::IMPORTED_FILES_PATH) != OK) {
+ Error err = da->make_dir_recursive(ProjectSettings::IMPORTED_FILES_PATH);
+ if (err || da->change_dir(ProjectSettings::IMPORTED_FILES_PATH) != OK) {
memdelete(da);
- ERR_FAIL_MSG("Failed to create 'res://.import' folder.");
+ ERR_FAIL_MSG("Failed to create '" + ProjectSettings::IMPORTED_FILES_PATH + "' folder.");
}
}
memdelete(da);
@@ -2055,8 +2056,8 @@ EditorFileSystem::EditorFileSystem() {
scanning_changes_done = false;
DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- if (da->change_dir("res://.import") != OK) {
- da->make_dir("res://.import");
+ if (da->change_dir(ProjectSettings::IMPORTED_FILES_PATH) != OK) {
+ da->make_dir(ProjectSettings::IMPORTED_FILES_PATH);
}
// This should probably also work on Unix and use the string it returns for FAT32 or exFAT
using_fat32_or_exfat = (da->get_filesystem_type() == "FAT32" || da->get_filesystem_type() == "exFAT");
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index bce46b719a..082c317655 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -234,8 +234,8 @@ String EditorInterface::get_current_path() const {
return EditorNode::get_singleton()->get_filesystem_dock()->get_current_path();
}
-void EditorInterface::inspect_object(Object *p_obj, const String &p_for_property) {
- EditorNode::get_singleton()->push_item(p_obj, p_for_property);
+void EditorInterface::inspect_object(Object *p_obj, const String &p_for_property, bool p_inspector_only) {
+ EditorNode::get_singleton()->push_item(p_obj, p_for_property, p_inspector_only);
}
EditorFileSystem *EditorInterface::get_resource_file_system() {
@@ -301,7 +301,7 @@ bool EditorInterface::is_distraction_free_mode_enabled() const {
EditorInterface *EditorInterface::singleton = nullptr;
void EditorInterface::_bind_methods() {
- ClassDB::bind_method(D_METHOD("inspect_object", "object", "for_property"), &EditorInterface::inspect_object, DEFVAL(String()));
+ ClassDB::bind_method(D_METHOD("inspect_object", "object", "for_property", "inspector_only"), &EditorInterface::inspect_object, DEFVAL(String()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_selection"), &EditorInterface::get_selection);
ClassDB::bind_method(D_METHOD("get_editor_settings"), &EditorInterface::get_editor_settings);
ClassDB::bind_method(D_METHOD("get_script_editor"), &EditorInterface::get_script_editor);
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index c7803f73c9..40a91cbfb9 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -89,7 +89,7 @@ public:
String get_selected_path() const;
String get_current_path() const;
- void inspect_object(Object *p_obj, const String &p_for_property = String());
+ void inspect_object(Object *p_obj, const String &p_for_property = String(), bool p_inspector_only = false);
EditorSelection *get_selection();
//EditorImportExport *get_import_export();
diff --git a/editor/editor_settings.h b/editor/editor_settings.h
index 4896fb58db..04bb49bb51 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -44,7 +44,6 @@ class EditorPlugin;
class EditorSettings : public Resource {
GDCLASS(EditorSettings, Resource);
-private:
_THREAD_SAFE_CLASS_
public:
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index d76a3d2da7..ac61a75a6c 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -356,7 +356,12 @@ String EditorSpinSlider::get_label() const {
}
void EditorSpinSlider::_evaluate_input_text() {
- String text = value_input->get_text();
+ // Replace comma with dot to support it as decimal separator (GH-6028).
+ // This prevents using functions like `pow()`, but using functions
+ // in EditorSpinSlider is a barely known (and barely used) feature.
+ // Instead, we'd rather support German/French keyboard layouts out of the box.
+ const String text = value_input->get_text().replace(",", ".");
+
Ref<Expression> expr;
expr.instance();
Error err = expr->parse(text);
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index bb144d2ed6..8caa4aeeaf 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -1226,6 +1226,12 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
const Ref<Material> &mat = state.materials[material];
mesh.mesh->surface_set_material(mesh.mesh->get_surface_count() - 1, mat);
+ } else {
+ Ref<StandardMaterial3D> mat;
+ mat.instance();
+ mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+
+ mesh.mesh->surface_set_material(mesh.mesh->get_surface_count() - 1, mat);
}
}
@@ -1386,6 +1392,7 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) {
if (d.has("name")) {
material->set_name(d["name"]);
}
+ material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
if (d.has("pbrMetallicRoughness")) {
const Dictionary &mr = d["pbrMetallicRoughness"];
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index d28bbadf39..944bf9913c 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -900,12 +900,15 @@ bool Node3DEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_high
}
float dist = r.distance_to(gt.origin);
-
- if (dist > gs * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gs * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) {
- float d = ray_pos.distance_to(r);
- if (d < col_d) {
- col_d = d;
- col_axis = i;
+ Vector3 r_dir = (r - gt.origin).normalized();
+
+ if (_get_camera_normal().dot(r_dir) <= 0.005) {
+ if (dist > gs * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gs * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) {
+ float d = ray_pos.distance_to(r);
+ if (d < col_d) {
+ col_d = d;
+ col_axis = i;
+ }
}
}
}
@@ -3125,6 +3128,14 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer);
}
+
+ // Rotation white outline
+ rotate_gizmo_instance[3] = RS::get_singleton()->instance_create();
+ RS::get_singleton()->instance_set_base(rotate_gizmo_instance[3], spatial_editor->get_rotate_gizmo(3)->get_rid());
+ RS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[3], get_tree()->get_root()->get_world_3d()->get_scenario());
+ RS::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], false);
+ RS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[3], RS::SHADOW_CASTING_SETTING_OFF);
+ RS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[3], layer);
}
void Node3DEditorViewport::_finish_gizmo_instances() {
@@ -3135,6 +3146,8 @@ void Node3DEditorViewport::_finish_gizmo_instances() {
RS::get_singleton()->free(scale_gizmo_instance[i]);
RS::get_singleton()->free(scale_plane_gizmo_instance[i]);
}
+ // Rotation white outline
+ RS::get_singleton()->free(rotate_gizmo_instance[3]);
}
void Node3DEditorViewport::_toggle_camera_preview(bool p_activate) {
@@ -3226,6 +3239,8 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false);
RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false);
}
+ // Rotation white outline
+ RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], false);
return;
}
@@ -3264,6 +3279,9 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
RenderingServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform);
RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE));
}
+ // Rotation white outline
+ RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[3], xform);
+ RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE));
}
void Node3DEditorViewport::set_state(const Dictionary &p_state) {
@@ -4403,7 +4421,7 @@ void Node3DEditor::select_gizmo_highlight_axis(int p_axis) {
for (int i = 0; i < 3; i++) {
move_gizmo[i]->surface_set_material(0, i == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
move_plane_gizmo[i]->surface_set_material(0, (i + 6) == p_axis ? plane_gizmo_color_hl[i] : plane_gizmo_color[i]);
- rotate_gizmo[i]->surface_set_material(0, (i + 3) == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
+ rotate_gizmo[i]->surface_set_material(0, (i + 3) == p_axis ? rotate_gizmo_color_hl[i] : rotate_gizmo_color[i]);
scale_gizmo[i]->surface_set_material(0, (i + 9) == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
scale_plane_gizmo[i]->surface_set_material(0, (i + 12) == p_axis ? plane_gizmo_color_hl[i] : plane_gizmo_color[i]);
}
@@ -5287,37 +5305,122 @@ void Node3DEditor::_init_indicators() {
Ref<SurfaceTool> surftool = memnew(SurfaceTool);
surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
- Vector3 circle[5] = {
- ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
- ivec * -0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
- ivec * -0.02 + ivec2 * -0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
- ivec * 0.02 + ivec2 * -0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
- ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
- };
+ int n = 128; // number of circle segments
+ int m = 6; // number of thickness segments
- for (int k = 0; k < 64; k++) {
- Basis ma(ivec, Math_PI * 2 * float(k) / 64);
- Basis mb(ivec, Math_PI * 2 * float(k + 1) / 64);
+ for (int j = 0; j < n; ++j) {
+ Basis basis = Basis(ivec, (Math_PI * 2.0f * j) / n);
- for (int j = 0; j < 4; j++) {
- Vector3 points[4] = {
- ma.xform(circle[j]),
- mb.xform(circle[j]),
- mb.xform(circle[j + 1]),
- ma.xform(circle[j + 1]),
- };
- surftool->add_vertex(points[0]);
- surftool->add_vertex(points[1]);
- surftool->add_vertex(points[2]);
+ Vector3 vertex = basis.xform(ivec2 * GIZMO_CIRCLE_SIZE);
- surftool->add_vertex(points[0]);
- surftool->add_vertex(points[2]);
- surftool->add_vertex(points[3]);
+ for (int k = 0; k < m; ++k) {
+ Vector2 ofs = Vector2(Math::cos((Math_PI * 2.0 * k) / m), Math::sin((Math_PI * 2.0 * k) / m));
+ Vector3 normal = ivec * ofs.x + ivec2 * ofs.y;
+
+ surftool->add_normal(basis.xform(normal));
+ surftool->add_vertex(vertex);
}
}
- surftool->set_material(mat);
- surftool->commit(rotate_gizmo[i]);
+ for (int j = 0; j < n; ++j) {
+ for (int k = 0; k < m; ++k) {
+ int current_ring = j * m;
+ int next_ring = ((j + 1) % n) * m;
+ int current_segment = k;
+ int next_segment = (k + 1) % m;
+
+ surftool->add_index(current_ring + next_segment);
+ surftool->add_index(current_ring + current_segment);
+ surftool->add_index(next_ring + current_segment);
+
+ surftool->add_index(next_ring + current_segment);
+ surftool->add_index(next_ring + next_segment);
+ surftool->add_index(current_ring + next_segment);
+ }
+ }
+
+ Ref<Shader> rotate_shader = memnew(Shader);
+
+ rotate_shader->set_code("\n"
+ "shader_type spatial; \n"
+ "render_mode unshaded, depth_test_disabled; \n"
+ "uniform vec4 albedo; \n"
+ "\n"
+ "mat3 orthonormalize(mat3 m) { \n"
+ " vec3 x = normalize(m[0]); \n"
+ " vec3 y = normalize(m[1] - x * dot(x, m[1])); \n"
+ " vec3 z = m[2] - x * dot(x, m[2]); \n"
+ " z = normalize(z - y * (dot(y,m[2]))); \n"
+ " return mat3(x,y,z); \n"
+ "} \n"
+ "\n"
+ "void vertex() { \n"
+ " mat3 mv = orthonormalize(mat3(MODELVIEW_MATRIX)); \n"
+ " vec3 n = mv * VERTEX; \n"
+ " float orientation = dot(vec3(0,0,-1),n); \n"
+ " if (orientation <= 0.005) { \n"
+ " VERTEX += NORMAL*0.02; \n"
+ " } \n"
+ "} \n"
+ "\n"
+ "void fragment() { \n"
+ " ALBEDO = albedo.rgb; \n"
+ " ALPHA = albedo.a; \n"
+ "}");
+
+ Ref<ShaderMaterial> rotate_mat = memnew(ShaderMaterial);
+ rotate_mat->set_render_priority(Material::RENDER_PRIORITY_MAX);
+ rotate_mat->set_shader(rotate_shader);
+ rotate_mat->set_shader_param("albedo", col);
+ rotate_gizmo_color[i] = rotate_mat;
+
+ Array arrays = surftool->commit_to_arrays();
+ rotate_gizmo[i]->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
+ rotate_gizmo[i]->surface_set_material(0, rotate_mat);
+
+ Ref<ShaderMaterial> rotate_mat_hl = rotate_mat->duplicate();
+ rotate_mat_hl->set_shader_param("albedo", Color(col.r, col.g, col.b, 1.0));
+ rotate_gizmo_color_hl[i] = rotate_mat_hl;
+
+ if (i == 2) { // Rotation white outline
+ Ref<ShaderMaterial> border_mat = rotate_mat->duplicate();
+
+ Ref<Shader> border_shader = memnew(Shader);
+ border_shader->set_code("\n"
+ "shader_type spatial; \n"
+ "render_mode unshaded, depth_test_disabled; \n"
+ "uniform vec4 albedo; \n"
+ "\n"
+ "mat3 orthonormalize(mat3 m) { \n"
+ " vec3 x = normalize(m[0]); \n"
+ " vec3 y = normalize(m[1] - x * dot(x, m[1])); \n"
+ " vec3 z = m[2] - x * dot(x, m[2]); \n"
+ " z = normalize(z - y * (dot(y,m[2]))); \n"
+ " return mat3(x,y,z); \n"
+ "} \n"
+ "\n"
+ "void vertex() { \n"
+ " mat3 mv = orthonormalize(mat3(MODELVIEW_MATRIX)); \n"
+ " mv = inverse(mv); \n"
+ " VERTEX += NORMAL*0.008; \n"
+ " vec3 camera_dir_local = mv * vec3(0,0,1); \n"
+ " vec3 camera_up_local = mv * vec3(0,1,0); \n"
+ " mat3 rotation_matrix = mat3(cross(camera_dir_local, camera_up_local), camera_up_local, camera_dir_local); \n"
+ " VERTEX = rotation_matrix * VERTEX; \n"
+ "} \n"
+ "\n"
+ "void fragment() { \n"
+ " ALBEDO = albedo.rgb; \n"
+ " ALPHA = albedo.a; \n"
+ "}");
+
+ border_mat->set_shader(border_shader);
+ border_mat->set_shader_param("albedo", Color(0.75, 0.75, 0.75, col.a / 3.0));
+
+ rotate_gizmo[3] = Ref<ArrayMesh>(memnew(ArrayMesh));
+ rotate_gizmo[3]->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
+ rotate_gizmo[3]->surface_set_material(0, border_mat);
+ }
}
// Scale
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 6a8af38742..b3dc4ef5f2 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -412,7 +412,7 @@ private:
real_t zoom_indicator_delay;
- RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[3], scale_gizmo_instance[3], scale_plane_gizmo_instance[3];
+ RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[4], scale_gizmo_instance[3], scale_plane_gizmo_instance[3];
String last_message;
String message;
@@ -600,11 +600,13 @@ private:
bool grid_enable[3]; //should be always visible if true
bool grid_enabled;
- Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[3], scale_gizmo[3], scale_plane_gizmo[3];
+ Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[4], scale_gizmo[3], scale_plane_gizmo[3];
Ref<StandardMaterial3D> gizmo_color[3];
Ref<StandardMaterial3D> plane_gizmo_color[3];
+ Ref<ShaderMaterial> rotate_gizmo_color[3];
Ref<StandardMaterial3D> gizmo_color_hl[3];
Ref<StandardMaterial3D> plane_gizmo_color_hl[3];
+ Ref<ShaderMaterial> rotate_gizmo_color_hl[3];
int over_gizmo_handle;
float snap_translate_value;
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index c14d07789f..914fa56755 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -1658,7 +1658,7 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
VisualShaderNodeMultiplyAdd *fmaFunc = Object::cast_to<VisualShaderNodeMultiplyAdd>(vsn);
if (fmaFunc) {
- fmaFunc->set_type((VisualShaderNodeMultiplyAdd::Type)p_op_idx);
+ fmaFunc->set_op_type((VisualShaderNodeMultiplyAdd::OpType)p_op_idx);
}
}
@@ -3169,7 +3169,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Max", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the greater of two values."), VisualShaderNodeFloatOp::OP_MAX, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Min", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the lesser of two values."), VisualShaderNodeFloatOp::OP_MIN, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Mix", "Scalar", "Functions", "VisualShaderNodeScalarInterp", TTR("Linear interpolation between two scalars."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("MultiplyAdd", "Scalar", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on scalars."), VisualShaderNodeMultiplyAdd::TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("MultiplyAdd", "Scalar", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on scalars."), VisualShaderNodeMultiplyAdd::OP_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeFloatFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeIntFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_SCALAR_INT));
add_options.push_back(AddOption("OneMinus", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("1.0 - scalar"), VisualShaderNodeFloatFunc::FUNC_ONEMINUS, VisualShaderNode::PORT_TYPE_SCALAR));
@@ -3275,7 +3275,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Min", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the lesser of two values."), VisualShaderNodeVectorOp::OP_MIN, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("Mix", "Vector", "Functions", "VisualShaderNodeVectorInterp", TTR("Linear interpolation between two vectors."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("MixS", "Vector", "Functions", "VisualShaderNodeVectorScalarMix", TTR("Linear interpolation between two vectors using scalar."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("MultiplyAdd", "Vector", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), VisualShaderNodeMultiplyAdd::TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("MultiplyAdd", "Vector", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("Negate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("Normalize", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("OneMinus", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNode::PORT_TYPE_VECTOR));
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 1fb889d793..6393aa30ed 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -2093,7 +2093,8 @@ void ProjectManager::_run_project_confirm() {
const String &selected = selected_list[i].project_key;
String path = EditorSettings::get_singleton()->get("projects/" + selected);
- if (!DirAccess::exists(path + "/.import")) {
+ // `.right(6)` on `IMPORTED_FILES_PATH` strips away the leading "res://".
+ if (!DirAccess::exists(path.plus_file(ProjectSettings::IMPORTED_FILES_PATH.right(6)))) {
run_error_diag->set_text(TTR("Can't run project: Assets need to be imported.\nPlease edit the project to trigger the initial import."));
run_error_diag->popup_centered();
return;
diff --git a/main/main.cpp b/main/main.cpp
index a039283235..a2ea085618 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1569,7 +1569,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
Color boot_bg_color = GLOBAL_DEF("application/boot_splash/bg_color", boot_splash_bg_color);
if (boot_logo.is_valid()) {
- OS::get_singleton()->_msec_splash = OS::get_singleton()->get_ticks_msec();
RenderingServer::get_singleton()->set_boot_image(boot_logo, boot_bg_color, boot_logo_scale,
boot_logo_filter);
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
index 4f8faffde2..5febcf3175 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
@@ -14,15 +14,15 @@
<GodotProjectDir Condition=" '$(SolutionDir)' == '' ">$(MSBuildProjectDirectory)</GodotProjectDir>
<GodotProjectDir>$([MSBuild]::EnsureTrailingSlash('$(GodotProjectDir)'))</GodotProjectDir>
- <!-- Custom output paths for Godot projects. In brief, 'bin\' and 'obj\' are moved to '$(GodotProjectDir)\.mono\temp\'. -->
- <BaseOutputPath>$(GodotProjectDir).mono\temp\bin\</BaseOutputPath>
- <OutputPath>$(GodotProjectDir).mono\temp\bin\$(Configuration)\</OutputPath>
+ <!-- Custom output paths for Godot projects. In brief, 'bin\' and 'obj\' are moved to '$(GodotProjectDir)\.godot\mono\temp\'. -->
+ <BaseOutputPath>$(GodotProjectDir).godot\mono\temp\bin\</BaseOutputPath>
+ <OutputPath>$(GodotProjectDir).godot\mono\temp\bin\$(Configuration)\</OutputPath>
<!--
Use custom IntermediateOutputPath and BaseIntermediateOutputPath only if it wasn't already set.
Otherwise the old values may have already been changed by MSBuild which can cause problems with NuGet.
-->
- <IntermediateOutputPath Condition=" '$(IntermediateOutputPath)' == '' ">$(GodotProjectDir).mono\temp\obj\$(Configuration)\</IntermediateOutputPath>
- <BaseIntermediateOutputPath Condition=" '$(BaseIntermediateOutputPath)' == '' ">$(GodotProjectDir).mono\temp\obj\</BaseIntermediateOutputPath>
+ <IntermediateOutputPath Condition=" '$(IntermediateOutputPath)' == '' ">$(GodotProjectDir).godot\mono\temp\obj\$(Configuration)\</IntermediateOutputPath>
+ <BaseIntermediateOutputPath Condition=" '$(BaseIntermediateOutputPath)' == '' ">$(GodotProjectDir).godot\mono\temp\obj\</BaseIntermediateOutputPath>
<!-- Do not append the target framework name to the output path. -->
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
@@ -102,11 +102,11 @@
-->
<Reference Include="GodotSharp">
<Private>false</Private>
- <HintPath>$(GodotProjectDir).mono\assemblies\$(GodotApiConfiguration)\GodotSharp.dll</HintPath>
+ <HintPath>$(GodotProjectDir).godot\mono\assemblies\$(GodotApiConfiguration)\GodotSharp.dll</HintPath>
</Reference>
<Reference Include="GodotSharpEditor" Condition=" '$(Configuration)' == 'Debug' ">
<Private>false</Private>
- <HintPath>$(GodotProjectDir).mono\assemblies\$(GodotApiConfiguration)\GodotSharpEditor.dll</HintPath>
+ <HintPath>$(GodotProjectDir).godot\mono\assemblies\$(GodotApiConfiguration)\GodotSharpEditor.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs
index 572c541412..0f50c90531 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs
@@ -121,7 +121,7 @@ namespace GodotTools.IdeMessaging
this.messageHandler = messageHandler;
this.logger = logger;
- string projectMetadataDir = Path.Combine(godotProjectDir, ".mono", "metadata");
+ string projectMetadataDir = Path.Combine(godotProjectDir, ".godot", "mono", "metadata");
MetaFilePath = Path.Combine(projectMetadataDir, GodotIdeMetadata.DefaultFileName);
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index 692da991c7..df31823deb 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -122,7 +122,7 @@ public:
private:
_GodotSharpDirs() {
- res_data_dir = "res://.mono";
+ res_data_dir = "res://.godot/mono";
res_metadata_dir = res_data_dir.plus_file("metadata");
res_assemblies_base_dir = res_data_dir.plus_file("assemblies");
res_assemblies_dir = res_assemblies_base_dir.plus_file(GDMono::get_expected_api_build_config());
diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp
index 36c0913f62..050dce1aab 100644
--- a/modules/pvr/texture_loader_pvr.cpp
+++ b/modules/pvr/texture_loader_pvr.cpp
@@ -213,10 +213,12 @@ static void _compress_pvrtc4(Image *p_img) {
int ofs, size, w, h;
img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
Javelin::RgbaBitmap bm(w, h);
+ void *dst = (void *)bm.GetData();
+ copymem(dst, &r[ofs], size);
+ Javelin::ColorRgba<unsigned char> *dp = bm.GetData();
for (int j = 0; j < size / 4; j++) {
- Javelin::ColorRgba<unsigned char> *dp = bm.GetData();
- /* red and Green colors are swapped. */
- new (dp) Javelin::ColorRgba<unsigned char>(r[ofs + 4 * j + 2], r[ofs + 4 * j + 1], r[ofs + 4 * j], r[ofs + 4 * j + 3]);
+ /* red and blue colors are swapped. */
+ SWAP(dp[j].r, dp[j].b);
}
new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs], bm);
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index 9a144c0a78..5e6cc3e4e2 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -44,6 +44,7 @@
#include "editor/editor_log.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "main/splash.gen.h"
#include "platform/android/export/gradle_export_util.h"
#include "platform/android/logo.gen.h"
#include "platform/android/plugin/godot_plugin_config.h"
@@ -200,6 +201,9 @@ static const char *android_perms[] = {
nullptr
};
+static const char *SPLASH_IMAGE_EXPORT_PATH = "res/drawable/splash.png";
+static const char *SPLASH_BG_COLOR_PATH = "res/drawable/splash_bg_color.png";
+
struct LauncherIcon {
const char *export_path;
int dimensions;
@@ -1433,6 +1437,18 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
//printf("end\n");
}
+ void _load_image_data(const Ref<Image> &p_splash_image, Vector<uint8_t> &p_data) {
+ Vector<uint8_t> png_buffer;
+ Error err = PNGDriverCommon::image_to_png(p_splash_image, png_buffer);
+ if (err == OK) {
+ p_data.resize(png_buffer.size());
+ memcpy(p_data.ptrw(), png_buffer.ptr(), p_data.size());
+ } else {
+ String err_str = String("Failed to convert splash image to png.");
+ WARN_PRINT(err_str.utf8().get_data());
+ }
+ }
+
void _process_launcher_icons(const String &p_file_name, const Ref<Image> &p_source_image, int dimension, Vector<uint8_t> &p_data) {
Ref<Image> working_image = p_source_image;
@@ -1452,6 +1468,35 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
}
+ void load_splash_refs(Ref<Image> &splash_image, Ref<Image> &splash_bg_color_image) {
+ // TODO: Figure out how to handle remaining boot splash parameters (e.g: fullsize, filter)
+ String project_splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
+
+ if (!project_splash_path.empty()) {
+ splash_image.instance();
+ const Error err = ImageLoader::load_image(project_splash_path, splash_image);
+ if (err) {
+ splash_image.unref();
+ }
+ }
+
+ if (splash_image.is_null()) {
+ // Use the default
+ splash_image = Ref<Image>(memnew(Image(boot_splash_png)));
+ }
+
+ // Setup the splash bg color
+ bool bg_color_valid;
+ Color bg_color = ProjectSettings::get_singleton()->get("application/boot_splash/bg_color", &bg_color_valid);
+ if (!bg_color_valid) {
+ bg_color = boot_splash_bg_color;
+ }
+
+ splash_bg_color_image.instance();
+ splash_bg_color_image->create(splash_image->get_width(), splash_image->get_height(), false, splash_image->get_format());
+ splash_bg_color_image->fill(bg_color);
+ }
+
void load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background) {
String project_icon_path = ProjectSettings::get_singleton()->get("application/config/icon");
@@ -1479,13 +1524,34 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
void store_image(const LauncherIcon launcher_icon, const Vector<uint8_t> &data) {
- String img_path = launcher_icon.export_path;
- img_path = img_path.insert(0, "res://android/build/");
+ store_image(launcher_icon.export_path, data);
+ }
+
+ void store_image(const String &export_path, const Vector<uint8_t> &data) {
+ String img_path = export_path.insert(0, "res://android/build/");
store_file_at_path(img_path, data);
}
- void _copy_icons_to_gradle_project(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &main_image,
- const Ref<Image> &foreground, const Ref<Image> &background) {
+ void _copy_icons_to_gradle_project(const Ref<EditorExportPreset> &p_preset,
+ const Ref<Image> &splash_image,
+ const Ref<Image> &splash_bg_color_image,
+ const Ref<Image> &main_image,
+ const Ref<Image> &foreground,
+ const Ref<Image> &background) {
+ // Store the splash image
+ if (splash_image.is_valid() && !splash_image->empty()) {
+ Vector<uint8_t> data;
+ _load_image_data(splash_image, data);
+ store_image(SPLASH_IMAGE_EXPORT_PATH, data);
+ }
+
+ // Store the splash bg color image
+ if (splash_bg_color_image.is_valid() && !splash_bg_color_image->empty()) {
+ Vector<uint8_t> data;
+ _load_image_data(splash_bg_color_image, data);
+ store_image(SPLASH_BG_COLOR_PATH, data);
+ }
+
// Prepare images to be resized for the icons. If some image ends up being uninitialized,
// the default image from the export template will be used.
@@ -2195,6 +2261,10 @@ public:
bool apk_expansion = p_preset->get("apk_expansion/enable");
Vector<String> enabled_abis = get_enabled_abis(p_preset);
+ Ref<Image> splash_image;
+ Ref<Image> splash_bg_color_image;
+ load_splash_refs(splash_image, splash_bg_color_image);
+
Ref<Image> main_image;
Ref<Image> foreground;
Ref<Image> background;
@@ -2247,7 +2317,7 @@ public:
EditorNode::add_io_error("Unable to overwrite res://android/build/res/*.xml files with project name");
}
// Copies the project icon files into the appropriate Gradle project directory.
- _copy_icons_to_gradle_project(p_preset, main_image, foreground, background);
+ _copy_icons_to_gradle_project(p_preset, splash_image, splash_bg_color_image, main_image, foreground, background);
// Write an AndroidManifest.xml file into the Gradle project directory.
_write_tmp_manifest(p_preset, p_give_internet, p_debug);
@@ -2448,6 +2518,17 @@ public:
if (file == "resources.arsc") {
_fix_resources(p_preset, data);
}
+
+ // Process the splash image
+ if (file == SPLASH_IMAGE_EXPORT_PATH && splash_image.is_valid() && !splash_image->empty()) {
+ _load_image_data(splash_image, data);
+ }
+
+ // Process the splash bg color image
+ if (file == SPLASH_BG_COLOR_PATH && splash_bg_color_image.is_valid() && !splash_bg_color_image->empty()) {
+ _load_image_data(splash_bg_color_image, data);
+ }
+
for (int i = 0; i < icon_densities_count; ++i) {
if (main_image.is_valid() && !main_image->empty()) {
if (file == launcher_icons[i].export_path) {
diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml
index 48c09552c1..e94681659c 100644
--- a/platform/android/java/app/AndroidManifest.xml
+++ b/platform/android/java/app/AndroidManifest.xml
@@ -38,7 +38,7 @@
<activity
android:name=".GodotApp"
android:label="@string/godot_project_name_string"
- android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
+ android:theme="@style/GodotAppSplashTheme"
android:launchMode="singleTask"
android:screenOrientation="landscape"
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
diff --git a/platform/android/java/app/res/drawable/splash.png b/platform/android/java/app/res/drawable/splash.png
new file mode 100644
index 0000000000..7bddd4325a
--- /dev/null
+++ b/platform/android/java/app/res/drawable/splash.png
Binary files differ
diff --git a/platform/android/java/app/res/drawable/splash_bg_color.png b/platform/android/java/app/res/drawable/splash_bg_color.png
new file mode 100644
index 0000000000..004b6fd508
--- /dev/null
+++ b/platform/android/java/app/res/drawable/splash_bg_color.png
Binary files differ
diff --git a/platform/android/java/app/res/drawable/splash_drawable.xml b/platform/android/java/app/res/drawable/splash_drawable.xml
new file mode 100644
index 0000000000..2794a40817
--- /dev/null
+++ b/platform/android/java/app/res/drawable/splash_drawable.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:drawable="@drawable/splash_bg_color" />
+
+ <item>
+ <bitmap
+ android:gravity="center"
+ android:src="@drawable/splash" />
+ </item>
+
+</layer-list>
diff --git a/platform/android/java/app/res/values/themes.xml b/platform/android/java/app/res/values/themes.xml
new file mode 100644
index 0000000000..26912538d3
--- /dev/null
+++ b/platform/android/java/app/res/values/themes.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <style name="GodotAppMainTheme" parent="@android:style/Theme.Black.NoTitleBar.Fullscreen"/>
+
+ <style name="GodotAppSplashTheme" parent="@style/GodotAppMainTheme">
+ <item name="android:windowBackground">@drawable/splash_drawable</item>
+ </style>
+</resources>
diff --git a/platform/android/java/app/src/com/godot/game/GodotApp.java b/platform/android/java/app/src/com/godot/game/GodotApp.java
index 1af5950cbe..51df70969e 100644
--- a/platform/android/java/app/src/com/godot/game/GodotApp.java
+++ b/platform/android/java/app/src/com/godot/game/GodotApp.java
@@ -32,9 +32,16 @@ package com.godot.game;
import org.godotengine.godot.FullScreenGodotApp;
+import android.os.Bundle;
+
/**
* Template activity for Godot Android custom builds.
* Feel free to extend and modify this class for your custom logic.
*/
public class GodotApp extends FullScreenGodotApp {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ setTheme(R.style.GodotAppMainTheme);
+ super.onCreate(savedInstanceState);
+ }
}
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index 97f954ebb2..19f7c8e482 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -160,9 +160,8 @@ public:
void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
String driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name");
- if (driver == "GLES2") {
- r_features->push_back("etc");
- } else if (driver == "Vulkan") {
+ r_features->push_back("pvrtc");
+ if (driver == "Vulkan") {
// FIXME: Review if this is correct.
r_features->push_back("etc2");
}
@@ -1649,7 +1648,7 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset
}
}
- String etc_error = test_etc2();
+ String etc_error = test_etc2_or_pvrtc();
if (etc_error != String()) {
valid = false;
err += etc_error;
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index e33af520c9..49f0e7bfa3 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -2041,6 +2041,12 @@ void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) {
CGDisplayHideCursor(kCGDirectMainDisplay);
}
CGAssociateMouseAndMouseCursorPosition(false);
+ WindowData &wd = windows[MAIN_WINDOW_ID];
+ const NSRect contentRect = [wd.window_view frame];
+ NSRect pointInWindowRect = NSMakeRect(contentRect.size.width / 2, contentRect.size.height / 2, 0, 0);
+ NSPoint pointOnScreen = [[wd.window_view window] convertRectToScreen:pointInWindowRect].origin;
+ CGPoint lMouseWarpPos = { pointOnScreen.x, CGDisplayBounds(CGMainDisplayID()).size.height - pointOnScreen.y };
+ CGWarpMouseCursorPosition(lMouseWarpPos);
} else if (p_mode == MOUSE_MODE_HIDDEN) {
if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
CGDisplayHideCursor(kCGDirectMainDisplay);
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 2cdee4641e..13d7440eb3 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -591,7 +591,7 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible_in_tree()) {
if (get_viewport() != nullptr) {
- get_viewport()->_gui_hid_control(this);
+ get_viewport()->_gui_hide_control(this);
}
//remove key focus
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index f6636cf392..070948237a 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1208,8 +1208,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (drop_mode_flags && drop_mode_over == p_item) {
Rect2 r = cell_rect;
+ bool has_parent = p_item->get_children() != nullptr;
- if (drop_mode_section == -1 || drop_mode_section == 0) {
+ if (drop_mode_section == -1 || has_parent || drop_mode_section == 0) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), cache.drop_position_color);
}
@@ -1218,7 +1219,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x + r.size.x - 1, r.position.y, 1, r.size.y), cache.drop_position_color);
}
- if (drop_mode_section == 1 || drop_mode_section == 0) {
+ if ((drop_mode_section == 1 && !has_parent) || drop_mode_section == 0) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y, r.size.x, 1), cache.drop_position_color);
}
}
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index b29b40ea5f..7fefbc3f3c 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2422,7 +2422,7 @@ void Viewport::_gui_unfocus_control(Control *p_control) {
}
}
-void Viewport::_gui_hid_control(Control *p_control) {
+void Viewport::_gui_hide_control(Control *p_control) {
if (gui.mouse_focus == p_control) {
_drop_mouse_focus();
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 52145a7761..878ac47bca 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -387,7 +387,7 @@ private:
void _gui_show_tooltip();
void _gui_remove_control(Control *p_control);
- void _gui_hid_control(Control *p_control);
+ void _gui_hide_control(Control *p_control);
void _gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control);
void _gui_set_drag_preview(Control *p_base, Control *p_control);
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index cffe0bb5cd..7c4500468b 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -5213,7 +5213,7 @@ int VisualShaderNodeMultiplyAdd::get_input_port_count() const {
}
VisualShaderNodeMultiplyAdd::PortType VisualShaderNodeMultiplyAdd::get_input_port_type(int p_port) const {
- if (type == TYPE_SCALAR) {
+ if (op_type == OP_TYPE_SCALAR) {
return PORT_TYPE_SCALAR;
}
return PORT_TYPE_VECTOR;
@@ -5235,7 +5235,7 @@ int VisualShaderNodeMultiplyAdd::get_output_port_count() const {
}
VisualShaderNodeMultiplyAdd::PortType VisualShaderNodeMultiplyAdd::get_output_port_type(int p_port) const {
- if (type == TYPE_SCALAR) {
+ if (op_type == OP_TYPE_SCALAR) {
return PORT_TYPE_SCALAR;
} else {
return PORT_TYPE_VECTOR;
@@ -5250,10 +5250,10 @@ String VisualShaderNodeMultiplyAdd::generate_code(Shader::Mode p_mode, VisualSha
return "\t" + p_output_vars[0] + " = fma(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n";
}
-void VisualShaderNodeMultiplyAdd::set_type(Type p_type) {
- ERR_FAIL_INDEX((int)p_type, TYPE_MAX);
- if (p_type != type) {
- if (p_type == TYPE_SCALAR) {
+void VisualShaderNodeMultiplyAdd::set_op_type(OpType p_op_type) {
+ ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX);
+ if (p_op_type != op_type) {
+ if (p_op_type == OP_TYPE_SCALAR) {
set_input_port_default_value(0, 0.0);
set_input_port_default_value(1, 0.0);
set_input_port_default_value(2, 0.0);
@@ -5263,29 +5263,29 @@ void VisualShaderNodeMultiplyAdd::set_type(Type p_type) {
set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0));
}
}
- type = p_type;
+ op_type = p_op_type;
emit_changed();
}
-VisualShaderNodeMultiplyAdd::Type VisualShaderNodeMultiplyAdd::get_type() const {
- return type;
+VisualShaderNodeMultiplyAdd::OpType VisualShaderNodeMultiplyAdd::get_op_type() const {
+ return op_type;
}
Vector<StringName> VisualShaderNodeMultiplyAdd::get_editable_properties() const {
Vector<StringName> props;
- props.push_back("type");
+ props.push_back("op_type");
return props;
}
void VisualShaderNodeMultiplyAdd::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_type", "type"), &VisualShaderNodeMultiplyAdd::set_type);
- ClassDB::bind_method(D_METHOD("get_type"), &VisualShaderNodeMultiplyAdd::get_type);
+ ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeMultiplyAdd::set_op_type);
+ ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeMultiplyAdd::get_op_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, "Scalar,Vector"), "set_type", "get_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector"), "set_op_type", "get_op_type");
- BIND_ENUM_CONSTANT(TYPE_SCALAR);
- BIND_ENUM_CONSTANT(TYPE_VECTOR);
- BIND_ENUM_CONSTANT(TYPE_MAX);
+ BIND_ENUM_CONSTANT(OP_TYPE_SCALAR);
+ BIND_ENUM_CONSTANT(OP_TYPE_VECTOR);
+ BIND_ENUM_CONSTANT(OP_TYPE_MAX);
}
VisualShaderNodeMultiplyAdd::VisualShaderNodeMultiplyAdd() {
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 1c986d1ef4..95042f8e56 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -2138,14 +2138,14 @@ class VisualShaderNodeMultiplyAdd : public VisualShaderNode {
GDCLASS(VisualShaderNodeMultiplyAdd, VisualShaderNode);
public:
- enum Type {
- TYPE_SCALAR,
- TYPE_VECTOR,
- TYPE_MAX,
+ enum OpType {
+ OP_TYPE_SCALAR,
+ OP_TYPE_VECTOR,
+ OP_TYPE_MAX,
};
protected:
- Type type = TYPE_SCALAR;
+ OpType op_type = OP_TYPE_SCALAR;
protected:
static void _bind_methods();
@@ -2163,14 +2163,14 @@ public:
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
- void set_type(Type p_type);
- Type get_type() const;
+ void set_op_type(OpType p_type);
+ OpType get_op_type() const;
virtual Vector<StringName> get_editable_properties() const override;
VisualShaderNodeMultiplyAdd();
};
-VARIANT_ENUM_CAST(VisualShaderNodeMultiplyAdd::Type)
+VARIANT_ENUM_CAST(VisualShaderNodeMultiplyAdd::OpType)
#endif // VISUAL_SHADER_NODES_H