summaryrefslogtreecommitdiff
path: root/scene/resources
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources')
-rw-r--r--scene/resources/animation.cpp33
-rw-r--r--scene/resources/animation.h8
-rw-r--r--scene/resources/animation_library.cpp33
-rw-r--r--scene/resources/animation_library.h6
-rw-r--r--scene/resources/bit_map.cpp4
-rw-r--r--scene/resources/bone_map.cpp181
-rw-r--r--scene/resources/bone_map.h70
-rw-r--r--scene/resources/box_shape_3d.cpp2
-rw-r--r--scene/resources/camera_effects.cpp4
-rw-r--r--scene/resources/canvas_item_material.cpp2
-rw-r--r--scene/resources/canvas_item_material.h17
-rw-r--r--scene/resources/capsule_shape_2d.cpp4
-rw-r--r--scene/resources/capsule_shape_3d.cpp4
-rw-r--r--scene/resources/circle_shape_2d.cpp2
-rw-r--r--scene/resources/concave_polygon_shape_3d.cpp8
-rw-r--r--scene/resources/concave_polygon_shape_3d.h12
-rw-r--r--scene/resources/curve.cpp571
-rw-r--r--scene/resources/curve.h37
-rw-r--r--scene/resources/cylinder_shape_3d.cpp4
-rw-r--r--scene/resources/default_theme/default_theme.cpp121
-rw-r--r--scene/resources/default_theme/default_theme.h2
-rw-r--r--scene/resources/environment.cpp11
-rw-r--r--scene/resources/fog_material.cpp6
-rw-r--r--scene/resources/font.cpp2315
-rw-r--r--scene/resources/font.h266
-rw-r--r--scene/resources/gradient.cpp2
-rw-r--r--scene/resources/gradient.h14
-rw-r--r--scene/resources/immediate_mesh.cpp2
-rw-r--r--scene/resources/importer_mesh.cpp33
-rw-r--r--scene/resources/label_settings.cpp187
-rw-r--r--scene/resources/label_settings.h89
-rw-r--r--scene/resources/material.cpp201
-rw-r--r--scene/resources/material.h96
-rw-r--r--scene/resources/mesh.cpp104
-rw-r--r--scene/resources/mesh.h34
-rw-r--r--scene/resources/mesh_data_tool.cpp2
-rw-r--r--scene/resources/mesh_library.cpp16
-rw-r--r--scene/resources/mesh_library.h4
-rw-r--r--scene/resources/multimesh.cpp12
-rw-r--r--scene/resources/navigation_mesh.cpp124
-rw-r--r--scene/resources/navigation_mesh.h33
-rw-r--r--scene/resources/packed_scene.cpp212
-rw-r--r--scene/resources/packed_scene.h24
-rw-r--r--scene/resources/particles_material.cpp48
-rw-r--r--scene/resources/particles_material.h42
-rw-r--r--scene/resources/polygon_path_finder.cpp80
-rw-r--r--scene/resources/polygon_path_finder.h22
-rw-r--r--scene/resources/primitive_meshes.cpp854
-rw-r--r--scene/resources/primitive_meshes.h157
-rw-r--r--scene/resources/rectangle_shape_2d.cpp2
-rw-r--r--scene/resources/resource_format_text.cpp306
-rw-r--r--scene/resources/resource_format_text.h50
-rw-r--r--scene/resources/scene_replication_config.cpp22
-rw-r--r--scene/resources/scene_replication_config.h1
-rw-r--r--scene/resources/segment_shape_2d.cpp4
-rw-r--r--scene/resources/separation_ray_shape_2d.cpp2
-rw-r--r--scene/resources/separation_ray_shape_3d.cpp2
-rw-r--r--scene/resources/shader.cpp12
-rw-r--r--scene/resources/shader.h16
-rw-r--r--scene/resources/shape_3d.cpp2
-rw-r--r--scene/resources/skeleton_modification_2d_physicalbones.h2
-rw-r--r--scene/resources/skeleton_modification_2d_twoboneik.cpp4
-rw-r--r--scene/resources/skeleton_modification_stack_2d.cpp2
-rw-r--r--scene/resources/skeleton_modification_stack_3d.cpp2
-rw-r--r--scene/resources/skeleton_profile.cpp793
-rw-r--r--scene/resources/skeleton_profile.h131
-rw-r--r--scene/resources/skin.cpp9
-rw-r--r--scene/resources/sky.cpp2
-rw-r--r--scene/resources/sky_material.cpp86
-rw-r--r--scene/resources/sky_material.h34
-rw-r--r--scene/resources/sphere_shape_3d.cpp4
-rw-r--r--scene/resources/sphere_shape_3d.h2
-rw-r--r--scene/resources/sprite_frames.cpp89
-rw-r--r--scene/resources/sprite_frames.h19
-rw-r--r--scene/resources/style_box.cpp126
-rw-r--r--scene/resources/style_box.h4
-rw-r--r--scene/resources/surface_tool.cpp68
-rw-r--r--scene/resources/surface_tool.h12
-rw-r--r--scene/resources/syntax_highlighter.h4
-rw-r--r--scene/resources/text_file.cpp2
-rw-r--r--scene/resources/text_line.cpp94
-rw-r--r--scene/resources/text_line.h29
-rw-r--r--scene/resources/text_paragraph.cpp321
-rw-r--r--scene/resources/text_paragraph.h41
-rw-r--r--scene/resources/texture.cpp258
-rw-r--r--scene/resources/texture.h105
-rw-r--r--scene/resources/theme.cpp363
-rw-r--r--scene/resources/theme.h22
-rw-r--r--scene/resources/tile_set.cpp440
-rw-r--r--scene/resources/tile_set.h111
-rw-r--r--scene/resources/visual_shader.cpp708
-rw-r--r--scene/resources/visual_shader.h49
-rw-r--r--scene/resources/visual_shader_nodes.cpp1111
-rw-r--r--scene/resources/visual_shader_nodes.h128
-rw-r--r--scene/resources/visual_shader_particle_nodes.cpp14
-rw-r--r--scene/resources/visual_shader_particle_nodes.h4
-rw-r--r--scene/resources/world_2d.cpp4
-rw-r--r--scene/resources/world_2d.h4
-rw-r--r--scene/resources/world_3d.cpp9
-rw-r--r--scene/resources/world_3d.h4
-rw-r--r--scene/resources/world_boundary_shape_2d.cpp2
-rw-r--r--scene/resources/world_boundary_shape_3d.cpp2
102 files changed, 8077 insertions, 3675 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index e045a379d2..7183accc66 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -3379,17 +3379,6 @@ Vector2 Animation::bezier_track_get_key_out_handle(int p_track, int p_index) con
return bt->values[p_index].value.out_handle;
}
-static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, const Vector2 &start, const Vector2 &control_1, const Vector2 &control_2, const Vector2 &end) {
- /* Formula from Wikipedia article on Bezier curves. */
- real_t omt = (1.0 - t);
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = t * t;
- real_t t3 = t2 * t;
-
- return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3;
-}
-
real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
//this uses a different interpolation scheme
ERR_FAIL_INDEX_V(p_track, tracks.size(), 0);
@@ -3438,7 +3427,7 @@ real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
for (int i = 0; i < iterations; i++) {
real_t middle = (low + high) / 2;
- Vector2 interp = _bezier_interp(middle, start, start_out, end_in, end);
+ Vector2 interp = start.bezier_interpolate(start_out, end_in, end, middle);
if (interp.x < t) {
low = middle;
@@ -3448,14 +3437,14 @@ real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
}
//interpolate the result:
- Vector2 low_pos = _bezier_interp(low, start, start_out, end_in, end);
- Vector2 high_pos = _bezier_interp(high, start, start_out, end_in, end);
+ Vector2 low_pos = start.bezier_interpolate(start_out, end_in, end, low);
+ Vector2 high_pos = start.bezier_interpolate(start_out, end_in, end, high);
real_t c = (t - low_pos.x) / (high_pos.x - low_pos.x);
return low_pos.lerp(high_pos, c).y;
}
-int Animation::audio_track_insert_key(int p_track, double p_time, const RES &p_stream, real_t p_start_offset, real_t p_end_offset) {
+int Animation::audio_track_insert_key(int p_track, double p_time, const Ref<Resource> &p_stream, real_t p_start_offset, real_t p_end_offset) {
ERR_FAIL_INDEX_V(p_track, tracks.size(), -1);
Track *t = tracks[p_track];
ERR_FAIL_COND_V(t->type != TYPE_AUDIO, -1);
@@ -3481,7 +3470,7 @@ int Animation::audio_track_insert_key(int p_track, double p_time, const RES &p_s
return key;
}
-void Animation::audio_track_set_key_stream(int p_track, int p_key, const RES &p_stream) {
+void Animation::audio_track_set_key_stream(int p_track, int p_key, const Ref<Resource> &p_stream) {
ERR_FAIL_INDEX(p_track, tracks.size());
Track *t = tracks[p_track];
ERR_FAIL_COND(t->type != TYPE_AUDIO);
@@ -3531,14 +3520,14 @@ void Animation::audio_track_set_key_end_offset(int p_track, int p_key, real_t p_
emit_changed();
}
-RES Animation::audio_track_get_key_stream(int p_track, int p_key) const {
- ERR_FAIL_INDEX_V(p_track, tracks.size(), RES());
+Ref<Resource> Animation::audio_track_get_key_stream(int p_track, int p_key) const {
+ ERR_FAIL_INDEX_V(p_track, tracks.size(), Ref<Resource>());
const Track *t = tracks[p_track];
- ERR_FAIL_COND_V(t->type != TYPE_AUDIO, RES());
+ ERR_FAIL_COND_V(t->type != TYPE_AUDIO, Ref<Resource>());
const AudioTrack *at = static_cast<const AudioTrack *>(t);
- ERR_FAIL_INDEX_V(p_key, at->values.size(), RES());
+ ERR_FAIL_INDEX_V(p_key, at->values.size(), Ref<Resource>());
return at->values[p_key].value.stream;
}
@@ -3827,9 +3816,9 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("compress", "page_size", "fps", "split_tolerance"), &Animation::compress, DEFVAL(8192), DEFVAL(120), DEFVAL(4.0));
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.001,99999,0.001"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.001,99999,0.001,suffix:s"), "set_length", "get_length");
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Ping-Pong"), "set_loop_mode", "get_loop_mode");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step", PROPERTY_HINT_RANGE, "0,4096,0.001"), "set_step", "get_step");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step", PROPERTY_HINT_RANGE, "0,4096,0.001,suffix:s"), "set_step", "get_step");
ADD_SIGNAL(MethodInfo("tracks_changed"));
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index f9a33da428..b4528ccd3a 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -180,7 +180,7 @@ private:
/* AUDIO TRACK */
struct AudioKey {
- RES stream;
+ Ref<Resource> stream;
real_t start_offset = 0.0; //offset from start
real_t end_offset = 0.0; //offset from end, if 0 then full length or infinite
AudioKey() {
@@ -436,11 +436,11 @@ public:
real_t bezier_track_interpolate(int p_track, double p_time) const;
- int audio_track_insert_key(int p_track, double p_time, const RES &p_stream, real_t p_start_offset = 0, real_t p_end_offset = 0);
- void audio_track_set_key_stream(int p_track, int p_key, const RES &p_stream);
+ int audio_track_insert_key(int p_track, double p_time, const Ref<Resource> &p_stream, real_t p_start_offset = 0, real_t p_end_offset = 0);
+ void audio_track_set_key_stream(int p_track, int p_key, const Ref<Resource> &p_stream);
void audio_track_set_key_start_offset(int p_track, int p_key, real_t p_offset);
void audio_track_set_key_end_offset(int p_track, int p_key, real_t p_offset);
- RES audio_track_get_key_stream(int p_track, int p_key) const;
+ Ref<Resource> audio_track_get_key_stream(int p_track, int p_key) const;
real_t audio_track_get_key_start_offset(int p_track, int p_key) const;
real_t audio_track_get_key_end_offset(int p_track, int p_key) const;
diff --git a/scene/resources/animation_library.cpp b/scene/resources/animation_library.cpp
index 229d9ab218..5f725b2fbe 100644
--- a/scene/resources/animation_library.cpp
+++ b/scene/resources/animation_library.cpp
@@ -30,8 +30,25 @@
#include "animation_library.h"
+bool AnimationLibrary::is_valid_animation_name(const String &p_name) {
+ return !(p_name.is_empty() || p_name.contains("/") || p_name.contains(":") || p_name.contains(",") || p_name.contains("["));
+}
+
+bool AnimationLibrary::is_valid_library_name(const String &p_name) {
+ return !(p_name.contains("/") || p_name.contains(":") || p_name.contains(",") || p_name.contains("["));
+}
+
+String AnimationLibrary::validate_library_name(const String &p_name) {
+ String name = p_name;
+ const char *characters = "/:,[";
+ for (const char *p = characters; *p; p++) {
+ name = name.replace(String::chr(*p), "_");
+ }
+ return name;
+}
+
Error AnimationLibrary::add_animation(const StringName &p_name, const Ref<Animation> &p_animation) {
- ERR_FAIL_COND_V_MSG(String(p_name).contains("/") || String(p_name).contains(":") || String(p_name).contains(",") || String(p_name).contains("["), ERR_INVALID_PARAMETER, "Invalid animation name: " + String(p_name) + ".");
+ ERR_FAIL_COND_V_MSG(!is_valid_animation_name(p_name), ERR_INVALID_PARAMETER, "Invalid animation name: '" + String(p_name) + "'.");
ERR_FAIL_COND_V(p_animation.is_null(), ERR_INVALID_PARAMETER);
if (animations.has(p_name)) {
@@ -46,7 +63,7 @@ Error AnimationLibrary::add_animation(const StringName &p_name, const Ref<Animat
}
void AnimationLibrary::remove_animation(const StringName &p_name) {
- ERR_FAIL_COND(!animations.has(p_name));
+ ERR_FAIL_COND_MSG(!animations.has(p_name), vformat("Animation not found: %s.", p_name));
animations.erase(p_name);
emit_signal(SNAME("animation_removed"), p_name);
@@ -54,9 +71,9 @@ void AnimationLibrary::remove_animation(const StringName &p_name) {
}
void AnimationLibrary::rename_animation(const StringName &p_name, const StringName &p_new_name) {
- ERR_FAIL_COND(!animations.has(p_name));
- ERR_FAIL_COND_MSG(String(p_new_name).contains("/") || String(p_new_name).contains(":") || String(p_new_name).contains(",") || String(p_new_name).contains("["), "Invalid animation name: " + String(p_new_name) + ".");
- ERR_FAIL_COND(animations.has(p_new_name));
+ ERR_FAIL_COND_MSG(!animations.has(p_name), vformat("Animation not found: %s.", p_name));
+ ERR_FAIL_COND_MSG(!is_valid_animation_name(p_new_name), "Invalid animation name: '" + String(p_new_name) + "'.");
+ ERR_FAIL_COND_MSG(animations.has(p_new_name), vformat("Animation name \"%s\" already exists in library.", p_new_name));
animations.insert(p_new_name, animations[p_name]);
animations.erase(p_name);
@@ -126,9 +143,9 @@ void AnimationLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_data"), &AnimationLibrary::_get_data);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "_set_data", "_get_data");
- ADD_SIGNAL(MethodInfo("animation_added", PropertyInfo(Variant::OBJECT, "name", PROPERTY_HINT_RESOURCE_TYPE, "Animation")));
- ADD_SIGNAL(MethodInfo("animation_removed", PropertyInfo(Variant::OBJECT, "name", PROPERTY_HINT_RESOURCE_TYPE, "Animation")));
- ADD_SIGNAL(MethodInfo("animation_renamed", PropertyInfo(Variant::OBJECT, "name", PROPERTY_HINT_RESOURCE_TYPE, "Animation"), PropertyInfo(Variant::OBJECT, "to_name", PROPERTY_HINT_RESOURCE_TYPE, "Animation")));
+ ADD_SIGNAL(MethodInfo("animation_added", PropertyInfo(Variant::STRING_NAME, "name")));
+ ADD_SIGNAL(MethodInfo("animation_removed", PropertyInfo(Variant::STRING_NAME, "name")));
+ ADD_SIGNAL(MethodInfo("animation_renamed", PropertyInfo(Variant::STRING_NAME, "name"), PropertyInfo(Variant::STRING_NAME, "to_name")));
}
AnimationLibrary::AnimationLibrary() {
}
diff --git a/scene/resources/animation_library.h b/scene/resources/animation_library.h
index 69ac5a97d2..7a69cd140a 100644
--- a/scene/resources/animation_library.h
+++ b/scene/resources/animation_library.h
@@ -43,12 +43,16 @@ class AnimationLibrary : public Resource {
TypedArray<StringName> _get_animation_list() const;
friend class AnimationPlayer; //for faster access
- Map<StringName, Ref<Animation>> animations;
+ HashMap<StringName, Ref<Animation>> animations;
protected:
static void _bind_methods();
public:
+ static bool is_valid_animation_name(const String &p_name);
+ static bool is_valid_library_name(const String &p_name);
+ static String validate_library_name(const String &p_name);
+
Error add_animation(const StringName &p_name, const Ref<Animation> &p_animation);
void remove_animation(const StringName &p_name);
void rename_animation(const StringName &p_name, const StringName &p_new_name);
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index c2988c2e8c..1ff72825ac 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -170,8 +170,8 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
int curx = startx;
int cury = starty;
unsigned int count = 0;
- Set<Point2i> case9s;
- Set<Point2i> case6s;
+ HashSet<Point2i> case9s;
+ HashSet<Point2i> case6s;
Vector<Vector2> _points;
do {
int sv = 0;
diff --git a/scene/resources/bone_map.cpp b/scene/resources/bone_map.cpp
new file mode 100644
index 0000000000..aff917b2d4
--- /dev/null
+++ b/scene/resources/bone_map.cpp
@@ -0,0 +1,181 @@
+/*************************************************************************/
+/* bone_map.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "bone_map.h"
+
+bool BoneMap::_set(const StringName &p_path, const Variant &p_value) {
+ String path = p_path;
+ if (path.begins_with("bone_map/")) {
+ String which = path.get_slicec('/', 1);
+ set_skeleton_bone_name(which, p_value);
+ return true;
+ }
+ return true;
+}
+
+bool BoneMap::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+ if (path.begins_with("bone_map/")) {
+ String which = path.get_slicec('/', 1);
+ r_ret = get_skeleton_bone_name(which);
+ return true;
+ }
+ return true;
+}
+
+void BoneMap::_get_property_list(List<PropertyInfo> *p_list) const {
+ HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
+ while (E) {
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bone_map/" + E->key, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
+ ++E;
+ }
+}
+
+Ref<SkeletonProfile> BoneMap::get_profile() const {
+ return profile;
+}
+
+void BoneMap::set_profile(const Ref<SkeletonProfile> &p_profile) {
+ bool is_changed = profile != p_profile;
+ if (is_changed) {
+ if (!profile.is_null() && profile->is_connected("profile_updated", callable_mp(this, &BoneMap::_update_profile))) {
+ profile->disconnect("profile_updated", callable_mp(this, &BoneMap::_update_profile));
+ }
+ profile = p_profile;
+ if (!profile.is_null()) {
+ profile->connect("profile_updated", callable_mp(this, &BoneMap::_update_profile));
+ }
+ _update_profile();
+ }
+ notify_property_list_changed();
+}
+
+StringName BoneMap::get_skeleton_bone_name(StringName p_profile_bone_name) const {
+ ERR_FAIL_COND_V(!bone_map.has(p_profile_bone_name), StringName());
+ return bone_map.get(p_profile_bone_name);
+}
+
+void BoneMap::set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) {
+ ERR_FAIL_COND(!bone_map.has(p_profile_bone_name));
+ bone_map.insert(p_profile_bone_name, p_skeleton_bone_name);
+ emit_signal("bone_map_updated");
+}
+
+StringName BoneMap::find_profile_bone_name(StringName p_skeleton_bone_name) const {
+ StringName profile_bone_name = StringName();
+ HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
+ while (E) {
+ if (E->value == p_skeleton_bone_name) {
+ profile_bone_name = E->key;
+ break;
+ }
+ ++E;
+ }
+ return profile_bone_name;
+}
+
+int BoneMap::get_skeleton_bone_name_count(const StringName p_skeleton_bone_name) const {
+ int count = 0;
+ HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
+ while (E) {
+ if (E->value == p_skeleton_bone_name) {
+ ++count;
+ }
+ ++E;
+ }
+ return count;
+}
+
+void BoneMap::_update_profile() {
+ _validate_bone_map();
+ emit_signal("profile_updated");
+}
+
+void BoneMap::_validate_bone_map() {
+ Ref<SkeletonProfile> current_profile = get_profile();
+ if (current_profile.is_valid()) {
+ // Insert missing profile bones into bone map.
+ int len = current_profile->get_bone_size();
+ StringName profile_bone_name;
+ for (int i = 0; i < len; i++) {
+ profile_bone_name = current_profile->get_bone_name(i);
+ if (!bone_map.has(profile_bone_name)) {
+ bone_map.insert(profile_bone_name, StringName());
+ }
+ }
+ // Remove bones that do not exist in the profile from the map.
+ Vector<StringName> delete_bones;
+ StringName k;
+ HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
+ while (E) {
+ k = E->key;
+ if (!current_profile->has_bone(k)) {
+ delete_bones.push_back(k);
+ }
+ ++E;
+ }
+ len = delete_bones.size();
+ for (int i = 0; i < len; i++) {
+ bone_map.erase(delete_bones[i]);
+ }
+ } else {
+ bone_map.clear();
+ }
+ emit_signal("retarget_option_updated");
+}
+
+void BoneMap::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_profile"), &BoneMap::get_profile);
+ ClassDB::bind_method(D_METHOD("set_profile", "profile"), &BoneMap::set_profile);
+
+ ClassDB::bind_method(D_METHOD("get_skeleton_bone_name", "profile_bone_name"), &BoneMap::get_skeleton_bone_name);
+ ClassDB::bind_method(D_METHOD("set_skeleton_bone_name", "profile_bone_name", "skeleton_bone_name"), &BoneMap::set_skeleton_bone_name);
+
+ ClassDB::bind_method(D_METHOD("find_profile_bone_name", "skeleton_bone_name"), &BoneMap::find_profile_bone_name);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "profile", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonProfile"), "set_profile", "get_profile");
+ ADD_ARRAY("bonemap", "bonemap");
+
+ ADD_SIGNAL(MethodInfo("bone_map_updated"));
+ ADD_SIGNAL(MethodInfo("profile_updated"));
+}
+
+void BoneMap::_validate_property(PropertyInfo &property) const {
+ //
+}
+
+BoneMap::BoneMap() {
+ _validate_bone_map();
+}
+
+BoneMap::~BoneMap() {
+}
+
+//////////////////////////////////////
diff --git a/scene/resources/bone_map.h b/scene/resources/bone_map.h
new file mode 100644
index 0000000000..17452dfc73
--- /dev/null
+++ b/scene/resources/bone_map.h
@@ -0,0 +1,70 @@
+/*************************************************************************/
+/* bone_map.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef BONE_MAP_H
+#define BONE_MAP_H
+
+#include "skeleton_profile.h"
+
+class BoneMap : public Resource {
+ GDCLASS(BoneMap, Resource);
+
+ Ref<SkeletonProfile> profile;
+ HashMap<StringName, StringName> bone_map;
+
+ void _update_profile();
+ void _validate_bone_map();
+
+protected:
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ bool _set(const StringName &p_path, const Variant &p_value);
+ virtual void _validate_property(PropertyInfo &property) const override;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+ static void _bind_methods();
+
+public:
+ int get_profile_type() const;
+ void set_profile_type(const int p_profile_type);
+
+ Ref<SkeletonProfile> get_profile() const;
+ void set_profile(const Ref<SkeletonProfile> &p_profile);
+
+ int get_skeleton_bone_name_count(const StringName p_skeleton_bone_name) const;
+
+ StringName get_skeleton_bone_name(StringName p_profile_bone_name) const;
+ void set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name);
+
+ StringName find_profile_bone_name(StringName p_skeleton_bone_name) const;
+
+ BoneMap();
+ ~BoneMap();
+};
+
+#endif // BONE_MAP_H
diff --git a/scene/resources/box_shape_3d.cpp b/scene/resources/box_shape_3d.cpp
index 1abbf366fd..aac334b4be 100644
--- a/scene/resources/box_shape_3d.cpp
+++ b/scene/resources/box_shape_3d.cpp
@@ -91,7 +91,7 @@ void BoxShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size", "size"), &BoxShape3D::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &BoxShape3D::get_size);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
}
BoxShape3D::BoxShape3D() :
diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp
index ebe2aa4dba..97617adbae 100644
--- a/scene/resources/camera_effects.cpp
+++ b/scene/resources/camera_effects.cpp
@@ -175,10 +175,10 @@ void CameraEffects::_bind_methods() {
ADD_GROUP("DOF Blur", "dof_blur_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_distance", "get_dof_blur_far_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_far_distance", "get_dof_blur_far_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_distance", "get_dof_blur_near_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_near_distance", "get_dof_blur_near_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount");
diff --git a/scene/resources/canvas_item_material.cpp b/scene/resources/canvas_item_material.cpp
index 2d668cdf7f..aa6cc4aded 100644
--- a/scene/resources/canvas_item_material.cpp
+++ b/scene/resources/canvas_item_material.cpp
@@ -34,7 +34,7 @@
Mutex CanvasItemMaterial::material_mutex;
SelfList<CanvasItemMaterial>::List *CanvasItemMaterial::dirty_materials = nullptr;
-Map<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData> CanvasItemMaterial::shader_map;
+HashMap<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData, CanvasItemMaterial::MaterialKey> CanvasItemMaterial::shader_map;
CanvasItemMaterial::ShaderNames *CanvasItemMaterial::shader_names = nullptr;
void CanvasItemMaterial::init_shaders() {
diff --git a/scene/resources/canvas_item_material.h b/scene/resources/canvas_item_material.h
index e40e4392cb..160c67d6b1 100644
--- a/scene/resources/canvas_item_material.h
+++ b/scene/resources/canvas_item_material.h
@@ -63,8 +63,11 @@ private:
uint32_t key = 0;
- bool operator<(const MaterialKey &p_key) const {
- return key < p_key.key;
+ static uint32_t hash(const MaterialKey &p_key) {
+ return hash_murmur3_one_32(p_key.key);
+ }
+ bool operator==(const MaterialKey &p_key) const {
+ return key == p_key.key;
}
};
@@ -81,7 +84,7 @@ private:
int users = 0;
};
- static Map<MaterialKey, ShaderData> shader_map;
+ static HashMap<MaterialKey, ShaderData, MaterialKey> shader_map;
MaterialKey current_key;
@@ -107,10 +110,10 @@ private:
LightMode light_mode = LIGHT_MODE_NORMAL;
bool particles_animation = false;
- // Initialized in the constructor.
- int particles_anim_h_frames;
- int particles_anim_v_frames;
- bool particles_anim_loop;
+ // Proper values set in constructor.
+ int particles_anim_h_frames = 0;
+ int particles_anim_v_frames = 0;
+ bool particles_anim_loop = false;
protected:
static void _bind_methods();
diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp
index c7bd4cb698..eb27ffaf35 100644
--- a/scene/resources/capsule_shape_2d.cpp
+++ b/scene/resources/capsule_shape_2d.cpp
@@ -109,8 +109,8 @@ void CapsuleShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_height", "height"), &CapsuleShape2D::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &CapsuleShape2D::get_height);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:px"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:px"), "set_height", "get_height");
ADD_LINKED_PROPERTY("radius", "height");
ADD_LINKED_PROPERTY("height", "radius");
}
diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp
index d708706ff2..214004824f 100644
--- a/scene/resources/capsule_shape_3d.cpp
+++ b/scene/resources/capsule_shape_3d.cpp
@@ -113,8 +113,8 @@ void CapsuleShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_height", "height"), &CapsuleShape3D::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &CapsuleShape3D::get_height);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_LINKED_PROPERTY("radius", "height");
ADD_LINKED_PROPERTY("height", "radius");
}
diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp
index c287de9ede..ff60162180 100644
--- a/scene/resources/circle_shape_2d.cpp
+++ b/scene/resources/circle_shape_2d.cpp
@@ -56,7 +56,7 @@ void CircleShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CircleShape2D::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &CircleShape2D::get_radius);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:px"), "set_radius", "get_radius");
}
Rect2 CircleShape2D::get_rect() const {
diff --git a/scene/resources/concave_polygon_shape_3d.cpp b/scene/resources/concave_polygon_shape_3d.cpp
index 3e178108c4..b91f0e4f1c 100644
--- a/scene/resources/concave_polygon_shape_3d.cpp
+++ b/scene/resources/concave_polygon_shape_3d.cpp
@@ -33,7 +33,7 @@
#include "servers/physics_server_3d.h"
Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
- Set<DrawEdge> edges;
+ HashSet<DrawEdge, DrawEdge> edges;
int index_count = faces.size();
ERR_FAIL_COND_V((index_count % 3) != 0, Vector<Vector3>());
@@ -50,9 +50,9 @@ Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
Vector<Vector3> points;
points.resize(edges.size() * 2);
int idx = 0;
- for (Set<DrawEdge>::Element *E = edges.front(); E; E = E->next()) {
- points.write[idx + 0] = E->get().a;
- points.write[idx + 1] = E->get().b;
+ for (const DrawEdge &E : edges) {
+ points.write[idx + 0] = E.a;
+ points.write[idx + 1] = E.b;
idx += 2;
}
diff --git a/scene/resources/concave_polygon_shape_3d.h b/scene/resources/concave_polygon_shape_3d.h
index 5337deb5fb..a265590edd 100644
--- a/scene/resources/concave_polygon_shape_3d.h
+++ b/scene/resources/concave_polygon_shape_3d.h
@@ -42,12 +42,12 @@ class ConcavePolygonShape3D : public Shape3D {
struct DrawEdge {
Vector3 a;
Vector3 b;
- bool operator<(const DrawEdge &p_edge) const {
- if (a == p_edge.a) {
- return b < p_edge.b;
- } else {
- return a < p_edge.a;
- }
+ static uint32_t hash(const DrawEdge &p_edge) {
+ uint32_t h = hash_murmur3_one_32(HashMapHasherDefault::hash(p_edge.a));
+ return hash_murmur3_one_32(HashMapHasherDefault::hash(p_edge.b), h);
+ }
+ bool operator==(const DrawEdge &p_edge) const {
+ return (a == p_edge.a && b == p_edge.b);
}
DrawEdge(const Vector3 &p_a = Vector3(), const Vector3 &p_b = Vector3()) {
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 6485c1ac77..da26a0261f 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -32,24 +32,25 @@
#include "core/core_string_names.h"
-template <class T>
-static _FORCE_INLINE_ T _bezier_interp(real_t p_t, T p_start, T p_control_1, T p_control_2, T p_end) {
- /* Formula from Wikipedia article on Bezier curves. */
- real_t omt = (1.0 - p_t);
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = p_t * p_t;
- real_t t3 = t2 * p_t;
-
- return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
-}
-
const char *Curve::SIGNAL_RANGE_CHANGED = "range_changed";
Curve::Curve() {
}
-int Curve::add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_tangent, TangentMode p_left_mode, TangentMode p_right_mode) {
+void Curve::set_point_count(int p_count) {
+ ERR_FAIL_COND(p_count < 0);
+ if (_points.size() >= p_count) {
+ _points.resize(p_count);
+ mark_dirty();
+ } else {
+ for (int i = p_count - _points.size(); i > 0; i--) {
+ _add_point(Vector2());
+ }
+ }
+ notify_property_list_changed();
+}
+
+int Curve::_add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_tangent, TangentMode p_left_mode, TangentMode p_right_mode) {
// Add a point and preserve order
// Curve bounds is in 0..1
@@ -100,6 +101,13 @@ int Curve::add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_t
return ret;
}
+int Curve::add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_tangent, TangentMode p_left_mode, TangentMode p_right_mode) {
+ int ret = _add_point(p_position, p_left_tangent, p_right_tangent, p_left_mode, p_right_mode);
+ notify_property_list_changed();
+
+ return ret;
+}
+
int Curve::get_index(real_t p_offset) const {
// Lower-bound float binary search
@@ -205,15 +213,21 @@ Curve::TangentMode Curve::get_point_right_mode(int p_index) const {
return _points[p_index].right_mode;
}
-void Curve::remove_point(int p_index) {
+void Curve::_remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, _points.size());
_points.remove_at(p_index);
mark_dirty();
}
+void Curve::remove_point(int p_index) {
+ _remove_point(p_index);
+ notify_property_list_changed();
+}
+
void Curve::clear_points() {
_points.clear();
mark_dirty();
+ notify_property_list_changed();
}
void Curve::set_point_value(int p_index, real_t p_position) {
@@ -226,8 +240,8 @@ void Curve::set_point_value(int p_index, real_t p_position) {
int Curve::set_point_offset(int p_index, real_t p_offset) {
ERR_FAIL_INDEX_V(p_index, _points.size(), -1);
Point p = _points[p_index];
- remove_point(p_index);
- int i = add_point(Vector2(p_offset, p.position.y));
+ _remove_point(p_index);
+ int i = _add_point(Vector2(p_offset, p.position.y));
_points.write[i].left_tangent = p.left_tangent;
_points.write[i].right_tangent = p.right_tangent;
_points.write[i].left_mode = p.left_mode;
@@ -350,7 +364,7 @@ real_t Curve::interpolate_local_nocheck(int p_index, real_t p_local_offset) cons
real_t yac = a.position.y + d * a.right_tangent;
real_t ybc = b.position.y - d * b.left_tangent;
- real_t y = _bezier_interp(p_local_offset, a.position.y, yac, ybc, b.position.y);
+ real_t y = Math::bezier_interpolate(a.position.y, yac, ybc, b.position.y, p_local_offset);
return y;
}
@@ -409,7 +423,6 @@ void Curve::set_data(const Array p_input) {
p.position = p_input[i];
p.left_tangent = p_input[i + 1];
p.right_tangent = p_input[i + 2];
- // TODO For some reason the compiler won't convert from Variant to enum
int left_mode = p_input[i + 3];
int right_mode = p_input[i + 4];
p.left_mode = (TangentMode)left_mode;
@@ -417,6 +430,7 @@ void Curve::set_data(const Array p_input) {
}
mark_dirty();
+ notify_property_list_changed();
}
void Curve::bake() {
@@ -490,8 +504,91 @@ void Curve::ensure_default_setup(real_t p_min, real_t p_max) {
}
}
+bool Curve::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
+ int point_index = components[0].trim_prefix("point_").to_int();
+ String property = components[1];
+ if (property == "position") {
+ Vector2 position = p_value.operator Vector2();
+ set_point_offset(point_index, position.x);
+ set_point_value(point_index, position.y);
+ return true;
+ } else if (property == "left_tangent") {
+ set_point_left_tangent(point_index, p_value);
+ return true;
+ } else if (property == "left_mode") {
+ int mode = p_value;
+ set_point_left_mode(point_index, (TangentMode)mode);
+ return true;
+ } else if (property == "right_tangent") {
+ set_point_right_tangent(point_index, p_value);
+ return true;
+ } else if (property == "right_mode") {
+ int mode = p_value;
+ set_point_right_mode(point_index, (TangentMode)mode);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Curve::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
+ int point_index = components[0].trim_prefix("point_").to_int();
+ String property = components[1];
+ if (property == "position") {
+ r_ret = get_point_position(point_index);
+ return true;
+ } else if (property == "left_tangent") {
+ r_ret = get_point_left_tangent(point_index);
+ return true;
+ } else if (property == "left_mode") {
+ r_ret = get_point_left_mode(point_index);
+ return true;
+ } else if (property == "right_tangent") {
+ r_ret = get_point_right_tangent(point_index);
+ return true;
+ } else if (property == "right_mode") {
+ r_ret = get_point_right_mode(point_index);
+ return true;
+ }
+ }
+ return false;
+}
+
+void Curve::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < _points.size(); i++) {
+ PropertyInfo pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/position", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+
+ if (i != 0) {
+ pi = PropertyInfo(Variant::FLOAT, vformat("point_%d/left_tangent", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+
+ pi = PropertyInfo(Variant::INT, vformat("point_%d/left_mode", i), PROPERTY_HINT_ENUM, "Free,Linear");
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+
+ if (i != _points.size() - 1) {
+ pi = PropertyInfo(Variant::FLOAT, vformat("point_%d/right_tangent", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+
+ pi = PropertyInfo(Variant::INT, vformat("point_%d/right_mode", i), PROPERTY_HINT_ENUM, "Free,Linear");
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+ }
+}
+
void Curve::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Curve::get_point_count);
+ ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve::set_point_count);
ClassDB::bind_method(D_METHOD("add_point", "position", "left_tangent", "right_tangent", "left_mode", "right_mode"), &Curve::add_point, DEFVAL(0), DEFVAL(0), DEFVAL(TANGENT_FREE), DEFVAL(TANGENT_FREE));
ClassDB::bind_method(D_METHOD("remove_point", "index"), &Curve::remove_point);
ClassDB::bind_method(D_METHOD("clear_points"), &Curve::clear_points);
@@ -523,6 +620,7 @@ void Curve::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_value", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_max_value", "get_max_value");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_resolution", PROPERTY_HINT_RANGE, "1,1000,1"), "set_bake_resolution", "get_bake_resolution");
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
+ ADD_ARRAY_COUNT("Points", "point_count", "set_point_count", "get_point_count", "point_");
ADD_SIGNAL(MethodInfo(SIGNAL_RANGE_CHANGED));
@@ -535,7 +633,20 @@ int Curve2D::get_point_count() const {
return points.size();
}
-void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) {
+void Curve2D::set_point_count(int p_count) {
+ ERR_FAIL_COND(p_count < 0);
+ if (points.size() >= p_count) {
+ points.resize(p_count);
+ mark_dirty();
+ } else {
+ for (int i = p_count - points.size(); i > 0; i--) {
+ _add_point(Vector2());
+ }
+ }
+ notify_property_list_changed();
+}
+
+void Curve2D::_add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) {
Point n;
n.position = p_position;
n.in = p_in;
@@ -546,16 +657,19 @@ void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Ve
points.push_back(n);
}
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
+}
+
+void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) {
+ _add_point(p_position, p_in, p_out, p_atpos);
+ notify_property_list_changed();
}
void Curve2D::set_point_position(int p_index, const Vector2 &p_position) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].position = p_position;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
Vector2 Curve2D::get_point_position(int p_index) const {
@@ -567,8 +681,7 @@ void Curve2D::set_point_in(int p_index, const Vector2 &p_in) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].in = p_in;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
Vector2 Curve2D::get_point_in(int p_index) const {
@@ -580,8 +693,7 @@ void Curve2D::set_point_out(int p_index, const Vector2 &p_out) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].out = p_out;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
Vector2 Curve2D::get_point_out(int p_index) const {
@@ -589,18 +701,22 @@ Vector2 Curve2D::get_point_out(int p_index) const {
return points[p_index].out;
}
-void Curve2D::remove_point(int p_index) {
+void Curve2D::_remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, points.size());
points.remove_at(p_index);
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
+}
+
+void Curve2D::remove_point(int p_index) {
+ _remove_point(p_index);
+ notify_property_list_changed();
}
void Curve2D::clear_points() {
if (!points.is_empty()) {
points.clear();
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
+ notify_property_list_changed();
}
}
@@ -619,7 +735,7 @@ Vector2 Curve2D::interpolate(int p_index, const real_t p_offset) const {
Vector2 p3 = points[p_index + 1].position;
Vector2 p2 = p3 + points[p_index + 1].in;
- return _bezier_interp(p_offset, p0, p1, p2, p3);
+ return p0.bezier_interpolate(p1, p2, p3, p_offset);
}
Vector2 Curve2D::interpolatef(real_t p_findex) const {
@@ -632,11 +748,16 @@ Vector2 Curve2D::interpolatef(real_t p_findex) const {
return interpolate((int)p_findex, Math::fmod(p_findex, (real_t)1.0));
}
-void Curve2D::_bake_segment2d(Map<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
+void Curve2D::mark_dirty() {
+ baked_cache_dirty = true;
+ emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+void Curve2D::_bake_segment2d(RBMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
real_t mp = p_begin + (p_end - p_begin) * 0.5;
- Vector2 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector2 mid = _bezier_interp(mp, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector2 end = _bezier_interp(p_end, p_a, p_a + p_out, p_b + p_in, p_b);
+ Vector2 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin);
+ Vector2 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp);
+ Vector2 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end);
Vector2 na = (mid - beg).normalized();
Vector2 nb = (end - mid).normalized();
@@ -681,7 +802,8 @@ void Curve2D::_bake() const {
List<Vector2> pointlist;
List<real_t> distlist;
- pointlist.push_back(position); //start always from origin
+ // Start always from origin.
+ pointlist.push_back(position);
distlist.push_back(0.0);
for (int i = 0; i < points.size() - 1; i++) {
@@ -694,7 +816,7 @@ void Curve2D::_bake() const {
np = 1.0;
}
- Vector2 npp = _bezier_interp(np, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+ Vector2 npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, np);
real_t d = position.distance_to(npp);
if (d > bake_interval) {
@@ -707,7 +829,7 @@ void Curve2D::_bake() const {
real_t mid = low + (hi - low) * 0.5;
for (int j = 0; j < iterations; j++) {
- npp = _bezier_interp(mid, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+ npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, mid);
d = position.distance_to(npp);
if (bake_interval < d) {
@@ -728,15 +850,18 @@ void Curve2D::_bake() const {
p = np;
}
}
- }
- Vector2 lastpos = points[points.size() - 1].position;
+ Vector2 npp = points[i + 1].position;
+ real_t d = position.distance_to(npp);
+
+ position = npp;
+ dist += d;
+
+ pointlist.push_back(position);
+ distlist.push_back(dist);
+ }
- real_t rem = position.distance_to(lastpos);
- dist += rem;
baked_max_ofs = dist;
- pointlist.push_back(lastpos);
- distlist.push_back(dist);
baked_point_cache.resize(pointlist.size());
baked_dist_cache.resize(distlist.size());
@@ -763,7 +888,7 @@ Vector2 Curve2D::interpolate_baked(real_t p_offset, bool p_cubic) const {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked points.
int pc = baked_point_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, Vector2(), "No points in Curve2D.");
@@ -771,18 +896,19 @@ Vector2 Curve2D::interpolate_baked(real_t p_offset, bool p_cubic) const {
return baked_point_cache.get(0);
}
- int bpc = baked_point_cache.size();
const Vector2 *r = baked_point_cache.ptr();
if (p_offset < 0) {
return r[0];
}
if (p_offset >= baked_max_ofs) {
- return r[bpc - 1];
+ return r[pc - 1];
}
- int start = 0, end = bpc, idx = (end + start) / 2;
- // binary search to find baked points
+ int start = 0;
+ int end = pc;
+ int idx = (end + start) / 2;
+ // Binary search to find baked points.
while (start < idx) {
real_t offset = baked_dist_cache[idx];
if (p_offset <= offset) {
@@ -803,7 +929,7 @@ Vector2 Curve2D::interpolate_baked(real_t p_offset, bool p_cubic) const {
if (p_cubic) {
Vector2 pre = idx > 0 ? r[idx - 1] : r[idx];
- Vector2 post = (idx < (bpc - 2)) ? r[idx + 2] : r[idx + 1];
+ Vector2 post = (idx < (pc - 2)) ? r[idx + 2] : r[idx + 1];
return r[idx].cubic_interpolate(r[idx + 1], pre, post, frac);
} else {
return r[idx].lerp(r[idx + 1], frac);
@@ -820,8 +946,7 @@ PackedVector2Array Curve2D::get_baked_points() const {
void Curve2D::set_bake_interval(real_t p_tolerance) {
bake_interval = p_tolerance;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
real_t Curve2D::get_bake_interval() const {
@@ -829,13 +954,13 @@ real_t Curve2D::get_bake_interval() const {
}
Vector2 Curve2D::get_closest_point(const Vector2 &p_to_point) const {
- // Brute force method
+ // Brute force method.
if (baked_cache_dirty) {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked points.
int pc = baked_point_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, Vector2(), "No points in Curve2D.");
@@ -867,13 +992,13 @@ Vector2 Curve2D::get_closest_point(const Vector2 &p_to_point) const {
}
real_t Curve2D::get_closest_offset(const Vector2 &p_to_point) const {
- // Brute force method
+ // Brute force method.
if (baked_cache_dirty) {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked points.
int pc = baked_point_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, 0.0f, "No points in Curve2D.");
@@ -940,7 +1065,8 @@ void Curve2D::_set_data(const Dictionary &p_data) {
points.write[i].position = r[i * 3 + 2];
}
- baked_cache_dirty = true;
+ mark_dirty();
+ notify_property_list_changed();
}
PackedVector2Array Curve2D::tessellate(int p_max_stages, real_t p_tolerance) const {
@@ -949,7 +1075,9 @@ PackedVector2Array Curve2D::tessellate(int p_max_stages, real_t p_tolerance) con
if (points.size() == 0) {
return tess;
}
- Vector<Map<real_t, Vector2>> midpoints;
+
+ // The current implementation requires a sorted map.
+ Vector<RBMap<real_t, Vector2>> midpoints;
midpoints.resize(points.size() - 1);
@@ -978,8 +1106,67 @@ PackedVector2Array Curve2D::tessellate(int p_max_stages, real_t p_tolerance) con
return tess;
}
+bool Curve2D::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
+ int point_index = components[0].trim_prefix("point_").to_int();
+ String property = components[1];
+ if (property == "position") {
+ set_point_position(point_index, p_value);
+ return true;
+ } else if (property == "in") {
+ set_point_in(point_index, p_value);
+ return true;
+ } else if (property == "out") {
+ set_point_out(point_index, p_value);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Curve2D::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
+ int point_index = components[0].trim_prefix("point_").to_int();
+ String property = components[1];
+ if (property == "position") {
+ r_ret = get_point_position(point_index);
+ return true;
+ } else if (property == "in") {
+ r_ret = get_point_in(point_index);
+ return true;
+ } else if (property == "out") {
+ r_ret = get_point_out(point_index);
+ return true;
+ }
+ }
+ return false;
+}
+
+void Curve2D::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < points.size(); i++) {
+ PropertyInfo pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/position", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+
+ if (i != 0) {
+ pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/in", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+
+ if (i != points.size() - 1) {
+ pi = PropertyInfo(Variant::VECTOR2, vformat("point_%d/out", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+ }
+}
+
void Curve2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Curve2D::get_point_count);
+ ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve2D::set_point_count);
ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "at_position"), &Curve2D::add_point, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve2D::set_point_position);
ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve2D::get_point_position);
@@ -1007,13 +1194,10 @@ void Curve2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
+ ADD_ARRAY_COUNT("Points", "point_count", "set_point_count", "get_point_count", "point_");
}
-Curve2D::Curve2D() {
- /* add_point(Vector2(-1,0,0));
- add_point(Vector2(0,2,0));
- add_point(Vector2(0,3,5));*/
-}
+Curve2D::Curve2D() {}
/***********************************************************************************/
/***********************************************************************************/
@@ -1026,7 +1210,20 @@ int Curve3D::get_point_count() const {
return points.size();
}
-void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) {
+void Curve3D::set_point_count(int p_count) {
+ ERR_FAIL_COND(p_count < 0);
+ if (points.size() >= p_count) {
+ points.resize(p_count);
+ mark_dirty();
+ } else {
+ for (int i = p_count - points.size(); i > 0; i--) {
+ _add_point(Vector3());
+ }
+ }
+ notify_property_list_changed();
+}
+
+void Curve3D::_add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) {
Point n;
n.position = p_position;
n.in = p_in;
@@ -1037,16 +1234,19 @@ void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Ve
points.push_back(n);
}
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
+}
+
+void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) {
+ _add_point(p_position, p_in, p_out, p_atpos);
+ notify_property_list_changed();
}
void Curve3D::set_point_position(int p_index, const Vector3 &p_position) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].position = p_position;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
Vector3 Curve3D::get_point_position(int p_index) const {
@@ -1058,8 +1258,7 @@ void Curve3D::set_point_tilt(int p_index, real_t p_tilt) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].tilt = p_tilt;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
real_t Curve3D::get_point_tilt(int p_index) const {
@@ -1071,8 +1270,7 @@ void Curve3D::set_point_in(int p_index, const Vector3 &p_in) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].in = p_in;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
Vector3 Curve3D::get_point_in(int p_index) const {
@@ -1084,8 +1282,7 @@ void Curve3D::set_point_out(int p_index, const Vector3 &p_out) {
ERR_FAIL_INDEX(p_index, points.size());
points.write[p_index].out = p_out;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
Vector3 Curve3D::get_point_out(int p_index) const {
@@ -1093,18 +1290,22 @@ Vector3 Curve3D::get_point_out(int p_index) const {
return points[p_index].out;
}
-void Curve3D::remove_point(int p_index) {
+void Curve3D::_remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, points.size());
points.remove_at(p_index);
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
+}
+
+void Curve3D::remove_point(int p_index) {
+ _remove_point(p_index);
+ notify_property_list_changed();
}
void Curve3D::clear_points() {
if (!points.is_empty()) {
points.clear();
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
+ notify_property_list_changed();
}
}
@@ -1123,7 +1324,7 @@ Vector3 Curve3D::interpolate(int p_index, real_t p_offset) const {
Vector3 p3 = points[p_index + 1].position;
Vector3 p2 = p3 + points[p_index + 1].in;
- return _bezier_interp(p_offset, p0, p1, p2, p3);
+ return p0.bezier_interpolate(p1, p2, p3, p_offset);
}
Vector3 Curve3D::interpolatef(real_t p_findex) const {
@@ -1136,11 +1337,16 @@ Vector3 Curve3D::interpolatef(real_t p_findex) const {
return interpolate((int)p_findex, Math::fmod(p_findex, (real_t)1.0));
}
-void Curve3D::_bake_segment3d(Map<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
+void Curve3D::mark_dirty() {
+ baked_cache_dirty = true;
+ emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+void Curve3D::_bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
real_t mp = p_begin + (p_end - p_begin) * 0.5;
- Vector3 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector3 mid = _bezier_interp(mp, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector3 end = _bezier_interp(p_end, p_a, p_a + p_out, p_b + p_in, p_b);
+ Vector3 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin);
+ Vector3 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp);
+ Vector3 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end);
Vector3 na = (mid - beg).normalized();
Vector3 nb = (end - mid).normalized();
@@ -1194,6 +1400,7 @@ void Curve3D::_bake() const {
List<Plane> pointlist;
List<real_t> distlist;
+ // Start always from origin.
pointlist.push_back(Plane(position, points[0].tilt));
distlist.push_back(0.0);
@@ -1207,7 +1414,7 @@ void Curve3D::_bake() const {
np = 1.0;
}
- Vector3 npp = _bezier_interp(np, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+ Vector3 npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, np);
real_t d = position.distance_to(npp);
if (d > bake_interval) {
@@ -1220,7 +1427,7 @@ void Curve3D::_bake() const {
real_t mid = low + (hi - low) * 0.5;
for (int j = 0; j < iterations; j++) {
- npp = _bezier_interp(mid, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+ npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, mid);
d = position.distance_to(npp);
if (bake_interval < d) {
@@ -1244,16 +1451,22 @@ void Curve3D::_bake() const {
p = np;
}
}
- }
- Vector3 lastpos = points[points.size() - 1].position;
- real_t lastilt = points[points.size() - 1].tilt;
+ Vector3 npp = points[i + 1].position;
+ real_t d = position.distance_to(npp);
+
+ position = npp;
+ Plane post;
+ post.normal = position;
+ post.d = points[i + 1].tilt;
+
+ dist += d;
+
+ pointlist.push_back(post);
+ distlist.push_back(dist);
+ }
- real_t rem = position.distance_to(lastpos);
- dist += rem;
baked_max_ofs = dist;
- pointlist.push_back(Plane(lastpos, lastilt));
- distlist.push_back(dist);
baked_point_cache.resize(pointlist.size());
Vector3 *w = baked_point_cache.ptrw();
@@ -1328,7 +1541,7 @@ Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked points.
int pc = baked_point_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, Vector3(), "No points in Curve3D.");
@@ -1336,18 +1549,19 @@ Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const {
return baked_point_cache.get(0);
}
- int bpc = baked_point_cache.size();
const Vector3 *r = baked_point_cache.ptr();
if (p_offset < 0) {
return r[0];
}
if (p_offset >= baked_max_ofs) {
- return r[bpc - 1];
+ return r[pc - 1];
}
- int start = 0, end = bpc, idx = (end + start) / 2;
- // binary search to find baked points
+ int start = 0;
+ int end = pc;
+ int idx = (end + start) / 2;
+ // Binary search to find baked points.
while (start < idx) {
real_t offset = baked_dist_cache[idx];
if (p_offset <= offset) {
@@ -1368,7 +1582,7 @@ Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const {
if (p_cubic) {
Vector3 pre = idx > 0 ? r[idx - 1] : r[idx];
- Vector3 post = (idx < (bpc - 2)) ? r[idx + 2] : r[idx + 1];
+ Vector3 post = (idx < (pc - 2)) ? r[idx + 2] : r[idx + 1];
return r[idx].cubic_interpolate(r[idx + 1], pre, post, frac);
} else {
return r[idx].lerp(r[idx + 1], frac);
@@ -1380,7 +1594,7 @@ real_t Curve3D::interpolate_baked_tilt(real_t p_offset) const {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked tilts.
int pc = baked_tilt_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, 0, "No tilts in Curve3D.");
@@ -1388,29 +1602,37 @@ real_t Curve3D::interpolate_baked_tilt(real_t p_offset) const {
return baked_tilt_cache.get(0);
}
- int bpc = baked_tilt_cache.size();
const real_t *r = baked_tilt_cache.ptr();
if (p_offset < 0) {
return r[0];
}
if (p_offset >= baked_max_ofs) {
- return r[bpc - 1];
+ return r[pc - 1];
}
- int idx = Math::floor((double)p_offset / (double)bake_interval);
- real_t frac = Math::fmod(p_offset, bake_interval);
-
- if (idx >= bpc - 1) {
- return r[bpc - 1];
- } else if (idx == bpc - 2) {
- if (frac > 0) {
- frac /= Math::fmod(baked_max_ofs, bake_interval);
+ int start = 0;
+ int end = pc;
+ int idx = (end + start) / 2;
+ // Binary search to find baked points.
+ while (start < idx) {
+ real_t offset = baked_dist_cache[idx];
+ if (p_offset <= offset) {
+ end = idx;
+ } else {
+ start = idx;
}
- } else {
- frac /= bake_interval;
+ idx = (end + start) / 2;
}
+ real_t offset_begin = baked_dist_cache[idx];
+ real_t offset_end = baked_dist_cache[idx + 1];
+
+ real_t idx_interval = offset_end - offset_begin;
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, 0, "failed to find baked segment");
+
+ real_t frac = (p_offset - offset_begin) / idx_interval;
+
return Math::lerp(r[idx], r[idx + 1], (real_t)frac);
}
@@ -1419,8 +1641,7 @@ Vector3 Curve3D::interpolate_baked_up_vector(real_t p_offset, bool p_apply_tilt)
_bake();
}
- //validate//
- // curve may not have baked up vectors
+ // Validate: Curve may not have baked up vectors.
int count = baked_up_vector_cache.size();
ERR_FAIL_COND_V_MSG(count == 0, Vector3(0, 1, 0), "No up vectors in Curve3D.");
@@ -1432,10 +1653,27 @@ Vector3 Curve3D::interpolate_baked_up_vector(real_t p_offset, bool p_apply_tilt)
const Vector3 *rp = baked_point_cache.ptr();
const real_t *rt = baked_tilt_cache.ptr();
- real_t offset = CLAMP(p_offset, 0.0f, baked_max_ofs);
+ int start = 0;
+ int end = count;
+ int idx = (end + start) / 2;
+ // Binary search to find baked points.
+ while (start < idx) {
+ real_t offset = baked_dist_cache[idx];
+ if (p_offset <= offset) {
+ end = idx;
+ } else {
+ start = idx;
+ }
+ idx = (end + start) / 2;
+ }
+
+ real_t offset_begin = baked_dist_cache[idx];
+ real_t offset_end = baked_dist_cache[idx + 1];
+
+ real_t idx_interval = offset_end - offset_begin;
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(0, 1, 0), "failed to find baked segment");
- int idx = Math::floor((double)offset / (double)bake_interval);
- real_t frac = Math::fmod(offset, bake_interval) / bake_interval;
+ real_t frac = (p_offset - offset_begin) / idx_interval;
if (idx == count - 1) {
return p_apply_tilt ? r[idx].rotated((rp[idx] - rp[idx - 1]).normalized(), rt[idx]) : r[idx];
@@ -1486,13 +1724,13 @@ PackedVector3Array Curve3D::get_baked_up_vectors() const {
}
Vector3 Curve3D::get_closest_point(const Vector3 &p_to_point) const {
- // Brute force method
+ // Brute force method.
if (baked_cache_dirty) {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked points.
int pc = baked_point_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, Vector3(), "No points in Curve3D.");
@@ -1524,13 +1762,13 @@ Vector3 Curve3D::get_closest_point(const Vector3 &p_to_point) const {
}
real_t Curve3D::get_closest_offset(const Vector3 &p_to_point) const {
- // Brute force method
+ // Brute force method.
if (baked_cache_dirty) {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked points.
int pc = baked_point_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, 0.0f, "No points in Curve3D.");
@@ -1566,8 +1804,7 @@ real_t Curve3D::get_closest_offset(const Vector3 &p_to_point) const {
void Curve3D::set_bake_interval(real_t p_tolerance) {
bake_interval = p_tolerance;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
real_t Curve3D::get_bake_interval() const {
@@ -1576,8 +1813,7 @@ real_t Curve3D::get_bake_interval() const {
void Curve3D::set_up_vector_enabled(bool p_enable) {
up_vector_enabled = p_enable;
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
bool Curve3D::is_up_vector_enabled() const {
@@ -1626,7 +1862,8 @@ void Curve3D::_set_data(const Dictionary &p_data) {
points.write[i].tilt = rt[i];
}
- baked_cache_dirty = true;
+ mark_dirty();
+ notify_property_list_changed();
}
PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) const {
@@ -1635,7 +1872,7 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) con
if (points.size() == 0) {
return tess;
}
- Vector<Map<real_t, Vector3>> midpoints;
+ Vector<RBMap<real_t, Vector3>> midpoints;
midpoints.resize(points.size() - 1);
@@ -1664,8 +1901,77 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) con
return tess;
}
+bool Curve3D::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
+ int point_index = components[0].trim_prefix("point_").to_int();
+ String property = components[1];
+ if (property == "position") {
+ set_point_position(point_index, p_value);
+ return true;
+ } else if (property == "in") {
+ set_point_in(point_index, p_value);
+ return true;
+ } else if (property == "out") {
+ set_point_out(point_index, p_value);
+ return true;
+ } else if (property == "tilt") {
+ set_point_tilt(point_index, p_value);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Curve3D::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
+ int point_index = components[0].trim_prefix("point_").to_int();
+ String property = components[1];
+ if (property == "position") {
+ r_ret = get_point_position(point_index);
+ return true;
+ } else if (property == "in") {
+ r_ret = get_point_in(point_index);
+ return true;
+ } else if (property == "out") {
+ r_ret = get_point_out(point_index);
+ return true;
+ } else if (property == "tilt") {
+ r_ret = get_point_tilt(point_index);
+ return true;
+ }
+ }
+ return false;
+}
+
+void Curve3D::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < points.size(); i++) {
+ PropertyInfo pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/position", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+
+ if (i != 0) {
+ pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/in", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+
+ if (i != points.size() - 1) {
+ pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/out", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+
+ pi = PropertyInfo(Variant::FLOAT, vformat("point_%d/tilt", i));
+ pi.usage &= ~PROPERTY_USAGE_STORAGE;
+ p_list->push_back(pi);
+ }
+}
+
void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Curve3D::get_point_count);
+ ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve3D::set_point_count);
ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "at_position"), &Curve3D::add_point, DEFVAL(Vector3()), DEFVAL(Vector3()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve3D::set_point_position);
ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve3D::get_point_position);
@@ -1700,13 +2006,10 @@ void Curve3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
+ ADD_ARRAY_COUNT("Points", "point_count", "set_point_count", "get_point_count", "point_");
ADD_GROUP("Up Vector", "up_vector_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "up_vector_enabled"), "set_up_vector_enabled", "is_up_vector_enabled");
}
-Curve3D::Curve3D() {
- /* add_point(Vector3(-1,0,0));
- add_point(Vector3(0,2,0));
- add_point(Vector3(0,3,5));*/
-}
+Curve3D::Curve3D() {}
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index 767900b843..08807b1b6e 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -76,12 +76,13 @@ public:
int get_point_count() const { return _points.size(); }
+ void set_point_count(int p_count);
+
int add_point(Vector2 p_position,
real_t left_tangent = 0,
real_t right_tangent = 0,
TangentMode left_mode = TANGENT_FREE,
TangentMode right_mode = TANGENT_FREE);
-
void remove_point(int p_index);
void clear_points();
@@ -126,11 +127,21 @@ public:
void ensure_default_setup(real_t p_min, real_t p_max);
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
protected:
static void _bind_methods();
private:
void mark_dirty();
+ int _add_point(Vector2 p_position,
+ real_t left_tangent = 0,
+ real_t right_tangent = 0,
+ TangentMode left_mode = TANGENT_FREE,
+ TangentMode right_mode = TANGENT_FREE);
+ void _remove_point(int p_index);
Vector<Point> _points;
bool _baked_cache_dirty = false;
@@ -164,19 +175,29 @@ class Curve2D : public Resource {
mutable Vector<real_t> baked_dist_cache;
mutable real_t baked_max_ofs = 0.0;
+ void mark_dirty();
+
void _bake() const;
real_t bake_interval = 5.0;
- void _bake_segment2d(Map<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const;
+ void _bake_segment2d(RBMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const;
Dictionary _get_data() const;
void _set_data(const Dictionary &p_data);
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ void _add_point(const Vector2 &p_position, const Vector2 &p_in = Vector2(), const Vector2 &p_out = Vector2(), int p_atpos = -1);
+ void _remove_point(int p_index);
+
protected:
static void _bind_methods();
public:
int get_point_count() const;
+ void set_point_count(int p_count);
void add_point(const Vector2 &p_position, const Vector2 &p_in = Vector2(), const Vector2 &p_out = Vector2(), int p_atpos = -1);
void set_point_position(int p_index, const Vector2 &p_position);
Vector2 get_point_position(int p_index) const;
@@ -228,20 +249,30 @@ class Curve3D : public Resource {
mutable Vector<real_t> baked_dist_cache;
mutable real_t baked_max_ofs = 0.0;
+ void mark_dirty();
+
void _bake() const;
real_t bake_interval = 0.2;
bool up_vector_enabled = true;
- void _bake_segment3d(Map<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const;
+ void _bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const;
Dictionary _get_data() const;
void _set_data(const Dictionary &p_data);
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ void _add_point(const Vector3 &p_position, const Vector3 &p_in = Vector3(), const Vector3 &p_out = Vector3(), int p_atpos = -1);
+ void _remove_point(int p_index);
+
protected:
static void _bind_methods();
public:
int get_point_count() const;
+ void set_point_count(int p_count);
void add_point(const Vector3 &p_position, const Vector3 &p_in = Vector3(), const Vector3 &p_out = Vector3(), int p_atpos = -1);
void set_point_position(int p_index, const Vector3 &p_position);
Vector3 get_point_position(int p_index) const;
diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp
index a1fe5c46fb..345df5ffed 100644
--- a/scene/resources/cylinder_shape_3d.cpp
+++ b/scene/resources/cylinder_shape_3d.cpp
@@ -100,8 +100,8 @@ void CylinderShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderShape3D::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &CylinderShape3D::get_height);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_height", "get_height");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
}
CylinderShape3D::CylinderShape3D() :
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 69b8355497..520a0a04ed 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -76,7 +76,6 @@ static Ref<StyleBoxFlat> sb_expand(Ref<StyleBoxFlat> p_sbox, float p_left, float
// See also `editor_generate_icon()` in `editor/editor_themes.cpp`.
static Ref<ImageTexture> generate_icon(int p_index) {
- Ref<ImageTexture> icon = memnew(ImageTexture);
Ref<Image> img = memnew(Image);
#ifdef MODULE_SVG_ENABLED
@@ -87,9 +86,8 @@ static Ref<ImageTexture> generate_icon(int p_index) {
ImageLoaderSVG img_loader;
img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, false);
#endif
- icon->create_from_image(img);
- return icon;
+ return ImageTexture::create_from_image(img);
}
static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
@@ -177,7 +175,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("icon_focus_color", "Button", Color(1, 1, 1, 1));
theme->set_color("icon_disabled_color", "Button", Color(1, 1, 1, 0.4));
- theme->set_constant("hseparation", "Button", 2 * scale);
+ theme->set_constant("h_separation", "Button", 2 * scale);
// LinkButton
@@ -230,7 +228,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_disabled_color", "OptionButton", control_font_disabled_color);
theme->set_color("font_outline_color", "OptionButton", Color(1, 1, 1));
- theme->set_constant("hseparation", "OptionButton", 2 * scale);
+ theme->set_constant("h_separation", "OptionButton", 2 * scale);
theme->set_constant("arrow_margin", "OptionButton", 4 * scale);
theme->set_constant("outline_size", "OptionButton", 0);
@@ -252,7 +250,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_disabled_color", "MenuButton", Color(1, 1, 1, 0.3));
theme->set_color("font_outline_color", "MenuButton", Color(1, 1, 1));
- theme->set_constant("hseparation", "MenuButton", 3 * scale);
+ theme->set_constant("h_separation", "MenuButton", 3 * scale);
theme->set_constant("outline_size", "MenuButton", 0);
// CheckBox
@@ -295,8 +293,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_disabled_color", "CheckBox", control_font_disabled_color);
theme->set_color("font_outline_color", "CheckBox", Color(1, 1, 1));
- theme->set_constant("hseparation", "CheckBox", 4 * scale);
- theme->set_constant("check_vadjust", "CheckBox", 0 * scale);
+ theme->set_constant("h_separation", "CheckBox", 4 * scale);
+ theme->set_constant("check_v_adjust", "CheckBox", 0 * scale);
theme->set_constant("outline_size", "CheckBox", 0);
// CheckButton
@@ -335,8 +333,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_disabled_color", "CheckButton", control_font_disabled_color);
theme->set_color("font_outline_color", "CheckButton", Color(1, 1, 1));
- theme->set_constant("hseparation", "CheckButton", 4 * scale);
- theme->set_constant("check_vadjust", "CheckButton", 0 * scale);
+ theme->set_constant("h_separation", "CheckButton", 4 * scale);
+ theme->set_constant("check_v_adjust", "CheckButton", 0 * scale);
theme->set_constant("outline_size", "CheckButton", 0);
// Label
@@ -467,6 +465,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("completion_selected_color", "CodeEdit", Color(0.26, 0.26, 0.27));
theme->set_color("completion_existing_color", "CodeEdit", Color(0.87, 0.87, 0.87, 0.13));
theme->set_color("completion_scroll_color", "CodeEdit", control_font_pressed_color * Color(1, 1, 1, 0.29));
+ theme->set_color("completion_scroll_hovered_color", "CodeEdit", control_font_pressed_color * Color(1, 1, 1, 0.4));
theme->set_color("completion_font_color", "CodeEdit", Color(0.67, 0.67, 0.67));
theme->set_color("font_color", "CodeEdit", control_font_color);
theme->set_color("font_selected_color", "CodeEdit", Color(0, 0, 0));
@@ -570,7 +569,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Window
theme->set_stylebox("embedded_border", "Window", sb_expand(make_flat_stylebox(style_popup_color, 10, 28, 10, 8), 8, 32, 8, 6));
- theme->set_constant("scaleborder_size", "Window", 4 * scale);
theme->set_font("title_font", "Window", Ref<Font>());
theme->set_font_size("title_font_size", "Window", -1);
@@ -582,8 +580,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("close", "Window", icons["close"]);
theme->set_icon("close_pressed", "Window", icons["close_hl"]);
- theme->set_constant("close_h_ofs", "Window", 18 * scale);
- theme->set_constant("close_v_ofs", "Window", 24 * scale);
+ theme->set_constant("close_h_offset", "Window", 18 * scale);
+ theme->set_constant("close_v_offset", "Window", 24 * scale);
// Dialogs
@@ -605,7 +603,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("file", "FileDialog", icons["file"]);
theme->set_color("folder_icon_modulate", "FileDialog", Color(1, 1, 1));
theme->set_color("file_icon_modulate", "FileDialog", Color(1, 1, 1));
- theme->set_color("files_disabled", "FileDialog", Color(0, 0, 0, 0.7));
+ theme->set_color("files_disabled", "FileDialog", Color(1, 1, 1, 0.25));
// Popup
@@ -665,8 +663,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "PopupMenu", Color(1, 1, 1));
theme->set_color("font_separator_outline_color", "PopupMenu", Color(1, 1, 1));
- theme->set_constant("hseparation", "PopupMenu", 4 * scale);
- theme->set_constant("vseparation", "PopupMenu", 4 * scale);
+ theme->set_constant("h_separation", "PopupMenu", 4 * scale);
+ theme->set_constant("v_separation", "PopupMenu", 4 * scale);
theme->set_constant("outline_size", "PopupMenu", 0);
theme->set_constant("separator_outline_size", "PopupMenu", 0);
theme->set_constant("item_start_padding", "PopupMenu", 2 * scale);
@@ -686,13 +684,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
graphnode_breakpoint->set_border_color(Color(0.9, 0.29, 0.3));
Ref<StyleBoxFlat> graphnode_position = make_flat_stylebox(style_pressed_color, 18, 42, 18, 12, 6, true, 4);
graphnode_position->set_border_color(Color(0.98, 0.89, 0.27));
+ Ref<StyleBoxEmpty> graphnode_slot = make_empty_stylebox(0, 0, 0, 0);
theme->set_stylebox("frame", "GraphNode", graphnode_normal);
- theme->set_stylebox("selectedframe", "GraphNode", graphnode_selected);
+ theme->set_stylebox("selected_frame", "GraphNode", graphnode_selected);
theme->set_stylebox("comment", "GraphNode", graphnode_comment_normal);
- theme->set_stylebox("commentfocus", "GraphNode", graphnode_comment_selected);
+ theme->set_stylebox("comment_focus", "GraphNode", graphnode_comment_selected);
theme->set_stylebox("breakpoint", "GraphNode", graphnode_breakpoint);
theme->set_stylebox("position", "GraphNode", graphnode_position);
+ theme->set_stylebox("slot", "GraphNode", graphnode_slot);
theme->set_icon("port", "GraphNode", icons["graph_port"]);
theme->set_icon("close", "GraphNode", icons["close"]);
@@ -704,6 +704,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("separation", "GraphNode", 2 * scale);
theme->set_constant("title_offset", "GraphNode", 26 * scale);
theme->set_constant("close_offset", "GraphNode", 22 * scale);
+ theme->set_constant("close_h_offset", "GraphNode", 22 * scale);
theme->set_constant("port_offset", "GraphNode", 0);
// Tree
@@ -746,8 +747,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("children_hl_line_color", "Tree", Color(0.27, 0.27, 0.27));
theme->set_color("custom_button_font_highlight", "Tree", control_font_hover_color);
- theme->set_constant("hseparation", "Tree", 4 * scale);
- theme->set_constant("vseparation", "Tree", 4 * scale);
+ theme->set_constant("h_separation", "Tree", 4 * scale);
+ theme->set_constant("v_separation", "Tree", 4 * scale);
theme->set_constant("item_margin", "Tree", 16 * scale);
theme->set_constant("button_margin", "Tree", 4 * scale);
theme->set_constant("draw_relationship_lines", "Tree", 0);
@@ -764,8 +765,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("bg", "ItemList", make_flat_stylebox(style_normal_color));
theme->set_stylebox("bg_focus", "ItemList", focus);
- theme->set_constant("hseparation", "ItemList", 4);
- theme->set_constant("vseparation", "ItemList", 2);
+ theme->set_constant("h_separation", "ItemList", 4);
+ theme->set_constant("v_separation", "ItemList", 2);
theme->set_constant("icon_margin", "ItemList", 4);
theme->set_constant("line_separation", "ItemList", 2 * scale);
@@ -846,7 +847,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "TabBar", Color(1, 1, 1));
theme->set_color("drop_mark_color", "TabBar", Color(1, 1, 1));
- theme->set_constant("hseparation", "TabBar", 4 * scale);
+ theme->set_constant("h_separation", "TabBar", 4 * scale);
theme->set_constant("outline_size", "TabBar", 0);
// Separators
@@ -896,7 +897,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_disabled_color", "ColorPickerButton", Color(0.9, 0.9, 0.9, 0.3));
theme->set_color("font_outline_color", "ColorPickerButton", Color(1, 1, 1));
- theme->set_constant("hseparation", "ColorPickerButton", 2 * scale);
+ theme->set_constant("h_separation", "ColorPickerButton", 2 * scale);
theme->set_constant("outline_size", "ColorPickerButton", 0);
// ColorPresetButton
@@ -915,8 +916,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("panel", "TooltipPanel",
make_flat_stylebox(Color(0, 0, 0, 0.5), 2 * default_margin, 0.5 * default_margin, 2 * default_margin, 0.5 * default_margin));
- theme->set_font("font", "TooltipLabel", Ref<Font>());
theme->set_font_size("font_size", "TooltipLabel", -1);
+ theme->set_font("font", "TooltipLabel", Ref<Font>());
theme->set_color("font_color", "TooltipLabel", control_font_color);
theme->set_color("font_shadow_color", "TooltipLabel", Color(0, 0, 0, 0));
@@ -936,7 +937,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_font("italics_font", "RichTextLabel", italics_font);
theme->set_font("bold_italics_font", "RichTextLabel", bold_italics_font);
theme->set_font("mono_font", "RichTextLabel", Ref<Font>());
-
theme->set_font_size("normal_font_size", "RichTextLabel", -1);
theme->set_font_size("bold_font_size", "RichTextLabel", -1);
theme->set_font_size("italics_font_size", "RichTextLabel", -1);
@@ -956,8 +956,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("shadow_outline_size", "RichTextLabel", 1 * scale);
theme->set_constant("line_separation", "RichTextLabel", 0 * scale);
- theme->set_constant("table_hseparation", "RichTextLabel", 3 * scale);
- theme->set_constant("table_vseparation", "RichTextLabel", 3 * scale);
+ theme->set_constant("table_h_separation", "RichTextLabel", 3 * scale);
+ theme->set_constant("table_v_separation", "RichTextLabel", 3 * scale);
theme->set_constant("outline_size", "RichTextLabel", 0);
@@ -976,16 +976,16 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("margin_top", "MarginContainer", 0 * scale);
theme->set_constant("margin_right", "MarginContainer", 0 * scale);
theme->set_constant("margin_bottom", "MarginContainer", 0 * scale);
- theme->set_constant("hseparation", "GridContainer", 4 * scale);
- theme->set_constant("vseparation", "GridContainer", 4 * scale);
+ theme->set_constant("h_separation", "GridContainer", 4 * scale);
+ theme->set_constant("v_separation", "GridContainer", 4 * scale);
theme->set_constant("separation", "HSplitContainer", 12 * scale);
theme->set_constant("separation", "VSplitContainer", 12 * scale);
theme->set_constant("autohide", "HSplitContainer", 1 * scale);
theme->set_constant("autohide", "VSplitContainer", 1 * scale);
- theme->set_constant("hseparation", "HFlowContainer", 4 * scale);
- theme->set_constant("vseparation", "HFlowContainer", 4 * scale);
- theme->set_constant("hseparation", "VFlowContainer", 4 * scale);
- theme->set_constant("vseparation", "VFlowContainer", 4 * scale);
+ theme->set_constant("h_separation", "HFlowContainer", 4 * scale);
+ theme->set_constant("v_separation", "HFlowContainer", 4 * scale);
+ theme->set_constant("h_separation", "VFlowContainer", 4 * scale);
+ theme->set_constant("v_separation", "VFlowContainer", 4 * scale);
theme->set_stylebox("panel", "PanelContainer", make_flat_stylebox(style_normal_color, 0, 0, 0, 0));
@@ -1001,13 +1001,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("selection_fill", "GraphEdit", Color(1, 1, 1, 0.3));
theme->set_color("selection_stroke", "GraphEdit", Color(1, 1, 1, 0.8));
theme->set_color("activity", "GraphEdit", Color(1, 1, 1));
- theme->set_constant("bezier_len_pos", "GraphEdit", 80 * scale);
- theme->set_constant("bezier_len_neg", "GraphEdit", 160 * scale);
// Visual Node Ports
- theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 24 * scale);
- theme->set_constant("port_grab_distance_vertical", "GraphEdit", 26 * scale);
+ theme->set_constant("port_hotzone_inner_extent", "GraphEdit", 22 * scale);
+ theme->set_constant("port_hotzone_outer_extent", "GraphEdit", 26 * scale);
theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0));
Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0, 0);
@@ -1026,16 +1024,16 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
default_style = make_flat_stylebox(Color(1, 0.365, 0.365), 4, 4, 4, 4, 0, false, 2);
}
-void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_subpixel, TextServer::Hinting p_hinting, bool p_aa) {
+void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_font_subpixel, TextServer::Hinting p_font_hinting, bool p_font_antialiased, bool p_font_msdf, bool p_font_generate_mipmaps) {
Ref<Theme> t;
t.instantiate();
Ref<StyleBox> default_style;
Ref<Texture2D> default_icon;
Ref<Font> default_font;
- Ref<Font> bold_font;
- Ref<Font> bold_italics_font;
- Ref<Font> italics_font;
+ Ref<FontVariation> bold_font;
+ Ref<FontVariation> bold_italics_font;
+ Ref<FontVariation> italics_font;
float default_scale = CLAMP(p_scale, 0.5, 8.0);
if (p_font.is_valid()) {
@@ -1045,42 +1043,31 @@ void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPos
// Use the default DynamicFont (separate from the editor font).
// The default DynamicFont is chosen to have a small file size since it's
// embedded in both editor and export template binaries.
- Ref<Font> dynamic_font;
+ Ref<FontFile> dynamic_font;
dynamic_font.instantiate();
-
- Ref<FontData> dynamic_font_data;
- dynamic_font_data.instantiate();
- dynamic_font_data->set_data_ptr(_font_OpenSans_SemiBold, _font_OpenSans_SemiBold_size);
- dynamic_font_data->set_subpixel_positioning(p_subpixel);
- dynamic_font_data->set_hinting(p_hinting);
- dynamic_font_data->set_antialiased(p_aa);
- dynamic_font->add_data(dynamic_font_data);
+ dynamic_font->set_data_ptr(_font_OpenSans_SemiBold, _font_OpenSans_SemiBold_size);
+ dynamic_font->set_subpixel_positioning(p_font_subpixel);
+ dynamic_font->set_hinting(p_font_hinting);
+ dynamic_font->set_antialiased(p_font_antialiased);
+ dynamic_font->set_multichannel_signed_distance_field(p_font_msdf);
+ dynamic_font->set_generate_mipmaps(p_font_generate_mipmaps);
default_font = dynamic_font;
}
if (default_font.is_valid()) {
bold_font.instantiate();
- for (int i = 0; i < default_font->get_data_count(); i++) {
- Ref<FontData> data = default_font->get_data(i)->duplicate();
- data->set_embolden(1.2);
- bold_font->add_data(data);
- }
+ bold_font->set_base_font(default_font);
+ bold_font->set_variation_embolden(1.2);
bold_italics_font.instantiate();
- for (int i = 0; i < default_font->get_data_count(); i++) {
- Ref<FontData> data = default_font->get_data(i)->duplicate();
- data->set_embolden(1.2);
- data->set_transform(Transform2D(1.0, 0.4, 0.0, 1.0, 0.0, 0.0));
- bold_italics_font->add_data(data);
- }
+ bold_italics_font->set_base_font(default_font);
+ bold_italics_font->set_variation_embolden(1.2);
+ bold_italics_font->set_variation_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
italics_font.instantiate();
- for (int i = 0; i < default_font->get_data_count(); i++) {
- Ref<FontData> data = default_font->get_data(i)->duplicate();
- data->set_transform(Transform2D(1.0, 0.4, 0.0, 1.0, 0.0, 0.0));
- italics_font->add_data(data);
- }
+ italics_font->set_base_font(default_font);
+ italics_font->set_variation_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
}
fill_default_theme(t, default_font, bold_font, bold_italics_font, italics_font, default_icon, default_style, default_scale);
diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h
index a9e21dda3f..f777330a07 100644
--- a/scene/resources/default_theme/default_theme.h
+++ b/scene/resources/default_theme/default_theme.h
@@ -36,7 +36,7 @@
const int default_font_size = 16;
void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &bold_font, const Ref<Font> &bold_italics_font, const Ref<Font> &italics_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale);
-void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_subpixel, TextServer::Hinting p_hinting, bool p_aa);
+void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_font_subpixel = TextServer::SUBPIXEL_POSITIONING_AUTO, TextServer::Hinting p_font_hinting = TextServer::HINTING_LIGHT, bool p_font_antialiased = true, bool p_font_msdf = false, bool p_font_generate_mipmaps = false);
void clear_default_theme();
#endif
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index d92d34437e..854bd34d6a 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -1096,7 +1096,6 @@ void Environment::_validate_property(PropertyInfo &property) const {
static const char *high_end_prefixes[] = {
"auto_exposure_",
- "tonemap_",
"ssr_",
"ssao_",
nullptr
@@ -1179,8 +1178,8 @@ void Environment::_bind_methods() {
ADD_GROUP("Sky", "sky_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_sky", "get_sky");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_custom_fov", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_sky_custom_fov", "get_sky_custom_fov");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "sky_rotation"), "set_sky_rotation", "get_sky_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_custom_fov", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), "set_sky_custom_fov", "get_sky_custom_fov");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "sky_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_sky_rotation", "get_sky_rotation");
// Ambient light
@@ -1299,7 +1298,7 @@ void Environment::_bind_methods() {
ADD_GROUP("SSIL", "ssil_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ssil_enabled"), "set_ssil_enabled", "is_ssil_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssil_radius", PROPERTY_HINT_RANGE, "0.01,16,0.01,or_greater"), "set_ssil_radius", "get_ssil_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssil_radius", PROPERTY_HINT_RANGE, "0.01,16,0.01,or_greater,suffix:m"), "set_ssil_radius", "get_ssil_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssil_intensity", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_ssil_intensity", "get_ssil_intensity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssil_sharpness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssil_sharpness", "get_ssil_sharpness");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssil_normal_rejection", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssil_normal_rejection", "get_ssil_normal_rejection");
@@ -1426,7 +1425,7 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_density", PROPERTY_HINT_RANGE, "0,16,0.0001"), "set_fog_density", "get_fog_density");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_aerial_perspective", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_fog_aerial_perspective", "get_fog_aerial_perspective");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_lesser,or_greater"), "set_fog_height", "get_fog_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_lesser,or_greater,suffix:m"), "set_fog_height", "get_fog_height");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_density", PROPERTY_HINT_RANGE, "-16,16,0.0001,or_lesser,or_greater"), "set_fog_height_density", "get_fog_height_density");
ClassDB::bind_method(D_METHOD("set_volumetric_fog_enabled", "enabled"), &Environment::set_volumetric_fog_enabled);
@@ -1467,7 +1466,7 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_ambient_inject", PROPERTY_HINT_RANGE, "0.0,16,0.01,exp"), "set_volumetric_fog_ambient_inject", "get_volumetric_fog_ambient_inject");
ADD_SUBGROUP("Temporal Reprojection", "volumetric_fog_temporal_reprojection_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_temporal_reprojection_enabled"), "set_volumetric_fog_temporal_reprojection_enabled", "is_volumetric_fog_temporal_reprojection_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_temporal_reprojection_amount", PROPERTY_HINT_RANGE, "0.0,0.999,0.001"), "set_volumetric_fog_temporal_reprojection_amount", "get_volumetric_fog_temporal_reprojection_amount");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_temporal_reprojection_amount", PROPERTY_HINT_RANGE, "0.5,0.99,0.001"), "set_volumetric_fog_temporal_reprojection_amount", "get_volumetric_fog_temporal_reprojection_amount");
// Adjustment
diff --git a/scene/resources/fog_material.cpp b/scene/resources/fog_material.cpp
index a05ef0c779..39ade85af6 100644
--- a/scene/resources/fog_material.cpp
+++ b/scene/resources/fog_material.cpp
@@ -148,11 +148,11 @@ void FogMaterial::_update_shader() {
shader_type fog;
uniform float density : hint_range(0, 1, 0.0001) = 1.0;
-uniform vec4 albedo : hint_color = vec4(1.0);
-uniform vec4 emission : hint_color = vec4(0, 0, 0, 1);
+uniform vec4 albedo : source_color = vec4(1.0);
+uniform vec4 emission : source_color = vec4(0, 0, 0, 1);
uniform float height_falloff = 0.0;
uniform float edge_fade = 0.1;
-uniform sampler3D density_texture: hint_white;
+uniform sampler3D density_texture: hint_default_white;
void fog() {
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index efbe9c93f7..f61ac7fcaa 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -30,431 +30,566 @@
#include "font.h"
+#include "core/core_string_names.h"
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "core/string/translation.h"
+#include "core/templates/hash_map.h"
#include "core/templates/hashfuncs.h"
#include "scene/resources/text_line.h"
#include "scene/resources/text_paragraph.h"
+#include "scene/resources/theme.h"
-_FORCE_INLINE_ void FontData::_clear_cache() {
- for (int i = 0; i < cache.size(); i++) {
- if (cache[i].is_valid()) {
- TS->free_rid(cache[i]);
- cache.write[i] = RID();
- }
- }
+/*************************************************************************/
+/* Font */
+/*************************************************************************/
+
+void Font::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_fallbacks", "fallbacks"), &Font::set_fallbacks);
+ ClassDB::bind_method(D_METHOD("get_fallbacks"), &Font::get_fallbacks);
+
+ // Output.
+ ClassDB::bind_method(D_METHOD("find_variation", "variation_coordinates", "face_index", "strength", "transform"), &Font::find_variation, DEFVAL(0), DEFVAL(0.0), DEFVAL(Transform2D()));
+ ClassDB::bind_method(D_METHOD("get_rids"), &Font::get_rids);
+
+ // Font metrics.
+ ClassDB::bind_method(D_METHOD("get_height", "font_size"), &Font::get_height, DEFVAL(DEFAULT_FONT_SIZE));
+ ClassDB::bind_method(D_METHOD("get_ascent", "font_size"), &Font::get_ascent, DEFVAL(DEFAULT_FONT_SIZE));
+ ClassDB::bind_method(D_METHOD("get_descent", "font_size"), &Font::get_descent, DEFVAL(DEFAULT_FONT_SIZE));
+ ClassDB::bind_method(D_METHOD("get_underline_position", "font_size"), &Font::get_underline_position, DEFVAL(DEFAULT_FONT_SIZE));
+ ClassDB::bind_method(D_METHOD("get_underline_thickness", "font_size"), &Font::get_underline_thickness, DEFVAL(DEFAULT_FONT_SIZE));
+
+ ClassDB::bind_method(D_METHOD("get_font_name"), &Font::get_font_name);
+ ClassDB::bind_method(D_METHOD("get_font_style_name"), &Font::get_font_style_name);
+ ClassDB::bind_method(D_METHOD("get_font_style"), &Font::get_font_style);
+
+ ClassDB::bind_method(D_METHOD("get_spacing", "spacing"), &Font::get_spacing);
+ ClassDB::bind_method(D_METHOD("get_opentype_features"), &Font::get_opentype_features);
+
+ // Drawing string.
+ ClassDB::bind_method(D_METHOD("set_cache_capacity", "single_line", "multi_line"), &Font::set_cache_capacity);
+
+ ClassDB::bind_method(D_METHOD("get_string_size", "text", "alignment", "width", "font_size", "jst_flags", "direction", "orientation"), &Font::get_string_size, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
+ ClassDB::bind_method(D_METHOD("get_multiline_string_size", "text", "alignment", "width", "font_size", "max_lines", "brk_flags", "jst_flags", "direction", "orientation"), &Font::get_multiline_string_size, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(-1), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
+
+ ClassDB::bind_method(D_METHOD("draw_string", "canvas_item", "pos", "text", "alignment", "width", "font_size", "modulate", "jst_flags", "direction", "orientation"), &Font::draw_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
+ ClassDB::bind_method(D_METHOD("draw_multiline_string", "canvas_item", "pos", "text", "alignment", "width", "font_size", "max_lines", "modulate", "brk_flags", "jst_flags", "direction", "orientation"), &Font::draw_multiline_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(-1), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
+
+ ClassDB::bind_method(D_METHOD("draw_string_outline", "canvas_item", "pos", "text", "alignment", "width", "font_size", "size", "modulate", "jst_flags", "direction", "orientation"), &Font::draw_string_outline, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(1), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
+ ClassDB::bind_method(D_METHOD("draw_multiline_string_outline", "canvas_item", "pos", "text", "alignment", "width", "font_size", "max_lines", "size", "modulate", "brk_flags", "jst_flags", "direction", "orientation"), &Font::draw_multiline_string_outline, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(-1), DEFVAL(1), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
+
+ // Drawing char.
+ ClassDB::bind_method(D_METHOD("get_char_size", "char"), &Font::get_char_size);
+ ClassDB::bind_method(D_METHOD("draw_char", "canvas_item", "pos", "char", "modulate"), &Font::draw_char, DEFVAL(Color(1.0, 1.0, 1.0)));
+ ClassDB::bind_method(D_METHOD("draw_char_outline", "canvas_item", "pos", "char", "size", "modulate"), &Font::draw_char_outline, DEFVAL(-1), DEFVAL(Color(1.0, 1.0, 1.0)));
+
+ // Helper functions.
+ ClassDB::bind_method(D_METHOD("has_char", "char"), &Font::has_char);
+ ClassDB::bind_method(D_METHOD("get_supported_chars"), &Font::get_supported_chars);
+
+ ClassDB::bind_method(D_METHOD("is_language_supported", "language"), &Font::is_language_supported);
+ ClassDB::bind_method(D_METHOD("is_script_supported", "script"), &Font::is_script_supported);
+
+ ClassDB::bind_method(D_METHOD("get_supported_feature_list"), &Font::get_supported_feature_list);
+ ClassDB::bind_method(D_METHOD("get_supported_variation_list"), &Font::get_supported_variation_list);
+ ClassDB::bind_method(D_METHOD("get_face_count"), &Font::get_face_count);
}
-_FORCE_INLINE_ void FontData::_ensure_rid(int p_cache_index) const {
- if (unlikely(p_cache_index >= cache.size())) {
- cache.resize(p_cache_index + 1);
- }
- if (unlikely(!cache[p_cache_index].is_valid())) {
- cache.write[p_cache_index] = TS->create_font();
- TS->font_set_data_ptr(cache[p_cache_index], data_ptr, data_size);
- TS->font_set_antialiased(cache[p_cache_index], antialiased);
- TS->font_set_multichannel_signed_distance_field(cache[p_cache_index], msdf);
- TS->font_set_msdf_pixel_range(cache[p_cache_index], msdf_pixel_range);
- TS->font_set_msdf_size(cache[p_cache_index], msdf_size);
- TS->font_set_fixed_size(cache[p_cache_index], fixed_size);
- TS->font_set_force_autohinter(cache[p_cache_index], force_autohinter);
- TS->font_set_hinting(cache[p_cache_index], hinting);
- TS->font_set_subpixel_positioning(cache[p_cache_index], subpixel_positioning);
- TS->font_set_embolden(cache[p_cache_index], embolden);
- TS->font_set_transform(cache[p_cache_index], transform);
- TS->font_set_oversampling(cache[p_cache_index], oversampling);
+void Font::_update_rids_fb(const Ref<Font> &p_f, int p_depth) const {
+ ERR_FAIL_COND(p_depth > MAX_FALLBACK_DEPTH);
+ if (p_f.is_valid()) {
+ RID rid = p_f->_get_rid();
+ if (rid.is_valid()) {
+ rids.push_back(rid);
+ }
+ const TypedArray<Font> &_fallbacks = p_f->get_fallbacks();
+ for (int i = 0; i < _fallbacks.size(); i++) {
+ _update_rids_fb(_fallbacks[i], p_depth + 1);
+ }
}
}
-void FontData::_bind_methods() {
- ClassDB::bind_method(D_METHOD("load_bitmap_font", "path"), &FontData::load_bitmap_font);
- ClassDB::bind_method(D_METHOD("load_dynamic_font", "path"), &FontData::load_dynamic_font);
+void Font::_update_rids() const {
+ rids.clear();
+ _update_rids_fb(const_cast<Font *>(this), 0);
+ dirty_rids = false;
+}
- ClassDB::bind_method(D_METHOD("set_data", "data"), &FontData::set_data);
- ClassDB::bind_method(D_METHOD("get_data"), &FontData::get_data);
+void Font::_invalidate_rids() {
+ rids.clear();
+ dirty_rids = true;
- ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased);
- ClassDB::bind_method(D_METHOD("is_antialiased"), &FontData::is_antialiased);
+ cache.clear();
+ cache_wrap.clear();
- ClassDB::bind_method(D_METHOD("set_font_name", "name"), &FontData::set_font_name);
- ClassDB::bind_method(D_METHOD("get_font_name"), &FontData::get_font_name);
+ emit_changed();
+}
- ClassDB::bind_method(D_METHOD("set_font_style_name", "name"), &FontData::set_font_style_name);
- ClassDB::bind_method(D_METHOD("get_font_style_name"), &FontData::get_font_style_name);
+bool Font::_is_cyclic(const Ref<Font> &p_f, int p_depth) const {
+ ERR_FAIL_COND_V(p_depth > MAX_FALLBACK_DEPTH, false);
+ if (p_f.is_null()) {
+ return false;
+ }
+ for (int i = 0; i < p_f->fallbacks.size(); i++) {
+ const Ref<Font> &f = p_f->fallbacks[i];
+ if (f == this) {
+ return true;
+ }
+ return _is_cyclic(f, p_depth + 1);
+ }
+ return false;
+}
- ClassDB::bind_method(D_METHOD("set_font_style", "style"), &FontData::set_font_style);
- ClassDB::bind_method(D_METHOD("get_font_style"), &FontData::get_font_style);
+void Font::reset_state() {
+ _invalidate_rids();
+}
- ClassDB::bind_method(D_METHOD("set_multichannel_signed_distance_field", "msdf"), &FontData::set_multichannel_signed_distance_field);
- ClassDB::bind_method(D_METHOD("is_multichannel_signed_distance_field"), &FontData::is_multichannel_signed_distance_field);
+// Fallbacks.
+void Font::set_fallbacks(const TypedArray<Font> &p_fallbacks) {
+ ERR_FAIL_COND(_is_cyclic(this, 0));
+ for (int i = 0; i < fallbacks.size(); i++) {
+ Ref<Font> f = fallbacks[i];
+ if (f.is_valid()) {
+ f->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Font::_invalidate_rids));
+ }
+ }
+ fallbacks = p_fallbacks;
+ for (int i = 0; i < fallbacks.size(); i++) {
+ Ref<Font> f = fallbacks[i];
+ if (f.is_valid()) {
+ f->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Font::_invalidate_rids), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ }
+ _invalidate_rids();
+}
- ClassDB::bind_method(D_METHOD("set_msdf_pixel_range", "msdf_pixel_range"), &FontData::set_msdf_pixel_range);
- ClassDB::bind_method(D_METHOD("get_msdf_pixel_range"), &FontData::get_msdf_pixel_range);
+TypedArray<Font> Font::get_fallbacks() const {
+ return fallbacks;
+}
- ClassDB::bind_method(D_METHOD("set_msdf_size", "msdf_size"), &FontData::set_msdf_size);
- ClassDB::bind_method(D_METHOD("get_msdf_size"), &FontData::get_msdf_size);
+// Output.
+TypedArray<RID> Font::get_rids() const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ return rids;
+}
- ClassDB::bind_method(D_METHOD("set_fixed_size", "fixed_size"), &FontData::set_fixed_size);
- ClassDB::bind_method(D_METHOD("get_fixed_size"), &FontData::get_fixed_size);
+// Drawing string.
+real_t Font::get_height(int p_font_size) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ real_t ret = 0.f;
+ for (int i = 0; i < rids.size(); i++) {
+ ret = MAX(ret, TS->font_get_ascent(rids[i], p_font_size) + TS->font_get_descent(rids[i], p_font_size));
+ }
+ return ret + get_spacing(TextServer::SPACING_BOTTOM) + get_spacing(TextServer::SPACING_TOP);
+}
- ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &FontData::set_force_autohinter);
- ClassDB::bind_method(D_METHOD("is_force_autohinter"), &FontData::is_force_autohinter);
+real_t Font::get_ascent(int p_font_size) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ real_t ret = 0.f;
+ for (int i = 0; i < rids.size(); i++) {
+ ret = MAX(ret, TS->font_get_ascent(rids[i], p_font_size));
+ }
+ return ret + get_spacing(TextServer::SPACING_TOP);
+}
- ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &FontData::set_hinting);
- ClassDB::bind_method(D_METHOD("get_hinting"), &FontData::get_hinting);
+real_t Font::get_descent(int p_font_size) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ real_t ret = 0.f;
+ for (int i = 0; i < rids.size(); i++) {
+ ret = MAX(ret, TS->font_get_descent(rids[i], p_font_size));
+ }
+ return ret + get_spacing(TextServer::SPACING_BOTTOM);
+}
- ClassDB::bind_method(D_METHOD("set_subpixel_positioning", "subpixel_positioning"), &FontData::set_subpixel_positioning);
- ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &FontData::get_subpixel_positioning);
+real_t Font::get_underline_position(int p_font_size) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ real_t ret = 0.f;
+ for (int i = 0; i < rids.size(); i++) {
+ ret = MAX(ret, TS->font_get_underline_position(rids[i], p_font_size));
+ }
+ return ret + get_spacing(TextServer::SPACING_TOP);
+}
- ClassDB::bind_method(D_METHOD("set_embolden", "strength"), &FontData::set_embolden);
- ClassDB::bind_method(D_METHOD("get_embolden"), &FontData::get_embolden);
+real_t Font::get_underline_thickness(int p_font_size) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ real_t ret = 0.f;
+ for (int i = 0; i < rids.size(); i++) {
+ ret = MAX(ret, TS->font_get_underline_thickness(rids[i], p_font_size));
+ }
+ return ret;
+}
- ClassDB::bind_method(D_METHOD("set_transform", "transform"), &FontData::set_transform);
- ClassDB::bind_method(D_METHOD("get_transform"), &FontData::get_transform);
+String Font::get_font_name() const {
+ return TS->font_get_name(_get_rid());
+}
- ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &FontData::set_oversampling);
- ClassDB::bind_method(D_METHOD("get_oversampling"), &FontData::get_oversampling);
+String Font::get_font_style_name() const {
+ return TS->font_get_style_name(_get_rid());
+}
- ClassDB::bind_method(D_METHOD("find_cache", "variation_coordinates"), &FontData::find_cache);
+BitField<TextServer::FontStyle> Font::get_font_style() const {
+ return TS->font_get_style(_get_rid());
+}
- ClassDB::bind_method(D_METHOD("get_cache_count"), &FontData::get_cache_count);
- ClassDB::bind_method(D_METHOD("clear_cache"), &FontData::clear_cache);
- ClassDB::bind_method(D_METHOD("remove_cache", "cache_index"), &FontData::remove_cache);
+Dictionary Font::get_opentype_features() const {
+ return Dictionary();
+}
- ClassDB::bind_method(D_METHOD("get_size_cache_list", "cache_index"), &FontData::get_size_cache_list);
- ClassDB::bind_method(D_METHOD("clear_size_cache", "cache_index"), &FontData::clear_size_cache);
- ClassDB::bind_method(D_METHOD("remove_size_cache", "cache_index", "size"), &FontData::remove_size_cache);
+// Drawing string.
+void Font::set_cache_capacity(int p_single_line, int p_multi_line) {
+ cache.set_capacity(p_single_line);
+ cache_wrap.set_capacity(p_multi_line);
+}
- ClassDB::bind_method(D_METHOD("set_variation_coordinates", "cache_index", "variation_coordinates"), &FontData::set_variation_coordinates);
- ClassDB::bind_method(D_METHOD("get_variation_coordinates", "cache_index"), &FontData::get_variation_coordinates);
+Size2 Font::get_string_size(const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+ uint64_t hash = p_text.hash64();
+ hash = hash_djb2_one_64(p_font_size, hash);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
+ hash = hash_djb2_one_64(p_jst_flags.operator uint32_t(), hash);
+ }
+ hash = hash_djb2_one_64(p_direction, hash);
+ hash = hash_djb2_one_64(p_orientation, hash);
- ClassDB::bind_method(D_METHOD("set_ascent", "cache_index", "size", "ascent"), &FontData::set_ascent);
- ClassDB::bind_method(D_METHOD("get_ascent", "cache_index", "size"), &FontData::get_ascent);
+ Ref<TextLine> buffer;
+ if (cache.has(hash)) {
+ buffer = cache.get(hash);
+ } else {
+ buffer.instantiate();
+ buffer->set_direction(p_direction);
+ buffer->set_orientation(p_orientation);
+ buffer->add_string(p_text, Ref<Font>(this), p_font_size);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ buffer->set_horizontal_alignment(p_alignment);
+ buffer->set_width(p_width);
+ buffer->set_flags(p_jst_flags);
+ }
+ cache.insert(hash, buffer);
+ }
+ return buffer->get_size();
+}
- ClassDB::bind_method(D_METHOD("set_descent", "cache_index", "size", "descent"), &FontData::set_descent);
- ClassDB::bind_method(D_METHOD("get_descent", "cache_index", "size"), &FontData::get_descent);
+Size2 Font::get_multiline_string_size(const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+ uint64_t hash = p_text.hash64();
+ hash = hash_djb2_one_64(p_font_size, hash);
+ hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
+ hash = hash_djb2_one_64(p_brk_flags.operator uint32_t(), hash);
+ hash = hash_djb2_one_64(p_jst_flags.operator uint32_t(), hash);
+ hash = hash_djb2_one_64(p_direction, hash);
+ hash = hash_djb2_one_64(p_orientation, hash);
- ClassDB::bind_method(D_METHOD("set_underline_position", "cache_index", "size", "underline_position"), &FontData::set_underline_position);
- ClassDB::bind_method(D_METHOD("get_underline_position", "cache_index", "size"), &FontData::get_underline_position);
+ Ref<TextParagraph> lines_buffer;
+ if (cache_wrap.has(hash)) {
+ lines_buffer = cache_wrap.get(hash);
+ } else {
+ lines_buffer.instantiate();
+ lines_buffer->set_direction(p_direction);
+ lines_buffer->set_orientation(p_orientation);
+ lines_buffer->add_string(p_text, Ref<Font>(this), p_font_size);
+ lines_buffer->set_width(p_width);
+ lines_buffer->set_break_flags(p_brk_flags);
+ lines_buffer->set_justification_flags(p_jst_flags);
+ cache_wrap.insert(hash, lines_buffer);
+ }
- ClassDB::bind_method(D_METHOD("set_underline_thickness", "cache_index", "size", "underline_thickness"), &FontData::set_underline_thickness);
- ClassDB::bind_method(D_METHOD("get_underline_thickness", "cache_index", "size"), &FontData::get_underline_thickness);
+ lines_buffer->set_alignment(p_alignment);
+ lines_buffer->set_max_lines_visible(p_max_lines);
- ClassDB::bind_method(D_METHOD("set_scale", "cache_index", "size", "scale"), &FontData::set_scale);
- ClassDB::bind_method(D_METHOD("get_scale", "cache_index", "size"), &FontData::get_scale);
+ return lines_buffer->get_size();
+}
- ClassDB::bind_method(D_METHOD("set_spacing", "cache_index", "size", "spacing_type", "value"), &FontData::set_spacing);
- ClassDB::bind_method(D_METHOD("get_spacing", "cache_index", "size", "spacing_type"), &FontData::get_spacing);
+void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+ uint64_t hash = p_text.hash64();
+ hash = hash_djb2_one_64(p_font_size, hash);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
+ hash = hash_djb2_one_64(p_jst_flags.operator uint32_t(), hash);
+ }
+ hash = hash_djb2_one_64(p_direction, hash);
+ hash = hash_djb2_one_64(p_orientation, hash);
- ClassDB::bind_method(D_METHOD("get_texture_count", "cache_index", "size"), &FontData::get_texture_count);
- ClassDB::bind_method(D_METHOD("clear_textures", "cache_index", "size"), &FontData::clear_textures);
- ClassDB::bind_method(D_METHOD("remove_texture", "cache_index", "size", "texture_index"), &FontData::remove_texture);
+ Ref<TextLine> buffer;
+ if (cache.has(hash)) {
+ buffer = cache.get(hash);
+ } else {
+ buffer.instantiate();
+ buffer->set_direction(p_direction);
+ buffer->set_orientation(p_orientation);
+ buffer->add_string(p_text, Ref<Font>(this), p_font_size);
+ cache.insert(hash, buffer);
+ }
- ClassDB::bind_method(D_METHOD("set_texture_image", "cache_index", "size", "texture_index", "image"), &FontData::set_texture_image);
- ClassDB::bind_method(D_METHOD("get_texture_image", "cache_index", "size", "texture_index"), &FontData::get_texture_image);
+ Vector2 ofs = p_pos;
+ if (p_orientation == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y -= buffer->get_line_ascent();
+ } else {
+ ofs.x -= buffer->get_line_ascent();
+ }
- ClassDB::bind_method(D_METHOD("set_texture_offsets", "cache_index", "size", "texture_index", "offset"), &FontData::set_texture_offsets);
- ClassDB::bind_method(D_METHOD("get_texture_offsets", "cache_index", "size", "texture_index"), &FontData::get_texture_offsets);
+ buffer->set_width(p_width);
+ buffer->set_horizontal_alignment(p_alignment);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ buffer->set_flags(p_jst_flags);
+ }
- ClassDB::bind_method(D_METHOD("get_glyph_list", "cache_index", "size"), &FontData::get_glyph_list);
- ClassDB::bind_method(D_METHOD("clear_glyphs", "cache_index", "size"), &FontData::clear_glyphs);
- ClassDB::bind_method(D_METHOD("remove_glyph", "cache_index", "size", "glyph"), &FontData::remove_glyph);
+ buffer->draw(p_canvas_item, ofs, p_modulate);
+}
- ClassDB::bind_method(D_METHOD("set_glyph_advance", "cache_index", "size", "glyph", "advance"), &FontData::set_glyph_advance);
- ClassDB::bind_method(D_METHOD("get_glyph_advance", "cache_index", "size", "glyph"), &FontData::get_glyph_advance);
+void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+ uint64_t hash = p_text.hash64();
+ hash = hash_djb2_one_64(p_font_size, hash);
+ hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
+ hash = hash_djb2_one_64(p_brk_flags.operator uint32_t(), hash);
+ hash = hash_djb2_one_64(p_jst_flags.operator uint32_t(), hash);
+ hash = hash_djb2_one_64(p_direction, hash);
+ hash = hash_djb2_one_64(p_orientation, hash);
- ClassDB::bind_method(D_METHOD("set_glyph_offset", "cache_index", "size", "glyph", "offset"), &FontData::set_glyph_offset);
- ClassDB::bind_method(D_METHOD("get_glyph_offset", "cache_index", "size", "glyph"), &FontData::get_glyph_offset);
+ Ref<TextParagraph> lines_buffer;
+ if (cache_wrap.has(hash)) {
+ lines_buffer = cache_wrap.get(hash);
+ } else {
+ lines_buffer.instantiate();
+ lines_buffer->set_direction(p_direction);
+ lines_buffer->set_orientation(p_orientation);
+ lines_buffer->add_string(p_text, Ref<Font>(this), p_font_size);
+ lines_buffer->set_width(p_width);
+ lines_buffer->set_break_flags(p_brk_flags);
+ lines_buffer->set_justification_flags(p_jst_flags);
+ cache_wrap.insert(hash, lines_buffer);
+ }
- ClassDB::bind_method(D_METHOD("set_glyph_size", "cache_index", "size", "glyph", "gl_size"), &FontData::set_glyph_size);
- ClassDB::bind_method(D_METHOD("get_glyph_size", "cache_index", "size", "glyph"), &FontData::get_glyph_size);
+ Vector2 ofs = p_pos;
+ if (p_orientation == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y -= lines_buffer->get_line_ascent(0);
+ } else {
+ ofs.x -= lines_buffer->get_line_ascent(0);
+ }
- ClassDB::bind_method(D_METHOD("set_glyph_uv_rect", "cache_index", "size", "glyph", "uv_rect"), &FontData::set_glyph_uv_rect);
- ClassDB::bind_method(D_METHOD("get_glyph_uv_rect", "cache_index", "size", "glyph"), &FontData::get_glyph_uv_rect);
+ lines_buffer->set_alignment(p_alignment);
+ lines_buffer->set_max_lines_visible(p_max_lines);
- ClassDB::bind_method(D_METHOD("set_glyph_texture_idx", "cache_index", "size", "glyph", "texture_idx"), &FontData::set_glyph_texture_idx);
- ClassDB::bind_method(D_METHOD("get_glyph_texture_idx", "cache_index", "size", "glyph"), &FontData::get_glyph_texture_idx);
+ lines_buffer->draw(p_canvas_item, ofs, p_modulate);
+}
- ClassDB::bind_method(D_METHOD("get_kerning_list", "cache_index", "size"), &FontData::get_kerning_list);
- ClassDB::bind_method(D_METHOD("clear_kerning_map", "cache_index", "size"), &FontData::clear_kerning_map);
- ClassDB::bind_method(D_METHOD("remove_kerning", "cache_index", "size", "glyph_pair"), &FontData::remove_kerning);
+void Font::draw_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+ uint64_t hash = p_text.hash64();
+ hash = hash_djb2_one_64(p_font_size, hash);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
+ hash = hash_djb2_one_64(p_jst_flags.operator uint32_t(), hash);
+ }
+ hash = hash_djb2_one_64(p_direction, hash);
+ hash = hash_djb2_one_64(p_orientation, hash);
- ClassDB::bind_method(D_METHOD("set_kerning", "cache_index", "size", "glyph_pair", "kerning"), &FontData::set_kerning);
- ClassDB::bind_method(D_METHOD("get_kerning", "cache_index", "size", "glyph_pair"), &FontData::get_kerning);
+ Ref<TextLine> buffer;
+ if (cache.has(hash)) {
+ buffer = cache.get(hash);
+ } else {
+ buffer.instantiate();
+ buffer->set_direction(p_direction);
+ buffer->set_orientation(p_orientation);
+ buffer->add_string(p_text, Ref<Font>(this), p_font_size);
+ cache.insert(hash, buffer);
+ }
- ClassDB::bind_method(D_METHOD("render_range", "cache_index", "size", "start", "end"), &FontData::render_range);
- ClassDB::bind_method(D_METHOD("render_glyph", "cache_index", "size", "index"), &FontData::render_glyph);
+ Vector2 ofs = p_pos;
+ if (p_orientation == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y -= buffer->get_line_ascent();
+ } else {
+ ofs.x -= buffer->get_line_ascent();
+ }
- ClassDB::bind_method(D_METHOD("get_cache_rid", "cache_index"), &FontData::get_cache_rid);
+ buffer->set_width(p_width);
+ buffer->set_horizontal_alignment(p_alignment);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ buffer->set_flags(p_jst_flags);
+ }
- ClassDB::bind_method(D_METHOD("is_language_supported", "language"), &FontData::is_language_supported);
- ClassDB::bind_method(D_METHOD("set_language_support_override", "language", "supported"), &FontData::set_language_support_override);
- ClassDB::bind_method(D_METHOD("get_language_support_override", "language"), &FontData::get_language_support_override);
- ClassDB::bind_method(D_METHOD("remove_language_support_override", "language"), &FontData::remove_language_support_override);
- ClassDB::bind_method(D_METHOD("get_language_support_overrides"), &FontData::get_language_support_overrides);
+ buffer->draw_outline(p_canvas_item, ofs, p_size, p_modulate);
+}
- ClassDB::bind_method(D_METHOD("is_script_supported", "script"), &FontData::is_script_supported);
- ClassDB::bind_method(D_METHOD("set_script_support_override", "script", "supported"), &FontData::set_script_support_override);
- ClassDB::bind_method(D_METHOD("get_script_support_override", "script"), &FontData::get_script_support_override);
- ClassDB::bind_method(D_METHOD("remove_script_support_override", "script"), &FontData::remove_script_support_override);
- ClassDB::bind_method(D_METHOD("get_script_support_overrides"), &FontData::get_script_support_overrides);
+void Font::draw_multiline_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, int p_size, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+ uint64_t hash = p_text.hash64();
+ hash = hash_djb2_one_64(p_font_size, hash);
+ hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
+ hash = hash_djb2_one_64(p_brk_flags.operator uint32_t(), hash);
+ hash = hash_djb2_one_64(p_jst_flags.operator uint32_t(), hash);
+ hash = hash_djb2_one_64(p_direction, hash);
+ hash = hash_djb2_one_64(p_orientation, hash);
- ClassDB::bind_method(D_METHOD("set_opentype_feature_overrides", "overrides"), &FontData::set_opentype_feature_overrides);
- ClassDB::bind_method(D_METHOD("get_opentype_feature_overrides"), &FontData::get_opentype_feature_overrides);
+ Ref<TextParagraph> lines_buffer;
+ if (cache_wrap.has(hash)) {
+ lines_buffer = cache_wrap.get(hash);
+ } else {
+ lines_buffer.instantiate();
+ lines_buffer->set_direction(p_direction);
+ lines_buffer->set_orientation(p_orientation);
+ lines_buffer->add_string(p_text, Ref<Font>(this), p_font_size);
+ lines_buffer->set_width(p_width);
+ lines_buffer->set_break_flags(p_brk_flags);
+ lines_buffer->set_justification_flags(p_jst_flags);
+ cache_wrap.insert(hash, lines_buffer);
+ }
- ClassDB::bind_method(D_METHOD("has_char", "char"), &FontData::has_char);
- ClassDB::bind_method(D_METHOD("get_supported_chars"), &FontData::get_supported_chars);
+ Vector2 ofs = p_pos;
+ if (p_orientation == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y -= lines_buffer->get_line_ascent(0);
+ } else {
+ ofs.x -= lines_buffer->get_line_ascent(0);
+ }
- ClassDB::bind_method(D_METHOD("get_glyph_index", "size", "char", "variation_selector"), &FontData::get_glyph_index);
+ lines_buffer->set_alignment(p_alignment);
+ lines_buffer->set_max_lines_visible(p_max_lines);
- ClassDB::bind_method(D_METHOD("get_supported_feature_list"), &FontData::get_supported_feature_list);
- ClassDB::bind_method(D_METHOD("get_supported_variation_list"), &FontData::get_supported_variation_list);
+ lines_buffer->draw_outline(p_canvas_item, ofs, p_size, p_modulate);
+}
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_data", "get_data");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_antialiased", "is_antialiased");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_name", "get_font_name");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "style_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style_name", "get_font_style_name");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style", "get_font_style");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel", PROPERTY_USAGE_STORAGE), "set_subpixel_positioning", "get_subpixel_positioning");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "embolden", PROPERTY_HINT_RANGE, "-2,2,0.01", PROPERTY_USAGE_STORAGE), "set_embolden", "get_embolden");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_transform", "get_transform");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_pixel_range", "get_msdf_pixel_range");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_size", "get_msdf_size");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_force_autohinter", "is_force_autohinter");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_STORAGE), "set_hinting", "get_hinting");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_oversampling", "get_oversampling");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_fixed_size", "get_fixed_size");
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "opentype_feature_overrides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_opentype_feature_overrides", "get_opentype_feature_overrides");
+// Drawing char.
+Size2 Font::get_char_size(char32_t p_char, int p_font_size) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ for (int i = 0; i < rids.size(); i++) {
+ if (TS->font_has_char(rids[i], p_char)) {
+ int32_t glyph = TS->font_get_glyph_index(rids[i], p_font_size, p_char, 0);
+ return Size2(TS->font_get_glyph_advance(rids[i], p_font_size, glyph).x, get_height(p_font_size));
+ }
+ }
+ return Size2();
}
-bool FontData::_set(const StringName &p_name, const Variant &p_value) {
- Vector<String> tokens = p_name.operator String().split("/");
- if (tokens.size() == 2 && tokens[0] == "language_support_override") {
- String lang = tokens[1];
- set_language_support_override(lang, p_value);
- return true;
- } else if (tokens.size() == 2 && tokens[0] == "script_support_override") {
- String script = tokens[1];
- set_script_support_override(script, p_value);
- return true;
- } else if (tokens.size() >= 3 && tokens[0] == "cache") {
- int cache_index = tokens[1].to_int();
- if (tokens.size() == 3 && tokens[2] == "variation_coordinates") {
- set_variation_coordinates(cache_index, p_value);
- return true;
+real_t Font::draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, int p_font_size, const Color &p_modulate) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ for (int i = 0; i < rids.size(); i++) {
+ if (TS->font_has_char(rids[i], p_char)) {
+ int32_t glyph = TS->font_get_glyph_index(rids[i], p_font_size, p_char, 0);
+ TS->font_draw_glyph(rids[i], p_canvas_item, p_font_size, p_pos, glyph, p_modulate);
+ return TS->font_get_glyph_advance(rids[i], p_font_size, glyph).x;
}
- if (tokens.size() >= 5) {
- Vector2i sz = Vector2i(tokens[2].to_int(), tokens[3].to_int());
- if (tokens[4] == "ascent") {
- set_ascent(cache_index, sz.x, p_value);
- return true;
- } else if (tokens[4] == "descent") {
- set_descent(cache_index, sz.x, p_value);
- return true;
- } else if (tokens[4] == "underline_position") {
- set_underline_position(cache_index, sz.x, p_value);
- return true;
- } else if (tokens[4] == "underline_thickness") {
- set_underline_thickness(cache_index, sz.x, p_value);
- return true;
- } else if (tokens[4] == "scale") {
- set_scale(cache_index, sz.x, p_value);
- return true;
- } else if (tokens[4] == "spacing_glyph") {
- set_spacing(cache_index, sz.x, TextServer::SPACING_GLYPH, p_value);
- return true;
- } else if (tokens[4] == "spacing_space") {
- set_spacing(cache_index, sz.x, TextServer::SPACING_SPACE, p_value);
- return true;
- } else if (tokens.size() == 7 && tokens[4] == "textures") {
- int texture_index = tokens[5].to_int();
- if (tokens[6] == "image") {
- set_texture_image(cache_index, sz, texture_index, p_value);
- return true;
- } else if (tokens[6] == "offsets") {
- set_texture_offsets(cache_index, sz, texture_index, p_value);
- return true;
- }
- } else if (tokens.size() == 7 && tokens[4] == "glyphs") {
- int32_t glyph_index = tokens[5].to_int();
- if (tokens[6] == "advance") {
- set_glyph_advance(cache_index, sz.x, glyph_index, p_value);
- return true;
- } else if (tokens[6] == "offset") {
- set_glyph_offset(cache_index, sz, glyph_index, p_value);
- return true;
- } else if (tokens[6] == "size") {
- set_glyph_size(cache_index, sz, glyph_index, p_value);
- return true;
- } else if (tokens[6] == "uv_rect") {
- set_glyph_uv_rect(cache_index, sz, glyph_index, p_value);
- return true;
- } else if (tokens[6] == "texture_idx") {
- set_glyph_texture_idx(cache_index, sz, glyph_index, p_value);
- return true;
- }
- } else if (tokens.size() == 7 && tokens[4] == "kerning_overrides") {
- Vector2i gp = Vector2i(tokens[5].to_int(), tokens[6].to_int());
- set_kerning(cache_index, sz.x, gp, p_value);
- return true;
- }
+ }
+ return 0.f;
+}
+
+real_t Font::draw_char_outline(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, int p_font_size, int p_size, const Color &p_modulate) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ for (int i = 0; i < rids.size(); i++) {
+ if (TS->font_has_char(rids[i], p_char)) {
+ int32_t glyph = TS->font_get_glyph_index(rids[i], p_font_size, p_char, 0);
+ TS->font_draw_glyph_outline(rids[i], p_canvas_item, p_font_size, p_size, p_pos, glyph, p_modulate);
+ return TS->font_get_glyph_advance(rids[i], p_font_size, glyph).x;
}
}
- return false;
+ return 0.f;
}
-bool FontData::_get(const StringName &p_name, Variant &r_ret) const {
- Vector<String> tokens = p_name.operator String().split("/");
- if (tokens.size() == 2 && tokens[0] == "language_support_override") {
- String lang = tokens[1];
- r_ret = get_language_support_override(lang);
- return true;
- } else if (tokens.size() == 2 && tokens[0] == "script_support_override") {
- String script = tokens[1];
- r_ret = get_script_support_override(script);
- return true;
- } else if (tokens.size() >= 3 && tokens[0] == "cache") {
- int cache_index = tokens[1].to_int();
- if (tokens.size() == 3 && tokens[2] == "variation_coordinates") {
- r_ret = get_variation_coordinates(cache_index);
+// Helper functions.
+bool Font::has_char(char32_t p_char) const {
+ if (dirty_rids) {
+ _update_rids();
+ }
+ for (int i = 0; i < rids.size(); i++) {
+ if (TS->font_has_char(rids[i], p_char)) {
return true;
}
- if (tokens.size() >= 5) {
- Vector2i sz = Vector2i(tokens[2].to_int(), tokens[3].to_int());
- if (tokens[4] == "ascent") {
- r_ret = get_ascent(cache_index, sz.x);
- return true;
- } else if (tokens[4] == "descent") {
- r_ret = get_descent(cache_index, sz.x);
- return true;
- } else if (tokens[4] == "underline_position") {
- r_ret = get_underline_position(cache_index, sz.x);
- return true;
- } else if (tokens[4] == "underline_thickness") {
- r_ret = get_underline_thickness(cache_index, sz.x);
- return true;
- } else if (tokens[4] == "scale") {
- r_ret = get_scale(cache_index, sz.x);
- return true;
- } else if (tokens[4] == "spacing_glyph") {
- r_ret = get_spacing(cache_index, sz.x, TextServer::SPACING_GLYPH);
- return true;
- } else if (tokens[4] == "spacing_space") {
- r_ret = get_spacing(cache_index, sz.x, TextServer::SPACING_SPACE);
- return true;
- } else if (tokens.size() == 7 && tokens[4] == "textures") {
- int texture_index = tokens[5].to_int();
- if (tokens[6] == "image") {
- r_ret = get_texture_image(cache_index, sz, texture_index);
- return true;
- } else if (tokens[6] == "offsets") {
- r_ret = get_texture_offsets(cache_index, sz, texture_index);
- return true;
- }
- } else if (tokens.size() == 7 && tokens[4] == "glyphs") {
- int32_t glyph_index = tokens[5].to_int();
- if (tokens[6] == "advance") {
- r_ret = get_glyph_advance(cache_index, sz.x, glyph_index);
- return true;
- } else if (tokens[6] == "offset") {
- r_ret = get_glyph_offset(cache_index, sz, glyph_index);
- return true;
- } else if (tokens[6] == "size") {
- r_ret = get_glyph_size(cache_index, sz, glyph_index);
- return true;
- } else if (tokens[6] == "uv_rect") {
- r_ret = get_glyph_uv_rect(cache_index, sz, glyph_index);
- return true;
- } else if (tokens[6] == "texture_idx") {
- r_ret = get_glyph_texture_idx(cache_index, sz, glyph_index);
- return true;
- }
- } else if (tokens.size() == 7 && tokens[4] == "kerning_overrides") {
- Vector2i gp = Vector2i(tokens[5].to_int(), tokens[6].to_int());
- r_ret = get_kerning(cache_index, sz.x, gp);
- return true;
- }
- }
}
return false;
}
-void FontData::_get_property_list(List<PropertyInfo> *p_list) const {
- Vector<String> lang_over = get_language_support_overrides();
- for (int i = 0; i < lang_over.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::BOOL, "language_support_override/" + lang_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- }
- Vector<String> scr_over = get_script_support_overrides();
- for (int i = 0; i < scr_over.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::BOOL, "script_support_override/" + scr_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+String Font::get_supported_chars() const {
+ if (dirty_rids) {
+ _update_rids();
}
- for (int i = 0; i < cache.size(); i++) {
- String prefix = "cache/" + itos(i) + "/";
- Array sizes = get_size_cache_list(i);
- p_list->push_back(PropertyInfo(Variant::DICTIONARY, prefix + "variation_coordinates", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- for (int j = 0; j < sizes.size(); j++) {
- Vector2i sz = sizes[j];
- String prefix_sz = prefix + itos(sz.x) + "/" + itos(sz.y) + "/";
- if (sz.y == 0) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "ascent", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "descent", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "underline_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "underline_thickness", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::BOOL, prefix_sz + "spacing_glyph", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::BOOL, prefix_sz + "spacing_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- }
-
- int tx_cnt = get_texture_count(i, sz);
- for (int k = 0; k < tx_cnt; k++) {
- p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, prefix_sz + "textures/" + itos(k) + "/offsets", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::OBJECT, prefix_sz + "textures/" + itos(k) + "/image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
- }
- Array glyphs = get_glyph_list(i, sz);
- for (int k = 0; k < glyphs.size(); k++) {
- const int32_t &gl = glyphs[k];
- if (sz.y == 0) {
- p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- }
- p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::RECT2, prefix_sz + "glyphs/" + itos(gl) + "/uv_rect", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- p_list->push_back(PropertyInfo(Variant::INT, prefix_sz + "glyphs/" + itos(gl) + "/texture_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- }
- if (sz.y == 0) {
- Array kerning_map = get_kerning_list(i, sz.x);
- for (int k = 0; k < kerning_map.size(); k++) {
- const Vector2i &gl_pair = kerning_map[k];
- p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "kerning_overrides/" + itos(gl_pair.x) + "/" + itos(gl_pair.y), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
- }
+ String chars;
+ for (int i = 0; i < rids.size(); i++) {
+ String data_chars = TS->font_get_supported_chars(rids[i]);
+ for (int j = 0; j < data_chars.length(); j++) {
+ if (chars.find_char(data_chars[j]) == -1) {
+ chars += data_chars[j];
}
}
}
+ return chars;
}
-void FontData::reset_state() {
- _clear_cache();
- data.clear();
- data_ptr = nullptr;
- data_size = 0;
- cache.clear();
+bool Font::is_language_supported(const String &p_language) const {
+ return TS->font_is_language_supported(_get_rid(), p_language);
+}
- antialiased = true;
- msdf = false;
- force_autohinter = false;
- hinting = TextServer::HINTING_LIGHT;
- subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;
- msdf_pixel_range = 14;
- msdf_size = 128;
- fixed_size = 0;
- embolden = 0.f;
- transform = Transform2D();
- oversampling = 0.f;
+bool Font::is_script_supported(const String &p_script) const {
+ return TS->font_is_script_supported(_get_rid(), p_script);
+}
+
+Dictionary Font::get_supported_feature_list() const {
+ return TS->font_supported_feature_list(_get_rid());
+}
+
+Dictionary Font::get_supported_variation_list() const {
+ return TS->font_supported_variation_list(_get_rid());
+}
+
+int64_t Font::get_face_count() const {
+ return TS->font_get_face_count(_get_rid());
+}
+
+Font::Font() {
+ cache.set_capacity(64);
+ cache_wrap.set_capacity(16);
}
-void FontData::_convert_packed_8bit(Ref<Image> &p_source, int p_page, int p_sz) {
+Font::~Font() {
+ reset_state();
+}
+
+/*************************************************************************/
+/* FontFile */
+/*************************************************************************/
+
+_FORCE_INLINE_ void FontFile::_clear_cache() {
+ for (int i = 0; i < cache.size(); i++) {
+ if (cache[i].is_valid()) {
+ TS->free_rid(cache[i]);
+ cache.write[i] = RID();
+ }
+ }
+}
+
+_FORCE_INLINE_ void FontFile::_ensure_rid(int p_cache_index) const {
+ if (unlikely(p_cache_index >= cache.size())) {
+ cache.resize(p_cache_index + 1);
+ }
+ if (unlikely(!cache[p_cache_index].is_valid())) {
+ cache.write[p_cache_index] = TS->create_font();
+ TS->font_set_data_ptr(cache[p_cache_index], data_ptr, data_size);
+ TS->font_set_antialiased(cache[p_cache_index], antialiased);
+ TS->font_set_generate_mipmaps(cache[p_cache_index], mipmaps);
+ TS->font_set_multichannel_signed_distance_field(cache[p_cache_index], msdf);
+ TS->font_set_msdf_pixel_range(cache[p_cache_index], msdf_pixel_range);
+ TS->font_set_msdf_size(cache[p_cache_index], msdf_size);
+ TS->font_set_fixed_size(cache[p_cache_index], fixed_size);
+ TS->font_set_force_autohinter(cache[p_cache_index], force_autohinter);
+ TS->font_set_hinting(cache[p_cache_index], hinting);
+ TS->font_set_subpixel_positioning(cache[p_cache_index], subpixel_positioning);
+ TS->font_set_oversampling(cache[p_cache_index], oversampling);
+ }
+}
+
+void FontFile::_convert_packed_8bit(Ref<Image> &p_source, int p_page, int p_sz) {
int w = p_source->get_width();
int h = p_source->get_height();
@@ -501,7 +636,7 @@ void FontData::_convert_packed_8bit(Ref<Image> &p_source, int p_page, int p_sz)
set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 3, img_a);
}
-void FontData::_convert_packed_4bit(Ref<Image> &p_source, int p_page, int p_sz) {
+void FontFile::_convert_packed_4bit(Ref<Image> &p_source, int p_page, int p_sz) {
int w = p_source->get_width();
int h = p_source->get_height();
@@ -601,7 +736,7 @@ void FontData::_convert_packed_4bit(Ref<Image> &p_source, int p_page, int p_sz)
set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 3, img_ao);
}
-void FontData::_convert_rgba_4bit(Ref<Image> &p_source, int p_page, int p_sz) {
+void FontFile::_convert_rgba_4bit(Ref<Image> &p_source, int p_page, int p_sz) {
int w = p_source->get_width();
int h = p_source->get_height();
@@ -657,7 +792,7 @@ void FontData::_convert_rgba_4bit(Ref<Image> &p_source, int p_page, int p_sz) {
set_texture_image(0, Vector2i(p_sz, 1), p_page, img_o);
}
-void FontData::_convert_mono_8bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) {
+void FontFile::_convert_mono_8bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) {
int w = p_source->get_width();
int h = p_source->get_height();
@@ -686,7 +821,7 @@ void FontData::_convert_mono_8bit(Ref<Image> &p_source, int p_page, int p_ch, in
set_texture_image(0, Vector2i(p_sz, p_ol), p_page, img_g);
}
-void FontData::_convert_mono_4bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) {
+void FontFile::_convert_mono_4bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) {
int w = p_source->get_width();
int h = p_source->get_height();
@@ -729,12 +864,481 @@ void FontData::_convert_mono_4bit(Ref<Image> &p_source, int p_page, int p_ch, in
set_texture_image(0, Vector2i(p_sz, p_ol), p_page, img_o);
}
+void FontFile::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("load_bitmap_font", "path"), &FontFile::load_bitmap_font);
+ ClassDB::bind_method(D_METHOD("load_dynamic_font", "path"), &FontFile::load_dynamic_font);
+
+ ClassDB::bind_method(D_METHOD("set_data", "data"), &FontFile::set_data);
+ ClassDB::bind_method(D_METHOD("get_data"), &FontFile::get_data);
+
+ ClassDB::bind_method(D_METHOD("set_font_name", "name"), &FontFile::set_font_name);
+ ClassDB::bind_method(D_METHOD("set_font_style_name", "name"), &FontFile::set_font_style_name);
+ ClassDB::bind_method(D_METHOD("set_font_style", "style"), &FontFile::set_font_style);
+
+ ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontFile::set_antialiased);
+ ClassDB::bind_method(D_METHOD("is_antialiased"), &FontFile::is_antialiased);
+
+ ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "generate_mipmaps"), &FontFile::set_generate_mipmaps);
+ ClassDB::bind_method(D_METHOD("get_generate_mipmaps"), &FontFile::get_generate_mipmaps);
+
+ ClassDB::bind_method(D_METHOD("set_multichannel_signed_distance_field", "msdf"), &FontFile::set_multichannel_signed_distance_field);
+ ClassDB::bind_method(D_METHOD("is_multichannel_signed_distance_field"), &FontFile::is_multichannel_signed_distance_field);
+
+ ClassDB::bind_method(D_METHOD("set_msdf_pixel_range", "msdf_pixel_range"), &FontFile::set_msdf_pixel_range);
+ ClassDB::bind_method(D_METHOD("get_msdf_pixel_range"), &FontFile::get_msdf_pixel_range);
+
+ ClassDB::bind_method(D_METHOD("set_msdf_size", "msdf_size"), &FontFile::set_msdf_size);
+ ClassDB::bind_method(D_METHOD("get_msdf_size"), &FontFile::get_msdf_size);
+
+ ClassDB::bind_method(D_METHOD("set_fixed_size", "fixed_size"), &FontFile::set_fixed_size);
+ ClassDB::bind_method(D_METHOD("get_fixed_size"), &FontFile::get_fixed_size);
+
+ ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &FontFile::set_force_autohinter);
+ ClassDB::bind_method(D_METHOD("is_force_autohinter"), &FontFile::is_force_autohinter);
+
+ ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &FontFile::set_hinting);
+ ClassDB::bind_method(D_METHOD("get_hinting"), &FontFile::get_hinting);
+
+ ClassDB::bind_method(D_METHOD("set_subpixel_positioning", "subpixel_positioning"), &FontFile::set_subpixel_positioning);
+ ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &FontFile::get_subpixel_positioning);
+
+ ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &FontFile::set_oversampling);
+ ClassDB::bind_method(D_METHOD("get_oversampling"), &FontFile::get_oversampling);
+
+ ClassDB::bind_method(D_METHOD("get_cache_count"), &FontFile::get_cache_count);
+ ClassDB::bind_method(D_METHOD("clear_cache"), &FontFile::clear_cache);
+ ClassDB::bind_method(D_METHOD("remove_cache", "cache_index"), &FontFile::remove_cache);
+
+ ClassDB::bind_method(D_METHOD("get_size_cache_list", "cache_index"), &FontFile::get_size_cache_list);
+ ClassDB::bind_method(D_METHOD("clear_size_cache", "cache_index"), &FontFile::clear_size_cache);
+ ClassDB::bind_method(D_METHOD("remove_size_cache", "cache_index", "size"), &FontFile::remove_size_cache);
+
+ ClassDB::bind_method(D_METHOD("set_variation_coordinates", "cache_index", "variation_coordinates"), &FontFile::set_variation_coordinates);
+ ClassDB::bind_method(D_METHOD("get_variation_coordinates", "cache_index"), &FontFile::get_variation_coordinates);
+
+ ClassDB::bind_method(D_METHOD("set_embolden", "cache_index", "strength"), &FontFile::set_embolden);
+ ClassDB::bind_method(D_METHOD("get_embolden", "cache_index"), &FontFile::get_embolden);
+
+ ClassDB::bind_method(D_METHOD("set_transform", "cache_index", "transform"), &FontFile::set_transform);
+ ClassDB::bind_method(D_METHOD("get_transform", "cache_index"), &FontFile::get_transform);
+
+ ClassDB::bind_method(D_METHOD("set_face_index", "cache_index", "face_index"), &FontFile::set_face_index);
+ ClassDB::bind_method(D_METHOD("get_face_index", "cache_index"), &FontFile::get_face_index);
+
+ ClassDB::bind_method(D_METHOD("set_cache_ascent", "cache_index", "size", "ascent"), &FontFile::set_cache_ascent);
+ ClassDB::bind_method(D_METHOD("get_cache_ascent", "cache_index", "size"), &FontFile::get_cache_ascent);
+
+ ClassDB::bind_method(D_METHOD("set_cache_descent", "cache_index", "size", "descent"), &FontFile::set_cache_descent);
+ ClassDB::bind_method(D_METHOD("get_cache_descent", "cache_index", "size"), &FontFile::get_cache_descent);
+
+ ClassDB::bind_method(D_METHOD("set_cache_underline_position", "cache_index", "size", "underline_position"), &FontFile::set_cache_underline_position);
+ ClassDB::bind_method(D_METHOD("get_cache_underline_position", "cache_index", "size"), &FontFile::get_cache_underline_position);
+
+ ClassDB::bind_method(D_METHOD("set_cache_underline_thickness", "cache_index", "size", "underline_thickness"), &FontFile::set_cache_underline_thickness);
+ ClassDB::bind_method(D_METHOD("get_cache_underline_thickness", "cache_index", "size"), &FontFile::get_cache_underline_thickness);
+
+ ClassDB::bind_method(D_METHOD("set_cache_scale", "cache_index", "size", "scale"), &FontFile::set_cache_scale);
+ ClassDB::bind_method(D_METHOD("get_cache_scale", "cache_index", "size"), &FontFile::get_cache_scale);
+
+ ClassDB::bind_method(D_METHOD("get_texture_count", "cache_index", "size"), &FontFile::get_texture_count);
+ ClassDB::bind_method(D_METHOD("clear_textures", "cache_index", "size"), &FontFile::clear_textures);
+ ClassDB::bind_method(D_METHOD("remove_texture", "cache_index", "size", "texture_index"), &FontFile::remove_texture);
+
+ ClassDB::bind_method(D_METHOD("set_texture_image", "cache_index", "size", "texture_index", "image"), &FontFile::set_texture_image);
+ ClassDB::bind_method(D_METHOD("get_texture_image", "cache_index", "size", "texture_index"), &FontFile::get_texture_image);
+
+ ClassDB::bind_method(D_METHOD("set_texture_offsets", "cache_index", "size", "texture_index", "offset"), &FontFile::set_texture_offsets);
+ ClassDB::bind_method(D_METHOD("get_texture_offsets", "cache_index", "size", "texture_index"), &FontFile::get_texture_offsets);
+
+ ClassDB::bind_method(D_METHOD("get_glyph_list", "cache_index", "size"), &FontFile::get_glyph_list);
+ ClassDB::bind_method(D_METHOD("clear_glyphs", "cache_index", "size"), &FontFile::clear_glyphs);
+ ClassDB::bind_method(D_METHOD("remove_glyph", "cache_index", "size", "glyph"), &FontFile::remove_glyph);
+
+ ClassDB::bind_method(D_METHOD("set_glyph_advance", "cache_index", "size", "glyph", "advance"), &FontFile::set_glyph_advance);
+ ClassDB::bind_method(D_METHOD("get_glyph_advance", "cache_index", "size", "glyph"), &FontFile::get_glyph_advance);
+
+ ClassDB::bind_method(D_METHOD("set_glyph_offset", "cache_index", "size", "glyph", "offset"), &FontFile::set_glyph_offset);
+ ClassDB::bind_method(D_METHOD("get_glyph_offset", "cache_index", "size", "glyph"), &FontFile::get_glyph_offset);
+
+ ClassDB::bind_method(D_METHOD("set_glyph_size", "cache_index", "size", "glyph", "gl_size"), &FontFile::set_glyph_size);
+ ClassDB::bind_method(D_METHOD("get_glyph_size", "cache_index", "size", "glyph"), &FontFile::get_glyph_size);
+
+ ClassDB::bind_method(D_METHOD("set_glyph_uv_rect", "cache_index", "size", "glyph", "uv_rect"), &FontFile::set_glyph_uv_rect);
+ ClassDB::bind_method(D_METHOD("get_glyph_uv_rect", "cache_index", "size", "glyph"), &FontFile::get_glyph_uv_rect);
+
+ ClassDB::bind_method(D_METHOD("set_glyph_texture_idx", "cache_index", "size", "glyph", "texture_idx"), &FontFile::set_glyph_texture_idx);
+ ClassDB::bind_method(D_METHOD("get_glyph_texture_idx", "cache_index", "size", "glyph"), &FontFile::get_glyph_texture_idx);
+
+ ClassDB::bind_method(D_METHOD("get_kerning_list", "cache_index", "size"), &FontFile::get_kerning_list);
+ ClassDB::bind_method(D_METHOD("clear_kerning_map", "cache_index", "size"), &FontFile::clear_kerning_map);
+ ClassDB::bind_method(D_METHOD("remove_kerning", "cache_index", "size", "glyph_pair"), &FontFile::remove_kerning);
+
+ ClassDB::bind_method(D_METHOD("set_kerning", "cache_index", "size", "glyph_pair", "kerning"), &FontFile::set_kerning);
+ ClassDB::bind_method(D_METHOD("get_kerning", "cache_index", "size", "glyph_pair"), &FontFile::get_kerning);
+
+ ClassDB::bind_method(D_METHOD("render_range", "cache_index", "size", "start", "end"), &FontFile::render_range);
+ ClassDB::bind_method(D_METHOD("render_glyph", "cache_index", "size", "index"), &FontFile::render_glyph);
+
+ ClassDB::bind_method(D_METHOD("set_language_support_override", "language", "supported"), &FontFile::set_language_support_override);
+ ClassDB::bind_method(D_METHOD("get_language_support_override", "language"), &FontFile::get_language_support_override);
+ ClassDB::bind_method(D_METHOD("remove_language_support_override", "language"), &FontFile::remove_language_support_override);
+ ClassDB::bind_method(D_METHOD("get_language_support_overrides"), &FontFile::get_language_support_overrides);
+
+ ClassDB::bind_method(D_METHOD("set_script_support_override", "script", "supported"), &FontFile::set_script_support_override);
+ ClassDB::bind_method(D_METHOD("get_script_support_override", "script"), &FontFile::get_script_support_override);
+ ClassDB::bind_method(D_METHOD("remove_script_support_override", "script"), &FontFile::remove_script_support_override);
+ ClassDB::bind_method(D_METHOD("get_script_support_overrides"), &FontFile::get_script_support_overrides);
+
+ ClassDB::bind_method(D_METHOD("set_opentype_feature_overrides", "overrides"), &FontFile::set_opentype_feature_overrides);
+ ClassDB::bind_method(D_METHOD("get_opentype_feature_overrides"), &FontFile::get_opentype_feature_overrides);
+
+ ClassDB::bind_method(D_METHOD("get_glyph_index", "size", "char", "variation_selector"), &FontFile::get_glyph_index);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_data", "get_data");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_generate_mipmaps", "get_generate_mipmaps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_antialiased", "is_antialiased");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_name", "get_font_name");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "style_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style_name", "get_font_style_name");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_FLAGS, "Bold,Italic,Fixed Size", PROPERTY_USAGE_STORAGE), "set_font_style", "get_font_style");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel", PROPERTY_USAGE_STORAGE), "set_subpixel_positioning", "get_subpixel_positioning");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_pixel_range", "get_msdf_pixel_range");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_size", "get_msdf_size");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_force_autohinter", "is_force_autohinter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_STORAGE), "set_hinting", "get_hinting");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_oversampling", "get_oversampling");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_fixed_size", "get_fixed_size");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "opentype_feature_overrides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_opentype_feature_overrides", "get_opentype_feature_overrides");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font"), PROPERTY_USAGE_STORAGE), "set_fallbacks", "get_fallbacks");
+}
+
+bool FontFile::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> tokens = p_name.operator String().split("/");
+
+#ifndef DISABLE_DEPRECATED
+ if (tokens.size() == 1 && tokens[0] == "font_path") {
+ // Compatibility, DynamicFontData.
+ load_dynamic_font(p_value);
+ } else if (tokens.size() == 1 && tokens[0] == "override_oversampling") {
+ set_oversampling(p_value);
+ }
+ if (tokens.size() == 1 && tokens[0] == "font_data") {
+ // Compatibility, DynamicFont.
+ Ref<Font> f = p_value;
+ if (f.is_valid()) {
+ fallbacks.push_back(f);
+ return true;
+ }
+ return false;
+ } else if (tokens.size() == 2 && tokens[0] == "fallback") {
+ // Compatibility, DynamicFont.
+ Ref<FontFile> f = p_value;
+ if (f.is_valid()) {
+ fallbacks.push_back(f);
+ return true;
+ }
+ return false;
+ } else if (tokens.size() == 1 && tokens[0] == "textures") {
+ // Compatibility, BitmapFont.
+ set_fixed_size(16);
+ Array textures = p_value;
+ for (int i = 0; i < textures.size(); i++) {
+ Ref<ImageTexture> tex = textures[i];
+ ERR_CONTINUE(!tex.is_valid());
+ set_texture_image(0, Vector2i(16, 0), i, tex->get_image());
+ }
+ } else if (tokens.size() == 1 && tokens[0] == "chars") {
+ // Compatibility, BitmapFont.
+ set_fixed_size(16);
+ PackedInt32Array arr = p_value;
+ int len = arr.size();
+ ERR_FAIL_COND_V(len % 9, false);
+ if (!len) {
+ return false;
+ }
+ int chars = len / 9;
+ for (int i = 0; i < chars; i++) {
+ const int32_t *data = &arr[i * 9];
+ char32_t c = data[0];
+ set_glyph_texture_idx(0, Vector2i(16, 0), c, data[1]);
+ set_glyph_uv_rect(0, Vector2i(16, 0), c, Rect2(data[2], data[3], data[4], data[5]));
+ set_glyph_offset(0, Vector2i(16, 0), c, Size2(data[6], data[7]));
+ set_glyph_advance(0, 16, c, Vector2(data[8], 0));
+ }
+ } else if (tokens.size() == 1 && tokens[0] == "kernings") {
+ // Compatibility, BitmapFont.
+ set_fixed_size(16);
+ PackedInt32Array arr = p_value;
+ int len = arr.size();
+ ERR_FAIL_COND_V(len % 3, false);
+ if (!len) {
+ return false;
+ }
+ for (int i = 0; i < len / 3; i++) {
+ const int32_t *data = &arr[i * 3];
+ set_kerning(0, 16, Vector2i(data[0], data[1]), Vector2(data[2], 0));
+ }
+ } else if (tokens.size() == 1 && tokens[0] == "height") {
+ // Compatibility, BitmapFont.
+ bmp_height = p_value;
+ set_fixed_size(16);
+ set_cache_descent(0, 16, bmp_height - bmp_ascent);
+ } else if (tokens.size() == 1 && tokens[0] == "ascent") {
+ // Compatibility, BitmapFont.
+ bmp_ascent = p_value;
+ set_fixed_size(16);
+ set_cache_ascent(0, 16, bmp_ascent);
+ set_cache_descent(0, 16, bmp_height - bmp_ascent);
+ } else if (tokens.size() == 1 && tokens[0] == "fallback") {
+ // Compatibility, BitmapFont.
+ Ref<Font> f = p_value;
+ if (f.is_valid()) {
+ fallbacks.push_back(f);
+ return true;
+ }
+ return false;
+ }
+#endif // DISABLE_DEPRECATED
+
+ if (tokens.size() == 2 && tokens[0] == "language_support_override") {
+ String lang = tokens[1];
+ set_language_support_override(lang, p_value);
+ return true;
+ } else if (tokens.size() == 2 && tokens[0] == "script_support_override") {
+ String script = tokens[1];
+ set_script_support_override(script, p_value);
+ return true;
+ } else if (tokens.size() >= 3 && tokens[0] == "cache") {
+ int cache_index = tokens[1].to_int();
+ if (tokens.size() == 3 && tokens[2] == "variation_coordinates") {
+ set_variation_coordinates(cache_index, p_value);
+ return true;
+ } else if (tokens.size() == 3 && tokens[2] == "embolden") {
+ set_embolden(cache_index, p_value);
+ return true;
+ } else if (tokens.size() == 3 && tokens[2] == "face_index") {
+ set_face_index(cache_index, p_value);
+ return true;
+ } else if (tokens.size() == 3 && tokens[2] == "transform") {
+ set_transform(cache_index, p_value);
+ return true;
+ }
+ if (tokens.size() >= 5) {
+ Vector2i sz = Vector2i(tokens[2].to_int(), tokens[3].to_int());
+ if (tokens[4] == "ascent") {
+ set_cache_ascent(cache_index, sz.x, p_value);
+ return true;
+ } else if (tokens[4] == "descent") {
+ set_cache_descent(cache_index, sz.x, p_value);
+ return true;
+ } else if (tokens[4] == "underline_position") {
+ set_cache_underline_position(cache_index, sz.x, p_value);
+ return true;
+ } else if (tokens[4] == "underline_thickness") {
+ set_cache_underline_thickness(cache_index, sz.x, p_value);
+ return true;
+ } else if (tokens[4] == "scale") {
+ set_cache_scale(cache_index, sz.x, p_value);
+ return true;
+ } else if (tokens.size() == 7 && tokens[4] == "textures") {
+ int texture_index = tokens[5].to_int();
+ if (tokens[6] == "image") {
+ set_texture_image(cache_index, sz, texture_index, p_value);
+ return true;
+ } else if (tokens[6] == "offsets") {
+ set_texture_offsets(cache_index, sz, texture_index, p_value);
+ return true;
+ }
+ } else if (tokens.size() == 7 && tokens[4] == "glyphs") {
+ int32_t glyph_index = tokens[5].to_int();
+ if (tokens[6] == "advance") {
+ set_glyph_advance(cache_index, sz.x, glyph_index, p_value);
+ return true;
+ } else if (tokens[6] == "offset") {
+ set_glyph_offset(cache_index, sz, glyph_index, p_value);
+ return true;
+ } else if (tokens[6] == "size") {
+ set_glyph_size(cache_index, sz, glyph_index, p_value);
+ return true;
+ } else if (tokens[6] == "uv_rect") {
+ set_glyph_uv_rect(cache_index, sz, glyph_index, p_value);
+ return true;
+ } else if (tokens[6] == "texture_idx") {
+ set_glyph_texture_idx(cache_index, sz, glyph_index, p_value);
+ return true;
+ }
+ } else if (tokens.size() == 7 && tokens[4] == "kerning_overrides") {
+ Vector2i gp = Vector2i(tokens[5].to_int(), tokens[6].to_int());
+ set_kerning(cache_index, sz.x, gp, p_value);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool FontFile::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> tokens = p_name.operator String().split("/");
+ if (tokens.size() == 2 && tokens[0] == "language_support_override") {
+ String lang = tokens[1];
+ r_ret = get_language_support_override(lang);
+ return true;
+ } else if (tokens.size() == 2 && tokens[0] == "script_support_override") {
+ String script = tokens[1];
+ r_ret = get_script_support_override(script);
+ return true;
+ } else if (tokens.size() >= 3 && tokens[0] == "cache") {
+ int cache_index = tokens[1].to_int();
+ if (tokens.size() == 3 && tokens[2] == "variation_coordinates") {
+ r_ret = get_variation_coordinates(cache_index);
+ return true;
+ } else if (tokens.size() == 3 && tokens[2] == "embolden") {
+ r_ret = get_embolden(cache_index);
+ return true;
+ } else if (tokens.size() == 3 && tokens[2] == "face_index") {
+ r_ret = get_face_index(cache_index);
+ return true;
+ } else if (tokens.size() == 3 && tokens[2] == "transform") {
+ r_ret = get_transform(cache_index);
+ return true;
+ }
+ if (tokens.size() >= 5) {
+ Vector2i sz = Vector2i(tokens[2].to_int(), tokens[3].to_int());
+ if (tokens[4] == "ascent") {
+ r_ret = get_cache_ascent(cache_index, sz.x);
+ return true;
+ } else if (tokens[4] == "descent") {
+ r_ret = get_cache_descent(cache_index, sz.x);
+ return true;
+ } else if (tokens[4] == "underline_position") {
+ r_ret = get_cache_underline_position(cache_index, sz.x);
+ return true;
+ } else if (tokens[4] == "underline_thickness") {
+ r_ret = get_cache_underline_thickness(cache_index, sz.x);
+ return true;
+ } else if (tokens[4] == "scale") {
+ r_ret = get_cache_scale(cache_index, sz.x);
+ return true;
+ } else if (tokens.size() == 7 && tokens[4] == "textures") {
+ int texture_index = tokens[5].to_int();
+ if (tokens[6] == "image") {
+ r_ret = get_texture_image(cache_index, sz, texture_index);
+ return true;
+ } else if (tokens[6] == "offsets") {
+ r_ret = get_texture_offsets(cache_index, sz, texture_index);
+ return true;
+ }
+ } else if (tokens.size() == 7 && tokens[4] == "glyphs") {
+ int32_t glyph_index = tokens[5].to_int();
+ if (tokens[6] == "advance") {
+ r_ret = get_glyph_advance(cache_index, sz.x, glyph_index);
+ return true;
+ } else if (tokens[6] == "offset") {
+ r_ret = get_glyph_offset(cache_index, sz, glyph_index);
+ return true;
+ } else if (tokens[6] == "size") {
+ r_ret = get_glyph_size(cache_index, sz, glyph_index);
+ return true;
+ } else if (tokens[6] == "uv_rect") {
+ r_ret = get_glyph_uv_rect(cache_index, sz, glyph_index);
+ return true;
+ } else if (tokens[6] == "texture_idx") {
+ r_ret = get_glyph_texture_idx(cache_index, sz, glyph_index);
+ return true;
+ }
+ } else if (tokens.size() == 7 && tokens[4] == "kerning_overrides") {
+ Vector2i gp = Vector2i(tokens[5].to_int(), tokens[6].to_int());
+ r_ret = get_kerning(cache_index, sz.x, gp);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void FontFile::_get_property_list(List<PropertyInfo> *p_list) const {
+ Vector<String> lang_over = get_language_support_overrides();
+ for (int i = 0; i < lang_over.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "language_support_override/" + lang_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ }
+ Vector<String> scr_over = get_script_support_overrides();
+ for (int i = 0; i < scr_over.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "script_support_override/" + scr_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ }
+ for (int i = 0; i < cache.size(); i++) {
+ String prefix = "cache/" + itos(i) + "/";
+ Array sizes = get_size_cache_list(i);
+ p_list->push_back(PropertyInfo(Variant::DICTIONARY, prefix + "variation_coordinates", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::INT, "face_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "embolden", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+
+ for (int j = 0; j < sizes.size(); j++) {
+ Vector2i sz = sizes[j];
+ String prefix_sz = prefix + itos(sz.x) + "/" + itos(sz.y) + "/";
+ if (sz.y == 0) {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "ascent", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "descent", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "underline_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "underline_thickness", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ }
+
+ int tx_cnt = get_texture_count(i, sz);
+ for (int k = 0; k < tx_cnt; k++) {
+ p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, prefix_sz + "textures/" + itos(k) + "/offsets", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, prefix_sz + "textures/" + itos(k) + "/image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
+ }
+ Array glyphs = get_glyph_list(i, sz);
+ for (int k = 0; k < glyphs.size(); k++) {
+ const int32_t &gl = glyphs[k];
+ if (sz.y == 0) {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ }
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::RECT2, prefix_sz + "glyphs/" + itos(gl) + "/uv_rect", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ p_list->push_back(PropertyInfo(Variant::INT, prefix_sz + "glyphs/" + itos(gl) + "/texture_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ }
+ if (sz.y == 0) {
+ Array kerning_map = get_kerning_list(i, sz.x);
+ for (int k = 0; k < kerning_map.size(); k++) {
+ const Vector2i &gl_pair = kerning_map[k];
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "kerning_overrides/" + itos(gl_pair.x) + "/" + itos(gl_pair.y), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
+ }
+ }
+ }
+ }
+}
+
+void FontFile::reset_state() {
+ _clear_cache();
+ data.clear();
+ data_ptr = nullptr;
+ data_size = 0;
+ cache.clear();
+
+ antialiased = true;
+ mipmaps = false;
+ msdf = false;
+ force_autohinter = false;
+ hinting = TextServer::HINTING_LIGHT;
+ subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;
+ msdf_pixel_range = 14;
+ msdf_size = 128;
+ fixed_size = 0;
+ oversampling = 0.f;
+
+ Font::reset_state();
+}
+
/*************************************************************************/
-Error FontData::load_bitmap_font(const String &p_path) {
+Error FontFile::load_bitmap_font(const String &p_path) {
reset_state();
antialiased = false;
+ mipmaps = false;
msdf = false;
force_autohinter = false;
hinting = TextServer::HINTING_NONE;
@@ -747,7 +1351,7 @@ Error FontData::load_bitmap_font(const String &p_path) {
int height = 0;
int ascent = 0;
int outline = 0;
- uint32_t st_flags = 0;
+ BitField<TextServer::FontStyle> st_flags = 0;
String font_name;
bool packed = false;
@@ -773,10 +1377,10 @@ Error FontData::load_bitmap_font(const String &p_path) {
uint8_t flags = f->get_8();
ERR_FAIL_COND_V_MSG(flags & 0x02, ERR_CANT_CREATE, RTR("Non-unicode version of BMFont is not supported."));
if (flags & (1 << 3)) {
- st_flags |= TextServer::FONT_BOLD;
+ st_flags.set_flag(TextServer::FONT_BOLD);
}
if (flags & (1 << 2)) {
- st_flags |= TextServer::FONT_ITALIC;
+ st_flags.set_flag(TextServer::FONT_ITALIC);
}
f->get_8(); // non-unicode charset, skip
f->get_16(); // stretch_h, skip
@@ -956,7 +1560,7 @@ Error FontData::load_bitmap_font(const String &p_path) {
int delimiter = line.find(" ");
String type = line.substr(0, delimiter);
int pos = delimiter + 1;
- Map<String, String> keys;
+ HashMap<String, String> keys;
while (pos < line.size() && line[pos] == ' ') {
pos++;
@@ -1003,12 +1607,12 @@ Error FontData::load_bitmap_font(const String &p_path) {
}
if (keys.has("bold")) {
if (keys["bold"].to_int()) {
- st_flags |= TextServer::FONT_BOLD;
+ st_flags.set_flag(TextServer::FONT_BOLD);
}
}
if (keys.has("italic")) {
if (keys["italic"].to_int()) {
- st_flags |= TextServer::FONT_ITALIC;
+ st_flags.set_flag(TextServer::FONT_ITALIC);
}
}
if (keys.has("face")) {
@@ -1193,13 +1797,13 @@ Error FontData::load_bitmap_font(const String &p_path) {
set_font_name(font_name);
set_font_style(st_flags);
- set_ascent(0, base_size, ascent);
- set_descent(0, base_size, height - ascent);
+ set_cache_ascent(0, base_size, ascent);
+ set_cache_descent(0, base_size, height - ascent);
return OK;
}
-Error FontData::load_dynamic_font(const String &p_path) {
+Error FontFile::load_dynamic_font(const String &p_path) {
reset_state();
Vector<uint8_t> data = FileAccess::get_file_as_array(p_path);
@@ -1208,7 +1812,7 @@ Error FontData::load_dynamic_font(const String &p_path) {
return OK;
}
-void FontData::set_data_ptr(const uint8_t *p_data, size_t p_size) {
+void FontFile::set_data_ptr(const uint8_t *p_data, size_t p_size) {
data.clear();
data_ptr = p_data;
data_size = p_size;
@@ -1222,7 +1826,7 @@ void FontData::set_data_ptr(const uint8_t *p_data, size_t p_size) {
}
}
-void FontData::set_data(const PackedByteArray &p_data) {
+void FontFile::set_data(const PackedByteArray &p_data) {
data = p_data;
data_ptr = data.ptr();
data_size = data.size();
@@ -1236,7 +1840,7 @@ void FontData::set_data(const PackedByteArray &p_data) {
}
}
-PackedByteArray FontData::get_data() const {
+PackedByteArray FontFile::get_data() const {
if (unlikely((size_t)data.size() != data_size)) {
PackedByteArray *data_w = const_cast<PackedByteArray *>(&data);
data_w->resize(data_size);
@@ -1245,37 +1849,22 @@ PackedByteArray FontData::get_data() const {
return data;
}
-void FontData::set_font_name(const String &p_name) {
+void FontFile::set_font_name(const String &p_name) {
_ensure_rid(0);
TS->font_set_name(cache[0], p_name);
}
-String FontData::get_font_name() const {
- _ensure_rid(0);
- return TS->font_get_name(cache[0]);
-}
-
-void FontData::set_font_style_name(const String &p_name) {
+void FontFile::set_font_style_name(const String &p_name) {
_ensure_rid(0);
TS->font_set_style_name(cache[0], p_name);
}
-String FontData::get_font_style_name() const {
- _ensure_rid(0);
- return TS->font_get_style_name(cache[0]);
-}
-
-void FontData::set_font_style(uint32_t p_style) {
+void FontFile::set_font_style(BitField<TextServer::FontStyle> p_style) {
_ensure_rid(0);
TS->font_set_style(cache[0], p_style);
}
-uint32_t FontData::get_font_style() const {
- _ensure_rid(0);
- return TS->font_get_style(cache[0]);
-}
-
-void FontData::set_antialiased(bool p_antialiased) {
+void FontFile::set_antialiased(bool p_antialiased) {
if (antialiased != p_antialiased) {
antialiased = p_antialiased;
for (int i = 0; i < cache.size(); i++) {
@@ -1286,11 +1875,26 @@ void FontData::set_antialiased(bool p_antialiased) {
}
}
-bool FontData::is_antialiased() const {
+bool FontFile::is_antialiased() const {
return antialiased;
}
-void FontData::set_multichannel_signed_distance_field(bool p_msdf) {
+void FontFile::set_generate_mipmaps(bool p_generate_mipmaps) {
+ if (mipmaps != p_generate_mipmaps) {
+ mipmaps = p_generate_mipmaps;
+ for (int i = 0; i < cache.size(); i++) {
+ _ensure_rid(i);
+ TS->font_set_generate_mipmaps(cache[i], mipmaps);
+ }
+ emit_changed();
+ }
+}
+
+bool FontFile::get_generate_mipmaps() const {
+ return mipmaps;
+}
+
+void FontFile::set_multichannel_signed_distance_field(bool p_msdf) {
if (msdf != p_msdf) {
msdf = p_msdf;
for (int i = 0; i < cache.size(); i++) {
@@ -1301,11 +1905,11 @@ void FontData::set_multichannel_signed_distance_field(bool p_msdf) {
}
}
-bool FontData::is_multichannel_signed_distance_field() const {
+bool FontFile::is_multichannel_signed_distance_field() const {
return msdf;
}
-void FontData::set_msdf_pixel_range(int p_msdf_pixel_range) {
+void FontFile::set_msdf_pixel_range(int p_msdf_pixel_range) {
if (msdf_pixel_range != p_msdf_pixel_range) {
msdf_pixel_range = p_msdf_pixel_range;
for (int i = 0; i < cache.size(); i++) {
@@ -1316,11 +1920,11 @@ void FontData::set_msdf_pixel_range(int p_msdf_pixel_range) {
}
}
-int FontData::get_msdf_pixel_range() const {
+int FontFile::get_msdf_pixel_range() const {
return msdf_pixel_range;
}
-void FontData::set_msdf_size(int p_msdf_size) {
+void FontFile::set_msdf_size(int p_msdf_size) {
if (msdf_size != p_msdf_size) {
msdf_size = p_msdf_size;
for (int i = 0; i < cache.size(); i++) {
@@ -1331,11 +1935,11 @@ void FontData::set_msdf_size(int p_msdf_size) {
}
}
-int FontData::get_msdf_size() const {
+int FontFile::get_msdf_size() const {
return msdf_size;
}
-void FontData::set_fixed_size(int p_fixed_size) {
+void FontFile::set_fixed_size(int p_fixed_size) {
if (fixed_size != p_fixed_size) {
fixed_size = p_fixed_size;
for (int i = 0; i < cache.size(); i++) {
@@ -1346,11 +1950,11 @@ void FontData::set_fixed_size(int p_fixed_size) {
}
}
-int FontData::get_fixed_size() const {
+int FontFile::get_fixed_size() const {
return fixed_size;
}
-void FontData::set_force_autohinter(bool p_force_autohinter) {
+void FontFile::set_force_autohinter(bool p_force_autohinter) {
if (force_autohinter != p_force_autohinter) {
force_autohinter = p_force_autohinter;
for (int i = 0; i < cache.size(); i++) {
@@ -1361,11 +1965,11 @@ void FontData::set_force_autohinter(bool p_force_autohinter) {
}
}
-bool FontData::is_force_autohinter() const {
+bool FontFile::is_force_autohinter() const {
return force_autohinter;
}
-void FontData::set_hinting(TextServer::Hinting p_hinting) {
+void FontFile::set_hinting(TextServer::Hinting p_hinting) {
if (hinting != p_hinting) {
hinting = p_hinting;
for (int i = 0; i < cache.size(); i++) {
@@ -1376,11 +1980,11 @@ void FontData::set_hinting(TextServer::Hinting p_hinting) {
}
}
-TextServer::Hinting FontData::get_hinting() const {
+TextServer::Hinting FontFile::get_hinting() const {
return hinting;
}
-void FontData::set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel) {
+void FontFile::set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel) {
if (subpixel_positioning != p_subpixel) {
subpixel_positioning = p_subpixel;
for (int i = 0; i < cache.size(); i++) {
@@ -1391,41 +1995,11 @@ void FontData::set_subpixel_positioning(TextServer::SubpixelPositioning p_subpix
}
}
-TextServer::SubpixelPositioning FontData::get_subpixel_positioning() const {
+TextServer::SubpixelPositioning FontFile::get_subpixel_positioning() const {
return subpixel_positioning;
}
-void FontData::set_embolden(float p_strength) {
- if (embolden != p_strength) {
- embolden = p_strength;
- for (int i = 0; i < cache.size(); i++) {
- _ensure_rid(i);
- TS->font_set_embolden(cache[i], embolden);
- }
- emit_changed();
- }
-}
-
-float FontData::get_embolden() const {
- return embolden;
-}
-
-void FontData::set_transform(Transform2D p_transform) {
- if (transform != p_transform) {
- transform = p_transform;
- for (int i = 0; i < cache.size(); i++) {
- _ensure_rid(i);
- TS->font_set_transform(cache[i], transform);
- }
- emit_changed();
- }
-}
-
-Transform2D FontData::get_transform() const {
- return transform;
-}
-
-void FontData::set_oversampling(real_t p_oversampling) {
+void FontFile::set_oversampling(real_t p_oversampling) {
if (oversampling != p_oversampling) {
oversampling = p_oversampling;
for (int i = 0; i < cache.size(); i++) {
@@ -1436,17 +2010,20 @@ void FontData::set_oversampling(real_t p_oversampling) {
}
}
-real_t FontData::get_oversampling() const {
+real_t FontFile::get_oversampling() const {
return oversampling;
}
-RID FontData::find_cache(const Dictionary &p_variation_coordinates) const {
+RID FontFile::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform) const {
// Find existing variation cache.
const Dictionary &supported_coords = get_supported_variation_list();
for (int i = 0; i < cache.size(); i++) {
if (cache[i].is_valid()) {
const Dictionary &cache_var = TS->font_get_variation_coordinates(cache[i]);
bool match = true;
+ match = match && (TS->font_get_face_index(cache[i]) == p_face_index);
+ match = match && (TS->font_get_embolden(cache[i]) == p_strength);
+ match = match && (TS->font_get_transform(cache[i]) == p_transform);
for (const Variant *V = supported_coords.next(nullptr); V && match; V = supported_coords.next(V)) {
const Vector3 &def = supported_coords[*V];
@@ -1482,19 +2059,28 @@ RID FontData::find_cache(const Dictionary &p_variation_coordinates) const {
int idx = cache.size();
_ensure_rid(idx);
TS->font_set_variation_coordinates(cache[idx], p_variation_coordinates);
+ TS->font_set_face_index(cache[idx], p_face_index);
+ TS->font_set_embolden(cache[idx], p_strength);
+ TS->font_set_transform(cache[idx], p_transform);
return cache[idx];
}
-int FontData::get_cache_count() const {
+RID FontFile::_get_rid() const {
+ _ensure_rid(0);
+ return cache[0];
+}
+
+int FontFile::get_cache_count() const {
return cache.size();
}
-void FontData::clear_cache() {
+void FontFile::clear_cache() {
_clear_cache();
cache.clear();
+ emit_changed();
}
-void FontData::remove_cache(int p_cache_index) {
+void FontFile::remove_cache(int p_cache_index) {
ERR_FAIL_INDEX(p_cache_index, cache.size());
if (cache[p_cache_index].is_valid()) {
TS->free_rid(cache.write[p_cache_index]);
@@ -1503,952 +2089,607 @@ void FontData::remove_cache(int p_cache_index) {
emit_changed();
}
-Array FontData::get_size_cache_list(int p_cache_index) const {
+Array FontFile::get_size_cache_list(int p_cache_index) const {
ERR_FAIL_COND_V(p_cache_index < 0, Array());
_ensure_rid(p_cache_index);
return TS->font_get_size_cache_list(cache[p_cache_index]);
}
-void FontData::clear_size_cache(int p_cache_index) {
+void FontFile::clear_size_cache(int p_cache_index) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_clear_size_cache(cache[p_cache_index]);
}
-void FontData::remove_size_cache(int p_cache_index, const Vector2i &p_size) {
+void FontFile::remove_size_cache(int p_cache_index, const Vector2i &p_size) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_remove_size_cache(cache[p_cache_index], p_size);
}
-void FontData::set_variation_coordinates(int p_cache_index, const Dictionary &p_variation_coordinates) {
+void FontFile::set_variation_coordinates(int p_cache_index, const Dictionary &p_variation_coordinates) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_variation_coordinates(cache[p_cache_index], p_variation_coordinates);
- emit_changed();
}
-Dictionary FontData::get_variation_coordinates(int p_cache_index) const {
+Dictionary FontFile::get_variation_coordinates(int p_cache_index) const {
ERR_FAIL_COND_V(p_cache_index < 0, Dictionary());
_ensure_rid(p_cache_index);
return TS->font_get_variation_coordinates(cache[p_cache_index]);
}
-void FontData::set_ascent(int p_cache_index, int p_size, real_t p_ascent) {
+void FontFile::set_embolden(int p_cache_index, float p_strength) {
+ ERR_FAIL_COND(p_cache_index < 0);
+ _ensure_rid(p_cache_index);
+ TS->font_set_embolden(cache[p_cache_index], p_strength);
+}
+
+float FontFile::get_embolden(int p_cache_index) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
+ _ensure_rid(p_cache_index);
+ return TS->font_get_embolden(cache[p_cache_index]);
+}
+
+void FontFile::set_transform(int p_cache_index, Transform2D p_transform) {
+ ERR_FAIL_COND(p_cache_index < 0);
+ _ensure_rid(p_cache_index);
+ TS->font_set_transform(cache[p_cache_index], p_transform);
+}
+
+Transform2D FontFile::get_transform(int p_cache_index) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, Transform2D());
+ _ensure_rid(p_cache_index);
+ return TS->font_get_transform(cache[p_cache_index]);
+}
+
+void FontFile::set_face_index(int p_cache_index, int64_t p_index) {
+ ERR_FAIL_COND(p_cache_index < 0);
+ ERR_FAIL_COND(p_index < 0);
+ ERR_FAIL_COND(p_index >= 0x7FFF);
+
+ _ensure_rid(p_cache_index);
+ TS->font_set_face_index(cache[p_cache_index], p_index);
+}
+
+int64_t FontFile::get_face_index(int p_cache_index) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, 0);
+ _ensure_rid(p_cache_index);
+ return TS->font_get_face_index(cache[p_cache_index]);
+}
+
+void FontFile::set_cache_ascent(int p_cache_index, int p_size, real_t p_ascent) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_ascent(cache[p_cache_index], p_size, p_ascent);
}
-real_t FontData::get_ascent(int p_cache_index, int p_size) const {
+real_t FontFile::get_cache_ascent(int p_cache_index, int p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_ascent(cache[p_cache_index], p_size);
}
-void FontData::set_descent(int p_cache_index, int p_size, real_t p_descent) {
+void FontFile::set_cache_descent(int p_cache_index, int p_size, real_t p_descent) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_descent(cache[p_cache_index], p_size, p_descent);
}
-real_t FontData::get_descent(int p_cache_index, int p_size) const {
+real_t FontFile::get_cache_descent(int p_cache_index, int p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_descent(cache[p_cache_index], p_size);
}
-void FontData::set_underline_position(int p_cache_index, int p_size, real_t p_underline_position) {
+void FontFile::set_cache_underline_position(int p_cache_index, int p_size, real_t p_underline_position) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_underline_position(cache[p_cache_index], p_size, p_underline_position);
}
-real_t FontData::get_underline_position(int p_cache_index, int p_size) const {
+real_t FontFile::get_cache_underline_position(int p_cache_index, int p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_underline_position(cache[p_cache_index], p_size);
}
-void FontData::set_underline_thickness(int p_cache_index, int p_size, real_t p_underline_thickness) {
+void FontFile::set_cache_underline_thickness(int p_cache_index, int p_size, real_t p_underline_thickness) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_underline_thickness(cache[p_cache_index], p_size, p_underline_thickness);
}
-real_t FontData::get_underline_thickness(int p_cache_index, int p_size) const {
+real_t FontFile::get_cache_underline_thickness(int p_cache_index, int p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_underline_thickness(cache[p_cache_index], p_size);
}
-void FontData::set_scale(int p_cache_index, int p_size, real_t p_scale) {
+void FontFile::set_cache_scale(int p_cache_index, int p_size, real_t p_scale) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_scale(cache[p_cache_index], p_size, p_scale);
}
-real_t FontData::get_scale(int p_cache_index, int p_size) const {
+real_t FontFile::get_cache_scale(int p_cache_index, int p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
_ensure_rid(p_cache_index);
return TS->font_get_scale(cache[p_cache_index], p_size);
}
-void FontData::set_spacing(int p_cache_index, int p_size, TextServer::SpacingType p_spacing, int p_value) {
- ERR_FAIL_COND(p_cache_index < 0);
- _ensure_rid(p_cache_index);
- TS->font_set_spacing(cache[p_cache_index], p_size, p_spacing, p_value);
-}
-
-int FontData::get_spacing(int p_cache_index, int p_size, TextServer::SpacingType p_spacing) const {
- ERR_FAIL_COND_V(p_cache_index < 0, 0);
- _ensure_rid(p_cache_index);
- return TS->font_get_spacing(cache[p_cache_index], p_size, p_spacing);
-}
-
-int FontData::get_texture_count(int p_cache_index, const Vector2i &p_size) const {
+int FontFile::get_texture_count(int p_cache_index, const Vector2i &p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0);
_ensure_rid(p_cache_index);
return TS->font_get_texture_count(cache[p_cache_index], p_size);
}
-void FontData::clear_textures(int p_cache_index, const Vector2i &p_size) {
+void FontFile::clear_textures(int p_cache_index, const Vector2i &p_size) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_clear_textures(cache[p_cache_index], p_size);
}
-void FontData::remove_texture(int p_cache_index, const Vector2i &p_size, int p_texture_index) {
+void FontFile::remove_texture(int p_cache_index, const Vector2i &p_size, int p_texture_index) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_remove_texture(cache[p_cache_index], p_size, p_texture_index);
}
-void FontData::set_texture_image(int p_cache_index, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
+void FontFile::set_texture_image(int p_cache_index, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_texture_image(cache[p_cache_index], p_size, p_texture_index, p_image);
}
-Ref<Image> FontData::get_texture_image(int p_cache_index, const Vector2i &p_size, int p_texture_index) const {
+Ref<Image> FontFile::get_texture_image(int p_cache_index, const Vector2i &p_size, int p_texture_index) const {
ERR_FAIL_COND_V(p_cache_index < 0, Ref<Image>());
_ensure_rid(p_cache_index);
return TS->font_get_texture_image(cache[p_cache_index], p_size, p_texture_index);
}
-void FontData::set_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
+void FontFile::set_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_texture_offsets(cache[p_cache_index], p_size, p_texture_index, p_offset);
}
-PackedInt32Array FontData::get_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index) const {
+PackedInt32Array FontFile::get_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index) const {
ERR_FAIL_COND_V(p_cache_index < 0, PackedInt32Array());
_ensure_rid(p_cache_index);
return TS->font_get_texture_offsets(cache[p_cache_index], p_size, p_texture_index);
}
-Array FontData::get_glyph_list(int p_cache_index, const Vector2i &p_size) const {
+Array FontFile::get_glyph_list(int p_cache_index, const Vector2i &p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, Array());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_list(cache[p_cache_index], p_size);
}
-void FontData::clear_glyphs(int p_cache_index, const Vector2i &p_size) {
+void FontFile::clear_glyphs(int p_cache_index, const Vector2i &p_size) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_clear_glyphs(cache[p_cache_index], p_size);
}
-void FontData::remove_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) {
+void FontFile::remove_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_remove_glyph(cache[p_cache_index], p_size, p_glyph);
}
-void FontData::set_glyph_advance(int p_cache_index, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
+void FontFile::set_glyph_advance(int p_cache_index, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_advance(cache[p_cache_index], p_size, p_glyph, p_advance);
}
-Vector2 FontData::get_glyph_advance(int p_cache_index, int p_size, int32_t p_glyph) const {
+Vector2 FontFile::get_glyph_advance(int p_cache_index, int p_size, int32_t p_glyph) const {
ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_advance(cache[p_cache_index], p_size, p_glyph);
}
-void FontData::set_glyph_offset(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
+void FontFile::set_glyph_offset(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_offset(cache[p_cache_index], p_size, p_glyph, p_offset);
}
-Vector2 FontData::get_glyph_offset(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
+Vector2 FontFile::get_glyph_offset(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_offset(cache[p_cache_index], p_size, p_glyph);
}
-void FontData::set_glyph_size(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
+void FontFile::set_glyph_size(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_size(cache[p_cache_index], p_size, p_glyph, p_gl_size);
}
-Vector2 FontData::get_glyph_size(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
+Vector2 FontFile::get_glyph_size(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_size(cache[p_cache_index], p_size, p_glyph);
}
-void FontData::set_glyph_uv_rect(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
+void FontFile::set_glyph_uv_rect(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_uv_rect(cache[p_cache_index], p_size, p_glyph, p_uv_rect);
}
-Rect2 FontData::get_glyph_uv_rect(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
+Rect2 FontFile::get_glyph_uv_rect(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
ERR_FAIL_COND_V(p_cache_index < 0, Rect2());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_uv_rect(cache[p_cache_index], p_size, p_glyph);
}
-void FontData::set_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
+void FontFile::set_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_glyph_texture_idx(cache[p_cache_index], p_size, p_glyph, p_texture_idx);
}
-int FontData::get_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
+int FontFile::get_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
ERR_FAIL_COND_V(p_cache_index < 0, 0);
_ensure_rid(p_cache_index);
return TS->font_get_glyph_texture_idx(cache[p_cache_index], p_size, p_glyph);
}
-Array FontData::get_kerning_list(int p_cache_index, int p_size) const {
+Array FontFile::get_kerning_list(int p_cache_index, int p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, Array());
_ensure_rid(p_cache_index);
return TS->font_get_kerning_list(cache[p_cache_index], p_size);
}
-void FontData::clear_kerning_map(int p_cache_index, int p_size) {
+void FontFile::clear_kerning_map(int p_cache_index, int p_size) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_clear_kerning_map(cache[p_cache_index], p_size);
}
-void FontData::remove_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair) {
+void FontFile::remove_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_remove_kerning(cache[p_cache_index], p_size, p_glyph_pair);
}
-void FontData::set_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
+void FontFile::set_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_set_kerning(cache[p_cache_index], p_size, p_glyph_pair, p_kerning);
}
-Vector2 FontData::get_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair) const {
+Vector2 FontFile::get_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair) const {
ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
_ensure_rid(p_cache_index);
return TS->font_get_kerning(cache[p_cache_index], p_size, p_glyph_pair);
}
-void FontData::render_range(int p_cache_index, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
+void FontFile::render_range(int p_cache_index, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_render_range(cache[p_cache_index], p_size, p_start, p_end);
}
-void FontData::render_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_index) {
+void FontFile::render_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_index) {
ERR_FAIL_COND(p_cache_index < 0);
_ensure_rid(p_cache_index);
TS->font_render_glyph(cache[p_cache_index], p_size, p_index);
}
-RID FontData::get_cache_rid(int p_cache_index) const {
- ERR_FAIL_COND_V(p_cache_index < 0, RID());
- _ensure_rid(p_cache_index);
- return cache[p_cache_index];
-}
-
-bool FontData::is_language_supported(const String &p_language) const {
- _ensure_rid(0);
- return TS->font_is_language_supported(cache[0], p_language);
-}
-
-void FontData::set_language_support_override(const String &p_language, bool p_supported) {
+void FontFile::set_language_support_override(const String &p_language, bool p_supported) {
_ensure_rid(0);
TS->font_set_language_support_override(cache[0], p_language, p_supported);
}
-bool FontData::get_language_support_override(const String &p_language) const {
+bool FontFile::get_language_support_override(const String &p_language) const {
_ensure_rid(0);
return TS->font_get_language_support_override(cache[0], p_language);
}
-void FontData::remove_language_support_override(const String &p_language) {
+void FontFile::remove_language_support_override(const String &p_language) {
_ensure_rid(0);
TS->font_remove_language_support_override(cache[0], p_language);
}
-Vector<String> FontData::get_language_support_overrides() const {
+Vector<String> FontFile::get_language_support_overrides() const {
_ensure_rid(0);
return TS->font_get_language_support_overrides(cache[0]);
}
-bool FontData::is_script_supported(const String &p_script) const {
- _ensure_rid(0);
- return TS->font_is_script_supported(cache[0], p_script);
-}
-
-void FontData::set_script_support_override(const String &p_script, bool p_supported) {
+void FontFile::set_script_support_override(const String &p_script, bool p_supported) {
_ensure_rid(0);
TS->font_set_script_support_override(cache[0], p_script, p_supported);
}
-bool FontData::get_script_support_override(const String &p_script) const {
+bool FontFile::get_script_support_override(const String &p_script) const {
_ensure_rid(0);
return TS->font_get_script_support_override(cache[0], p_script);
}
-void FontData::remove_script_support_override(const String &p_script) {
+void FontFile::remove_script_support_override(const String &p_script) {
_ensure_rid(0);
TS->font_remove_script_support_override(cache[0], p_script);
}
-Vector<String> FontData::get_script_support_overrides() const {
+Vector<String> FontFile::get_script_support_overrides() const {
_ensure_rid(0);
return TS->font_get_script_support_overrides(cache[0]);
}
-void FontData::set_opentype_feature_overrides(const Dictionary &p_overrides) {
+void FontFile::set_opentype_feature_overrides(const Dictionary &p_overrides) {
_ensure_rid(0);
TS->font_set_opentype_feature_overrides(cache[0], p_overrides);
}
-Dictionary FontData::get_opentype_feature_overrides() const {
+Dictionary FontFile::get_opentype_feature_overrides() const {
_ensure_rid(0);
return TS->font_get_opentype_feature_overrides(cache[0]);
}
-bool FontData::has_char(char32_t p_char) const {
- _ensure_rid(0);
- return TS->font_has_char(cache[0], p_char);
-}
-
-String FontData::get_supported_chars() const {
- _ensure_rid(0);
- return TS->font_get_supported_chars(cache[0]);
-}
-
-int32_t FontData::get_glyph_index(int p_size, char32_t p_char, char32_t p_variation_selector) const {
+int32_t FontFile::get_glyph_index(int p_size, char32_t p_char, char32_t p_variation_selector) const {
_ensure_rid(0);
return TS->font_get_glyph_index(cache[0], p_size, p_char, p_variation_selector);
}
-Dictionary FontData::get_supported_feature_list() const {
- _ensure_rid(0);
- return TS->font_supported_feature_list(cache[0]);
-}
-
-Dictionary FontData::get_supported_variation_list() const {
- _ensure_rid(0);
- return TS->font_supported_variation_list(cache[0]);
-}
-
-FontData::FontData() {
+FontFile::FontFile() {
/* NOP */
}
-FontData::~FontData() {
- _clear_cache();
+FontFile::~FontFile() {
+ reset_state();
}
/*************************************************************************/
+/* FontVariation */
+/*************************************************************************/
-void Font::_data_changed() {
- for (int i = 0; i < rids.size(); i++) {
- rids.write[i] = RID();
- }
- emit_changed();
-}
-
-void Font::_ensure_rid(int p_index) const {
- // Find or create cache record.
- if (!rids[p_index].is_valid() && data[p_index].is_valid()) {
- rids.write[p_index] = data[p_index]->find_cache(variation_coordinates);
- }
-}
+void FontVariation::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_base_font", "font"), &FontVariation::set_base_font);
+ ClassDB::bind_method(D_METHOD("get_base_font"), &FontVariation::get_base_font);
-void Font::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_data", "data"), &Font::add_data);
- ClassDB::bind_method(D_METHOD("set_data", "idx", "data"), &Font::set_data);
- ClassDB::bind_method(D_METHOD("get_data_count"), &Font::get_data_count);
- ClassDB::bind_method(D_METHOD("get_data", "idx"), &Font::get_data);
- ClassDB::bind_method(D_METHOD("get_data_rid", "idx"), &Font::get_data_rid);
- ClassDB::bind_method(D_METHOD("clear_data"), &Font::clear_data);
- ClassDB::bind_method(D_METHOD("remove_data", "idx"), &Font::remove_data);
-
- ClassDB::bind_method(D_METHOD("set_variation_coordinates", "variation_coordinates"), &Font::set_variation_coordinates);
- ClassDB::bind_method(D_METHOD("get_variation_coordinates"), &Font::get_variation_coordinates);
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "variation_coordinates"), "set_variation_coordinates", "get_variation_coordinates");
-
- ClassDB::bind_method(D_METHOD("set_spacing", "spacing", "value"), &Font::set_spacing);
- ClassDB::bind_method(D_METHOD("get_spacing", "spacing"), &Font::get_spacing);
+ ClassDB::bind_method(D_METHOD("set_variation_opentype", "coords"), &FontVariation::set_variation_opentype);
+ ClassDB::bind_method(D_METHOD("get_variation_opentype"), &FontVariation::get_variation_opentype);
- ADD_GROUP("Extra Spacing", "spacing");
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_top"), "set_spacing", "get_spacing", TextServer::SPACING_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_bottom"), "set_spacing", "get_spacing", TextServer::SPACING_BOTTOM);
+ ClassDB::bind_method(D_METHOD("set_variation_embolden", "strength"), &FontVariation::set_variation_embolden);
+ ClassDB::bind_method(D_METHOD("get_variation_embolden"), &FontVariation::get_variation_embolden);
- ClassDB::bind_method(D_METHOD("get_height", "size"), &Font::get_height, DEFVAL(DEFAULT_FONT_SIZE));
- ClassDB::bind_method(D_METHOD("get_ascent", "size"), &Font::get_ascent, DEFVAL(DEFAULT_FONT_SIZE));
- ClassDB::bind_method(D_METHOD("get_descent", "size"), &Font::get_descent, DEFVAL(DEFAULT_FONT_SIZE));
- ClassDB::bind_method(D_METHOD("get_underline_position", "size"), &Font::get_underline_position, DEFVAL(DEFAULT_FONT_SIZE));
- ClassDB::bind_method(D_METHOD("get_underline_thickness", "size"), &Font::get_underline_thickness, DEFVAL(DEFAULT_FONT_SIZE));
+ ClassDB::bind_method(D_METHOD("set_variation_face_index", "face_index"), &FontVariation::set_variation_face_index);
+ ClassDB::bind_method(D_METHOD("get_variation_face_index"), &FontVariation::get_variation_face_index);
- ClassDB::bind_method(D_METHOD("get_string_size", "text", "size", "alignment", "width", "flags"), &Font::get_string_size, DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND));
- ClassDB::bind_method(D_METHOD("get_multiline_string_size", "text", "width", "size", "flags"), &Font::get_multiline_string_size, DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND));
+ ClassDB::bind_method(D_METHOD("set_variation_transform", "transform"), &FontVariation::set_variation_transform);
+ ClassDB::bind_method(D_METHOD("get_variation_transform"), &FontVariation::get_variation_transform);
- ClassDB::bind_method(D_METHOD("draw_string", "canvas_item", "pos", "text", "alignment", "width", "size", "modulate", "outline_size", "outline_modulate", "flags"), &Font::draw_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(1, 1, 1, 0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND));
- ClassDB::bind_method(D_METHOD("draw_multiline_string", "canvas_item", "pos", "text", "alignment", "width", "max_lines", "size", "modulate", "outline_size", "outline_modulate", "flags"), &Font::draw_multiline_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(1, 1, 1, 0)), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND));
+ ClassDB::bind_method(D_METHOD("set_opentype_features", "features"), &FontVariation::set_opentype_features);
- ClassDB::bind_method(D_METHOD("get_char_size", "char", "next", "size"), &Font::get_char_size, DEFVAL(0), DEFVAL(DEFAULT_FONT_SIZE));
- ClassDB::bind_method(D_METHOD("draw_char", "canvas_item", "pos", "char", "next", "size", "modulate", "outline_size", "outline_modulate"), &Font::draw_char, DEFVAL(0), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(1, 1, 1, 0)));
+ ClassDB::bind_method(D_METHOD("set_spacing", "spacing", "value"), &FontVariation::set_spacing);
- ClassDB::bind_method(D_METHOD("has_char", "char"), &Font::has_char);
- ClassDB::bind_method(D_METHOD("get_supported_chars"), &Font::get_supported_chars);
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_base_font", "get_base_font");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), "set_fallbacks", "get_fallbacks");
- ClassDB::bind_method(D_METHOD("update_changes"), &Font::update_changes);
+ ADD_GROUP("Variation", "variation");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "variation_opentype"), "set_variation_opentype", "get_variation_opentype");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "variation_face_index"), "set_variation_face_index", "get_variation_face_index");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "variation_embolden", PROPERTY_HINT_RANGE, "-2,2,0.01"), "set_variation_embolden", "get_variation_embolden");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "variation_transform", PROPERTY_HINT_NONE, "suffix:px"), "set_variation_transform", "get_variation_transform");
- ClassDB::bind_method(D_METHOD("get_rids"), &Font::get_rids);
-}
+ ADD_GROUP("OpenType Features", "opentype");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "opentype_features"), "set_opentype_features", "get_opentype_features");
-bool Font::_set(const StringName &p_name, const Variant &p_value) {
- Vector<String> tokens = p_name.operator String().split("/");
-#ifndef DISABLE_DEPRECATED
- if (tokens.size() == 1 && tokens[0] == "font_data") {
- // Compatibility, DynamicFont main data.
- Ref<FontData> fd = p_value;
- if (fd.is_valid()) {
- add_data(fd);
- return true;
- }
- return false;
- } else if (tokens.size() == 2 && tokens[0] == "fallback") {
- // Compatibility, DynamicFont fallback data.
- Ref<FontData> fd = p_value;
- if (fd.is_valid()) {
- add_data(fd);
- return true;
- }
- return false;
- } else if (tokens.size() == 1 && tokens[0] == "fallback") {
- // Compatibility, BitmapFont fallback data.
- Ref<Font> f = p_value;
- if (f.is_valid()) {
- for (int i = 0; i < f->get_data_count(); i++) {
- add_data(f->get_data(i));
- }
- return true;
- }
- return false;
- }
-#endif /* DISABLE_DEPRECATED */
- if (tokens.size() == 2 && tokens[0] == "data") {
- int idx = tokens[1].to_int();
- Ref<FontData> fd = p_value;
- if (fd.is_valid()) {
- if (idx == data.size()) {
- add_data(fd);
- return true;
- } else if (idx >= 0 && idx < data.size()) {
- set_data(idx, fd);
- return true;
- } else {
- return false;
- }
- } else if (idx >= 0 && idx < data.size()) {
- remove_data(idx);
- return true;
- }
- }
- return false;
+ ADD_GROUP("Extra Spacing", "spacing");
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_glyph", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_GLYPH);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_space", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_SPACE);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_top", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_bottom", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_BOTTOM);
}
-bool Font::_get(const StringName &p_name, Variant &r_ret) const {
- Vector<String> tokens = p_name.operator String().split("/");
- if (tokens.size() == 2 && tokens[0] == "data") {
- int idx = tokens[1].to_int();
+void FontVariation::_update_rids() const {
+ Ref<Font> f = _get_base_font_or_default();
- if (idx == data.size()) {
- r_ret = Ref<FontData>();
- return true;
- } else if (idx >= 0 && idx < data.size()) {
- r_ret = get_data(idx);
- return true;
+ rids.clear();
+ if (fallbacks.is_empty() && f.is_valid()) {
+ RID rid = _get_rid();
+ if (rid.is_valid()) {
+ rids.push_back(rid);
}
- }
-
- return false;
-}
-void Font::_get_property_list(List<PropertyInfo> *p_list) const {
- for (int i = 0; i < data.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "data/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "FontData"));
+ const TypedArray<Font> &base_fallbacks = f->get_fallbacks();
+ for (int i = 0; i < base_fallbacks.size(); i++) {
+ _update_rids_fb(base_fallbacks[i], 0);
+ }
+ } else {
+ _update_rids_fb(const_cast<FontVariation *>(this), 0);
}
- p_list->push_back(PropertyInfo(Variant::OBJECT, "data/" + itos(data.size()), PROPERTY_HINT_RESOURCE_TYPE, "FontData"));
+ dirty_rids = false;
}
-void Font::reset_state() {
- for (int i = 0; i < data.size(); i++) {
- if (data[i].is_valid()) {
- data.write[i]->connect(SNAME("changed"), callable_mp(this, &Font::_data_changed), varray(), CONNECT_REFERENCE_COUNTED);
- }
+void FontVariation::reset_state() {
+ if (base_font.is_valid()) {
+ base_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
+ base_font.unref();
}
- cache.clear();
- cache_wrap.clear();
- data.clear();
- rids.clear();
- variation_coordinates.clear();
- spacing_bottom = 0;
- spacing_top = 0;
-}
-
-Dictionary Font::get_feature_list() const {
- Dictionary out;
- for (int i = 0; i < data.size(); i++) {
- Dictionary data_ftrs = data[i]->get_supported_feature_list();
- for (const Variant *ftr = data_ftrs.next(nullptr); ftr != nullptr; ftr = data_ftrs.next(ftr)) {
- out[*ftr] = data_ftrs[*ftr];
- }
+ if (theme_font.is_valid()) {
+ theme_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
+ theme_font.unref();
}
- return out;
-}
-void Font::add_data(const Ref<FontData> &p_data) {
- ERR_FAIL_COND(p_data.is_null());
- data.push_back(p_data);
- rids.push_back(RID());
+ variation = Variation();
+ opentype_features = Dictionary();
- if (data[data.size() - 1].is_valid()) {
- data.write[data.size() - 1]->connect(SNAME("changed"), callable_mp(this, &Font::_data_changed), varray(), CONNECT_REFERENCE_COUNTED);
- Dictionary data_var_list = p_data->get_supported_variation_list();
- for (int j = 0; j < data_var_list.size(); j++) {
- int32_t tag = data_var_list.get_key_at_index(j);
- Vector3i value = data_var_list.get_value_at_index(j);
- if (!variation_coordinates.has(tag) && !variation_coordinates.has(TS->tag_to_name(tag))) {
- variation_coordinates[TS->tag_to_name(tag)] = value.z;
- }
- }
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ extra_spacing[i] = 0;
}
- cache.clear();
- cache_wrap.clear();
-
- emit_changed();
- notify_property_list_changed();
+ Font::reset_state();
}
-void Font::set_data(int p_idx, const Ref<FontData> &p_data) {
- ERR_FAIL_COND(p_data.is_null());
- ERR_FAIL_INDEX(p_idx, data.size());
-
- if (data[p_idx].is_valid()) {
- data.write[p_idx]->disconnect(SNAME("changed"), callable_mp(this, &Font::_data_changed));
- }
-
- data.write[p_idx] = p_data;
- rids.write[p_idx] = RID();
- Dictionary data_var_list = p_data->get_supported_variation_list();
- for (int j = 0; j < data_var_list.size(); j++) {
- int32_t tag = data_var_list.get_key_at_index(j);
- Vector3i value = data_var_list.get_value_at_index(j);
- if (!variation_coordinates.has(tag) && !variation_coordinates.has(TS->tag_to_name(tag))) {
- variation_coordinates[TS->tag_to_name(tag)] = value.z;
+void FontVariation::set_base_font(const Ref<Font> &p_font) {
+ if (base_font != p_font) {
+ if (base_font.is_valid()) {
+ base_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
}
+ base_font = p_font;
+ if (base_font.is_valid()) {
+ base_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ _invalidate_rids();
+ notify_property_list_changed();
}
-
- if (data[p_idx].is_valid()) {
- data.write[p_idx]->connect(SNAME("changed"), callable_mp(this, &Font::_data_changed), varray(), CONNECT_REFERENCE_COUNTED);
- }
-
- cache.clear();
- cache_wrap.clear();
-
- emit_changed();
- notify_property_list_changed();
-}
-
-int Font::get_data_count() const {
- return data.size();
-}
-
-Ref<FontData> Font::get_data(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, data.size(), Ref<FontData>());
- return data[p_idx];
}
-RID Font::get_data_rid(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, data.size(), RID());
- _ensure_rid(p_idx);
- return rids[p_idx];
+Ref<Font> FontVariation::get_base_font() const {
+ return base_font;
}
-void Font::clear_data() {
- for (int i = 0; i < data.size(); i++) {
- if (data[i].is_valid()) {
- data.write[i]->connect(SNAME("changed"), callable_mp(this, &Font::_data_changed), varray(), CONNECT_REFERENCE_COUNTED);
- }
+Ref<Font> FontVariation::_get_base_font_or_default() const {
+ if (theme_font.is_valid()) {
+ theme_font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids));
+ theme_font.unref();
}
- data.clear();
- rids.clear();
-}
-
-void Font::remove_data(int p_idx) {
- ERR_FAIL_INDEX(p_idx, data.size());
- if (data[p_idx].is_valid()) {
- data.write[p_idx]->disconnect(SNAME("changed"), callable_mp(this, &Font::_data_changed));
+ if (base_font.is_valid()) {
+ return base_font;
}
- data.remove_at(p_idx);
- rids.remove_at(p_idx);
-
- cache.clear();
- cache_wrap.clear();
+ // Check the project-defined Theme resource.
+ if (Theme::get_project_default().is_valid()) {
+ List<StringName> theme_types;
+ Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
- emit_changed();
- notify_property_list_changed();
-}
+ for (const StringName &E : theme_types) {
+ if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (f.is_valid()) {
+ theme_font = f;
+ theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ return f;
+ }
+ }
+ }
-void Font::set_variation_coordinates(const Dictionary &p_variation_coordinates) {
- _data_changed();
- variation_coordinates = p_variation_coordinates;
-}
+ // Lastly, fall back on the items defined in the default Theme, if they exist.
+ if (Theme::get_default().is_valid()) {
+ List<StringName> theme_types;
+ Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
-Dictionary Font::get_variation_coordinates() const {
- return variation_coordinates;
-}
+ for (const StringName &E : theme_types) {
+ if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (f.is_valid()) {
+ theme_font = f;
+ theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ return f;
+ }
+ }
-void Font::set_spacing(TextServer::SpacingType p_spacing, int p_value) {
- _data_changed();
- switch (p_spacing) {
- case TextServer::SPACING_TOP: {
- spacing_top = p_value;
- } break;
- case TextServer::SPACING_BOTTOM: {
- spacing_bottom = p_value;
- } break;
- default: {
- ERR_FAIL_MSG("Invalid spacing type: " + itos(p_spacing));
- } break;
+ // If they don't exist, use any type to return the default/empty value.
+ Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
+ if (f.is_valid()) {
+ theme_font = f;
+ theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ return f;
}
-}
-int Font::get_spacing(TextServer::SpacingType p_spacing) const {
- switch (p_spacing) {
- case TextServer::SPACING_TOP: {
- return spacing_top;
- } break;
- case TextServer::SPACING_BOTTOM: {
- return spacing_bottom;
- } break;
- default: {
- ERR_FAIL_V_MSG(0, "Invalid spacing type: " + itos(p_spacing));
- } break;
- }
+ return Ref<Font>();
}
-real_t Font::get_height(int p_size) const {
- real_t ret = 0.f;
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- ret = MAX(ret, TS->font_get_ascent(rids[i], p_size) + TS->font_get_descent(rids[i], p_size));
+void FontVariation::set_variation_opentype(const Dictionary &p_coords) {
+ if (variation.opentype != p_coords) {
+ variation.opentype = p_coords;
+ _invalidate_rids();
}
- return ret + spacing_bottom + spacing_top;
}
-real_t Font::get_ascent(int p_size) const {
- real_t ret = 0.f;
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- ret = MAX(ret, TS->font_get_ascent(rids[i], p_size));
- }
- return ret + spacing_top;
+Dictionary FontVariation::get_variation_opentype() const {
+ return variation.opentype;
}
-real_t Font::get_descent(int p_size) const {
- real_t ret = 0.f;
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- ret = MAX(ret, TS->font_get_descent(rids[i], p_size));
+void FontVariation::set_variation_embolden(float p_strength) {
+ if (variation.embolden != p_strength) {
+ variation.embolden = p_strength;
+ _invalidate_rids();
}
- return ret + spacing_bottom;
}
-real_t Font::get_underline_position(int p_size) const {
- real_t ret = 0.f;
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- ret = MAX(ret, TS->font_get_underline_position(rids[i], p_size));
- }
- return ret + spacing_top;
+float FontVariation::get_variation_embolden() const {
+ return variation.embolden;
}
-real_t Font::get_underline_thickness(int p_size) const {
- real_t ret = 0.f;
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- ret = MAX(ret, TS->font_get_underline_thickness(rids[i], p_size));
+void FontVariation::set_variation_transform(Transform2D p_transform) {
+ if (variation.transform != p_transform) {
+ variation.transform = p_transform;
+ _invalidate_rids();
}
- return ret;
}
-Size2 Font::get_string_size(const String &p_text, int p_size, HorizontalAlignment p_alignment, float p_width, uint16_t p_flags) const {
- ERR_FAIL_COND_V(data.is_empty(), Size2());
-
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- }
-
- uint64_t hash = p_text.hash64();
- if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash);
- hash = hash_djb2_one_64(p_flags, hash);
- }
- hash = hash_djb2_one_64(p_size, hash);
-
- Ref<TextLine> buffer;
- if (cache.has(hash)) {
- buffer = cache.get(hash);
- } else {
- buffer.instantiate();
- buffer->add_string(p_text, Ref<Font>(this), p_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale());
- cache.insert(hash, buffer);
- }
- return buffer->get_size();
+Transform2D FontVariation::get_variation_transform() const {
+ return variation.transform;
}
-Size2 Font::get_multiline_string_size(const String &p_text, float p_width, int p_size, uint16_t p_flags) const {
- ERR_FAIL_COND_V(data.is_empty(), Size2());
-
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- }
-
- uint64_t hash = p_text.hash64();
- uint64_t wrp_hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash);
- wrp_hash = hash_djb2_one_64(p_flags, wrp_hash);
- wrp_hash = hash_djb2_one_64(p_size, wrp_hash);
-
- Ref<TextParagraph> lines_buffer;
- if (cache_wrap.has(wrp_hash)) {
- lines_buffer = cache_wrap.get(wrp_hash);
- } else {
- lines_buffer.instantiate();
- lines_buffer->add_string(p_text, Ref<Font>(this), p_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale());
- lines_buffer->set_width(p_width);
- lines_buffer->set_flags(p_flags);
- cache_wrap.insert(wrp_hash, lines_buffer);
- }
-
- Size2 ret;
- for (int i = 0; i < lines_buffer->get_line_count(); i++) {
- Size2 line_size = lines_buffer->get_line_size(i);
- if (lines_buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) {
- ret.x = MAX(ret.x, line_size.x);
- ret.y += line_size.y;
- } else {
- ret.y = MAX(ret.y, line_size.y);
- ret.x += line_size.x;
- }
+void FontVariation::set_variation_face_index(int p_face_index) {
+ if (variation.face_index != p_face_index) {
+ variation.face_index = p_face_index;
+ _invalidate_rids();
}
- return ret;
}
-void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint16_t p_flags) const {
- ERR_FAIL_COND(data.is_empty());
-
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- }
-
- uint64_t hash = p_text.hash64();
- if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash);
- hash = hash_djb2_one_64(p_flags, hash);
- }
- hash = hash_djb2_one_64(p_size, hash);
-
- Ref<TextLine> buffer;
- if (cache.has(hash)) {
- buffer = cache.get(hash);
- } else {
- buffer.instantiate();
- buffer->add_string(p_text, Ref<Font>(this), p_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale());
- cache.insert(hash, buffer);
- }
-
- Vector2 ofs = p_pos;
- if (buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y -= buffer->get_line_ascent();
- } else {
- ofs.x -= buffer->get_line_ascent();
- }
-
- buffer->set_width(p_width);
- buffer->set_horizontal_alignment(p_alignment);
- buffer->set_flags(p_flags);
-
- if (p_outline_size > 0 && p_outline_modulate.a != 0.0f) {
- buffer->draw_outline(p_canvas_item, ofs, p_outline_size, p_outline_modulate);
- }
- buffer->draw(p_canvas_item, ofs, p_modulate);
+int FontVariation::get_variation_face_index() const {
+ return variation.face_index;
}
-void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint16_t p_flags) const {
- ERR_FAIL_COND(data.is_empty());
-
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- }
-
- uint64_t hash = p_text.hash64();
- uint64_t wrp_hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash);
- wrp_hash = hash_djb2_one_64(p_flags, wrp_hash);
- wrp_hash = hash_djb2_one_64(p_size, wrp_hash);
-
- Ref<TextParagraph> lines_buffer;
- if (cache_wrap.has(wrp_hash)) {
- lines_buffer = cache_wrap.get(wrp_hash);
- } else {
- lines_buffer.instantiate();
- lines_buffer->add_string(p_text, Ref<Font>(this), p_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale());
- lines_buffer->set_width(p_width);
- lines_buffer->set_flags(p_flags);
- cache_wrap.insert(wrp_hash, lines_buffer);
- }
-
- lines_buffer->set_alignment(p_alignment);
-
- Vector2 lofs = p_pos;
- for (int i = 0; i < lines_buffer->get_line_count(); i++) {
- if (lines_buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) {
- if (i == 0) {
- lofs.y -= lines_buffer->get_line_ascent(0);
- }
- } else {
- if (i == 0) {
- lofs.x -= lines_buffer->get_line_ascent(0);
- }
- }
- if (p_width > 0) {
- lines_buffer->set_alignment(p_alignment);
- }
-
- if (p_outline_size > 0 && p_outline_modulate.a != 0.0f) {
- lines_buffer->draw_line_outline(p_canvas_item, lofs, i, p_outline_size, p_outline_modulate);
- }
- lines_buffer->draw_line(p_canvas_item, lofs, i, p_modulate);
-
- Size2 line_size = lines_buffer->get_line_size(i);
- if (lines_buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) {
- lofs.y += line_size.y;
- } else {
- lofs.x += line_size.x;
- }
-
- if ((p_max_lines > 0) && (i >= p_max_lines)) {
- return;
- }
+void FontVariation::set_opentype_features(const Dictionary &p_features) {
+ if (opentype_features != p_features) {
+ opentype_features = p_features;
+ _invalidate_rids();
}
}
-Size2 Font::get_char_size(char32_t p_char, char32_t p_next, int p_size) const {
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- if (data[i]->has_char(p_char)) {
- int32_t glyph_a = TS->font_get_glyph_index(rids[i], p_size, p_char, 0);
- Size2 ret = Size2(TS->font_get_glyph_advance(rids[i], p_size, glyph_a).x, TS->font_get_ascent(rids[i], p_size) + TS->font_get_descent(rids[i], p_size));
- if ((p_next != 0) && data[i]->has_char(p_next)) {
- int32_t glyph_b = TS->font_get_glyph_index(rids[i], p_size, p_next, 0);
- ret.x -= TS->font_get_kerning(rids[i], p_size, Vector2i(glyph_a, glyph_b)).x;
- }
- return ret;
- }
- }
- return Size2();
+Dictionary FontVariation::get_opentype_features() const {
+ return opentype_features;
}
-real_t Font::draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate) const {
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- if (data[i]->has_char(p_char)) {
- int32_t glyph_a = TS->font_get_glyph_index(rids[i], p_size, p_char, 0);
- real_t ret = TS->font_get_glyph_advance(rids[i], p_size, glyph_a).x;
- if ((p_next != 0) && data[i]->has_char(p_next)) {
- int32_t glyph_b = TS->font_get_glyph_index(rids[i], p_size, p_next, 0);
- ret -= TS->font_get_kerning(rids[i], p_size, Vector2i(glyph_a, glyph_b)).x;
- }
-
- if (p_outline_size > 0 && p_outline_modulate.a != 0.0f) {
- TS->font_draw_glyph_outline(rids[i], p_canvas_item, p_size, p_outline_size, p_pos, glyph_a, p_outline_modulate);
- }
- TS->font_draw_glyph(rids[i], p_canvas_item, p_size, p_pos, glyph_a, p_modulate);
- return ret;
- }
+void FontVariation::set_spacing(TextServer::SpacingType p_spacing, int p_value) {
+ ERR_FAIL_INDEX((int)p_spacing, TextServer::SPACING_MAX);
+ if (extra_spacing[p_spacing] != p_value) {
+ extra_spacing[p_spacing] = p_value;
+ _invalidate_rids();
}
- return 0;
}
-bool Font::has_char(char32_t p_char) const {
- for (int i = 0; i < data.size(); i++) {
- if (data[i]->has_char(p_char)) {
- return true;
- }
- }
- return false;
+int FontVariation::get_spacing(TextServer::SpacingType p_spacing) const {
+ ERR_FAIL_INDEX_V((int)p_spacing, TextServer::SPACING_MAX, 0);
+ return extra_spacing[p_spacing];
}
-String Font::get_supported_chars() const {
- String chars;
- for (int i = 0; i < data.size(); i++) {
- String data_chars = data[i]->get_supported_chars();
- for (int j = 0; j < data_chars.length(); j++) {
- if (chars.find_char(data_chars[j]) == -1) {
- chars += data_chars[j];
- }
- }
+RID FontVariation::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform) const {
+ Ref<Font> f = _get_base_font_or_default();
+ if (f.is_valid()) {
+ return f->find_variation(p_variation_coordinates, p_face_index, p_strength, p_transform);
}
- return chars;
+ return RID();
}
-Array Font::get_rids() const {
- Array _rids;
- for (int i = 0; i < data.size(); i++) {
- _ensure_rid(i);
- if (rids[i].is_valid()) {
- _rids.push_back(rids[i]);
- }
+RID FontVariation::_get_rid() const {
+ Ref<Font> f = _get_base_font_or_default();
+ if (f.is_valid()) {
+ return f->find_variation(variation.opentype, variation.face_index, variation.embolden, variation.transform);
}
- return _rids;
-}
-
-void Font::update_changes() {
- emit_changed();
+ return RID();
}
-Font::Font() {
- cache.set_capacity(128);
- cache_wrap.set_capacity(32);
+FontVariation::FontVariation() {
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ extra_spacing[i] = 0;
+ }
}
-Font::~Font() {
- clear_data();
- cache.clear();
- cache_wrap.clear();
+FontVariation::~FontVariation() {
+ reset_state();
}
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 2aa12dd2de..7a42a4dfea 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -33,14 +33,107 @@
#include "core/io/resource.h"
#include "core/templates/lru.h"
-#include "core/templates/map.h"
+#include "core/templates/rb_map.h"
#include "scene/resources/texture.h"
#include "servers/text_server.h"
+class TextLine;
+class TextParagraph;
+
+/*************************************************************************/
+/* Font */
/*************************************************************************/
-class FontData : public Resource {
- GDCLASS(FontData, Resource);
+class Font : public Resource {
+ GDCLASS(Font, Resource);
+
+ // Shaped string cache.
+ mutable LRUCache<uint64_t, Ref<TextLine>> cache;
+ mutable LRUCache<uint64_t, Ref<TextParagraph>> cache_wrap;
+
+protected:
+ // Output.
+ mutable TypedArray<RID> rids;
+ mutable bool dirty_rids = true;
+
+ // Fallbacks.
+ static constexpr int MAX_FALLBACK_DEPTH = 64;
+ TypedArray<Font> fallbacks;
+
+ static void _bind_methods();
+
+ virtual void _update_rids_fb(const Ref<Font> &p_f, int p_depth) const;
+ virtual void _update_rids() const;
+ virtual bool _is_cyclic(const Ref<Font> &p_f, int p_depth) const;
+
+ virtual void reset_state() override;
+
+public:
+ virtual void _invalidate_rids();
+
+ static constexpr int DEFAULT_FONT_SIZE = 16;
+
+ // Fallbacks.
+ virtual void set_fallbacks(const TypedArray<Font> &p_fallbacks);
+ virtual TypedArray<Font> get_fallbacks() const;
+
+ // Output.
+ virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D()) const { return RID(); };
+ virtual RID _get_rid() const { return RID(); };
+ virtual TypedArray<RID> get_rids() const;
+
+ // Font metrics.
+ virtual real_t get_height(int p_font_size) const;
+ virtual real_t get_ascent(int p_font_size) const;
+ virtual real_t get_descent(int p_font_size) const;
+ virtual real_t get_underline_position(int p_font_size) const;
+ virtual real_t get_underline_thickness(int p_font_size) const;
+
+ virtual String get_font_name() const;
+ virtual String get_font_style_name() const;
+ virtual BitField<TextServer::FontStyle> get_font_style() const;
+
+ virtual int get_spacing(TextServer::SpacingType p_spacing) const { return 0; };
+ virtual Dictionary get_opentype_features() const;
+
+ // Drawing string.
+ virtual void set_cache_capacity(int p_single_line, int p_multi_line);
+
+ virtual Size2 get_string_size(const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = DEFAULT_FONT_SIZE, BitField<TextServer::JustificationFlag> p_jst_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
+ virtual Size2 get_multiline_string_size(const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = DEFAULT_FONT_SIZE, int p_max_lines = -1, BitField<TextServer::LineBreakFlag> p_brk_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND, BitField<TextServer::JustificationFlag> p_jst_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
+
+ virtual void draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = DEFAULT_FONT_SIZE, const Color &p_modulate = Color(1.0, 1.0, 1.0), BitField<TextServer::JustificationFlag> p_jst_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
+ virtual void draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = DEFAULT_FONT_SIZE, int p_max_lines = -1, const Color &p_modulate = Color(1.0, 1.0, 1.0), BitField<TextServer::LineBreakFlag> p_brk_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND, BitField<TextServer::JustificationFlag> p_jst_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
+
+ virtual void draw_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = DEFAULT_FONT_SIZE, int p_size = 1, const Color &p_modulate = Color(1.0, 1.0, 1.0), BitField<TextServer::JustificationFlag> p_jst_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
+ virtual void draw_multiline_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_font_size = DEFAULT_FONT_SIZE, int p_max_lines = -1, int p_size = 1, const Color &p_modulate = Color(1.0, 1.0, 1.0), BitField<TextServer::LineBreakFlag> p_brk_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND, BitField<TextServer::JustificationFlag> p_jst_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL) const;
+
+ // Drawing char.
+ virtual Size2 get_char_size(char32_t p_char, int p_font_size = DEFAULT_FONT_SIZE) const;
+ virtual real_t draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, int p_font_size = DEFAULT_FONT_SIZE, const Color &p_modulate = Color(1.0, 1.0, 1.0)) const;
+ virtual real_t draw_char_outline(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, int p_font_size = DEFAULT_FONT_SIZE, int p_size = 1, const Color &p_modulate = Color(1.0, 1.0, 1.0)) const;
+
+ // Helper functions.
+ virtual bool has_char(char32_t p_char) const;
+ virtual String get_supported_chars() const;
+
+ virtual bool is_language_supported(const String &p_language) const;
+ virtual bool is_script_supported(const String &p_script) const;
+
+ virtual Dictionary get_supported_feature_list() const;
+ virtual Dictionary get_supported_variation_list() const;
+ virtual int64_t get_face_count() const;
+
+ Font();
+ ~Font();
+};
+
+/*************************************************************************/
+/* FontFile */
+/*************************************************************************/
+
+class FontFile : public Font {
+ GDCLASS(FontFile, Font);
RES_BASE_EXTENSION("fontdata");
// Font source data.
@@ -49,6 +142,7 @@ class FontData : public Resource {
PackedByteArray data;
bool antialiased = true;
+ bool mipmaps = false;
bool msdf = false;
int msdf_pixel_range = 16;
int msdf_size = 48;
@@ -57,8 +151,11 @@ class FontData : public Resource {
TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
real_t oversampling = 0.f;
- real_t embolden = 0.f;
- Transform2D transform;
+
+#ifndef DISABLE_DEPRECATED
+ real_t bmp_height = 0.0;
+ real_t bmp_ascent = 0.0;
+#endif
// Cache.
mutable Vector<RID> cache;
@@ -92,17 +189,15 @@ public:
// Common properties.
virtual void set_font_name(const String &p_name);
- virtual String get_font_name() const;
-
virtual void set_font_style_name(const String &p_name);
- virtual String get_font_style_name() const;
-
- virtual void set_font_style(uint32_t p_style);
- virtual uint32_t get_font_style() const;
+ virtual void set_font_style(BitField<TextServer::FontStyle> p_style);
virtual void set_antialiased(bool p_antialiased);
virtual bool is_antialiased() const;
+ virtual void set_generate_mipmaps(bool p_generate_mipmaps);
+ virtual bool get_generate_mipmaps() const;
+
virtual void set_multichannel_signed_distance_field(bool p_msdf);
virtual bool is_multichannel_signed_distance_field() const;
@@ -124,17 +219,12 @@ public:
virtual void set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel);
virtual TextServer::SubpixelPositioning get_subpixel_positioning() const;
- virtual void set_embolden(float p_strength);
- virtual float get_embolden() const;
-
- virtual void set_transform(Transform2D p_transform);
- virtual Transform2D get_transform() const;
-
virtual void set_oversampling(real_t p_oversampling);
virtual real_t get_oversampling() const;
// Cache.
- virtual RID find_cache(const Dictionary &p_variation_coordinates) const;
+ virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D()) const override;
+ virtual RID _get_rid() const override;
virtual int get_cache_count() const;
virtual void clear_cache();
@@ -147,23 +237,29 @@ public:
virtual void set_variation_coordinates(int p_cache_index, const Dictionary &p_variation_coordinates);
virtual Dictionary get_variation_coordinates(int p_cache_index) const;
- virtual void set_ascent(int p_cache_index, int p_size, real_t p_ascent);
- virtual real_t get_ascent(int p_cache_index, int p_size) const;
+ virtual void set_embolden(int p_cache_index, float p_strength);
+ virtual float get_embolden(int p_cache_index) const;
+
+ virtual void set_transform(int p_cache_index, Transform2D p_transform);
+ virtual Transform2D get_transform(int p_cache_index) const;
- virtual void set_descent(int p_cache_index, int p_size, real_t p_descent);
- virtual real_t get_descent(int p_cache_index, int p_size) const;
+ virtual void set_face_index(int p_cache_index, int64_t p_index);
+ virtual int64_t get_face_index(int p_cache_index) const;
- virtual void set_underline_position(int p_cache_index, int p_size, real_t p_underline_position);
- virtual real_t get_underline_position(int p_cache_index, int p_size) const;
+ virtual void set_cache_ascent(int p_cache_index, int p_size, real_t p_ascent);
+ virtual real_t get_cache_ascent(int p_cache_index, int p_size) const;
- virtual void set_underline_thickness(int p_cache_index, int p_size, real_t p_underline_thickness);
- virtual real_t get_underline_thickness(int p_cache_index, int p_size) const;
+ virtual void set_cache_descent(int p_cache_index, int p_size, real_t p_descent);
+ virtual real_t get_cache_descent(int p_cache_index, int p_size) const;
- virtual void set_scale(int p_cache_index, int p_size, real_t p_scale); // Rendering scale for bitmap fonts (e.g. emoji fonts).
- virtual real_t get_scale(int p_cache_index, int p_size) const;
+ virtual void set_cache_underline_position(int p_cache_index, int p_size, real_t p_underline_position);
+ virtual real_t get_cache_underline_position(int p_cache_index, int p_size) const;
- virtual void set_spacing(int p_cache_index, int p_size, TextServer::SpacingType p_spacing, int p_value);
- virtual int get_spacing(int p_cache_index, int p_size, TextServer::SpacingType p_spacing) const;
+ virtual void set_cache_underline_thickness(int p_cache_index, int p_size, real_t p_underline_thickness);
+ virtual real_t get_cache_underline_thickness(int p_cache_index, int p_size) const;
+
+ virtual void set_cache_scale(int p_cache_index, int p_size, real_t p_scale); // Rendering scale for bitmap fonts (e.g. emoji fonts).
+ virtual real_t get_cache_scale(int p_cache_index, int p_size) const;
virtual int get_texture_count(int p_cache_index, const Vector2i &p_size) const;
virtual void clear_textures(int p_cache_index, const Vector2i &p_size);
@@ -204,16 +300,12 @@ public:
virtual void render_range(int p_cache_index, const Vector2i &p_size, char32_t p_start, char32_t p_end);
virtual void render_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_index);
- virtual RID get_cache_rid(int p_cache_index) const;
-
// Language/script support override.
- virtual bool is_language_supported(const String &p_language) const;
virtual void set_language_support_override(const String &p_language, bool p_supported);
virtual bool get_language_support_override(const String &p_language) const;
virtual void remove_language_support_override(const String &p_language);
virtual Vector<String> get_language_support_overrides() const;
- virtual bool is_script_supported(const String &p_script) const;
virtual void set_script_support_override(const String &p_script, bool p_supported);
virtual bool get_script_support_override(const String &p_script) const;
virtual void remove_script_support_override(const String &p_script);
@@ -223,100 +315,70 @@ public:
virtual Dictionary get_opentype_feature_overrides() const;
// Base font properties.
- virtual bool has_char(char32_t p_char) const;
- virtual String get_supported_chars() const;
-
virtual int32_t get_glyph_index(int p_size, char32_t p_char, char32_t p_variation_selector = 0x0000) const;
- virtual Dictionary get_supported_feature_list() const;
- virtual Dictionary get_supported_variation_list() const;
-
- FontData();
- ~FontData();
+ FontFile();
+ ~FontFile();
};
/*************************************************************************/
+/* FontVariation */
+/*************************************************************************/
-class TextLine;
-class TextParagraph;
-
-class Font : public Resource {
- GDCLASS(Font, Resource);
+class FontVariation : public Font {
+ GDCLASS(FontVariation, Font);
- // Shaped string cache.
- mutable LRUCache<uint64_t, Ref<TextLine>> cache;
- mutable LRUCache<uint64_t, Ref<TextParagraph>> cache_wrap;
+ struct Variation {
+ Dictionary opentype;
+ real_t embolden = 0.f;
+ int face_index = 0;
+ Transform2D transform;
+ };
- // Font data cache.
- Vector<Ref<FontData>> data;
- mutable Vector<RID> rids;
+ mutable Ref<Font> theme_font;
- // Font config.
- Dictionary variation_coordinates;
- int spacing_bottom = 0;
- int spacing_top = 0;
+ Ref<Font> base_font;
- _FORCE_INLINE_ void _data_changed();
- _FORCE_INLINE_ void _ensure_rid(int p_index) const; // Find or create cache record.
+ Variation variation;
+ Dictionary opentype_features;
+ int extra_spacing[TextServer::SPACING_MAX];
protected:
static void _bind_methods();
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void _update_rids() const override;
virtual void reset_state() override;
public:
- static const int DEFAULT_FONT_SIZE = 16;
-
- Dictionary get_feature_list() const;
-
- // Font data.
- virtual void add_data(const Ref<FontData> &p_data);
- virtual void set_data(int p_idx, const Ref<FontData> &p_data);
- virtual int get_data_count() const;
- virtual Ref<FontData> get_data(int p_idx) const;
- virtual RID get_data_rid(int p_idx) const;
- virtual void clear_data();
- virtual void remove_data(int p_idx);
+ virtual void set_base_font(const Ref<Font> &p_font);
+ virtual Ref<Font> get_base_font() const;
+ virtual Ref<Font> _get_base_font_or_default() const;
- // Font configuration.
- virtual void set_variation_coordinates(const Dictionary &p_variation_coordinates);
- virtual Dictionary get_variation_coordinates() const;
+ virtual void set_variation_opentype(const Dictionary &p_coords);
+ virtual Dictionary get_variation_opentype() const;
- virtual void set_spacing(TextServer::SpacingType p_spacing, int p_value);
- virtual int get_spacing(TextServer::SpacingType p_spacing) const;
-
- // Font metrics.
- virtual real_t get_height(int p_size = DEFAULT_FONT_SIZE) const;
- virtual real_t get_ascent(int p_size = DEFAULT_FONT_SIZE) const;
- virtual real_t get_descent(int p_size = DEFAULT_FONT_SIZE) const;
- virtual real_t get_underline_position(int p_size = DEFAULT_FONT_SIZE) const;
- virtual real_t get_underline_thickness(int p_size = DEFAULT_FONT_SIZE) const;
+ virtual void set_variation_embolden(float p_strength);
+ virtual float get_variation_embolden() const;
- // Drawing string.
- virtual Size2 get_string_size(const String &p_text, int p_size = DEFAULT_FONT_SIZE, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, uint16_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
- virtual Size2 get_multiline_string_size(const String &p_text, float p_width = -1, int p_size = DEFAULT_FONT_SIZE, uint16_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND) const;
-
- virtual void draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_size = DEFAULT_FONT_SIZE, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint16_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
- virtual void draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment = HORIZONTAL_ALIGNMENT_LEFT, float p_width = -1, int p_max_lines = -1, int p_size = DEFAULT_FONT_SIZE, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint16_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
+ virtual void set_variation_transform(Transform2D p_transform);
+ virtual Transform2D get_variation_transform() const;
- // Helper functions.
- virtual bool has_char(char32_t p_char) const;
- virtual String get_supported_chars() const;
+ virtual void set_variation_face_index(int p_face_index);
+ virtual int get_variation_face_index() const;
- // Drawing char.
- virtual Size2 get_char_size(char32_t p_char, char32_t p_next = 0, int p_size = DEFAULT_FONT_SIZE) const;
- virtual real_t draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next = 0, int p_size = DEFAULT_FONT_SIZE, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0)) const;
+ virtual void set_opentype_features(const Dictionary &p_features);
+ virtual Dictionary get_opentype_features() const override;
- Array get_rids() const;
+ virtual void set_spacing(TextServer::SpacingType p_spacing, int p_value);
+ virtual int get_spacing(TextServer::SpacingType p_spacing) const override;
- void update_changes();
+ // Output.
+ virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D()) const override;
+ virtual RID _get_rid() const override;
- Font();
- ~Font();
+ FontVariation();
+ ~FontVariation();
};
#endif /* FONT_H */
diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp
index caaa3d8628..a9c44dc6bf 100644
--- a/scene/resources/gradient.cpp
+++ b/scene/resources/gradient.cpp
@@ -157,7 +157,7 @@ void Gradient::reverse() {
emit_signal(CoreStringNames::get_singleton()->changed);
}
-void Gradient::set_points(Vector<Gradient::Point> &p_points) {
+void Gradient::set_points(const Vector<Gradient::Point> &p_points) {
points = p_points;
is_sorted = false;
emit_signal(CoreStringNames::get_singleton()->changed);
diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h
index c2085b3a13..e4bac15e4b 100644
--- a/scene/resources/gradient.h
+++ b/scene/resources/gradient.h
@@ -73,7 +73,7 @@ public:
void add_point(float p_offset, const Color &p_color);
void remove_point(int p_index);
- void set_points(Vector<Point> &p_points);
+ void set_points(const Vector<Point> &p_points);
Vector<Point> &get_points();
void reverse();
@@ -92,10 +92,6 @@ public:
void set_interpolation_mode(InterpolationMode p_interp_mode);
InterpolationMode get_interpolation_mode();
- _FORCE_INLINE_ float cubic_interpolate(float p0, float p1, float p2, float p3, float x) {
- return p1 + 0.5 * x * (p2 - p0 + x * (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3 + x * (3.0 * (p1 - p2) + p3 - p0)));
- }
-
_FORCE_INLINE_ Color get_color_at_offset(float p_offset) {
if (points.is_empty()) {
return Color(0, 0, 0, 1);
@@ -161,10 +157,10 @@ public:
const Point &pointP3 = points[p3];
float x = (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset);
- float r = cubic_interpolate(pointP0.color.r, pointFirst.color.r, pointSecond.color.r, pointP3.color.r, x);
- float g = cubic_interpolate(pointP0.color.g, pointFirst.color.g, pointSecond.color.g, pointP3.color.g, x);
- float b = cubic_interpolate(pointP0.color.b, pointFirst.color.b, pointSecond.color.b, pointP3.color.b, x);
- float a = cubic_interpolate(pointP0.color.a, pointFirst.color.a, pointSecond.color.a, pointP3.color.a, x);
+ float r = Math::cubic_interpolate(pointFirst.color.r, pointSecond.color.r, pointP0.color.r, pointP3.color.r, x);
+ float g = Math::cubic_interpolate(pointFirst.color.g, pointSecond.color.g, pointP0.color.g, pointP3.color.g, x);
+ float b = Math::cubic_interpolate(pointFirst.color.b, pointSecond.color.b, pointP0.color.b, pointP3.color.b, x);
+ float a = Math::cubic_interpolate(pointFirst.color.a, pointSecond.color.a, pointP0.color.a, pointP3.color.a, x);
return Color(r, g, b, a);
} break;
diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp
index 28afef8638..044477e744 100644
--- a/scene/resources/immediate_mesh.cpp
+++ b/scene/resources/immediate_mesh.cpp
@@ -211,7 +211,7 @@ void ImmediateMesh::surface_end() {
value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
if (t.d > 0) {
- value |= 3 << 30;
+ value |= 3UL << 30;
}
*tangent = value;
diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp
index 60a9200176..293fdd6f05 100644
--- a/scene/resources/importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -306,7 +306,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
float normal_split_threshold = Math::cos(Math::deg2rad(p_normal_split_angle));
const Vector3 *normals_ptr = normals.ptr();
- Map<Vector3, LocalVector<Pair<int, int>>> unique_vertices;
+ HashMap<Vector3, LocalVector<Pair<int, int>>> unique_vertices;
LocalVector<int> vertex_remap;
LocalVector<int> vertex_inverse_remap;
@@ -320,10 +320,10 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
const Vector3 &v = vertices_ptr[j];
const Vector3 &n = normals_ptr[j];
- Map<Vector3, LocalVector<Pair<int, int>>>::Element *E = unique_vertices.find(v);
+ HashMap<Vector3, LocalVector<Pair<int, int>>>::Iterator E = unique_vertices.find(v);
if (E) {
- const LocalVector<Pair<int, int>> &close_verts = E->get();
+ const LocalVector<Pair<int, int>> &close_verts = E->value;
bool found = false;
for (unsigned int k = 0; k < close_verts.size(); k++) {
@@ -331,6 +331,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
bool is_uvs_close = (!uvs_ptr || uvs_ptr[j].distance_squared_to(uvs_ptr[idx.second]) < CMP_EPSILON2);
bool is_uv2s_close = (!uv2s_ptr || uv2s_ptr[j].distance_squared_to(uv2s_ptr[idx.second]) < CMP_EPSILON2);
+ ERR_FAIL_INDEX(idx.second, normals.size());
bool is_normals_close = normals[idx.second].dot(n) > normal_merge_threshold;
if (is_uvs_close && is_uv2s_close && is_normals_close) {
vertex_remap.push_back(idx.first);
@@ -706,15 +707,15 @@ void ImporterMesh::create_shadow_mesh() {
Vector<Vector3> vertices = surfaces[i].arrays[RS::ARRAY_VERTEX];
int vertex_count = vertices.size();
{
- Map<Vector3, int> unique_vertices;
+ HashMap<Vector3, int> unique_vertices;
const Vector3 *vptr = vertices.ptr();
for (int j = 0; j < vertex_count; j++) {
const Vector3 &v = vptr[j];
- Map<Vector3, int>::Element *E = unique_vertices.find(v);
+ HashMap<Vector3, int>::Iterator E = unique_vertices.find(v);
if (E) {
- vertex_remap.push_back(E->get());
+ vertex_remap.push_back(E->value);
} else {
int vcount = unique_vertices.size();
unique_vertices[v] = vcount;
@@ -898,16 +899,16 @@ Vector<Ref<Shape3D>> ImporterMesh::convex_decompose(const Mesh::ConvexDecomposit
Vector<uint32_t> indices;
indices.resize(face_count * 3);
{
- Map<Vector3, uint32_t> vertex_map;
+ HashMap<Vector3, uint32_t> vertex_map;
Vector3 *vertex_w = vertices.ptrw();
uint32_t *index_w = indices.ptrw();
for (int i = 0; i < face_count; i++) {
for (int j = 0; j < 3; j++) {
const Vector3 &vertex = faces[i].vertex[j];
- Map<Vector3, uint32_t>::Element *found_vertex = vertex_map.find(vertex);
+ HashMap<Vector3, uint32_t>::Iterator found_vertex = vertex_map.find(vertex);
uint32_t index;
if (found_vertex) {
- index = found_vertex->get();
+ index = found_vertex->value;
} else {
index = ++vertex_count;
vertex_map[vertex] = index;
@@ -960,7 +961,7 @@ Ref<NavigationMesh> ImporterMesh::create_navigation_mesh() {
return Ref<NavigationMesh>();
}
- Map<Vector3, int> unique_vertices;
+ HashMap<Vector3, int> unique_vertices;
LocalVector<int> face_indices;
for (int i = 0; i < faces.size(); i++) {
@@ -1023,7 +1024,7 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
// Keep only the scale
Basis basis = p_base_transform.get_basis();
- Vector3 scale = Vector3(basis.get_axis(0).length(), basis.get_axis(1).length(), basis.get_axis(2).length());
+ Vector3 scale = Vector3(basis.get_column(0).length(), basis.get_column(1).length(), basis.get_column(2).length());
Transform3D transform;
transform.scale(scale);
@@ -1046,6 +1047,10 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
PackedVector3Array rnormals = arrays[Mesh::ARRAY_NORMAL];
+ if (!rnormals.size()) {
+ continue;
+ }
+
int vertex_ofs = vertices.size() / 3;
vertices.resize((vertex_ofs + vc) * 3);
@@ -1086,6 +1091,9 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
} else {
for (int j = 0; j < ic / 3; j++) {
+ ERR_FAIL_INDEX_V(rindices[j * 3 + 0], rvertices.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(rindices[j * 3 + 1], rvertices.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(rindices[j * 3 + 2], rvertices.size(), ERR_INVALID_DATA);
Vector3 p0 = transform.xform(rvertices[rindices[j * 3 + 0]]);
Vector3 p1 = transform.xform(rvertices[rindices[j * 3 + 1]]);
Vector3 p2 = transform.xform(rvertices[rindices[j * 3 + 2]]);
@@ -1185,7 +1193,7 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
for (unsigned int i = 0; i < surfaces_tools.size(); i++) {
surfaces_tools[i]->index();
Array arrays = surfaces_tools[i]->commit_to_arrays();
- add_surface(surfaces_tools[i]->get_primitive(), arrays, Array(), Dictionary(), surfaces_tools[i]->get_material(), surfaces_tools[i]->get_meta("name"));
+ add_surface(surfaces_tools[i]->get_primitive_type(), arrays, Array(), Dictionary(), surfaces_tools[i]->get_material(), surfaces_tools[i]->get_meta("name"));
}
set_lightmap_size_hint(Size2(size_x, size_y));
@@ -1238,6 +1246,7 @@ void ImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_surface_name", "surface_idx", "name"), &ImporterMesh::set_surface_name);
ClassDB::bind_method(D_METHOD("set_surface_material", "surface_idx", "material"), &ImporterMesh::set_surface_material);
+ ClassDB::bind_method(D_METHOD("generate_lods", "normal_merge_angle", "normal_split_angle"), &ImporterMesh::generate_lods);
ClassDB::bind_method(D_METHOD("get_mesh", "base_mesh"), &ImporterMesh::get_mesh, DEFVAL(Ref<ArrayMesh>()));
ClassDB::bind_method(D_METHOD("clear"), &ImporterMesh::clear);
diff --git a/scene/resources/label_settings.cpp b/scene/resources/label_settings.cpp
new file mode 100644
index 0000000000..e8b986b431
--- /dev/null
+++ b/scene/resources/label_settings.cpp
@@ -0,0 +1,187 @@
+/*************************************************************************/
+/* label_settings.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "label_settings.h"
+
+#include "core/core_string_names.h"
+
+void LabelSettings::_font_changed() {
+ emit_changed();
+}
+
+void LabelSettings::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_line_spacing", "spacing"), &LabelSettings::set_line_spacing);
+ ClassDB::bind_method(D_METHOD("get_line_spacing"), &LabelSettings::get_line_spacing);
+
+ ClassDB::bind_method(D_METHOD("set_font", "font"), &LabelSettings::set_font);
+ ClassDB::bind_method(D_METHOD("get_font"), &LabelSettings::get_font);
+
+ ClassDB::bind_method(D_METHOD("set_font_size", "size"), &LabelSettings::set_font_size);
+ ClassDB::bind_method(D_METHOD("get_font_size"), &LabelSettings::get_font_size);
+
+ ClassDB::bind_method(D_METHOD("set_font_color", "color"), &LabelSettings::set_font_color);
+ ClassDB::bind_method(D_METHOD("get_font_color"), &LabelSettings::get_font_color);
+
+ ClassDB::bind_method(D_METHOD("set_outline_size", "size"), &LabelSettings::set_outline_size);
+ ClassDB::bind_method(D_METHOD("get_outline_size"), &LabelSettings::get_outline_size);
+
+ ClassDB::bind_method(D_METHOD("set_outline_color", "color"), &LabelSettings::set_outline_color);
+ ClassDB::bind_method(D_METHOD("get_outline_color"), &LabelSettings::get_outline_color);
+
+ ClassDB::bind_method(D_METHOD("set_shadow_size", "size"), &LabelSettings::set_shadow_size);
+ ClassDB::bind_method(D_METHOD("get_shadow_size"), &LabelSettings::get_shadow_size);
+
+ ClassDB::bind_method(D_METHOD("set_shadow_color", "color"), &LabelSettings::set_shadow_color);
+ ClassDB::bind_method(D_METHOD("get_shadow_color"), &LabelSettings::get_shadow_color);
+
+ ClassDB::bind_method(D_METHOD("set_shadow_offset", "offset"), &LabelSettings::set_shadow_offset);
+ ClassDB::bind_method(D_METHOD("get_shadow_offset"), &LabelSettings::get_shadow_offset);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "line_spacing", PROPERTY_HINT_NONE, "suffix:px"), "set_line_spacing", "get_line_spacing");
+
+ ADD_GROUP("Font", "font");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_font", "get_font");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "font_size", PROPERTY_HINT_RANGE, "1,1024,1,or_greater,suffix:px"), "set_font_size", "get_font_size");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "font_color"), "set_font_color", "get_font_color");
+
+ ADD_GROUP("Outline", "outline");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_size", PROPERTY_HINT_RANGE, "0,127,1,or_greater,suffix:px"), "set_outline_size", "get_outline_size");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "outline_color"), "set_outline_color", "get_outline_color");
+
+ ADD_GROUP("Shadow", "shadow");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size", PROPERTY_HINT_RANGE, "0,127,1,or_greater,suffix:px"), "set_shadow_size", "get_shadow_size");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_shadow_offset", "get_shadow_offset");
+}
+
+void LabelSettings::set_line_spacing(real_t p_spacing) {
+ if (line_spacing != p_spacing) {
+ line_spacing = p_spacing;
+ emit_changed();
+ }
+}
+
+real_t LabelSettings::get_line_spacing() const {
+ return line_spacing;
+}
+
+void LabelSettings::set_font(const Ref<Font> &p_font) {
+ if (font != p_font) {
+ if (font.is_valid()) {
+ font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &LabelSettings::_font_changed));
+ }
+ font = p_font;
+ if (font.is_valid()) {
+ font->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &LabelSettings::_font_changed), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ emit_changed();
+ }
+}
+
+Ref<Font> LabelSettings::get_font() const {
+ return font;
+}
+
+void LabelSettings::set_font_size(int p_size) {
+ if (font_size != p_size) {
+ font_size = p_size;
+ emit_changed();
+ }
+}
+
+int LabelSettings::get_font_size() const {
+ return font_size;
+}
+
+void LabelSettings::set_font_color(const Color &p_color) {
+ if (font_color != p_color) {
+ font_color = p_color;
+ emit_changed();
+ }
+}
+
+Color LabelSettings::get_font_color() const {
+ return font_color;
+}
+
+void LabelSettings::set_outline_size(int p_size) {
+ if (outline_size != p_size) {
+ outline_size = p_size;
+ emit_changed();
+ }
+}
+
+int LabelSettings::get_outline_size() const {
+ return outline_size;
+}
+
+void LabelSettings::set_outline_color(const Color &p_color) {
+ if (outline_color != p_color) {
+ outline_color = p_color;
+ emit_changed();
+ }
+}
+
+Color LabelSettings::get_outline_color() const {
+ return outline_color;
+}
+
+void LabelSettings::set_shadow_size(int p_size) {
+ if (shadow_size != p_size) {
+ shadow_size = p_size;
+ emit_changed();
+ }
+}
+
+int LabelSettings::get_shadow_size() const {
+ return shadow_size;
+}
+
+void LabelSettings::set_shadow_color(const Color &p_color) {
+ if (shadow_color != p_color) {
+ shadow_color = p_color;
+ emit_changed();
+ }
+}
+
+Color LabelSettings::get_shadow_color() const {
+ return shadow_color;
+}
+
+void LabelSettings::set_shadow_offset(const Vector2 &p_offset) {
+ if (shadow_offset != p_offset) {
+ shadow_offset = p_offset;
+ emit_changed();
+ }
+}
+
+Vector2 LabelSettings::get_shadow_offset() const {
+ return shadow_offset;
+}
diff --git a/scene/resources/label_settings.h b/scene/resources/label_settings.h
new file mode 100644
index 0000000000..d2644a7484
--- /dev/null
+++ b/scene/resources/label_settings.h
@@ -0,0 +1,89 @@
+/*************************************************************************/
+/* label_settings.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef LABEL_SETTINGS_H
+#define LABEL_SETTINGS_H
+
+#include "core/io/resource.h"
+#include "font.h"
+
+/*************************************************************************/
+
+class LabelSettings : public Resource {
+ GDCLASS(LabelSettings, Resource);
+
+ real_t line_spacing = 0;
+
+ Ref<Font> font;
+ int font_size = Font::DEFAULT_FONT_SIZE;
+ Color font_color = Color(0.875, 0.875, 0.875);
+
+ int outline_size = 0;
+ Color outline_color = Color(1, 1, 1);
+
+ int shadow_size = 0;
+ Color shadow_color = Color(1, 1, 1);
+ Vector2 shadow_offset = Vector2(1, 1);
+
+ void _font_changed();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_line_spacing(real_t p_spacing);
+ real_t get_line_spacing() const;
+
+ void set_font(const Ref<Font> &p_font);
+ Ref<Font> get_font() const;
+
+ void set_font_size(int p_size);
+ int get_font_size() const;
+
+ void set_font_color(const Color &p_color);
+ Color get_font_color() const;
+
+ void set_outline_size(int p_size);
+ int get_outline_size() const;
+
+ void set_outline_color(const Color &p_color);
+ Color get_outline_color() const;
+
+ void set_shadow_size(int p_size);
+ int get_shadow_size() const;
+
+ void set_shadow_color(const Color &p_color);
+ Color get_shadow_color() const;
+
+ void set_shadow_offset(const Vector2 &p_offset);
+ Vector2 get_shadow_offset() const;
+};
+
+#endif // LABEL_SETTINGS_H
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 430626b008..b7a3b677f5 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -84,7 +84,7 @@ void Material::inspect_native_shader_code() {
SceneTree *st = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop());
RID shader = get_shader_rid();
if (st && shader.is_valid()) {
- st->call_group("_native_shader_source_visualizer", "_inspect_shader", shader);
+ st->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_native_shader_source_visualizer", "_inspect_shader", shader);
}
}
@@ -187,9 +187,9 @@ bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
}
if (pr) {
- const Map<StringName, Variant>::Element *E = param_cache.find(pr);
+ HashMap<StringName, Variant>::ConstIterator E = param_cache.find(pr);
if (E) {
- r_ret = E->get();
+ r_ret = E->value;
} else {
r_ret = Variant();
}
@@ -348,7 +348,7 @@ ShaderMaterial::~ShaderMaterial() {
Mutex BaseMaterial3D::material_mutex;
SelfList<BaseMaterial3D>::List *BaseMaterial3D::dirty_materials = nullptr;
-Map<BaseMaterial3D::MaterialKey, BaseMaterial3D::ShaderData> BaseMaterial3D::shader_map;
+HashMap<BaseMaterial3D::MaterialKey, BaseMaterial3D::ShaderData, BaseMaterial3D::MaterialKey> BaseMaterial3D::shader_map;
BaseMaterial3D::ShaderNames *BaseMaterial3D::shader_names = nullptr;
void BaseMaterial3D::init_shaders() {
@@ -395,6 +395,9 @@ void BaseMaterial3D::init_shaders() {
shader_names->distance_fade_min = "distance_fade_min";
shader_names->distance_fade_max = "distance_fade_max";
+ shader_names->msdf_pixel_range = "msdf_pixel_range";
+ shader_names->msdf_outline_size = "msdf_outline_size";
+
shader_names->metallic_texture_channel = "metallic_texture_channel";
shader_names->ao_texture_channel = "ao_texture_channel";
shader_names->clearcoat_texture_channel = "clearcoat_texture_channel";
@@ -432,12 +435,10 @@ void BaseMaterial3D::init_shaders() {
shader_names->albedo_texture_size = "albedo_texture_size";
}
-Ref<StandardMaterial3D> BaseMaterial3D::materials_for_2d[BaseMaterial3D::MAX_MATERIALS_FOR_2D];
+HashMap<uint64_t, Ref<StandardMaterial3D>> BaseMaterial3D::materials_for_2d;
void BaseMaterial3D::finish_shaders() {
- for (int i = 0; i < MAX_MATERIALS_FOR_2D; i++) {
- materials_for_2d[i].unref();
- }
+ materials_for_2d.clear();
memdelete(dirty_materials);
dirty_materials = nullptr;
@@ -471,24 +472,33 @@ void BaseMaterial3D::_update_shader() {
}
String texfilter_str;
+ // Force linear filtering for the heightmap texture, as the heightmap effect
+ // looks broken with nearest-neighbor filtering (with and without Deep Parallax).
+ String texfilter_height_str;
switch (texture_filter) {
case TEXTURE_FILTER_NEAREST:
texfilter_str = "filter_nearest";
+ texfilter_height_str = "filter_linear";
break;
case TEXTURE_FILTER_LINEAR:
texfilter_str = "filter_linear";
+ texfilter_height_str = "filter_linear";
break;
case TEXTURE_FILTER_NEAREST_WITH_MIPMAPS:
texfilter_str = "filter_nearest_mipmap";
+ texfilter_height_str = "filter_linear_mipmap";
break;
case TEXTURE_FILTER_LINEAR_WITH_MIPMAPS:
texfilter_str = "filter_linear_mipmap";
+ texfilter_height_str = "filter_linear_mipmap";
break;
case TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC:
texfilter_str = "filter_nearest_mipmap_anisotropic";
+ texfilter_height_str = "filter_linear_mipmap_anisotropic";
break;
case TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC:
texfilter_str = "filter_linear_mipmap_anisotropic";
+ texfilter_height_str = "filter_linear_mipmap_anisotropic";
break;
case TEXTURE_FILTER_MAX:
break; // Internal value, skip.
@@ -496,8 +506,10 @@ void BaseMaterial3D::_update_shader() {
if (flags[FLAG_USE_TEXTURE_REPEAT]) {
texfilter_str += ",repeat_enable";
+ texfilter_height_str += ",repeat_enable";
} else {
texfilter_str += ",repeat_disable";
+ texfilter_height_str += ",repeat_disable";
}
//must create a shader!
@@ -630,8 +642,8 @@ void BaseMaterial3D::_update_shader() {
code += ";\n";
- code += "uniform vec4 albedo : hint_color;\n";
- code += "uniform sampler2D texture_albedo : hint_albedo," + texfilter_str + ";\n";
+ code += "uniform vec4 albedo : source_color;\n";
+ code += "uniform sampler2D texture_albedo : source_color," + texfilter_str + ";\n";
if (grow_enabled) {
code += "uniform float grow;\n";
}
@@ -644,6 +656,11 @@ void BaseMaterial3D::_update_shader() {
code += "uniform float distance_fade_max;\n";
}
+ if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ code += "uniform float msdf_pixel_range;\n";
+ code += "uniform float msdf_outline_size;\n";
+ }
+
// alpha scissor is only valid if there is not antialiasing edge
// alpha hash is valid whenever, but not with alpha scissor
if (transparency == TRANSPARENCY_ALPHA_SCISSOR) {
@@ -663,7 +680,7 @@ void BaseMaterial3D::_update_shader() {
//TODO ALL HINTS
if (!orm) {
code += "uniform float roughness : hint_range(0,1);\n";
- code += "uniform sampler2D texture_metallic : hint_white," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_metallic : hint_default_white," + texfilter_str + ";\n";
code += "uniform vec4 metallic_texture_channel;\n";
switch (roughness_texture_channel) {
case TEXTURE_CHANNEL_RED: {
@@ -698,8 +715,8 @@ void BaseMaterial3D::_update_shader() {
}
if (features[FEATURE_EMISSION]) {
- code += "uniform sampler2D texture_emission : hint_black_albedo," + texfilter_str + ";\n";
- code += "uniform vec4 emission : hint_color;\n";
+ code += "uniform sampler2D texture_emission : source_color, hint_default_black," + texfilter_str + ";\n";
+ code += "uniform vec4 emission : source_color;\n";
code += "uniform float emission_energy;\n";
}
@@ -716,48 +733,48 @@ void BaseMaterial3D::_update_shader() {
if (features[FEATURE_RIM]) {
code += "uniform float rim : hint_range(0,1);\n";
code += "uniform float rim_tint : hint_range(0,1);\n";
- code += "uniform sampler2D texture_rim : hint_white," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_rim : hint_default_white," + texfilter_str + ";\n";
}
if (features[FEATURE_CLEARCOAT]) {
code += "uniform float clearcoat : hint_range(0,1);\n";
code += "uniform float clearcoat_roughness : hint_range(0,1);\n";
- code += "uniform sampler2D texture_clearcoat : hint_white," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_clearcoat : hint_default_white," + texfilter_str + ";\n";
}
if (features[FEATURE_ANISOTROPY]) {
code += "uniform float anisotropy_ratio : hint_range(0,256);\n";
code += "uniform sampler2D texture_flowmap : hint_anisotropy," + texfilter_str + ";\n";
}
if (features[FEATURE_AMBIENT_OCCLUSION]) {
- code += "uniform sampler2D texture_ambient_occlusion : hint_white, " + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_ambient_occlusion : hint_default_white, " + texfilter_str + ";\n";
code += "uniform vec4 ao_texture_channel;\n";
code += "uniform float ao_light_affect;\n";
}
if (features[FEATURE_DETAIL]) {
- code += "uniform sampler2D texture_detail_albedo : hint_albedo," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_detail_albedo : source_color," + texfilter_str + ";\n";
code += "uniform sampler2D texture_detail_normal : hint_normal," + texfilter_str + ";\n";
- code += "uniform sampler2D texture_detail_mask : hint_white," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_detail_mask : hint_default_white," + texfilter_str + ";\n";
}
if (features[FEATURE_SUBSURFACE_SCATTERING]) {
code += "uniform float subsurface_scattering_strength : hint_range(0,1);\n";
- code += "uniform sampler2D texture_subsurface_scattering : hint_white," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_subsurface_scattering : hint_default_white," + texfilter_str + ";\n";
}
if (features[FEATURE_SUBSURFACE_TRANSMITTANCE]) {
- code += "uniform vec4 transmittance_color : hint_color;\n";
+ code += "uniform vec4 transmittance_color : source_color;\n";
code += "uniform float transmittance_depth;\n";
- code += "uniform sampler2D texture_subsurface_transmittance : hint_white," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_subsurface_transmittance : hint_default_white," + texfilter_str + ";\n";
code += "uniform float transmittance_boost;\n";
}
if (features[FEATURE_BACKLIGHT]) {
- code += "uniform vec4 backlight : hint_color;\n";
- code += "uniform sampler2D texture_backlight : hint_black," + texfilter_str + ";\n";
+ code += "uniform vec4 backlight : source_color;\n";
+ code += "uniform sampler2D texture_backlight : hint_default_black," + texfilter_str + ";\n";
}
if (features[FEATURE_HEIGHT_MAPPING]) {
- code += "uniform sampler2D texture_heightmap : hint_black," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_heightmap : hint_default_black," + texfilter_height_str + ";\n";
code += "uniform float heightmap_scale;\n";
code += "uniform int heightmap_min_layers;\n";
code += "uniform int heightmap_max_layers;\n";
@@ -911,6 +928,12 @@ void BaseMaterial3D::_update_shader() {
code += "}\n";
code += "\n\n";
+ if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ code += "float msdf_median(float r, float g, float b, float a) {\n";
+ code += " return min(max(min(r, g), min(max(r, g), b)), a);\n";
+ code += "}\n";
+ }
+ code += "\n\n";
if (flags[FLAG_UV1_USE_TRIPLANAR] || flags[FLAG_UV2_USE_TRIPLANAR]) {
code += "vec4 triplanar_texture(sampler2D p_sampler,vec3 p_weights,vec3 p_triplanar_pos) {\n";
code += " vec4 samp=vec4(0.0);\n";
@@ -1010,7 +1033,30 @@ void BaseMaterial3D::_update_shader() {
}
}
- if (flags[FLAG_ALBEDO_TEXTURE_FORCE_SRGB]) {
+ if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ code += " {\n";
+ code += " albedo_tex.rgb = mix(vec3(1.0 + 0.055) * pow(albedo_tex.rgb, vec3(1.0 / 2.4)) - vec3(0.055), vec3(12.92) * albedo_tex.rgb.rgb, lessThan(albedo_tex.rgb, vec3(0.0031308)));\n";
+ code += " vec2 msdf_size = vec2(msdf_pixel_range) / vec2(textureSize(texture_albedo, 0));\n";
+ if (flags[FLAG_USE_POINT_SIZE]) {
+ code += " vec2 dest_size = vec2(1.0) / fwidth(POINT_COORD);\n";
+ } else {
+ if (flags[FLAG_UV1_USE_TRIPLANAR]) {
+ code += " vec2 dest_size = vec2(1.0) / fwidth(uv1_triplanar_pos);\n";
+ } else {
+ code += " vec2 dest_size = vec2(1.0) / fwidth(base_uv);\n";
+ }
+ }
+ code += " float px_size = max(0.5 * dot(msdf_size, dest_size), 1.0);\n";
+ code += " float d = msdf_median(albedo_tex.r, albedo_tex.g, albedo_tex.b, albedo_tex.a) - 0.5;\n";
+ code += " if (msdf_outline_size > 0.0) {\n";
+ code += " float cr = clamp(msdf_outline_size, 0.0, msdf_pixel_range / 2.0) / msdf_pixel_range;\n";
+ code += " albedo_tex.a = clamp((d + cr) * px_size, 0.0, 1.0);\n";
+ code += " } else {\n";
+ code += " albedo_tex.a = clamp(d * px_size + 0.5, 0.0, 1.0);\n";
+ code += " }\n";
+ code += " albedo_tex.rgb = vec3(1.0);\n";
+ code += " }\n";
+ } else if (flags[FLAG_ALBEDO_TEXTURE_FORCE_SRGB]) {
code += " albedo_tex.rgb = mix(pow((albedo_tex.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)),vec3(2.4)),albedo_tex.rgb.rgb * (1.0 / 12.92),lessThan(albedo_tex.rgb,vec3(0.04045)));\n";
}
@@ -1753,8 +1799,6 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
_validate_high_end("refraction", property);
_validate_high_end("subsurf_scatter", property);
- _validate_high_end("anisotropy", property);
- _validate_high_end("clearcoat", property);
_validate_high_end("heightmap", property);
if (property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) {
@@ -1777,6 +1821,14 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
property.usage = PROPERTY_USAGE_NO_EDITOR;
}
+ if (property.name == "msdf_pixel_range" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+
+ if (property.name == "msdf_outline_size" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+
if ((property.name == "distance_fade_max_distance" || property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) {
property.usage = PROPERTY_USAGE_NO_EDITOR;
}
@@ -2125,35 +2177,45 @@ BaseMaterial3D::TextureChannel BaseMaterial3D::get_refraction_texture_channel()
return refraction_texture_channel;
}
-Ref<Material> BaseMaterial3D::get_material_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard, bool p_billboard_y, RID *r_shader_rid) {
- int version = 0;
+Ref<Material> BaseMaterial3D::get_material_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard, bool p_billboard_y, bool p_msdf, bool p_no_depth, bool p_fixed_size, TextureFilter p_filter, RID *r_shader_rid) {
+ int64_t hash = 0;
if (p_shaded) {
- version = 1;
+ hash |= 1 << 0;
}
if (p_transparent) {
- version |= 2;
+ hash |= 1 << 1;
}
if (p_cut_alpha) {
- version |= 4;
+ hash |= 1 << 2;
}
if (p_opaque_prepass) {
- version |= 8;
+ hash |= 1 << 3;
}
if (p_double_sided) {
- version |= 16;
+ hash |= 1 << 4;
}
if (p_billboard) {
- version |= 32;
+ hash |= 1 << 5;
}
if (p_billboard_y) {
- version |= 64;
+ hash |= 1 << 6;
+ }
+ if (p_msdf) {
+ hash |= 1 << 7;
+ }
+ if (p_no_depth) {
+ hash |= 1 << 8;
+ }
+ if (p_fixed_size) {
+ hash |= 1 << 9;
}
+ hash = hash_murmur3_one_64(p_filter, hash);
- if (materials_for_2d[version].is_valid()) {
+ if (materials_for_2d.has(hash)) {
if (r_shader_rid) {
- *r_shader_rid = materials_for_2d[version]->get_shader_rid();
+ *r_shader_rid = materials_for_2d[hash]->get_shader_rid();
}
- return materials_for_2d[version];
+ return materials_for_2d[hash];
}
Ref<StandardMaterial3D> material;
@@ -2164,18 +2226,22 @@ Ref<Material> BaseMaterial3D::get_material_for_2d(bool p_shaded, bool p_transpar
material->set_cull_mode(p_double_sided ? CULL_DISABLED : CULL_BACK);
material->set_flag(FLAG_SRGB_VERTEX_COLOR, true);
material->set_flag(FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ material->set_flag(FLAG_ALBEDO_TEXTURE_MSDF, p_msdf);
+ material->set_flag(FLAG_DISABLE_DEPTH_TEST, p_no_depth);
+ material->set_flag(FLAG_FIXED_SIZE, p_fixed_size);
+ material->set_texture_filter(p_filter);
if (p_billboard || p_billboard_y) {
material->set_flag(FLAG_BILLBOARD_KEEP_SCALE, true);
material->set_billboard_mode(p_billboard_y ? BILLBOARD_FIXED_Y : BILLBOARD_ENABLED);
}
- materials_for_2d[version] = material;
+ materials_for_2d[hash] = material;
if (r_shader_rid) {
- *r_shader_rid = materials_for_2d[version]->get_shader_rid();
+ *r_shader_rid = materials_for_2d[hash]->get_shader_rid();
}
- return materials_for_2d[version];
+ return materials_for_2d[hash];
}
void BaseMaterial3D::set_on_top_of_alpha() {
@@ -2203,6 +2269,24 @@ float BaseMaterial3D::get_proximity_fade_distance() const {
return proximity_fade_distance;
}
+void BaseMaterial3D::set_msdf_pixel_range(float p_range) {
+ msdf_pixel_range = p_range;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->msdf_pixel_range, p_range);
+}
+
+float BaseMaterial3D::get_msdf_pixel_range() const {
+ return msdf_pixel_range;
+}
+
+void BaseMaterial3D::set_msdf_outline_size(float p_size) {
+ msdf_outline_size = p_size;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->msdf_outline_size, p_size);
+}
+
+float BaseMaterial3D::get_msdf_outline_size() const {
+ return msdf_outline_size;
+}
+
void BaseMaterial3D::set_distance_fade(DistanceFadeMode p_mode) {
distance_fade = p_mode;
_queue_shader_change();
@@ -2445,6 +2529,12 @@ void BaseMaterial3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_proximity_fade_distance", "distance"), &BaseMaterial3D::set_proximity_fade_distance);
ClassDB::bind_method(D_METHOD("get_proximity_fade_distance"), &BaseMaterial3D::get_proximity_fade_distance);
+ ClassDB::bind_method(D_METHOD("set_msdf_pixel_range", "range"), &BaseMaterial3D::set_msdf_pixel_range);
+ ClassDB::bind_method(D_METHOD("get_msdf_pixel_range"), &BaseMaterial3D::get_msdf_pixel_range);
+
+ ClassDB::bind_method(D_METHOD("set_msdf_outline_size", "size"), &BaseMaterial3D::set_msdf_outline_size);
+ ClassDB::bind_method(D_METHOD("get_msdf_outline_size"), &BaseMaterial3D::get_msdf_outline_size);
+
ClassDB::bind_method(D_METHOD("set_distance_fade", "mode"), &BaseMaterial3D::set_distance_fade);
ClassDB::bind_method(D_METHOD("get_distance_fade"), &BaseMaterial3D::get_distance_fade);
@@ -2478,7 +2568,8 @@ void BaseMaterial3D::_bind_methods() {
ADD_GROUP("Albedo", "albedo_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "albedo_color"), "set_albedo", "get_albedo");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "albedo_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_ALBEDO);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "albedo_tex_force_srgb"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_FORCE_SRGB);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "albedo_texture_force_srgb"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_FORCE_SRGB);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "albedo_texture_msdf"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_MSDF);
ADD_GROUP("ORM", "orm_");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orm_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_ORM);
@@ -2575,14 +2666,14 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "detail_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_DETAIL_NORMAL);
ADD_GROUP("UV1", "uv1_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv1_scale"), "set_uv1_scale", "get_uv1_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv1_scale", PROPERTY_HINT_LINK), "set_uv1_scale", "get_uv1_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv1_offset"), "set_uv1_offset", "get_uv1_offset");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv1_triplanar"), "set_flag", "get_flag", FLAG_UV1_USE_TRIPLANAR);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "uv1_triplanar_sharpness", PROPERTY_HINT_EXP_EASING), "set_uv1_triplanar_blend_sharpness", "get_uv1_triplanar_blend_sharpness");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv1_world_triplanar"), "set_flag", "get_flag", FLAG_UV1_USE_WORLD_TRIPLANAR);
ADD_GROUP("UV2", "uv2_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv2_scale"), "set_uv2_scale", "get_uv2_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv2_scale", PROPERTY_HINT_LINK), "set_uv2_scale", "get_uv2_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv2_offset"), "set_uv2_offset", "get_uv2_offset");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv2_triplanar"), "set_flag", "get_flag", FLAG_UV2_USE_TRIPLANAR);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "uv2_triplanar_sharpness", PROPERTY_HINT_EXP_EASING), "set_uv2_triplanar_blend_sharpness", "get_uv2_triplanar_blend_sharpness");
@@ -2607,19 +2698,22 @@ void BaseMaterial3D::_bind_methods() {
ADD_GROUP("Grow", "grow_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "grow"), "set_grow_enabled", "is_grow_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_amount", PROPERTY_HINT_RANGE, "-16,16,0.001"), "set_grow", "get_grow");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_amount", PROPERTY_HINT_RANGE, "-16,16,0.001,suffix:m"), "set_grow", "get_grow");
ADD_GROUP("Transform", "");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "fixed_size"), "set_flag", "get_flag", FLAG_FIXED_SIZE);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_point_size"), "set_flag", "get_flag", FLAG_USE_POINT_SIZE);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "point_size", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_point_size", "get_point_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "point_size", PROPERTY_HINT_RANGE, "0.1,128,0.1,suffix:px"), "set_point_size", "get_point_size");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_particle_trails"), "set_flag", "get_flag", FLAG_PARTICLE_TRAILS_MODE);
ADD_GROUP("Proximity Fade", "proximity_fade_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enable"), "set_proximity_fade", "is_proximity_fade_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_proximity_fade_distance", "get_proximity_fade_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_proximity_fade_distance", "get_proximity_fade_distance");
+ ADD_GROUP("MSDF", "msdf_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), "set_msdf_pixel_range", "get_msdf_pixel_range");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "msdf_outline_size", PROPERTY_HINT_RANGE, "1,250,1"), "set_msdf_outline_size", "get_msdf_outline_size");
ADD_GROUP("Distance Fade", "distance_fade_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "distance_fade_mode", PROPERTY_HINT_ENUM, "Disabled,PixelAlpha,PixelDither,ObjectDither"), "set_distance_fade", "get_distance_fade");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_min_distance", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_distance_fade_min_distance", "get_distance_fade_min_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_max_distance", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_distance_fade_max_distance", "get_distance_fade_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_min_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_distance_fade_min_distance", "get_distance_fade_min_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_max_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_distance_fade_max_distance", "get_distance_fade_max_distance");
BIND_ENUM_CONSTANT(TEXTURE_ALBEDO);
BIND_ENUM_CONSTANT(TEXTURE_METALLIC);
@@ -2715,6 +2809,7 @@ void BaseMaterial3D::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_INVERT_HEIGHTMAP);
BIND_ENUM_CONSTANT(FLAG_SUBSURFACE_MODE_SKIN);
BIND_ENUM_CONSTANT(FLAG_PARTICLE_TRAILS_MODE);
+ BIND_ENUM_CONSTANT(FLAG_ALBEDO_TEXTURE_MSDF);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(DIFFUSE_BURLEY);
@@ -2804,6 +2899,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_heightmap_deep_parallax_max_layers(32);
set_heightmap_deep_parallax_flip_tangent(false); //also sets binormal
+ flags[FLAG_ALBEDO_TEXTURE_MSDF] = false;
flags[FLAG_USE_TEXTURE_REPEAT] = true;
is_initialized = true;
@@ -2880,7 +2976,7 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value)
{ "flags_no_depth_test", "no_depth_test" },
{ "flags_use_point_size", "use_point_size" },
{ "flags_fixed_size", "fixed_Size" },
- { "flags_albedo_tex_force_srg", "albedo_tex_force_srgb" },
+ { "flags_albedo_tex_force_srgb", "albedo_texture_force_srgb" },
{ "flags_do_not_receive_shadows", "disable_receive_shadows" },
{ "flags_disable_ambient_light", "disable_ambient_light" },
{ "params_diffuse_mode", "diffuse_mode" },
@@ -2923,4 +3019,7 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value)
return false;
}
+
#endif // DISABLE_DEPRECATED
+
+///////////////////////
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 07227c037c..b845fd68c8 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -82,7 +82,7 @@ class ShaderMaterial : public Material {
GDCLASS(ShaderMaterial, Material);
Ref<Shader> shader;
- Map<StringName, Variant> param_cache;
+ HashMap<StringName, Variant> param_cache;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@@ -242,6 +242,7 @@ public:
FLAG_INVERT_HEIGHTMAP,
FLAG_SUBSURFACE_MODE_SKIN,
FLAG_PARTICLE_TRAILS_MODE,
+ FLAG_ALBEDO_TEXTURE_MSDF,
FLAG_MAX
};
@@ -322,6 +323,9 @@ private:
memset(this, 0, sizeof(MaterialKey));
}
+ static uint32_t hash(const MaterialKey &p_key) {
+ return hash_djb2_buffer((const uint8_t *)&p_key, sizeof(MaterialKey));
+ }
bool operator==(const MaterialKey &p_key) const {
return memcmp(this, &p_key, sizeof(MaterialKey)) == 0;
}
@@ -336,7 +340,7 @@ private:
int users = 0;
};
- static Map<MaterialKey, ShaderData> shader_map;
+ static HashMap<MaterialKey, ShaderData, MaterialKey> shader_map;
MaterialKey current_key;
@@ -412,6 +416,8 @@ private:
StringName uv2_blend_sharpness;
StringName grow;
StringName proximity_fade_distance;
+ StringName msdf_pixel_range;
+ StringName msdf_outline_size;
StringName distance_fade_min;
StringName distance_fade_max;
StringName ao_light_affect;
@@ -446,36 +452,36 @@ private:
bool orm;
Color albedo;
- float specular;
- float metallic;
- float roughness;
+ float specular = 0.0f;
+ float metallic = 0.0f;
+ float roughness = 0.0f;
Color emission;
- float emission_energy;
- float normal_scale;
- float rim;
- float rim_tint;
- float clearcoat;
- float clearcoat_roughness;
- float anisotropy;
- float heightmap_scale;
- float subsurface_scattering_strength;
- float transmittance_amount;
+ float emission_energy = 0.0f;
+ float normal_scale = 0.0f;
+ float rim = 0.0f;
+ float rim_tint = 0.0f;
+ float clearcoat = 0.0f;
+ float clearcoat_roughness = 0.0f;
+ float anisotropy = 0.0f;
+ float heightmap_scale = 0.0f;
+ float subsurface_scattering_strength = 0.0f;
+ float transmittance_amount = 0.0f;
Color transmittance_color;
- float transmittance_depth;
- float transmittance_boost;
+ float transmittance_depth = 0.0f;
+ float transmittance_boost = 0.0f;
Color backlight;
- float refraction;
- float point_size;
- float alpha_scissor_threshold;
- float alpha_hash_scale;
- float alpha_antialiasing_edge;
+ float refraction = 0.0f;
+ float point_size = 0.0f;
+ float alpha_scissor_threshold = 0.0f;
+ float alpha_hash_scale = 0.0f;
+ float alpha_antialiasing_edge = 0.0f;
bool grow_enabled = false;
- float ao_light_affect;
- float grow;
- int particles_anim_h_frames;
- int particles_anim_v_frames;
- bool particles_anim_loop;
+ float ao_light_affect = 0.0f;
+ float grow = 0.0f;
+ int particles_anim_h_frames = 0;
+ int particles_anim_v_frames = 0;
+ bool particles_anim_loop = false;
Transparency transparency = TRANSPARENCY_DISABLED;
ShadingMode shading_mode = SHADING_MODE_PER_PIXEL;
@@ -483,26 +489,29 @@ private:
Vector3 uv1_scale;
Vector3 uv1_offset;
- float uv1_triplanar_sharpness;
+ float uv1_triplanar_sharpness = 0.0f;
Vector3 uv2_scale;
Vector3 uv2_offset;
- float uv2_triplanar_sharpness;
+ float uv2_triplanar_sharpness = 0.0f;
DetailUV detail_uv = DETAIL_UV_1;
bool deep_parallax = false;
- int deep_parallax_min_layers;
- int deep_parallax_max_layers;
+ int deep_parallax_min_layers = 0;
+ int deep_parallax_max_layers = 0;
bool heightmap_parallax_flip_tangent = false;
bool heightmap_parallax_flip_binormal = false;
bool proximity_fade_enabled = false;
- float proximity_fade_distance;
+ float proximity_fade_distance = 0.0f;
+
+ float msdf_pixel_range = 4.f;
+ float msdf_outline_size = 0.f;
DistanceFadeMode distance_fade = DISTANCE_FADE_DISABLED;
- float distance_fade_max_distance;
- float distance_fade_min_distance;
+ float distance_fade_max_distance = 0.0f;
+ float distance_fade_min_distance = 0.0f;
BlendMode blend_mode = BLEND_MODE_MIX;
BlendMode detail_blend_mode = BLEND_MODE_MIX;
@@ -527,9 +536,7 @@ private:
_FORCE_INLINE_ void _validate_feature(const String &text, Feature feature, PropertyInfo &property) const;
- static const int MAX_MATERIALS_FOR_2D = 128;
-
- static Ref<StandardMaterial3D> materials_for_2d[MAX_MATERIALS_FOR_2D]; //used by Sprite3D and other stuff
+ static HashMap<uint64_t, Ref<StandardMaterial3D>> materials_for_2d; //used by Sprite3D, Label3D and other stuff
void _validate_high_end(const String &text, PropertyInfo &property) const;
@@ -714,6 +721,12 @@ public:
void set_proximity_fade_distance(float p_distance);
float get_proximity_fade_distance() const;
+ void set_msdf_pixel_range(float p_range);
+ float get_msdf_pixel_range() const;
+
+ void set_msdf_outline_size(float p_size);
+ float get_msdf_outline_size() const;
+
void set_distance_fade(DistanceFadeMode p_mode);
DistanceFadeMode get_distance_fade() const;
@@ -739,7 +752,7 @@ public:
static void finish_shaders();
static void flush_changes();
- static Ref<Material> get_material_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard = false, bool p_billboard_y = false, RID *r_shader_rid = nullptr);
+ static Ref<Material> get_material_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard = false, bool p_billboard_y = false, bool p_msdf = false, bool p_no_depth = false, bool p_fixed_size = false, TextureFilter p_filter = TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RID *r_shader_rid = nullptr);
virtual RID get_shader_rid() const override;
@@ -787,6 +800,13 @@ public:
BaseMaterial3D(true) {}
};
+class PlaceholderMaterial : public Material {
+ GDCLASS(PlaceholderMaterial, Material)
+public:
+ virtual RID get_shader_rid() const override { return RID(); }
+ virtual Shader::Mode get_shader_mode() const override { return Shader::MODE_CANVAS_ITEM; }
+};
+
//////////////////////
#endif
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 3c67a20f50..3e7b0a2808 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -161,32 +161,48 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
return triangle_mesh;
}
- int facecount = 0;
+ int faces_size = 0;
for (int i = 0; i < get_surface_count(); i++) {
- if (surface_get_primitive_type(i) != PRIMITIVE_TRIANGLES) {
- continue;
- }
-
- if (surface_get_format(i) & ARRAY_FORMAT_INDEX) {
- facecount += surface_get_array_index_len(i);
- } else {
- facecount += surface_get_array_len(i);
+ switch (surface_get_primitive_type(i)) {
+ case PRIMITIVE_TRIANGLES: {
+ int len = (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(i) : surface_get_array_len(i);
+ // Don't error if zero, it's valid (we'll just skip it later).
+ ERR_CONTINUE_MSG((len % 3) != 0, vformat("Ignoring surface %d, incorrect %s count: %d (for PRIMITIVE_TRIANGLES).", i, (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? "index" : "vertex", len));
+ faces_size += len;
+ } break;
+ case PRIMITIVE_TRIANGLE_STRIP: {
+ int len = (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(i) : surface_get_array_len(i);
+ // Don't error if zero, it's valid (we'll just skip it later).
+ ERR_CONTINUE_MSG(len != 0 && len < 3, vformat("Ignoring surface %d, incorrect %s count: %d (for PRIMITIVE_TRIANGLE_STRIP).", i, (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? "index" : "vertex", len));
+ faces_size += (len == 0) ? 0 : (len - 2) * 3;
+ } break;
+ default: {
+ } break;
}
}
- if (facecount == 0 || (facecount % 3) != 0) {
+ if (faces_size == 0) {
return triangle_mesh;
}
Vector<Vector3> faces;
- faces.resize(facecount);
+ faces.resize(faces_size);
+ Vector<int32_t> surface_indices;
+ surface_indices.resize(faces_size / 3);
Vector3 *facesw = faces.ptrw();
+ int32_t *surface_indicesw = surface_indices.ptrw();
int widx = 0;
for (int i = 0; i < get_surface_count(); i++) {
- if (surface_get_primitive_type(i) != PRIMITIVE_TRIANGLES) {
+ Mesh::PrimitiveType primitive = surface_get_primitive_type(i);
+ if (primitive != PRIMITIVE_TRIANGLES && primitive != PRIMITIVE_TRIANGLE_STRIP) {
+ continue;
+ }
+ int len = (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(i) : surface_get_array_len(i);
+ if ((primitive == PRIMITIVE_TRIANGLES && (len == 0 || (len % 3) != 0)) || (primitive == PRIMITIVE_TRIANGLE_STRIP && len < 3)) {
+ // Error was already shown, just skip (including zero).
continue;
}
@@ -197,21 +213,45 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
Vector<Vector3> vertices = a[ARRAY_VERTEX];
const Vector3 *vr = vertices.ptr();
+ int32_t from_index = widx / 3;
+
if (surface_get_format(i) & ARRAY_FORMAT_INDEX) {
int ic = surface_get_array_index_len(i);
Vector<int> indices = a[ARRAY_INDEX];
const int *ir = indices.ptr();
- for (int j = 0; j < ic; j++) {
- int index = ir[j];
- facesw[widx++] = vr[index];
+ if (primitive == PRIMITIVE_TRIANGLES) {
+ for (int j = 0; j < ic; j++) {
+ int index = ir[j];
+ facesw[widx++] = vr[index];
+ }
+ } else { // PRIMITIVE_TRIANGLE_STRIP
+ for (int j = 2; j < ic; j++) {
+ facesw[widx++] = vr[ir[j - 2]];
+ facesw[widx++] = vr[ir[j - 1]];
+ facesw[widx++] = vr[ir[j]];
+ }
}
} else {
- for (int j = 0; j < vc; j++) {
- facesw[widx++] = vr[j];
+ if (primitive == PRIMITIVE_TRIANGLES) {
+ for (int j = 0; j < vc; j++) {
+ facesw[widx++] = vr[j];
+ }
+ } else { // PRIMITIVE_TRIANGLE_STRIP
+ for (int j = 2; j < vc; j++) {
+ facesw[widx++] = vr[j - 2];
+ facesw[widx++] = vr[j - 1];
+ facesw[widx++] = vr[j];
+ }
}
}
+
+ int32_t to_index = widx / 3;
+
+ for (int j = from_index; j < to_index; j++) {
+ surface_indicesw[j] = i;
+ }
}
triangle_mesh = Ref<TriangleMesh>(memnew(TriangleMesh));
@@ -455,7 +495,7 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const {
has_indices = true;
}
- Map<Vector3, Vector3> normal_accum;
+ HashMap<Vector3, Vector3> normal_accum;
//fill normals with triangle normals
for (int i = 0; i < vc; i += 3) {
@@ -474,13 +514,13 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const {
Vector3 n = Plane(t[0], t[1], t[2]).normal;
for (int j = 0; j < 3; j++) {
- Map<Vector3, Vector3>::Element *E = normal_accum.find(t[j]);
+ HashMap<Vector3, Vector3>::Iterator E = normal_accum.find(t[j]);
if (!E) {
normal_accum[t[j]] = n;
} else {
- float d = n.dot(E->get());
+ float d = n.dot(E->value);
if (d < 1.0) {
- E->get() += n * (1.0 - d);
+ E->value += n * (1.0 - d);
}
//E->get()+=n;
}
@@ -499,10 +539,10 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const {
for (int i = 0; i < vc2; i++) {
Vector3 t = r[i];
- Map<Vector3, Vector3>::Element *E = normal_accum.find(t);
+ HashMap<Vector3, Vector3>::Iterator E = normal_accum.find(t);
ERR_CONTINUE(!E);
- t += E->get() * p_margin;
+ t += E->value * p_margin;
r[i] = t;
}
@@ -1827,7 +1867,7 @@ Error ArrayMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, flo
// Keep only the scale
Basis basis = p_base_transform.get_basis();
- Vector3 scale = Vector3(basis.get_axis(0).length(), basis.get_axis(1).length(), basis.get_axis(2).length());
+ Vector3 scale = Vector3(basis.get_column(0).length(), basis.get_column(1).length(), basis.get_column(2).length());
Transform3D transform;
transform.scale(scale);
@@ -2067,7 +2107,7 @@ void ArrayMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "_blend_shape_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_blend_shape_names", "_get_blend_shape_names");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_surfaces", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_surfaces", "_get_surfaces");
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_shape_mode", PROPERTY_HINT_ENUM, "Normalized,Relative"), "set_blend_shape_mode", "get_blend_shape_mode");
- ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb");
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, "suffix:m"), "set_custom_aabb", "get_custom_aabb");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shadow_mesh", PROPERTY_HINT_RESOURCE_TYPE, "ArrayMesh"), "set_shadow_mesh", "get_shadow_mesh");
}
@@ -2092,3 +2132,17 @@ ArrayMesh::~ArrayMesh() {
RenderingServer::get_singleton()->free(mesh);
}
}
+///////////////
+
+void PlaceholderMesh::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_aabb", "aabb"), &PlaceholderMesh::set_aabb);
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "aabb", PROPERTY_HINT_NONE, "suffix:m"), "set_aabb", "get_aabb");
+}
+
+PlaceholderMesh::PlaceholderMesh() {
+ rid = RS::get_singleton()->mesh_create();
+}
+
+PlaceholderMesh::~PlaceholderMesh() {
+ RS::get_singleton()->free(rid);
+}
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 652c045a24..b166d12ead 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -328,4 +328,38 @@ VARIANT_ENUM_CAST(Mesh::ArrayCustomFormat);
VARIANT_ENUM_CAST(Mesh::PrimitiveType);
VARIANT_ENUM_CAST(Mesh::BlendShapeMode);
+class PlaceholderMesh : public Mesh {
+ GDCLASS(PlaceholderMesh, Mesh);
+
+ RID rid;
+ AABB aabb;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual int get_surface_count() const override { return 0; }
+ virtual int surface_get_array_len(int p_idx) const override { return 0; }
+ virtual int surface_get_array_index_len(int p_idx) const override { return 0; }
+ virtual Array surface_get_arrays(int p_surface) const override { return Array(); }
+ virtual Array surface_get_blend_shape_arrays(int p_surface) const override { return Array(); }
+ virtual Dictionary surface_get_lods(int p_surface) const override { return Dictionary(); }
+ virtual uint32_t surface_get_format(int p_idx) const override { return 0; }
+ virtual PrimitiveType surface_get_primitive_type(int p_idx) const override { return PRIMITIVE_TRIANGLES; }
+ virtual void surface_set_material(int p_idx, const Ref<Material> &p_material) override {}
+ virtual Ref<Material> surface_get_material(int p_idx) const override { return Ref<Material>(); }
+ virtual int get_blend_shape_count() const override { return 0; }
+ virtual StringName get_blend_shape_name(int p_index) const override { return StringName(); }
+ virtual void set_blend_shape_name(int p_index, const StringName &p_name) override {}
+ virtual RID get_rid() const override { return rid; }
+ virtual AABB get_aabb() const override { return aabb; }
+ void set_aabb(const AABB &p_aabb) { aabb = p_aabb; }
+
+ virtual int get_builtin_bind_pose_count() const override { return 0; }
+ virtual Transform3D get_builtin_bind_pose(int p_index) const override { return Transform3D(); }
+
+ PlaceholderMesh();
+ ~PlaceholderMesh();
+};
+
#endif
diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp
index 594f723a1d..33d63adc71 100644
--- a/scene/resources/mesh_data_tool.cpp
+++ b/scene/resources/mesh_data_tool.cpp
@@ -150,7 +150,7 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf
vertices.write[i] = v;
}
- Map<Point2i, int> edge_indices;
+ HashMap<Point2i, int> edge_indices;
for (int i = 0; i < icount; i += 3) {
Vertex *v[3] = { &vertices.write[r[i + 0]], &vertices.write[r[i + 1]], &vertices.write[r[i + 2]] };
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index 5168bf83eb..2d3f9d9afc 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -100,14 +100,14 @@ bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const {
void MeshLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
for (const KeyValue<int, Item> &E : item_map) {
- String name = "item/" + itos(E.key) + "/";
- p_list->push_back(PropertyInfo(Variant::STRING, name + "name"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, name + "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + "mesh_transform"));
- p_list->push_back(PropertyInfo(Variant::ARRAY, name + "shapes"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, name + "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + "navmesh_transform"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, name + "preview", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_HELPER));
+ String name = vformat("%s/%d/", PNAME("item"), E.key);
+ p_list->push_back(PropertyInfo(Variant::STRING, name + PNAME("name")));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, name + PNAME("mesh"), PROPERTY_HINT_RESOURCE_TYPE, "Mesh"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + PNAME("mesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, name + PNAME("shapes")));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, name + PNAME("navmesh"), PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + PNAME("navmesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, name + PNAME("preview"), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT));
}
}
diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h
index e0f2ab2114..4105bd6960 100644
--- a/scene/resources/mesh_library.h
+++ b/scene/resources/mesh_library.h
@@ -32,7 +32,7 @@
#define MESH_LIBRARY_H
#include "core/io/resource.h"
-#include "core/templates/map.h"
+#include "core/templates/rb_map.h"
#include "mesh.h"
#include "scene/3d/navigation_region_3d.h"
#include "shape_3d.h"
@@ -56,7 +56,7 @@ public:
Ref<NavigationMesh> navmesh;
};
- Map<int, Item> item_map;
+ RBMap<int, Item> item_map;
void _set_item_shapes(int p_item, const Array &p_shapes);
Array _get_item_shapes(int p_item) const;
diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp
index c30e748f66..e5fc61ade5 100644
--- a/scene/resources/multimesh.cpp
+++ b/scene/resources/multimesh.cpp
@@ -101,9 +101,9 @@ void MultiMesh::_set_transform_2d_array(const Vector<Vector2> &p_array) {
for (int i = 0; i < len / 3; i++) {
Transform2D t;
- t.elements[0] = r[i * 3 + 0];
- t.elements[1] = r[i * 3 + 1];
- t.elements[2] = r[i * 3 + 2];
+ t.columns[0] = r[i * 3 + 0];
+ t.columns[1] = r[i * 3 + 1];
+ t.columns[2] = r[i * 3 + 2];
set_instance_transform_2d(i, t);
}
@@ -125,9 +125,9 @@ Vector<Vector2> MultiMesh::_get_transform_2d_array() const {
for (int i = 0; i < instance_count; i++) {
Transform2D t = get_instance_transform_2d(i);
- w[i * 3 + 0] = t.elements[0];
- w[i * 3 + 1] = t.elements[1];
- w[i * 3 + 2] = t.elements[2];
+ w[i * 3 + 0] = t.columns[0];
+ w[i * 3 + 1] = t.columns[1];
+ w[i * 3 + 2] = t.columns[2];
}
return xforms;
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index 552fa84bad..a808ead66b 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -38,6 +38,7 @@ void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) {
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
+ WARN_PRINT("A mesh surface was skipped when creating a NavigationMesh due to wrong primitive type in the source mesh. Mesh surface must be made out of triangles.");
continue;
}
Array arr = p_mesh->surface_get_arrays(i);
@@ -46,6 +47,7 @@ void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) {
Vector<Vector3> varr = arr[Mesh::ARRAY_VERTEX];
Vector<int> iarr = arr[Mesh::ARRAY_INDEX];
if (varr.size() == 0 || iarr.size() == 0) {
+ WARN_PRINT("A mesh surface was skipped when creating a NavigationMesh due to an empty vertex or index array.");
continue;
}
@@ -229,7 +231,7 @@ float NavigationMesh::get_verts_per_poly() const {
}
void NavigationMesh::set_detail_sample_distance(float p_value) {
- ERR_FAIL_COND(p_value < 0);
+ ERR_FAIL_COND(p_value < 0.1);
detail_sample_distance = p_value;
}
@@ -270,6 +272,24 @@ bool NavigationMesh::get_filter_walkable_low_height_spans() const {
return filter_walkable_low_height_spans;
}
+void NavigationMesh::set_filter_baking_aabb(const AABB &p_aabb) {
+ filter_baking_aabb = p_aabb;
+ notify_property_list_changed();
+}
+
+AABB NavigationMesh::get_filter_baking_aabb() const {
+ return filter_baking_aabb;
+}
+
+void NavigationMesh::set_filter_baking_aabb_offset(const Vector3 &p_aabb_offset) {
+ filter_baking_aabb_offset = p_aabb_offset;
+ notify_property_list_changed();
+}
+
+Vector3 NavigationMesh::get_filter_baking_aabb_offset() const {
+ return filter_baking_aabb_offset;
+}
+
void NavigationMesh::set_vertices(const Vector<Vector3> &p_vertices) {
vertices = p_vertices;
notify_property_list_changed();
@@ -338,7 +358,7 @@ Ref<Mesh> NavigationMesh::get_debug_mesh() {
}
}
- Map<_EdgeKey, bool> edge_map;
+ HashMap<_EdgeKey, bool, _EdgeKey> edge_map;
Vector<Vector3> tmeshfaces;
tmeshfaces.resize(faces.size() * 3);
@@ -356,10 +376,10 @@ Ref<Mesh> NavigationMesh::get_debug_mesh() {
SWAP(ek.from, ek.to);
}
- Map<_EdgeKey, bool>::Element *F = edge_map.find(ek);
+ HashMap<_EdgeKey, bool, _EdgeKey>::Iterator F = edge_map.find(ek);
if (F) {
- F->get() = false;
+ F->value = false;
} else {
edge_map[ek] = true;
@@ -467,6 +487,10 @@ void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_filter_walkable_low_height_spans", "filter_walkable_low_height_spans"), &NavigationMesh::set_filter_walkable_low_height_spans);
ClassDB::bind_method(D_METHOD("get_filter_walkable_low_height_spans"), &NavigationMesh::get_filter_walkable_low_height_spans);
+ ClassDB::bind_method(D_METHOD("set_filter_baking_aabb", "baking_aabb"), &NavigationMesh::set_filter_baking_aabb);
+ ClassDB::bind_method(D_METHOD("get_filter_baking_aabb"), &NavigationMesh::get_filter_baking_aabb);
+ ClassDB::bind_method(D_METHOD("set_filter_baking_aabb_offset", "baking_aabb_offset"), &NavigationMesh::set_filter_baking_aabb_offset);
+ ClassDB::bind_method(D_METHOD("get_filter_baking_aabb_offset"), &NavigationMesh::get_filter_baking_aabb_offset);
ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationMesh::set_vertices);
ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationMesh::get_vertices);
@@ -484,29 +508,38 @@ void NavigationMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type/sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/source_geometry_mode", PROPERTY_HINT_ENUM, "Navmesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry/source_group_name"), "set_source_group_name", "get_source_group_name");
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell/size", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_size", "get_cell_size");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell/height", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_height", "get_cell_height");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent/height", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_height", "get_agent_height");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent/radius", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_radius", "get_agent_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent/max_climb", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_max_climb", "get_agent_max_climb");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent/max_slope", PROPERTY_HINT_RANGE, "0.0,90.0,0.1"), "set_agent_max_slope", "get_agent_max_slope");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "region/min_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_min_size", "get_region_min_size");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "region/merge_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_merge_size", "get_region_merge_size");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge/max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01,or_greater"), "set_edge_max_length", "get_edge_max_length");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge/max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01,or_greater"), "set_edge_max_error", "get_edge_max_error");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "polygon/verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_verts_per_poly", "get_verts_per_poly");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail/sample_distance", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater"), "set_detail_sample_distance", "get_detail_sample_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail/sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater"), "set_detail_sample_max_error", "get_detail_sample_max_error");
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/low_hanging_obstacles"), "set_filter_low_hanging_obstacles", "get_filter_low_hanging_obstacles");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/ledge_spans"), "set_filter_ledge_spans", "get_filter_ledge_spans");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/filter_walkable_low_height_spans"), "set_filter_walkable_low_height_spans", "get_filter_walkable_low_height_spans");
+ ADD_GROUP("Sampling", "sample_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type");
+ ADD_GROUP("Geometry", "geometry_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_source_geometry_mode", PROPERTY_HINT_ENUM, "NavMesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry_source_group_name"), "set_source_group_name", "get_source_group_name");
+ ADD_GROUP("Cells", "cell_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_size", "get_cell_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_height", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_height", "get_cell_height");
+ ADD_GROUP("Agents", "agent_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater,suffix:m"), "set_agent_height", "get_agent_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_radius", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater,suffix:m"), "set_agent_radius", "get_agent_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_max_climb", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater,suffix:m"), "set_agent_max_climb", "get_agent_max_climb");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_max_slope", PROPERTY_HINT_RANGE, "0.02,90.0,0.01,degrees"), "set_agent_max_slope", "get_agent_max_slope");
+ ADD_GROUP("Regions", "region_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "region_min_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_min_size", "get_region_min_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "region_merge_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_merge_size", "get_region_merge_size");
+ ADD_GROUP("Edges", "edge_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01,or_greater,suffix:m"), "set_edge_max_length", "get_edge_max_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01,or_greater,suffix:m"), "set_edge_max_error", "get_edge_max_error");
+ ADD_GROUP("Polygons", "polygon_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "polygon_verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_verts_per_poly", "get_verts_per_poly");
+ ADD_GROUP("Details", "detail_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_sample_distance", PROPERTY_HINT_RANGE, "0.1,16.0,0.01,or_greater,suffix:m"), "set_detail_sample_distance", "get_detail_sample_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater,suffix:m"), "set_detail_sample_max_error", "get_detail_sample_max_error");
+ ADD_GROUP("Filters", "filter_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_low_hanging_obstacles"), "set_filter_low_hanging_obstacles", "get_filter_low_hanging_obstacles");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_ledge_spans"), "set_filter_ledge_spans", "get_filter_ledge_spans");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_walkable_low_height_spans"), "set_filter_walkable_low_height_spans", "get_filter_walkable_low_height_spans");
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "filter_baking_aabb"), "set_filter_baking_aabb", "get_filter_baking_aabb");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "filter_baking_aabb_offset"), "set_filter_baking_aabb_offset", "get_filter_baking_aabb_offset");
BIND_ENUM_CONSTANT(SAMPLE_PARTITION_WATERSHED);
BIND_ENUM_CONSTANT(SAMPLE_PARTITION_MONOTONE);
@@ -540,4 +573,41 @@ void NavigationMesh::_validate_property(PropertyInfo &property) const {
}
}
+#ifndef DISABLE_DEPRECATED
+bool NavigationMesh::_set(const StringName &p_name, const Variant &p_value) {
+ String name = p_name;
+ if (name.find("/") != -1) {
+ // Compatibility with pre-3.5 "category/path" property names.
+ name = name.replace("/", "_");
+ if (name == "sample_partition_type_sample_partition_type") {
+ set("sample_partition_type", p_value);
+ } else if (name == "filter_filter_walkable_low_height_spans") {
+ set("filter_walkable_low_height_spans", p_value);
+ } else {
+ set(name, p_value);
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool NavigationMesh::_get(const StringName &p_name, Variant &r_ret) const {
+ String name = p_name;
+ if (name.find("/") != -1) {
+ // Compatibility with pre-3.5 "category/path" property names.
+ name = name.replace("/", "_");
+ if (name == "sample_partition_type_sample_partition_type") {
+ r_ret = get("sample_partition_type");
+ } else if (name == "filter_filter_walkable_low_height_spans") {
+ r_ret = get("filter_walkable_low_height_spans");
+ } else {
+ r_ret = get(name);
+ }
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
NavigationMesh::NavigationMesh() {}
diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h
index e43e8627e4..40b275c792 100644
--- a/scene/resources/navigation_mesh.h
+++ b/scene/resources/navigation_mesh.h
@@ -49,13 +49,24 @@ class NavigationMesh : public Resource {
Vector3 from;
Vector3 to;
- bool operator<(const _EdgeKey &p_with) const { return from == p_with.from ? to < p_with.to : from < p_with.from; }
+ static uint32_t hash(const _EdgeKey &p_key) {
+ return HashMapHasherDefault::hash(p_key.from) ^ HashMapHasherDefault::hash(p_key.to);
+ }
+
+ bool operator==(const _EdgeKey &p_with) const {
+ return HashMapComparatorDefault<Vector3>::compare(from, p_with.from) && HashMapComparatorDefault<Vector3>::compare(to, p_with.to);
+ }
};
protected:
static void _bind_methods();
virtual void _validate_property(PropertyInfo &property) const override;
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+#endif // DISABLE_DEPRECATED
+
void _set_polygons(const Array &p_array);
Array _get_polygons() const;
@@ -82,13 +93,13 @@ public:
};
protected:
- float cell_size = 0.3f;
- float cell_height = 0.2f;
- float agent_height = 2.0f;
- float agent_radius = 1.0f;
- float agent_max_climb = 0.9f;
+ float cell_size = 0.25f;
+ float cell_height = 0.25f;
+ float agent_height = 1.5f;
+ float agent_radius = 0.5f;
+ float agent_max_climb = 0.25f;
float agent_max_slope = 45.0f;
- float region_min_size = 8.0f;
+ float region_min_size = 2.0f;
float region_merge_size = 20.0f;
float edge_max_length = 12.0f;
float edge_max_error = 1.3f;
@@ -106,6 +117,8 @@ protected:
bool filter_low_hanging_obstacles = false;
bool filter_ledge_spans = false;
bool filter_walkable_low_height_spans = false;
+ AABB filter_baking_aabb;
+ Vector3 filter_baking_aabb_offset;
public:
// Recast settings
@@ -175,6 +188,12 @@ public:
void set_filter_walkable_low_height_spans(bool p_value);
bool get_filter_walkable_low_height_spans() const;
+ void set_filter_baking_aabb(const AABB &p_aabb);
+ AABB get_filter_baking_aabb() const;
+
+ void set_filter_baking_aabb_offset(const Vector3 &p_aabb_offset);
+ Vector3 get_filter_baking_aabb_offset() const;
+
void create_from_mesh(const Ref<Mesh> &p_mesh);
void set_vertices(const Vector<Vector3> &p_vertices);
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index b1c2702a1e..2c58aa83a9 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -33,28 +33,28 @@
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/core_string_names.h"
+#include "core/io/missing_resource.h"
#include "core/io/resource_loader.h"
+#include "core/templates/local_vector.h"
#include "scene/2d/node_2d.h"
#include "scene/3d/node_3d.h"
#include "scene/gui/control.h"
#include "scene/main/instance_placeholder.h"
+#include "scene/main/missing_node.h"
#include "scene/property_utils.h"
#define PACKED_SCENE_VERSION 2
-
+#define META_POINTER_PROPERTY_BASE "metadata/_editor_prop_ptr_"
bool SceneState::can_instantiate() const {
return nodes.size() > 0;
}
static Array _sanitize_node_pinned_properties(Node *p_node) {
- if (!p_node->has_meta("_edit_pinned_properties_")) {
- return Array();
- }
- Array pinned = p_node->get_meta("_edit_pinned_properties_");
+ Array pinned = p_node->get_meta("_edit_pinned_properties_", Array());
if (pinned.is_empty()) {
return Array();
}
- Set<StringName> storable_properties;
+ HashSet<StringName> storable_properties;
p_node->get_storable_properties(storable_properties);
int i = 0;
do {
@@ -107,12 +107,15 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
bool gen_node_path_cache = p_edit_state != GEN_EDIT_STATE_DISABLED && node_path_cache.is_empty();
- Map<Ref<Resource>, Ref<Resource>> resources_local_to_scene;
+ HashMap<Ref<Resource>, Ref<Resource>> resources_local_to_scene;
+
+ LocalVector<DeferredNodePathProperties> deferred_node_paths;
for (int i = 0; i < nc; i++) {
const NodeData &n = nd[i];
Node *parent = nullptr;
+ String old_parent_path;
if (i > 0) {
ERR_FAIL_COND_V_MSG(n.parent == -1, nullptr, vformat("Invalid scene: node %s does not specify its parent node.", snames[n.name]));
@@ -120,6 +123,8 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
#ifdef DEBUG_ENABLED
if (!nparent && (n.parent & FLAG_ID_IS_PATH)) {
WARN_PRINT(String("Parent path '" + String(node_paths[n.parent & FLAG_MASK]) + "' for node '" + String(snames[n.name]) + "' has vanished when instancing: '" + get_path() + "'.").ascii().get_data());
+ old_parent_path = String(node_paths[n.parent & FLAG_MASK]).trim_prefix("./").replace("/", "@");
+ nparent = ret_nodes[0];
}
#endif
parent = nparent;
@@ -130,6 +135,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
}
Node *node = nullptr;
+ MissingNode *missing_node = nullptr;
if (i == 0 && base_scene_idx >= 0) {
//scene inheritance on root node
@@ -184,24 +190,33 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
memdelete(obj);
obj = nullptr;
}
- WARN_PRINT(vformat("Node %s of type %s cannot be created. A placeholder will be created instead.", snames[n.name], snames[n.type]).ascii().get_data());
- if (n.parent >= 0 && n.parent < nc && ret_nodes[n.parent]) {
- if (Object::cast_to<Control>(ret_nodes[n.parent])) {
- obj = memnew(Control);
- } else if (Object::cast_to<Node2D>(ret_nodes[n.parent])) {
- obj = memnew(Node2D);
+
+ if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) {
+ missing_node = memnew(MissingNode);
+ missing_node->set_original_class(snames[n.type]);
+ missing_node->set_recording_properties(true);
+ node = missing_node;
+ obj = missing_node;
+ } else {
+ WARN_PRINT(vformat("Node %s of type %s cannot be created. A placeholder will be created instead.", snames[n.name], snames[n.type]).ascii().get_data());
+ if (n.parent >= 0 && n.parent < nc && ret_nodes[n.parent]) {
+ if (Object::cast_to<Control>(ret_nodes[n.parent])) {
+ obj = memnew(Control);
+ } else if (Object::cast_to<Node2D>(ret_nodes[n.parent])) {
+ obj = memnew(Node2D);
#ifndef _3D_DISABLED
- } else if (Object::cast_to<Node3D>(ret_nodes[n.parent])) {
- obj = memnew(Node3D);
+ } else if (Object::cast_to<Node3D>(ret_nodes[n.parent])) {
+ obj = memnew(Node3D);
#endif // _3D_DISABLED
+ }
}
- }
- if (!obj) {
- obj = memnew(Node);
- }
+ if (!obj) {
+ obj = memnew(Node);
+ }
- node = Object::cast_to<Node>(obj);
+ node = Object::cast_to<Node>(obj);
+ }
}
}
@@ -214,11 +229,32 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
if (nprop_count) {
const NodeData::Property *nprops = &n.properties[0];
+ Dictionary missing_resource_properties;
+
for (int j = 0; j < nprop_count; j++) {
bool valid;
- ERR_FAIL_INDEX_V(nprops[j].name, sname_count, nullptr);
+
ERR_FAIL_INDEX_V(nprops[j].value, prop_count, nullptr);
+ if (nprops[j].name & FLAG_PATH_PROPERTY_IS_NODE) {
+ uint32_t name_idx = nprops[j].name & (FLAG_PATH_PROPERTY_IS_NODE - 1);
+ ERR_FAIL_UNSIGNED_INDEX_V(name_idx, (uint32_t)sname_count, nullptr);
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // If editor, just set the metadata and be it
+ node->set(META_POINTER_PROPERTY_BASE + String(snames[name_idx]), props[nprops[j].value]);
+ } else {
+ // Do an actual deferred sed of the property path.
+ DeferredNodePathProperties dnp;
+ dnp.path = props[nprops[j].value];
+ dnp.base = node;
+ dnp.property = snames[name_idx];
+ deferred_node_paths.push_back(dnp);
+ }
+ continue;
+ }
+
+ ERR_FAIL_INDEX_V(nprops[j].name, sname_count, nullptr);
+
if (snames[nprops[j].name] == CoreStringNames::get_singleton()->_script) {
//work around to avoid old script variables from disappearing, should be the proper fix to:
//https://github.com/godotengine/godot/issues/2958
@@ -243,10 +279,10 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
Ref<Resource> res = value;
if (res.is_valid()) {
if (res->is_local_to_scene()) {
- Map<Ref<Resource>, Ref<Resource>>::Element *E = resources_local_to_scene.find(res);
+ HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = resources_local_to_scene.find(res);
if (E) {
- value = E->get();
+ value = E->value;
} else {
Node *base = i == 0 ? node : ret_nodes[0];
@@ -270,9 +306,24 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
} else if (p_edit_state == GEN_EDIT_STATE_INSTANCE) {
value = value.duplicate(true); // Duplicate arrays and dictionaries for the editor
}
- node->set(snames[nprops[j].name], value, &valid);
+
+ bool set_valid = true;
+ if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled() && value.get_type() == Variant::OBJECT) {
+ Ref<MissingResource> mr = value;
+ if (mr.is_valid()) {
+ missing_resource_properties[snames[nprops[j].name]] = mr;
+ set_valid = false;
+ }
+ }
+
+ if (set_valid) {
+ node->set(snames[nprops[j].name], value, &valid);
+ }
}
}
+ if (!missing_resource_properties.is_empty()) {
+ node->set_meta(META_MISSING_RESOURCES, missing_resource_properties);
+ }
}
//name
@@ -306,10 +357,17 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
}
}
+ if (!old_parent_path.is_empty()) {
+ node->_set_name_nocheck(old_parent_path + "@" + node->get_name());
+ }
+
if (n.owner >= 0) {
NODE_FROM_ID(owner, n.owner);
if (owner) {
node->_set_owner_nocheck(owner);
+ if (node->data.unique_name_in_owner) {
+ node->_acquire_unique_name_in_owner();
+ }
}
}
@@ -321,6 +379,10 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
}
}
+ if (missing_node) {
+ missing_node->set_recording_properties(false);
+ }
+
ret_nodes[i] = node;
if (node && gen_node_path_cache && ret_nodes[0]) {
@@ -329,6 +391,12 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
}
}
+ for (uint32_t i = 0; i < deferred_node_paths.size(); i++) {
+ const DeferredNodePathProperties &dnp = deferred_node_paths[i];
+ Node *other = dnp.base->get_node_or_null(dnp.path);
+ dnp.base->set(dnp.property, other);
+ }
+
for (KeyValue<Ref<Resource>, Ref<Resource>> &E : resources_local_to_scene) {
E.value->setup_local_to_scene();
}
@@ -390,7 +458,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
return ret_nodes[0];
}
-static int _nm_get_string(const String &p_string, Map<StringName, int> &name_map) {
+static int _nm_get_string(const String &p_string, HashMap<StringName, int> &name_map) {
if (name_map.has(p_string)) {
return name_map[p_string];
}
@@ -410,7 +478,7 @@ static int _vm_get_variant(const Variant &p_variant, HashMap<Variant, int, Varia
return idx;
}
-Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, Map<Node *, int> &node_map, Map<Node *, int> &nodepath_map) {
+Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, HashMap<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map) {
// this function handles all the work related to properly packing scenes, be it
// instantiated or inherited.
// given the complexity of this process, an attempt will be made to properly
@@ -482,33 +550,46 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
p_node->get_property_list(&plist);
Array pinned_props = _sanitize_node_pinned_properties(p_node);
+ Dictionary missing_resource_properties = p_node->get_meta(META_MISSING_RESOURCES, Dictionary());
for (const PropertyInfo &E : plist) {
if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
continue;
}
- Variant forced_value;
+ if (E.name == META_PROPERTY_MISSING_RESOURCES) {
+ continue; // Ignore this property when packing.
+ }
+ if (E.name.begins_with(META_POINTER_PROPERTY_BASE)) {
+ continue; // do not save.
+ }
- // If instance or inheriting, not saving if property requested so, or it's meta
- if (states_stack.size()) {
+ // If instance or inheriting, not saving if property requested so.
+ if (!states_stack.is_empty()) {
if ((E.usage & PROPERTY_USAGE_NO_INSTANCE_STATE)) {
continue;
}
- // Meta is normally not saved in instances/inherited (see GH-12838), but we need to save the pinned list
- if (E.name == "__meta__") {
- if (pinned_props.size()) {
- Dictionary meta_override;
- meta_override["_edit_pinned_properties_"] = pinned_props;
- forced_value = meta_override;
- }
- }
}
StringName name = E.name;
- Variant value = forced_value.get_type() == Variant::NIL ? p_node->get(name) : forced_value;
+ Variant value = p_node->get(name);
+ bool use_deferred_node_path_bit = false;
- if (!pinned_props.has(name) && forced_value.get_type() == Variant::NIL) {
+ if (E.type == Variant::OBJECT && E.hint == PROPERTY_HINT_NODE_TYPE) {
+ value = p_node->get(META_POINTER_PROPERTY_BASE + E.name);
+ if (value.get_type() != Variant::NODE_PATH) {
+ continue; //was never set, ignore.
+ }
+ use_deferred_node_path_bit = true;
+ } else if (E.type == Variant::OBJECT && missing_resource_properties.has(E.name)) {
+ // Was this missing resource overridden? If so do not save the old value.
+ Ref<Resource> ures = value;
+ if (ures.is_null()) {
+ value = missing_resource_properties[E.name];
+ }
+ }
+
+ if (!pinned_props.has(name)) {
bool is_valid_default = false;
Variant default_value = PropertyUtils::get_property_default_value(p_node, name, &is_valid_default, &states_stack, true);
if (is_valid_default && !PropertyUtils::is_property_value_different(value, default_value)) {
@@ -519,6 +600,9 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
NodeData::Property prop;
prop.name = _nm_get_string(name, name_map);
prop.value = _vm_get_variant(value, variant_map);
+ if (use_deferred_node_path_bit) {
+ prop.name |= FLAG_PATH_PROPERTY_IS_NODE;
+ }
nd.properties.push_back(prop);
}
@@ -563,11 +647,18 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
nd.owner = -1;
}
+ MissingNode *missing_node = Object::cast_to<MissingNode>(p_node);
+
// Save the right type. If this node was created by an instance
// then flag that the node should not be created but reused
if (states_stack.is_empty() && !is_editable_instance) {
//this node is not part of an instancing process, so save the type
- nd.type = _nm_get_string(p_node->get_class(), name_map);
+ if (missing_node != nullptr) {
+ // It's a missing node (type non existent on load).
+ nd.type = _nm_get_string(missing_node->get_original_class(), name_map);
+ } else {
+ nd.type = _nm_get_string(p_node->get_class(), name_map);
+ }
} else {
// this node is part of an instantiated process, so do not save the type.
// instead, save that it was instantiated
@@ -622,7 +713,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
return OK;
}
-Error SceneState::_parse_connections(Node *p_owner, Node *p_node, Map<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, Map<Node *, int> &node_map, Map<Node *, int> &nodepath_map) {
+Error SceneState::_parse_connections(Node *p_owner, Node *p_node, HashMap<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map) {
if (p_node != p_owner && p_node->get_owner() && p_node->get_owner() != p_owner && !p_owner->is_editable_instance(p_node->get_owner())) {
return OK;
}
@@ -829,10 +920,10 @@ Error SceneState::pack(Node *p_scene) {
Node *scene = p_scene;
- Map<StringName, int> name_map;
+ HashMap<StringName, int> name_map;
HashMap<Variant, int, VariantHasher, VariantComparator> variant_map;
- Map<Node *, int> node_map;
- Map<Node *, int> nodepath_map;
+ HashMap<Node *, int> node_map;
+ HashMap<Node *, int> nodepath_map;
// If using scene inheritance, pack the scene it inherits from.
if (scene->get_scene_inherited_state().is_valid()) {
@@ -863,10 +954,10 @@ Error SceneState::pack(Node *p_scene) {
}
variants.resize(variant_map.size());
- const Variant *K = nullptr;
- while ((K = variant_map.next(K))) {
- int idx = variant_map[*K];
- variants.write[idx] = *K;
+
+ for (const KeyValue<Variant, int> &E : variant_map) {
+ int idx = E.value;
+ variants.write[idx] = E.key;
}
node_paths.resize(nodepath_map.size());
@@ -968,7 +1059,7 @@ Variant SceneState::get_property_value(int p_node, const StringName &p_property,
const NodeData::Property *p = nodes[p_node].properties.ptr();
for (int i = 0; i < pc; i++) {
- if (p_property == namep[p[i].name]) {
+ if (p_property == namep[p[i].name & FLAG_PROP_NAME_MASK]) {
found = true;
return variants[p[i].value];
}
@@ -1359,7 +1450,19 @@ int SceneState::get_node_property_count(int p_idx) const {
StringName SceneState::get_node_property_name(int p_idx, int p_prop) const {
ERR_FAIL_INDEX_V(p_idx, nodes.size(), StringName());
ERR_FAIL_INDEX_V(p_prop, nodes[p_idx].properties.size(), StringName());
- return names[nodes[p_idx].properties[p_prop].name];
+ return names[nodes[p_idx].properties[p_prop].name & FLAG_PROP_NAME_MASK];
+}
+
+Vector<String> SceneState::get_node_deferred_nodepath_properties(int p_idx) const {
+ Vector<String> ret;
+ ERR_FAIL_INDEX_V(p_idx, nodes.size(), ret);
+ for (int i = 0; i < nodes[p_idx].properties.size(); i++) {
+ uint32_t idx = nodes[p_idx].properties[i].name;
+ if (idx & FLAG_PATH_PROPERTY_IS_NODE) {
+ ret.push_back(names[idx & FLAG_PROP_NAME_MASK]);
+ }
+ }
+ return ret;
}
Variant SceneState::get_node_property_value(int p_idx, int p_prop) const {
@@ -1505,13 +1608,16 @@ int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int
return nodes.size() - 1;
}
-void SceneState::add_node_property(int p_node, int p_name, int p_value) {
+void SceneState::add_node_property(int p_node, int p_name, int p_value, bool p_deferred_node_path) {
ERR_FAIL_INDEX(p_node, nodes.size());
ERR_FAIL_INDEX(p_name, names.size());
ERR_FAIL_INDEX(p_value, variants.size());
NodeData::Property prop;
prop.name = p_name;
+ if (p_deferred_node_path) {
+ prop.name |= FLAG_PATH_PROPERTY_IS_NODE;
+ }
prop.value = p_value;
nodes.write[p_node].properties.push_back(prop);
}
@@ -1549,6 +1655,10 @@ void SceneState::add_editable_instance(const NodePath &p_path) {
editable_instances.push_back(p_path);
}
+String SceneState::get_meta_pointer_property(const String &p_property) {
+ return META_POINTER_PROPERTY_BASE + p_property;
+}
+
Vector<String> SceneState::_get_node_groups(int p_idx) const {
Vector<StringName> groups = get_node_groups(p_idx);
Vector<String> ret;
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 96222937d0..5f8001c871 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -42,7 +42,7 @@ class SceneState : public RefCounted {
Vector<NodePath> node_paths;
Vector<NodePath> editable_instances;
mutable HashMap<NodePath, int> node_path_cache;
- mutable Map<int, int> base_scene_node_remap;
+ mutable HashMap<int, int> base_scene_node_remap;
int base_scene_idx = -1;
@@ -69,6 +69,12 @@ class SceneState : public RefCounted {
Vector<int> groups;
};
+ struct DeferredNodePathProperties {
+ Node *base = nullptr;
+ StringName property;
+ NodePath path;
+ };
+
Vector<NodeData> nodes;
struct ConnectionData {
@@ -83,8 +89,8 @@ class SceneState : public RefCounted {
Vector<ConnectionData> connections;
- Error _parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, Map<Node *, int> &node_map, Map<Node *, int> &nodepath_map);
- Error _parse_connections(Node *p_owner, Node *p_node, Map<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, Map<Node *, int> &node_map, Map<Node *, int> &nodepath_map);
+ Error _parse_node(Node *p_owner, Node *p_node, int p_parent_idx, HashMap<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map);
+ Error _parse_connections(Node *p_owner, Node *p_node, HashMap<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map);
String path;
@@ -104,6 +110,8 @@ public:
FLAG_ID_IS_PATH = (1 << 30),
TYPE_INSTANCED = 0x7FFFFFFF,
FLAG_INSTANCE_IS_PLACEHOLDER = (1 << 30),
+ FLAG_PATH_PROPERTY_IS_NODE = (1 << 30),
+ FLAG_PROP_NAME_MASK = FLAG_PATH_PROPERTY_IS_NODE - 1,
FLAG_MASK = (1 << 24) - 1,
};
@@ -157,6 +165,7 @@ public:
int get_node_property_count(int p_idx) const;
StringName get_node_property_name(int p_idx, int p_prop) const;
Variant get_node_property_value(int p_idx, int p_prop) const;
+ Vector<String> get_node_deferred_nodepath_properties(int p_idx) const;
int get_connection_count() const;
NodePath get_connection_source(int p_idx) const;
@@ -177,7 +186,7 @@ public:
int add_value(const Variant &p_value);
int add_node_path(const NodePath &p_path);
int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index);
- void add_node_property(int p_node, int p_name, int p_value);
+ void add_node_property(int p_node, int p_name, int p_value, bool p_deferred_node_path = false);
void add_node_group(int p_node, int p_group);
void set_base_scene(int p_idx);
void add_connection(int p_from, int p_to, int p_signal, int p_method, int p_flags, int p_unbinds, const Vector<int> &p_binds);
@@ -186,6 +195,9 @@ public:
virtual void set_last_modified_time(uint64_t p_time) { last_modified_time = p_time; }
uint64_t get_last_modified_time() const { return last_modified_time; }
+ // Used when saving pointers (saves a path property instead).
+ static String get_meta_pointer_property(const String &p_property);
+
SceneState();
};
@@ -225,7 +237,9 @@ public:
virtual void set_path(const String &p_path, bool p_take_over = false) override;
#ifdef TOOLS_ENABLED
- virtual void set_last_modified_time(uint64_t p_time) override { state->set_last_modified_time(p_time); }
+ virtual void set_last_modified_time(uint64_t p_time) override {
+ state->set_last_modified_time(p_time);
+ }
#endif
Ref<SceneState> get_state() const;
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index 01a0411545..7a49b9b515 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -34,7 +34,7 @@
Mutex ParticlesMaterial::material_mutex;
SelfList<ParticlesMaterial>::List *ParticlesMaterial::dirty_materials = nullptr;
-Map<ParticlesMaterial::MaterialKey, ParticlesMaterial::ShaderData> ParticlesMaterial::shader_map;
+HashMap<ParticlesMaterial::MaterialKey, ParticlesMaterial::ShaderData, ParticlesMaterial::MaterialKey> ParticlesMaterial::shader_map;
ParticlesMaterial::ShaderNames *ParticlesMaterial::shader_names = nullptr;
void ParticlesMaterial::init_shaders() {
@@ -197,14 +197,14 @@ void ParticlesMaterial::_update_shader() {
code += "uniform vec3 emission_box_extents;\n";
} break;
case EMISSION_SHAPE_DIRECTED_POINTS: {
- code += "uniform sampler2D emission_texture_normal : hint_black;\n";
+ code += "uniform sampler2D emission_texture_normal : hint_default_black;\n";
[[fallthrough]];
}
case EMISSION_SHAPE_POINTS: {
- code += "uniform sampler2D emission_texture_points : hint_black;\n";
+ code += "uniform sampler2D emission_texture_points : hint_default_black;\n";
code += "uniform int emission_texture_point_count;\n";
if (emission_color_texture.is_valid()) {
- code += "uniform sampler2D emission_texture_color : hint_white;\n";
+ code += "uniform sampler2D emission_texture_color : hint_default_white;\n";
}
} break;
case EMISSION_SHAPE_RING: {
@@ -228,53 +228,53 @@ void ParticlesMaterial::_update_shader() {
code += "uniform bool sub_emitter_keep_velocity;\n";
}
- code += "uniform vec4 color_value : hint_color;\n";
+ code += "uniform vec4 color_value : source_color;\n";
code += "uniform vec3 gravity;\n";
if (color_ramp.is_valid()) {
- code += "uniform sampler2D color_ramp;\n";
+ code += "uniform sampler2D color_ramp : repeat_disable;\n";
}
if (color_initial_ramp.is_valid()) {
- code += "uniform sampler2D color_initial_ramp;\n";
+ code += "uniform sampler2D color_initial_ramp : repeat_disable;\n";
}
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- code += "uniform sampler2D linear_velocity_texture;\n";
+ code += "uniform sampler2D linear_velocity_texture : repeat_disable;\n";
}
if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
- code += "uniform sampler2D orbit_velocity_texture;\n";
+ code += "uniform sampler2D orbit_velocity_texture : repeat_disable;\n";
}
if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
- code += "uniform sampler2D angular_velocity_texture;\n";
+ code += "uniform sampler2D angular_velocity_texture : repeat_disable;\n";
}
if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
- code += "uniform sampler2D linear_accel_texture;\n";
+ code += "uniform sampler2D linear_accel_texture : repeat_disable;\n";
}
if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
- code += "uniform sampler2D radial_accel_texture;\n";
+ code += "uniform sampler2D radial_accel_texture : repeat_disable;\n";
}
if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
- code += "uniform sampler2D tangent_accel_texture;\n";
+ code += "uniform sampler2D tangent_accel_texture : repeat_disable;\n";
}
if (tex_parameters[PARAM_DAMPING].is_valid()) {
- code += "uniform sampler2D damping_texture;\n";
+ code += "uniform sampler2D damping_texture : repeat_disable;\n";
}
if (tex_parameters[PARAM_ANGLE].is_valid()) {
- code += "uniform sampler2D angle_texture;\n";
+ code += "uniform sampler2D angle_texture : repeat_disable;\n";
}
if (tex_parameters[PARAM_SCALE].is_valid()) {
- code += "uniform sampler2D scale_texture;\n";
+ code += "uniform sampler2D scale_texture : repeat_disable;\n";
}
if (tex_parameters[PARAM_HUE_VARIATION].is_valid()) {
- code += "uniform sampler2D hue_variation_texture;\n";
+ code += "uniform sampler2D hue_variation_texture : repeat_disable;\n";
}
if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) {
- code += "uniform sampler2D anim_speed_texture;\n";
+ code += "uniform sampler2D anim_speed_texture : repeat_disable;\n";
}
if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) {
- code += "uniform sampler2D anim_offset_texture;\n";
+ code += "uniform sampler2D anim_offset_texture : repeat_disable;\n";
}
if (collision_enabled) {
@@ -488,6 +488,12 @@ void ParticlesMaterial::_update_shader() {
code += " float degree_to_rad = pi / 180.0;\n";
code += "\n";
+ if (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) {
+ code += " int point = min(emission_texture_point_count - 1, int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n";
+ code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n";
+ code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n";
+ }
+
code += " CUSTOM.y += DELTA / LIFETIME;\n";
code += " float tv = CUSTOM.y / CUSTOM.w;\n";
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
@@ -722,11 +728,9 @@ void ParticlesMaterial::_update_shader() {
code += " if (DELTA >= interval_rem) emit_count = 1;\n";
} break;
case SUB_EMITTER_AT_COLLISION: {
- //not implemented yet
code += " if (COLLIDED) emit_count = 1;\n";
} break;
case SUB_EMITTER_AT_END: {
- //not implemented yet
code += " float unit_delta = DELTA/LIFETIME;\n";
code += " float end_time = CUSTOM.w * 0.95;\n"; // if we do at the end we might miss it, as it can just get deactivated by emitter
code += " if (CUSTOM.y < end_time && (CUSTOM.y + unit_delta) >= end_time) emit_count = sub_emitter_amount_at_end;\n";
@@ -1473,7 +1477,7 @@ void ParticlesMaterial::_bind_methods() {
ADD_GROUP("Sub Emitter", "sub_emitter_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,At End,At Collision"), "set_sub_emitter_mode", "get_sub_emitter_mode");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_sub_emitter_frequency", "get_sub_emitter_frequency");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:Hz"), "set_sub_emitter_frequency", "get_sub_emitter_frequency");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_end", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_end", "get_sub_emitter_amount_at_end");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sub_emitter_keep_velocity"), "set_sub_emitter_keep_velocity", "get_sub_emitter_keep_velocity");
diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h
index 57da344ce0..af45593f38 100644
--- a/scene/resources/particles_material.h
+++ b/scene/resources/particles_material.h
@@ -109,6 +109,14 @@ private:
uint32_t key = 0;
+ static uint32_t hash(const MaterialKey &p_key) {
+ return hash_murmur3_one_32(p_key.key);
+ }
+
+ bool operator==(const MaterialKey &p_key) const {
+ return key == p_key.key;
+ }
+
bool operator<(const MaterialKey &p_key) const {
return key < p_key.key;
}
@@ -119,7 +127,7 @@ private:
int users = 0;
};
- static Map<MaterialKey, ShaderData> shader_map;
+ static HashMap<MaterialKey, ShaderData, MaterialKey> shader_map;
MaterialKey current_key;
@@ -230,8 +238,8 @@ private:
bool is_initialized = false;
Vector3 direction;
- float spread;
- float flatness;
+ float spread = 0.0f;
+ float flatness = 0.0f;
float params_min[PARAM_MAX];
float params_max[PARAM_MAX];
@@ -244,34 +252,34 @@ private:
bool particle_flags[PARTICLE_FLAG_MAX];
EmissionShape emission_shape;
- float emission_sphere_radius;
+ float emission_sphere_radius = 0.0f;
Vector3 emission_box_extents;
Ref<Texture2D> emission_point_texture;
Ref<Texture2D> emission_normal_texture;
Ref<Texture2D> emission_color_texture;
Vector3 emission_ring_axis;
- real_t emission_ring_height;
- real_t emission_ring_radius;
- real_t emission_ring_inner_radius;
+ real_t emission_ring_height = 0.0f;
+ real_t emission_ring_radius = 0.0f;
+ real_t emission_ring_inner_radius = 0.0f;
int emission_point_count = 1;
- bool anim_loop;
+ bool anim_loop = false;
Vector3 gravity;
- double lifetime_randomness;
+ double lifetime_randomness = 0.0;
SubEmitterMode sub_emitter_mode;
- double sub_emitter_frequency;
- int sub_emitter_amount_at_end;
- bool sub_emitter_keep_velocity;
+ double sub_emitter_frequency = 0.0;
+ int sub_emitter_amount_at_end = 0;
+ bool sub_emitter_keep_velocity = false;
//do not save emission points here
- bool attractor_interaction_enabled;
- bool collision_enabled;
- bool collision_scale;
- float collision_friction;
- float collision_bounce;
+ bool attractor_interaction_enabled = false;
+ bool collision_enabled = false;
+ bool collision_scale = false;
+ float collision_friction = 0.0f;
+ float collision_bounce = 0.0f;
protected:
static void _bind_methods();
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index 882afdb43d..29135e30c9 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -34,8 +34,8 @@
bool PolygonPathFinder::_is_point_inside(const Vector2 &p_point) const {
int crosses = 0;
- for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
Vector2 a = points[e.points[0]].pos;
Vector2 b = points[e.points[1]].pos;
@@ -105,8 +105,8 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int>
bool valid = true;
- for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
if (e.points[0] == i || e.points[1] == i || e.points[0] == j || e.points[1] == j) {
continue;
}
@@ -137,11 +137,11 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
Edge ignore_to_edge(-1, -1);
if (!_is_point_inside(from)) {
- float closest_dist = 1e20;
+ float closest_dist = 1e20f;
Vector2 closest_point;
- for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
Vector2 seg[2] = {
points[e.points[0]].pos,
points[e.points[1]].pos
@@ -151,7 +151,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
float d = from.distance_squared_to(closest);
if (d < closest_dist) {
- ignore_from_edge = E->get();
+ ignore_from_edge = E;
closest_dist = d;
closest_point = closest;
}
@@ -161,11 +161,11 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
};
if (!_is_point_inside(to)) {
- float closest_dist = 1e20;
+ float closest_dist = 1e20f;
Vector2 closest_point;
- for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
Vector2 seg[2] = {
points[e.points[0]].pos,
points[e.points[1]].pos
@@ -175,7 +175,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
float d = to.distance_squared_to(closest);
if (d < closest_dist) {
- ignore_to_edge = E->get();
+ ignore_to_edge = E;
closest_dist = d;
closest_point = closest;
}
@@ -188,8 +188,8 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
{
bool can_see_eachother = true;
- for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
if (e.points[0] == ignore_from_edge.points[0] && e.points[1] == ignore_from_edge.points[1]) {
continue;
}
@@ -240,8 +240,8 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
valid_b = false;
}
- for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
if (e.points[0] == i || e.points[1] == i) {
continue;
@@ -289,14 +289,14 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
}
//solve graph
- Set<int> open_list;
+ HashSet<int> open_list;
points.write[aidx].distance = 0;
points.write[aidx].prev = aidx;
- for (Set<int>::Element *E = points[aidx].connections.front(); E; E = E->next()) {
- open_list.insert(E->get());
- points.write[E->get()].distance = from.distance_to(points[E->get()].pos);
- points.write[E->get()].prev = aidx;
+ for (const int &E : points[aidx].connections) {
+ open_list.insert(E);
+ points.write[E].distance = from.distance_to(points[E].pos);
+ points.write[E].prev = aidx;
}
bool found_route = false;
@@ -312,14 +312,14 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
float least_cost = 1e30;
//this could be faster (cache previous results)
- for (Set<int>::Element *E = open_list.front(); E; E = E->next()) {
- const Point &p = points[E->get()];
+ for (const int &E : open_list) {
+ const Point &p = points[E];
float cost = p.distance;
cost += p.pos.distance_to(to);
cost += p.penalty;
if (cost < least_cost) {
- least_cost_point = E->get();
+ least_cost_point = E;
least_cost = cost;
}
}
@@ -327,8 +327,8 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
const Point &np = points[least_cost_point];
//open the neighbours for search
- for (Set<int>::Element *E = np.connections.front(); E; E = E->next()) {
- Point &p = points.write[E->get()];
+ for (const int &E : np.connections) {
+ Point &p = points.write[E];
float distance = np.pos.distance_to(p.pos) + np.distance;
if (p.prev != -1) {
@@ -343,9 +343,9 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
p.prev = least_cost_point;
p.distance = distance;
- open_list.insert(E->get());
+ open_list.insert(E);
- if (E->get() == bidx) {
+ if (E == bidx) {
//oh my reached end! stop algorithm
found_route = true;
break;
@@ -459,8 +459,8 @@ Dictionary PolygonPathFinder::_get_data() const {
{
int *cw = c.ptrw();
int idx = 0;
- for (Set<int>::Element *E = points[i].connections.front(); E; E = E->next()) {
- cw[idx++] = E->get();
+ for (const int &E : points[i].connections) {
+ cw[idx++] = E;
}
}
connections[i] = c;
@@ -469,9 +469,9 @@ Dictionary PolygonPathFinder::_get_data() const {
{
int *iw = ind.ptrw();
int idx = 0;
- for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
- iw[idx++] = E->get().points[0];
- iw[idx++] = E->get().points[1];
+ for (const Edge &E : edges) {
+ iw[idx++] = E.points[0];
+ iw[idx++] = E.points[1];
}
}
@@ -489,11 +489,11 @@ bool PolygonPathFinder::is_point_inside(const Vector2 &p_point) const {
}
Vector2 PolygonPathFinder::get_closest_point(const Vector2 &p_point) const {
- float closest_dist = 1e20;
+ float closest_dist = 1e20f;
Vector2 closest_point;
- for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
- const Edge &e = E->get();
+ for (const Edge &E : edges) {
+ const Edge &e = E;
Vector2 seg[2] = {
points[e.points[0]].pos,
points[e.points[1]].pos
@@ -508,7 +508,7 @@ Vector2 PolygonPathFinder::get_closest_point(const Vector2 &p_point) const {
}
}
- ERR_FAIL_COND_V(closest_dist == 1e20, Vector2());
+ ERR_FAIL_COND_V(Math::is_equal_approx(closest_dist, 1e20f), Vector2());
return closest_point;
}
@@ -516,9 +516,9 @@ Vector2 PolygonPathFinder::get_closest_point(const Vector2 &p_point) const {
Vector<Vector2> PolygonPathFinder::get_intersections(const Vector2 &p_from, const Vector2 &p_to) const {
Vector<Vector2> inters;
- for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
- Vector2 a = points[E->get().points[0]].pos;
- Vector2 b = points[E->get().points[1]].pos;
+ for (const Edge &E : edges) {
+ Vector2 a = points[E.points[0]].pos;
+ Vector2 b = points[E.points[1]].pos;
Vector2 res;
if (Geometry2D::segment_intersects_segment(a, b, p_from, p_to, &res)) {
diff --git a/scene/resources/polygon_path_finder.h b/scene/resources/polygon_path_finder.h
index db96192917..0e22b53dcb 100644
--- a/scene/resources/polygon_path_finder.h
+++ b/scene/resources/polygon_path_finder.h
@@ -38,21 +38,23 @@ class PolygonPathFinder : public Resource {
struct Point {
Vector2 pos;
- Set<int> connections;
+ HashSet<int> connections;
float distance = 0.0;
float penalty = 0.0;
int prev = 0;
};
- struct Edge {
- int points[2] = {};
+ union Edge {
+ struct {
+ int32_t points[2];
+ };
+ uint64_t key = 0;
- _FORCE_INLINE_ bool operator<(const Edge &p_edge) const {
- if (points[0] == p_edge.points[0]) {
- return points[1] < p_edge.points[1];
- } else {
- return points[0] < p_edge.points[0];
- }
+ _FORCE_INLINE_ bool operator==(const Edge &p_edge) const {
+ return key == p_edge.key;
+ }
+ _FORCE_INLINE_ static uint32_t hash(const Edge &p_edge) {
+ return hash_one_uint64(p_edge.key);
}
Edge(int a = 0, int b = 0) {
@@ -68,7 +70,7 @@ class PolygonPathFinder : public Resource {
Rect2 bounds;
Vector<Point> points;
- Set<Edge> edges;
+ HashSet<Edge, Edge> edges;
bool _is_point_inside(const Vector2 &p_point) const;
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 40edc5f198..68441afb1c 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -29,7 +29,12 @@
/*************************************************************************/
#include "primitive_meshes.h"
+
+#include "core/core_string_names.h"
+#include "scene/resources/theme.h"
#include "servers/rendering_server.h"
+#include "thirdparty/misc/clipper.hpp"
+#include "thirdparty/misc/polypartition.h"
/**
PrimitiveMesh
@@ -214,7 +219,7 @@ void PrimitiveMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_flip_faces"), &PrimitiveMesh::get_flip_faces);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material");
- ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb");
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, "suffix:m"), "set_custom_aabb", "get_custom_aabb");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces");
GDVIRTUAL_BIND(_create_mesh_array);
@@ -314,7 +319,7 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
Vector3 p = Vector3(x * radius * w, y, -z * radius * w);
points.push_back(p + Vector3(0.0, 0.5 * height - radius, 0.0));
normals.push_back(p.normalized());
- ADD_TANGENT(z, 0.0, x, 1.0)
+ ADD_TANGENT(-z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, v * onethird));
point++;
@@ -353,7 +358,7 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
Vector3 p = Vector3(x * radius, y, -z * radius);
points.push_back(p);
normals.push_back(Vector3(x, 0.0, -z));
- ADD_TANGENT(z, 0.0, x, 1.0)
+ ADD_TANGENT(-z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, onethird + (v * onethird)));
point++;
@@ -393,7 +398,7 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
Vector3 p = Vector3(x * radius * w, y, -z * radius * w);
points.push_back(p + Vector3(0.0, -0.5 * height + radius, 0.0));
normals.push_back(p.normalized());
- ADD_TANGENT(z, 0.0, x, 1.0)
+ ADD_TANGENT(-z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u2, twothirds + ((v - 1.0) * onethird)));
point++;
@@ -430,16 +435,19 @@ void CapsuleMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CapsuleMesh::set_rings);
ClassDB::bind_method(D_METHOD("get_rings"), &CapsuleMesh::get_rings);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
+
+ ADD_LINKED_PROPERTY("radius", "height");
+ ADD_LINKED_PROPERTY("height", "radius");
}
void CapsuleMesh::set_radius(const float p_radius) {
radius = p_radius;
if (radius > height * 0.5) {
- radius = height * 0.5;
+ height = radius * 2.0;
}
_request_update();
}
@@ -451,7 +459,7 @@ float CapsuleMesh::get_radius() const {
void CapsuleMesh::set_height(const float p_height) {
height = p_height;
if (radius > height * 0.5) {
- height = radius * 2;
+ radius = height * 0.5;
}
_request_update();
}
@@ -691,7 +699,7 @@ void BoxMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &BoxMesh::set_subdivide_depth);
ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &BoxMesh::get_subdivide_depth);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_height", "get_subdivide_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
@@ -740,10 +748,10 @@ BoxMesh::BoxMesh() {}
*/
void CylinderMesh::_create_mesh_array(Array &p_arr) const {
- create_mesh_array(p_arr, top_radius, bottom_radius, height, radial_segments, rings);
+ create_mesh_array(p_arr, top_radius, bottom_radius, height, radial_segments, rings, cap_top, cap_bottom);
}
-void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments, int rings) {
+void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments, int rings, bool cap_top, bool cap_bottom) {
int i, j, prevrow, thisrow, point;
float x, y, z, u, v, radius;
@@ -801,7 +809,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
};
// add top
- if (top_radius > 0.0) {
+ if (cap_top && top_radius > 0.0) {
y = height * 0.5;
thisrow = point;
@@ -837,7 +845,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
};
// add bottom
- if (bottom_radius > 0.0) {
+ if (cap_bottom && bottom_radius > 0.0) {
y = height * -0.5;
thisrow = point;
@@ -892,11 +900,19 @@ void CylinderMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CylinderMesh::set_rings);
ClassDB::bind_method(D_METHOD("get_rings"), &CylinderMesh::get_rings);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "top_radius", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_top_radius", "get_top_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bottom_radius", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_bottom_radius", "get_bottom_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_height", "get_height");
+ ClassDB::bind_method(D_METHOD("set_cap_top", "cap_top"), &CylinderMesh::set_cap_top);
+ ClassDB::bind_method(D_METHOD("is_cap_top"), &CylinderMesh::is_cap_top);
+
+ ClassDB::bind_method(D_METHOD("set_cap_bottom", "cap_bottom"), &CylinderMesh::set_cap_bottom);
+ ClassDB::bind_method(D_METHOD("is_cap_bottom"), &CylinderMesh::is_cap_bottom);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "top_radius", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater,suffix:m"), "set_top_radius", "get_top_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bottom_radius", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater,suffix:m"), "set_bottom_radius", "get_bottom_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cap_top"), "set_cap_top", "is_cap_top");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cap_bottom"), "set_cap_bottom", "is_cap_bottom");
}
void CylinderMesh::set_top_radius(const float p_radius) {
@@ -944,6 +960,24 @@ int CylinderMesh::get_rings() const {
return rings;
}
+void CylinderMesh::set_cap_top(bool p_cap_top) {
+ cap_top = p_cap_top;
+ _request_update();
+}
+
+bool CylinderMesh::is_cap_top() const {
+ return cap_top;
+}
+
+void CylinderMesh::set_cap_bottom(bool p_cap_bottom) {
+ cap_bottom = p_cap_bottom;
+ _request_update();
+}
+
+bool CylinderMesh::is_cap_bottom() const {
+ return cap_bottom;
+}
+
CylinderMesh::CylinderMesh() {}
/**
@@ -1022,10 +1056,10 @@ void PlaneMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_center_offset", "offset"), &PlaneMesh::set_center_offset);
ClassDB::bind_method(D_METHOD("get_center_offset"), &PlaneMesh::get_center_offset);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset"), "set_center_offset", "get_center_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_center_offset", "get_center_offset");
}
void PlaneMesh::set_size(const Size2 &p_size) {
@@ -1293,7 +1327,7 @@ void PrismMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PrismMesh::get_subdivide_depth);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "left_to_right", PROPERTY_HINT_RANGE, "-2.0,2.0,0.1"), "set_left_to_right", "get_left_to_right");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_height", "get_subdivide_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
@@ -1406,8 +1440,8 @@ void QuadMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_center_offset", "center_offset"), &QuadMesh::set_center_offset);
ClassDB::bind_method(D_METHOD("get_center_offset"), &QuadMesh::get_center_offset);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset"), "set_center_offset", "get_center_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_center_offset", "get_center_offset");
}
uint32_t QuadMesh::surface_get_format(int p_idx) const {
@@ -1533,8 +1567,8 @@ void SphereMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_is_hemisphere", "is_hemisphere"), &SphereMesh::set_is_hemisphere);
ClassDB::bind_method(D_METHOD("get_is_hemisphere"), &SphereMesh::get_is_hemisphere);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_hemisphere"), "set_is_hemisphere", "get_is_hemisphere");
@@ -1912,12 +1946,12 @@ void TubeTrailMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_curve", "curve"), &TubeTrailMesh::set_curve);
ClassDB::bind_method(D_METHOD("get_curve"), &TubeTrailMesh::get_curve);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_steps", PROPERTY_HINT_RANGE, "3,128,1"), "set_radial_steps", "get_radial_steps");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_sections", "get_sections");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "section_length", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001,or_greater"), "set_section_length", "get_section_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "section_length", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001,or_greater,suffix:m"), "set_section_length", "get_section_length");
ADD_PROPERTY(PropertyInfo(Variant::INT, "section_rings", PROPERTY_HINT_RANGE, "1,128,1"), "set_section_rings", "get_section_rings");
@@ -2139,9 +2173,9 @@ void RibbonTrailMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_shape"), &RibbonTrailMesh::get_shape);
ADD_PROPERTY(PropertyInfo(Variant::INT, "shape", PROPERTY_HINT_ENUM, "Flat,Cross"), "set_shape", "get_shape");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_sections", "get_sections");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "section_length", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001,or_greater"), "set_section_length", "get_section_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "section_length", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001,or_greater,suffix:m"), "set_section_length", "get_section_length");
ADD_PROPERTY(PropertyInfo(Variant::INT, "section_segments", PROPERTY_HINT_RANGE, "1,128,1"), "set_section_segments", "get_section_segments");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
@@ -2151,3 +2185,769 @@ void RibbonTrailMesh::_bind_methods() {
RibbonTrailMesh::RibbonTrailMesh() {
}
+
+/*************************************************************************/
+/* TextMesh */
+/*************************************************************************/
+
+void TextMesh::_generate_glyph_mesh_data(const GlyphMeshKey &p_key, const Glyph &p_gl) const {
+ if (cache.has(p_key)) {
+ return;
+ }
+
+ GlyphMeshData &gl_data = cache[p_key];
+
+ Dictionary d = TS->font_get_glyph_contours(p_gl.font_rid, p_gl.font_size, p_gl.index);
+ Vector2 origin = Vector2(p_gl.x_off, p_gl.y_off) * pixel_size;
+
+ PackedVector3Array points = d["points"];
+ PackedInt32Array contours = d["contours"];
+ bool orientation = d["orientation"];
+
+ if (points.size() < 3 || contours.size() < 1) {
+ return; // No full contours, only glyph control points (or nothing), ignore.
+ }
+
+ // Approximate Bezier curves as polygons.
+ // See https://freetype.org/freetype2/docs/glyphs/glyphs-6.html, for more info.
+ for (int i = 0; i < contours.size(); i++) {
+ int32_t start = (i == 0) ? 0 : (contours[i - 1] + 1);
+ int32_t end = contours[i];
+ Vector<ContourPoint> polygon;
+
+ for (int32_t j = start; j <= end; j++) {
+ if (points[j].z == TextServer::CONTOUR_CURVE_TAG_ON) {
+ // Point on the curve.
+ Vector2 p = Vector2(points[j].x, points[j].y) * pixel_size + origin;
+ polygon.push_back(ContourPoint(p, true));
+ } else if (points[j].z == TextServer::CONTOUR_CURVE_TAG_OFF_CONIC) {
+ // Conic Bezier arc.
+ int32_t next = (j == end) ? start : (j + 1);
+ int32_t prev = (j == start) ? end : (j - 1);
+ Vector2 p0;
+ Vector2 p1 = Vector2(points[j].x, points[j].y);
+ Vector2 p2;
+
+ // For successive conic OFF points add a virtual ON point in the middle.
+ if (points[prev].z == TextServer::CONTOUR_CURVE_TAG_OFF_CONIC) {
+ p0 = (Vector2(points[prev].x, points[prev].y) + Vector2(points[j].x, points[j].y)) / 2.0;
+ } else if (points[prev].z == TextServer::CONTOUR_CURVE_TAG_ON) {
+ p0 = Vector2(points[prev].x, points[prev].y);
+ } else {
+ ERR_FAIL_MSG(vformat("Invalid conic arc point sequence at %d:%d", i, j));
+ }
+ if (points[next].z == TextServer::CONTOUR_CURVE_TAG_OFF_CONIC) {
+ p2 = (Vector2(points[j].x, points[j].y) + Vector2(points[next].x, points[next].y)) / 2.0;
+ } else if (points[next].z == TextServer::CONTOUR_CURVE_TAG_ON) {
+ p2 = Vector2(points[next].x, points[next].y);
+ } else {
+ ERR_FAIL_MSG(vformat("Invalid conic arc point sequence at %d:%d", i, j));
+ }
+
+ real_t step = CLAMP(curve_step / (p0 - p2).length(), 0.01, 0.5);
+ real_t t = step;
+ while (t < 1.0) {
+ real_t omt = (1.0 - t);
+ real_t omt2 = omt * omt;
+ real_t t2 = t * t;
+
+ Vector2 point = p1 + omt2 * (p0 - p1) + t2 * (p2 - p1);
+ Vector2 p = point * pixel_size + origin;
+ polygon.push_back(ContourPoint(p, false));
+ t += step;
+ }
+ } else if (points[j].z == TextServer::CONTOUR_CURVE_TAG_OFF_CUBIC) {
+ // Cubic Bezier arc.
+ int32_t cur = j;
+ int32_t next1 = (j == end) ? start : (j + 1);
+ int32_t next2 = (next1 == end) ? start : (next1 + 1);
+ int32_t prev = (j == start) ? end : (j - 1);
+
+ // There must be exactly two OFF points and two ON points for each cubic arc.
+ if (points[prev].z != TextServer::CONTOUR_CURVE_TAG_ON) {
+ cur = (cur == 0) ? end : cur - 1;
+ next1 = (next1 == 0) ? end : next1 - 1;
+ next2 = (next2 == 0) ? end : next2 - 1;
+ prev = (prev == 0) ? end : prev - 1;
+ } else {
+ j++;
+ }
+ ERR_FAIL_COND_MSG(points[prev].z != TextServer::CONTOUR_CURVE_TAG_ON, vformat("Invalid cubic arc point sequence at %d:%d", i, prev));
+ ERR_FAIL_COND_MSG(points[cur].z != TextServer::CONTOUR_CURVE_TAG_OFF_CUBIC, vformat("Invalid cubic arc point sequence at %d:%d", i, cur));
+ ERR_FAIL_COND_MSG(points[next1].z != TextServer::CONTOUR_CURVE_TAG_OFF_CUBIC, vformat("Invalid cubic arc point sequence at %d:%d", i, next1));
+ ERR_FAIL_COND_MSG(points[next2].z != TextServer::CONTOUR_CURVE_TAG_ON, vformat("Invalid cubic arc point sequence at %d:%d", i, next2));
+
+ Vector2 p0 = Vector2(points[prev].x, points[prev].y);
+ Vector2 p1 = Vector2(points[cur].x, points[cur].y);
+ Vector2 p2 = Vector2(points[next1].x, points[next1].y);
+ Vector2 p3 = Vector2(points[next2].x, points[next2].y);
+
+ real_t step = CLAMP(curve_step / (p0 - p3).length(), 0.01, 0.5);
+ real_t t = step;
+ while (t < 1.0) {
+ real_t omt = (1.0 - t);
+ real_t omt2 = omt * omt;
+ real_t omt3 = omt2 * omt;
+ real_t t2 = t * t;
+ real_t t3 = t2 * t;
+
+ Vector2 point = p0 * omt3 + p1 * omt2 * t * 3.0 + p2 * omt * t2 * 3.0 + p3 * t3;
+ Vector2 p = point * pixel_size + origin;
+ polygon.push_back(ContourPoint(p, false));
+ t += step;
+ }
+ } else {
+ ERR_FAIL_MSG(vformat("Unknown point tag at %d:%d", i, j));
+ }
+ }
+
+ if (polygon.size() < 3) {
+ continue; // Skip glyph control points.
+ }
+
+ if (!orientation) {
+ polygon.reverse();
+ }
+
+ gl_data.contours.push_back(polygon);
+ }
+
+ // Calculate bounds.
+ List<TPPLPoly> in_poly;
+ for (int i = 0; i < gl_data.contours.size(); i++) {
+ TPPLPoly inp;
+ inp.Init(gl_data.contours[i].size());
+ real_t length = 0.0;
+ for (int j = 0; j < gl_data.contours[i].size(); j++) {
+ int next = (j + 1 == gl_data.contours[i].size()) ? 0 : (j + 1);
+
+ gl_data.min_p.x = MIN(gl_data.min_p.x, gl_data.contours[i][j].point.x);
+ gl_data.min_p.y = MIN(gl_data.min_p.y, gl_data.contours[i][j].point.y);
+ gl_data.max_p.x = MAX(gl_data.max_p.x, gl_data.contours[i][j].point.x);
+ gl_data.max_p.y = MAX(gl_data.max_p.y, gl_data.contours[i][j].point.y);
+ length += (gl_data.contours[i][next].point - gl_data.contours[i][j].point).length();
+
+ inp.GetPoint(j) = gl_data.contours[i][j].point;
+ }
+ TPPLOrientation poly_orient = inp.GetOrientation();
+ if (poly_orient == TPPL_ORIENTATION_CW) {
+ inp.SetHole(true);
+ }
+ in_poly.push_back(inp);
+ gl_data.contours_info.push_back(ContourInfo(length, poly_orient == TPPL_ORIENTATION_CCW));
+ }
+
+ TPPLPartition tpart;
+
+ //Decompose and triangulate.
+ List<TPPLPoly> out_poly;
+ if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) {
+ ERR_FAIL_MSG("Convex decomposing failed. Make sure the font doesn't contain self-intersecting lines, as these are not supported in TextMesh.");
+ }
+ List<TPPLPoly> out_tris;
+ for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) {
+ if (tpart.Triangulate_OPT(&(I->get()), &out_tris) == 0) {
+ ERR_FAIL_MSG("Triangulation failed. Make sure the font doesn't contain self-intersecting lines, as these are not supported in TextMesh.");
+ }
+ }
+
+ for (List<TPPLPoly>::Element *I = out_tris.front(); I; I = I->next()) {
+ TPPLPoly &tp = I->get();
+ ERR_FAIL_COND(tp.GetNumPoints() != 3); // Triangles only.
+
+ for (int i = 0; i < 3; i++) {
+ gl_data.triangles.push_back(Vector2(tp.GetPoint(i).x, tp.GetPoint(i).y));
+ }
+ }
+}
+
+void TextMesh::_create_mesh_array(Array &p_arr) const {
+ Ref<Font> font = _get_font_or_default();
+ ERR_FAIL_COND(font.is_null());
+
+ if (dirty_cache) {
+ cache.clear();
+ dirty_cache = false;
+ }
+
+ // Update text buffer.
+ if (dirty_text) {
+ TS->shaped_text_clear(text_rid);
+ TS->shaped_text_set_direction(text_rid, text_direction);
+
+ String text = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text;
+ TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, font->get_opentype_features(), language);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
+ }
+
+ Array stt;
+ if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
+ GDVIRTUAL_CALL(_structured_text_parser, st_args, text, stt);
+ } else {
+ stt = TS->parse_structured_text(st_parser, st_args, text);
+ }
+ TS->shaped_text_set_bidi_override(text_rid, stt);
+
+ dirty_text = false;
+ dirty_font = false;
+ if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ TS->shaped_text_fit_to_width(text_rid, width, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA);
+ }
+ } else if (dirty_font) {
+ int spans = TS->shaped_get_span_count(text_rid);
+ for (int i = 0; i < spans; i++) {
+ TS->shaped_set_span_update_font(text_rid, i, font->get_rids(), font_size, font->get_opentype_features());
+ }
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
+ }
+
+ dirty_font = false;
+ if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ TS->shaped_text_fit_to_width(text_rid, width, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA);
+ }
+ }
+
+ Vector2 offset;
+ const Glyph *glyphs = TS->shaped_text_get_glyphs(text_rid);
+ int gl_size = TS->shaped_text_get_glyph_count(text_rid);
+ float line_width = TS->shaped_text_get_width(text_rid) * pixel_size;
+
+ switch (horizontal_alignment) {
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ offset.x = 0.0;
+ break;
+ case HORIZONTAL_ALIGNMENT_FILL:
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ offset.x = -line_width / 2.0;
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ offset.x = -line_width;
+ } break;
+ }
+
+ bool has_depth = !Math::is_zero_approx(depth);
+
+ // Generate glyph data, precalculate size of the arrays and mesh bounds for UV.
+ int64_t p_size = 0;
+ int64_t i_size = 0;
+
+ Vector2 min_p = Vector2(INFINITY, INFINITY);
+ Vector2 max_p = Vector2(-INFINITY, -INFINITY);
+
+ Vector2 offset_pre = offset;
+ for (int i = 0; i < gl_size; i++) {
+ if (glyphs[i].index == 0) {
+ offset.x += glyphs[i].advance * pixel_size * glyphs[i].repeat;
+ continue;
+ }
+ if (glyphs[i].font_rid != RID()) {
+ GlyphMeshKey key = GlyphMeshKey(glyphs[i].font_rid.get_id(), glyphs[i].index);
+ _generate_glyph_mesh_data(key, glyphs[i]);
+ GlyphMeshData &gl_data = cache[key];
+
+ p_size += glyphs[i].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1);
+ i_size += glyphs[i].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1);
+
+ if (has_depth) {
+ for (int j = 0; j < gl_data.contours.size(); j++) {
+ p_size += glyphs[i].repeat * gl_data.contours[j].size() * 4;
+ i_size += glyphs[i].repeat * gl_data.contours[j].size() * 6;
+ }
+ }
+
+ for (int j = 0; j < glyphs[i].repeat; j++) {
+ min_p.x = MIN(gl_data.min_p.x + offset_pre.x, min_p.x);
+ min_p.y = MIN(gl_data.min_p.y + offset_pre.y, min_p.y);
+ max_p.x = MAX(gl_data.max_p.x + offset_pre.x, max_p.x);
+ max_p.y = MAX(gl_data.max_p.y + offset_pre.y, max_p.y);
+
+ offset_pre.x += glyphs[i].advance * pixel_size;
+ }
+ } else {
+ p_size += glyphs[i].repeat * 4;
+ i_size += glyphs[i].repeat * 6;
+
+ offset_pre.x += glyphs[i].advance * pixel_size * glyphs[i].repeat;
+ }
+ }
+
+ Vector<Vector3> vertices;
+ Vector<Vector3> normals;
+ Vector<float> tangents;
+ Vector<Vector2> uvs;
+ Vector<int32_t> indices;
+
+ vertices.resize(p_size);
+ normals.resize(p_size);
+ uvs.resize(p_size);
+ tangents.resize(p_size * 4);
+ indices.resize(i_size);
+
+ Vector3 *vertices_ptr = vertices.ptrw();
+ Vector3 *normals_ptr = normals.ptrw();
+ float *tangents_ptr = tangents.ptrw();
+ Vector2 *uvs_ptr = uvs.ptrw();
+ int32_t *indices_ptr = indices.ptrw();
+
+ // Generate mesh.
+ int32_t p_idx = 0;
+ int32_t i_idx = 0;
+ for (int i = 0; i < gl_size; i++) {
+ if (glyphs[i].index == 0) {
+ offset.x += glyphs[i].advance * pixel_size * glyphs[i].repeat;
+ continue;
+ }
+ if (glyphs[i].font_rid != RID()) {
+ GlyphMeshKey key = GlyphMeshKey(glyphs[i].font_rid.get_id(), glyphs[i].index);
+ _generate_glyph_mesh_data(key, glyphs[i]);
+ const GlyphMeshData &gl_data = cache[key];
+
+ int64_t ts = gl_data.triangles.size();
+ const Vector2 *ts_ptr = gl_data.triangles.ptr();
+
+ for (int j = 0; j < glyphs[i].repeat; j++) {
+ for (int k = 0; k < ts; k += 3) {
+ // Add front face.
+ for (int l = 0; l < 3; l++) {
+ Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, depth / 2.0);
+ vertices_ptr[p_idx] = point;
+ normals_ptr[p_idx] = Vector3(0.0, 0.0, 1.0);
+ if (has_depth) {
+ uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -min_p.y, -max_p.y, real_t(0.0), real_t(0.4)));
+ } else {
+ uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -min_p.y, -max_p.y, real_t(0.0), real_t(1.0)));
+ }
+ tangents_ptr[p_idx * 4 + 0] = 1.0;
+ tangents_ptr[p_idx * 4 + 1] = 0.0;
+ tangents_ptr[p_idx * 4 + 2] = 0.0;
+ tangents_ptr[p_idx * 4 + 3] = 1.0;
+ indices_ptr[i_idx++] = p_idx;
+ p_idx++;
+ }
+ if (has_depth) {
+ // Add back face.
+ for (int l = 2; l >= 0; l--) {
+ Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, -depth / 2.0);
+ vertices_ptr[p_idx] = point;
+ normals_ptr[p_idx] = Vector3(0.0, 0.0, -1.0);
+ uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -min_p.y, -max_p.y, real_t(0.4), real_t(0.8)));
+ tangents_ptr[p_idx * 4 + 0] = -1.0;
+ tangents_ptr[p_idx * 4 + 1] = 0.0;
+ tangents_ptr[p_idx * 4 + 2] = 0.0;
+ tangents_ptr[p_idx * 4 + 3] = 1.0;
+ indices_ptr[i_idx++] = p_idx;
+ p_idx++;
+ }
+ }
+ }
+ // Add sides.
+ if (has_depth) {
+ for (int k = 0; k < gl_data.contours.size(); k++) {
+ int64_t ps = gl_data.contours[k].size();
+ const ContourPoint *ps_ptr = gl_data.contours[k].ptr();
+ const ContourInfo &ps_info = gl_data.contours_info[k];
+ real_t length = 0.0;
+ for (int l = 0; l < ps; l++) {
+ int prev = (l == 0) ? (ps - 1) : (l - 1);
+ int next = (l + 1 == ps) ? 0 : (l + 1);
+ Vector2 d1;
+ Vector2 d2 = (ps_ptr[next].point - ps_ptr[l].point).normalized();
+ if (ps_ptr[l].sharp) {
+ d1 = d2;
+ } else {
+ d1 = (ps_ptr[l].point - ps_ptr[prev].point).normalized();
+ }
+ real_t seg_len = (ps_ptr[next].point - ps_ptr[l].point).length();
+
+ Vector3 quad_faces[4] = {
+ Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, -depth / 2.0),
+ Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, -depth / 2.0),
+ Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, depth / 2.0),
+ Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, depth / 2.0),
+ };
+ for (int m = 0; m < 4; m++) {
+ const Vector2 &d = ((m % 2) == 0) ? d1 : d2;
+ real_t u_pos = ((m % 2) == 0) ? length : length + seg_len;
+ vertices_ptr[p_idx + m] = quad_faces[m];
+ normals_ptr[p_idx + m] = Vector3(d.y, d.x, 0.0);
+ if (m < 2) {
+ uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.8 : 0.9);
+ } else {
+ uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.9 : 1.0);
+ }
+ tangents_ptr[(p_idx + m) * 4 + 0] = d.x;
+ tangents_ptr[(p_idx + m) * 4 + 1] = -d.y;
+ tangents_ptr[(p_idx + m) * 4 + 2] = 0.0;
+ tangents_ptr[(p_idx + m) * 4 + 3] = 1.0;
+ }
+
+ indices_ptr[i_idx++] = p_idx;
+ indices_ptr[i_idx++] = p_idx + 1;
+ indices_ptr[i_idx++] = p_idx + 2;
+
+ indices_ptr[i_idx++] = p_idx + 1;
+ indices_ptr[i_idx++] = p_idx + 3;
+ indices_ptr[i_idx++] = p_idx + 2;
+
+ length += seg_len;
+ p_idx += 4;
+ }
+ }
+ }
+ offset.x += glyphs[i].advance * pixel_size;
+ }
+ } else {
+ // Add fallback quad for missing glyphs.
+ for (int j = 0; j < glyphs[i].repeat; j++) {
+ Size2 sz = TS->get_hex_code_box_size(glyphs[i].font_size, glyphs[i].index) * pixel_size;
+ Vector3 quad_faces[4] = {
+ Vector3(offset.x, offset.y, 0.0),
+ Vector3(offset.x, sz.y + offset.y, 0.0),
+ Vector3(sz.x + offset.x, sz.y + offset.y, 0.0),
+ Vector3(sz.x + offset.x, offset.y, 0.0),
+ };
+ for (int k = 0; k < 4; k++) {
+ vertices_ptr[p_idx + k] = quad_faces[k];
+ normals_ptr[p_idx + k] = Vector3(0.0, 0.0, 1.0);
+ if (has_depth) {
+ uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -min_p.y, -max_p.y, real_t(0.0), real_t(0.4)));
+ } else {
+ uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -min_p.y, -max_p.y, real_t(0.0), real_t(1.0)));
+ }
+ tangents_ptr[(p_idx + k) * 4 + 0] = 1.0;
+ tangents_ptr[(p_idx + k) * 4 + 1] = 0.0;
+ tangents_ptr[(p_idx + k) * 4 + 2] = 0.0;
+ tangents_ptr[(p_idx + k) * 4 + 3] = 1.0;
+ }
+
+ indices_ptr[i_idx++] = p_idx;
+ indices_ptr[i_idx++] = p_idx + 1;
+ indices_ptr[i_idx++] = p_idx + 2;
+
+ indices_ptr[i_idx++] = p_idx + 0;
+ indices_ptr[i_idx++] = p_idx + 2;
+ indices_ptr[i_idx++] = p_idx + 3;
+ p_idx += 4;
+
+ offset.x += glyphs[i].advance * pixel_size;
+ }
+ }
+ }
+
+ if (p_size == 0) {
+ // If empty, add single triangle to suppress errors.
+ vertices.push_back(Vector3());
+ normals.push_back(Vector3());
+ uvs.push_back(Vector2());
+ tangents.push_back(1.0);
+ tangents.push_back(0.0);
+ tangents.push_back(0.0);
+ tangents.push_back(1.0);
+ indices.push_back(0);
+ indices.push_back(0);
+ indices.push_back(0);
+ }
+
+ p_arr[RS::ARRAY_VERTEX] = vertices;
+ p_arr[RS::ARRAY_NORMAL] = normals;
+ p_arr[RS::ARRAY_TANGENT] = tangents;
+ p_arr[RS::ARRAY_TEX_UV] = uvs;
+ p_arr[RS::ARRAY_INDEX] = indices;
+}
+
+void TextMesh::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &TextMesh::set_horizontal_alignment);
+ ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &TextMesh::get_horizontal_alignment);
+
+ ClassDB::bind_method(D_METHOD("set_text", "text"), &TextMesh::set_text);
+ ClassDB::bind_method(D_METHOD("get_text"), &TextMesh::get_text);
+
+ ClassDB::bind_method(D_METHOD("set_font", "font"), &TextMesh::set_font);
+ ClassDB::bind_method(D_METHOD("get_font"), &TextMesh::get_font);
+
+ ClassDB::bind_method(D_METHOD("set_font_size", "font_size"), &TextMesh::set_font_size);
+ ClassDB::bind_method(D_METHOD("get_font_size"), &TextMesh::get_font_size);
+
+ ClassDB::bind_method(D_METHOD("set_depth", "depth"), &TextMesh::set_depth);
+ ClassDB::bind_method(D_METHOD("get_depth"), &TextMesh::get_depth);
+
+ ClassDB::bind_method(D_METHOD("set_width", "width"), &TextMesh::set_width);
+ ClassDB::bind_method(D_METHOD("get_width"), &TextMesh::get_width);
+
+ ClassDB::bind_method(D_METHOD("set_pixel_size", "pixel_size"), &TextMesh::set_pixel_size);
+ ClassDB::bind_method(D_METHOD("get_pixel_size"), &TextMesh::get_pixel_size);
+
+ ClassDB::bind_method(D_METHOD("set_curve_step", "curve_step"), &TextMesh::set_curve_step);
+ ClassDB::bind_method(D_METHOD("get_curve_step"), &TextMesh::get_curve_step);
+
+ ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &TextMesh::set_text_direction);
+ ClassDB::bind_method(D_METHOD("get_text_direction"), &TextMesh::get_text_direction);
+
+ ClassDB::bind_method(D_METHOD("set_language", "language"), &TextMesh::set_language);
+ ClassDB::bind_method(D_METHOD("get_language"), &TextMesh::get_language);
+
+ ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override", "parser"), &TextMesh::set_structured_text_bidi_override);
+ ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override"), &TextMesh::get_structured_text_bidi_override);
+
+ ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override_options", "args"), &TextMesh::set_structured_text_bidi_override_options);
+ ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override_options"), &TextMesh::get_structured_text_bidi_override_options);
+
+ ClassDB::bind_method(D_METHOD("set_uppercase", "enable"), &TextMesh::set_uppercase);
+ ClassDB::bind_method(D_METHOD("is_uppercase"), &TextMesh::is_uppercase);
+
+ ClassDB::bind_method(D_METHOD("_font_changed"), &TextMesh::_font_changed);
+ ClassDB::bind_method(D_METHOD("_request_update"), &TextMesh::_request_update);
+
+ ADD_GROUP("Text", "");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_font", "get_font");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "font_size", PROPERTY_HINT_RANGE, "1,256,1,or_greater,suffix:px"), "set_font_size", "get_font_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "horizontal_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_horizontal_alignment", "get_horizontal_alignment");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase");
+
+ ADD_GROUP("Mesh", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pixel_size", PROPERTY_HINT_RANGE, "0.0001,128,0.0001,suffix:m"), "set_pixel_size", "get_pixel_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "curve_step", PROPERTY_HINT_RANGE, "0.1,10,0.1,suffix:px"), "set_curve_step", "get_curve_step");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_RANGE, "0.0,100.0,0.001,or_greater,suffix:m"), "set_depth", "get_depth");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width", PROPERTY_HINT_NONE, "suffix:m"), "set_width", "get_width");
+
+ ADD_GROUP("BiDi", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left"), "set_text_direction", "get_text_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options");
+}
+
+void TextMesh::_notification(int p_what) {
+ switch (p_what) {
+ case MainLoop::NOTIFICATION_TRANSLATION_CHANGED: {
+ String new_text = tr(text);
+ if (new_text == xl_text) {
+ return; // Nothing new.
+ }
+ xl_text = new_text;
+ dirty_text = true;
+ _request_update();
+ } break;
+ }
+}
+
+TextMesh::TextMesh() {
+ primitive_type = PRIMITIVE_TRIANGLES;
+ text_rid = TS->create_shaped_text();
+}
+
+TextMesh::~TextMesh() {
+ TS->free_rid(text_rid);
+}
+
+void TextMesh::set_horizontal_alignment(HorizontalAlignment p_alignment) {
+ ERR_FAIL_INDEX((int)p_alignment, 4);
+ if (horizontal_alignment != p_alignment) {
+ if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ dirty_text = true;
+ }
+ horizontal_alignment = p_alignment;
+ _request_update();
+ }
+}
+
+HorizontalAlignment TextMesh::get_horizontal_alignment() const {
+ return horizontal_alignment;
+}
+
+void TextMesh::set_text(const String &p_string) {
+ if (text != p_string) {
+ text = p_string;
+ xl_text = tr(text);
+ dirty_text = true;
+ _request_update();
+ }
+}
+
+String TextMesh::get_text() const {
+ return text;
+}
+
+void TextMesh::_font_changed() {
+ dirty_font = true;
+ dirty_cache = true;
+ call_deferred(SNAME("_request_update"));
+}
+
+void TextMesh::set_font(const Ref<Font> &p_font) {
+ if (font_override != p_font) {
+ if (font_override.is_valid()) {
+ font_override->disconnect(CoreStringNames::get_singleton()->changed, Callable(this, "_font_changed"));
+ }
+ font_override = p_font;
+ dirty_font = true;
+ dirty_cache = true;
+ if (font_override.is_valid()) {
+ font_override->connect(CoreStringNames::get_singleton()->changed, Callable(this, "_font_changed"));
+ }
+ _request_update();
+ }
+}
+
+Ref<Font> TextMesh::get_font() const {
+ return font_override;
+}
+
+Ref<Font> TextMesh::_get_font_or_default() const {
+ if (font_override.is_valid()) {
+ return font_override;
+ }
+
+ // Check the project-defined Theme resource.
+ if (Theme::get_project_default().is_valid()) {
+ List<StringName> theme_types;
+ Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+
+ for (const StringName &E : theme_types) {
+ if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ return Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ }
+ }
+ }
+
+ // Lastly, fall back on the items defined in the default Theme, if they exist.
+ {
+ List<StringName> theme_types;
+ Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+
+ for (const StringName &E : theme_types) {
+ if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ }
+ }
+ }
+
+ // If they don't exist, use any type to return the default/empty value.
+ return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
+}
+
+void TextMesh::set_font_size(int p_size) {
+ if (font_size != p_size) {
+ font_size = CLAMP(p_size, 1, 127);
+ dirty_font = true;
+ dirty_cache = true;
+ _request_update();
+ }
+}
+
+int TextMesh::get_font_size() const {
+ return font_size;
+}
+
+void TextMesh::set_depth(real_t p_depth) {
+ if (depth != p_depth) {
+ depth = MAX(p_depth, 0.0);
+ _request_update();
+ }
+}
+
+real_t TextMesh::get_depth() const {
+ return depth;
+}
+
+void TextMesh::set_width(real_t p_width) {
+ if (width != p_width) {
+ width = p_width;
+ if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ dirty_text = true;
+ }
+ _request_update();
+ }
+}
+
+real_t TextMesh::get_width() const {
+ return width;
+}
+
+void TextMesh::set_pixel_size(real_t p_amount) {
+ if (pixel_size != p_amount) {
+ pixel_size = CLAMP(p_amount, 0.0001, 128.0);
+ dirty_cache = true;
+ _request_update();
+ }
+}
+
+real_t TextMesh::get_pixel_size() const {
+ return pixel_size;
+}
+
+void TextMesh::set_curve_step(real_t p_step) {
+ if (curve_step != p_step) {
+ curve_step = CLAMP(p_step, 0.1, 10.0);
+ dirty_cache = true;
+ _request_update();
+ }
+}
+
+real_t TextMesh::get_curve_step() const {
+ return curve_step;
+}
+
+void TextMesh::set_text_direction(TextServer::Direction p_text_direction) {
+ ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3);
+ if (text_direction != p_text_direction) {
+ text_direction = p_text_direction;
+ dirty_text = true;
+ _request_update();
+ }
+}
+
+TextServer::Direction TextMesh::get_text_direction() const {
+ return text_direction;
+}
+
+void TextMesh::set_language(const String &p_language) {
+ if (language != p_language) {
+ language = p_language;
+ dirty_text = true;
+ _request_update();
+ }
+}
+
+String TextMesh::get_language() const {
+ return language;
+}
+
+void TextMesh::set_structured_text_bidi_override(TextServer::StructuredTextParser p_parser) {
+ if (st_parser != p_parser) {
+ st_parser = p_parser;
+ dirty_text = true;
+ _request_update();
+ }
+}
+
+TextServer::StructuredTextParser TextMesh::get_structured_text_bidi_override() const {
+ return st_parser;
+}
+
+void TextMesh::set_structured_text_bidi_override_options(Array p_args) {
+ if (st_args != p_args) {
+ st_args = p_args;
+ dirty_text = true;
+ _request_update();
+ }
+}
+
+Array TextMesh::get_structured_text_bidi_override_options() const {
+ return st_args;
+}
+
+void TextMesh::set_uppercase(bool p_uppercase) {
+ if (uppercase != p_uppercase) {
+ uppercase = p_uppercase;
+ dirty_text = true;
+ _request_update();
+ }
+}
+
+bool TextMesh::is_uppercase() const {
+ return uppercase;
+}
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 8cd05c1740..cb93211756 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -31,7 +31,9 @@
#ifndef PRIMITIVE_MESHES_H
#define PRIMITIVE_MESHES_H
+#include "scene/resources/font.h"
#include "scene/resources/mesh.h"
+#include "servers/text_server.h"
///@TODO probably should change a few integers to unsigned integers...
@@ -181,13 +183,15 @@ private:
float height = 2.0;
int radial_segments = 64;
int rings = 4;
+ bool cap_top = true;
+ bool cap_bottom = true;
protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
public:
- static void create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments = 64, int rings = 4);
+ static void create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments = 64, int rings = 4, bool cap_top = true, bool cap_bottom = true);
void set_top_radius(const float p_radius);
float get_top_radius() const;
@@ -204,6 +208,12 @@ public:
void set_rings(const int p_rings);
int get_rings() const;
+ void set_cap_top(bool p_cap_top);
+ bool is_cap_top() const;
+
+ void set_cap_bottom(bool p_cap_bottom);
+ bool is_cap_bottom() const;
+
CylinderMesh();
};
@@ -247,7 +257,7 @@ class PrismMesh : public PrimitiveMesh {
private:
float left_to_right = 0.5;
- Vector3 size = Vector3(2.0, 2.0, 2.0);
+ Vector3 size = Vector3(1.0, 1.0, 1.0);
int subdivide_w = 0;
int subdivide_h = 0;
int subdivide_d = 0;
@@ -309,8 +319,8 @@ class SphereMesh : public PrimitiveMesh {
GDCLASS(SphereMesh, PrimitiveMesh);
private:
- float radius = 1.0;
- float height = 2.0;
+ float radius = 0.5;
+ float height = 1.0;
int radial_segments = 64;
int rings = 32;
bool is_hemisphere = false;
@@ -358,7 +368,7 @@ class TubeTrailMesh : public PrimitiveMesh {
GDCLASS(TubeTrailMesh, PrimitiveMesh);
private:
- float radius = 1.0;
+ float radius = 0.5;
int radial_steps = 8;
int sections = 5;
float section_length = 0.2;
@@ -447,5 +457,142 @@ public:
RibbonTrailMesh();
};
+/**
+ Text...
+*/
+
+class TextMesh : public PrimitiveMesh {
+ GDCLASS(TextMesh, PrimitiveMesh);
+
+private:
+ struct ContourPoint {
+ Vector2 point;
+ bool sharp = false;
+
+ ContourPoint(){};
+ ContourPoint(const Vector2 &p_pt, bool p_sharp) {
+ point = p_pt;
+ sharp = p_sharp;
+ };
+ };
+
+ struct ContourInfo {
+ real_t length = 0.0;
+ bool ccw = true;
+ ContourInfo(){};
+ ContourInfo(real_t p_len, bool p_ccw) {
+ length = p_len;
+ ccw = p_ccw;
+ }
+ };
+
+ struct GlyphMeshKey {
+ uint64_t font_id;
+ uint32_t gl_id;
+
+ bool operator==(const GlyphMeshKey &p_b) const {
+ return (font_id == p_b.font_id) && (gl_id == p_b.gl_id);
+ }
+
+ GlyphMeshKey(uint64_t p_font_id, uint32_t p_gl_id) {
+ font_id = p_font_id;
+ gl_id = p_gl_id;
+ }
+ };
+
+ struct GlyphMeshKeyHasher {
+ _FORCE_INLINE_ static uint32_t hash(const GlyphMeshKey &p_a) {
+ return hash_murmur3_buffer(&p_a, sizeof(GlyphMeshKey));
+ }
+ };
+
+ struct GlyphMeshData {
+ Vector<Vector2> triangles;
+ Vector<Vector<ContourPoint>> contours;
+ Vector<ContourInfo> contours_info;
+ Vector2 min_p = Vector2(INFINITY, INFINITY);
+ Vector2 max_p = Vector2(-INFINITY, -INFINITY);
+ };
+ mutable HashMap<GlyphMeshKey, GlyphMeshData, GlyphMeshKeyHasher> cache;
+
+ RID text_rid;
+ String text;
+ String xl_text;
+
+ int font_size = 16;
+ Ref<Font> font_override;
+ float width = 500.0;
+
+ HorizontalAlignment horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER;
+ bool uppercase = false;
+ String language;
+ TextServer::Direction text_direction = TextServer::DIRECTION_AUTO;
+ TextServer::StructuredTextParser st_parser = TextServer::STRUCTURED_TEXT_DEFAULT;
+ Array st_args;
+
+ real_t depth = 0.05;
+ real_t pixel_size = 0.01;
+ real_t curve_step = 0.5;
+
+ mutable bool dirty_text = true;
+ mutable bool dirty_font = true;
+ mutable bool dirty_cache = true;
+
+ void _generate_glyph_mesh_data(const GlyphMeshKey &p_key, const Glyph &p_glyph) const;
+ void _font_changed();
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+ virtual void _create_mesh_array(Array &p_arr) const override;
+
+public:
+ GDVIRTUAL2RC(Array, _structured_text_parser, Array, String)
+
+ TextMesh();
+ ~TextMesh();
+
+ void set_horizontal_alignment(HorizontalAlignment p_alignment);
+ HorizontalAlignment get_horizontal_alignment() const;
+
+ void set_text(const String &p_string);
+ String get_text() const;
+
+ void set_font(const Ref<Font> &p_font);
+ Ref<Font> get_font() const;
+ Ref<Font> _get_font_or_default() const;
+
+ void set_font_size(int p_size);
+ int get_font_size() const;
+
+ void set_text_direction(TextServer::Direction p_text_direction);
+ TextServer::Direction get_text_direction() const;
+
+ void set_language(const String &p_language);
+ String get_language() const;
+
+ void set_structured_text_bidi_override(TextServer::StructuredTextParser p_parser);
+ TextServer::StructuredTextParser get_structured_text_bidi_override() const;
+
+ void set_structured_text_bidi_override_options(Array p_args);
+ Array get_structured_text_bidi_override_options() const;
+
+ void set_uppercase(bool p_uppercase);
+ bool is_uppercase() const;
+
+ void set_width(real_t p_width);
+ real_t get_width() const;
+
+ void set_depth(real_t p_depth);
+ real_t get_depth() const;
+
+ void set_curve_step(real_t p_step);
+ real_t get_curve_step() const;
+
+ void set_pixel_size(real_t p_amount);
+ real_t get_pixel_size() const;
+};
+
VARIANT_ENUM_CAST(RibbonTrailMesh::Shape)
#endif
diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp
index 5e88c9974c..a64b262cb4 100644
--- a/scene/resources/rectangle_shape_2d.cpp
+++ b/scene/resources/rectangle_shape_2d.cpp
@@ -101,7 +101,7 @@ void RectangleShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size", "size"), &RectangleShape2D::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &RectangleShape2D::get_size);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
}
RectangleShape2D::RectangleShape2D() :
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 4b0456681b..66afb001fb 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
+#include "core/io/missing_resource.h"
#include "core/io/resource_format_binary.h"
#include "core/version.h"
@@ -39,6 +40,8 @@
// Version 3: new string ID for ext/subresources, breaks forward compat.
#define FORMAT_VERSION 3
+#define BINARY_FORMAT_VERSION 4
+
#include "core/io/dir_access.h"
#include "core/version.h"
@@ -65,12 +68,8 @@ Error ResourceLoaderText::_parse_sub_resource_dummy(DummyReadData *p_data, Varia
String unique_id = token.value;
if (!p_data->resource_map.has(unique_id)) {
- Ref<DummyResource> dr;
- dr.instantiate();
- dr->set_scene_unique_id(unique_id);
- p_data->resource_map[unique_id] = dr;
- uint32_t im_size = p_data->resource_index_map.size();
- p_data->resource_index_map.insert(dr, im_size);
+ r_err_str = "Found unique_id reference before mapping, sub-resources stored out of order in resource file";
+ return ERR_PARSE_ERROR;
}
r_res = p_data->resource_map[unique_id];
@@ -150,7 +149,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R
if (ext_resources[id].cache.is_valid()) {
r_res = ext_resources[id].cache;
} else if (use_sub_threads) {
- RES res = ResourceLoader::load_threaded_get(path);
+ Ref<Resource> res = ResourceLoader::load_threaded_get(path);
if (res.is_null()) {
if (ResourceLoader::get_abort_on_missing_resources()) {
error = ERR_FILE_MISSING_DEPENDENCIES;
@@ -171,7 +170,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R
return error;
}
} else {
- r_res = RES();
+ r_res = Ref<Resource>();
}
VariantParser::get_token(p_stream, token, line, r_err_str);
@@ -213,6 +212,15 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
type = SceneState::TYPE_INSTANCED; //no type? assume this was instantiated
}
+ HashSet<StringName> path_properties;
+
+ if (next_tag.fields.has("node_paths")) {
+ Vector<String> paths = next_tag.fields["node_paths"];
+ for (int i = 0; i < paths.size(); i++) {
+ path_properties.insert(paths[i]);
+ }
+ }
+
if (next_tag.fields.has("instance")) {
instance = packed_scene->get_state()->add_value(next_tag.fields["instance"]);
@@ -277,9 +285,10 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
}
if (!assign.is_empty()) {
- int nameidx = packed_scene->get_state()->add_name(assign);
+ StringName assign_name = assign;
+ int nameidx = packed_scene->get_state()->add_name(assign_name);
int valueidx = packed_scene->get_state()->add_value(value);
- packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx);
+ packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx, path_properties.has(assign_name));
//it's assignment
} else if (!next_tag.name.is_empty()) {
break;
@@ -460,7 +469,7 @@ Error ResourceLoaderText::load() {
}
} else {
- RES res = ResourceLoader::load(path, type);
+ Ref<Resource> res = ResourceLoader::load(path, type);
if (res.is_null()) {
if (ResourceLoader::get_abort_on_missing_resources()) {
@@ -527,28 +536,37 @@ Error ResourceLoaderText::load() {
if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
//reuse existing
- Resource *r = ResourceCache::get(path);
- if (r && r->get_class() == type) {
- res = Ref<Resource>(r);
+ Ref<Resource> cache = ResourceCache::get_ref(path);
+ if (cache.is_valid() && cache->get_class() == type) {
+ res = cache;
res->reset_state();
do_assign = true;
}
}
+ MissingResource *missing_resource = nullptr;
+
if (res.is_null()) { //not reuse
- if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && ResourceCache::has(path)) { //only if it doesn't exist
+ Ref<Resource> cache = ResourceCache::get_ref(path);
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && cache.is_valid()) { //only if it doesn't exist
//cached, do not assign
- Resource *r = ResourceCache::get(path);
- res = Ref<Resource>(r);
+ res = cache;
} else {
//create
Object *obj = ClassDB::instantiate(type);
if (!obj) {
- error_text += "Can't create sub resource of type: " + type;
- _printerr();
- error = ERR_FILE_CORRUPT;
- return error;
+ if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) {
+ missing_resource = memnew(MissingResource);
+ missing_resource->set_original_class(type);
+ missing_resource->set_recording_properties(true);
+ obj = missing_resource;
+ } else {
+ error_text += "Can't create sub resource of type: " + type;
+ _printerr();
+ error = ERR_FILE_CORRUPT;
+ return error;
+ }
}
Resource *r = Object::cast_to<Resource>(obj);
@@ -572,6 +590,8 @@ Error ResourceLoaderText::load() {
res->set_scene_unique_id(id);
}
+ Dictionary missing_resource_properties;
+
while (true) {
String assign;
Variant value;
@@ -585,7 +605,23 @@ Error ResourceLoaderText::load() {
if (!assign.is_empty()) {
if (do_assign) {
- res->set(assign, value);
+ bool set_valid = true;
+
+ if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) {
+ // If the property being set is a missing resource (and the parent is not),
+ // then setting it will most likely not work.
+ // Instead, save it as metadata.
+
+ Ref<MissingResource> mr = value;
+ if (mr.is_valid()) {
+ missing_resource_properties[assign] = mr;
+ set_valid = false;
+ }
+ }
+
+ if (set_valid) {
+ res->set(assign, value);
+ }
}
//it's assignment
} else if (!next_tag.name.is_empty()) {
@@ -599,6 +635,14 @@ Error ResourceLoaderText::load() {
}
}
+ if (missing_resource) {
+ missing_resource->set_recording_properties(false);
+ }
+
+ if (!missing_resource_properties.is_empty()) {
+ res->set_meta(META_MISSING_RESOURCES, missing_resource_properties);
+ }
+
if (progress && resources_total > 0) {
*progress = resource_current / float(resources_total);
}
@@ -616,21 +660,28 @@ Error ResourceLoaderText::load() {
return error;
}
- if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(local_path)) {
- Resource *r = ResourceCache::get(local_path);
- if (r->get_class() == res_type) {
- r->reset_state();
- resource = Ref<Resource>(r);
- }
+ Ref<Resource> cache = ResourceCache::get_ref(local_path);
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && cache.is_valid() && cache->get_class() == res_type) {
+ cache->reset_state();
+ resource = cache;
}
+ MissingResource *missing_resource = nullptr;
+
if (!resource.is_valid()) {
Object *obj = ClassDB::instantiate(res_type);
if (!obj) {
- error_text += "Can't create sub resource of type: " + res_type;
- _printerr();
- error = ERR_FILE_CORRUPT;
- return error;
+ if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) {
+ missing_resource = memnew(MissingResource);
+ missing_resource->set_original_class(res_type);
+ missing_resource->set_recording_properties(true);
+ obj = missing_resource;
+ } else {
+ error_text += "Can't create sub resource of type: " + res_type;
+ _printerr();
+ error = ERR_FILE_CORRUPT;
+ return error;
+ }
}
Resource *r = Object::cast_to<Resource>(obj);
@@ -646,6 +697,8 @@ Error ResourceLoaderText::load() {
resource_current++;
+ Dictionary missing_resource_properties;
+
while (true) {
String assign;
Variant value;
@@ -668,7 +721,23 @@ Error ResourceLoaderText::load() {
}
if (!assign.is_empty()) {
- resource->set(assign, value);
+ bool set_valid = true;
+
+ if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) {
+ // If the property being set is a missing resource (and the parent is not),
+ // then setting it will most likely not work.
+ // Instead, save it as metadata.
+
+ Ref<MissingResource> mr = value;
+ if (mr.is_valid()) {
+ missing_resource_properties[assign] = mr;
+ set_valid = false;
+ }
+ }
+
+ if (set_valid) {
+ resource->set(assign, value);
+ }
//it's assignment
} else if (!next_tag.name.is_empty()) {
error = ERR_FILE_CORRUPT;
@@ -676,14 +745,24 @@ Error ResourceLoaderText::load() {
_printerr();
return error;
} else {
- error = OK;
- if (progress && resources_total > 0) {
- *progress = resource_current / float(resources_total);
- }
-
- return error;
+ break;
}
}
+
+ if (missing_resource) {
+ missing_resource->set_recording_properties(false);
+ }
+
+ if (!missing_resource_properties.is_empty()) {
+ resource->set_meta(META_MISSING_RESOURCES, missing_resource_properties);
+ }
+
+ error = OK;
+ if (progress && resources_total > 0) {
+ *progress = resource_current / float(resources_total);
+ }
+
+ return error;
}
//for scene files
@@ -794,7 +873,7 @@ void ResourceLoaderText::get_dependencies(Ref<FileAccess> p_f, List<String> *p_d
}
}
-Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String &p_path, const Map<String, String> &p_map) {
+Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String &p_path, const HashMap<String, String> &p_map) {
open(p_f, true);
ERR_FAIL_COND_V(error != OK, error);
ignore_resource_parsing = true;
@@ -890,7 +969,6 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String
fw->store_8(c);
c = f->get_8();
}
- f.unref();
bool all_ok = fw->get_error() == OK;
@@ -898,10 +976,6 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String
return ERR_CANT_CREATE;
}
- Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- da->remove(p_path);
- da->rename(p_path + ".depren", p_path);
-
return OK;
}
@@ -1010,7 +1084,7 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
wf->store_32(0); //64 bits file, false for now
wf->store_32(VERSION_MAJOR);
wf->store_32(VERSION_MINOR);
- static const int save_format_version = 3; //use format version 3 for saving
+ static const int save_format_version = BINARY_FORMAT_VERSION;
wf->store_32(save_format_version);
bs_save_unicode_string(wf, is_scene ? "PackedScene" : resource_type);
@@ -1108,7 +1182,7 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
while (next_tag.name == "sub_resource" || next_tag.name == "resource") {
String type;
- int id = -1;
+ String id;
bool main_res;
if (next_tag.name == "sub_resource") {
@@ -1129,15 +1203,26 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
type = next_tag.fields["type"];
id = next_tag.fields["id"];
main_res = false;
+
+ if (!dummy_read.resource_map.has(id)) {
+ Ref<DummyResource> dr;
+ dr.instantiate();
+ dr->set_scene_unique_id(id);
+ dummy_read.resource_map[id] = dr;
+ uint32_t im_size = dummy_read.resource_index_map.size();
+ dummy_read.resource_index_map.insert(dr, im_size);
+ }
+
} else {
type = res_type;
- id = 0; //used for last anyway
+ String uid_text = ResourceUID::get_singleton()->id_to_text(res_uid);
+ id = type + "_" + uid_text.replace("uid://", "").replace("<invalid>", "0");
main_res = true;
}
local_offsets.push_back(wf2->get_position());
- bs_save_unicode_string(wf, "local://" + itos(id));
+ bs_save_unicode_string(wf, "local://" + id);
local_pointers_pos.push_back(wf->get_position());
wf->store_64(0); //temp local offset
@@ -1164,7 +1249,7 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
}
if (!assign.is_empty()) {
- Map<StringName, int> empty_string_map; //unused
+ HashMap<StringName, int> empty_string_map; //unused
bs_save_unicode_string(wf2, assign, true);
ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map);
prop_count++;
@@ -1206,7 +1291,8 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
List<PropertyInfo> props;
packed_scene->get_property_list(&props);
- bs_save_unicode_string(wf, "local://0");
+ String id = "PackedScene_" + ResourceUID::get_singleton()->id_to_text(res_uid).replace("uid://", "").replace("<invalid>", "0");
+ bs_save_unicode_string(wf, "local://" + id);
local_pointers_pos.push_back(wf->get_position());
wf->store_64(0); //temp local offset
@@ -1225,7 +1311,7 @@ Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_pa
String name = E.name;
Variant value = packed_scene->get(name);
- Map<StringName, int> empty_string_map; //unused
+ HashMap<StringName, int> empty_string_map; //unused
bs_save_unicode_string(wf2, name, true);
ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map);
prop_count++;
@@ -1332,7 +1418,7 @@ ResourceUID::ID ResourceLoaderText::get_uid(Ref<FileAccess> p_f) {
/////////////////////
-RES ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
@@ -1341,7 +1427,7 @@ RES ResourceFormatLoaderText::load(const String &p_path, const String &p_origina
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
- ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot open file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Cannot open file '" + p_path + "'.");
ResourceLoaderText loader;
String path = !p_original_path.is_empty() ? p_original_path : p_path;
@@ -1358,7 +1444,7 @@ RES ResourceFormatLoaderText::load(const String &p_path, const String &p_origina
if (err == OK) {
return loader.get_resource();
} else {
- return RES();
+ return Ref<Resource>();
}
}
@@ -1368,9 +1454,12 @@ void ResourceFormatLoaderText::get_recognized_extensions_for_type(const String &
return;
}
- if (p_type == "PackedScene") {
+ if (ClassDB::is_parent_class("PackedScene", p_type)) {
p_extensions->push_back("tscn");
- } else {
+ }
+
+ // Don't allow .tres for PackedScenes.
+ if (p_type != "PackedScene") {
p_extensions->push_back("tres");
}
}
@@ -1436,16 +1525,27 @@ void ResourceFormatLoaderText::get_dependencies(const String &p_path, List<Strin
loader.get_dependencies(f, p_dependencies, p_add_types);
}
-Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const Map<String, String> &p_map) {
- Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
- if (f.is_null()) {
- ERR_FAIL_V(ERR_CANT_OPEN);
+Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const HashMap<String, String> &p_map) {
+ Error err = OK;
+ {
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ if (f.is_null()) {
+ ERR_FAIL_V(ERR_CANT_OPEN);
+ }
+
+ ResourceLoaderText loader;
+ loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
+ loader.res_path = loader.local_path;
+ err = loader.rename_dependencies(f, p_path, p_map);
}
- ResourceLoaderText loader;
- loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
- loader.res_path = loader.local_path;
- return loader.rename_dependencies(f, p_path, p_map);
+ if (err == OK) {
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ da->remove(p_path);
+ da->rename(p_path + ".depren", p_path);
+ }
+
+ return err;
}
ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = nullptr;
@@ -1475,24 +1575,24 @@ Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path,
/*****************************************************************************************************/
/*****************************************************************************************************/
-String ResourceFormatSaverTextInstance::_write_resources(void *ud, const RES &p_resource) {
+String ResourceFormatSaverTextInstance::_write_resources(void *ud, const Ref<Resource> &p_resource) {
ResourceFormatSaverTextInstance *rsi = static_cast<ResourceFormatSaverTextInstance *>(ud);
return rsi->_write_resource(p_resource);
}
-String ResourceFormatSaverTextInstance::_write_resource(const RES &res) {
+String ResourceFormatSaverTextInstance::_write_resource(const Ref<Resource> &res) {
if (external_resources.has(res)) {
- return "ExtResource( \"" + external_resources[res] + "\" )";
+ return "ExtResource(\"" + external_resources[res] + "\")";
} else {
if (internal_resources.has(res)) {
- return "SubResource( \"" + internal_resources[res] + "\" )";
+ return "SubResource(\"" + internal_resources[res] + "\")";
} else if (!res->is_built_in()) {
if (res->get_path() == local_path) { //circular reference attempt
return "null";
}
//external resource
String path = relative_paths ? local_path.path_to_file(res->get_path()) : res->get_path();
- return "Resource( \"" + path + "\" )";
+ return "Resource(\"" + path + "\")";
} else {
ERR_FAIL_V_MSG("null", "Resource was not pre cached for the resource section, bug?");
//internal resource
@@ -1503,7 +1603,7 @@ String ResourceFormatSaverTextInstance::_write_resource(const RES &res) {
void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, bool p_main) {
switch (p_variant.get_type()) {
case Variant::OBJECT: {
- RES res = p_variant;
+ Ref<Resource> res = p_variant;
if (res.is_null() || external_resources.has(res)) {
return;
@@ -1540,7 +1640,7 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant,
Variant v = res->get(I->get().name);
if (pi.usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT) {
- RES sres = v;
+ Ref<Resource> sres = v;
if (sres.is_valid()) {
NonPersistentKey npk;
npk.base = res;
@@ -1584,7 +1684,16 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant,
}
}
-Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+static String _resource_get_class(Ref<Resource> p_resource) {
+ Ref<MissingResource> missing_resource = p_resource;
+ if (missing_resource.is_valid()) {
+ return missing_resource->get_original_class();
+ } else {
+ return p_resource->get_class();
+ }
+}
+
+Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
if (p_path.ends_with(".tscn")) {
packed_scene = p_resource;
}
@@ -1625,7 +1734,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
{
String title = packed_scene.is_valid() ? "[gd_scene " : "[gd_resource ";
if (packed_scene.is_null()) {
- title += "type=\"" + p_resource->get_class() + "\" ";
+ title += "type=\"" + _resource_get_class(p_resource) + "\" ";
}
int load_steps = saved_resources.size() + external_resources.size();
@@ -1646,8 +1755,8 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
#ifdef TOOLS_ENABLED
// Keep order from cached ids.
- Set<String> cached_ids_found;
- for (KeyValue<RES, String> &E : external_resources) {
+ HashSet<String> cached_ids_found;
+ for (KeyValue<Ref<Resource>, String> &E : external_resources) {
String cached_id = E.key->get_id_for_path(local_path);
if (cached_id.is_empty() || cached_ids_found.has(cached_id)) {
int sep_pos = E.value.find("_");
@@ -1663,7 +1772,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
}
}
// Create IDs for non cached resources.
- for (KeyValue<RES, String> &E : external_resources) {
+ for (KeyValue<Ref<Resource>, String> &E : external_resources) {
if (cached_ids_found.has(E.value)) { // Already cached, go on.
continue;
}
@@ -1685,14 +1794,14 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
#else
// Make sure to start from one, as it makes format more readable.
int counter = 1;
- for (KeyValue<RES, String> &E : external_resources) {
+ for (KeyValue<Ref<Resource>, String> &E : external_resources) {
E.value = itos(counter++);
}
#endif
Vector<ResourceSort> sorted_er;
- for (const KeyValue<RES, String> &E : external_resources) {
+ for (const KeyValue<Ref<Resource>, String> &E : external_resources) {
ResourceSort rs;
rs.resource = E.key;
rs.id = E.value;
@@ -1718,10 +1827,10 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
f->store_line(String()); // Separate.
}
- Set<String> used_unique_ids;
+ HashSet<String> used_unique_ids;
- for (List<RES>::Element *E = saved_resources.front(); E; E = E->next()) {
- RES res = E->get();
+ for (List<Ref<Resource>>::Element *E = saved_resources.front(); E; E = E->next()) {
+ Ref<Resource> res = E->get();
if (E->next() && res->is_built_in()) {
if (!res->get_scene_unique_id().is_empty()) {
if (used_unique_ids.has(res->get_scene_unique_id())) {
@@ -1733,8 +1842,8 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
}
}
- for (List<RES>::Element *E = saved_resources.front(); E; E = E->next()) {
- RES res = E->get();
+ for (List<Ref<Resource>>::Element *E = saved_resources.front(); E; E = E->next()) {
+ Ref<Resource> res = E->get();
ERR_CONTINUE(!resource_set.has(res));
bool main = (E->next() == nullptr);
@@ -1749,7 +1858,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
if (res->get_scene_unique_id().is_empty()) {
String new_id;
while (true) {
- new_id = res->get_class() + "_" + Resource::generate_scene_unique_id();
+ new_id = _resource_get_class(res) + "_" + Resource::generate_scene_unique_id();
if (!used_unique_ids.has(new_id)) {
break;
@@ -1761,7 +1870,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
}
String id = res->get_scene_unique_id();
- line += "type=\"" + res->get_class() + "\" id=\"" + id;
+ line += "type=\"" + _resource_get_class(res) + "\" id=\"" + id;
f->store_line(line + "\"]");
if (takeover_paths) {
res->set_path(p_path + "::" + id, true);
@@ -1773,12 +1882,17 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
#endif
}
+ Dictionary missing_resource_properties = p_resource->get_meta(META_MISSING_RESOURCES, Dictionary());
+
List<PropertyInfo> property_list;
res->get_property_list(&property_list);
for (List<PropertyInfo>::Element *PE = property_list.front(); PE; PE = PE->next()) {
if (skip_editor && PE->get().name.begins_with("__editor")) {
continue;
}
+ if (PE->get().name == META_PROPERTY_MISSING_RESOURCES) {
+ continue;
+ }
if (PE->get().usage & PROPERTY_USAGE_STORAGE) {
String name = PE->get().name;
@@ -1793,6 +1907,15 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
} else {
value = res->get(name);
}
+
+ if (PE->get().type == Variant::OBJECT && missing_resource_properties.has(PE->get().name)) {
+ // Was this missing resource overridden? If so do not save the old value.
+ Ref<Resource> ures = value;
+ if (ures.is_null()) {
+ value = missing_resource_properties[PE->get().name];
+ }
+ }
+
Variant default_value = ClassDB::class_get_default_property_value(res->get_class(), name);
if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) {
@@ -1826,6 +1949,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
Ref<PackedScene> instance = state->get_node_instance(i);
String instance_placeholder = state->get_node_instance_placeholder(i);
Vector<StringName> groups = state->get_node_groups(i);
+ Vector<String> deferred_node_paths = state->get_node_deferred_nodepath_properties(i);
String header = "[node";
header += " name=\"" + String(name).c_escape() + "\"";
@@ -1842,6 +1966,10 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
header += " index=\"" + itos(index) + "\"";
}
+ if (deferred_node_paths.size()) {
+ header += " node_paths=" + Variant(deferred_node_paths).get_construct_string();
+ }
+
if (groups.size()) {
// Write all groups on the same line as they're part of a section header.
// This improves readability while not impacting VCS friendliness too much,
@@ -1935,7 +2063,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
return OK;
}
-Error ResourceFormatSaverText::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error ResourceFormatSaverText::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
if (p_path.ends_with(".tscn") && !Ref<PackedScene>(p_resource).is_valid()) {
return ERR_FILE_UNRECOGNIZED;
}
@@ -1944,11 +2072,11 @@ Error ResourceFormatSaverText::save(const String &p_path, const RES &p_resource,
return saver.save(p_path, p_resource, p_flags);
}
-bool ResourceFormatSaverText::recognize(const RES &p_resource) const {
+bool ResourceFormatSaverText::recognize(const Ref<Resource> &p_resource) const {
return true; // All resources recognized!
}
-void ResourceFormatSaverText::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+void ResourceFormatSaverText::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
if (Ref<PackedScene>(p_resource).is_valid()) {
p_extensions->push_back("tscn"); // Text scene.
} else {
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index c6543e616d..5c6a937bf2 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -48,7 +48,7 @@ class ResourceLoaderText {
VariantParser::StreamFile stream;
struct ExtResource {
- RES cache;
+ Ref<Resource> cache;
String path;
String type;
};
@@ -58,8 +58,8 @@ class ResourceLoaderText {
bool ignore_resource_parsing = false;
- Map<String, ExtResource> ext_resources;
- Map<String, RES> int_resources;
+ HashMap<String, ExtResource> ext_resources;
+ HashMap<String, Ref<Resource>> int_resources;
int resources_total = 0;
int resource_current = 0;
@@ -76,7 +76,7 @@ class ResourceLoaderText {
ResourceUID::ID res_uid = ResourceUID::INVALID_ID;
- Map<String, String> remaps;
+ HashMap<String, String> remaps;
static Error _parse_sub_resources(void *p_self, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { return reinterpret_cast<ResourceLoaderText *>(p_self)->_parse_sub_resource(p_stream, r_res, line, r_err_str); }
static Error _parse_ext_resources(void *p_self, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { return reinterpret_cast<ResourceLoaderText *>(p_self)->_parse_ext_resource(p_stream, r_res, line, r_err_str); }
@@ -90,10 +90,10 @@ class ResourceLoaderText {
};
struct DummyReadData {
- Map<RES, int> external_resources;
- Map<String, RES> rev_external_resources;
- Map<RES, int> resource_index_map;
- Map<String, RES> resource_map;
+ HashMap<Ref<Resource>, int> external_resources;
+ HashMap<String, Ref<Resource>> rev_external_resources;
+ HashMap<Ref<Resource>, int> resource_index_map;
+ HashMap<String, Ref<Resource>> resource_map;
};
static Error _parse_sub_resource_dummys(void *p_self, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { return _parse_sub_resource_dummy(static_cast<DummyReadData *>(p_self), p_stream, r_res, line, r_err_str); }
@@ -108,7 +108,7 @@ class ResourceLoaderText {
Error error = OK;
- RES resource;
+ Ref<Resource> resource;
Ref<PackedScene> _parse_node_tag(VariantParser::ResourceParser &parser);
@@ -124,7 +124,7 @@ public:
String recognize(Ref<FileAccess> p_f);
ResourceUID::ID get_uid(Ref<FileAccess> p_f);
void get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types);
- Error rename_dependencies(Ref<FileAccess> p_f, const String &p_path, const Map<String, String> &p_map);
+ Error rename_dependencies(Ref<FileAccess> p_f, const String &p_path, const HashMap<String, String> &p_map);
Error save_as_binary(Ref<FileAccess> p_f, const String &p_path);
ResourceLoaderText();
@@ -133,14 +133,14 @@ public:
class ResourceFormatLoaderText : public ResourceFormatLoader {
public:
static ResourceFormatLoaderText *singleton;
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
virtual ResourceUID::ID get_resource_uid(const String &p_path) const;
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
- virtual Error rename_dependencies(const String &p_path, const Map<String, String> &p_map);
+ virtual Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map);
static Error convert_file_to_binary(const String &p_src_path, const String &p_dst_path);
@@ -158,20 +158,20 @@ class ResourceFormatSaverTextInstance {
bool skip_editor = false;
struct NonPersistentKey { //for resource properties generated on the fly
- RES base;
+ Ref<Resource> base;
StringName property;
bool operator<(const NonPersistentKey &p_key) const { return base == p_key.base ? property < p_key.property : base < p_key.base; }
};
- Map<NonPersistentKey, RES> non_persistent_map;
+ RBMap<NonPersistentKey, Ref<Resource>> non_persistent_map;
- Set<RES> resource_set;
- List<RES> saved_resources;
- Map<RES, String> external_resources;
- Map<RES, String> internal_resources;
+ HashSet<Ref<Resource>> resource_set;
+ List<Ref<Resource>> saved_resources;
+ HashMap<Ref<Resource>, String> external_resources;
+ HashMap<Ref<Resource>, String> internal_resources;
struct ResourceSort {
- RES resource;
+ Ref<Resource> resource;
String id;
bool operator<(const ResourceSort &p_right) const {
return id.naturalnocasecmp_to(p_right.id) < 0;
@@ -180,19 +180,19 @@ class ResourceFormatSaverTextInstance {
void _find_resources(const Variant &p_variant, bool p_main = false);
- static String _write_resources(void *ud, const RES &p_resource);
- String _write_resource(const RES &res);
+ static String _write_resources(void *ud, const Ref<Resource> &p_resource);
+ String _write_resource(const Ref<Resource> &res);
public:
- Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
+ Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0);
};
class ResourceFormatSaverText : public ResourceFormatSaver {
public:
static ResourceFormatSaverText *singleton;
- virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
- virtual bool recognize(const RES &p_resource) const;
- virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
+ virtual Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0);
+ virtual bool recognize(const Ref<Resource> &p_resource) const;
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
ResourceFormatSaverText();
};
diff --git a/scene/resources/scene_replication_config.cpp b/scene/resources/scene_replication_config.cpp
index 2acc0f1922..6789f9f7d5 100644
--- a/scene/resources/scene_replication_config.cpp
+++ b/scene/resources/scene_replication_config.cpp
@@ -52,11 +52,19 @@ bool SceneReplicationConfig::_set(const StringName &p_name, const Variant &p_val
ReplicationProperty &prop = properties[idx];
if (what == "sync") {
prop.sync = p_value;
- sync_props.push_back(prop.name);
+ if (prop.sync) {
+ sync_props.push_back(prop.name);
+ } else {
+ sync_props.erase(prop.name);
+ }
return true;
} else if (what == "spawn") {
prop.spawn = p_value;
- spawn_props.push_back(prop.name);
+ if (prop.spawn) {
+ spawn_props.push_back(prop.name);
+ } else {
+ spawn_props.erase(prop.name);
+ }
return true;
}
}
@@ -124,6 +132,15 @@ void SceneReplicationConfig::remove_property(const NodePath &p_path) {
properties.erase(p_path);
}
+bool SceneReplicationConfig::has_property(const NodePath &p_path) const {
+ for (int i = 0; i < properties.size(); i++) {
+ if (properties[i].name == p_path) {
+ return true;
+ }
+ }
+ return false;
+}
+
int SceneReplicationConfig::property_get_index(const NodePath &p_path) const {
for (int i = 0; i < properties.size(); i++) {
if (properties[i].name == p_path) {
@@ -178,6 +195,7 @@ void SceneReplicationConfig::property_set_sync(const NodePath &p_path, bool p_en
void SceneReplicationConfig::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_properties"), &SceneReplicationConfig::get_properties);
ClassDB::bind_method(D_METHOD("add_property", "path", "index"), &SceneReplicationConfig::add_property, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("has_property", "path"), &SceneReplicationConfig::has_property);
ClassDB::bind_method(D_METHOD("remove_property", "path"), &SceneReplicationConfig::remove_property);
ClassDB::bind_method(D_METHOD("property_get_index", "path"), &SceneReplicationConfig::property_get_index);
ClassDB::bind_method(D_METHOD("property_get_spawn", "path"), &SceneReplicationConfig::property_get_spawn);
diff --git a/scene/resources/scene_replication_config.h b/scene/resources/scene_replication_config.h
index b791be9414..ab3658d2a7 100644
--- a/scene/resources/scene_replication_config.h
+++ b/scene/resources/scene_replication_config.h
@@ -73,6 +73,7 @@ public:
void add_property(const NodePath &p_path, int p_index = -1);
void remove_property(const NodePath &p_path);
+ bool has_property(const NodePath &p_path) const;
int property_get_index(const NodePath &p_path) const;
bool property_get_spawn(const NodePath &p_path);
diff --git a/scene/resources/segment_shape_2d.cpp b/scene/resources/segment_shape_2d.cpp
index cea8ca1b29..d53c777492 100644
--- a/scene/resources/segment_shape_2d.cpp
+++ b/scene/resources/segment_shape_2d.cpp
@@ -88,8 +88,8 @@ void SegmentShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_b", "b"), &SegmentShape2D::set_b);
ClassDB::bind_method(D_METHOD("get_b"), &SegmentShape2D::get_b);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "a"), "set_a", "get_a");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "b"), "set_b", "get_b");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "a", PROPERTY_HINT_NONE, "suffix:px"), "set_a", "get_a");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "b", PROPERTY_HINT_NONE, "suffix:px"), "set_b", "get_b");
}
SegmentShape2D::SegmentShape2D() :
diff --git a/scene/resources/separation_ray_shape_2d.cpp b/scene/resources/separation_ray_shape_2d.cpp
index df7b0d969a..0d6aee47d8 100644
--- a/scene/resources/separation_ray_shape_2d.cpp
+++ b/scene/resources/separation_ray_shape_2d.cpp
@@ -89,7 +89,7 @@ void SeparationRayShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_slide_on_slope", "active"), &SeparationRayShape2D::set_slide_on_slope);
ClassDB::bind_method(D_METHOD("get_slide_on_slope"), &SeparationRayShape2D::get_slide_on_slope);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:px"), "set_length", "get_length");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_slope"), "set_slide_on_slope", "get_slide_on_slope");
}
diff --git a/scene/resources/separation_ray_shape_3d.cpp b/scene/resources/separation_ray_shape_3d.cpp
index 736cb60c1c..7306d5b985 100644
--- a/scene/resources/separation_ray_shape_3d.cpp
+++ b/scene/resources/separation_ray_shape_3d.cpp
@@ -80,7 +80,7 @@ void SeparationRayShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_slide_on_slope", "active"), &SeparationRayShape3D::set_slide_on_slope);
ClassDB::bind_method(D_METHOD("get_slide_on_slope"), &SeparationRayShape3D::get_slide_on_slope);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_length", "get_length");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_slope"), "set_slide_on_slope", "get_slide_on_slope");
}
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 25a9278e66..d49157b1b8 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -100,7 +100,7 @@ RID Shader::get_rid() const {
void Shader::set_default_texture_param(const StringName &p_param, const Ref<Texture2D> &p_texture, int p_index) {
if (p_texture.is_valid()) {
if (!default_textures.has(p_param)) {
- default_textures[p_param] = Map<int, Ref<Texture2D>>();
+ default_textures[p_param] = HashMap<int, Ref<Texture2D>>();
}
default_textures[p_param][p_index] = p_texture;
RS::get_singleton()->shader_set_default_texture_param(shader, p_param, p_texture->get_rid(), p_index);
@@ -126,7 +126,7 @@ Ref<Texture2D> Shader::get_default_texture_param(const StringName &p_param, int
}
void Shader::get_default_texture_param_list(List<StringName> *r_textures) const {
- for (const KeyValue<StringName, Map<int, Ref<Texture2D>>> &E : default_textures) {
+ for (const KeyValue<StringName, HashMap<int, Ref<Texture2D>>> &E : default_textures) {
r_textures->push_back(E.key);
}
}
@@ -172,7 +172,7 @@ Shader::~Shader() {
////////////
-RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
@@ -210,7 +210,7 @@ String ResourceFormatLoaderShader::get_resource_type(const String &p_path) const
return "";
}
-Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error ResourceFormatSaverShader::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
Ref<Shader> shader = p_resource;
ERR_FAIL_COND_V(shader.is_null(), ERR_INVALID_PARAMETER);
@@ -229,7 +229,7 @@ Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resourc
return OK;
}
-void ResourceFormatSaverShader::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+void ResourceFormatSaverShader::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
if (const Shader *shader = Object::cast_to<Shader>(*p_resource)) {
if (shader->is_text_shader()) {
p_extensions->push_back("gdshader");
@@ -237,6 +237,6 @@ void ResourceFormatSaverShader::get_recognized_extensions(const RES &p_resource,
}
}
-bool ResourceFormatSaverShader::recognize(const RES &p_resource) const {
+bool ResourceFormatSaverShader::recognize(const Ref<Resource> &p_resource) const {
return p_resource->get_class_name() == "Shader"; //only shader, not inherited
}
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index d05ec06819..11c9f60ce8 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -58,8 +58,8 @@ private:
// shaders keep a list of ShaderMaterial -> RenderingServer name translations, to make
// conversion fast and save memory.
mutable bool params_cache_dirty = true;
- mutable Map<StringName, StringName> params_cache; //map a shader param to a material param..
- Map<StringName, Map<int, Ref<Texture2D>>> default_textures;
+ mutable HashMap<StringName, StringName> params_cache; //map a shader param to a material param..
+ HashMap<StringName, HashMap<int, Ref<Texture2D>>> default_textures;
virtual void _update_shader() const; //used for visual shader
protected:
@@ -86,9 +86,9 @@ public:
get_param_list(nullptr);
}
- const Map<StringName, StringName>::Element *E = params_cache.find(p_param);
+ const HashMap<StringName, StringName>::Iterator E = params_cache.find(p_param);
if (E) {
- return E->get();
+ return E->value;
}
return StringName();
}
@@ -103,7 +103,7 @@ VARIANT_ENUM_CAST(Shader::Mode);
class ResourceFormatLoaderShader : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
@@ -111,9 +111,9 @@ public:
class ResourceFormatSaverShader : public ResourceFormatSaver {
public:
- virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
- virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
- virtual bool recognize(const RES &p_resource) const;
+ virtual Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0);
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize(const Ref<Resource> &p_resource) const;
};
#endif // SHADER_H
diff --git a/scene/resources/shape_3d.cpp b/scene/resources/shape_3d.cpp
index ffb2b27644..4423c1d7bb 100644
--- a/scene/resources/shape_3d.cpp
+++ b/scene/resources/shape_3d.cpp
@@ -117,7 +117,7 @@ void Shape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_debug_mesh"), &Shape3D::get_debug_mesh);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_solver_bias", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_custom_solver_bias", "get_custom_solver_bias");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_margin", "get_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001,suffix:m"), "set_margin", "get_margin");
}
Shape3D::Shape3D() {
diff --git a/scene/resources/skeleton_modification_2d_physicalbones.h b/scene/resources/skeleton_modification_2d_physicalbones.h
index d53102fa5e..373ff666ee 100644
--- a/scene/resources/skeleton_modification_2d_physicalbones.h
+++ b/scene/resources/skeleton_modification_2d_physicalbones.h
@@ -52,7 +52,7 @@ private:
bool _simulation_state_dirty = false;
TypedArray<StringName> _simulation_state_dirty_names;
- bool _simulation_state_dirty_process;
+ bool _simulation_state_dirty_process = false;
void _update_simulation_state();
protected:
diff --git a/scene/resources/skeleton_modification_2d_twoboneik.cpp b/scene/resources/skeleton_modification_2d_twoboneik.cpp
index b08fd82381..d3c62e441f 100644
--- a/scene/resources/skeleton_modification_2d_twoboneik.cpp
+++ b/scene/resources/skeleton_modification_2d_twoboneik.cpp
@@ -464,8 +464,8 @@ void SkeletonModification2DTwoBoneIK::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_joint_two_bone_idx"), &SkeletonModification2DTwoBoneIK::get_joint_two_bone_idx);
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_minimum_distance", PROPERTY_HINT_RANGE, "0, 100000000, 0.01"), "set_target_minimum_distance", "get_target_minimum_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_maximum_distance", PROPERTY_HINT_NONE, "0, 100000000, 0.01"), "set_target_maximum_distance", "get_target_maximum_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_minimum_distance", PROPERTY_HINT_RANGE, "0,100000000,0.01,suffix:m"), "set_target_minimum_distance", "get_target_minimum_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_maximum_distance", PROPERTY_HINT_NONE, "0,100000000,0.01,suffix:m"), "set_target_maximum_distance", "get_target_maximum_distance");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_bend_direction", PROPERTY_HINT_NONE, ""), "set_flip_bend_direction", "get_flip_bend_direction");
ADD_GROUP("", "");
}
diff --git a/scene/resources/skeleton_modification_stack_2d.cpp b/scene/resources/skeleton_modification_stack_2d.cpp
index b944c244b6..38ec19828f 100644
--- a/scene/resources/skeleton_modification_stack_2d.cpp
+++ b/scene/resources/skeleton_modification_stack_2d.cpp
@@ -263,7 +263,7 @@ void SkeletonModificationStack2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0, 1, 0.001"), "set_strength", "get_strength");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "modification_count", PROPERTY_HINT_RANGE, "0, 100, 1"), "set_modification_count", "get_modification_count");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "modification_count", PROPERTY_HINT_RANGE, "0, 100, 1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Modifications,modifications/"), "set_modification_count", "get_modification_count");
}
SkeletonModificationStack2D::SkeletonModificationStack2D() {
diff --git a/scene/resources/skeleton_modification_stack_3d.cpp b/scene/resources/skeleton_modification_stack_3d.cpp
index 7ccba1228c..44fbfc934e 100644
--- a/scene/resources/skeleton_modification_stack_3d.cpp
+++ b/scene/resources/skeleton_modification_stack_3d.cpp
@@ -217,7 +217,7 @@ void SkeletonModificationStack3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0, 1, 0.001"), "set_strength", "get_strength");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "modification_count", PROPERTY_HINT_RANGE, "0, 100, 1"), "set_modification_count", "get_modification_count");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "modification_count", PROPERTY_HINT_RANGE, "0, 100, 1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Modifications,modifications/"), "set_modification_count", "get_modification_count");
}
SkeletonModificationStack3D::SkeletonModificationStack3D() {
diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp
new file mode 100644
index 0000000000..0714de470c
--- /dev/null
+++ b/scene/resources/skeleton_profile.cpp
@@ -0,0 +1,793 @@
+/*************************************************************************/
+/* skeleton_profile.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "skeleton_profile.h"
+
+bool SkeletonProfile::_set(const StringName &p_path, const Variant &p_value) {
+ ERR_FAIL_COND_V(is_read_only, false);
+ String path = p_path;
+
+ if (path.begins_with("groups/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, groups.size(), false);
+
+ if (what == "group_name") {
+ set_group_name(which, p_value);
+ } else if (what == "texture") {
+ set_texture(which, p_value);
+ } else {
+ return false;
+ }
+ }
+
+ if (path.begins_with("bones/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, bones.size(), false);
+
+ if (what == "bone_name") {
+ set_bone_name(which, p_value);
+ } else if (what == "bone_parent") {
+ set_bone_parent(which, p_value);
+ } else if (what == "tail_direction") {
+ set_tail_direction(which, static_cast<TailDirection>((int)p_value));
+ } else if (what == "bone_tail") {
+ set_bone_tail(which, p_value);
+ } else if (what == "reference_pose") {
+ set_reference_pose(which, p_value);
+ } else if (what == "handle_offset") {
+ set_handle_offset(which, p_value);
+ } else if (what == "group") {
+ set_group(which, p_value);
+ } else if (what == "require") {
+ set_require(which, p_value);
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool SkeletonProfile::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+ if (path.begins_with("groups/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, groups.size(), false);
+
+ if (what == "group_name") {
+ r_ret = get_group_name(which);
+ } else if (what == "texture") {
+ r_ret = get_texture(which);
+ } else {
+ return false;
+ }
+ }
+
+ if (path.begins_with("bones/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, bones.size(), false);
+
+ if (what == "bone_name") {
+ r_ret = get_bone_name(which);
+ } else if (what == "bone_parent") {
+ r_ret = get_bone_parent(which);
+ } else if (what == "tail_direction") {
+ r_ret = get_tail_direction(which);
+ } else if (what == "bone_tail") {
+ r_ret = get_bone_tail(which);
+ } else if (what == "reference_pose") {
+ r_ret = get_reference_pose(which);
+ } else if (what == "handle_offset") {
+ r_ret = get_handle_offset(which);
+ } else if (what == "group") {
+ r_ret = get_group(which);
+ } else if (what == "require") {
+ r_ret = is_require(which);
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+void SkeletonProfile::_validate_property(PropertyInfo &property) const {
+ if (is_read_only) {
+ if (property.name == ("group_size") || property.name == ("bone_size")) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ return;
+ }
+ }
+
+ PackedStringArray split = property.name.split("/");
+ if (split.size() == 3 && split[0] == "bones") {
+ if (split[2] == "bone_tail" && get_tail_direction(split[1].to_int()) != TAIL_DIRECTION_SPECIFIC_CHILD) {
+ property.usage = PROPERTY_USAGE_NONE;
+ }
+ }
+}
+
+void SkeletonProfile::_get_property_list(List<PropertyInfo> *p_list) const {
+ if (is_read_only) {
+ return;
+ }
+ String group_names = "";
+ for (int i = 0; i < groups.size(); i++) {
+ String path = "groups/" + itos(i) + "/";
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "group_name"));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, path + "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"));
+ if (i > 0) {
+ group_names = group_names + ",";
+ }
+ group_names = group_names + groups[i].group_name;
+ }
+ for (int i = 0; i < bones.size(); i++) {
+ String path = "bones/" + itos(i) + "/";
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "bone_name"));
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "bone_parent"));
+ p_list->push_back(PropertyInfo(Variant::INT, path + "tail_direction", PROPERTY_HINT_ENUM, "AverageChildren,SpecificChild,End"));
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "bone_tail"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, path + "reference_pose"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, path + "handle_offset"));
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "group", PROPERTY_HINT_ENUM, group_names));
+ p_list->push_back(PropertyInfo(Variant::BOOL, path + "require"));
+ }
+
+ for (PropertyInfo &E : *p_list) {
+ _validate_property(E);
+ }
+}
+
+int SkeletonProfile::get_group_size() {
+ return groups.size();
+}
+
+void SkeletonProfile::set_group_size(int p_size) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_COND(p_size < 0);
+ groups.resize(p_size);
+ emit_signal("profile_updated");
+ notify_property_list_changed();
+}
+
+StringName SkeletonProfile::get_group_name(int p_group_idx) const {
+ ERR_FAIL_INDEX_V(p_group_idx, groups.size(), StringName());
+ return groups[p_group_idx].group_name;
+}
+
+void SkeletonProfile::set_group_name(int p_group_idx, const StringName p_group_name) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_group_idx, groups.size());
+ groups.write[p_group_idx].group_name = p_group_name;
+ emit_signal("profile_updated");
+}
+
+Ref<Texture2D> SkeletonProfile::get_texture(int p_group_idx) const {
+ ERR_FAIL_INDEX_V(p_group_idx, groups.size(), Ref<Texture2D>());
+ return groups[p_group_idx].texture;
+}
+
+void SkeletonProfile::set_texture(int p_group_idx, const Ref<Texture2D> &p_texture) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_group_idx, groups.size());
+ groups.write[p_group_idx].texture = p_texture;
+ emit_signal("profile_updated");
+}
+
+int SkeletonProfile::get_bone_size() {
+ return bones.size();
+}
+
+void SkeletonProfile::set_bone_size(int p_size) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_COND(p_size < 0);
+ bones.resize(p_size);
+ emit_signal("profile_updated");
+ notify_property_list_changed();
+}
+
+int SkeletonProfile::find_bone(StringName p_bone_name) const {
+ if (p_bone_name == StringName()) {
+ return -1;
+ }
+ for (int i = 0; i < bones.size(); i++) {
+ if (bones[i].bone_name == p_bone_name) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+StringName SkeletonProfile::get_bone_name(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
+ return bones[p_bone_idx].bone_name;
+}
+
+void SkeletonProfile::set_bone_name(int p_bone_idx, const StringName p_bone_name) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].bone_name = p_bone_name;
+ emit_signal("profile_updated");
+}
+
+StringName SkeletonProfile::get_bone_parent(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
+ return bones[p_bone_idx].bone_parent;
+}
+
+void SkeletonProfile::set_bone_parent(int p_bone_idx, const StringName p_bone_parent) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].bone_parent = p_bone_parent;
+ emit_signal("profile_updated");
+}
+
+SkeletonProfile::TailDirection SkeletonProfile::get_tail_direction(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), TAIL_DIRECTION_AVERAGE_CHILDREN);
+ return bones[p_bone_idx].tail_direction;
+}
+
+void SkeletonProfile::set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].tail_direction = p_tail_direction;
+ emit_signal("profile_updated");
+ notify_property_list_changed();
+}
+
+StringName SkeletonProfile::get_bone_tail(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
+ return bones[p_bone_idx].bone_tail;
+}
+
+void SkeletonProfile::set_bone_tail(int p_bone_idx, const StringName p_bone_tail) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].bone_tail = p_bone_tail;
+ emit_signal("profile_updated");
+}
+
+Transform3D SkeletonProfile::get_reference_pose(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), Transform3D());
+ return bones[p_bone_idx].reference_pose;
+}
+
+void SkeletonProfile::set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].reference_pose = p_reference_pose;
+ emit_signal("profile_updated");
+}
+
+Vector2 SkeletonProfile::get_handle_offset(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), Vector2());
+ return bones[p_bone_idx].handle_offset;
+}
+
+void SkeletonProfile::set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].handle_offset = p_handle_offset;
+ emit_signal("profile_updated");
+}
+
+StringName SkeletonProfile::get_group(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
+ return bones[p_bone_idx].group;
+}
+
+void SkeletonProfile::set_group(int p_bone_idx, const StringName p_group) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].group = p_group;
+ emit_signal("profile_updated");
+}
+
+bool SkeletonProfile::is_require(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), false);
+ return bones[p_bone_idx].require;
+}
+
+void SkeletonProfile::set_require(int p_bone_idx, const bool p_require) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].require = p_require;
+ emit_signal("profile_updated");
+}
+
+bool SkeletonProfile::has_bone(StringName p_bone_name) {
+ bool is_found = false;
+ for (int i = 0; i < bones.size(); i++) {
+ if (bones[i].bone_name == p_bone_name) {
+ is_found = true;
+ break;
+ }
+ }
+ return is_found;
+}
+
+void SkeletonProfile::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_group_size", "size"), &SkeletonProfile::set_group_size);
+ ClassDB::bind_method(D_METHOD("get_group_size"), &SkeletonProfile::get_group_size);
+
+ ClassDB::bind_method(D_METHOD("get_group_name", "group_idx"), &SkeletonProfile::get_group_name);
+ ClassDB::bind_method(D_METHOD("set_group_name", "group_idx", "group_name"), &SkeletonProfile::set_group_name);
+
+ ClassDB::bind_method(D_METHOD("get_texture", "group_idx"), &SkeletonProfile::get_texture);
+ ClassDB::bind_method(D_METHOD("set_texture", "group_idx", "texture"), &SkeletonProfile::set_texture);
+
+ ClassDB::bind_method(D_METHOD("set_bone_size", "size"), &SkeletonProfile::set_bone_size);
+ ClassDB::bind_method(D_METHOD("get_bone_size"), &SkeletonProfile::get_bone_size);
+
+ ClassDB::bind_method(D_METHOD("find_bone", "bone_name"), &SkeletonProfile::find_bone);
+
+ ClassDB::bind_method(D_METHOD("get_bone_name", "bone_idx"), &SkeletonProfile::get_bone_name);
+ ClassDB::bind_method(D_METHOD("set_bone_name", "bone_idx", "bone_name"), &SkeletonProfile::set_bone_name);
+
+ ClassDB::bind_method(D_METHOD("get_bone_parent", "bone_idx"), &SkeletonProfile::get_bone_parent);
+ ClassDB::bind_method(D_METHOD("set_bone_parent", "bone_idx", "bone_parent"), &SkeletonProfile::set_bone_parent);
+
+ ClassDB::bind_method(D_METHOD("get_tail_direction", "bone_idx"), &SkeletonProfile::get_tail_direction);
+ ClassDB::bind_method(D_METHOD("set_tail_direction", "bone_idx", "tail_direction"), &SkeletonProfile::set_tail_direction);
+
+ ClassDB::bind_method(D_METHOD("get_bone_tail", "bone_idx"), &SkeletonProfile::get_bone_tail);
+ ClassDB::bind_method(D_METHOD("set_bone_tail", "bone_idx", "bone_tail"), &SkeletonProfile::set_bone_tail);
+
+ ClassDB::bind_method(D_METHOD("get_reference_pose", "bone_idx"), &SkeletonProfile::get_reference_pose);
+ ClassDB::bind_method(D_METHOD("set_reference_pose", "bone_idx", "bone_name"), &SkeletonProfile::set_reference_pose);
+
+ ClassDB::bind_method(D_METHOD("get_handle_offset", "bone_idx"), &SkeletonProfile::get_handle_offset);
+ ClassDB::bind_method(D_METHOD("set_handle_offset", "bone_idx", "handle_offset"), &SkeletonProfile::set_handle_offset);
+
+ ClassDB::bind_method(D_METHOD("get_group", "bone_idx"), &SkeletonProfile::get_group);
+ ClassDB::bind_method(D_METHOD("set_group", "bone_idx", "group"), &SkeletonProfile::set_group);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "group_size", PROPERTY_HINT_RANGE, "0,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Groups,groups/"), "set_group_size", "get_group_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_size", PROPERTY_HINT_RANGE, "0,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Bones,bones/"), "set_bone_size", "get_bone_size");
+
+ ADD_SIGNAL(MethodInfo("profile_updated"));
+
+ BIND_ENUM_CONSTANT(TAIL_DIRECTION_AVERAGE_CHILDREN);
+ BIND_ENUM_CONSTANT(TAIL_DIRECTION_SPECIFIC_CHILD);
+ BIND_ENUM_CONSTANT(TAIL_DIRECTION_END);
+}
+
+SkeletonProfile::SkeletonProfile() {
+}
+
+SkeletonProfile::~SkeletonProfile() {
+}
+
+SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
+ is_read_only = true;
+
+ groups.resize(4);
+
+ groups.write[0].group_name = "Body";
+ groups.write[1].group_name = "Face";
+ groups.write[2].group_name = "LeftHand";
+ groups.write[3].group_name = "RightHand";
+
+ bones.resize(56);
+
+ bones.write[0].bone_name = "Root";
+ bones.write[0].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
+ bones.write[0].handle_offset = Vector2(0.5, 0.91);
+ bones.write[0].group = "Body";
+
+ bones.write[1].bone_name = "Hips";
+ bones.write[1].bone_parent = "Root";
+ bones.write[1].tail_direction = TAIL_DIRECTION_SPECIFIC_CHILD;
+ bones.write[1].bone_tail = "Spine";
+ bones.write[1].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.75, 0);
+ bones.write[1].handle_offset = Vector2(0.5, 0.5);
+ bones.write[1].group = "Body";
+ bones.write[1].require = true;
+
+ bones.write[2].bone_name = "Spine";
+ bones.write[2].bone_parent = "Hips";
+ bones.write[2].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
+ bones.write[2].handle_offset = Vector2(0.5, 0.43);
+ bones.write[2].group = "Body";
+ bones.write[2].require = true;
+
+ bones.write[3].bone_name = "Chest";
+ bones.write[3].bone_parent = "Spine";
+ bones.write[3].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
+ bones.write[3].handle_offset = Vector2(0.5, 0.36);
+ bones.write[3].group = "Body";
+
+ bones.write[4].bone_name = "UpperChest";
+ bones.write[4].bone_parent = "Chest";
+ bones.write[4].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
+ bones.write[4].handle_offset = Vector2(0.5, 0.29);
+ bones.write[4].group = "Body";
+
+ bones.write[5].bone_name = "Neck";
+ bones.write[5].bone_parent = "UpperChest";
+ bones.write[5].tail_direction = TAIL_DIRECTION_SPECIFIC_CHILD;
+ bones.write[5].bone_tail = "Head";
+ bones.write[5].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
+ bones.write[5].handle_offset = Vector2(0.5, 0.23);
+ bones.write[5].group = "Body";
+ bones.write[5].require = true;
+
+ bones.write[6].bone_name = "Head";
+ bones.write[6].bone_parent = "Neck";
+ bones.write[6].tail_direction = TAIL_DIRECTION_END;
+ bones.write[6].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
+ bones.write[6].handle_offset = Vector2(0.5, 0.18);
+ bones.write[6].group = "Body";
+ bones.write[6].require = true;
+
+ bones.write[7].bone_name = "LeftEye";
+ bones.write[7].bone_parent = "Head";
+ bones.write[7].reference_pose = Transform3D(1, 0, 0, 0, 0, -1, 0, 1, 0, 0.05, 0.15, 0);
+ bones.write[7].handle_offset = Vector2(0.6, 0.46);
+ bones.write[7].group = "Face";
+
+ bones.write[8].bone_name = "RightEye";
+ bones.write[8].bone_parent = "Head";
+ bones.write[8].reference_pose = Transform3D(1, 0, 0, 0, 0, -1, 0, 1, 0, -0.05, 0.15, 0);
+ bones.write[8].handle_offset = Vector2(0.37, 0.46);
+ bones.write[8].group = "Face";
+
+ bones.write[9].bone_name = "Jaw";
+ bones.write[9].bone_parent = "Head";
+ bones.write[9].reference_pose = Transform3D(-1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0.05, 0.05);
+ bones.write[9].handle_offset = Vector2(0.46, 0.75);
+ bones.write[9].group = "Face";
+
+ bones.write[10].bone_name = "LeftShoulder";
+ bones.write[10].bone_parent = "UpperChest";
+ bones.write[10].reference_pose = Transform3D(0, 1, 0, 0, 0, 1, 1, 0, 0, 0.05, 0.1, 0);
+ bones.write[10].handle_offset = Vector2(0.55, 0.235);
+ bones.write[10].group = "Body";
+ bones.write[10].require = true;
+
+ bones.write[11].bone_name = "LeftUpperArm";
+ bones.write[11].bone_parent = "LeftShoulder";
+ bones.write[11].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.05, 0);
+ bones.write[11].handle_offset = Vector2(0.6, 0.24);
+ bones.write[11].group = "Body";
+ bones.write[11].require = true;
+
+ bones.write[12].bone_name = "LeftLowerArm";
+ bones.write[12].bone_parent = "LeftUpperArm";
+ bones.write[12].reference_pose = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0.25, 0);
+ bones.write[12].handle_offset = Vector2(0.7, 0.24);
+ bones.write[12].group = "Body";
+ bones.write[12].require = true;
+
+ bones.write[13].bone_name = "LeftHand";
+ bones.write[13].bone_parent = "LeftLowerArm";
+ bones.write[13].tail_direction = TAIL_DIRECTION_SPECIFIC_CHILD;
+ bones.write[13].bone_tail = "LeftMiddleProximal";
+ bones.write[13].reference_pose = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 0, 0.25, 0);
+ bones.write[13].handle_offset = Vector2(0.82, 0.235);
+ bones.write[13].group = "Body";
+ bones.write[13].require = true;
+
+ bones.write[14].bone_name = "LeftThumbMetacarpal";
+ bones.write[14].bone_parent = "LeftHand";
+ bones.write[14].reference_pose = Transform3D(0, -0.577, 0.816, 0.707, 0.577, 0.408, -0.707, 0.577, 0.408, -0.025, 0, 0);
+ bones.write[14].handle_offset = Vector2(0.4, 0.8);
+ bones.write[14].group = "LeftHand";
+
+ bones.write[15].bone_name = "LeftThumbProximal";
+ bones.write[15].bone_parent = "LeftThumbMetacarpal";
+ bones.write[15].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.043, 0);
+ bones.write[15].handle_offset = Vector2(0.3, 0.69);
+ bones.write[15].group = "LeftHand";
+
+ bones.write[16].bone_name = "LeftThumbDistal";
+ bones.write[16].bone_parent = "LeftThumbProximal";
+ bones.write[16].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.043, 0);
+ bones.write[16].handle_offset = Vector2(0.23, 0.555);
+ bones.write[16].group = "LeftHand";
+
+ bones.write[17].bone_name = "LeftIndexProximal";
+ bones.write[17].bone_parent = "LeftHand";
+ bones.write[17].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.025, 0.075, 0);
+ bones.write[17].handle_offset = Vector2(0.413, 0.52);
+ bones.write[17].group = "LeftHand";
+
+ bones.write[18].bone_name = "LeftIndexIntermediate";
+ bones.write[18].bone_parent = "LeftIndexProximal";
+ bones.write[18].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
+ bones.write[18].handle_offset = Vector2(0.403, 0.36);
+ bones.write[18].group = "LeftHand";
+
+ bones.write[19].bone_name = "LeftIndexDistal";
+ bones.write[19].bone_parent = "LeftIndexIntermediate";
+ bones.write[19].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[19].handle_offset = Vector2(0.403, 0.255);
+ bones.write[19].group = "LeftHand";
+
+ bones.write[20].bone_name = "LeftMiddleProximal";
+ bones.write[20].bone_parent = "LeftHand";
+ bones.write[20].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0);
+ bones.write[20].handle_offset = Vector2(0.5, 0.51);
+ bones.write[20].group = "LeftHand";
+
+ bones.write[21].bone_name = "LeftMiddleIntermediate";
+ bones.write[21].bone_parent = "LeftMiddleProximal";
+ bones.write[21].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0);
+ bones.write[21].handle_offset = Vector2(0.5, 0.345);
+ bones.write[21].group = "LeftHand";
+
+ bones.write[22].bone_name = "LeftMiddleDistal";
+ bones.write[22].bone_parent = "LeftMiddleIntermediate";
+ bones.write[22].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[22].handle_offset = Vector2(0.5, 0.22);
+ bones.write[22].group = "LeftHand";
+
+ bones.write[23].bone_name = "LeftRingProximal";
+ bones.write[23].bone_parent = "LeftHand";
+ bones.write[23].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.025, 0.075, 0);
+ bones.write[23].handle_offset = Vector2(0.586, 0.52);
+ bones.write[23].group = "LeftHand";
+
+ bones.write[24].bone_name = "LeftRingIntermediate";
+ bones.write[24].bone_parent = "LeftRingProximal";
+ bones.write[24].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
+ bones.write[24].handle_offset = Vector2(0.59, 0.36);
+ bones.write[24].group = "LeftHand";
+
+ bones.write[25].bone_name = "LeftRingDistal";
+ bones.write[25].bone_parent = "LeftRingIntermediate";
+ bones.write[25].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[25].handle_offset = Vector2(0.591, 0.25);
+ bones.write[25].group = "LeftHand";
+
+ bones.write[26].bone_name = "LeftLittleProximal";
+ bones.write[26].bone_parent = "LeftHand";
+ bones.write[26].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.05, 0.05, 0);
+ bones.write[26].handle_offset = Vector2(0.663, 0.543);
+ bones.write[26].group = "LeftHand";
+
+ bones.write[27].bone_name = "LeftLittleIntermediate";
+ bones.write[27].bone_parent = "LeftLittleProximal";
+ bones.write[27].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
+ bones.write[27].handle_offset = Vector2(0.672, 0.415);
+ bones.write[27].group = "LeftHand";
+
+ bones.write[28].bone_name = "LeftLittleDistal";
+ bones.write[28].bone_parent = "LeftLittleIntermediate";
+ bones.write[28].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[28].handle_offset = Vector2(0.672, 0.32);
+ bones.write[28].group = "LeftHand";
+
+ bones.write[29].bone_name = "RightShoulder";
+ bones.write[29].bone_parent = "UpperChest";
+ bones.write[29].reference_pose = Transform3D(0, -1, 0, 0, 0, 1, -1, 0, 0, -0.05, 0.1, 0);
+ bones.write[29].handle_offset = Vector2(0.45, 0.235);
+ bones.write[29].group = "Body";
+ bones.write[29].require = true;
+
+ bones.write[30].bone_name = "RightUpperArm";
+ bones.write[30].bone_parent = "RightShoulder";
+ bones.write[30].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.05, 0);
+ bones.write[30].handle_offset = Vector2(0.4, 0.24);
+ bones.write[30].group = "Body";
+ bones.write[30].require = true;
+
+ bones.write[31].bone_name = "RightLowerArm";
+ bones.write[31].bone_parent = "RightUpperArm";
+ bones.write[31].reference_pose = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 0, 0.25, 0);
+ bones.write[31].handle_offset = Vector2(0.3, 0.24);
+ bones.write[31].group = "Body";
+ bones.write[31].require = true;
+
+ bones.write[32].bone_name = "RightHand";
+ bones.write[32].bone_parent = "RightLowerArm";
+ bones.write[32].tail_direction = TAIL_DIRECTION_SPECIFIC_CHILD;
+ bones.write[32].bone_tail = "RightMiddleProximal";
+ bones.write[32].reference_pose = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0.25, 0);
+ bones.write[32].handle_offset = Vector2(0.18, 0.235);
+ bones.write[32].group = "Body";
+ bones.write[32].require = true;
+
+ bones.write[33].bone_name = "RightThumbMetacarpal";
+ bones.write[33].bone_parent = "RightHand";
+ bones.write[33].reference_pose = Transform3D(0, 0.577, -0.816, -0.707, 0.577, 0.408, 0.707, 0.577, 0.408, 0.025, 0, 0);
+ bones.write[33].handle_offset = Vector2(0.6, 0.8);
+ bones.write[33].group = "RightHand";
+
+ bones.write[34].bone_name = "RightThumbProximal";
+ bones.write[34].bone_parent = "RightThumbMetacarpal";
+ bones.write[34].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.043, 0);
+ bones.write[34].handle_offset = Vector2(0.7, 0.69);
+ bones.write[34].group = "RightHand";
+
+ bones.write[35].bone_name = "RightThumbDistal";
+ bones.write[35].bone_parent = "RightThumbProximal";
+ bones.write[35].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.043, 0);
+ bones.write[35].handle_offset = Vector2(0.77, 0.555);
+ bones.write[35].group = "RightHand";
+
+ bones.write[36].bone_name = "RightIndexProximal";
+ bones.write[36].bone_parent = "RightHand";
+ bones.write[36].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.025, 0.075, 0);
+ bones.write[36].handle_offset = Vector2(0.587, 0.52);
+ bones.write[36].group = "RightHand";
+
+ bones.write[37].bone_name = "RightIndexIntermediate";
+ bones.write[37].bone_parent = "RightIndexProximal";
+ bones.write[37].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
+ bones.write[37].handle_offset = Vector2(0.597, 0.36);
+ bones.write[37].group = "RightHand";
+
+ bones.write[38].bone_name = "RightIndexDistal";
+ bones.write[38].bone_parent = "RightIndexIntermediate";
+ bones.write[38].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[38].handle_offset = Vector2(0.597, 0.255);
+ bones.write[38].group = "RightHand";
+
+ bones.write[39].bone_name = "RightMiddleProximal";
+ bones.write[39].bone_parent = "RightHand";
+ bones.write[39].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0);
+ bones.write[39].handle_offset = Vector2(0.5, 0.51);
+ bones.write[39].group = "RightHand";
+
+ bones.write[40].bone_name = "RightMiddleIntermediate";
+ bones.write[40].bone_parent = "RightMiddleProximal";
+ bones.write[40].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0);
+ bones.write[40].handle_offset = Vector2(0.5, 0.345);
+ bones.write[40].group = "RightHand";
+
+ bones.write[41].bone_name = "RightMiddleDistal";
+ bones.write[41].bone_parent = "RightMiddleIntermediate";
+ bones.write[41].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[41].handle_offset = Vector2(0.5, 0.22);
+ bones.write[41].group = "RightHand";
+
+ bones.write[42].bone_name = "RightRingProximal";
+ bones.write[42].bone_parent = "RightHand";
+ bones.write[42].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.025, 0.075, 0);
+ bones.write[42].handle_offset = Vector2(0.414, 0.52);
+ bones.write[42].group = "RightHand";
+
+ bones.write[43].bone_name = "RightRingIntermediate";
+ bones.write[43].bone_parent = "RightRingProximal";
+ bones.write[43].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
+ bones.write[43].handle_offset = Vector2(0.41, 0.36);
+ bones.write[43].group = "RightHand";
+
+ bones.write[44].bone_name = "RightRingDistal";
+ bones.write[44].bone_parent = "RightRingIntermediate";
+ bones.write[44].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[44].handle_offset = Vector2(0.409, 0.25);
+ bones.write[44].group = "RightHand";
+
+ bones.write[45].bone_name = "RightLittleProximal";
+ bones.write[45].bone_parent = "RightHand";
+ bones.write[45].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.05, 0.05, 0);
+ bones.write[45].handle_offset = Vector2(0.337, 0.543);
+ bones.write[45].group = "RightHand";
+
+ bones.write[46].bone_name = "RightLittleIntermediate";
+ bones.write[46].bone_parent = "RightLittleProximal";
+ bones.write[46].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
+ bones.write[46].handle_offset = Vector2(0.328, 0.415);
+ bones.write[46].group = "RightHand";
+
+ bones.write[47].bone_name = "RightLittleDistal";
+ bones.write[47].bone_parent = "RightLittleIntermediate";
+ bones.write[47].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
+ bones.write[47].handle_offset = Vector2(0.328, 0.32);
+ bones.write[47].group = "RightHand";
+
+ bones.write[48].bone_name = "LeftUpperLeg";
+ bones.write[48].bone_parent = "Hips";
+ bones.write[48].reference_pose = Transform3D(-1, 0, 0, 0, -1, 0, 0, 0, 1, 0.1, 0, 0);
+ bones.write[48].handle_offset = Vector2(0.549, 0.49);
+ bones.write[48].group = "Body";
+ bones.write[48].require = true;
+
+ bones.write[49].bone_name = "LeftLowerLeg";
+ bones.write[49].bone_parent = "LeftUpperLeg";
+ bones.write[49].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.375, 0);
+ bones.write[49].handle_offset = Vector2(0.548, 0.683);
+ bones.write[49].group = "Body";
+ bones.write[49].require = true;
+
+ bones.write[50].bone_name = "LeftFoot";
+ bones.write[50].bone_parent = "LeftLowerLeg";
+ bones.write[50].reference_pose = Transform3D(-1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0.375, 0);
+ bones.write[50].handle_offset = Vector2(0.545, 0.9);
+ bones.write[50].group = "Body";
+ bones.write[50].require = true;
+
+ bones.write[51].bone_name = "LeftToes";
+ bones.write[51].bone_parent = "LeftFoot";
+ bones.write[51].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.15, 0);
+ bones.write[51].handle_offset = Vector2(0.545, 0.95);
+ bones.write[51].group = "Body";
+
+ bones.write[52].bone_name = "RightUpperLeg";
+ bones.write[52].bone_parent = "Hips";
+ bones.write[52].reference_pose = Transform3D(-1, 0, 0, 0, -1, 0, 0, 0, 1, -0.1, 0, 0);
+ bones.write[52].handle_offset = Vector2(0.451, 0.49);
+ bones.write[52].group = "Body";
+ bones.write[52].require = true;
+
+ bones.write[53].bone_name = "RightLowerLeg";
+ bones.write[53].bone_parent = "RightUpperLeg";
+ bones.write[53].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.375, 0);
+ bones.write[53].handle_offset = Vector2(0.452, 0.683);
+ bones.write[53].group = "Body";
+ bones.write[53].require = true;
+
+ bones.write[54].bone_name = "RightFoot";
+ bones.write[54].bone_parent = "RightLowerLeg";
+ bones.write[54].reference_pose = Transform3D(-1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0.375, 0);
+ bones.write[54].handle_offset = Vector2(0.455, 0.9);
+ bones.write[54].group = "Body";
+ bones.write[54].require = true;
+
+ bones.write[55].bone_name = "RightToes";
+ bones.write[55].bone_parent = "RightFoot";
+ bones.write[55].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.15, 0);
+ bones.write[55].handle_offset = Vector2(0.455, 0.95);
+ bones.write[55].group = "Body";
+}
+
+SkeletonProfileHumanoid::~SkeletonProfileHumanoid() {
+}
+
+//////////////////////////////////////
diff --git a/scene/resources/skeleton_profile.h b/scene/resources/skeleton_profile.h
new file mode 100644
index 0000000000..d305311538
--- /dev/null
+++ b/scene/resources/skeleton_profile.h
@@ -0,0 +1,131 @@
+/*************************************************************************/
+/* skeleton_profile.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SKELETON_PROFILE_H
+#define SKELETON_PROFILE_H
+
+#include "texture.h"
+
+class SkeletonProfile : public Resource {
+ GDCLASS(SkeletonProfile, Resource);
+
+public:
+ enum TailDirection {
+ TAIL_DIRECTION_AVERAGE_CHILDREN,
+ TAIL_DIRECTION_SPECIFIC_CHILD,
+ TAIL_DIRECTION_END
+ };
+
+protected:
+ // Note: SkeletonProfileHumanoid which extends SkeletonProfile exists to unify standard bone names.
+ // That is what is_read_only is for, so don't make it public.
+ bool is_read_only = false;
+
+ struct SkeletonProfileGroup {
+ StringName group_name;
+ Ref<Texture2D> texture;
+ };
+
+ struct SkeletonProfileBone {
+ StringName bone_name;
+ StringName bone_parent;
+ TailDirection tail_direction = TAIL_DIRECTION_AVERAGE_CHILDREN;
+ StringName bone_tail;
+ Transform3D reference_pose;
+ Vector2 handle_offset;
+ StringName group;
+ bool require = false;
+ };
+
+ Vector<SkeletonProfileGroup> groups;
+ Vector<SkeletonProfileBone> bones;
+
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ bool _set(const StringName &p_path, const Variant &p_value);
+ virtual void _validate_property(PropertyInfo &property) const override;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+ static void _bind_methods();
+
+public:
+ int get_group_size();
+ void set_group_size(int p_size);
+
+ StringName get_group_name(int p_group_idx) const;
+ void set_group_name(int p_group_idx, const StringName p_group_name);
+
+ Ref<Texture2D> get_texture(int p_group_idx) const;
+ void set_texture(int p_group_idx, const Ref<Texture2D> &p_texture);
+
+ int get_bone_size();
+ void set_bone_size(int p_size);
+
+ int find_bone(const StringName p_bone_name) const;
+
+ StringName get_bone_name(int p_bone_idx) const;
+ void set_bone_name(int p_bone_idx, const StringName p_bone_name);
+
+ StringName get_bone_parent(int p_bone_idx) const;
+ void set_bone_parent(int p_bone_idx, const StringName p_bone_parent);
+
+ TailDirection get_tail_direction(int p_bone_idx) const;
+ void set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction);
+
+ StringName get_bone_tail(int p_bone_idx) const;
+ void set_bone_tail(int p_bone_idx, const StringName p_bone_tail);
+
+ Transform3D get_reference_pose(int p_bone_idx) const;
+ void set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose);
+
+ Vector2 get_handle_offset(int p_bone_idx) const;
+ void set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset);
+
+ StringName get_group(int p_bone_idx) const;
+ void set_group(int p_bone_idx, const StringName p_group);
+
+ bool is_require(int p_bone_idx) const;
+ void set_require(int p_bone_idx, const bool p_require);
+
+ bool has_bone(StringName p_bone_name);
+
+ SkeletonProfile();
+ ~SkeletonProfile();
+};
+
+class SkeletonProfileHumanoid : public SkeletonProfile {
+ GDCLASS(SkeletonProfileHumanoid, SkeletonProfile);
+
+public:
+ SkeletonProfileHumanoid();
+ ~SkeletonProfileHumanoid();
+};
+
+VARIANT_ENUM_CAST(SkeletonProfile::TailDirection);
+
+#endif // SKELETON_PROFILE_H
diff --git a/scene/resources/skin.cpp b/scene/resources/skin.cpp
index 54ed71999c..1c04ba0cd4 100644
--- a/scene/resources/skin.cpp
+++ b/scene/resources/skin.cpp
@@ -130,11 +130,12 @@ bool Skin::_get(const StringName &p_name, Variant &r_ret) const {
}
void Skin::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::INT, "bind_count", PROPERTY_HINT_RANGE, "0,16384,1,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("bind_count"), PROPERTY_HINT_RANGE, "0,16384,1,or_greater"));
for (int i = 0; i < get_bind_count(); i++) {
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bind/" + itos(i) + "/name"));
- p_list->push_back(PropertyInfo(Variant::INT, "bind/" + itos(i) + "/bone", PROPERTY_HINT_RANGE, "0,16384,1,or_greater", get_bind_name(i) != StringName() ? PROPERTY_USAGE_NO_EDITOR : PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, "bind/" + itos(i) + "/pose"));
+ const String prefix = vformat("%s/%d/", PNAME("bind"), i);
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, prefix + PNAME("name")));
+ p_list->push_back(PropertyInfo(Variant::INT, prefix + PNAME("bone"), PROPERTY_HINT_RANGE, "0,16384,1,or_greater", get_bind_name(i) != StringName() ? PROPERTY_USAGE_NO_EDITOR : PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prefix + PNAME("pose")));
}
}
diff --git a/scene/resources/sky.cpp b/scene/resources/sky.cpp
index 9cb6a16f5c..735134e27b 100644
--- a/scene/resources/sky.cpp
+++ b/scene/resources/sky.cpp
@@ -83,7 +83,7 @@ void Sky::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_material"), &Sky::get_material);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,PanoramaSkyMaterial,ProceduralSkyMaterial,PhysicalSkyMaterial"), "set_material", "get_material");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Automatic,HighQuality,HighQualityIncremental,RealTime"), "set_process_mode", "get_process_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Automatic,High-Quality,High-Quality Incremental,Real-Time"), "set_process_mode", "get_process_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radiance_size", PROPERTY_HINT_ENUM, "32,64,128,256,512,1024,2048"), "set_radiance_size", "get_radiance_size");
BIND_ENUM_CONSTANT(RADIANCE_SIZE_32);
diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp
index 4681d3d6e3..5d1a223cc7 100644
--- a/scene/resources/sky_material.cpp
+++ b/scene/resources/sky_material.cpp
@@ -144,6 +144,15 @@ float ProceduralSkyMaterial::get_sun_curve() const {
return sun_curve;
}
+void ProceduralSkyMaterial::set_use_debanding(bool p_use_debanding) {
+ use_debanding = p_use_debanding;
+ RS::get_singleton()->material_set_param(_get_material(), "use_debanding", use_debanding);
+}
+
+bool ProceduralSkyMaterial::get_use_debanding() const {
+ return use_debanding;
+}
+
Shader::Mode ProceduralSkyMaterial::get_shader_mode() const {
return Shader::MODE_SKY;
}
@@ -199,6 +208,9 @@ void ProceduralSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sun_curve", "curve"), &ProceduralSkyMaterial::set_sun_curve);
ClassDB::bind_method(D_METHOD("get_sun_curve"), &ProceduralSkyMaterial::get_sun_curve);
+ ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &ProceduralSkyMaterial::set_use_debanding);
+ ClassDB::bind_method(D_METHOD("get_use_debanding"), &ProceduralSkyMaterial::get_use_debanding);
+
ADD_GROUP("Sky", "sky_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_top_color", "get_sky_top_color");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_horizon_color", "get_sky_horizon_color");
@@ -214,8 +226,11 @@ void ProceduralSkyMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy", "get_ground_energy");
ADD_GROUP("Sun", "sun_");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_angle_max", "get_sun_angle_max");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01,degrees"), "set_sun_angle_max", "get_sun_angle_max");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve");
+
+ ADD_GROUP("", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");
}
void ProceduralSkyMaterial::cleanup_shader() {
@@ -235,18 +250,26 @@ void ProceduralSkyMaterial::_update_shader() {
shader_type sky;
-uniform vec4 sky_top_color : hint_color = vec4(0.385, 0.454, 0.55, 1.0);
-uniform vec4 sky_horizon_color : hint_color = vec4(0.646, 0.656, 0.67, 1.0);
+uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0);
+uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);
uniform float sky_curve : hint_range(0, 1) = 0.15;
uniform float sky_energy = 1.0;
-uniform sampler2D sky_cover : hint_black_albedo;
-uniform vec4 sky_cover_modulate : hint_color = vec4(1.0, 1.0, 1.0, 1.0);
-uniform vec4 ground_bottom_color : hint_color = vec4(0.2, 0.169, 0.133, 1.0);
-uniform vec4 ground_horizon_color : hint_color = vec4(0.646, 0.656, 0.67, 1.0);
+uniform sampler2D sky_cover : source_color, hint_default_black;
+uniform vec4 sky_cover_modulate : source_color = vec4(1.0, 1.0, 1.0, 1.0);
+uniform vec4 ground_bottom_color : source_color = vec4(0.2, 0.169, 0.133, 1.0);
+uniform vec4 ground_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);
uniform float ground_curve : hint_range(0, 1) = 0.02;
uniform float ground_energy = 1.0;
uniform float sun_angle_max = 30.0;
uniform float sun_curve : hint_range(0, 1) = 0.15;
+uniform bool use_debanding = true;
+
+// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
+vec3 interleaved_gradient_noise(vec2 pos) {
+ const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
+ float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0;
+ return vec3(res, -res, res) / 255.0;
+}
void sky() {
float v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0));
@@ -302,6 +325,9 @@ void sky() {
ground *= ground_energy;
COLOR = mix(ground, sky, step(0.0, EYEDIR.y));
+ if (use_debanding) {
+ COLOR += interleaved_gradient_noise(FRAGCOORD.xy);
+ }
}
)");
}
@@ -322,6 +348,7 @@ ProceduralSkyMaterial::ProceduralSkyMaterial() {
set_sun_angle_max(30.0);
set_sun_curve(0.15);
+ set_use_debanding(true);
}
ProceduralSkyMaterial::~ProceduralSkyMaterial() {
@@ -407,7 +434,7 @@ void PanoramaSkyMaterial::_update_shader() {
shader_type sky;
-uniform sampler2D source_panorama : %s, hint_black_albedo;
+uniform sampler2D source_panorama : %s, source_color, hint_default_black;
void sky() {
COLOR = texture(source_panorama, SKY_COORDS).rgb;
@@ -510,13 +537,13 @@ float PhysicalSkyMaterial::get_exposure() const {
return exposure;
}
-void PhysicalSkyMaterial::set_dither_strength(float p_dither_strength) {
- dither_strength = p_dither_strength;
- RS::get_singleton()->material_set_param(_get_material(), "dither_strength", dither_strength);
+void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) {
+ use_debanding = p_use_debanding;
+ RS::get_singleton()->material_set_param(_get_material(), "use_debanding", use_debanding);
}
-float PhysicalSkyMaterial::get_dither_strength() const {
- return dither_strength;
+bool PhysicalSkyMaterial::get_use_debanding() const {
+ return use_debanding;
}
void PhysicalSkyMaterial::set_night_sky(const Ref<Texture2D> &p_night_sky) {
@@ -578,8 +605,8 @@ void PhysicalSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_exposure", "exposure"), &PhysicalSkyMaterial::set_exposure);
ClassDB::bind_method(D_METHOD("get_exposure"), &PhysicalSkyMaterial::get_exposure);
- ClassDB::bind_method(D_METHOD("set_dither_strength", "strength"), &PhysicalSkyMaterial::set_dither_strength);
- ClassDB::bind_method(D_METHOD("get_dither_strength"), &PhysicalSkyMaterial::get_dither_strength);
+ ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &PhysicalSkyMaterial::set_use_debanding);
+ ClassDB::bind_method(D_METHOD("get_use_debanding"), &PhysicalSkyMaterial::get_use_debanding);
ClassDB::bind_method(D_METHOD("set_night_sky", "night_sky"), &PhysicalSkyMaterial::set_night_sky);
ClassDB::bind_method(D_METHOD("get_night_sky"), &PhysicalSkyMaterial::get_night_sky);
@@ -597,7 +624,7 @@ void PhysicalSkyMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_disk_scale", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_disk_scale", "get_sun_disk_scale");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_color", "get_ground_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_exposure", "get_exposure");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dither_strength", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_dither_strength", "get_dither_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "night_sky", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_night_sky", "get_night_sky");
}
@@ -619,18 +646,18 @@ void PhysicalSkyMaterial::_update_shader() {
shader_type sky;
uniform float rayleigh : hint_range(0, 64) = 2.0;
-uniform vec4 rayleigh_color : hint_color = vec4(0.3, 0.405, 0.6, 1.0);
+uniform vec4 rayleigh_color : source_color = vec4(0.3, 0.405, 0.6, 1.0);
uniform float mie : hint_range(0, 1) = 0.005;
uniform float mie_eccentricity : hint_range(-1, 1) = 0.8;
-uniform vec4 mie_color : hint_color = vec4(0.69, 0.729, 0.812, 1.0);
+uniform vec4 mie_color : source_color = vec4(0.69, 0.729, 0.812, 1.0);
uniform float turbidity : hint_range(0, 1000) = 10.0;
uniform float sun_disk_scale : hint_range(0, 360) = 1.0;
-uniform vec4 ground_color : hint_color = vec4(0.1, 0.07, 0.034, 1.0);
+uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0);
uniform float exposure : hint_range(0, 128) = 0.1;
-uniform float dither_strength : hint_range(0, 10) = 1.0;
+uniform bool use_debanding = true;
-uniform sampler2D night_sky : hint_black_albedo;
+uniform sampler2D night_sky : source_color, hint_default_black;
const vec3 UP = vec3( 0.0, 1.0, 0.0 );
@@ -646,11 +673,11 @@ float henyey_greenstein(float cos_theta, float g) {
return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));
}
-// From: https://www.shadertoy.com/view/4sfGzS credit to iq
-float hash(vec3 p) {
- p = fract( p * 0.3183099 + 0.1 );
- p *= 17.0;
- return fract(p.x * p.y * p.z * (p.x + p.y + p.z));
+// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
+vec3 interleaved_gradient_noise(vec2 pos) {
+ const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
+ float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0;
+ return vec3(res, -res, res) / 255.0;
}
void sky() {
@@ -700,8 +727,9 @@ void sky() {
vec3 color = (Lin + L0) * 0.04;
COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));
COLOR *= exposure;
- // Make optional, eliminates banding.
- COLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.016 * dither_strength;
+ if (use_debanding) {
+ COLOR += interleaved_gradient_noise(FRAGCOORD.xy);
+ }
} else {
// There is no sun, so display night_sky and nothing else.
COLOR = texture(night_sky, SKY_COORDS).xyz * 0.04;
@@ -724,7 +752,7 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() {
set_sun_disk_scale(1.0);
set_ground_color(Color(0.1, 0.07, 0.034));
set_exposure(0.1);
- set_dither_strength(1.0);
+ set_use_debanding(true);
}
PhysicalSkyMaterial::~PhysicalSkyMaterial() {
diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h
index 5c791a185a..5be8922ba4 100644
--- a/scene/resources/sky_material.h
+++ b/scene/resources/sky_material.h
@@ -40,18 +40,19 @@ class ProceduralSkyMaterial : public Material {
private:
Color sky_top_color;
Color sky_horizon_color;
- float sky_curve;
- float sky_energy;
+ float sky_curve = 0.0f;
+ float sky_energy = 0.0f;
Ref<Texture2D> sky_cover;
Color sky_cover_modulate;
Color ground_bottom_color;
Color ground_horizon_color;
- float ground_curve;
- float ground_energy;
+ float ground_curve = 0.0f;
+ float ground_energy = 0.0f;
- float sun_angle_max;
- float sun_curve;
+ float sun_angle_max = 0.0f;
+ float sun_curve = 0.0f;
+ bool use_debanding = true;
static Mutex shader_mutex;
static RID shader;
@@ -98,6 +99,9 @@ public:
void set_sun_curve(float p_curve);
float get_sun_curve() const;
+ void set_use_debanding(bool p_use_debanding);
+ bool get_use_debanding() const;
+
virtual Shader::Mode get_shader_mode() const override;
virtual RID get_shader_rid() const override;
virtual RID get_rid() const override;
@@ -154,16 +158,16 @@ private:
static Mutex shader_mutex;
static RID shader;
- float rayleigh;
+ float rayleigh = 0.0f;
Color rayleigh_color;
- float mie;
- float mie_eccentricity;
+ float mie = 0.0f;
+ float mie_eccentricity = 0.0f;
Color mie_color;
- float turbidity;
- float sun_disk_scale;
+ float turbidity = 0.0f;
+ float sun_disk_scale = 0.0f;
Color ground_color;
- float exposure;
- float dither_strength;
+ float exposure = 0.0f;
+ bool use_debanding = true;
Ref<Texture2D> night_sky;
static void _update_shader();
mutable bool shader_set = false;
@@ -199,8 +203,8 @@ public:
void set_exposure(float p_exposure);
float get_exposure() const;
- void set_dither_strength(float p_dither_strength);
- float get_dither_strength() const;
+ void set_use_debanding(bool p_use_debanding);
+ bool get_use_debanding() const;
void set_night_sky(const Ref<Texture2D> &p_night_sky);
Ref<Texture2D> get_night_sky() const;
diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp
index 8de0dc1650..92efe3ce6f 100644
--- a/scene/resources/sphere_shape_3d.cpp
+++ b/scene/resources/sphere_shape_3d.cpp
@@ -78,10 +78,10 @@ void SphereShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &SphereShape3D::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &SphereShape3D::get_radius);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
}
SphereShape3D::SphereShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_SPHERE)) {
- set_radius(1.0);
+ set_radius(0.5);
}
diff --git a/scene/resources/sphere_shape_3d.h b/scene/resources/sphere_shape_3d.h
index ff6d883940..8f77378ef4 100644
--- a/scene/resources/sphere_shape_3d.h
+++ b/scene/resources/sphere_shape_3d.h
@@ -35,7 +35,7 @@
class SphereShape3D : public Shape3D {
GDCLASS(SphereShape3D, Shape3D);
- float radius;
+ float radius = 0.5f;
protected:
static void _bind_methods();
diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp
index ece126791e..55c9d7397d 100644
--- a/scene/resources/sprite_frames.cpp
+++ b/scene/resources/sprite_frames.cpp
@@ -33,38 +33,38 @@
#include "scene/scene_string_names.h"
void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ HashMap<StringName, Anim>::Iterator E = animations.find(p_anim);
ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
- if (p_at_pos >= 0 && p_at_pos < E->get().frames.size()) {
- E->get().frames.insert(p_at_pos, p_frame);
+ if (p_at_pos >= 0 && p_at_pos < E->value.frames.size()) {
+ E->value.frames.insert(p_at_pos, p_frame);
} else {
- E->get().frames.push_back(p_frame);
+ E->value.frames.push_back(p_frame);
}
emit_changed();
}
int SpriteFrames::get_frame_count(const StringName &p_anim) const {
- const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ HashMap<StringName, Anim>::ConstIterator E = animations.find(p_anim);
ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
- return E->get().frames.size();
+ return E->value.frames.size();
}
void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ HashMap<StringName, Anim>::Iterator E = animations.find(p_anim);
ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
- E->get().frames.remove_at(p_idx);
+ E->value.frames.remove_at(p_idx);
emit_changed();
}
void SpriteFrames::clear(const StringName &p_anim) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ HashMap<StringName, Anim>::Iterator E = animations.find(p_anim);
ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
- E->get().frames.clear();
+ E->value.frames.clear();
emit_changed();
}
@@ -96,17 +96,6 @@ void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &
animations[p_next] = anim;
}
-Vector<String> SpriteFrames::_get_animation_list() const {
- Vector<String> ret;
- List<StringName> al;
- get_animation_list(&al);
- for (const StringName &E : al) {
- ret.push_back(E);
- }
-
- return ret;
-}
-
void SpriteFrames::get_animation_list(List<StringName> *r_animations) const {
for (const KeyValue<StringName, Anim> &E : animations) {
r_animations->push_back(E.key);
@@ -124,54 +113,45 @@ Vector<String> SpriteFrames::get_animation_names() const {
void SpriteFrames::set_animation_speed(const StringName &p_anim, double p_fps) {
ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ").");
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ HashMap<StringName, Anim>::Iterator E = animations.find(p_anim);
ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
- E->get().speed = p_fps;
+ E->value.speed = p_fps;
}
double SpriteFrames::get_animation_speed(const StringName &p_anim) const {
- const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ HashMap<StringName, Anim>::ConstIterator E = animations.find(p_anim);
ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
- return E->get().speed;
+ return E->value.speed;
}
void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ HashMap<StringName, Anim>::Iterator E = animations.find(p_anim);
ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
- E->get().loop = p_loop;
+ E->value.loop = p_loop;
}
bool SpriteFrames::get_animation_loop(const StringName &p_anim) const {
- const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ HashMap<StringName, Anim>::ConstIterator E = animations.find(p_anim);
ERR_FAIL_COND_V_MSG(!E, false, "Animation '" + String(p_anim) + "' doesn't exist.");
- return E->get().loop;
-}
-
-void SpriteFrames::_set_frames(const Array &p_frames) {
- clear_all();
- Map<StringName, Anim>::Element *E = animations.find(SceneStringNames::get_singleton()->_default);
- ERR_FAIL_COND(!E);
-
- E->get().frames.resize(p_frames.size());
- for (int i = 0; i < E->get().frames.size(); i++) {
- E->get().frames.write[i] = p_frames[i];
- }
-}
-
-Array SpriteFrames::_get_frames() const {
- return Array();
+ return E->value.loop;
}
Array SpriteFrames::_get_animations() const {
Array anims;
- for (const KeyValue<StringName, Anim> &E : animations) {
+
+ List<StringName> sorted_names;
+ get_animation_list(&sorted_names);
+ sorted_names.sort_custom<StringName::AlphCompare>();
+
+ for (const StringName &name : sorted_names) {
+ const Anim &anim = animations[name];
Dictionary d;
- d["name"] = E.key;
- d["speed"] = E.value.speed;
- d["loop"] = E.value.loop;
+ d["name"] = name;
+ d["speed"] = anim.speed;
+ d["loop"] = anim.loop;
Array frames;
- for (int i = 0; i < E.value.frames.size(); i++) {
- frames.push_back(E.value.frames[i]);
+ for (int i = 0; i < anim.frames.size(); i++) {
+ frames.push_back(anim.frames[i]);
}
d["frames"] = frames;
anims.push_back(d);
@@ -195,7 +175,7 @@ void SpriteFrames::_set_animations(const Array &p_animations) {
anim.loop = d["loop"];
Array frames = d["frames"];
for (int j = 0; j < frames.size(); j++) {
- RES res = frames[j];
+ Ref<Resource> res = frames[j];
anim.frames.push_back(res);
}
@@ -225,15 +205,12 @@ void SpriteFrames::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear);
ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all);
- ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames);
- ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames);
-
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_frames", "_get_frames"); //compatibility
+ // `animations` property is for serialization.
ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations);
ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations);
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations");
}
SpriteFrames::SpriteFrames() {
diff --git a/scene/resources/sprite_frames.h b/scene/resources/sprite_frames.h
index 12b69afde1..87d84b70c0 100644
--- a/scene/resources/sprite_frames.h
+++ b/scene/resources/sprite_frames.h
@@ -42,16 +42,11 @@ class SpriteFrames : public Resource {
Vector<Ref<Texture2D>> frames;
};
- Map<StringName, Anim> animations;
-
- Array _get_frames() const;
- void _set_frames(const Array &p_frames);
+ HashMap<StringName, Anim> animations;
Array _get_animations() const;
void _set_animations(const Array &p_animations);
- Vector<String> _get_animation_list() const;
-
protected:
static void _bind_methods();
@@ -73,24 +68,24 @@ public:
void add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos = -1);
int get_frame_count(const StringName &p_anim) const;
_FORCE_INLINE_ Ref<Texture2D> get_frame(const StringName &p_anim, int p_idx) const {
- const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ HashMap<StringName, Anim>::ConstIterator E = animations.find(p_anim);
ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist.");
ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
- if (p_idx >= E->get().frames.size()) {
+ if (p_idx >= E->value.frames.size()) {
return Ref<Texture2D>();
}
- return E->get().frames[p_idx];
+ return E->value.frames[p_idx];
}
void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_frame) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ HashMap<StringName, Anim>::Iterator E = animations.find(p_anim);
ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
ERR_FAIL_COND(p_idx < 0);
- if (p_idx >= E->get().frames.size()) {
+ if (p_idx >= E->value.frames.size()) {
return;
}
- E->get().frames.write[p_idx] = p_frame;
+ E->value.frames.write[p_idx] = p_frame;
}
void remove_frame(const StringName &p_anim, int p_idx);
void clear(const StringName &p_anim);
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index fe52761482..a53c299d00 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -122,11 +122,11 @@ void StyleBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw", "canvas_item", "rect"), &StyleBox::draw);
- ADD_GROUP("Content Margin", "content_margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_BOTTOM);
+ ADD_GROUP("Content Margins", "content_margin_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_BOTTOM);
GDVIRTUAL_BIND(_get_style_margin, "side")
GDVIRTUAL_BIND(_test_mask, "point", "rect")
@@ -315,20 +315,26 @@ void StyleBoxTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_v_axis_stretch_mode"), &StyleBoxTexture::get_v_axis_stretch_mode);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
- ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
- ADD_GROUP("Margin", "margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_BOTTOM);
- ADD_GROUP("Expand Margin", "expand_margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_BOTTOM);
+
+ ADD_GROUP("Margins", "margin_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_BOTTOM);
+
+ ADD_GROUP("Expand Margins", "expand_margin_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_BOTTOM);
+
ADD_GROUP("Axis Stretch", "axis_stretch_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode");
+
+ ADD_GROUP("Sub-Region", "region_");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect", PROPERTY_HINT_NONE, "suffix:px"), "set_region_rect", "get_region_rect");
+
ADD_GROUP("Modulate", "modulate_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate_color"), "set_modulate", "get_modulate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled");
@@ -457,6 +463,15 @@ bool StyleBoxFlat::is_draw_center_enabled() const {
return draw_center;
}
+void StyleBoxFlat::set_skew(Vector2 p_skew) {
+ skew = p_skew;
+ emit_changed();
+}
+
+Vector2 StyleBoxFlat::get_skew() const {
+ return skew;
+}
+
void StyleBoxFlat::set_shadow_color(const Color &p_color) {
shadow_color = p_color;
emit_changed();
@@ -542,7 +557,7 @@ inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_re
}
inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color> &colors, const Rect2 &style_rect, const real_t corner_radius[4],
- const Rect2 &ring_rect, const Rect2 &inner_rect, const Color &inner_color, const Color &outer_color, const int corner_detail, const bool fill_center = false) {
+ const Rect2 &ring_rect, const Rect2 &inner_rect, const Color &inner_color, const Color &outer_color, const int corner_detail, const Vector2 &skew, bool fill_center = false) {
int vert_offset = verts.size();
if (!vert_offset) {
vert_offset = 0;
@@ -586,9 +601,12 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
color = outer_color;
corner_point = outer_points[corner_index];
}
- real_t x = radius * (real_t)cos((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.x;
- real_t y = radius * (real_t)sin((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.y;
- verts.push_back(Vector2(x, y));
+
+ const real_t x = radius * (real_t)cos((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.x;
+ const real_t y = radius * (real_t)sin((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.y;
+ const float x_skew = -skew.x * (y - ring_rect.get_center().y);
+ const float y_skew = -skew.y * (x - ring_rect.get_center().x);
+ verts.push_back(Vector2(x + x_skew, y + y_skew));
colors.push_back(color);
}
}
@@ -666,10 +684,12 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
return;
}
- bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0);
- bool aa_on = rounded_corners && anti_aliased;
+ const bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0);
+ // Only enable antialiasing if it is actually needed. This improve performances
+ // and maximizes sharpness for non-skewed StyleBoxes with sharp corners.
+ const bool aa_on = (rounded_corners || !skew.is_equal_approx(Vector2())) && anti_aliased;
- bool blend_on = blend_border && draw_border;
+ const bool blend_on = blend_border && draw_border;
Color border_color_alpha = Color(border_color.r, border_color.g, border_color.b, 0);
Color border_color_blend = (draw_center ? bg_color : border_color_alpha);
@@ -716,24 +736,24 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
Color shadow_color_transparent = Color(shadow_color.r, shadow_color.g, shadow_color.b, 0);
draw_ring(verts, indices, colors, shadow_inner_rect, adapted_corner,
- shadow_rect, shadow_inner_rect, shadow_color, shadow_color_transparent, corner_detail);
+ shadow_rect, shadow_inner_rect, shadow_color, shadow_color_transparent, corner_detail, skew);
if (draw_center) {
draw_ring(verts, indices, colors, shadow_inner_rect, adapted_corner,
- shadow_inner_rect, shadow_inner_rect, shadow_color, shadow_color, corner_detail, true);
+ shadow_inner_rect, shadow_inner_rect, shadow_color, shadow_color, corner_detail, skew, true);
}
}
// Create border (no AA).
if (draw_border && !aa_on) {
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
- border_style_rect, infill_rect, border_color_inner, border_color, corner_detail);
+ border_style_rect, infill_rect, border_color_inner, border_color, corner_detail, skew);
}
// Create infill (no AA).
if (draw_center && (!aa_on || blend_on || !draw_border)) {
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
- infill_rect, infill_rect, bg_color, bg_color, corner_detail, true);
+ infill_rect, infill_rect, bg_color, bg_color, corner_detail, skew, true);
}
if (aa_on) {
@@ -765,7 +785,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
aa_border_width[SIDE_RIGHT], aa_border_width[SIDE_BOTTOM]);
// Create infill within AA border.
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
- infill_inner_rect_aa, infill_inner_rect_aa, bg_color, bg_color, corner_detail, true);
+ infill_inner_rect_aa, infill_inner_rect_aa, bg_color, bg_color, corner_detail, skew, true);
}
if (!blend_on || !draw_border) {
@@ -776,7 +796,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
// Create infill fake AA gradient.
draw_ring(verts, indices, colors, style_rect, adapted_corner,
- infill_rect_aa, infill_rect, bg_color, alpha_bg, corner_detail);
+ infill_rect_aa, infill_rect, bg_color, alpha_bg, corner_detail, skew);
}
}
@@ -790,17 +810,17 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
// Create border.
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
- border_style_rect_aa, ((blend_on) ? infill_rect : infill_rect_aa), border_color_inner, border_color, corner_detail);
+ border_style_rect_aa, ((blend_on) ? infill_rect : infill_rect_aa), border_color_inner, border_color, corner_detail, skew);
if (!blend_on) {
// Create inner border fake AA gradient.
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
- infill_rect_aa, infill_rect, border_color_blend, border_color, corner_detail);
+ infill_rect_aa, infill_rect, border_color_blend, border_color, corner_detail, skew);
}
// Create outer border fake AA gradient.
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
- style_rect_aa, border_style_rect_aa, border_color, border_color_alpha, corner_detail);
+ style_rect_aa, border_style_rect_aa, border_color, border_color_alpha, corner_detail, skew);
}
}
@@ -858,6 +878,9 @@ void StyleBoxFlat::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_draw_center", "draw_center"), &StyleBoxFlat::set_draw_center);
ClassDB::bind_method(D_METHOD("is_draw_center_enabled"), &StyleBoxFlat::is_draw_center_enabled);
+ ClassDB::bind_method(D_METHOD("set_skew", "skew"), &StyleBoxFlat::set_skew);
+ ClassDB::bind_method(D_METHOD("get_skew"), &StyleBoxFlat::get_skew);
+
ClassDB::bind_method(D_METHOD("set_shadow_color", "color"), &StyleBoxFlat::set_shadow_color);
ClassDB::bind_method(D_METHOD("get_shadow_color"), &StyleBoxFlat::get_shadow_color);
@@ -879,12 +902,13 @@ void StyleBoxFlat::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "bg_color"), "set_bg_color", "get_bg_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "skew"), "set_skew", "get_skew");
ADD_GROUP("Border Width", "border_width_");
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_BOTTOM);
ADD_GROUP("Border", "border_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "border_color"), "set_border_color", "get_border_color");
@@ -892,27 +916,27 @@ void StyleBoxFlat::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "border_blend"), "set_border_blend", "get_border_blend");
ADD_GROUP("Corner Radius", "corner_radius_");
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_left", PROPERTY_HINT_RANGE, "0,1024,1"), "set_corner_radius", "get_corner_radius", CORNER_TOP_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_right", PROPERTY_HINT_RANGE, "0,1024,1"), "set_corner_radius", "get_corner_radius", CORNER_TOP_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_right", PROPERTY_HINT_RANGE, "0,1024,1"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_left", PROPERTY_HINT_RANGE, "0,1024,1"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_LEFT);
ADD_PROPERTY(PropertyInfo(Variant::INT, "corner_detail", PROPERTY_HINT_RANGE, "1,20,1"), "set_corner_detail", "get_corner_detail");
- ADD_GROUP("Expand Margin", "expand_margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
+ ADD_GROUP("Expand Margins", "expand_margin_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
ADD_GROUP("Shadow", "shadow_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_shadow_size", "get_shadow_size");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset"), "set_shadow_offset", "get_shadow_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_shadow_size", "get_shadow_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_shadow_offset", "get_shadow_offset");
ADD_GROUP("Anti Aliasing", "anti_aliasing_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "anti_aliasing"), "set_anti_aliased", "is_anti_aliased");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "anti_aliasing_size", PROPERTY_HINT_RANGE, "0.01,10,0.001"), "set_aa_size", "get_aa_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "anti_aliasing_size", PROPERTY_HINT_RANGE, "0.01,10,0.001,suffix:px"), "set_aa_size", "get_aa_size");
}
StyleBoxFlat::StyleBoxFlat() {}
@@ -977,9 +1001,9 @@ void StyleBoxLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_vertical"), &StyleBoxLine::is_vertical);
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_begin", PROPERTY_HINT_RANGE, "-300,300,1"), "set_grow_begin", "get_grow_begin");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_end", PROPERTY_HINT_RANGE, "-300,300,1"), "set_grow_end", "get_grow_end");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "thickness", PROPERTY_HINT_RANGE, "0,10"), "set_thickness", "get_thickness");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_begin", PROPERTY_HINT_RANGE, "-300,300,1,suffix:px"), "set_grow_begin", "get_grow_begin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_end", PROPERTY_HINT_RANGE, "-300,300,1,suffix:px"), "set_grow_end", "get_grow_end");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "thickness", PROPERTY_HINT_RANGE, "0,10,suffix:px"), "set_thickness", "get_thickness");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
}
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 68ad41b69c..3b3654775f 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -155,6 +155,7 @@ class StyleBoxFlat : public StyleBox {
bool draw_center = true;
bool blend_border = false;
+ Vector2 skew;
bool anti_aliased = true;
int corner_detail = 8;
@@ -200,6 +201,9 @@ public:
void set_draw_center(bool p_enabled);
bool is_draw_center_enabled() const;
+ void set_skew(Vector2 p_skew);
+ Vector2 get_skew() const;
+
void set_shadow_color(const Color &p_color);
Color get_shadow_color() const;
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 8ff1fde2cf..9829c7e86b 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -141,7 +141,8 @@ uint32_t SurfaceTool::VertexHasher::hash(const Vertex &p_vtx) {
h = hash_djb2_buffer((const uint8_t *)p_vtx.bones.ptr(), p_vtx.bones.size() * sizeof(int), h);
h = hash_djb2_buffer((const uint8_t *)p_vtx.weights.ptr(), p_vtx.weights.size() * sizeof(float), h);
h = hash_djb2_buffer((const uint8_t *)&p_vtx.custom[0], sizeof(Color) * RS::ARRAY_CUSTOM_COUNT, h);
- h = hash_djb2_one_32(p_vtx.smooth_group, h);
+ h = hash_murmur3_one_32(p_vtx.smooth_group, h);
+ h = hash_fmix32(h);
return h;
}
@@ -315,19 +316,17 @@ void SurfaceTool::set_uv2(const Vector2 &p_uv2) {
last_uv2 = p_uv2;
}
-void SurfaceTool::set_custom(int p_index, const Color &p_custom) {
- ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT);
+void SurfaceTool::set_custom(int p_channel_index, const Color &p_custom) {
+ ERR_FAIL_INDEX(p_channel_index, RS::ARRAY_CUSTOM_COUNT);
ERR_FAIL_COND(!begun);
- ERR_FAIL_COND(last_custom_format[p_index] == CUSTOM_MAX);
+ ERR_FAIL_COND(last_custom_format[p_channel_index] == CUSTOM_MAX);
static const uint32_t mask[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0, Mesh::ARRAY_FORMAT_CUSTOM1, Mesh::ARRAY_FORMAT_CUSTOM2, Mesh::ARRAY_FORMAT_CUSTOM3 };
- static const uint32_t shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT };
- ERR_FAIL_COND(!first && !(format & mask[p_index]));
+ ERR_FAIL_COND(!first && !(format & mask[p_channel_index]));
if (first) {
- format |= mask[p_index];
- format |= last_custom_format[p_index] << shift[p_index];
+ format |= mask[p_channel_index];
}
- last_custom[p_index] = p_custom;
+ last_custom[p_channel_index] = p_custom;
}
void SurfaceTool::set_bones(const Vector<int> &p_bones) {
@@ -689,7 +688,7 @@ Array SurfaceTool::commit_to_arrays() {
return a;
}
-Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_flags) {
+Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_compress_flags) {
Ref<ArrayMesh> mesh;
if (p_existing.is_valid()) {
mesh = p_existing;
@@ -707,7 +706,15 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_
Array a = commit_to_arrays();
- mesh->add_surface_from_arrays(primitive, a, Array(), Dictionary(), p_flags);
+ uint32_t compress_flags = (p_compress_flags >> RS::ARRAY_COMPRESS_FLAGS_BASE) << RS::ARRAY_COMPRESS_FLAGS_BASE;
+ static const uint32_t shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT };
+ for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+ if (last_custom_format[i] != CUSTOM_MAX) {
+ compress_flags |= last_custom_format[i] << shift[i];
+ }
+ }
+
+ mesh->add_surface_from_arrays(primitive, a, Array(), Dictionary(), compress_flags);
if (material.is_valid()) {
mesh->surface_set_material(surface, material);
@@ -988,9 +995,6 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
for (int j = 0; j < RS::ARRAY_CUSTOM_COUNT; j++) {
if (format & custom_mask[j]) {
CustomFormat new_format = (CustomFormat)((format >> custom_shift[j]) & RS::ARRAY_FORMAT_CUSTOM_MASK);
- if (last_custom_format[j] != CUSTOM_MAX && last_custom_format[j] != new_format) {
- WARN_PRINT(vformat("Custom %d format %d mismatch when appending format %d", j, last_custom_format[j], new_format));
- }
last_custom_format[j] = new_format;
}
}
@@ -1165,7 +1169,7 @@ void SurfaceTool::generate_normals(bool p_flip) {
for (int i = 0; i < 3; i++) {
Vector3 *lv = vertex_hash.getptr(v[i]);
if (!lv) {
- vertex_hash.set(v[i], normal);
+ vertex_hash.insert(v[i], normal);
} else {
(*lv) += normal;
}
@@ -1220,22 +1224,24 @@ SurfaceTool::SkinWeightCount SurfaceTool::get_skin_weight_count() const {
return skin_weights;
}
-void SurfaceTool::set_custom_format(int p_index, CustomFormat p_format) {
- ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT);
- ERR_FAIL_COND(begun);
- last_custom_format[p_index] = p_format;
+void SurfaceTool::set_custom_format(int p_channel_index, CustomFormat p_format) {
+ ERR_FAIL_INDEX(p_channel_index, RS::ARRAY_CUSTOM_COUNT);
+ ERR_FAIL_COND(!begun);
+ ERR_FAIL_INDEX(p_format, CUSTOM_MAX + 1);
+ last_custom_format[p_channel_index] = p_format;
}
-Mesh::PrimitiveType SurfaceTool::get_primitive() const {
+Mesh::PrimitiveType SurfaceTool::get_primitive_type() const {
return primitive;
}
-SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_index) const {
- ERR_FAIL_INDEX_V(p_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX);
- return last_custom_format[p_index];
+SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_channel_index) const {
+ ERR_FAIL_INDEX_V(p_channel_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX);
+ return last_custom_format[p_channel_index];
}
void SurfaceTool::optimize_indices_for_cache() {
ERR_FAIL_COND(optimize_vertex_cache_func == nullptr);
ERR_FAIL_COND(index_array.size() == 0);
+ ERR_FAIL_COND(primitive != Mesh::PRIMITIVE_TRIANGLES);
ERR_FAIL_COND(index_array.size() % 3 != 0);
LocalVector old_index_array = index_array;
@@ -1243,8 +1249,8 @@ void SurfaceTool::optimize_indices_for_cache() {
optimize_vertex_cache_func((unsigned int *)index_array.ptr(), (unsigned int *)old_index_array.ptr(), old_index_array.size(), vertex_array.size());
}
-float SurfaceTool::get_max_axis_length() const {
- ERR_FAIL_COND_V(vertex_array.size() == 0, 0);
+AABB SurfaceTool::get_aabb() const {
+ ERR_FAIL_COND_V(vertex_array.size() == 0, AABB());
AABB aabb;
for (uint32_t i = 0; i < vertex_array.size(); i++) {
@@ -1255,7 +1261,7 @@ float SurfaceTool::get_max_axis_length() const {
}
}
- return aabb.get_longest_axis_size();
+ return aabb;
}
Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_count) {
Vector<int> lod;
@@ -1288,8 +1294,8 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_skin_weight_count", "count"), &SurfaceTool::set_skin_weight_count);
ClassDB::bind_method(D_METHOD("get_skin_weight_count"), &SurfaceTool::get_skin_weight_count);
- ClassDB::bind_method(D_METHOD("set_custom_format", "index", "format"), &SurfaceTool::set_custom_format);
- ClassDB::bind_method(D_METHOD("get_custom_format", "index"), &SurfaceTool::get_custom_format);
+ ClassDB::bind_method(D_METHOD("set_custom_format", "channel_index", "format"), &SurfaceTool::set_custom_format);
+ ClassDB::bind_method(D_METHOD("get_custom_format", "channel_index"), &SurfaceTool::get_custom_format);
ClassDB::bind_method(D_METHOD("begin", "primitive"), &SurfaceTool::begin);
@@ -1301,7 +1307,7 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_uv2", "uv2"), &SurfaceTool::set_uv2);
ClassDB::bind_method(D_METHOD("set_bones", "bones"), &SurfaceTool::set_bones);
ClassDB::bind_method(D_METHOD("set_weights", "weights"), &SurfaceTool::set_weights);
- ClassDB::bind_method(D_METHOD("set_custom", "index", "custom"), &SurfaceTool::set_custom);
+ ClassDB::bind_method(D_METHOD("set_custom", "channel_index", "custom_color"), &SurfaceTool::set_custom);
ClassDB::bind_method(D_METHOD("set_smooth_group", "index"), &SurfaceTool::set_smooth_group);
ClassDB::bind_method(D_METHOD("add_triangle_fan", "vertices", "uvs", "colors", "uv2s", "normals", "tangents"), &SurfaceTool::add_triangle_fan, DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Color>()), DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Vector3>()), DEFVAL(Vector<Plane>()));
@@ -1315,11 +1321,11 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("optimize_indices_for_cache"), &SurfaceTool::optimize_indices_for_cache);
- ClassDB::bind_method(D_METHOD("get_max_axis_length"), &SurfaceTool::get_max_axis_length);
+ ClassDB::bind_method(D_METHOD("get_aabb"), &SurfaceTool::get_aabb);
ClassDB::bind_method(D_METHOD("generate_lod", "nd_threshold", "target_index_count"), &SurfaceTool::generate_lod, DEFVAL(3));
ClassDB::bind_method(D_METHOD("set_material", "material"), &SurfaceTool::set_material);
- ClassDB::bind_method(D_METHOD("get_primitive"), &SurfaceTool::get_primitive);
+ ClassDB::bind_method(D_METHOD("get_primitive_type"), &SurfaceTool::get_primitive_type);
ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear);
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index bf4332ad2a..2d399ca3bf 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -154,10 +154,10 @@ public:
void set_skin_weight_count(SkinWeightCount p_weights);
SkinWeightCount get_skin_weight_count() const;
- void set_custom_format(int p_index, CustomFormat p_format);
- CustomFormat get_custom_format(int p_index) const;
+ void set_custom_format(int p_channel_index, CustomFormat p_format);
+ CustomFormat get_custom_format(int p_channel_index) const;
- Mesh::PrimitiveType get_primitive() const;
+ Mesh::PrimitiveType get_primitive_type() const;
void begin(Mesh::PrimitiveType p_primitive);
@@ -166,7 +166,7 @@ public:
void set_tangent(const Plane &p_tangent);
void set_uv(const Vector2 &p_uv);
void set_uv2(const Vector2 &p_uv2);
- void set_custom(int p_index, const Color &p_custom);
+ void set_custom(int p_channel_index, const Color &p_custom);
void set_bones(const Vector<int> &p_bones);
void set_weights(const Vector<float> &p_weights);
void set_smooth_group(uint32_t p_group);
@@ -183,7 +183,7 @@ public:
void generate_tangents();
void optimize_indices_for_cache();
- float get_max_axis_length() const;
+ AABB get_aabb() const;
Vector<int> generate_lod(float p_threshold, int p_target_index_count = 3);
void set_material(const Ref<Material> &p_material);
@@ -199,7 +199,7 @@ public:
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 Transform3D &p_xform);
- Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = 0);
+ Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_compress_flags = 0);
SurfaceTool();
};
diff --git a/scene/resources/syntax_highlighter.h b/scene/resources/syntax_highlighter.h
index 143f1679c6..1243a9dbf7 100644
--- a/scene/resources/syntax_highlighter.h
+++ b/scene/resources/syntax_highlighter.h
@@ -41,7 +41,7 @@ class SyntaxHighlighter : public Resource {
GDCLASS(SyntaxHighlighter, Resource)
private:
- Map<int, Dictionary> highlighting_cache;
+ RBMap<int, Dictionary> highlighting_cache;
void _lines_edited_from(int p_from_line, int p_to_line);
protected:
@@ -83,7 +83,7 @@ private:
bool line_only = false;
};
Vector<ColorRegion> color_regions;
- Map<int, int> color_region_cache;
+ HashMap<int, int> color_region_cache;
Dictionary keywords;
Dictionary member_keywords;
diff --git a/scene/resources/text_file.cpp b/scene/resources/text_file.cpp
index 96a47c37c4..0404e1f79b 100644
--- a/scene/resources/text_file.cpp
+++ b/scene/resources/text_file.cpp
@@ -64,7 +64,7 @@ Error TextFile::load_text(const String &p_path) {
w[len] = 0;
String s;
- ERR_FAIL_COND_V_MSG(s.parse_utf8((const char *)w), ERR_INVALID_DATA, "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded. Please ensure that scripts are saved in valid UTF-8 unicode.");
+ ERR_FAIL_COND_V_MSG(s.parse_utf8((const char *)w) != OK, ERR_INVALID_DATA, "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded. Please ensure that scripts are saved in valid UTF-8 unicode.");
text = s;
path = p_path;
return OK;
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index 337776fd47..823d742d72 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -36,7 +36,7 @@ void TextLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_direction", "direction"), &TextLine::set_direction);
ClassDB::bind_method(D_METHOD("get_direction"), &TextLine::get_direction);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "direction", PROPERTY_HINT_ENUM, "Auto,Light-to-right,Right-to-left"), "set_direction", "get_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "direction", PROPERTY_HINT_ENUM, "Auto,Left-to-right,Right-to-left"), "set_direction", "get_direction");
ClassDB::bind_method(D_METHOD("set_orientation", "orientation"), &TextLine::set_orientation);
ClassDB::bind_method(D_METHOD("get_orientation"), &TextLine::get_orientation);
@@ -55,7 +55,7 @@ void TextLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextLine::set_bidi_override);
- ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language", "meta"), &TextLine::add_string, DEFVAL(Dictionary()), DEFVAL(""), DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("add_string", "text", "font", "font_size", "language", "meta"), &TextLine::add_string, DEFVAL(""), DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextLine::add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1));
ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextLine::resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER));
@@ -74,7 +74,7 @@ void TextLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flags", "flags"), &TextLine::set_flags);
ClassDB::bind_method(D_METHOD("get_flags"), &TextLine::get_flags);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida Justify,Word Justify,Trim Edge Spaces After Justify,Justify Only After Last Tab"), "set_flags", "get_flags");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida Justification,Word Justification,Trim Edge Spaces After Justification,Justify Only After Last Tab,Constrain Ellipsis"), "set_flags", "get_flags");
ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "overrun_behavior"), &TextLine::set_text_overrun_behavior);
ClassDB::bind_method(D_METHOD("get_text_overrun_behavior"), &TextLine::get_text_overrun_behavior);
@@ -98,12 +98,6 @@ void TextLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_outline", "canvas", "pos", "outline_size", "color"), &TextLine::draw_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1)));
ClassDB::bind_method(D_METHOD("hit_test", "coords"), &TextLine::hit_test);
-
- BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_CHAR);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_ELLIPSIS);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ELLIPSIS);
}
void TextLine::_shape() {
@@ -112,32 +106,32 @@ void TextLine::_shape() {
TS->shaped_text_tab_align(rid, tab_stops);
}
- uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
- if (overrun_behavior != OVERRUN_NO_TRIMMING) {
+ BitField<TextServer::TextOverrunFlag> overrun_flags = TextServer::OVERRUN_NO_TRIM;
+ if (overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
switch (overrun_behavior) {
- case OVERRUN_TRIM_WORD_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ case TextServer::OVERRUN_TRIM_WORD_ELLIPSIS:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
+ overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
break;
- case OVERRUN_TRIM_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ case TextServer::OVERRUN_TRIM_ELLIPSIS:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
break;
- case OVERRUN_TRIM_WORD:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ case TextServer::OVERRUN_TRIM_WORD:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
break;
- case OVERRUN_TRIM_CHAR:
- overrun_flags |= TextServer::OVERRUN_TRIM;
+ case TextServer::OVERRUN_TRIM_CHAR:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
break;
- case OVERRUN_NO_TRIMMING:
+ case TextServer::OVERRUN_NO_TRIMMING:
break;
}
if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
TS->shaped_text_fit_to_width(rid, width, flags);
- overrun_flags |= TextServer::OVERRUN_JUSTIFICATION_AWARE;
+ overrun_flags.set_flag(TextServer::OVERRUN_JUSTIFICATION_AWARE);
TS->shaped_text_overrun_trim_to_width(rid, width, overrun_flags);
} else {
TS->shaped_text_overrun_trim_to_width(rid, width, overrun_flags);
@@ -155,8 +149,6 @@ RID TextLine::get_rid() const {
void TextLine::clear() {
TS->shaped_text_clear(rid);
- spacing_top = 0;
- spacing_bottom = 0;
}
void TextLine::set_preserve_invalid(bool p_enabled) {
@@ -200,11 +192,12 @@ void TextLine::set_bidi_override(const Array &p_override) {
dirty = true;
}
-bool TextLine::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
- ERR_FAIL_COND_V(p_fonts.is_null(), false);
- bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language, p_meta);
- spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP);
- spacing_bottom = p_fonts->get_spacing(TextServer::SPACING_BOTTOM);
+bool TextLine::add_string(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language, const Variant &p_meta) {
+ ERR_FAIL_COND_V(p_font.is_null(), false);
+ bool res = TS->shaped_text_add_string(rid, p_text, p_font->get_rids(), p_font_size, p_font->get_opentype_features(), p_language, p_meta);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(rid, TextServer::SpacingType(i), p_font->get_spacing(TextServer::SpacingType(i)));
+ }
dirty = true;
return res;
}
@@ -248,31 +241,31 @@ void TextLine::tab_align(const Vector<float> &p_tab_stops) {
dirty = true;
}
-void TextLine::set_flags(uint16_t p_flags) {
+void TextLine::set_flags(BitField<TextServer::JustificationFlag> p_flags) {
if (flags != p_flags) {
flags = p_flags;
dirty = true;
}
}
-uint16_t TextLine::get_flags() const {
+BitField<TextServer::JustificationFlag> TextLine::get_flags() const {
return flags;
}
-void TextLine::set_text_overrun_behavior(TextLine::OverrunBehavior p_behavior) {
+void TextLine::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) {
if (overrun_behavior != p_behavior) {
overrun_behavior = p_behavior;
dirty = true;
}
}
-TextLine::OverrunBehavior TextLine::get_text_overrun_behavior() const {
+TextServer::OverrunBehavior TextLine::get_text_overrun_behavior() const {
return overrun_behavior;
}
void TextLine::set_width(float p_width) {
width = p_width;
- if (alignment == HORIZONTAL_ALIGNMENT_FILL || overrun_behavior != OVERRUN_NO_TRIMMING) {
+ if (alignment == HORIZONTAL_ALIGNMENT_FILL || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
dirty = true;
}
}
@@ -284,20 +277,20 @@ float TextLine::get_width() const {
Size2 TextLine::get_size() const {
const_cast<TextLine *>(this)->_shape();
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom);
+ return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y);
} else {
- return Size2(TS->shaped_text_get_size(rid).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(rid).y);
+ return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y);
}
}
float TextLine::get_line_ascent() const {
const_cast<TextLine *>(this)->_shape();
- return TS->shaped_text_get_ascent(rid) + spacing_top;
+ return TS->shaped_text_get_ascent(rid);
}
float TextLine::get_line_descent() const {
const_cast<TextLine *>(this)->_shape();
- return TS->shaped_text_get_descent(rid) + spacing_bottom;
+ return TS->shaped_text_get_descent(rid);
}
float TextLine::get_line_width() const {
@@ -353,10 +346,10 @@ void TextLine::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color) co
float clip_l;
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(rid) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.x - ofs.x);
} else {
- ofs.x += TS->shaped_text_get_ascent(rid) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.y - ofs.y);
}
return TS->shaped_text_draw(rid, p_canvas, ofs, clip_l, clip_l + width, p_color);
@@ -400,10 +393,10 @@ void TextLine::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_si
float clip_l;
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(rid) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.x - ofs.x);
} else {
- ofs.x += TS->shaped_text_get_ascent(rid) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(rid);
clip_l = MAX(0, p_pos.y - ofs.y);
}
return TS->shaped_text_draw_outline(rid, p_canvas, ofs, clip_l, clip_l + width, p_outline_size, p_color);
@@ -415,11 +408,14 @@ int TextLine::hit_test(float p_coords) const {
return TS->shaped_text_hit_test_position(rid, p_coords);
}
-TextLine::TextLine(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
+TextLine::TextLine(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
rid = TS->create_shaped_text(p_direction, p_orientation);
- spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP);
- spacing_bottom = p_fonts->get_spacing(TextServer::SPACING_BOTTOM);
- TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
+ if (p_font.is_valid()) {
+ TS->shaped_text_add_string(rid, p_text, p_font->get_rids(), p_font_size, p_font->get_opentype_features(), p_language);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(rid, TextServer::SpacingType(i), p_font->get_spacing(TextServer::SpacingType(i)));
+ }
+ }
}
TextLine::TextLine() {
diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h
index c5762db0f2..e70e82cf2b 100644
--- a/scene/resources/text_line.h
+++ b/scene/resources/text_line.h
@@ -39,26 +39,15 @@
class TextLine : public RefCounted {
GDCLASS(TextLine, RefCounted);
-public:
- enum OverrunBehavior {
- OVERRUN_NO_TRIMMING,
- OVERRUN_TRIM_CHAR,
- OVERRUN_TRIM_WORD,
- OVERRUN_TRIM_ELLIPSIS,
- OVERRUN_TRIM_WORD_ELLIPSIS,
- };
-
private:
RID rid;
- int spacing_top = 0;
- int spacing_bottom = 0;
bool dirty = true;
float width = -1.0;
- uint16_t flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
+ BitField<TextServer::JustificationFlag> flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT;
- OverrunBehavior overrun_behavior = OVERRUN_TRIM_ELLIPSIS;
+ TextServer::OverrunBehavior overrun_behavior = TextServer::OVERRUN_TRIM_ELLIPSIS;
Vector<float> tab_stops;
@@ -86,7 +75,7 @@ public:
void set_preserve_control(bool p_enabled);
bool get_preserve_control() const;
- bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant());
+ bool add_string(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", const Variant &p_meta = Variant());
bool add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1);
bool resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER);
@@ -95,11 +84,11 @@ public:
void tab_align(const Vector<float> &p_tab_stops);
- void set_flags(uint16_t p_flags);
- uint16_t get_flags() const;
+ void set_flags(BitField<TextServer::JustificationFlag> p_flags);
+ BitField<TextServer::JustificationFlag> get_flags() const;
- void set_text_overrun_behavior(OverrunBehavior p_behavior);
- OverrunBehavior get_text_overrun_behavior() const;
+ void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior);
+ TextServer::OverrunBehavior get_text_overrun_behavior() const;
void set_width(float p_width);
float get_width() const;
@@ -120,11 +109,9 @@ public:
int hit_test(float p_coords) const;
- TextLine(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
+ TextLine(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
TextLine();
~TextLine();
};
-VARIANT_ENUM_CAST(TextLine::OverrunBehavior);
-
#endif // TEXT_LINE_H
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 61adaf43dd..43d3f329fa 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -60,10 +60,10 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextParagraph::set_bidi_override);
- ClassDB::bind_method(D_METHOD("set_dropcap", "text", "fonts", "size", "dropcap_margins", "opentype_features", "language"), &TextParagraph::set_dropcap, DEFVAL(Rect2()), DEFVAL(Dictionary()), DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("set_dropcap", "text", "font", "font_size", "dropcap_margins", "language"), &TextParagraph::set_dropcap, DEFVAL(Rect2()), DEFVAL(""));
ClassDB::bind_method(D_METHOD("clear_dropcap"), &TextParagraph::clear_dropcap);
- ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language", "meta"), &TextParagraph::add_string, DEFVAL(Dictionary()), DEFVAL(""), DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("add_string", "text", "font", "font_size", "language", "meta"), &TextParagraph::add_string, DEFVAL(""), DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextParagraph::add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1));
ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextParagraph::resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER));
@@ -74,10 +74,15 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("tab_align", "tab_stops"), &TextParagraph::tab_align);
- ClassDB::bind_method(D_METHOD("set_flags", "flags"), &TextParagraph::set_flags);
- ClassDB::bind_method(D_METHOD("get_flags"), &TextParagraph::get_flags);
+ ClassDB::bind_method(D_METHOD("set_break_flags", "flags"), &TextParagraph::set_break_flags);
+ ClassDB::bind_method(D_METHOD("get_break_flags"), &TextParagraph::get_break_flags);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida Justify,Word Justify,Trim Edge Spaces After Justify,Justify Only After Last Tab,Break Mandatory,Break Words,Break Graphemes"), "set_flags", "get_flags");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "break_flags", PROPERTY_HINT_FLAGS, "Mandatory,Word Bound,Grapheme Bound,Adaptive"), "set_break_flags", "get_break_flags");
+
+ ClassDB::bind_method(D_METHOD("set_justification_flags", "flags"), &TextParagraph::set_justification_flags);
+ ClassDB::bind_method(D_METHOD("get_justification_flags"), &TextParagraph::get_justification_flags);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "justification_flags", PROPERTY_HINT_FLAGS, "Kashida Justification,Word Justification,Trim Edge Spaces After Justification,Justify Only After Last Tab,Constrain Ellipsis"), "set_justification_flags", "get_justification_flags");
ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "overrun_behavior"), &TextParagraph::set_text_overrun_behavior);
ClassDB::bind_method(D_METHOD("get_text_overrun_behavior"), &TextParagraph::get_text_overrun_behavior);
@@ -113,9 +118,6 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line_underline_position", "line"), &TextParagraph::get_line_underline_position);
ClassDB::bind_method(D_METHOD("get_line_underline_thickness", "line"), &TextParagraph::get_line_underline_thickness);
- ClassDB::bind_method(D_METHOD("get_spacing_top"), &TextParagraph::get_spacing_top);
- ClassDB::bind_method(D_METHOD("get_spacing_bottom"), &TextParagraph::get_spacing_bottom);
-
ClassDB::bind_method(D_METHOD("get_dropcap_size"), &TextParagraph::get_dropcap_size);
ClassDB::bind_method(D_METHOD("get_dropcap_lines"), &TextParagraph::get_dropcap_lines);
@@ -129,17 +131,11 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_dropcap_outline", "canvas", "pos", "outline_size", "color"), &TextParagraph::draw_dropcap_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1)));
ClassDB::bind_method(D_METHOD("hit_test", "coords"), &TextParagraph::hit_test);
-
- BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_CHAR);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_ELLIPSIS);
- BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ELLIPSIS);
}
void TextParagraph::_shape_lines() {
if (lines_dirty) {
- for (int i = 0; i < lines_rid.size(); i++) {
+ for (int i = 0; i < (int)lines_rid.size(); i++) {
TS->free_rid(lines_rid[i]);
}
lines_rid.clear();
@@ -163,7 +159,7 @@ void TextParagraph::_shape_lines() {
if (h_offset > 0) {
// Dropcap, flow around.
- PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(rid, width - h_offset, 0, flags);
+ PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(rid, width - h_offset, 0, brk_flags);
for (int i = 0; i < line_breaks.size(); i = i + 2) {
RID line = TS->shaped_text_substr(rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
float h = (TS->shaped_text_get_orientation(line) == TextServer::ORIENTATION_HORIZONTAL) ? TS->shaped_text_get_size(line).y : TS->shaped_text_get_size(line).x;
@@ -181,7 +177,7 @@ void TextParagraph::_shape_lines() {
}
}
// Use fixed for the rest of lines.
- PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(rid, width, start, flags);
+ PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(rid, width, start, brk_flags);
for (int i = 0; i < line_breaks.size(); i = i + 2) {
RID line = TS->shaped_text_substr(rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
if (!tab_stops.is_empty()) {
@@ -190,43 +186,43 @@ void TextParagraph::_shape_lines() {
lines_rid.push_back(line);
}
- uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
- if (overrun_behavior != OVERRUN_NO_TRIMMING) {
+ BitField<TextServer::TextOverrunFlag> overrun_flags = TextServer::OVERRUN_NO_TRIM;
+ if (overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
switch (overrun_behavior) {
- case OVERRUN_TRIM_WORD_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ case TextServer::OVERRUN_TRIM_WORD_ELLIPSIS:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
+ overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
break;
- case OVERRUN_TRIM_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ case TextServer::OVERRUN_TRIM_ELLIPSIS:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
break;
- case OVERRUN_TRIM_WORD:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ case TextServer::OVERRUN_TRIM_WORD:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
break;
- case OVERRUN_TRIM_CHAR:
- overrun_flags |= TextServer::OVERRUN_TRIM;
+ case TextServer::OVERRUN_TRIM_CHAR:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
break;
- case OVERRUN_NO_TRIMMING:
+ case TextServer::OVERRUN_NO_TRIMMING:
break;
}
}
- bool autowrap_enabled = ((flags & TextServer::BREAK_WORD_BOUND) == TextServer::BREAK_WORD_BOUND) || ((flags & TextServer::BREAK_GRAPHEME_BOUND) == TextServer::BREAK_GRAPHEME_BOUND);
+ bool autowrap_enabled = brk_flags.has_flag(TextServer::BREAK_WORD_BOUND) || brk_flags.has_flag(TextServer::BREAK_GRAPHEME_BOUND);
// Fill after min_size calculation.
if (autowrap_enabled) {
- int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
- bool lines_hidden = visible_lines > 0 && visible_lines < lines_rid.size();
+ int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, (int)lines_rid.size()) : (int)lines_rid.size();
+ bool lines_hidden = visible_lines > 0 && visible_lines < (int)lines_rid.size();
if (lines_hidden) {
- overrun_flags |= TextServer::OVERRUN_ENFORCE_ELLIPSIS;
+ overrun_flags.set_flag(TextServer::OVERRUN_ENFORCE_ELLIPSIS);
}
if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
- for (int i = 0; i < lines_rid.size(); i++) {
- if (i < visible_lines - 1 || lines_rid.size() == 1) {
- TS->shaped_text_fit_to_width(lines_rid[i], width, flags);
+ for (int i = 0; i < (int)lines_rid.size(); i++) {
+ if (i < visible_lines - 1 || (int)lines_rid.size() == 1) {
+ TS->shaped_text_fit_to_width(lines_rid[i], width, jst_flags);
} else if (i == (visible_lines - 1)) {
TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
}
@@ -238,12 +234,12 @@ void TextParagraph::_shape_lines() {
} else {
// Autowrap disabled.
- for (int i = 0; i < lines_rid.size(); i++) {
+ for (int i = 0; i < (int)lines_rid.size(); i++) {
if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
- TS->shaped_text_fit_to_width(lines_rid[i], width, flags);
- overrun_flags |= TextServer::OVERRUN_JUSTIFICATION_AWARE;
+ TS->shaped_text_fit_to_width(lines_rid[i], width, jst_flags);
+ overrun_flags.set_flag(TextServer::OVERRUN_JUSTIFICATION_AWARE);
TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
- TS->shaped_text_fit_to_width(lines_rid[i], width, flags | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS);
+ TS->shaped_text_fit_to_width(lines_rid[i], width, jst_flags | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS);
} else {
TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
}
@@ -258,8 +254,10 @@ RID TextParagraph::get_rid() const {
}
RID TextParagraph::get_line_rid(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), RID());
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), RID());
return lines_rid[p_line];
}
@@ -268,9 +266,9 @@ RID TextParagraph::get_dropcap_rid() const {
}
void TextParagraph::clear() {
- spacing_top = 0;
- spacing_bottom = 0;
- for (int i = 0; i < lines_rid.size(); i++) {
+ _THREAD_SAFE_METHOD_
+
+ for (int i = 0; i < (int)lines_rid.size(); i++) {
TS->free_rid(lines_rid[i]);
}
lines_rid.clear();
@@ -279,106 +277,133 @@ void TextParagraph::clear() {
}
void TextParagraph::set_preserve_invalid(bool p_enabled) {
+ _THREAD_SAFE_METHOD_
+
TS->shaped_text_set_preserve_invalid(rid, p_enabled);
TS->shaped_text_set_preserve_invalid(dropcap_rid, p_enabled);
lines_dirty = true;
}
bool TextParagraph::get_preserve_invalid() const {
+ _THREAD_SAFE_METHOD_
+
return TS->shaped_text_get_preserve_invalid(rid);
}
void TextParagraph::set_preserve_control(bool p_enabled) {
+ _THREAD_SAFE_METHOD_
+
TS->shaped_text_set_preserve_control(rid, p_enabled);
TS->shaped_text_set_preserve_control(dropcap_rid, p_enabled);
lines_dirty = true;
}
bool TextParagraph::get_preserve_control() const {
+ _THREAD_SAFE_METHOD_
+
return TS->shaped_text_get_preserve_control(rid);
}
void TextParagraph::set_direction(TextServer::Direction p_direction) {
+ _THREAD_SAFE_METHOD_
+
TS->shaped_text_set_direction(rid, p_direction);
TS->shaped_text_set_direction(dropcap_rid, p_direction);
lines_dirty = true;
}
TextServer::Direction TextParagraph::get_direction() const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
return TS->shaped_text_get_direction(rid);
}
void TextParagraph::set_custom_punctuation(const String &p_punct) {
+ _THREAD_SAFE_METHOD_
+
TS->shaped_text_set_custom_punctuation(rid, p_punct);
lines_dirty = true;
}
String TextParagraph::get_custom_punctuation() const {
+ _THREAD_SAFE_METHOD_
+
return TS->shaped_text_get_custom_punctuation(rid);
}
void TextParagraph::set_orientation(TextServer::Orientation p_orientation) {
+ _THREAD_SAFE_METHOD_
+
TS->shaped_text_set_orientation(rid, p_orientation);
TS->shaped_text_set_orientation(dropcap_rid, p_orientation);
lines_dirty = true;
}
TextServer::Orientation TextParagraph::get_orientation() const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
return TS->shaped_text_get_orientation(rid);
}
-bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins, const Dictionary &p_opentype_features, const String &p_language) {
- ERR_FAIL_COND_V(p_fonts.is_null(), false);
+bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_font, int p_font_size, const Rect2 &p_dropcap_margins, const String &p_language) {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(p_font.is_null(), false);
TS->shaped_text_clear(dropcap_rid);
dropcap_margins = p_dropcap_margins;
- bool res = TS->shaped_text_add_string(dropcap_rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
+ bool res = TS->shaped_text_add_string(dropcap_rid, p_text, p_font->get_rids(), p_font_size, p_font->get_opentype_features(), p_language);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(dropcap_rid, TextServer::SpacingType(i), p_font->get_spacing(TextServer::SpacingType(i)));
+ }
lines_dirty = true;
return res;
}
void TextParagraph::clear_dropcap() {
+ _THREAD_SAFE_METHOD_
dropcap_margins = Rect2();
TS->shaped_text_clear(dropcap_rid);
lines_dirty = true;
}
-bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
- ERR_FAIL_COND_V(p_fonts.is_null(), false);
- bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language, p_meta);
- spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP);
- spacing_bottom = p_fonts->get_spacing(TextServer::SPACING_BOTTOM);
+bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language, const Variant &p_meta) {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(p_font.is_null(), false);
+ bool res = TS->shaped_text_add_string(rid, p_text, p_font->get_rids(), p_font_size, p_font->get_opentype_features(), p_language, p_meta);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(rid, TextServer::SpacingType(i), p_font->get_spacing(TextServer::SpacingType(i)));
+ }
lines_dirty = true;
return res;
}
-int TextParagraph::get_spacing_top() const {
- return spacing_top;
-}
-
-int TextParagraph::get_spacing_bottom() const {
- return spacing_bottom;
-}
-
void TextParagraph::set_bidi_override(const Array &p_override) {
+ _THREAD_SAFE_METHOD_
+
TS->shaped_text_set_bidi_override(rid, p_override);
lines_dirty = true;
}
bool TextParagraph::add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length) {
+ _THREAD_SAFE_METHOD_
+
bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length);
lines_dirty = true;
return res;
}
bool TextParagraph::resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
+ _THREAD_SAFE_METHOD_
+
bool res = TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align);
lines_dirty = true;
return res;
}
void TextParagraph::set_alignment(HorizontalAlignment p_alignment) {
+ _THREAD_SAFE_METHOD_
+
if (alignment != p_alignment) {
if (alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
alignment = p_alignment;
@@ -394,33 +419,54 @@ HorizontalAlignment TextParagraph::get_alignment() const {
}
void TextParagraph::tab_align(const Vector<float> &p_tab_stops) {
+ _THREAD_SAFE_METHOD_
+
tab_stops = p_tab_stops;
lines_dirty = true;
}
-void TextParagraph::set_flags(uint16_t p_flags) {
- if (flags != p_flags) {
- flags = p_flags;
+void TextParagraph::set_justification_flags(BitField<TextServer::JustificationFlag> p_flags) {
+ _THREAD_SAFE_METHOD_
+
+ if (jst_flags != p_flags) {
+ jst_flags = p_flags;
+ lines_dirty = true;
+ }
+}
+
+BitField<TextServer::JustificationFlag> TextParagraph::get_justification_flags() const {
+ return jst_flags;
+}
+
+void TextParagraph::set_break_flags(BitField<TextServer::LineBreakFlag> p_flags) {
+ _THREAD_SAFE_METHOD_
+
+ if (brk_flags != p_flags) {
+ brk_flags = p_flags;
lines_dirty = true;
}
}
-uint16_t TextParagraph::get_flags() const {
- return flags;
+BitField<TextServer::LineBreakFlag> TextParagraph::get_break_flags() const {
+ return brk_flags;
}
-void TextParagraph::set_text_overrun_behavior(TextParagraph::OverrunBehavior p_behavior) {
+void TextParagraph::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) {
+ _THREAD_SAFE_METHOD_
+
if (overrun_behavior != p_behavior) {
overrun_behavior = p_behavior;
lines_dirty = true;
}
}
-TextParagraph::OverrunBehavior TextParagraph::get_text_overrun_behavior() const {
+TextServer::OverrunBehavior TextParagraph::get_text_overrun_behavior() const {
return overrun_behavior;
}
void TextParagraph::set_width(float p_width) {
+ _THREAD_SAFE_METHOD_
+
if (width != p_width) {
width = p_width;
lines_dirty = true;
@@ -432,25 +478,29 @@ float TextParagraph::get_width() const {
}
Size2 TextParagraph::get_non_wrapped_size() const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom);
+ return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y);
} else {
- return Size2(TS->shaped_text_get_size(rid).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(rid).y);
+ return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y);
}
}
Size2 TextParagraph::get_size() const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
Size2 size;
- int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
+ int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, (int)lines_rid.size()) : (int)lines_rid.size();
for (int i = 0; i < visible_lines; i++) {
Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
size.x = MAX(size.x, lsize.x);
- size.y += lsize.y + spacing_top + spacing_bottom;
+ size.y += lsize.y;
} else {
- size.x += lsize.x + spacing_top + spacing_bottom;
+ size.x += lsize.x;
size.y = MAX(size.y, lsize.y);
}
}
@@ -458,11 +508,15 @@ Size2 TextParagraph::get_size() const {
}
int TextParagraph::get_line_count() const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- return lines_rid.size();
+ return (int)lines_rid.size();
}
void TextParagraph::set_max_lines_visible(int p_lines) {
+ _THREAD_SAFE_METHOD_
+
if (p_lines != max_lines_visible) {
max_lines_visible = p_lines;
lines_dirty = true;
@@ -474,73 +528,93 @@ int TextParagraph::get_max_lines_visible() const {
}
Array TextParagraph::get_line_objects(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Array());
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Array());
return TS->shaped_text_get_objects(lines_rid[p_line]);
}
Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Rect2());
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Rect2());
Rect2 xrect = TS->shaped_text_get_object_rect(lines_rid[p_line], p_key);
for (int i = 0; i < p_line; i++) {
Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
- xrect.position.y += lsize.y + spacing_top + spacing_bottom;
+ xrect.position.y += lsize.y;
} else {
- xrect.position.x += lsize.x + spacing_top + spacing_bottom;
+ xrect.position.x += lsize.x;
}
}
return xrect;
}
Size2 TextParagraph::get_line_size(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Size2());
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Size2());
if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
- return Size2(TS->shaped_text_get_size(lines_rid[p_line]).x, TS->shaped_text_get_size(lines_rid[p_line]).y + spacing_top + spacing_bottom);
+ return Size2(TS->shaped_text_get_size(lines_rid[p_line]).x, TS->shaped_text_get_size(lines_rid[p_line]).y);
} else {
- return Size2(TS->shaped_text_get_size(lines_rid[p_line]).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(lines_rid[p_line]).y);
+ return Size2(TS->shaped_text_get_size(lines_rid[p_line]).x, TS->shaped_text_get_size(lines_rid[p_line]).y);
}
}
Vector2i TextParagraph::get_line_range(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Vector2i());
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Vector2i());
return TS->shaped_text_get_range(lines_rid[p_line]);
}
float TextParagraph::get_line_ascent(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
- return TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
+ return TS->shaped_text_get_ascent(lines_rid[p_line]);
}
float TextParagraph::get_line_descent(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
- return TS->shaped_text_get_descent(lines_rid[p_line]) + spacing_bottom;
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
+ return TS->shaped_text_get_descent(lines_rid[p_line]);
}
float TextParagraph::get_line_width(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
return TS->shaped_text_get_width(lines_rid[p_line]);
}
float TextParagraph::get_line_underline_position(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
return TS->shaped_text_get_underline_position(lines_rid[p_line]);
}
float TextParagraph::get_line_underline_thickness(int p_line) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
return TS->shaped_text_get_underline_thickness(lines_rid[p_line]);
}
Size2 TextParagraph::get_dropcap_size() const {
+ _THREAD_SAFE_METHOD_
+
return TS->shaped_text_get_size(dropcap_rid) + dropcap_margins.size + dropcap_margins.position;
}
@@ -549,6 +623,8 @@ int TextParagraph::get_dropcap_lines() const {
}
void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color, const Color &p_dc_color) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
Vector2 ofs = p_pos;
float h_offset = 0.f;
@@ -571,13 +647,13 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
TS->shaped_text_draw(dropcap_rid, p_canvas, dc_off + Vector2(0, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.size.y + dropcap_margins.position.y / 2), -1, -1, p_dc_color);
}
- int lines_visible = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
+ int lines_visible = (max_lines_visible >= 0) ? MIN(max_lines_visible, (int)lines_rid.size()) : (int)lines_rid.size();
for (int i = 0; i < lines_visible; i++) {
float l_width = width;
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_ascent(lines_rid[i]) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[i]);
if (i <= dropcap_lines) {
if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
ofs.x -= h_offset;
@@ -586,7 +662,7 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
}
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_ascent(lines_rid[i]) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[i]);
if (i <= dropcap_lines) {
if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
ofs.x -= h_offset;
@@ -641,15 +717,17 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
TS->shaped_text_draw(lines_rid[i], p_canvas, ofs, clip_l, clip_l + l_width, p_color);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + spacing_bottom;
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]);
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + spacing_bottom;
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]);
}
}
}
void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color, const Color &p_dc_color) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
Vector2 ofs = p_pos;
@@ -673,11 +751,11 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
TS->shaped_text_draw_outline(dropcap_rid, p_canvas, dc_off + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_outline_size, p_dc_color);
}
- for (int i = 0; i < lines_rid.size(); i++) {
+ for (int i = 0; i < (int)lines_rid.size(); i++) {
float l_width = width;
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_ascent(lines_rid[i]) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[i]);
if (i <= dropcap_lines) {
if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
ofs.x -= h_offset;
@@ -686,7 +764,7 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
}
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_ascent(lines_rid[i]) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[i]);
if (i <= dropcap_lines) {
if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
ofs.x -= h_offset;
@@ -741,15 +819,17 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
TS->shaped_text_draw_outline(lines_rid[i], p_canvas, ofs, clip_l, clip_l + l_width, p_outline_size, p_color);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + spacing_bottom;
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]);
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + spacing_bottom;
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]);
}
}
}
int TextParagraph::hit_test(const Point2 &p_coords) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
Vector2 ofs;
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
@@ -761,23 +841,25 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
return 0;
}
}
- for (int i = 0; i < lines_rid.size(); i++) {
+ for (int i = 0; i < (int)lines_rid.size(); i++) {
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(lines_rid[i]).y)) {
return TS->shaped_text_hit_test_position(lines_rid[i], p_coords.x);
}
- ofs.y += TS->shaped_text_get_size(lines_rid[i]).y + spacing_bottom + spacing_top;
+ ofs.y += TS->shaped_text_get_size(lines_rid[i]).y;
} else {
if ((p_coords.x >= ofs.x) && (p_coords.x <= ofs.x + TS->shaped_text_get_size(lines_rid[i]).x)) {
return TS->shaped_text_hit_test_position(lines_rid[i], p_coords.y);
}
- ofs.y += TS->shaped_text_get_size(lines_rid[i]).x + spacing_bottom + spacing_top;
+ ofs.y += TS->shaped_text_get_size(lines_rid[i]).x;
}
}
return TS->shaped_text_get_range(rid).y;
}
void TextParagraph::draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+
Vector2 ofs = p_pos;
float h_offset = 0.f;
if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
@@ -800,6 +882,8 @@ void TextParagraph::draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color
}
void TextParagraph::draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+
Vector2 ofs = p_pos;
float h_offset = 0.f;
if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
@@ -822,37 +906,44 @@ void TextParagraph::draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int
}
void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND(p_line < 0 || p_line >= lines_rid.size());
+ ERR_FAIL_COND(p_line < 0 || p_line >= (int)lines_rid.size());
Vector2 ofs = p_pos;
if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[p_line]);
} else {
- ofs.x += TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[p_line]);
}
return TS->shaped_text_draw(lines_rid[p_line], p_canvas, ofs, -1, -1, p_color);
}
void TextParagraph::draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_line, int p_outline_size, const Color &p_color) const {
+ _THREAD_SAFE_METHOD_
+
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND(p_line < 0 || p_line >= lines_rid.size());
+ ERR_FAIL_COND(p_line < 0 || p_line >= (int)lines_rid.size());
Vector2 ofs = p_pos;
if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[p_line]);
} else {
- ofs.x += TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[p_line]);
}
return TS->shaped_text_draw_outline(lines_rid[p_line], p_canvas, ofs, -1, -1, p_outline_size, p_color);
}
-TextParagraph::TextParagraph(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, float p_width, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
+TextParagraph::TextParagraph(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language, float p_width, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
rid = TS->create_shaped_text(p_direction, p_orientation);
- TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
- spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP);
- spacing_bottom = p_fonts->get_spacing(TextServer::SPACING_BOTTOM);
+ if (p_font.is_valid()) {
+ TS->shaped_text_add_string(rid, p_text, p_font->get_rids(), p_font_size, p_font->get_opentype_features(), p_language);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(rid, TextServer::SpacingType(i), p_font->get_spacing(TextServer::SpacingType(i)));
+ }
+ }
width = p_width;
}
@@ -862,7 +953,7 @@ TextParagraph::TextParagraph() {
}
TextParagraph::~TextParagraph() {
- for (int i = 0; i < lines_rid.size(); i++) {
+ for (int i = 0; i < (int)lines_rid.size(); i++) {
TS->free_rid(lines_rid[i]);
}
lines_rid.clear();
diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h
index 8a8a53943b..0fe82b4364 100644
--- a/scene/resources/text_paragraph.h
+++ b/scene/resources/text_paragraph.h
@@ -31,6 +31,7 @@
#ifndef TEXT_PARAGRAPH_H
#define TEXT_PARAGRAPH_H
+#include "core/templates/local_vector.h"
#include "scene/resources/font.h"
#include "servers/text_server.h"
@@ -38,15 +39,7 @@
class TextParagraph : public RefCounted {
GDCLASS(TextParagraph, RefCounted);
-
-public:
- enum OverrunBehavior {
- OVERRUN_NO_TRIMMING,
- OVERRUN_TRIM_CHAR,
- OVERRUN_TRIM_WORD,
- OVERRUN_TRIM_ELLIPSIS,
- OVERRUN_TRIM_WORD_ELLIPSIS,
- };
+ _THREAD_SAFE_CLASS_
private:
RID dropcap_rid;
@@ -54,17 +47,16 @@ private:
Rect2 dropcap_margins;
RID rid;
- Vector<RID> lines_rid;
- int spacing_top = 0;
- int spacing_bottom = 0;
+ LocalVector<RID> lines_rid;
bool lines_dirty = true;
float width = -1.0;
int max_lines_visible = -1;
- uint16_t flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
- OverrunBehavior overrun_behavior = OVERRUN_NO_TRIMMING;
+ BitField<TextServer::LineBreakFlag> brk_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND;
+ BitField<TextServer::JustificationFlag> jst_flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
+ TextServer::OverrunBehavior overrun_behavior = TextServer::OVERRUN_NO_TRIMMING;
HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT;
@@ -99,10 +91,10 @@ public:
void set_custom_punctuation(const String &p_punct);
String get_custom_punctuation() const;
- bool set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "");
+ bool set_dropcap(const String &p_text, const Ref<Font> &p_font, int p_font_size, const Rect2 &p_dropcap_margins = Rect2(), const String &p_language = "");
void clear_dropcap();
- bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant());
+ bool add_string(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", const Variant &p_meta = Variant());
bool add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1);
bool resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER);
@@ -111,11 +103,14 @@ public:
void tab_align(const Vector<float> &p_tab_stops);
- void set_flags(uint16_t p_flags);
- uint16_t get_flags() const;
+ void set_justification_flags(BitField<TextServer::JustificationFlag> p_flags);
+ BitField<TextServer::JustificationFlag> get_justification_flags() const;
+
+ void set_break_flags(BitField<TextServer::LineBreakFlag> p_flags);
+ BitField<TextServer::LineBreakFlag> get_break_flags() const;
- void set_text_overrun_behavior(OverrunBehavior p_behavior);
- OverrunBehavior get_text_overrun_behavior() const;
+ void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior);
+ TextServer::OverrunBehavior get_text_overrun_behavior() const;
void set_width(float p_width);
float get_width() const;
@@ -156,11 +151,11 @@ public:
int hit_test(const Point2 &p_coords) const;
- TextParagraph(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", float p_width = -1.f, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
+ Mutex &get_mutex() const { return _thread_safe_; };
+
+ TextParagraph(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", float p_width = -1.f, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
TextParagraph();
~TextParagraph();
};
-VARIANT_ENUM_CAST(TextParagraph::OverrunBehavior);
-
#endif // TEXT_PARAGRAPH_H
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 4c20e07976..0aefe34f7d 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -139,7 +139,7 @@ void ImageTexture::reload_from_file() {
img.instantiate();
if (ImageLoader::load_image(path, img) == OK) {
- create_from_image(img);
+ set_image(img);
} else {
Resource::reload_from_file();
notify_property_list_changed();
@@ -149,37 +149,34 @@ void ImageTexture::reload_from_file() {
bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "image") {
- create_from_image(p_value);
- } else if (p_name == "size") {
- Size2 s = p_value;
- w = s.width;
- h = s.height;
- RenderingServer::get_singleton()->texture_set_size_override(texture, w, h);
- } else {
- return false;
+ set_image(p_value);
+ return true;
}
-
- return true;
+ return false;
}
bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name == "image") {
r_ret = get_image();
- } else if (p_name == "size") {
- r_ret = Size2(w, h);
- } else {
- return false;
+ return true;
}
-
- return true;
+ return false;
}
void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("image"), PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
}
-void ImageTexture::create_from_image(const Ref<Image> &p_image) {
+Ref<ImageTexture> ImageTexture::create_from_image(const Ref<Image> &p_image) {
+ ERR_FAIL_COND_V_MSG(p_image.is_null() || p_image->is_empty(), Ref<ImageTexture>(), "Invalid image");
+
+ Ref<ImageTexture> image_texture;
+ image_texture.instantiate();
+ image_texture->set_image(p_image);
+ return image_texture;
+}
+
+void ImageTexture::set_image(const Ref<Image> &p_image) {
ERR_FAIL_COND_MSG(p_image.is_null() || p_image->is_empty(), "Invalid image");
w = p_image->get_width();
h = p_image->get_height();
@@ -303,8 +300,8 @@ bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const {
return true;
}
-void ImageTexture::set_size_override(const Size2 &p_size) {
- Size2 s = p_size;
+void ImageTexture::set_size_override(const Size2i &p_size) {
+ Size2i s = p_size;
if (s.x != 0) {
w = s.x;
}
@@ -323,9 +320,10 @@ void ImageTexture::set_path(const String &p_path, bool p_take_over) {
}
void ImageTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("create_from_image", "image"), &ImageTexture::create_from_image);
+ ClassDB::bind_static_method("ImageTexture", D_METHOD("create_from_image", "image"), &ImageTexture::create_from_image);
ClassDB::bind_method(D_METHOD("get_format"), &ImageTexture::get_format);
+ ClassDB::bind_method(D_METHOD("set_image", "image"), &ImageTexture::set_image);
ClassDB::bind_method(D_METHOD("update", "image"), &ImageTexture::update);
ClassDB::bind_method(D_METHOD("set_size_override", "size"), &ImageTexture::set_size_override);
}
@@ -625,7 +623,7 @@ void PortableCompressedTexture2D::_bind_methods() {
ClassDB::bind_static_method("PortableCompressedTexture2D", D_METHOD("is_keeping_all_compressed_buffers"), &PortableCompressedTexture2D::is_keeping_all_compressed_buffers);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "_set_data", "_get_data");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size_override"), "set_size_override", "get_size_override");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size_override", PROPERTY_HINT_NONE, "suffix:px"), "set_size_override", "get_size_override");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_compressed_buffer"), "set_keep_compressed_buffer", "is_keeping_compressed_buffer");
BIND_ENUM_CONSTANT(COMPRESSION_MODE_LOSSLESS);
@@ -1058,7 +1056,7 @@ CompressedTexture2D::~CompressedTexture2D() {
}
}
-RES ResourceFormatLoaderCompressedTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoaderCompressedTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
Ref<CompressedTexture2D> st;
st.instantiate();
Error err = st->load(p_path);
@@ -1066,7 +1064,7 @@ RES ResourceFormatLoaderCompressedTexture2D::load(const String &p_path, const St
*r_error = err;
}
if (err != OK) {
- return RES();
+ return Ref<Resource>();
}
return st;
@@ -1416,7 +1414,7 @@ CompressedTexture3D::~CompressedTexture3D() {
/////////////////////////////
-RES ResourceFormatLoaderCompressedTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoaderCompressedTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
Ref<CompressedTexture3D> st;
st.instantiate();
Error err = st->load(p_path);
@@ -1424,7 +1422,7 @@ RES ResourceFormatLoaderCompressedTexture3D::load(const String &p_path, const St
*r_error = err;
}
if (err != OK) {
- return RES();
+ return Ref<Resource>();
}
return st;
@@ -1545,8 +1543,8 @@ void AtlasTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_filter_clip"), &AtlasTexture::has_filter_clip);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "atlas", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_atlas", "get_atlas");
- ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region"), "set_region", "get_region");
- ADD_PROPERTY(PropertyInfo(Variant::RECT2, "margin"), "set_margin", "get_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region", PROPERTY_HINT_NONE, "suffix:px"), "set_region", "get_region");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "margin", PROPERTY_HINT_NONE, "suffix:px"), "set_margin", "get_margin");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_clip"), "set_filter_clip", "has_filter_clip");
}
@@ -1717,8 +1715,8 @@ void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_mo
Transform2D xform;
xform.set_origin(p_pos);
if (p_transpose) {
- SWAP(xform.elements[0][1], xform.elements[1][0]);
- SWAP(xform.elements[0][0], xform.elements[1][1]);
+ SWAP(xform.columns[0][1], xform.columns[1][0]);
+ SWAP(xform.columns[0][0], xform.columns[1][1]);
}
RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid());
}
@@ -1739,8 +1737,8 @@ void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile,
xform.set_scale(p_rect.size / size);
if (p_transpose) {
- SWAP(xform.elements[0][1], xform.elements[1][0]);
- SWAP(xform.elements[0][0], xform.elements[1][1]);
+ SWAP(xform.columns[0][1], xform.columns[1][0]);
+ SWAP(xform.columns[0][0], xform.columns[1][1]);
}
RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid());
}
@@ -1761,8 +1759,8 @@ void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const
xform.set_scale(p_rect.size / size);
if (p_transpose) {
- SWAP(xform.elements[0][1], xform.elements[1][0]);
- SWAP(xform.elements[0][0], xform.elements[1][1]);
+ SWAP(xform.columns[0][1], xform.columns[1][0]);
+ SWAP(xform.columns[0][0], xform.columns[1][1]);
}
RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid());
}
@@ -1787,7 +1785,7 @@ void MeshTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_base_texture", "get_base_texture");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "image_size", PROPERTY_HINT_RANGE, "0,16384,1"), "set_image_size", "get_image_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "image_size", PROPERTY_HINT_RANGE, "0,16384,1,suffix:px"), "set_image_size", "get_image_size");
}
MeshTexture::MeshTexture() {
@@ -1806,7 +1804,7 @@ void CurveTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &CurveTexture::_update);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "RGB,Red"), "set_texture_mode", "get_texture_mode");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
@@ -1954,7 +1952,7 @@ void CurveXYZTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &CurveXYZTexture::_update);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_x", "get_curve_x");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_y", "get_curve_y");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_z", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_z", "get_curve_z");
@@ -2160,8 +2158,8 @@ void GradientTexture1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &GradientTexture1D::_update);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_gradient", "get_gradient");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,16384,suffix:px"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
}
@@ -2249,7 +2247,7 @@ void GradientTexture1D::_update() {
}
void GradientTexture1D::set_width(int p_width) {
- ERR_FAIL_COND(p_width <= 0);
+ ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range.");
width = p_width;
_queue_update();
}
@@ -2278,6 +2276,8 @@ Ref<Image> GradientTexture1D::get_image() const {
return RenderingServer::get_singleton()->texture_2d_get(texture);
}
+//////////////////
+
GradientTexture2D::GradientTexture2D() {
_queue_update();
}
@@ -2299,7 +2299,8 @@ void GradientTexture2D::set_gradient(Ref<Gradient> p_gradient) {
if (gradient.is_valid()) {
gradient->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GradientTexture2D::_queue_update));
}
- _queue_update();
+ _update();
+ emit_changed();
}
Ref<Gradient> GradientTexture2D::get_gradient() const {
@@ -2410,6 +2411,7 @@ float GradientTexture2D::_get_gradient_offset_at(int x, int y) const {
}
void GradientTexture2D::set_width(int p_width) {
+ ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range.");
width = p_width;
_queue_update();
}
@@ -2419,6 +2421,7 @@ int GradientTexture2D::get_width() const {
}
void GradientTexture2D::set_height(int p_height) {
+ ERR_FAIL_COND_MSG(p_height <= 0 || p_height > 16384, "Texture dimensions have to be within 1 to 16384 range.");
height = p_height;
_queue_update();
}
@@ -2512,8 +2515,8 @@ void GradientTexture2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &GradientTexture2D::_update);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_gradient", "get_gradient");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048"), "set_width", "get_width");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,or_greater,suffix:px"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,or_greater,suffix:px"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
ADD_GROUP("Fill", "fill_");
@@ -2833,7 +2836,7 @@ void AnimatedTexture::_bind_methods() {
for (int i = 0; i < MAX_FRAMES; i++) {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "frame_" + itos(i) + "/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_texture", "get_frame_texture", i);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "frame_" + itos(i) + "/delay_sec", PROPERTY_HINT_RANGE, "0.0,16.0,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_delay", "get_frame_delay", i);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "frame_" + itos(i) + "/delay_sec", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_delay", "get_frame_delay", i);
}
BIND_CONSTANT(MAX_FRAMES);
@@ -3023,12 +3026,12 @@ Error ImageTextureLayered::create_from_images(Vector<Ref<Image>> p_images) {
}
void ImageTextureLayered::update_layer(const Ref<Image> &p_image, int p_layer) {
- ERR_FAIL_COND(texture.is_valid());
- ERR_FAIL_COND(p_image.is_null());
- ERR_FAIL_COND(p_image->get_format() != format);
- ERR_FAIL_COND(p_image->get_width() != width || p_image->get_height() != height);
- ERR_FAIL_INDEX(p_layer, layers);
- ERR_FAIL_COND(p_image->has_mipmaps() != mipmaps);
+ ERR_FAIL_COND_MSG(texture.is_null(), "Texture is not initialized.");
+ ERR_FAIL_COND_MSG(p_image.is_null(), "Invalid image.");
+ ERR_FAIL_COND_MSG(p_image->get_format() != format, "Image format must match texture's image format.");
+ ERR_FAIL_COND_MSG(p_image->get_width() != width || p_image->get_height() != height, "Image size must match texture's image size.");
+ ERR_FAIL_COND_MSG(p_image->has_mipmaps() != mipmaps, "Image mipmap configuration must match texture's image mipmap configuration.");
+ ERR_FAIL_INDEX_MSG(p_layer, layers, "Layer index is out of bounds.");
RS::get_singleton()->texture_2d_update(texture, p_image, p_layer);
}
@@ -3240,7 +3243,7 @@ CompressedTextureLayered::~CompressedTextureLayered() {
/////////////////////////////////////////////////
-RES ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
Ref<CompressedTextureLayered> ct;
if (p_path.get_extension().to_lower() == "ctexarray") {
Ref<CompressedTexture2DArray> c;
@@ -3258,14 +3261,14 @@ RES ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, con
if (r_error) {
*r_error = ERR_FILE_UNRECOGNIZED;
}
- return RES();
+ return Ref<Resource>();
}
Error err = ct->load(p_path);
if (r_error) {
*r_error = err;
}
if (err != OK) {
- return RES();
+ return Ref<Resource>();
}
return ct;
@@ -3392,3 +3395,148 @@ CameraTexture::~CameraTexture() {
RenderingServer::get_singleton()->free(_texture);
}
}
+
+///////////////////////////
+
+void PlaceholderTexture2D::set_size(Size2 p_size) {
+ size = p_size;
+}
+
+int PlaceholderTexture2D::get_width() const {
+ return size.width;
+}
+
+int PlaceholderTexture2D::get_height() const {
+ return size.height;
+}
+
+bool PlaceholderTexture2D::has_alpha() const {
+ return false;
+}
+
+Ref<Image> PlaceholderTexture2D::get_image() const {
+ return Ref<Image>();
+}
+
+RID PlaceholderTexture2D::get_rid() const {
+ return rid;
+}
+
+void PlaceholderTexture2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTexture2D::set_size);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
+}
+
+PlaceholderTexture2D::PlaceholderTexture2D() {
+ rid = RS::get_singleton()->texture_2d_placeholder_create();
+}
+
+PlaceholderTexture2D::~PlaceholderTexture2D() {
+ RS::get_singleton()->free(rid);
+}
+
+///////////////////////////////////////////////
+
+void PlaceholderTexture3D::set_size(const Vector3i &p_size) {
+ size = p_size;
+}
+
+Vector3i PlaceholderTexture3D::get_size() const {
+ return size;
+}
+
+Image::Format PlaceholderTexture3D::get_format() const {
+ return Image::FORMAT_RGB8;
+}
+
+int PlaceholderTexture3D::get_width() const {
+ return size.x;
+}
+
+int PlaceholderTexture3D::get_height() const {
+ return size.y;
+}
+
+int PlaceholderTexture3D::get_depth() const {
+ return size.z;
+}
+
+bool PlaceholderTexture3D::has_mipmaps() const {
+ return false;
+}
+
+Vector<Ref<Image>> PlaceholderTexture3D::get_data() const {
+ return Vector<Ref<Image>>();
+}
+
+void PlaceholderTexture3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTexture3D::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &PlaceholderTexture3D::get_size);
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
+}
+
+PlaceholderTexture3D::PlaceholderTexture3D() {
+ rid = RS::get_singleton()->texture_3d_placeholder_create();
+}
+PlaceholderTexture3D::~PlaceholderTexture3D() {
+ RS::get_singleton()->free(rid);
+}
+
+/////////////////////////////////////////////////
+
+void PlaceholderTextureLayered::set_size(const Size2i &p_size) {
+ size = p_size;
+}
+
+Size2i PlaceholderTextureLayered::get_size() const {
+ return size;
+}
+
+void PlaceholderTextureLayered::set_layers(int p_layers) {
+ layers = p_layers;
+}
+
+Image::Format PlaceholderTextureLayered::get_format() const {
+ return Image::FORMAT_RGB8;
+}
+
+TextureLayered::LayeredType PlaceholderTextureLayered::get_layered_type() const {
+ return layered_type;
+}
+
+int PlaceholderTextureLayered::get_width() const {
+ return size.x;
+}
+
+int PlaceholderTextureLayered::get_height() const {
+ return size.y;
+}
+
+int PlaceholderTextureLayered::get_layers() const {
+ return layers;
+}
+
+bool PlaceholderTextureLayered::has_mipmaps() const {
+ return false;
+}
+
+Ref<Image> PlaceholderTextureLayered::get_layer_data(int p_layer) const {
+ return Ref<Image>();
+}
+
+void PlaceholderTextureLayered::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTextureLayered::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &PlaceholderTextureLayered::get_size);
+ ClassDB::bind_method(D_METHOD("set_layers", "layers"), &PlaceholderTextureLayered::set_layers);
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_RANGE, "1,4096"), "set_layers", "get_layers");
+}
+
+PlaceholderTextureLayered::PlaceholderTextureLayered(LayeredType p_type) {
+ layered_type = p_type;
+ rid = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type));
+}
+PlaceholderTextureLayered::~PlaceholderTextureLayered() {
+ RS::get_singleton()->free(rid);
+}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 525e3ff979..b107a2a70d 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -110,7 +110,8 @@ protected:
static void _bind_methods();
public:
- void create_from_image(const Ref<Image> &p_image);
+ void set_image(const Ref<Image> &p_image);
+ static Ref<ImageTexture> create_from_image(const Ref<Image> &p_image);
Image::Format get_format() const;
@@ -129,7 +130,7 @@ public:
bool is_pixel_opaque(int p_x, int p_y) const override;
- void set_size_override(const Size2 &p_size);
+ void set_size_override(const Size2i &p_size);
virtual void set_path(const String &p_path, bool p_take_over = false) override;
@@ -287,7 +288,7 @@ public:
class ResourceFormatLoaderCompressedTexture2D : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
@@ -552,7 +553,7 @@ public:
class ResourceFormatLoaderCompressedTextureLayered : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
@@ -673,7 +674,7 @@ public:
class ResourceFormatLoaderCompressedTexture3D : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
@@ -1011,4 +1012,98 @@ public:
~CameraTexture();
};
+class PlaceholderTexture2D : public Texture2D {
+ GDCLASS(PlaceholderTexture2D, Texture2D)
+
+ RID rid;
+ Size2 size = Size2(1, 1);
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_size(Size2 p_size);
+
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual RID get_rid() const override;
+ virtual bool has_alpha() const override;
+
+ virtual Ref<Image> get_image() const override;
+
+ PlaceholderTexture2D();
+ ~PlaceholderTexture2D();
+};
+
+class PlaceholderTexture3D : public Texture3D {
+ GDCLASS(PlaceholderTexture3D, Texture3D)
+
+ RID rid;
+ Vector3i size = Vector3i(1, 1, 1);
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_size(const Vector3i &p_size);
+ Vector3i get_size() const;
+ virtual Image::Format get_format() const override;
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual int get_depth() const override;
+ virtual bool has_mipmaps() const override;
+ virtual Vector<Ref<Image>> get_data() const override;
+
+ PlaceholderTexture3D();
+ ~PlaceholderTexture3D();
+};
+
+class PlaceholderTextureLayered : public TextureLayered {
+ GDCLASS(PlaceholderTextureLayered, TextureLayered)
+
+ RID rid;
+ Size2i size = Size2i(1, 1);
+ int layers = 1;
+ LayeredType layered_type = LAYERED_TYPE_2D_ARRAY;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_size(const Size2i &p_size);
+ Size2i get_size() const;
+ void set_layers(int p_layers);
+ virtual Image::Format get_format() const override;
+ virtual LayeredType get_layered_type() const override;
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual int get_layers() const override;
+ virtual bool has_mipmaps() const override;
+ virtual Ref<Image> get_layer_data(int p_layer) const override;
+
+ PlaceholderTextureLayered(LayeredType p_type);
+ ~PlaceholderTextureLayered();
+};
+
+class PlaceholderTexture2DArray : public PlaceholderTextureLayered {
+ GDCLASS(PlaceholderTexture2DArray, PlaceholderTextureLayered)
+public:
+ PlaceholderTexture2DArray() :
+ PlaceholderTextureLayered(LAYERED_TYPE_2D_ARRAY) {}
+};
+
+class PlaceholderCubemap : public PlaceholderTextureLayered {
+ GDCLASS(PlaceholderCubemap, PlaceholderTextureLayered)
+public:
+ PlaceholderCubemap() :
+ PlaceholderTextureLayered(LAYERED_TYPE_CUBEMAP) {}
+};
+
+class PlaceholderCubemapArray : public PlaceholderTextureLayered {
+ GDCLASS(PlaceholderCubemapArray, PlaceholderTextureLayered)
+public:
+ PlaceholderCubemapArray() :
+ PlaceholderTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {}
+};
+
#endif
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index 373fbb94ea..39b77568cf 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -123,82 +123,64 @@ bool Theme::_get(const StringName &p_name, Variant &r_ret) const {
void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
List<PropertyInfo> list;
- const StringName *key = nullptr;
-
// Type variations.
- while ((key = variation_map.next(key))) {
- list.push_back(PropertyInfo(Variant::STRING_NAME, String() + *key + "/base_type"));
+ for (const KeyValue<StringName, StringName> &E : variation_map) {
+ list.push_back(PropertyInfo(Variant::STRING_NAME, String() + E.key + "/base_type"));
}
- key = nullptr;
-
// Icons.
- while ((key = icon_map.next(key))) {
- const StringName *key2 = nullptr;
-
- while ((key2 = icon_map[*key].next(key2))) {
- list.push_back(PropertyInfo(Variant::OBJECT, String() + *key + "/icons/" + *key2, PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
+ for (const KeyValue<StringName, ThemeIconMap> &E : icon_map) {
+ for (const KeyValue<StringName, Ref<Texture2D>> &F : E.value) {
+ list.push_back(PropertyInfo(Variant::OBJECT, String() + E.key + "/icons/" + F.key, PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
}
}
- key = nullptr;
-
// Styles.
- while ((key = style_map.next(key))) {
- const StringName *key2 = nullptr;
-
- while ((key2 = style_map[*key].next(key2))) {
- list.push_back(PropertyInfo(Variant::OBJECT, String() + *key + "/styles/" + *key2, PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
+ for (const KeyValue<StringName, ThemeStyleMap> &E : style_map) {
+ for (const KeyValue<StringName, Ref<StyleBox>> &F : E.value) {
+ list.push_back(PropertyInfo(Variant::OBJECT, String() + E.key + "/styles/" + F.key, PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
}
}
- key = nullptr;
-
// Fonts.
- while ((key = font_map.next(key))) {
- const StringName *key2 = nullptr;
-
- while ((key2 = font_map[*key].next(key2))) {
- list.push_back(PropertyInfo(Variant::OBJECT, String() + *key + "/fonts/" + *key2, PROPERTY_HINT_RESOURCE_TYPE, "Font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
+ for (const KeyValue<StringName, ThemeFontMap> &E : font_map) {
+ for (const KeyValue<StringName, Ref<Font>> &F : E.value) {
+ list.push_back(PropertyInfo(Variant::OBJECT, String() + E.key + "/fonts/" + F.key, PROPERTY_HINT_RESOURCE_TYPE, "Font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
}
}
- key = nullptr;
-
// Font sizes.
- while ((key = font_size_map.next(key))) {
- const StringName *key2 = nullptr;
-
- while ((key2 = font_size_map[*key].next(key2))) {
- list.push_back(PropertyInfo(Variant::INT, String() + *key + "/font_sizes/" + *key2, PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
+ for (const KeyValue<StringName, ThemeFontSizeMap> &E : font_size_map) {
+ for (const KeyValue<StringName, int> &F : E.value) {
+ list.push_back(PropertyInfo(Variant::INT, String() + E.key + "/font_sizes/" + F.key, PROPERTY_HINT_RANGE, "0,256,1,or_greater,suffix:px"));
}
}
- key = nullptr;
-
// Colors.
- while ((key = color_map.next(key))) {
- const StringName *key2 = nullptr;
-
- while ((key2 = color_map[*key].next(key2))) {
- list.push_back(PropertyInfo(Variant::COLOR, String() + *key + "/colors/" + *key2));
+ for (const KeyValue<StringName, ThemeColorMap> &E : color_map) {
+ for (const KeyValue<StringName, Color> &F : E.value) {
+ list.push_back(PropertyInfo(Variant::COLOR, String() + E.key + "/colors/" + F.key));
}
}
- key = nullptr;
-
// Constants.
- while ((key = constant_map.next(key))) {
- const StringName *key2 = nullptr;
-
- while ((key2 = constant_map[*key].next(key2))) {
- list.push_back(PropertyInfo(Variant::INT, String() + *key + "/constants/" + *key2));
+ for (const KeyValue<StringName, ThemeConstantMap> &E : constant_map) {
+ for (const KeyValue<StringName, int> &F : E.value) {
+ list.push_back(PropertyInfo(Variant::INT, String() + E.key + "/constants/" + F.key));
}
}
// Sort and store properties.
list.sort();
+ String prev_type;
for (const PropertyInfo &E : list) {
+ // Add groups for types so that their names are left unchanged in the inspector.
+ String current_type = E.name.get_slice("/", 0);
+ if (prev_type != current_type) {
+ p_list->push_back(PropertyInfo(Variant::NIL, current_type, PROPERTY_HINT_NONE, current_type + "/", PROPERTY_USAGE_GROUP));
+ prev_type = current_type;
+ }
+
p_list->push_back(E);
}
}
@@ -261,6 +243,27 @@ int Theme::get_fallback_font_size() {
return fallback_font_size;
}
+bool Theme::is_valid_type_name(const String &p_name) {
+ for (int i = 0; i < p_name.length(); i++) {
+ if (!is_ascii_identifier_char(p_name[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Theme::is_valid_item_name(const String &p_name) {
+ if (p_name.is_empty()) {
+ return false;
+ }
+ for (int i = 0; i < p_name.length(); i++) {
+ if (!is_ascii_identifier_char(p_name[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
// Fallback values for theme item types, configurable per theme.
void Theme::set_default_base_scale(float p_base_scale) {
if (default_base_scale == p_base_scale) {
@@ -326,6 +329,9 @@ bool Theme::has_default_font_size() const {
// Icons.
void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref<Texture2D> &p_icon) {
+ ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name));
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
+
bool existing = false;
if (icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) {
existing = true;
@@ -358,6 +364,8 @@ bool Theme::has_icon_nocheck(const StringName &p_name, const StringName &p_theme
}
void Theme::rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name));
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
ERR_FAIL_COND_MSG(!icon_map.has(p_theme_type), "Cannot rename the icon '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
ERR_FAIL_COND_MSG(icon_map[p_theme_type].has(p_name), "Cannot rename the icon '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
ERR_FAIL_COND_MSG(!icon_map[p_theme_type].has(p_old_name), "Cannot rename the icon '" + String(p_old_name) + "' because it does not exist.");
@@ -388,18 +396,18 @@ void Theme::get_icon_list(StringName p_theme_type, List<StringName> *p_list) con
return;
}
- const StringName *key = nullptr;
-
- while ((key = icon_map[p_theme_type].next(key))) {
- p_list->push_back(*key);
+ for (const KeyValue<StringName, Ref<Texture2D>> &E : icon_map[p_theme_type]) {
+ p_list->push_back(E.key);
}
}
void Theme::add_icon_type(const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
+
if (icon_map.has(p_theme_type)) {
return;
}
- icon_map[p_theme_type] = HashMap<StringName, Ref<Texture2D>>();
+ icon_map[p_theme_type] = ThemeIconMap();
}
void Theme::remove_icon_type(const StringName &p_theme_type) {
@@ -409,9 +417,8 @@ void Theme::remove_icon_type(const StringName &p_theme_type) {
_freeze_change_propagation();
- const StringName *L = nullptr;
- while ((L = icon_map[p_theme_type].next(L))) {
- Ref<Texture2D> icon = icon_map[p_theme_type][*L];
+ for (const KeyValue<StringName, Ref<Texture2D>> &E : icon_map[p_theme_type]) {
+ Ref<Texture2D> icon = E.value;
if (icon.is_valid()) {
icon->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
@@ -425,14 +432,16 @@ void Theme::remove_icon_type(const StringName &p_theme_type) {
void Theme::get_icon_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- const StringName *key = nullptr;
- while ((key = icon_map.next(key))) {
- p_list->push_back(*key);
+ for (const KeyValue<StringName, ThemeIconMap> &E : icon_map) {
+ p_list->push_back(E.key);
}
}
// Styleboxes.
void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_type, const Ref<StyleBox> &p_style) {
+ ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name));
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
+
bool existing = false;
if (style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) {
existing = true;
@@ -465,6 +474,8 @@ bool Theme::has_stylebox_nocheck(const StringName &p_name, const StringName &p_t
}
void Theme::rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name));
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
ERR_FAIL_COND_MSG(!style_map.has(p_theme_type), "Cannot rename the stylebox '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
ERR_FAIL_COND_MSG(style_map[p_theme_type].has(p_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
ERR_FAIL_COND_MSG(!style_map[p_theme_type].has(p_old_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because it does not exist.");
@@ -495,18 +506,18 @@ void Theme::get_stylebox_list(StringName p_theme_type, List<StringName> *p_list)
return;
}
- const StringName *key = nullptr;
-
- while ((key = style_map[p_theme_type].next(key))) {
- p_list->push_back(*key);
+ for (const KeyValue<StringName, Ref<StyleBox>> &E : style_map[p_theme_type]) {
+ p_list->push_back(E.key);
}
}
void Theme::add_stylebox_type(const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
+
if (style_map.has(p_theme_type)) {
return;
}
- style_map[p_theme_type] = HashMap<StringName, Ref<StyleBox>>();
+ style_map[p_theme_type] = ThemeStyleMap();
}
void Theme::remove_stylebox_type(const StringName &p_theme_type) {
@@ -516,9 +527,8 @@ void Theme::remove_stylebox_type(const StringName &p_theme_type) {
_freeze_change_propagation();
- const StringName *L = nullptr;
- while ((L = style_map[p_theme_type].next(L))) {
- Ref<StyleBox> style = style_map[p_theme_type][*L];
+ for (const KeyValue<StringName, Ref<StyleBox>> &E : style_map[p_theme_type]) {
+ Ref<StyleBox> style = E.value;
if (style.is_valid()) {
style->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
@@ -532,14 +542,16 @@ void Theme::remove_stylebox_type(const StringName &p_theme_type) {
void Theme::get_stylebox_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- const StringName *key = nullptr;
- while ((key = style_map.next(key))) {
- p_list->push_back(*key);
+ for (const KeyValue<StringName, ThemeStyleMap> &E : style_map) {
+ p_list->push_back(E.key);
}
}
// Fonts.
void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, const Ref<Font> &p_font) {
+ ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name));
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
+
bool existing = false;
if (font_map[p_theme_type][p_name].is_valid()) {
existing = true;
@@ -574,6 +586,8 @@ bool Theme::has_font_nocheck(const StringName &p_name, const StringName &p_theme
}
void Theme::rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name));
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
ERR_FAIL_COND_MSG(!font_map.has(p_theme_type), "Cannot rename the font '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
ERR_FAIL_COND_MSG(font_map[p_theme_type].has(p_name), "Cannot rename the font '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
ERR_FAIL_COND_MSG(!font_map[p_theme_type].has(p_old_name), "Cannot rename the font '" + String(p_old_name) + "' because it does not exist.");
@@ -604,18 +618,18 @@ void Theme::get_font_list(StringName p_theme_type, List<StringName> *p_list) con
return;
}
- const StringName *key = nullptr;
-
- while ((key = font_map[p_theme_type].next(key))) {
- p_list->push_back(*key);
+ for (const KeyValue<StringName, Ref<Font>> &E : font_map[p_theme_type]) {
+ p_list->push_back(E.key);
}
}
void Theme::add_font_type(const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
+
if (font_map.has(p_theme_type)) {
return;
}
- font_map[p_theme_type] = HashMap<StringName, Ref<Font>>();
+ font_map[p_theme_type] = ThemeFontMap();
}
void Theme::remove_font_type(const StringName &p_theme_type) {
@@ -625,9 +639,8 @@ void Theme::remove_font_type(const StringName &p_theme_type) {
_freeze_change_propagation();
- const StringName *L = nullptr;
- while ((L = font_map[p_theme_type].next(L))) {
- Ref<Font> font = font_map[p_theme_type][*L];
+ for (const KeyValue<StringName, Ref<Font>> &E : font_map[p_theme_type]) {
+ Ref<Font> font = E.value;
if (font.is_valid()) {
font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
@@ -641,14 +654,16 @@ void Theme::remove_font_type(const StringName &p_theme_type) {
void Theme::get_font_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- const StringName *key = nullptr;
- while ((key = font_map.next(key))) {
- p_list->push_back(*key);
+ for (const KeyValue<StringName, ThemeFontMap> &E : font_map) {
+ p_list->push_back(E.key);
}
}
// Font sizes.
void Theme::set_font_size(const StringName &p_name, const StringName &p_theme_type, int p_font_size) {
+ ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name));
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
+
bool existing = has_font_size_nocheck(p_name, p_theme_type);
font_size_map[p_theme_type][p_name] = p_font_size;
@@ -674,6 +689,8 @@ bool Theme::has_font_size_nocheck(const StringName &p_name, const StringName &p_
}
void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name));
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
ERR_FAIL_COND_MSG(!font_size_map.has(p_theme_type), "Cannot rename the font size '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
ERR_FAIL_COND_MSG(font_size_map[p_theme_type].has(p_name), "Cannot rename the font size '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
ERR_FAIL_COND_MSG(!font_size_map[p_theme_type].has(p_old_name), "Cannot rename the font size '" + String(p_old_name) + "' because it does not exist.");
@@ -700,18 +717,18 @@ void Theme::get_font_size_list(StringName p_theme_type, List<StringName> *p_list
return;
}
- const StringName *key = nullptr;
-
- while ((key = font_size_map[p_theme_type].next(key))) {
- p_list->push_back(*key);
+ for (const KeyValue<StringName, int> &E : font_size_map[p_theme_type]) {
+ p_list->push_back(E.key);
}
}
void Theme::add_font_size_type(const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
+
if (font_size_map.has(p_theme_type)) {
return;
}
- font_size_map[p_theme_type] = HashMap<StringName, int>();
+ font_size_map[p_theme_type] = ThemeFontSizeMap();
}
void Theme::remove_font_size_type(const StringName &p_theme_type) {
@@ -725,14 +742,16 @@ void Theme::remove_font_size_type(const StringName &p_theme_type) {
void Theme::get_font_size_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- const StringName *key = nullptr;
- while ((key = font_size_map.next(key))) {
- p_list->push_back(*key);
+ for (const KeyValue<StringName, ThemeFontSizeMap> &E : font_size_map) {
+ p_list->push_back(E.key);
}
}
// Colors.
void Theme::set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color) {
+ ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name));
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
+
bool existing = has_color_nocheck(p_name, p_theme_type);
color_map[p_theme_type][p_name] = p_color;
@@ -756,6 +775,8 @@ bool Theme::has_color_nocheck(const StringName &p_name, const StringName &p_them
}
void Theme::rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name));
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
ERR_FAIL_COND_MSG(!color_map.has(p_theme_type), "Cannot rename the color '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
ERR_FAIL_COND_MSG(color_map[p_theme_type].has(p_name), "Cannot rename the color '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
ERR_FAIL_COND_MSG(!color_map[p_theme_type].has(p_old_name), "Cannot rename the color '" + String(p_old_name) + "' because it does not exist.");
@@ -782,18 +803,18 @@ void Theme::get_color_list(StringName p_theme_type, List<StringName> *p_list) co
return;
}
- const StringName *key = nullptr;
-
- while ((key = color_map[p_theme_type].next(key))) {
- p_list->push_back(*key);
+ for (const KeyValue<StringName, Color> &E : color_map[p_theme_type]) {
+ p_list->push_back(E.key);
}
}
void Theme::add_color_type(const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
+
if (color_map.has(p_theme_type)) {
return;
}
- color_map[p_theme_type] = HashMap<StringName, Color>();
+ color_map[p_theme_type] = ThemeColorMap();
}
void Theme::remove_color_type(const StringName &p_theme_type) {
@@ -807,14 +828,16 @@ void Theme::remove_color_type(const StringName &p_theme_type) {
void Theme::get_color_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- const StringName *key = nullptr;
- while ((key = color_map.next(key))) {
- p_list->push_back(*key);
+ for (const KeyValue<StringName, ThemeColorMap> &E : color_map) {
+ p_list->push_back(E.key);
}
}
// Theme constants.
void Theme::set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant) {
+ ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name));
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
+
bool existing = has_constant_nocheck(p_name, p_theme_type);
constant_map[p_theme_type][p_name] = p_constant;
@@ -838,6 +861,8 @@ bool Theme::has_constant_nocheck(const StringName &p_name, const StringName &p_t
}
void Theme::rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name));
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
ERR_FAIL_COND_MSG(!constant_map.has(p_theme_type), "Cannot rename the constant '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
ERR_FAIL_COND_MSG(constant_map[p_theme_type].has(p_name), "Cannot rename the constant '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
ERR_FAIL_COND_MSG(!constant_map[p_theme_type].has(p_old_name), "Cannot rename the constant '" + String(p_old_name) + "' because it does not exist.");
@@ -864,18 +889,18 @@ void Theme::get_constant_list(StringName p_theme_type, List<StringName> *p_list)
return;
}
- const StringName *key = nullptr;
-
- while ((key = constant_map[p_theme_type].next(key))) {
- p_list->push_back(*key);
+ for (const KeyValue<StringName, int> &E : constant_map[p_theme_type]) {
+ p_list->push_back(E.key);
}
}
void Theme::add_constant_type(const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
+
if (constant_map.has(p_theme_type)) {
return;
}
- constant_map[p_theme_type] = HashMap<StringName, int>();
+ constant_map[p_theme_type] = ThemeConstantMap();
}
void Theme::remove_constant_type(const StringName &p_theme_type) {
@@ -889,9 +914,8 @@ void Theme::remove_constant_type(const StringName &p_theme_type) {
void Theme::get_constant_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- const StringName *key = nullptr;
- while ((key = constant_map.next(key))) {
- p_list->push_back(*key);
+ for (const KeyValue<StringName, ThemeConstantMap> &E : constant_map) {
+ p_list->push_back(E.key);
}
}
@@ -1154,6 +1178,8 @@ void Theme::get_theme_item_type_list(DataType p_data_type, List<StringName> *p_l
// Theme type variations.
void Theme::set_type_variation(const StringName &p_theme_type, const StringName &p_base_type) {
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type));
+ ERR_FAIL_COND_MSG(!is_valid_type_name(p_base_type), vformat("Invalid type name: '%s'", p_base_type));
ERR_FAIL_COND_MSG(p_theme_type == StringName(), "An empty theme type cannot be marked as a variation of another type.");
ERR_FAIL_COND_MSG(ClassDB::class_exists(p_theme_type), "A type associated with a built-in class cannot be marked as a variation of another type.");
ERR_FAIL_COND_MSG(p_base_type == StringName(), "An empty theme type cannot be the base type of a variation. Use clear_type_variation() instead if you want to unmark '" + String(p_theme_type) + "' as a variation.");
@@ -1246,51 +1272,43 @@ void Theme::remove_type(const StringName &p_theme_type) {
void Theme::get_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- Set<StringName> types;
- const StringName *key = nullptr;
+ // This Set guarantees uniqueness.
+ // Because each map can have the same type defined, but for this method
+ // we only want one occurrence of each type.
+ HashSet<StringName> types;
// Icons.
- while ((key = icon_map.next(key))) {
- types.insert(*key);
+ for (const KeyValue<StringName, ThemeIconMap> &E : icon_map) {
+ types.insert(E.key);
}
- key = nullptr;
-
- // StyleBoxes.
- while ((key = style_map.next(key))) {
- types.insert(*key);
+ // Styles.
+ for (const KeyValue<StringName, ThemeStyleMap> &E : style_map) {
+ types.insert(E.key);
}
- key = nullptr;
-
// Fonts.
- while ((key = font_map.next(key))) {
- types.insert(*key);
+ for (const KeyValue<StringName, ThemeFontMap> &E : font_map) {
+ types.insert(E.key);
}
- key = nullptr;
-
// Font sizes.
- while ((key = font_size_map.next(key))) {
- types.insert(*key);
+ for (const KeyValue<StringName, ThemeFontSizeMap> &E : font_size_map) {
+ types.insert(E.key);
}
- key = nullptr;
-
// Colors.
- while ((key = color_map.next(key))) {
- types.insert(*key);
+ for (const KeyValue<StringName, ThemeColorMap> &E : color_map) {
+ types.insert(E.key);
}
- key = nullptr;
-
// Constants.
- while ((key = constant_map.next(key))) {
- types.insert(*key);
+ for (const KeyValue<StringName, ThemeConstantMap> &E : constant_map) {
+ types.insert(E.key);
}
- for (Set<StringName>::Element *E = types.front(); E; E = E->next()) {
- p_list->push_back(E->get());
+ for (const StringName &E : types) {
+ p_list->push_back(E);
}
}
@@ -1602,75 +1620,62 @@ void Theme::merge_with(const Ref<Theme> &p_other) {
// Colors.
{
- const StringName *K = nullptr;
- while ((K = p_other->color_map.next(K))) {
- const StringName *L = nullptr;
- while ((L = p_other->color_map[*K].next(L))) {
- set_color(*L, *K, p_other->color_map[*K][*L]);
+ for (const KeyValue<StringName, ThemeColorMap> &E : p_other->color_map) {
+ for (const KeyValue<StringName, Color> &F : E.value) {
+ set_color(F.key, E.key, F.value);
}
}
}
// Constants.
{
- const StringName *K = nullptr;
- while ((K = p_other->constant_map.next(K))) {
- const StringName *L = nullptr;
- while ((L = p_other->constant_map[*K].next(L))) {
- set_constant(*L, *K, p_other->constant_map[*K][*L]);
+ for (const KeyValue<StringName, ThemeConstantMap> &E : p_other->constant_map) {
+ for (const KeyValue<StringName, int> &F : E.value) {
+ set_constant(F.key, E.key, F.value);
}
}
}
// Fonts.
{
- const StringName *K = nullptr;
- while ((K = p_other->font_map.next(K))) {
- const StringName *L = nullptr;
- while ((L = p_other->font_map[*K].next(L))) {
- set_font(*L, *K, p_other->font_map[*K][*L]);
+ for (const KeyValue<StringName, ThemeFontMap> &E : p_other->font_map) {
+ for (const KeyValue<StringName, Ref<Font>> &F : E.value) {
+ set_font(F.key, E.key, F.value);
}
}
}
// Font sizes.
{
- const StringName *K = nullptr;
- while ((K = p_other->font_size_map.next(K))) {
- const StringName *L = nullptr;
- while ((L = p_other->font_size_map[*K].next(L))) {
- set_font_size(*L, *K, p_other->font_size_map[*K][*L]);
+ for (const KeyValue<StringName, ThemeFontSizeMap> &E : p_other->font_size_map) {
+ for (const KeyValue<StringName, int> &F : E.value) {
+ set_font_size(F.key, E.key, F.value);
}
}
}
// Icons.
{
- const StringName *K = nullptr;
- while ((K = p_other->icon_map.next(K))) {
- const StringName *L = nullptr;
- while ((L = p_other->icon_map[*K].next(L))) {
- set_icon(*L, *K, p_other->icon_map[*K][*L]);
+ for (const KeyValue<StringName, ThemeIconMap> &E : p_other->icon_map) {
+ for (const KeyValue<StringName, Ref<Texture2D>> &F : E.value) {
+ set_icon(F.key, E.key, F.value);
}
}
}
// Styleboxes.
{
- const StringName *K = nullptr;
- while ((K = p_other->style_map.next(K))) {
- const StringName *L = nullptr;
- while ((L = p_other->style_map[*K].next(L))) {
- set_stylebox(*L, *K, p_other->style_map[*K][*L]);
+ for (const KeyValue<StringName, ThemeStyleMap> &E : p_other->style_map) {
+ for (const KeyValue<StringName, Ref<StyleBox>> &F : E.value) {
+ set_stylebox(F.key, E.key, F.value);
}
}
}
// Type variations.
{
- const StringName *K = nullptr;
- while ((K = p_other->variation_map.next(K))) {
- set_type_variation(*K, p_other->variation_map[*K]);
+ for (const KeyValue<StringName, StringName> &E : p_other->variation_map) {
+ set_type_variation(E.key, E.value);
}
}
@@ -1680,12 +1685,10 @@ void Theme::merge_with(const Ref<Theme> &p_other) {
void Theme::clear() {
// These items need disconnecting.
{
- const StringName *K = nullptr;
- while ((K = icon_map.next(K))) {
- const StringName *L = nullptr;
- while ((L = icon_map[*K].next(L))) {
- Ref<Texture2D> icon = icon_map[*K][*L];
- if (icon.is_valid()) {
+ for (const KeyValue<StringName, ThemeIconMap> &E : icon_map) {
+ for (const KeyValue<StringName, Ref<Texture2D>> &F : E.value) {
+ if (F.value.is_valid()) {
+ Ref<Texture2D> icon = F.value;
icon->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
}
@@ -1693,12 +1696,10 @@ void Theme::clear() {
}
{
- const StringName *K = nullptr;
- while ((K = style_map.next(K))) {
- const StringName *L = nullptr;
- while ((L = style_map[*K].next(L))) {
- Ref<StyleBox> style = style_map[*K][*L];
- if (style.is_valid()) {
+ for (const KeyValue<StringName, ThemeStyleMap> &E : style_map) {
+ for (const KeyValue<StringName, Ref<StyleBox>> &F : E.value) {
+ if (F.value.is_valid()) {
+ Ref<StyleBox> style = F.value;
style->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
}
@@ -1706,12 +1707,10 @@ void Theme::clear() {
}
{
- const StringName *K = nullptr;
- while ((K = font_map.next(K))) {
- const StringName *L = nullptr;
- while ((L = font_map[*K].next(L))) {
- Ref<Font> font = font_map[*K][*L];
- if (font.is_valid()) {
+ for (const KeyValue<StringName, ThemeFontMap> &E : font_map) {
+ for (const KeyValue<StringName, Ref<Font>> &F : E.value) {
+ if (F.value.is_valid()) {
+ Ref<Font> font = F.value;
font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
}
@@ -1819,7 +1818,7 @@ void Theme::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "default_base_scale", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,or_greater"), "set_default_base_scale", "get_default_base_scale");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "default_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_default_font", "get_default_font");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "default_font_size", PROPERTY_HINT_RANGE, "0,256,1,or_greater"), "set_default_font_size", "get_default_font_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "default_font_size", PROPERTY_HINT_RANGE, "0,256,1,or_greater,suffix:px"), "set_default_font_size", "get_default_font_size");
BIND_ENUM_CONSTANT(DATA_TYPE_COLOR);
BIND_ENUM_CONSTANT(DATA_TYPE_CONSTANT);
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index 9afe05007d..87d7d2fdea 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -47,6 +47,13 @@ class Theme : public Resource {
#endif
public:
+ using ThemeIconMap = HashMap<StringName, Ref<Texture2D>>;
+ using ThemeStyleMap = HashMap<StringName, Ref<StyleBox>>;
+ using ThemeFontMap = HashMap<StringName, Ref<Font>>;
+ using ThemeFontSizeMap = HashMap<StringName, int>;
+ using ThemeColorMap = HashMap<StringName, Color>;
+ using ThemeConstantMap = HashMap<StringName, int>;
+
enum DataType {
DATA_TYPE_COLOR,
DATA_TYPE_CONSTANT,
@@ -62,12 +69,12 @@ private:
void _emit_theme_changed(bool p_notify_list_changed = false);
- HashMap<StringName, HashMap<StringName, Ref<Texture2D>>> icon_map;
- HashMap<StringName, HashMap<StringName, Ref<StyleBox>>> style_map;
- HashMap<StringName, HashMap<StringName, Ref<Font>>> font_map;
- HashMap<StringName, HashMap<StringName, int>> font_size_map;
- HashMap<StringName, HashMap<StringName, Color>> color_map;
- HashMap<StringName, HashMap<StringName, int>> constant_map;
+ HashMap<StringName, ThemeIconMap> icon_map;
+ HashMap<StringName, ThemeStyleMap> style_map;
+ HashMap<StringName, ThemeFontMap> font_map;
+ HashMap<StringName, ThemeFontSizeMap> font_size_map;
+ HashMap<StringName, ThemeColorMap> color_map;
+ HashMap<StringName, ThemeConstantMap> constant_map;
HashMap<StringName, StringName> variation_map;
HashMap<StringName, List<StringName>> variation_base_map;
@@ -137,6 +144,9 @@ public:
static Ref<Font> get_fallback_font();
static int get_fallback_font_size();
+ static bool is_valid_type_name(const String &p_name);
+ static bool is_valid_item_name(const String &p_name);
+
void set_default_base_scale(float p_base_scale);
float get_default_base_scale() const;
bool has_default_base_scale() const;
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index da9e1ef2f6..22b5ef0108 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -34,7 +34,7 @@
#include "core/io/marshalls.h"
#include "core/math/geometry_2d.h"
#include "core/templates/local_vector.h"
-
+#include "core/templates/rb_set.h"
#include "scene/2d/navigation_region_2d.h"
#include "scene/gui/control.h"
#include "scene/resources/convex_polygon_shape_2d.h"
@@ -236,6 +236,9 @@ bool TileSet::TerrainsPattern::operator<(const TerrainsPattern &p_terrains_patte
return is_valid_bit[i] < p_terrains_pattern.is_valid_bit[i];
}
}
+ if (terrain != p_terrains_pattern.terrain) {
+ return terrain < p_terrains_pattern.terrain;
+ }
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i] && bits[i] != p_terrains_pattern.bits[i]) {
return bits[i] < p_terrains_pattern.bits[i];
@@ -253,10 +256,23 @@ bool TileSet::TerrainsPattern::operator==(const TerrainsPattern &p_terrains_patt
return false;
}
}
+ if (terrain != p_terrains_pattern.terrain) {
+ return false;
+ }
return true;
}
-void TileSet::TerrainsPattern::set_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain) {
+void TileSet::TerrainsPattern::set_terrain(int p_terrain) {
+ ERR_FAIL_COND(p_terrain < -1);
+
+ terrain = p_terrain;
+}
+
+int TileSet::TerrainsPattern::get_terrain() const {
+ return terrain;
+}
+
+void TileSet::TerrainsPattern::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain) {
ERR_FAIL_COND(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX);
ERR_FAIL_COND(!is_valid_bit[p_peering_bit]);
ERR_FAIL_COND(p_terrain < -1);
@@ -271,25 +287,27 @@ void TileSet::TerrainsPattern::set_terrain(TileSet::CellNeighbor p_peering_bit,
bits[p_peering_bit] = p_terrain;
}
-int TileSet::TerrainsPattern::get_terrain(TileSet::CellNeighbor p_peering_bit) const {
+int TileSet::TerrainsPattern::get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
ERR_FAIL_COND_V(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX, -1);
ERR_FAIL_COND_V(!is_valid_bit[p_peering_bit], -1);
return bits[p_peering_bit];
}
-void TileSet::TerrainsPattern::set_terrains_from_array(Array p_terrains) {
- int in_array_index = 0;
+void TileSet::TerrainsPattern::from_array(Array p_terrains) {
+ set_terrain(p_terrains[0]);
+ int in_array_index = 1;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i]) {
- ERR_FAIL_COND(in_array_index >= p_terrains.size());
- set_terrain(TileSet::CellNeighbor(i), p_terrains[in_array_index]);
+ ERR_FAIL_INDEX(in_array_index, p_terrains.size());
+ set_terrain_peering_bit(TileSet::CellNeighbor(i), p_terrains[in_array_index]);
in_array_index++;
}
}
}
-Array TileSet::TerrainsPattern::get_terrains_as_array() const {
+Array TileSet::TerrainsPattern::as_array() const {
Array output;
+ output.push_back(get_terrain());
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i]) {
output.push_back(bits[i]);
@@ -297,10 +315,11 @@ Array TileSet::TerrainsPattern::get_terrains_as_array() const {
}
return output;
}
+
TileSet::TerrainsPattern::TerrainsPattern(const TileSet *p_tile_set, int p_terrain_set) {
ERR_FAIL_COND(p_terrain_set < 0);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
- is_valid_bit[i] = (p_tile_set->is_valid_peering_bit_terrain(p_terrain_set, TileSet::CellNeighbor(i)));
+ is_valid_bit[i] = (p_tile_set->is_valid_terrain_peering_bit(p_terrain_set, TileSet::CellNeighbor(i)));
bits[i] = -1;
}
valid = true;
@@ -410,11 +429,16 @@ void TileSet::_update_terrains_cache() {
TileSet::TerrainsPattern terrains_pattern = tile_data->get_terrains_pattern();
+ // Main terrain.
+ if (terrains_pattern.get_terrain() >= 0) {
+ per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
+ }
+
// Terrain bits.
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
CellNeighbor bit = CellNeighbor(i);
- if (is_valid_peering_bit_terrain(terrain_set, bit)) {
- int terrain = terrains_pattern.get_terrain(bit);
+ if (is_valid_terrain_peering_bit(terrain_set, bit)) {
+ int terrain = terrains_pattern.get_terrain_peering_bit(bit);
if (terrain >= 0) {
per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
}
@@ -822,7 +846,7 @@ Color TileSet::get_terrain_color(int p_terrain_set, int p_terrain_index) const {
return terrain_sets[p_terrain_set].terrains[p_terrain_index].color;
}
-bool TileSet::is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const {
+bool TileSet::is_valid_terrain_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const {
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
@@ -905,13 +929,13 @@ bool TileSet::is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode,
return false;
}
-bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const {
+bool TileSet::is_valid_terrain_peering_bit(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const {
if (p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count()) {
return false;
}
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set);
- return is_valid_peering_bit_for_mode(terrain_mode, p_peering_bit);
+ return is_valid_terrain_peering_bit_for_mode(terrain_mode, p_peering_bit);
}
// Navigation
@@ -1345,19 +1369,19 @@ int TileSet::get_patterns_count() {
return patterns.size();
}
-Set<TileSet::TerrainsPattern> TileSet::get_terrains_pattern_set(int p_terrain_set) {
- ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), Set<TileSet::TerrainsPattern>());
+RBSet<TileSet::TerrainsPattern> TileSet::get_terrains_pattern_set(int p_terrain_set) {
+ ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), RBSet<TileSet::TerrainsPattern>());
_update_terrains_cache();
- Set<TileSet::TerrainsPattern> output;
- for (KeyValue<TileSet::TerrainsPattern, Set<TileMapCell>> kv : per_terrain_pattern_tiles[p_terrain_set]) {
+ RBSet<TileSet::TerrainsPattern> output;
+ for (KeyValue<TileSet::TerrainsPattern, RBSet<TileMapCell>> kv : per_terrain_pattern_tiles[p_terrain_set]) {
output.insert(kv.key);
}
return output;
}
-Set<TileMapCell> TileSet::get_tiles_for_terrains_pattern(int p_terrain_set, TerrainsPattern p_terrain_tile_pattern) {
- ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), Set<TileMapCell>());
+RBSet<TileMapCell> TileSet::get_tiles_for_terrains_pattern(int p_terrain_set, TerrainsPattern p_terrain_tile_pattern) {
+ ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), RBSet<TileMapCell>());
_update_terrains_cache();
return per_terrain_pattern_tiles[p_terrain_set][p_terrain_tile_pattern];
}
@@ -1368,13 +1392,13 @@ TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, Ti
// Count the sum of probabilities.
double sum = 0.0;
- Set<TileMapCell> set = per_terrain_pattern_tiles[p_terrain_set][p_terrain_tile_pattern];
- for (Set<TileMapCell>::Element *E = set.front(); E; E = E->next()) {
- if (E->get().source_id >= 0) {
- Ref<TileSetSource> source = sources[E->get().source_id];
+ RBSet<TileMapCell> set = per_terrain_pattern_tiles[p_terrain_set][p_terrain_tile_pattern];
+ for (const TileMapCell &E : set) {
+ if (E.source_id >= 0) {
+ Ref<TileSetSource> source = sources[E.source_id];
Ref<TileSetAtlasSource> atlas_source = source;
if (atlas_source.is_valid()) {
- TileData *tile_data = atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile);
+ TileData *tile_data = atlas_source->get_tile_data(E.get_atlas_coords(), E.alternative_tile);
sum += tile_data->get_probability();
} else {
sum += 1.0;
@@ -1389,13 +1413,13 @@ TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, Ti
double picked = Math::random(0.0, sum);
// Pick the tile.
- for (Set<TileMapCell>::Element *E = set.front(); E; E = E->next()) {
- if (E->get().source_id >= 0) {
- Ref<TileSetSource> source = sources[E->get().source_id];
+ for (const TileMapCell &E : set) {
+ if (E.source_id >= 0) {
+ Ref<TileSetSource> source = sources[E.source_id];
Ref<TileSetAtlasSource> atlas_source = source;
if (atlas_source.is_valid()) {
- TileData *tile_data = atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile);
+ TileData *tile_data = atlas_source->get_tile_data(E.get_atlas_coords(), E.alternative_tile);
count += tile_data->get_probability();
} else {
count += 1.0;
@@ -1405,7 +1429,7 @@ TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, Ti
}
if (count >= picked) {
- return E->get();
+ return E;
}
}
@@ -1494,26 +1518,48 @@ void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform
}
}
-Vector<Point2> TileSet::get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::get_terrain_polygon(int p_terrain_set) {
+ if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
+ return _get_square_terrain_polygon(tile_size);
+ } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ return _get_isometric_terrain_polygon(tile_size);
+ } else {
+ float overlap = 0.0;
+ switch (tile_shape) {
+ case TileSet::TILE_SHAPE_HEXAGON:
+ overlap = 0.25;
+ break;
+ case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
+ overlap = 0.0;
+ break;
+ default:
+ break;
+ }
+ return _get_half_offset_terrain_polygon(tile_size, overlap, tile_offset_axis);
+ }
+ return Vector<Point2>();
+}
+
+Vector<Point2> TileSet::get_terrain_peering_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit) {
ERR_FAIL_COND_V(p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count(), Vector<Point2>());
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set);
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- return _get_square_corner_or_side_terrain_bit_polygon(tile_size, p_bit);
+ return _get_square_corner_or_side_terrain_peering_bit_polygon(tile_size, p_bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- return _get_square_corner_terrain_bit_polygon(tile_size, p_bit);
+ return _get_square_corner_terrain_peering_bit_polygon(tile_size, p_bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- return _get_square_side_terrain_bit_polygon(tile_size, p_bit);
+ return _get_square_side_terrain_peering_bit_polygon(tile_size, p_bit);
}
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- return _get_isometric_corner_or_side_terrain_bit_polygon(tile_size, p_bit);
+ return _get_isometric_corner_or_side_terrain_peering_bit_polygon(tile_size, p_bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- return _get_isometric_corner_terrain_bit_polygon(tile_size, p_bit);
+ return _get_isometric_corner_terrain_peering_bit_polygon(tile_size, p_bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- return _get_isometric_side_terrain_bit_polygon(tile_size, p_bit);
+ return _get_isometric_side_terrain_peering_bit_polygon(tile_size, p_bit);
}
} else {
float overlap = 0.0;
@@ -1528,11 +1574,11 @@ Vector<Point2> TileSet::get_terrain_bit_polygon(int p_terrain_set, TileSet::Cell
break;
}
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- return _get_half_offset_corner_or_side_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis);
+ return _get_half_offset_corner_or_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- return _get_half_offset_corner_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis);
+ return _get_half_offset_corner_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- return _get_half_offset_side_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis);
+ return _get_half_offset_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
}
}
}
@@ -1544,30 +1590,68 @@ void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform,
if (terrain_bits_meshes_dirty) {
// Recompute the meshes.
- terrain_bits_meshes.clear();
+ terrain_peering_bits_meshes.clear();
for (int terrain_mode_index = 0; terrain_mode_index < 3; terrain_mode_index++) {
TerrainMode terrain_mode = TerrainMode(terrain_mode_index);
+
+ // Center terrain
+ Vector<Vector2> polygon;
+ if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
+ polygon = _get_square_terrain_polygon(tile_size);
+ } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ polygon = _get_isometric_terrain_polygon(tile_size);
+ } else {
+ float overlap = 0.0;
+ switch (tile_shape) {
+ case TileSet::TILE_SHAPE_HEXAGON:
+ overlap = 0.25;
+ break;
+ case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
+ overlap = 0.0;
+ break;
+ default:
+ break;
+ }
+ polygon = _get_half_offset_terrain_polygon(tile_size, overlap, tile_offset_axis);
+ }
+ {
+ Ref<ArrayMesh> mesh;
+ mesh.instantiate();
+ Vector<Vector2> uvs;
+ uvs.resize(polygon.size());
+ Vector<Color> colors;
+ colors.resize(polygon.size());
+ colors.fill(Color(1.0, 1.0, 1.0, 1.0));
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[Mesh::ARRAY_VERTEX] = polygon;
+ a[Mesh::ARRAY_TEX_UV] = uvs;
+ a[Mesh::ARRAY_COLOR] = colors;
+ a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
+ terrain_meshes[terrain_mode] = mesh;
+ }
+ // Peering bits
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
CellNeighbor bit = CellNeighbor(i);
- if (is_valid_peering_bit_for_mode(terrain_mode, bit)) {
- Vector<Vector2> polygon;
+ if (is_valid_terrain_peering_bit_for_mode(terrain_mode, bit)) {
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- polygon = _get_square_corner_or_side_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_square_corner_or_side_terrain_peering_bit_polygon(tile_size, bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- polygon = _get_square_corner_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_square_corner_terrain_peering_bit_polygon(tile_size, bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- polygon = _get_square_side_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_square_side_terrain_peering_bit_polygon(tile_size, bit);
}
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- polygon = _get_isometric_corner_or_side_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_isometric_corner_or_side_terrain_peering_bit_polygon(tile_size, bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- polygon = _get_isometric_corner_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_isometric_corner_terrain_peering_bit_polygon(tile_size, bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- polygon = _get_isometric_side_terrain_bit_polygon(tile_size, bit);
+ polygon = _get_isometric_side_terrain_peering_bit_polygon(tile_size, bit);
}
} else {
float overlap = 0.0;
@@ -1582,29 +1666,30 @@ void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform,
break;
}
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
- polygon = _get_half_offset_corner_or_side_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis);
+ polygon = _get_half_offset_corner_or_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
- polygon = _get_half_offset_corner_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis);
+ polygon = _get_half_offset_corner_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
- polygon = _get_half_offset_side_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis);
+ polygon = _get_half_offset_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
}
}
-
- Ref<ArrayMesh> mesh;
- mesh.instantiate();
- Vector<Vector2> uvs;
- uvs.resize(polygon.size());
- Vector<Color> colors;
- colors.resize(polygon.size());
- colors.fill(Color(1.0, 1.0, 1.0, 1.0));
- Array a;
- a.resize(Mesh::ARRAY_MAX);
- a[Mesh::ARRAY_VERTEX] = polygon;
- a[Mesh::ARRAY_TEX_UV] = uvs;
- a[Mesh::ARRAY_COLOR] = colors;
- a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
- mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
- terrain_bits_meshes[terrain_mode][bit] = mesh;
+ {
+ Ref<ArrayMesh> mesh;
+ mesh.instantiate();
+ Vector<Vector2> uvs;
+ uvs.resize(polygon.size());
+ Vector<Color> colors;
+ colors.resize(polygon.size());
+ colors.fill(Color(1.0, 1.0, 1.0, 1.0));
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[Mesh::ARRAY_VERTEX] = polygon;
+ a[Mesh::ARRAY_TEX_UV] = uvs;
+ a[Mesh::ARRAY_COLOR] = colors;
+ a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
+ terrain_peering_bits_meshes[terrain_mode][bit] = mesh;
+ }
}
}
}
@@ -1618,14 +1703,21 @@ void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform,
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(terrain_set);
RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
+ int terrain_id = p_tile_data->get_terrain();
+ if (terrain_id >= 0) {
+ Color color = get_terrain_color(terrain_set, terrain_id);
+ color.a = TERRAIN_ALPHA;
+ p_canvas_item->draw_mesh(terrain_meshes[terrain_mode], Ref<Texture2D>(), Transform2D(), color);
+ }
+
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
CellNeighbor bit = CellNeighbor(i);
- if (is_valid_peering_bit_terrain(terrain_set, bit)) {
- int terrain_id = p_tile_data->get_peering_bit_terrain(bit);
+ if (is_valid_terrain_peering_bit(terrain_set, bit)) {
+ terrain_id = p_tile_data->get_terrain_peering_bit(bit);
if (terrain_id >= 0) {
Color color = get_terrain_color(terrain_set, terrain_id);
color.a = TERRAIN_ALPHA;
- p_canvas_item->draw_mesh(terrain_bits_meshes[terrain_mode][bit], Ref<Texture2D>(), Transform2D(), color);
+ p_canvas_item->draw_mesh(terrain_peering_bits_meshes[terrain_mode][bit], Ref<Texture2D>(), Transform2D(), color);
}
}
}
@@ -1670,13 +1762,16 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) {
for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) {
bit_counts[terrain] = 0;
}
+ if (tile_data->get_terrain() >= 0) {
+ bit_counts[tile_data->get_terrain()] += 10;
+ }
for (int terrain_bit = 0; terrain_bit < TileSet::CELL_NEIGHBOR_MAX; terrain_bit++) {
TileSet::CellNeighbor cell_neighbor = TileSet::CellNeighbor(terrain_bit);
- if (is_valid_peering_bit_terrain(terrain_set, cell_neighbor)) {
- int terrain = tile_data->get_peering_bit_terrain(cell_neighbor);
+ if (is_valid_terrain_peering_bit(terrain_set, cell_neighbor)) {
+ int terrain = tile_data->get_terrain_peering_bit(cell_neighbor);
if (terrain >= 0) {
if (terrain >= (int)bit_counts.size()) {
- WARN_PRINT(vformat("Invalid peering bit terrain: %d", terrain));
+ WARN_PRINT(vformat("Invalid terrain peering bit: %d", terrain));
} else {
bit_counts[terrain] += 1;
}
@@ -1706,19 +1801,16 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) {
if (counts[terrain_set][terrain].count > 0) {
// Get the best tile.
Ref<Texture2D> texture = counts[terrain_set][terrain].texture;
- Rect2 region = counts[terrain_set][terrain].region;
+ Rect2i region = counts[terrain_set][terrain].region;
image->create(region.size.x, region.size.y, false, Image::FORMAT_RGBA8);
- image->blit_rect(texture->get_image(), region, Point2());
+ image->blit_rect(texture->get_image(), region, Point2i());
image->resize(p_size.x, p_size.y, Image::INTERPOLATE_NEAREST);
} else {
image->create(1, 1, false, Image::FORMAT_RGBA8);
image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain));
}
- Ref<ImageTexture> icon;
- icon.instantiate();
- icon->create_from_image(image);
+ Ref<ImageTexture> icon = ImageTexture::create_from_image(image);
icon->set_size_override(p_size);
-
output.write[terrain_set].write[terrain] = icon;
}
}
@@ -1730,7 +1822,17 @@ void TileSet::_source_changed() {
emit_changed();
}
-Vector<Point2> TileSet::_get_square_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_square_terrain_polygon(Vector2i p_size) {
+ Rect2 rect(-Vector2(p_size) / 6.0, Vector2(p_size) / 3.0);
+ return {
+ rect.position,
+ Vector2(rect.get_end().x, rect.position.y),
+ rect.get_end(),
+ Vector2(rect.position.x, rect.get_end().y)
+ };
+}
+
+Vector<Point2> TileSet::_get_square_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Rect2 bit_rect;
bit_rect.size = Vector2(p_size) / 3;
switch (p_bit) {
@@ -1773,7 +1875,7 @@ Vector<Point2> TileSet::_get_square_corner_or_side_terrain_bit_polygon(Vector2i
return polygon;
}
-Vector<Point2> TileSet::_get_square_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_square_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1815,7 +1917,7 @@ Vector<Point2> TileSet::_get_square_corner_terrain_bit_polygon(Vector2i p_size,
return polygon;
}
-Vector<Point2> TileSet::_get_square_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_square_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1849,7 +1951,17 @@ Vector<Point2> TileSet::_get_square_side_terrain_bit_polygon(Vector2i p_size, Ti
return polygon;
}
-Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_isometric_terrain_polygon(Vector2i p_size) {
+ Vector2 unit = Vector2(p_size) / 6.0;
+ return {
+ Vector2(1, 0) * unit,
+ Vector2(0, 1) * unit,
+ Vector2(-1, 0) * unit,
+ Vector2(0, -1) * unit,
+ };
+}
+
+Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1907,7 +2019,7 @@ Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_bit_polygon(Vector
return polygon;
}
-Vector<Point2> TileSet::_get_isometric_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_isometric_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1949,7 +2061,7 @@ Vector<Point2> TileSet::_get_isometric_corner_terrain_bit_polygon(Vector2i p_siz
return polygon;
}
-Vector<Point2> TileSet::_get_isometric_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
+Vector<Point2> TileSet::_get_isometric_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
Vector2 unit = Vector2(p_size) / 6.0;
Vector<Vector2> polygon;
switch (p_bit) {
@@ -1983,7 +2095,30 @@ Vector<Point2> TileSet::_get_isometric_side_terrain_bit_polygon(Vector2i p_size,
return polygon;
}
-Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+Vector<Point2> TileSet::_get_half_offset_terrain_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+ Vector2 unit = Vector2(p_size) / 6.0;
+ if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ return {
+ Vector2(1, 1.0 - p_overlap * 2.0) * unit,
+ Vector2(0, 1) * unit,
+ Vector2(-1, 1.0 - p_overlap * 2.0) * unit,
+ Vector2(-1, -1.0 + p_overlap * 2.0) * unit,
+ Vector2(0, -1) * unit,
+ Vector2(1, -1.0 + p_overlap * 2.0) * unit,
+ };
+ } else {
+ return {
+ Vector2(1, 0) * unit,
+ Vector2(1.0 - p_overlap * 2.0, -1) * unit,
+ Vector2(-1.0 + p_overlap * 2.0, -1) * unit,
+ Vector2(-1, 0) * unit,
+ Vector2(-1.0 + p_overlap * 2.0, 1) * unit,
+ Vector2(1.0 - p_overlap * 2.0, 1) * unit,
+ };
+ }
+}
+
+Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
Vector<Vector2> point_list = {
Vector2(3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0),
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
@@ -2006,12 +2141,11 @@ Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vect
};
Vector2 unit = Vector2(p_size) / 6.0;
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = point_list[i] * unit;
- }
-
Vector<Vector2> polygon;
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = point_list[i] * unit;
+ }
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
polygon.push_back(point_list[17]);
@@ -2071,10 +2205,8 @@ Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vect
break;
}
} else {
- if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
- }
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
}
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
@@ -2144,7 +2276,7 @@ Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vect
return polygon;
}
-Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+Vector<Point2> TileSet::_get_half_offset_corner_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
Vector<Vector2> point_list = {
Vector2(3, 0),
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
@@ -2161,12 +2293,11 @@ Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_s
};
Vector2 unit = Vector2(p_size) / 6.0;
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = point_list[i] * unit;
- }
-
Vector<Vector2> polygon;
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = point_list[i] * unit;
+ }
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
polygon.push_back(point_list[0]);
@@ -2202,10 +2333,8 @@ Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_s
break;
}
} else {
- if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
- }
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
}
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
@@ -2251,7 +2380,7 @@ Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_s
return polygon;
}
-Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+Vector<Point2> TileSet::_get_half_offset_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
Vector<Vector2> point_list = {
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
Vector2(0, 3),
@@ -2262,12 +2391,11 @@ Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_siz
};
Vector2 unit = Vector2(p_size) / 6.0;
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = point_list[i] * unit;
- }
-
Vector<Vector2> polygon;
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = point_list[i] * unit;
+ }
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
polygon.push_back(point_list[5]);
@@ -2297,10 +2425,8 @@ Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_siz
break;
}
} else {
- if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- for (int i = 0; i < point_list.size(); i++) {
- point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
- }
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
}
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
@@ -2391,7 +2517,7 @@ void TileSet::_compatibility_conversion() {
value_array.push_back(alternative_tile);
if (!compatibility_tilemap_mapping.has(E.key)) {
- compatibility_tilemap_mapping[E.key] = Map<Array, Array>();
+ compatibility_tilemap_mapping[E.key] = RBMap<Array, Array>();
}
compatibility_tilemap_mapping[E.key][key_array] = value_array;
compatibility_tilemap_mapping_tile_modes[E.key] = COMPATIBILITY_TILE_MODE_SINGLE_TILE;
@@ -2483,7 +2609,7 @@ void TileSet::_compatibility_conversion() {
value_array.push_back(alternative_tile);
if (!compatibility_tilemap_mapping.has(E.key)) {
- compatibility_tilemap_mapping[E.key] = Map<Array, Array>();
+ compatibility_tilemap_mapping[E.key] = RBMap<Array, Array>();
}
compatibility_tilemap_mapping[E.key][key_array] = value_array;
compatibility_tilemap_mapping_tile_modes[E.key] = COMPATIBILITY_TILE_MODE_ATLAS_TILE;
@@ -2571,7 +2697,7 @@ void TileSet::_compatibility_conversion() {
for (const KeyValue<int, CompatibilityTileData *> &E : compatibility_data) {
memdelete(E.value);
}
- compatibility_data = Map<int, CompatibilityTileData *>();
+ compatibility_data = HashMap<int, CompatibilityTileData *>();
}
Array TileSet::compatibility_tilemap_map(int p_tile_id, Vector2i p_coords, bool p_flip_h, bool p_flip_v, bool p_transpose) {
@@ -2622,12 +2748,12 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
// Get or create the compatibility object
CompatibilityTileData *ctd;
- Map<int, CompatibilityTileData *>::Element *E = compatibility_data.find(id);
+ HashMap<int, CompatibilityTileData *>::Iterator E = compatibility_data.find(id);
if (!E) {
ctd = memnew(CompatibilityTileData);
compatibility_data.insert(id, ctd);
} else {
- ctd = E->get();
+ ctd = E->value;
}
if (components.size() < 2) {
@@ -3099,7 +3225,7 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
// Terrains.
p_list->push_back(PropertyInfo(Variant::NIL, "Terrains", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
for (int terrain_set_index = 0; terrain_set_index < terrain_sets.size(); terrain_set_index++) {
- p_list->push_back(PropertyInfo(Variant::INT, vformat("terrain_set_%d/mode", terrain_set_index), PROPERTY_HINT_ENUM, "Match corners and sides,Match corners,Match sides"));
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("terrain_set_%d/mode", terrain_set_index), PROPERTY_HINT_ENUM, "Match Corners and Sides,Match Corners,Match Sides"));
p_list->push_back(PropertyInfo(Variant::NIL, vformat("terrain_set_%d/terrains", terrain_set_index), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, vformat("terrain_set_%d/terrain_", terrain_set_index)));
for (int terrain_index = 0; terrain_index < terrain_sets[terrain_set_index].terrains.size(); terrain_index++) {
p_list->push_back(PropertyInfo(Variant::STRING, vformat("terrain_set_%d/terrain_%d/name", terrain_set_index, terrain_index)));
@@ -3175,7 +3301,7 @@ void TileSet::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_shape", PROPERTY_HINT_ENUM, "Square,Isometric,Half-Offset Square,Hexagon"), "set_tile_shape", "get_tile_shape");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_layout", PROPERTY_HINT_ENUM, "Stacked,Stacked Offset,Stairs Right,Stairs Down,Diamond Right,Diamond Down"), "set_tile_layout", "get_tile_layout");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_offset_axis", PROPERTY_HINT_ENUM, "Horizontal Offset,Vertical Offset"), "set_tile_offset_axis", "get_tile_offset_axis");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "tile_size"), "set_tile_size", "get_tile_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "tile_size", PROPERTY_HINT_NONE, "suffix:px"), "set_tile_size", "get_tile_size");
// Rendering.
ClassDB::bind_method(D_METHOD("set_uv_clipping", "uv_clipping"), &TileSet::set_uv_clipping);
@@ -3264,16 +3390,10 @@ void TileSet::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uv_clipping"), "set_uv_clipping", "is_uv_clipping");
ADD_ARRAY("occlusion_layers", "occlusion_layer_");
- ADD_GROUP("Physics", "");
+ ADD_GROUP("", "");
ADD_ARRAY("physics_layers", "physics_layer_");
-
- ADD_GROUP("Terrains", "");
ADD_ARRAY("terrain_sets", "terrain_set_");
-
- ADD_GROUP("Navigation", "");
ADD_ARRAY("navigation_layers", "navigation_layer_");
-
- ADD_GROUP("Custom Data", "");
ADD_ARRAY("custom_data_layers", "custom_data_layer_");
// -- Enum binding --
@@ -3807,7 +3927,7 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
tile_property_list.push_back(property_info);
// animation_frames_count.
- tile_property_list.push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NETWORK));
+ tile_property_list.push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
// animation_frame_*.
bool store_durations = tiles[E_tile.key].animation_frames_durations.size() >= 2;
@@ -4279,9 +4399,9 @@ void TileSetAtlasSource::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_use_texture_padding"), &TileSetAtlasSource::get_use_texture_padding);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NO_EDITOR), "set_texture", "get_texture");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_margins", "get_margins");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_separation", "get_separation");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_texture_region_size", "get_texture_region_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NO_EDITOR), "set_margins", "get_margins");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NO_EDITOR), "set_separation", "get_separation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NO_EDITOR), "set_texture_region_size", "get_texture_region_size");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_texture_padding", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_texture_padding", "get_use_texture_padding");
// Base tiles
@@ -4471,7 +4591,7 @@ void TileSetAtlasSource::_update_padded_texture() {
if (!padded_texture.is_valid()) {
padded_texture.instantiate();
}
- padded_texture->create_from_image(image);
+ padded_texture->set_image(image);
emit_changed();
}
@@ -4801,6 +4921,10 @@ void TileData::move_terrain(int p_terrain_set, int p_from_index, int p_to_pos) {
void TileData::remove_terrain(int p_terrain_set, int p_index) {
if (terrain_set == p_terrain_set) {
+ if (terrain == p_index) {
+ terrain = -1;
+ }
+
for (int i = 0; i < 16; i++) {
if (terrain_peering_bits[i] == p_index) {
terrain_peering_bits[i] = -1;
@@ -4935,11 +5059,11 @@ Vector2i TileData::get_texture_offset() const {
return tex_offset;
}
-void TileData::set_material(Ref<ShaderMaterial> p_material) {
+void TileData::set_material(Ref<Material> p_material) {
material = p_material;
emit_signal(SNAME("changed"));
}
-Ref<ShaderMaterial> TileData::get_material() const {
+Ref<Material> TileData::get_material() const {
return material;
}
@@ -5120,36 +5244,51 @@ int TileData::get_terrain_set() const {
return terrain_set;
}
-void TileData::set_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) {
+void TileData::set_terrain(int p_terrain) {
+ ERR_FAIL_COND(terrain_set < 0);
+ ERR_FAIL_COND(p_terrain < -1);
+ if (tile_set) {
+ ERR_FAIL_COND(p_terrain >= tile_set->get_terrains_count(terrain_set));
+ }
+ terrain = p_terrain;
+ emit_signal(SNAME("changed"));
+}
+
+int TileData::get_terrain() const {
+ return terrain;
+}
+
+void TileData::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) {
ERR_FAIL_INDEX(p_peering_bit, TileSet::CellNeighbor::CELL_NEIGHBOR_MAX);
ERR_FAIL_COND(terrain_set < 0);
ERR_FAIL_COND(p_terrain_index < -1);
if (tile_set) {
ERR_FAIL_COND(p_terrain_index >= tile_set->get_terrains_count(terrain_set));
- ERR_FAIL_COND(!is_valid_peering_bit_terrain(p_peering_bit));
+ ERR_FAIL_COND(!is_valid_terrain_peering_bit(p_peering_bit));
}
terrain_peering_bits[p_peering_bit] = p_terrain_index;
emit_signal(SNAME("changed"));
}
-int TileData::get_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const {
- ERR_FAIL_COND_V(!is_valid_peering_bit_terrain(p_peering_bit), -1);
+int TileData::get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
+ ERR_FAIL_COND_V(!is_valid_terrain_peering_bit(p_peering_bit), -1);
return terrain_peering_bits[p_peering_bit];
}
-bool TileData::is_valid_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const {
+bool TileData::is_valid_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
ERR_FAIL_COND_V(!tile_set, false);
- return tile_set->is_valid_peering_bit_terrain(terrain_set, p_peering_bit);
+ return tile_set->is_valid_terrain_peering_bit(terrain_set, p_peering_bit);
}
TileSet::TerrainsPattern TileData::get_terrains_pattern() const {
ERR_FAIL_COND_V(!tile_set, TileSet::TerrainsPattern());
TileSet::TerrainsPattern output(tile_set, terrain_set);
+ output.set_terrain(terrain);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
- if (tile_set->is_valid_peering_bit_terrain(terrain_set, TileSet::CellNeighbor(i))) {
- output.set_terrain(TileSet::CellNeighbor(i), get_peering_bit_terrain(TileSet::CellNeighbor(i)));
+ if (tile_set->is_valid_terrain_peering_bit(terrain_set, TileSet::CellNeighbor(i))) {
+ output.set_terrain_peering_bit(TileSet::CellNeighbor(i), get_terrain_peering_bit(TileSet::CellNeighbor(i)));
}
}
return output;
@@ -5299,7 +5438,7 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) {
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (components[1] == TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]) {
- set_peering_bit_terrain(bit, p_value);
+ set_terrain_peering_bit(bit, p_value);
return true;
}
}
@@ -5461,9 +5600,9 @@ void TileData::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::NIL, "Terrains", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- if (is_valid_peering_bit_terrain(bit)) {
+ if (is_valid_terrain_peering_bit(bit)) {
property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]));
- if (get_peering_bit_terrain(bit) == -1) {
+ if (get_terrain_peering_bit(bit) == -1) {
property_info.usage ^= PROPERTY_USAGE_STORAGE;
}
p_list->push_back(property_info);
@@ -5537,8 +5676,10 @@ void TileData::_bind_methods() {
// Terrain
ClassDB::bind_method(D_METHOD("set_terrain_set", "terrain_set"), &TileData::set_terrain_set);
ClassDB::bind_method(D_METHOD("get_terrain_set"), &TileData::get_terrain_set);
- ClassDB::bind_method(D_METHOD("set_peering_bit_terrain", "peering_bit", "terrain"), &TileData::set_peering_bit_terrain);
- ClassDB::bind_method(D_METHOD("get_peering_bit_terrain", "peering_bit"), &TileData::get_peering_bit_terrain);
+ ClassDB::bind_method(D_METHOD("set_terrain", "terrain"), &TileData::set_terrain);
+ ClassDB::bind_method(D_METHOD("get_terrain"), &TileData::get_terrain);
+ ClassDB::bind_method(D_METHOD("set_terrain_peering_bit", "peering_bit", "terrain"), &TileData::set_terrain_peering_bit);
+ ClassDB::bind_method(D_METHOD("get_terrain_peering_bit", "peering_bit"), &TileData::get_terrain_peering_bit);
// Navigation
ClassDB::bind_method(D_METHOD("set_navigation_polygon", "layer_id", "navigation_polygon"), &TileData::set_navigation_polygon);
@@ -5558,14 +5699,15 @@ void TileData::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "get_flip_h");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "get_flip_v");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transpose"), "set_transpose", "get_transpose");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_offset"), "set_texture_offset", "get_texture_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_texture_offset", "get_texture_offset");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"), "set_material", "get_material");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial,ShaderMaterial"), "set_material", "get_material");
ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index"), "set_z_index", "get_z_index");
ADD_PROPERTY(PropertyInfo(Variant::INT, "y_sort_origin"), "set_y_sort_origin", "get_y_sort_origin");
ADD_GROUP("Terrains", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "terrain_set"), "set_terrain_set", "get_terrain_set");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "terrain"), "set_terrain", "get_terrain");
ADD_GROUP("Miscellaneous", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "probability"), "set_probability", "get_probability");
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 95de46c9ab..7368d2bd87 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -34,6 +34,7 @@
#include "core/io/resource.h"
#include "core/object/object.h"
#include "core/templates/local_vector.h"
+#include "core/templates/rb_set.h"
#include "scene/2d/light_occluder_2d.h"
#include "scene/2d/navigation_region_2d.h"
#include "scene/main/canvas_item.h"
@@ -69,6 +70,11 @@ union TileMapCell {
};
uint64_t _u64t;
+
+ static uint32_t hash(const TileMapCell &p_hash) {
+ return hash_one_uint64(p_hash._u64t);
+ }
+
TileMapCell(int p_source_id = -1, Vector2i p_atlas_coords = Vector2i(-1, -1), int p_alternative_tile = -1) { // default are INVALID_SOURCE, INVALID_ATLAS_COORDS, INVALID_TILE_ALTERNATIVE
source_id = p_source_id;
set_atlas_coords(p_atlas_coords);
@@ -103,13 +109,16 @@ union TileMapCell {
bool operator!=(const TileMapCell &p_other) const {
return !(source_id == p_other.source_id && coord_x == p_other.coord_x && coord_y == p_other.coord_y && alternative_tile == p_other.alternative_tile);
}
+ bool operator==(const TileMapCell &p_other) const {
+ return source_id == p_other.source_id && coord_x == p_other.coord_x && coord_y == p_other.coord_y && alternative_tile == p_other.alternative_tile;
+ }
};
class TileMapPattern : public Resource {
GDCLASS(TileMapPattern, Resource);
Vector2i size;
- Map<Vector2i, TileMapCell> pattern;
+ HashMap<Vector2i, TileMapCell> pattern;
void _set_tile_data(const Vector<int> &p_data);
Vector<int> _get_tile_data() const;
@@ -155,7 +164,7 @@ private:
String name;
Ref<Texture2D> texture;
Vector2 tex_offset;
- Ref<ShaderMaterial> material;
+ Ref<Material> material;
Rect2 region;
int tile_mode = 0;
Color modulate = Color(1, 1, 1);
@@ -166,11 +175,11 @@ private:
Size2i autotile_tile_size = Size2i(16, 16);
int autotile_spacing = 0;
- Map<Vector2i, int> autotile_bitmask_flags;
- Map<Vector2i, Ref<OccluderPolygon2D>> autotile_occluder_map;
- Map<Vector2i, Ref<NavigationPolygon>> autotile_navpoly_map;
- Map<Vector2i, int> autotile_priority_map;
- Map<Vector2i, int> autotile_z_index_map;
+ HashMap<Vector2i, int> autotile_bitmask_flags;
+ HashMap<Vector2i, Ref<OccluderPolygon2D>> autotile_occluder_map;
+ HashMap<Vector2i, Ref<NavigationPolygon>> autotile_navpoly_map;
+ HashMap<Vector2i, int> autotile_priority_map;
+ HashMap<Vector2i, int> autotile_z_index_map;
Vector<CompatibilityShapeData> shapes;
Ref<OccluderPolygon2D> occluder;
@@ -186,9 +195,9 @@ private:
COMPATIBILITY_TILE_MODE_ATLAS_TILE,
};
- Map<int, CompatibilityTileData *> compatibility_data;
- Map<int, int> compatibility_tilemap_mapping_tile_modes;
- Map<int, Map<Array, Array>> compatibility_tilemap_mapping;
+ HashMap<int, CompatibilityTileData *> compatibility_data;
+ HashMap<int, int> compatibility_tilemap_mapping_tile_modes;
+ HashMap<int, RBMap<Array, Array>> compatibility_tilemap_mapping;
void _compatibility_conversion();
@@ -256,6 +265,7 @@ public:
class TerrainsPattern {
bool valid = false;
+ int terrain = -1;
int bits[TileSet::CELL_NEIGHBOR_MAX];
bool is_valid_bit[TileSet::CELL_NEIGHBOR_MAX];
@@ -268,11 +278,14 @@ public:
bool operator<(const TerrainsPattern &p_terrains_pattern) const;
bool operator==(const TerrainsPattern &p_terrains_pattern) const;
- void set_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain);
- int get_terrain(TileSet::CellNeighbor p_peering_bit) const;
+ void set_terrain(int p_terrain);
+ int get_terrain() const;
+
+ void set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain);
+ int get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const;
- void set_terrains_from_array(Array p_terrains);
- Array get_terrains_as_array() const;
+ void from_array(Array p_terrains);
+ Array as_array() const;
TerrainsPattern(const TileSet *p_tile_set, int p_terrain_set);
TerrainsPattern() {}
@@ -324,10 +337,11 @@ private:
};
Vector<TerrainSet> terrain_sets;
- Map<TerrainMode, Map<CellNeighbor, Ref<ArrayMesh>>> terrain_bits_meshes;
+ HashMap<TerrainMode, Ref<ArrayMesh>> terrain_meshes;
+ HashMap<TerrainMode, HashMap<CellNeighbor, Ref<ArrayMesh>>> terrain_peering_bits_meshes;
bool terrain_bits_meshes_dirty = true;
- LocalVector<Map<TileSet::TerrainsPattern, Set<TileMapCell>>> per_terrain_pattern_tiles; // Cached data.
+ LocalVector<RBMap<TileSet::TerrainsPattern, RBSet<TileMapCell>>> per_terrain_pattern_tiles; // Cached data.
bool terrains_cache_dirty = true;
void _update_terrains_cache();
@@ -343,10 +357,10 @@ private:
Variant::Type type = Variant::NIL;
};
Vector<CustomDataLayer> custom_data_layers;
- Map<String, int> custom_data_layers_by_name;
+ HashMap<String, int> custom_data_layers_by_name;
// Per Atlas source data.
- Map<int, Ref<TileSetSource>> sources;
+ HashMap<int, Ref<TileSetSource>> sources;
Vector<int> source_ids;
int next_source_id = 0;
// ---------------------
@@ -357,22 +371,25 @@ private:
void _source_changed();
// Tile proxies
- Map<int, int> source_level_proxies;
- Map<Array, Array> coords_level_proxies;
- Map<Array, Array> alternative_level_proxies;
+ RBMap<int, int> source_level_proxies;
+ RBMap<Array, Array> coords_level_proxies;
+ RBMap<Array, Array> alternative_level_proxies;
// Helpers
- Vector<Point2> _get_square_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_square_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_square_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_square_terrain_polygon(Vector2i p_size);
+ Vector<Point2> _get_square_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_square_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_square_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_isometric_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_isometric_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_isometric_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_isometric_terrain_polygon(Vector2i p_size);
+ Vector<Point2> _get_isometric_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_isometric_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_isometric_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
- Vector<Point2> _get_half_offset_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
- Vector<Point2> _get_half_offset_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
- Vector<Point2> _get_half_offset_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
+ Vector<Point2> _get_half_offset_terrain_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
+ Vector<Point2> _get_half_offset_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_half_offset_corner_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit);
+ Vector<Point2> _get_half_offset_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit);
protected:
static void _bind_methods();
@@ -445,8 +462,8 @@ public:
String get_terrain_name(int p_terrain_set, int p_terrain_index) const;
void set_terrain_color(int p_terrain_set, int p_terrain_index, Color p_color);
Color get_terrain_color(int p_terrain_set, int p_terrain_index) const;
- bool is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const;
- bool is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const;
+ bool is_valid_terrain_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const;
+ bool is_valid_terrain_peering_bit(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const;
// Navigation
int get_navigation_layers_count() const;
@@ -499,15 +516,16 @@ public:
int get_patterns_count();
// Terrains.
- Set<TerrainsPattern> get_terrains_pattern_set(int p_terrain_set);
- Set<TileMapCell> get_tiles_for_terrains_pattern(int p_terrain_set, TerrainsPattern p_terrain_tile_pattern);
+ RBSet<TerrainsPattern> get_terrains_pattern_set(int p_terrain_set);
+ RBSet<TileMapCell> get_tiles_for_terrains_pattern(int p_terrain_set, TerrainsPattern p_terrain_tile_pattern);
TileMapCell get_random_tile_from_terrains_pattern(int p_terrain_set, TerrainsPattern p_terrain_tile_pattern);
// Helpers
Vector<Vector2> get_tile_shape_polygon();
void draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>());
- Vector<Point2> get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit);
+ Vector<Point2> get_terrain_polygon(int p_terrain_set);
+ Vector<Point2> get_terrain_peering_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit);
void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data);
Vector<Vector<Ref<Texture2D>>> generate_terrains_icons(Size2i p_size);
@@ -579,7 +597,7 @@ private:
LocalVector<real_t> animation_frames_durations;
// Alternatives
- Map<int, TileData *> alternatives;
+ HashMap<int, TileData *> alternatives;
Vector<int> alternatives_ids;
int next_alternative_id = 1;
};
@@ -589,9 +607,9 @@ private:
Vector2i separation;
Size2i texture_region_size = Size2i(16, 16);
- Map<Vector2i, TileAlternativesData> tiles;
+ HashMap<Vector2i, TileAlternativesData> tiles;
Vector<Vector2i> tiles_ids;
- Map<Vector2i, Vector2i> _coords_mapping_cache; // Maps any coordinate to the including tile
+ HashMap<Vector2i, Vector2i> _coords_mapping_cache; // Maps any coordinate to the including tile
TileData *_get_atlas_tile_data(Vector2i p_atlas_coords, int p_alternative_tile);
const TileData *_get_atlas_tile_data(Vector2i p_atlas_coords, int p_alternative_tile) const;
@@ -716,7 +734,7 @@ private:
bool display_placeholder = false;
};
Vector<int> scenes_ids;
- Map<int, SceneData> scenes;
+ HashMap<int, SceneData> scenes;
int next_scene_id = 1;
void _compute_next_alternative_id();
@@ -765,7 +783,7 @@ private:
bool flip_v = false;
bool transpose = false;
Vector2i tex_offset = Vector2i();
- Ref<ShaderMaterial> material = Ref<ShaderMaterial>();
+ Ref<Material> material = Ref<Material>();
Color modulate = Color(1.0, 1.0, 1.0, 1.0);
int z_index = 0;
int y_sort_origin = 0;
@@ -789,6 +807,7 @@ private:
// Terrain
int terrain_set = -1;
+ int terrain = -1;
int terrain_peering_bits[16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
// Navigation
@@ -845,8 +864,8 @@ public:
void set_texture_offset(Vector2i p_texture_offset);
Vector2i get_texture_offset() const;
- void set_material(Ref<ShaderMaterial> p_material);
- Ref<ShaderMaterial> get_material() const;
+ void set_material(Ref<Material> p_material);
+ Ref<Material> get_material() const;
void set_modulate(Color p_modulate);
Color get_modulate() const;
void set_z_index(int p_z_index);
@@ -878,9 +897,11 @@ public:
// Terrain
void set_terrain_set(int p_terrain_id);
int get_terrain_set() const;
- void set_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain_id);
- int get_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const;
- bool is_valid_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const;
+ void set_terrain(int p_terrain_id);
+ int get_terrain() const;
+ void set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain_id);
+ int get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const;
+ bool is_valid_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const;
TileSet::TerrainsPattern get_terrains_pattern() const; // Not exposed.
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 129f76702e..b68cce9dda 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -30,6 +30,7 @@
#include "visual_shader.h"
+#include "core/templates/rb_map.h"
#include "core/templates/vmap.h"
#include "servers/rendering/shader_types.h"
#include "visual_shader_nodes.h"
@@ -74,6 +75,10 @@ void VisualShaderNode::set_input_port_default_value(int p_port, const Variant &p
Vector3 pv = p_prev_value;
value = pv.x;
} break;
+ case Variant::QUATERNION: {
+ Quaternion pv = p_prev_value;
+ value = pv.x;
+ } break;
default:
break;
}
@@ -94,6 +99,10 @@ void VisualShaderNode::set_input_port_default_value(int p_port, const Variant &p
Vector3 pv = p_prev_value;
value = (int)pv.x;
} break;
+ case Variant::QUATERNION: {
+ Quaternion pv = p_prev_value;
+ value = (int)pv.x;
+ } break;
default:
break;
}
@@ -115,6 +124,10 @@ void VisualShaderNode::set_input_port_default_value(int p_port, const Variant &p
Vector3 pv = p_prev_value;
value = Vector2(pv.x, pv.y);
} break;
+ case Variant::QUATERNION: {
+ Quaternion pv = p_prev_value;
+ value = Vector2(pv.x, pv.y);
+ } break;
default:
break;
}
@@ -136,6 +149,35 @@ void VisualShaderNode::set_input_port_default_value(int p_port, const Variant &p
case Variant::VECTOR3: {
value = p_prev_value;
} break;
+ case Variant::QUATERNION: {
+ Quaternion pv = p_prev_value;
+ value = Vector3(pv.x, pv.y, pv.z);
+ } break;
+ default:
+ break;
+ }
+ } break;
+ case Variant::QUATERNION: {
+ switch (p_prev_value.get_type()) {
+ case Variant::INT: {
+ float pv = (float)(int)p_prev_value;
+ value = Quaternion(pv, pv, pv, pv);
+ } break;
+ case Variant::FLOAT: {
+ float pv = p_prev_value;
+ value = Quaternion(pv, pv, pv, pv);
+ } break;
+ case Variant::VECTOR2: {
+ Vector2 pv = p_prev_value;
+ value = Quaternion(pv.x, pv.y, pv.y, pv.y);
+ } break;
+ case Variant::VECTOR3: {
+ Vector3 pv = p_prev_value;
+ value = Quaternion(pv.x, pv.y, pv.z, pv.z);
+ } break;
+ case Variant::QUATERNION: {
+ value = p_prev_value;
+ } break;
default:
break;
}
@@ -253,6 +295,9 @@ int VisualShaderNode::get_expanded_output_port_count() const {
case PORT_TYPE_VECTOR_3D: {
count2 += 3;
} break;
+ case PORT_TYPE_VECTOR_4D: {
+ count2 += 4;
+ } break;
default:
break;
}
@@ -301,8 +346,8 @@ Vector<StringName> VisualShaderNode::get_editable_properties() const {
return Vector<StringName>();
}
-Map<StringName, String> VisualShaderNode::get_editable_properties_names() const {
- return Map<StringName, String>();
+HashMap<StringName, String> VisualShaderNode::get_editable_properties_names() const {
+ return HashMap<StringName, String>();
}
Array VisualShaderNode::get_default_input_values() const {
@@ -360,6 +405,7 @@ void VisualShaderNode::_bind_methods() {
BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR_INT);
BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR_2D);
BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR_3D);
+ BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR_4D);
BIND_ENUM_CONSTANT(PORT_TYPE_BOOLEAN);
BIND_ENUM_CONSTANT(PORT_TYPE_TRANSFORM);
BIND_ENUM_CONSTANT(PORT_TYPE_SAMPLER);
@@ -667,86 +713,6 @@ VisualShader::VaryingType VisualShader::get_varying_type(const String &p_name) {
return varyings[p_name].type;
}
-void VisualShader::set_engine_version(const Dictionary &p_engine_version) {
- ERR_FAIL_COND(!p_engine_version.has("major"));
- ERR_FAIL_COND(!p_engine_version.has("minor"));
- engine_version["major"] = p_engine_version["major"];
- engine_version["minor"] = p_engine_version["minor"];
-}
-
-Dictionary VisualShader::get_engine_version() const {
- return engine_version;
-}
-
-#ifndef DISABLE_DEPRECATED
-
-void VisualShader::update_engine_version(const Dictionary &p_new_version) {
- if (engine_version.is_empty()) { // before 4.0
- for (int i = 0; i < TYPE_MAX; i++) {
- for (KeyValue<int, Node> &E : graph[i].nodes) {
- Ref<VisualShaderNodeInput> input = Object::cast_to<VisualShaderNodeInput>(E.value.node.ptr());
- if (input.is_valid()) {
- if (input->get_input_name() == "side") {
- input->set_input_name("front_facing");
- }
- }
- Ref<VisualShaderNodeExpression> expression = Object::cast_to<VisualShaderNodeExpression>(E.value.node.ptr());
- if (expression.is_valid()) {
- for (int j = 0; j < expression->get_input_port_count(); j++) {
- int type = expression->get_input_port_type(j);
- if (type > 0) { // + PORT_TYPE_SCALAR_INT + PORT_TYPE_VECTOR_2D
- type += 2;
- }
- expression->set_input_port_type(j, type);
- }
- for (int j = 0; j < expression->get_output_port_count(); j++) {
- int type = expression->get_output_port_type(j);
- if (type > 0) { // + PORT_TYPE_SCALAR_INT + PORT_TYPE_VECTOR_2D
- type += 2;
- }
- expression->set_output_port_type(j, type);
- }
- }
- Ref<VisualShaderNodeStep> step = Object::cast_to<VisualShaderNodeStep>(E.value.node.ptr());
- if (step.is_valid()) {
- int op_type = int(step->get_op_type());
- if (int(op_type) > 0) { // + OP_TYPE_VECTOR_2D + OP_TYPE_VECTOR_2D_SCALAR
- op_type += 2;
- }
- step->set_op_type(VisualShaderNodeStep::OpType(op_type));
- }
- Ref<VisualShaderNodeSmoothStep> sstep = Object::cast_to<VisualShaderNodeSmoothStep>(E.value.node.ptr());
- if (sstep.is_valid()) {
- int op_type = int(sstep->get_op_type());
- if (int(op_type) > 0) { // + OP_TYPE_VECTOR_2D + OP_TYPE_VECTOR_2D_SCALAR
- op_type += 2;
- }
- sstep->set_op_type(VisualShaderNodeSmoothStep::OpType(op_type));
- }
- Ref<VisualShaderNodeMix> mix = Object::cast_to<VisualShaderNodeMix>(E.value.node.ptr());
- if (mix.is_valid()) {
- int op_type = int(mix->get_op_type());
- if (int(op_type) > 0) { // + OP_TYPE_VECTOR_2D + OP_TYPE_VECTOR_2D_SCALAR
- op_type += 2;
- }
- mix->set_op_type(VisualShaderNodeMix::OpType(op_type));
- }
- Ref<VisualShaderNodeCompare> compare = Object::cast_to<VisualShaderNodeCompare>(E.value.node.ptr());
- if (compare.is_valid()) {
- int ctype = int(compare->get_comparison_type());
- if (int(ctype) > 0) { // + CTYPE_SCALAR_INT + CTYPE_VECTOR_2D
- ctype += 2;
- }
- compare->set_comparison_type(VisualShaderNodeCompare::ComparisonType(ctype));
- }
- }
- }
- }
- set_engine_version(p_new_version);
-}
-
-#endif /* DISABLE_DEPRECATED */
-
void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id) {
ERR_FAIL_COND(p_node.is_null());
ERR_FAIL_COND(p_id < 2);
@@ -767,7 +733,6 @@ void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, co
if (input.is_valid()) {
input->shader_mode = shader_mode;
input->shader_type = p_type;
- input->connect("input_type_changed", callable_mp(this, &VisualShader::_input_type_changed), varray(p_type, p_id));
}
n.node->connect("changed", callable_mp(this, &VisualShader::_queue_update));
@@ -837,11 +802,6 @@ void VisualShader::remove_node(Type p_type, int p_id) {
Graph *g = &graph[p_type];
ERR_FAIL_COND(!g->nodes.has(p_id));
- Ref<VisualShaderNodeInput> input = g->nodes[p_id].node;
- if (input.is_valid()) {
- input->disconnect("input_type_changed", callable_mp(this, &VisualShader::_input_type_changed));
- }
-
g->nodes[p_id].node->disconnect("changed", callable_mp(this, &VisualShader::_queue_update));
g->nodes.erase(p_id);
@@ -871,6 +831,48 @@ void VisualShader::replace_node(Type p_type, int p_id, const StringName &p_new_c
return;
}
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(p_new_class));
+ VisualShaderNode *prev_vsn = g->nodes[p_id].node.ptr();
+
+ // Update connection data.
+ for (int i = 0; i < vsn->get_output_port_count(); i++) {
+ if (i < prev_vsn->get_output_port_count()) {
+ if (prev_vsn->is_output_port_connected(i)) {
+ vsn->set_output_port_connected(i, true);
+ }
+
+ if (prev_vsn->is_output_port_expandable(i) && prev_vsn->_is_output_port_expanded(i) && vsn->is_output_port_expandable(i)) {
+ vsn->_set_output_port_expanded(i, true);
+
+ int component_count = 0;
+ switch (prev_vsn->get_output_port_type(i)) {
+ case VisualShaderNode::PORT_TYPE_VECTOR_2D:
+ component_count = 2;
+ break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_3D:
+ component_count = 3;
+ break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D:
+ component_count = 4;
+ break;
+ default:
+ break;
+ }
+
+ for (int j = 0; j < component_count; j++) {
+ int sub_port = i + 1 + j;
+
+ if (prev_vsn->is_output_port_connected(sub_port)) {
+ vsn->set_output_port_connected(sub_port, true);
+ }
+ }
+
+ i += component_count;
+ }
+ } else {
+ break;
+ }
+ }
+
vsn->connect("changed", callable_mp(this, &VisualShader::_queue_update));
g->nodes[p_id].node = Ref<VisualShaderNode>(vsn);
@@ -1139,16 +1141,16 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
StringBuilder global_code;
StringBuilder global_code_per_node;
- Map<Type, StringBuilder> global_code_per_func;
+ HashMap<Type, StringBuilder> global_code_per_func;
StringBuilder code;
- Set<StringName> classes;
+ HashSet<StringName> classes;
global_code += String() + "shader_type canvas_item;\n";
String global_expressions;
for (int i = 0, index = 0; i < TYPE_MAX; i++) {
- for (Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) {
- Ref<VisualShaderNodeGlobalExpression> global_expression = Object::cast_to<VisualShaderNodeGlobalExpression>(E->get().node.ptr());
+ for (const KeyValue<int, Node> &E : graph[i].nodes) {
+ Ref<VisualShaderNodeGlobalExpression> global_expression = E.value.node;
if (global_expression.is_valid()) {
String expr = "";
expr += "// " + global_expression->get_caption() + ":" + itos(index++) + "\n";
@@ -1183,7 +1185,7 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
code += "\nvoid fragment() {\n";
- Set<int> processed;
+ HashSet<int> processed;
Error err = _write_node(p_type, &global_code, &global_code_per_node, &global_code_per_func, code, default_tex_params, input_connections, output_connections, p_node, processed, true, classes);
ERR_FAIL_COND_V(err != OK, String());
@@ -1203,6 +1205,9 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n";
} break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ".xyz;\n";
+ } break;
default: {
code += " COLOR.rgb = vec3(0.0);\n";
} break;
@@ -1505,11 +1510,11 @@ void VisualShader::reset_state() {
}
void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
//mode
- p_list->push_back(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky,Fog"));
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("mode"), PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky,Fog"));
//render modes
- Map<String, String> blend_mode_enums;
- Set<String> toggles;
+ HashMap<String, String> blend_mode_enums;
+ HashSet<String> toggles;
const Vector<ShaderLanguage::ModeInfo> &rmodes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode));
@@ -1520,7 +1525,7 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
const String begin = String(info.name);
for (int j = 0; j < info.options.size(); j++) {
- const String option = String(info.options[j]);
+ const String option = String(info.options[j]).capitalize();
if (!blend_mode_enums.has(begin)) {
blend_mode_enums[begin] = option;
@@ -1534,15 +1539,15 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
}
for (const KeyValue<String, String> &E : blend_mode_enums) {
- p_list->push_back(PropertyInfo(Variant::INT, "modes/" + E.key, PROPERTY_HINT_ENUM, E.value));
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("%s/%s", PNAME("modes"), E.key), PROPERTY_HINT_ENUM, E.value));
}
- for (Set<String>::Element *E = toggles.front(); E; E = E->next()) {
- p_list->push_back(PropertyInfo(Variant::BOOL, "flags/" + E->get()));
+ for (const String &E : toggles) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("flags"), E)));
}
for (const KeyValue<String, Varying> &E : varyings) {
- p_list->push_back(PropertyInfo(Variant::STRING, "varyings/" + E.key));
+ p_list->push_back(PropertyInfo(Variant::STRING, vformat("%s/%s", PNAME("varyings"), E.key)));
}
for (int i = 0; i < TYPE_MAX; i++) {
@@ -1569,7 +1574,7 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBuilder *global_code_per_node, Map<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<VisualShader::DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const {
+Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBuilder *global_code_per_node, HashMap<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<VisualShader::DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, HashSet<int> &processed, bool for_preview, HashSet<StringName> &r_classes) const {
const Ref<VisualShaderNode> vsnode = graph[type].nodes[node].node;
if (vsnode->is_disabled()) {
@@ -1687,11 +1692,14 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
inputs[i] = "(" + src_var + " ? 1.0 : 0.0)";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
- inputs[i] = "dot(" + src_var + ", vec2(0.333333, 0.333333))";
+ inputs[i] = "dot(" + src_var + ", vec2(0.5, 0.5))";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
inputs[i] = "dot(" + src_var + ", vec3(0.333333, 0.333333, 0.333333))";
} break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ inputs[i] = "dot(" + src_var + ", vec4(0.25, 0.25, 0.25, 0.25))";
+ } break;
default:
break;
}
@@ -1705,11 +1713,14 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
inputs[i] = "(" + src_var + " ? 1 : 0)";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
- inputs[i] = "dot(float(" + src_var + "), vec2(0.333333, 0.333333))";
+ inputs[i] = "dot(float(" + src_var + "), vec2(0.5, 0.5))";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
inputs[i] = "dot(float(" + src_var + "), vec3(0.333333, 0.333333, 0.333333))";
} break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ inputs[i] = "dot(float(" + src_var + "), vec4(0.25, 0.25, 0.25, 0.25))";
+ } break;
default:
break;
}
@@ -1728,6 +1739,9 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
inputs[i] = "all(bvec3(" + src_var + "))";
} break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ inputs[i] = "all(bvec4(" + src_var + "))";
+ } break;
default:
break;
}
@@ -1743,7 +1757,8 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
case VisualShaderNode::PORT_TYPE_BOOLEAN: {
inputs[i] = "vec2(" + src_var + " ? 1.0 : 0.0)";
} break;
- case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
+ case VisualShaderNode::PORT_TYPE_VECTOR_3D:
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
inputs[i] = "vec2(" + src_var + ".xy)";
} break;
default:
@@ -1765,6 +1780,30 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
inputs[i] = "vec3(" + src_var + ", 0.0)";
} break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ inputs[i] = "vec3(" + src_var + ".xyz)";
+ } break;
+ default:
+ break;
+ }
+ } break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ switch (out_type) {
+ case VisualShaderNode::PORT_TYPE_SCALAR: {
+ inputs[i] = "vec4(" + src_var + ")";
+ } break;
+ case VisualShaderNode::PORT_TYPE_SCALAR_INT: {
+ inputs[i] = "vec4(float(" + src_var + "))";
+ } break;
+ case VisualShaderNode::PORT_TYPE_BOOLEAN: {
+ inputs[i] = "vec4(" + src_var + " ? 1.0 : 0.0)";
+ } break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
+ inputs[i] = "vec4(" + src_var + ", 0.0, 0.0)";
+ } break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
+ inputs[i] = "vec4(" + src_var + ", 0.0)";
+ } break;
default:
break;
}
@@ -1799,6 +1838,10 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
Vector3 val = defval;
inputs[i] = "n_in" + itos(node) + "p" + itos(i);
node_code += " vec3 " + inputs[i] + " = " + vformat("vec3(%.5f, %.5f, %.5f);\n", val.x, val.y, val.z);
+ } else if (defval.get_type() == Variant::QUATERNION) {
+ Quaternion val = defval;
+ inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ node_code += " vec4 " + inputs[i] + " = " + vformat("vec4(%.5f, %.5f, %.5f, %.5f);\n", val.x, val.y, val.z, val.w);
} else if (defval.get_type() == Variant::TRANSFORM3D) {
Transform3D val = defval;
val.basis.transpose();
@@ -1823,7 +1866,7 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
int output_count = vsnode->get_output_port_count();
int initial_output_count = output_count;
- Map<int, bool> expanded_output_ports;
+ HashMap<int, bool> expanded_output_ports;
for (int i = 0; i < initial_output_count; i++) {
bool expanded = false;
@@ -1838,6 +1881,9 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
output_count += 3;
} break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ output_count += 4;
+ } break;
default:
break;
}
@@ -1865,6 +1911,9 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
case VisualShaderNode::PORT_TYPE_VECTOR_3D:
outputs[i] = "vec3 " + var_name;
break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D:
+ outputs[i] = "vec4 " + var_name;
+ break;
case VisualShaderNode::PORT_TYPE_BOOLEAN:
outputs[i] = "bool " + var_name;
break;
@@ -1882,6 +1931,9 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
j += 3;
} break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ j += 4;
+ } break;
default:
break;
}
@@ -1904,6 +1956,9 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
case VisualShaderNode::PORT_TYPE_VECTOR_3D:
code += " vec3 " + outputs[i] + ";\n";
break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D:
+ code += " vec4 " + outputs[i] + ";\n";
+ break;
case VisualShaderNode::PORT_TYPE_BOOLEAN:
code += " bool " + outputs[i] + ";\n";
break;
@@ -1921,6 +1976,9 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
j += 3;
} break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ j += 4;
+ } break;
default:
break;
}
@@ -1932,29 +1990,19 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
if (!node_code.is_empty()) {
code += node_name;
code += node_code;
- code += "\n";
}
for (int i = 0; i < output_count; i++) {
- bool new_line_inserted = false;
if (expanded_output_ports[i]) {
switch (vsnode->get_output_port_type(i)) {
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
- if (!new_line_inserted) {
- code += "\n";
- new_line_inserted = true;
- }
String r = "n_out" + itos(node) + "p" + itos(i + 1);
code += " float " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n";
outputs[i + 1] = r;
}
if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
- if (!new_line_inserted) {
- code += "\n";
- new_line_inserted = true;
- }
String g = "n_out" + itos(node) + "p" + itos(i + 2);
code += " float " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n";
outputs[i + 2] = g;
@@ -1964,30 +2012,18 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
- if (!new_line_inserted) {
- code += "\n";
- new_line_inserted = true;
- }
String r = "n_out" + itos(node) + "p" + itos(i + 1);
code += " float " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n";
outputs[i + 1] = r;
}
if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
- if (!new_line_inserted) {
- code += "\n";
- new_line_inserted = true;
- }
String g = "n_out" + itos(node) + "p" + itos(i + 2);
code += " float " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n";
outputs[i + 2] = g;
}
if (vsnode->is_output_port_connected(i + 3) || (for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component
- if (!new_line_inserted) {
- code += "\n";
- new_line_inserted = true;
- }
String b = "n_out" + itos(node) + "p" + itos(i + 3);
code += " float " + b + " = n_out" + itos(node) + "p" + itos(i) + ".b;\n";
outputs[i + 3] = b;
@@ -1995,12 +2031,43 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
i += 3;
} break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
+ String r = "n_out" + itos(node) + "p" + itos(i + 1);
+ code += " float " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n";
+ outputs[i + 1] = r;
+ }
+
+ if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
+ String g = "n_out" + itos(node) + "p" + itos(i + 2);
+ code += " float " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n";
+ outputs[i + 2] = g;
+ }
+
+ if (vsnode->is_output_port_connected(i + 3) || (for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component
+ String b = "n_out" + itos(node) + "p" + itos(i + 3);
+ code += " float " + b + " = n_out" + itos(node) + "p" + itos(i) + ".b;\n";
+ outputs[i + 3] = b;
+ }
+
+ if (vsnode->is_output_port_connected(i + 4) || (for_preview && vsnode->get_output_port_for_preview() == (i + 4))) { // alpha-component
+ String a = "n_out" + itos(node) + "p" + itos(i + 4);
+ code += " float " + a + " = n_out" + itos(node) + "p" + itos(i) + ".a;\n";
+ outputs[i + 4] = a;
+ }
+
+ i += 4;
+ } break;
default:
break;
}
}
}
+ if (!node_code.is_empty()) {
+ code += "\n";
+ }
+
code += "\n"; //
processed.insert(node);
@@ -2029,11 +2096,11 @@ void VisualShader::_update_shader() const {
StringBuilder global_code;
StringBuilder global_code_per_node;
- Map<Type, StringBuilder> global_code_per_func;
+ HashMap<Type, StringBuilder> global_code_per_func;
StringBuilder code;
Vector<VisualShader::DefaultTextureParam> default_tex_params;
- Set<StringName> classes;
- Map<int, int> insertion_pos;
+ HashSet<StringName> classes;
+ HashMap<int, int> insertion_pos;
static const char *shader_mode_str[Shader::MODE_MAX] = { "spatial", "canvas_item", "particles", "sky", "fog" };
global_code += String() + "shader_type " + shader_mode_str[shader_mode] + ";\n";
@@ -2077,18 +2144,18 @@ void VisualShader::_update_shader() const {
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog" };
String global_expressions;
- Set<String> used_uniform_names;
+ HashSet<String> used_uniform_names;
List<VisualShaderNodeUniform *> uniforms;
- Map<int, List<int>> emitters;
- Map<int, List<int>> varying_setters;
+ HashMap<int, List<int>> emitters;
+ HashMap<int, List<int>> varying_setters;
for (int i = 0, index = 0; i < TYPE_MAX; i++) {
if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) {
continue;
}
- for (Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) {
- Ref<VisualShaderNodeGlobalExpression> global_expression = Object::cast_to<VisualShaderNodeGlobalExpression>(E->get().node.ptr());
+ for (const KeyValue<int, Node> &E : graph[i].nodes) {
+ Ref<VisualShaderNodeGlobalExpression> global_expression = E.value.node;
if (global_expression.is_valid()) {
String expr = "";
expr += "// " + global_expression->get_caption() + ":" + itos(index++) + "\n";
@@ -2097,27 +2164,27 @@ void VisualShader::_update_shader() const {
expr += "\n";
global_expressions += expr;
}
- Ref<VisualShaderNodeUniformRef> uniform_ref = Object::cast_to<VisualShaderNodeUniformRef>(E->get().node.ptr());
+ Ref<VisualShaderNodeUniformRef> uniform_ref = E.value.node;
if (uniform_ref.is_valid()) {
used_uniform_names.insert(uniform_ref->get_uniform_name());
}
- Ref<VisualShaderNodeUniform> uniform = Object::cast_to<VisualShaderNodeUniform>(E->get().node.ptr());
+ Ref<VisualShaderNodeUniform> uniform = E.value.node;
if (uniform.is_valid()) {
uniforms.push_back(uniform.ptr());
}
- Ref<VisualShaderNodeVaryingSetter> varying_setter = Object::cast_to<VisualShaderNodeVaryingSetter>(E->get().node.ptr());
+ Ref<VisualShaderNodeVaryingSetter> varying_setter = E.value.node;
if (varying_setter.is_valid() && varying_setter->is_input_port_connected(0)) {
if (!varying_setters.has(i)) {
varying_setters.insert(i, List<int>());
}
- varying_setters[i].push_back(E->key());
+ varying_setters[i].push_back(E.key);
}
- Ref<VisualShaderNodeParticleEmit> emit_particle = Object::cast_to<VisualShaderNodeParticleEmit>(E->get().node.ptr());
+ Ref<VisualShaderNodeParticleEmit> emit_particle = E.value.node;
if (emit_particle.is_valid()) {
if (!emitters.has(i)) {
emitters.insert(i, List<int>());
}
- emitters[i].push_back(E->key());
+ emitters[i].push_back(E.key);
}
}
}
@@ -2147,6 +2214,9 @@ void VisualShader::_update_shader() const {
case VaryingType::VARYING_TYPE_VECTOR_3D:
global_code += "vec3 ";
break;
+ case VaryingType::VARYING_TYPE_VECTOR_4D:
+ global_code += "vec4 ";
+ break;
case VaryingType::VARYING_TYPE_COLOR:
global_code += "vec4 ";
break;
@@ -2162,8 +2232,8 @@ void VisualShader::_update_shader() const {
global_code += "\n";
}
- Map<int, String> code_map;
- Set<int> empty_funcs;
+ HashMap<int, String> code_map;
+ HashSet<int> empty_funcs;
for (int i = 0; i < TYPE_MAX; i++) {
if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) {
@@ -2175,7 +2245,7 @@ void VisualShader::_update_shader() const {
VMap<ConnectionKey, const List<Connection>::Element *> output_connections;
StringBuilder func_code;
- Set<int> processed;
+ HashSet<int> processed;
bool is_empty_func = false;
if (shader_mode != Shader::MODE_PARTICLES && shader_mode != Shader::MODE_SKY && shader_mode != Shader::MODE_FOG) {
@@ -2207,6 +2277,9 @@ void VisualShader::_update_shader() const {
case VaryingType::VARYING_TYPE_VECTOR_3D:
code2 += "vec3(0.0)";
break;
+ case VaryingType::VARYING_TYPE_VECTOR_4D:
+ code2 += "vec4(0.0)";
+ break;
case VaryingType::VARYING_TYPE_COLOR:
code2 += "vec4(0.0)";
break;
@@ -2447,21 +2520,6 @@ void VisualShader::_queue_update() {
call_deferred(SNAME("_update_shader"));
}
-void VisualShader::_input_type_changed(Type p_type, int p_id) {
- ERR_FAIL_INDEX(p_type, TYPE_MAX);
- //erase connections using this input, as type changed
- Graph *g = &graph[p_type];
-
- for (List<Connection>::Element *E = g->connections.front(); E;) {
- List<Connection>::Element *N = E->next();
- if (E->get().from_node == p_id) {
- g->connections.erase(E);
- g->nodes[E->get().to_node].prev_connected_nodes.erase(p_id);
- }
- E = N;
- }
-}
-
void VisualShader::rebuild() {
dirty.set();
_update_shader();
@@ -2491,9 +2549,6 @@ void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_node_connections", "type"), &VisualShader::_get_node_connections);
- ClassDB::bind_method(D_METHOD("set_engine_version", "version"), &VisualShader::set_engine_version);
- ClassDB::bind_method(D_METHOD("get_engine_version"), &VisualShader::get_engine_version);
-
ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &VisualShader::set_graph_offset);
ClassDB::bind_method(D_METHOD("get_graph_offset"), &VisualShader::get_graph_offset);
@@ -2504,7 +2559,6 @@ void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_shader"), &VisualShader::_update_shader);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset");
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "engine_version", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_engine_version", "get_engine_version");
ADD_PROPERTY_DEFAULT("code", ""); // Inherited from Shader, prevents showing default code as override in docs.
@@ -2527,6 +2581,7 @@ void VisualShader::_bind_methods() {
BIND_ENUM_CONSTANT(VARYING_TYPE_FLOAT);
BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_2D);
BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_3D);
+ BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_4D);
BIND_ENUM_CONSTANT(VARYING_TYPE_COLOR);
BIND_ENUM_CONSTANT(VARYING_TYPE_TRANSFORM);
BIND_ENUM_CONSTANT(VARYING_TYPE_MAX);
@@ -2569,12 +2624,10 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "BINORMAL" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV2" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "instance_id", "INSTANCE_ID" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "instance_custom", "INSTANCE_CUSTOM.rgb" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "instance_custom_alpha", "INSTANCE_CUSTOM.a" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "instance_custom", "INSTANCE_CUSTOM" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_matrix", "MODEL_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "modelview_matrix", "MODELVIEW_MATRIX" },
@@ -2590,7 +2643,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
// Node3D, Fragment
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "vertex", "VERTEX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "TANGENT" },
@@ -2598,8 +2651,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "view", "VIEW" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV2" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "point_coord", "POINT_COORD" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_matrix", "MODEL_MATRIX" },
@@ -2619,7 +2671,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
// Node3D, Light
- { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV2" },
@@ -2647,8 +2699,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
// Canvas Item, Vertex
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "texture_pixel_size", "TEXTURE_PIXEL_SIZE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_matrix", "MODEL_MATRIX" },
@@ -2656,16 +2707,14 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "screen_matrix", "SCREEN_MATRIX" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "instance_custom", "INSTANCE_CUSTOM.rgb" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "instance_custom_alpha", "INSTANCE_CUSTOM.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "instance_custom", "INSTANCE_CUSTOM" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "instance_id", "INSTANCE_ID" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "vertex_id", "VERTEX_ID" },
// Canvas Item, Fragment
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "texture_pixel_size", "TEXTURE_PIXEL_SIZE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_pixel_size", "SCREEN_PIXEL_SIZE" },
@@ -2675,42 +2724,34 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "normal_texture", "NORMAL_TEXTURE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "specular_shininess", "SPECULAR_SHININESS.rgb" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "specular_shininess_alpha", "SPECULAR_SHININESS.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "specular_shininess", "SPECULAR_SHININESS" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" },
// Canvas Item, Light
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light", "LIGHT.rgb" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.a" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_color", "LIGHT_COLOR.rgb" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_color_alpha", "LIGHT_COLOR.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "light", "LIGHT" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "light_color", "LIGHT_COLOR" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_position", "LIGHT_POSITION" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_vertex", "LIGHT_VERTEX" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "shadow", "SHADOW_MODULATE.rgb" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "shadow_alpha", "SHADOW_MODULATE.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "shadow", "SHADOW_MODULATE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "texture_pixel_size", "TEXTURE_PIXEL_SIZE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "point_coord", "POINT_COORD" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "specular_shininess", "SPECULAR_SHININESS.rgb" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "specular_shininess_alpha", "SPECULAR_SHININESS.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "specular_shininess", "SPECULAR_SHININESS" },
// Particles, Start
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_3D, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom", "CUSTOM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
@@ -2720,13 +2761,11 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
// Particles, Start (Custom)
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom", "CUSTOM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
@@ -2736,13 +2775,11 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
// Particles, Process
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_3D, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom", "CUSTOM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
@@ -2752,13 +2789,11 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
// Particles, Process (Custom)
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom", "CUSTOM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
@@ -2770,13 +2805,11 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "collision_depth", "COLLISION_DEPTH" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_3D, "collision_normal", "COLLISION_NORMAL" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_3D, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom", "CUSTOM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
@@ -2789,8 +2822,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_half_res_pass", "AT_HALF_RES_PASS" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_quarter_res_pass", "AT_QUARTER_RES_PASS" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "eyedir", "EYEDIR" },
- { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "half_res_color", "HALF_RES_COLOR.rgb" },
- { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "half_res_alpha", "HALF_RES_COLOR.a" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_4D, "half_res_color", "HALF_RES_COLOR" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light0_color", "LIGHT0_COLOR" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light0_direction", "LIGHT0_DIRECTION" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light0_enabled", "LIGHT0_ENABLED" },
@@ -2808,10 +2840,10 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light3_enabled", "LIGHT3_ENABLED" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light3_energy", "LIGHT3_ENERGY" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "position", "POSITION" },
- { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "quarter_res_color", "QUARTER_RES_COLOR.rgb" },
- { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "quarter_res_alpha", "QUARTER_RES_COLOR.a" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_4D, "quarter_res_color", "QUARTER_RES_COLOR" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SAMPLER, "radiance", "RADIANCE" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "sky_coords", "SKY_COORDS" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
@@ -2835,20 +2867,20 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "vec3(1.0, 0.0, 0.0)" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "vec3(1.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "vec4(1.0)" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "vec2(1.0)" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
// Spatial, Fragment
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.rgb" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "vec3(0.0, 0.0, 1.0)" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "vec3(0.0, 1.0, 0.0)" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "vec3(1.0, 0.0, 0.0)" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "vec3(1.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "vec4(1.0)" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "vec2(1.0)" },
@@ -2856,7 +2888,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = {
// Spatial, Light
- { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.rgb" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "vec3(0.0, 0.0, 1.0)" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV" },
@@ -2867,25 +2899,25 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "vec3(1.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "vec4(1.0)" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
// Canvas Item, Fragment
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "vec3(1.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "vec3(1.0)" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
// Canvas Item, Light
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "vec3(0.0, 0.0, 1.0)" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "vec3(1.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "vec4(1.0)" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
@@ -2927,7 +2959,7 @@ int VisualShaderNodeInput::get_output_port_count() const {
}
VisualShaderNodeInput::PortType VisualShaderNodeInput::get_output_port_type(int p_port) const {
- return get_input_type_by_name(input_name);
+ return p_port == 0 ? get_input_type_by_name(input_name) : PORT_TYPE_SCALAR;
}
String VisualShaderNodeInput::get_output_port_name(int p_port) const {
@@ -2938,6 +2970,22 @@ String VisualShaderNodeInput::get_caption() const {
return "Input";
}
+bool VisualShaderNodeInput::is_output_port_expandable(int p_port) const {
+ if (p_port == 0) {
+ switch (get_input_type_by_name(input_name)) {
+ case PORT_TYPE_VECTOR_2D:
+ return true;
+ case PORT_TYPE_VECTOR_3D:
+ return true;
+ case PORT_TYPE_VECTOR_4D:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
String VisualShaderNodeInput::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) const {
if (get_output_port_type(0) == PORT_TYPE_SAMPLER) {
return "";
@@ -2970,6 +3018,9 @@ String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::T
case PORT_TYPE_VECTOR_3D: {
code = " " + p_output_vars[0] + " = vec3(0.0);\n";
} break;
+ case PORT_TYPE_VECTOR_4D: {
+ code = " " + p_output_vars[0] + " = vec4(0.0);\n";
+ } break;
case PORT_TYPE_BOOLEAN: {
code = " " + p_output_vars[0] + " = false;\n";
} break;
@@ -3139,18 +3190,18 @@ VisualShaderNodeInput::VisualShaderNodeInput() {
////////////// UniformRef
-List<VisualShaderNodeUniformRef::Uniform> uniforms;
+RBMap<RID, List<VisualShaderNodeUniformRef::Uniform>> uniforms;
-void VisualShaderNodeUniformRef::add_uniform(const String &p_name, UniformType p_type) {
- uniforms.push_back({ p_name, p_type });
+void VisualShaderNodeUniformRef::add_uniform(RID p_shader_rid, const String &p_name, UniformType p_type) {
+ uniforms[p_shader_rid].push_back({ p_name, p_type });
}
-void VisualShaderNodeUniformRef::clear_uniforms() {
- uniforms.clear();
+void VisualShaderNodeUniformRef::clear_uniforms(RID p_shader_rid) {
+ uniforms[p_shader_rid].clear();
}
-bool VisualShaderNodeUniformRef::has_uniform(const String &p_name) {
- for (const VisualShaderNodeUniformRef::Uniform &E : uniforms) {
+bool VisualShaderNodeUniformRef::has_uniform(RID p_shader_rid, const String &p_name) {
+ for (const VisualShaderNodeUniformRef::Uniform &E : uniforms[p_shader_rid]) {
if (E.name == p_name) {
return true;
}
@@ -3186,6 +3237,8 @@ int VisualShaderNodeUniformRef::get_output_port_count() const {
return 1;
case UniformType::UNIFORM_TYPE_VECTOR3:
return 1;
+ case UniformType::UNIFORM_TYPE_VECTOR4:
+ return 1;
case UniformType::UNIFORM_TYPE_TRANSFORM:
return 1;
case UniformType::UNIFORM_TYPE_COLOR:
@@ -3210,6 +3263,8 @@ VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port
return PortType::PORT_TYPE_VECTOR_2D;
case UniformType::UNIFORM_TYPE_VECTOR3:
return PortType::PORT_TYPE_VECTOR_3D;
+ case UniformType::UNIFORM_TYPE_VECTOR4:
+ return PortType::PORT_TYPE_VECTOR_4D;
case UniformType::UNIFORM_TYPE_TRANSFORM:
return PortType::PORT_TYPE_TRANSFORM;
case UniformType::UNIFORM_TYPE_COLOR:
@@ -3239,6 +3294,8 @@ String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const {
return "";
case UniformType::UNIFORM_TYPE_VECTOR3:
return "";
+ case UniformType::UNIFORM_TYPE_VECTOR4:
+ return "";
case UniformType::UNIFORM_TYPE_TRANSFORM:
return "";
case UniformType::UNIFORM_TYPE_COLOR:
@@ -3257,14 +3314,24 @@ String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const {
return "";
}
+void VisualShaderNodeUniformRef::set_shader_rid(const RID &p_shader_rid) {
+ shader_rid = p_shader_rid;
+}
+
void VisualShaderNodeUniformRef::set_uniform_name(const String &p_name) {
uniform_name = p_name;
+ if (shader_rid.is_valid()) {
+ update_uniform_type();
+ }
+ emit_changed();
+}
+
+void VisualShaderNodeUniformRef::update_uniform_type() {
if (uniform_name != "[None]") {
uniform_type = get_uniform_type_by_name(uniform_name);
} else {
uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
}
- emit_changed();
}
String VisualShaderNodeUniformRef::get_uniform_name() const {
@@ -3272,35 +3339,45 @@ String VisualShaderNodeUniformRef::get_uniform_name() const {
}
int VisualShaderNodeUniformRef::get_uniforms_count() const {
- return uniforms.size();
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), 0);
+
+ return uniforms[shader_rid].size();
}
String VisualShaderNodeUniformRef::get_uniform_name_by_index(int p_idx) const {
- if (p_idx >= 0 && p_idx < uniforms.size()) {
- return uniforms[p_idx].name;
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), String());
+
+ if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) {
+ return uniforms[shader_rid][p_idx].name;
}
return "";
}
VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_name(const String &p_name) const {
- for (int i = 0; i < uniforms.size(); i++) {
- if (uniforms[i].name == p_name) {
- return uniforms[i].type;
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), UNIFORM_TYPE_FLOAT);
+
+ for (int i = 0; i < uniforms[shader_rid].size(); i++) {
+ if (uniforms[shader_rid][i].name == p_name) {
+ return uniforms[shader_rid][i].type;
}
}
return UniformType::UNIFORM_TYPE_FLOAT;
}
VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_index(int p_idx) const {
- if (p_idx >= 0 && p_idx < uniforms.size()) {
- return uniforms[p_idx].type;
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), UNIFORM_TYPE_FLOAT);
+
+ if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) {
+ return uniforms[shader_rid][p_idx].type;
}
return UniformType::UNIFORM_TYPE_FLOAT;
}
VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_port_type_by_index(int p_idx) const {
- if (p_idx >= 0 && p_idx < uniforms.size()) {
- switch (uniforms[p_idx].type) {
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), PORT_TYPE_SCALAR);
+
+ if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) {
+ switch (uniforms[shader_rid][p_idx].type) {
case UniformType::UNIFORM_TYPE_FLOAT:
return PORT_TYPE_SCALAR;
case UniformType::UNIFORM_TYPE_INT:
@@ -3311,6 +3388,8 @@ VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_port_type_b
return PORT_TYPE_VECTOR_2D;
case UniformType::UNIFORM_TYPE_VECTOR3:
return PORT_TYPE_VECTOR_3D;
+ case UniformType::UNIFORM_TYPE_VECTOR4:
+ return PORT_TYPE_VECTOR_4D;
case UniformType::UNIFORM_TYPE_TRANSFORM:
return PORT_TYPE_TRANSFORM;
case UniformType::UNIFORM_TYPE_COLOR:
@@ -3380,94 +3459,94 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
////////////////////////////////////////////////////////////////////////
// Node3D, Vertex.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "vertex", "VERTEX" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "TANGENT" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "BINORMAL" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV2" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_view_matrix", "MODELVIEW_MATRIX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Vertex", "VERTEX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal", "NORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Tangent", "TANGENT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Binormal", "BINORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "UV", "UV" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "UV2", "UV2" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Color", "COLOR.rgb" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "COLOR.a" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Roughness", "ROUGHNESS" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Point Size", "POINT_SIZE" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "Model View Matrix", "MODELVIEW_MATRIX" },
////////////////////////////////////////////////////////////////////////
// Node3D, Fragment.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "albedo", "ALBEDO" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "metallic", "METALLIC" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "specular", "SPECULAR" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "emission", "EMISSION" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao", "AO" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao_light_affect", "AO_LIGHT_AFFECT" },
-
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal_map", "NORMAL_MAP" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normal_map_depth", "NORMAL_MAP_DEPTH" },
-
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim", "RIM" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim_tint", "RIM_TINT" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat", "CLEARCOAT" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat_roughness", "CLEARCOAT_ROUGHNESS" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "anisotropy", "ANISOTROPY" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "anisotropy_flow", "ANISOTROPY_FLOW" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "subsurf_scatter", "SSS_STRENGTH" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "backlight", "BACKLIGHT" },
-
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_scissor_threshold", "ALPHA_SCISSOR_THRESHOLD" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_hash_scale", "ALPHA_HASH_SCALE" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_aa_edge", "ALPHA_ANTIALIASING_EDGE" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "alpha_uv", "ALPHA_TEXTURE_COORDINATE" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Albedo", "ALBEDO" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "ALPHA" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Metallic", "METALLIC" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Roughness", "ROUGHNESS" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Specular", "SPECULAR" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Emission", "EMISSION" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "AO", "AO" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "AO Light Affect", "AO_LIGHT_AFFECT" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal", "NORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal Map", "NORMAL_MAP" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Normal Map Depth", "NORMAL_MAP_DEPTH" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Rim", "RIM" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Rim Tint", "RIM_TINT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Clearcoat", "CLEARCOAT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Clearcoat Roughness", "CLEARCOAT_ROUGHNESS" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Anisotropy", "ANISOTROPY" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Anisotropy Flow", "ANISOTROPY_FLOW" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Subsurf Scatter", "SSS_STRENGTH" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Backlight", "BACKLIGHT" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha Scissor Threshold", "ALPHA_SCISSOR_THRESHOLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha Hash Scale", "ALPHA_HASH_SCALE" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha AA Edge", "ALPHA_ANTIALIASING_EDGE" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Alpha UV", "ALPHA_TEXTURE_COORDINATE" },
////////////////////////////////////////////////////////////////////////
// Node3D, Light.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "diffuse", "DIFFUSE_LIGHT" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "specular", "SPECULAR_LIGHT" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Diffuse", "DIFFUSE_LIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Specular", "SPECULAR_LIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "ALPHA" },
////////////////////////////////////////////////////////////////////////
// Canvas Item.
////////////////////////////////////////////////////////////////////////
// Canvas Item, Vertex.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Vertex", "VERTEX" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "UV", "UV" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Color", "COLOR.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "COLOR.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Point Size", "POINT_SIZE" },
////////////////////////////////////////////////////////////////////////
// Canvas Item, Fragment.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal_map", "NORMAL_MAP" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normal_map_depth", "NORMAL_MAP_DEPTH" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_vertex", "LIGHT_VERTEX" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "shadow_vertex", "SHADOW_VERTEX" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Color", "COLOR.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "COLOR.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal", "NORMAL" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal Map", "NORMAL_MAP" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Normal Map Depth", "NORMAL_MAP_DEPTH" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Light Vertex", "LIGHT_VERTEX" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Shadow Vertex", "SHADOW_VERTEX" },
////////////////////////////////////////////////////////////////////////
// Canvas Item, Light.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light", "LIGHT.rgb" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Light", "LIGHT.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "Light Alpha", "LIGHT.a" },
////////////////////////////////////////////////////////////////////////
// Sky, Sky.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR" },
- { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
- { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fog", "FOG.rgb" },
- { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "fog_alpha", "FOG.a" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Color", "COLOR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "ALPHA" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Fog", "FOG.rgb" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "Fog Alpha", "FOG.a" },
////////////////////////////////////////////////////////////////////////
// Fog, Fog.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "density", "DENSITY" },
- { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "albedo", "ALBEDO" },
- { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "emission", "EMISSION" },
+ { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "Density", "DENSITY" },
+ { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Albedo", "ALBEDO" },
+ { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Emission", "EMISSION" },
////////////////////////////////////////////////////////////////////////
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
@@ -3511,7 +3590,7 @@ String VisualShaderNodeOutput::get_input_port_name(int p_port) const {
while (ports[idx].mode != Shader::MODE_MAX) {
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
if (count == p_port) {
- return String(ports[idx].name).capitalize();
+ return String(ports[idx].name);
}
count++;
}
@@ -3544,7 +3623,7 @@ bool VisualShaderNodeOutput::is_port_separator(int p_index) const {
}
if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_FRAGMENT) {
String name = get_input_port_name(p_index);
- return bool(name == "Ao" || name == "Normal" || name == "Rim" || name == "Clearcoat" || name == "Anisotropy" || name == "Subsurf Scatter" || name == "Alpha Scissor Threshold");
+ return bool(name == "AO" || name == "Normal" || name == "Rim" || name == "Clearcoat" || name == "Anisotropy" || name == "Subsurf Scatter" || name == "Alpha Scissor Threshold");
}
return false;
}
@@ -3697,6 +3776,11 @@ String VisualShaderNodeUniform::get_warning(Shader::Mode p_mode, VisualShader::T
incompatible_type = true;
}
} break;
+ case RS::GLOBAL_VAR_TYPE_VEC4: {
+ if (!Object::cast_to<VisualShaderNodeVec4Uniform>(this)) {
+ incompatible_type = true;
+ }
+ } break;
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
if (!Object::cast_to<VisualShaderNodeTransformUniform>(this)) {
incompatible_type = true;
@@ -4404,6 +4488,9 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad
case PORT_TYPE_VECTOR_3D:
tk = "vec3(0.0, 0.0, 0.0)";
break;
+ case PORT_TYPE_VECTOR_4D:
+ tk = "vec4(0.0, 0.0, 0.0, 0.0)";
+ break;
case PORT_TYPE_BOOLEAN:
tk = "false";
break;
@@ -4542,6 +4629,8 @@ String VisualShaderNodeVarying::get_type_str() const {
return "vec2";
case VisualShader::VARYING_TYPE_VECTOR_3D:
return "vec3";
+ case VisualShader::VARYING_TYPE_VECTOR_4D:
+ return "vec4";
case VisualShader::VARYING_TYPE_COLOR:
return "vec4";
case VisualShader::VARYING_TYPE_TRANSFORM:
@@ -4558,6 +4647,8 @@ VisualShaderNodeVarying::PortType VisualShaderNodeVarying::get_port_type(VisualS
return PORT_TYPE_VECTOR_2D;
case VisualShader::VARYING_TYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
+ case VisualShader::VARYING_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
case VisualShader::VARYING_TYPE_COLOR:
if (p_port == 1) {
break; // scalar
@@ -4718,6 +4809,9 @@ String VisualShaderNodeVaryingGetter::generate_code(Shader::Mode p_mode, VisualS
case VisualShader::VARYING_TYPE_VECTOR_3D:
from = "vec3(0.0)";
break;
+ case VisualShader::VARYING_TYPE_VECTOR_4D:
+ from = "vec4(0.0)";
+ break;
case VisualShader::VARYING_TYPE_COLOR:
from = "vec3(0.0)";
from2 = "0.0";
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 2d4b2852e9..7ca4e5fc4a 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -44,8 +44,6 @@ class VisualShader : public Shader {
friend class VisualShaderNodeVersionChecker;
- Dictionary engine_version;
-
public:
enum Type {
TYPE_VERTEX,
@@ -83,6 +81,7 @@ public:
VARYING_TYPE_FLOAT,
VARYING_TYPE_VECTOR_2D,
VARYING_TYPE_VECTOR_3D,
+ VARYING_TYPE_VECTOR_4D,
VARYING_TYPE_COLOR,
VARYING_TYPE_TRANSFORM,
VARYING_TYPE_MAX,
@@ -126,7 +125,7 @@ private:
};
struct Graph {
- Map<int, Node> nodes;
+ RBMap<int, Node> nodes;
List<Connection> connections;
} graph[TYPE_MAX];
@@ -138,9 +137,9 @@ private:
Vector2 graph_offset;
HashMap<String, int> modes;
- Set<StringName> flags;
+ HashSet<StringName> flags;
- Map<String, Varying> varyings;
+ HashMap<String, Varying> varyings;
List<Varying> varyings_list;
mutable SafeFlag dirty;
@@ -157,7 +156,7 @@ private:
}
};
- Error _write_node(Type p_type, StringBuilder *global_code, StringBuilder *global_code_per_node, Map<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const;
+ Error _write_node(Type p_type, StringBuilder *global_code, StringBuilder *global_code_per_node, HashMap<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, HashSet<int> &processed, bool for_preview, HashSet<StringName> &r_classes) const;
void _input_type_changed(Type p_type, int p_id);
bool has_func_name(RenderingServer::ShaderMode p_mode, const String &p_func_name) const;
@@ -176,14 +175,6 @@ public: // internal methods
void set_shader_type(Type p_type);
Type get_shader_type() const;
-public:
- void set_engine_version(const Dictionary &p_version);
- Dictionary get_engine_version() const;
-
-#ifndef DISABLE_DEPRECATED
- void update_engine_version(const Dictionary &p_new_version);
-#endif /* DISABLE_DEPRECATED */
-
enum {
NODE_ID_INVALID = -1,
NODE_ID_OUTPUT = 0,
@@ -254,10 +245,10 @@ class VisualShaderNode : public Resource {
int port_preview = -1;
- Map<int, Variant> default_input_values;
- Map<int, bool> connected_input_ports;
- Map<int, int> connected_output_ports;
- Map<int, bool> expanded_output_ports;
+ HashMap<int, Variant> default_input_values;
+ HashMap<int, bool> connected_input_ports;
+ HashMap<int, int> connected_output_ports;
+ HashMap<int, bool> expanded_output_ports;
protected:
bool simple_decl = true;
@@ -271,6 +262,7 @@ public:
PORT_TYPE_SCALAR_INT,
PORT_TYPE_VECTOR_2D,
PORT_TYPE_VECTOR_3D,
+ PORT_TYPE_VECTOR_4D,
PORT_TYPE_BOOLEAN,
PORT_TYPE_TRANSFORM,
PORT_TYPE_SAMPLER,
@@ -326,7 +318,7 @@ public:
void set_disabled(bool p_disabled = true);
virtual Vector<StringName> get_editable_properties() const;
- virtual Map<StringName, String> get_editable_properties_names() const;
+ virtual HashMap<StringName, String> get_editable_properties_names() const;
virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
@@ -446,6 +438,7 @@ public:
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ virtual bool is_output_port_expandable(int p_port) const override;
virtual String get_caption() const override;
@@ -556,6 +549,7 @@ public:
UNIFORM_TYPE_BOOLEAN,
UNIFORM_TYPE_VECTOR2,
UNIFORM_TYPE_VECTOR3,
+ UNIFORM_TYPE_VECTOR4,
UNIFORM_TYPE_TRANSFORM,
UNIFORM_TYPE_COLOR,
UNIFORM_TYPE_SAMPLER,
@@ -567,6 +561,7 @@ public:
};
private:
+ RID shader_rid;
String uniform_name = "[None]";
UniformType uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
@@ -574,9 +569,9 @@ protected:
static void _bind_methods();
public:
- static void add_uniform(const String &p_name, UniformType p_type);
- static void clear_uniforms();
- static bool has_uniform(const String &p_name);
+ static void add_uniform(RID p_shader_rid, const String &p_name, UniformType p_type);
+ static void clear_uniforms(RID p_shader_rid);
+ static bool has_uniform(RID p_shader_rid, const String &p_name);
public:
virtual String get_caption() const override;
@@ -589,9 +584,13 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ void set_shader_rid(const RID &p_shader);
+
void set_uniform_name(const String &p_name);
String get_uniform_name() const;
+ void update_uniform_type();
+
void _set_uniform_type(int p_uniform_type);
int _get_uniform_type() const;
@@ -676,9 +675,9 @@ protected:
String name;
};
- Map<int, Port> input_ports;
- Map<int, Port> output_ports;
- Map<int, Control *> controls;
+ HashMap<int, Port> input_ports;
+ HashMap<int, Port> output_ports;
+ HashMap<int, Control *> controls;
protected:
static void _bind_methods();
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 4e16353460..b8667f07fe 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -38,6 +38,8 @@ VisualShaderNodeVectorBase::PortType VisualShaderNodeVectorBase::get_input_port_
return PORT_TYPE_VECTOR_2D;
case OP_TYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
default:
break;
}
@@ -50,6 +52,8 @@ VisualShaderNodeVectorBase::PortType VisualShaderNodeVectorBase::get_output_port
return PORT_TYPE_VECTOR_2D;
case OP_TYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
default:
break;
}
@@ -73,10 +77,11 @@ void VisualShaderNodeVectorBase::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeVectorBase::set_op_type);
ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeVectorBase::get_op_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Vector2,Vector3"), "set_op_type", "get_op_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Vector2,Vector3,Vector4"), "set_op_type", "get_op_type");
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D);
+ BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D);
BIND_ENUM_CONSTANT(OP_TYPE_MAX);
}
@@ -291,7 +296,7 @@ int VisualShaderNodeColorConstant::get_input_port_count() const {
}
VisualShaderNodeColorConstant::PortType VisualShaderNodeColorConstant::get_input_port_type(int p_port) const {
- return PORT_TYPE_VECTOR_3D;
+ return PORT_TYPE_VECTOR_4D;
}
String VisualShaderNodeColorConstant::get_input_port_name(int p_port) const {
@@ -299,15 +304,15 @@ String VisualShaderNodeColorConstant::get_input_port_name(int p_port) const {
}
int VisualShaderNodeColorConstant::get_output_port_count() const {
- return 2;
+ return 1;
}
VisualShaderNodeColorConstant::PortType VisualShaderNodeColorConstant::get_output_port_type(int p_port) const {
- return p_port == 0 ? PORT_TYPE_VECTOR_3D : PORT_TYPE_SCALAR;
+ return p_port == 0 ? PORT_TYPE_VECTOR_4D : PORT_TYPE_SCALAR;
}
String VisualShaderNodeColorConstant::get_output_port_name(int p_port) const {
- return p_port == 0 ? "" : "alpha"; //no output port means the editor will be used as port
+ return "";
}
bool VisualShaderNodeColorConstant::is_output_port_expandable(int p_port) const {
@@ -318,11 +323,7 @@ bool VisualShaderNodeColorConstant::is_output_port_expandable(int p_port) const
}
String VisualShaderNodeColorConstant::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) const {
- String code;
- code += " " + p_output_vars[0] + " = " + vformat("vec3(%.6f, %.6f, %.6f)", constant.r, constant.g, constant.b) + ";\n";
- code += " " + p_output_vars[1] + " = " + vformat("%.6f", constant.a) + ";\n";
-
- return code;
+ return " " + p_output_vars[0] + " = " + vformat("vec4(%.6f, %.6f, %.6f, %.6f)", constant.r, constant.g, constant.b, constant.a) + ";\n";
}
void VisualShaderNodeColorConstant::set_constant(const Color &p_constant) {
@@ -477,6 +478,68 @@ void VisualShaderNodeVec3Constant::_bind_methods() {
VisualShaderNodeVec3Constant::VisualShaderNodeVec3Constant() {
}
+////////////// Vector4
+
+String VisualShaderNodeVec4Constant::get_caption() const {
+ return "Vector4Constant";
+}
+
+int VisualShaderNodeVec4Constant::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeVec4Constant::PortType VisualShaderNodeVec4Constant::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR_4D;
+}
+
+String VisualShaderNodeVec4Constant::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeVec4Constant::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeVec4Constant::PortType VisualShaderNodeVec4Constant::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR_4D;
+}
+
+String VisualShaderNodeVec4Constant::get_output_port_name(int p_port) const {
+ return ""; // No output port means the editor will be used as port.
+}
+
+String VisualShaderNodeVec4Constant::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) const {
+ return " " + p_output_vars[0] + " = " + vformat("vec4(%.6f, %.6f, %.6f, %.6f)", constant.x, constant.y, constant.z, constant.w) + ";\n";
+}
+
+void VisualShaderNodeVec4Constant::set_constant(const Quaternion &p_constant) {
+ if (constant.is_equal_approx(p_constant)) {
+ return;
+ }
+ constant = p_constant;
+ emit_changed();
+}
+
+Quaternion VisualShaderNodeVec4Constant::get_constant() const {
+ return constant;
+}
+
+Vector<StringName> VisualShaderNodeVec4Constant::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("constant");
+ return props;
+}
+
+void VisualShaderNodeVec4Constant::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_constant", "constant"), &VisualShaderNodeVec4Constant::set_constant);
+ ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeVec4Constant::get_constant);
+
+ ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "constant"), "set_constant", "get_constant");
+}
+
+VisualShaderNodeVec4Constant::VisualShaderNodeVec4Constant() {
+}
+
////////////// Transform3D
String VisualShaderNodeTransformConstant::get_caption() const {
@@ -584,21 +647,25 @@ String VisualShaderNodeTexture::get_input_port_name(int p_port) const {
}
int VisualShaderNodeTexture::get_output_port_count() const {
- return 2;
+ return 1;
}
VisualShaderNodeTexture::PortType VisualShaderNodeTexture::get_output_port_type(int p_port) const {
- if (p_port == 0 && source == SOURCE_DEPTH) {
- return PORT_TYPE_SCALAR;
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR_4D;
+ default:
+ return PORT_TYPE_SCALAR;
}
- return p_port == 0 ? PORT_TYPE_VECTOR_3D : PORT_TYPE_SCALAR;
}
String VisualShaderNodeTexture::get_output_port_name(int p_port) const {
- if (p_port == 0 && source == SOURCE_DEPTH) {
- return "depth";
+ switch (p_port) {
+ case 0:
+ return "color";
+ default:
+ return "";
}
- return p_port == 0 ? "rgb" : "alpha";
}
bool VisualShaderNodeTexture::is_output_port_expandable(int p_port) const {
@@ -633,7 +700,7 @@ String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShade
case TYPE_DATA:
break;
case TYPE_COLOR:
- u += " : hint_albedo";
+ u += " : source_color";
break;
case TYPE_NORMAL_MAP:
u += " : hint_normal";
@@ -655,170 +722,116 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader:
default_uv = "vec2(0.0)";
}
+ String code;
if (source == SOURCE_TEXTURE) {
String id = make_unique_id(p_type, p_id, "tex");
- String code;
if (p_input_vars[0].is_empty()) { // Use UV by default.
-
if (p_input_vars[1].is_empty()) {
- code += " vec4 " + id + "_read = texture(" + id + ", " + default_uv + ");\n";
+ code += " " + p_output_vars[0] + " = texture(" + id + ", " + default_uv + ");\n";
} else {
- code += " vec4 " + id + "_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n";
}
-
} else if (p_input_vars[1].is_empty()) {
//no lod
- code += " vec4 " + id + "_read = texture(" + id + ", " + p_input_vars[0] + ");\n";
+ code += " " + p_output_vars[0] + " = texture(" + id + ", " + p_input_vars[0] + ");\n";
} else {
- code += " vec4 " + id + "_read = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
}
-
- code += " " + p_output_vars[0] + " = " + id + "_read.rgb;\n";
- code += " " + p_output_vars[1] + " = " + id + "_read.a;\n";
return code;
}
if (source == SOURCE_PORT) {
String id = p_input_vars[2];
-
- String code;
- code += " {\n";
if (id.is_empty()) {
- code += " vec4 " + id + "_tex_read = vec4(0.0);\n";
+ code += " " + p_output_vars[0] + " = vec4(0.0);\n";
} else {
if (p_input_vars[0].is_empty()) { // Use UV by default.
-
if (p_input_vars[1].is_empty()) {
- code += " vec4 " + id + "_tex_read = texture(" + id + ", " + default_uv + ");\n";
+ code += " " + p_output_vars[0] + " = texture(" + id + ", " + default_uv + ");\n";
} else {
- code += " vec4 " + id + "_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n";
}
-
} else if (p_input_vars[1].is_empty()) {
//no lod
- code += " vec4 " + id + "_tex_read = texture(" + id + ", " + p_input_vars[0] + ");\n";
+ code += " " + p_output_vars[0] + " = texture(" + id + ", " + p_input_vars[0] + ");\n";
} else {
- code += " vec4 " + id + "_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
}
-
- code += " " + p_output_vars[0] + " = " + id + "_tex_read.rgb;\n";
- code += " " + p_output_vars[1] + " = " + id + "_tex_read.a;\n";
}
- code += " }\n";
return code;
}
if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) {
- String code = " {\n";
if (p_input_vars[0].is_empty() || p_for_preview) { // Use UV by default.
-
if (p_input_vars[1].is_empty()) {
- code += " vec4 _tex_read = textureLod(SCREEN_TEXTURE, " + default_uv + ", 0.0 );\n";
+ code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + default_uv + ", 0.0);\n";
} else {
- code += " vec4 _tex_read = textureLod(SCREEN_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n";
}
-
} else if (p_input_vars[1].is_empty()) {
//no lod
- code += " vec4 _tex_read = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ", 0.0);\n";
+ code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ", 0.0);\n";
} else {
- code += " vec4 _tex_read = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
}
-
- code += " " + p_output_vars[0] + " = _tex_read.rgb;\n";
- code += " " + p_output_vars[1] + " = _tex_read.a;\n";
- code += " }\n";
return code;
}
if (source == SOURCE_2D_TEXTURE && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) {
- String code = " {\n";
if (p_input_vars[0].is_empty()) { // Use UV by default.
-
if (p_input_vars[1].is_empty()) {
- code += " vec4 _tex_read = texture(TEXTURE, " + default_uv + ");\n";
+ code += " " + p_output_vars[0] + " = texture(TEXTURE, " + default_uv + ");\n";
} else {
- code += " vec4 _tex_read = textureLod(TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n";
}
-
} else if (p_input_vars[1].is_empty()) {
//no lod
- code += " vec4 _tex_read = texture(TEXTURE, " + p_input_vars[0] + ");\n";
+ code += " " + p_output_vars[0] + " = texture(TEXTURE, " + p_input_vars[0] + ");\n";
} else {
- code += " vec4 _tex_read = textureLod(TEXTURE, " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(TEXTURE, " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
}
-
- code += " " + p_output_vars[0] + " = _tex_read.rgb;\n";
- code += " " + p_output_vars[1] + " = _tex_read.a;\n";
- code += " }\n";
return code;
}
if (source == SOURCE_2D_NORMAL && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) {
- String code = " {\n";
if (p_input_vars[0].is_empty()) { // Use UV by default.
-
if (p_input_vars[1].is_empty()) {
- code += " vec4 _tex_read = texture(NORMAL_TEXTURE, " + default_uv + ");\n";
+ code += " " + p_output_vars[0] + " = texture(NORMAL_TEXTURE, " + default_uv + ");\n";
} else {
- code += " vec4 _tex_read = textureLod(NORMAL_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(NORMAL_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n";
}
-
} else if (p_input_vars[1].is_empty()) {
//no lod
- code += " vec4 _tex_read = texture(NORMAL_TEXTURE, " + p_input_vars[0] + ".xy);\n";
+ code += " " + p_output_vars[0] + " = texture(NORMAL_TEXTURE, " + p_input_vars[0] + ".xy);\n";
} else {
- code += " vec4 _tex_read = textureLod(NORMAL_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(NORMAL_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n";
}
-
- code += " " + p_output_vars[0] + " = _tex_read.rgb;\n";
- code += " " + p_output_vars[1] + " = _tex_read.a;\n";
- code += " }\n";
return code;
}
- if (p_for_preview) // DEPTH_TEXTURE is not supported in preview(canvas_item) shader
- {
- if (source == SOURCE_DEPTH) {
- String code;
- code += " " + p_output_vars[0] + " = 0.0;\n";
- code += " " + p_output_vars[1] + " = 1.0;\n";
- return code;
- }
- }
-
- if (source == SOURCE_DEPTH && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) {
- String code = " {\n";
- if (p_input_vars[0].is_empty()) { // Use UV by default.
-
- if (p_input_vars[1].is_empty()) {
- code += " float _depth = texture(DEPTH_TEXTURE, " + default_uv + ").r;\n";
+ if (source == SOURCE_DEPTH) {
+ if (!p_for_preview && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) {
+ code += " {\n";
+ if (p_input_vars[0].is_empty()) { // Use UV by default.
+ if (p_input_vars[1].is_empty()) {
+ code += " float _depth = texture(DEPTH_TEXTURE, " + default_uv + ").r;\n";
+ } else {
+ code += " float _depth = textureLod(DEPTH_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ").r;\n";
+ }
+ } else if (p_input_vars[1].is_empty()) {
+ //no lod
+ code += " float _depth = texture(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy).r;\n";
} else {
- code += " float _depth = textureLod(DEPTH_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ").r;\n";
+ code += " float _depth = textureLod(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ").r;\n";
}
- } else if (p_input_vars[1].is_empty()) {
- //no lod
- code += " float _depth = texture(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy).r;\n";
- } else {
- code += " float _depth = textureLod(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ").r;\n";
+ code += " " + p_output_vars[0] + " = vec4(_depth, _depth, _depth, 1.0);\n";
+ code += " }\n";
+ return code;
}
-
- code += " " + p_output_vars[0] + " = _depth;\n";
- code += " " + p_output_vars[1] + " = 1.0;\n";
- code += " }\n";
- return code;
- } else if (source == SOURCE_DEPTH) {
- String code;
- code += " " + p_output_vars[0] + " = 0.0;\n";
- code += " " + p_output_vars[1] + " = 1.0;\n";
- return code;
}
- //none
- String code;
- code += " " + p_output_vars[0] + " = vec3(0.0);\n";
- code += " " + p_output_vars[1] + " = 1.0;\n";
+ code += " " + p_output_vars[0] + " = vec4(0.0);\n";
return code;
}
@@ -1157,15 +1170,15 @@ String VisualShaderNodeSample3D::get_input_port_name(int p_port) const {
}
int VisualShaderNodeSample3D::get_output_port_count() const {
- return 2;
+ return 1;
}
VisualShaderNodeSample3D::PortType VisualShaderNodeSample3D::get_output_port_type(int p_port) const {
- return p_port == 0 ? PORT_TYPE_VECTOR_3D : PORT_TYPE_SCALAR;
+ return p_port == 0 ? PORT_TYPE_VECTOR_4D : PORT_TYPE_SCALAR;
}
String VisualShaderNodeSample3D::get_output_port_name(int p_port) const {
- return p_port == 0 ? "rgb" : "alpha";
+ return "color";
}
bool VisualShaderNodeSample3D::is_output_port_expandable(int p_port) const {
@@ -1195,7 +1208,6 @@ String VisualShaderNodeSample3D::generate_code(Shader::Mode p_mode, VisualShader
String code;
if (source == SOURCE_TEXTURE || source == SOURCE_PORT) {
String id;
- code += " {\n";
if (source == SOURCE_TEXTURE) {
id = make_unique_id(p_type, p_id, "tex3d");
} else {
@@ -1204,27 +1216,22 @@ String VisualShaderNodeSample3D::generate_code(Shader::Mode p_mode, VisualShader
if (!id.is_empty()) {
if (p_input_vars[0].is_empty()) { // Use UV by default.
if (p_input_vars[1].is_empty()) {
- code += " vec4 " + id + "_tex_read = texture(" + id + ", " + default_uv + ");\n";
+ code += " " + p_output_vars[0] + " = texture(" + id + ", " + default_uv + ");\n";
} else {
- code += " vec4 " + id + "_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n";
}
} else if (p_input_vars[1].is_empty()) {
//no lod
- code += " vec4 " + id + "_tex_read = texture(" + id + ", " + p_input_vars[0] + ");\n";
+ code += " " + p_output_vars[0] + " = texture(" + id + ", " + p_input_vars[0] + ");\n";
} else {
- code += " vec4 " + id + "_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
}
} else {
- code += " vec4 " + id + "_tex_read = vec4(0.0);\n";
+ code += " " + p_output_vars[0] + " = vec4(0.0);\n";
}
-
- code += " " + p_output_vars[0] + " = " + id + "_tex_read.rgb;\n";
- code += " " + p_output_vars[1] + " = " + id + "_tex_read.a;\n";
- code += " }\n";
return code;
}
- code += " " + p_output_vars[0] + " = vec3(0.0);\n";
- code += " " + p_output_vars[1] + " = 1.0;\n";
+ code += " " + p_output_vars[0] + " = vec4(0.0);\n";
return code;
}
@@ -1422,15 +1429,15 @@ String VisualShaderNodeCubemap::get_input_port_name(int p_port) const {
}
int VisualShaderNodeCubemap::get_output_port_count() const {
- return 2;
+ return 1;
}
VisualShaderNodeCubemap::PortType VisualShaderNodeCubemap::get_output_port_type(int p_port) const {
- return p_port == 0 ? PORT_TYPE_VECTOR_3D : PORT_TYPE_SCALAR;
+ return PORT_TYPE_VECTOR_4D;
}
String VisualShaderNodeCubemap::get_output_port_name(int p_port) const {
- return p_port == 0 ? "rgb" : "alpha";
+ return "color";
}
bool VisualShaderNodeCubemap::is_output_port_expandable(int p_port) const {
@@ -1456,7 +1463,7 @@ String VisualShaderNodeCubemap::generate_global(Shader::Mode p_mode, VisualShade
case TYPE_DATA:
break;
case TYPE_COLOR:
- u += " : hint_albedo";
+ u += " : source_color";
break;
case TYPE_NORMAL_MAP:
u += " : hint_normal";
@@ -1484,37 +1491,28 @@ String VisualShaderNodeCubemap::generate_code(Shader::Mode p_mode, VisualShader:
} else if (source == SOURCE_PORT) {
id = p_input_vars[2];
} else {
- return String();
+ return code;
}
- code += " {\n";
-
if (id.is_empty()) {
- code += " vec4 " + id + "_read = vec4(0.0);\n";
- code += " " + p_output_vars[0] + " = " + id + "_read.rgb;\n";
- code += " " + p_output_vars[1] + " = " + id + "_read.a;\n";
- code += " }\n";
+ code += " " + p_output_vars[0] + " = vec4(0.0);\n";
return code;
}
if (p_input_vars[0].is_empty()) { // Use UV by default.
if (p_input_vars[1].is_empty()) {
- code += " vec4 " + id + "_read = texture(" + id + ", " + default_uv + ");\n";
+ code += " " + p_output_vars[0] + " = texture(" + id + ", " + default_uv + ");\n";
} else {
- code += " vec4 " + id + "_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + " );\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n";
}
} else if (p_input_vars[1].is_empty()) {
//no lod
- code += " vec4 " + id + "_read = texture(" + id + ", " + p_input_vars[0] + ");\n";
+ code += " " + p_output_vars[0] + " = texture(" + id + ", " + p_input_vars[0] + ");\n";
} else {
- code += " vec4 " + id + "_read = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
}
- code += " " + p_output_vars[0] + " = " + id + "_read.rgb;\n";
- code += " " + p_output_vars[1] + " = " + id + "_read.a;\n";
- code += " }\n";
-
return code;
}
@@ -1891,8 +1889,10 @@ String VisualShaderNodeVectorOp::generate_code(Shader::Mode p_mode, VisualShader
code += "min(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
break;
case OP_CROSS:
- if (op_type == OP_TYPE_VECTOR_2D) { // not supported
+ if (op_type == OP_TYPE_VECTOR_2D) { // Not supported.
code += "vec2(0.0);\n";
+ } else if (op_type == OP_TYPE_VECTOR_4D) { // Not supported.
+ code += "vec4(0.0);\n";
} else {
code += "cross(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
}
@@ -1901,8 +1901,10 @@ String VisualShaderNodeVectorOp::generate_code(Shader::Mode p_mode, VisualShader
code += "atan(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
break;
case OP_REFLECT:
- if (op_type == OP_TYPE_VECTOR_2D) { // not supported
+ if (op_type == OP_TYPE_VECTOR_2D) { // Not supported.
code += "vec2(0.0);\n";
+ } else if (op_type == OP_TYPE_VECTOR_4D) { // Not supported.
+ code += "vec4(0.0);\n";
} else {
code += "reflect(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
}
@@ -1931,6 +1933,10 @@ void VisualShaderNodeVectorOp::set_op_type(OpType p_op_type) {
set_input_port_default_value(0, Vector3(), get_input_port_default_value(0));
set_input_port_default_value(1, Vector3(), get_input_port_default_value(1));
} break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1));
+ } break;
default:
break;
}
@@ -1960,7 +1966,7 @@ Vector<StringName> VisualShaderNodeVectorOp::get_editable_properties() const {
String VisualShaderNodeVectorOp::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
bool invalid_type = false;
- if (op_type == OP_TYPE_VECTOR_2D) {
+ if (op_type == OP_TYPE_VECTOR_2D || op_type == OP_TYPE_VECTOR_4D) {
if (op == OP_CROSS || op == OP_REFLECT) {
invalid_type = true;
}
@@ -2004,6 +2010,10 @@ VisualShaderNodeVectorOp::VisualShaderNodeVectorOp() {
set_input_port_default_value(0, Vector3());
set_input_port_default_value(1, Vector3());
} break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion());
+ set_input_port_default_value(1, Quaternion());
+ } break;
default:
break;
}
@@ -2452,7 +2462,7 @@ void VisualShaderNodeFloatFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeFloatFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeFloatFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc,OneMinus"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Fract,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc,OneMinus"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_SIN);
BIND_ENUM_CONSTANT(FUNC_COS);
@@ -2471,7 +2481,7 @@ void VisualShaderNodeFloatFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_FLOOR);
BIND_ENUM_CONSTANT(FUNC_ROUND);
BIND_ENUM_CONSTANT(FUNC_CEIL);
- BIND_ENUM_CONSTANT(FUNC_FRAC);
+ BIND_ENUM_CONSTANT(FUNC_FRACT);
BIND_ENUM_CONSTANT(FUNC_SATURATE);
BIND_ENUM_CONSTANT(FUNC_NEGATE);
BIND_ENUM_CONSTANT(FUNC_ACOSH);
@@ -2598,8 +2608,6 @@ String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShad
"", // FUNC_SATURATE
"-($)",
"1.0 / ($)",
- "", // FUNC_RGB2HSV
- "", // FUNC_HSV2RGB
"abs($)",
"acos($)",
"acosh($)",
@@ -2636,8 +2644,10 @@ String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShad
if (op_type == OP_TYPE_VECTOR_2D) {
code = "max(min($, vec2(1.0)), vec2(0.0))";
- } else {
+ } else if (op_type == OP_TYPE_VECTOR_3D) {
code = "max(min($, vec3(1.0)), vec3(0.0))";
+ } else {
+ code = "max(min($, vec4(1.0)), vec4(0.0))";
}
return " " + p_output_vars[0] + " = " + code.replace("$", p_input_vars[0]) + ";\n";
}
@@ -2646,44 +2656,16 @@ String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShad
String code;
if (op_type == OP_TYPE_VECTOR_2D) {
- code = "vec2(1.0, 1.0) - $";
+ code = "vec2(1.0) - $";
+ } else if (op_type == OP_TYPE_VECTOR_3D) {
+ code = "vec3(1.0) - $";
} else {
- code = "vec3(1.0, 1.0, 1.0) - $";
+ code = "vec4(1.0) - $";
}
return " " + p_output_vars[0] + " = " + code.replace("$", p_input_vars[0]) + ";\n";
}
- String code;
-
- if (func == FUNC_RGB2HSV) {
- if (op_type == OP_TYPE_VECTOR_2D) { // not supported
- return " " + p_output_vars[0] + " = vec2(0.0);\n";
- }
- code += " {\n";
- code += " vec3 c = " + p_input_vars[0] + ";\n";
- code += " vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n";
- code += " vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n";
- code += " vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n";
- code += " float d = q.x - min(q.w, q.y);\n";
- code += " float e = 1.0e-10;\n";
- code += " " + p_output_vars[0] + " = vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n";
- code += " }\n";
- } else if (func == FUNC_HSV2RGB) {
- if (op_type == OP_TYPE_VECTOR_2D) { // not supported
- return " " + p_output_vars[0] + " = vec2(0.0);\n";
- }
- code += " {\n";
- code += " vec3 c = " + p_input_vars[0] + ";\n";
- code += " vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n";
- code += " vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n";
- code += " " + p_output_vars[0] + " = c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n";
- code += " }\n";
-
- } else {
- code += " " + p_output_vars[0] + " = " + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n";
- }
-
- return code;
+ return " " + p_output_vars[0] + " = " + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n";
}
void VisualShaderNodeVectorFunc::set_op_type(OpType p_op_type) {
@@ -2698,6 +2680,9 @@ void VisualShaderNodeVectorFunc::set_op_type(OpType p_op_type) {
case OP_TYPE_VECTOR_3D: {
set_input_port_default_value(0, Vector3(), get_input_port_default_value(0));
} break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
+ } break;
default:
break;
}
@@ -2710,13 +2695,6 @@ void VisualShaderNodeVectorFunc::set_function(Function p_func) {
if (func == p_func) {
return;
}
- if (p_func == FUNC_RGB2HSV) {
- simple_decl = false;
- } else if (p_func == FUNC_HSV2RGB) {
- simple_decl = false;
- } else {
- simple_decl = true;
- }
func = p_func;
emit_changed();
}
@@ -2731,34 +2709,16 @@ Vector<StringName> VisualShaderNodeVectorFunc::get_editable_properties() const {
return props;
}
-String VisualShaderNodeVectorFunc::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
- bool invalid_type = false;
-
- if (op_type == OP_TYPE_VECTOR_2D) {
- if (func == FUNC_RGB2HSV || func == FUNC_HSV2RGB) {
- invalid_type = true;
- }
- }
-
- if (invalid_type) {
- return RTR("Invalid function for that type.");
- }
-
- return String();
-}
-
void VisualShaderNodeVectorFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,RGB2HSV,HSV2RGB,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Frac,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Fract,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_NORMALIZE);
BIND_ENUM_CONSTANT(FUNC_SATURATE);
BIND_ENUM_CONSTANT(FUNC_NEGATE);
BIND_ENUM_CONSTANT(FUNC_RECIPROCAL);
- BIND_ENUM_CONSTANT(FUNC_RGB2HSV);
- BIND_ENUM_CONSTANT(FUNC_HSV2RGB);
BIND_ENUM_CONSTANT(FUNC_ABS);
BIND_ENUM_CONSTANT(FUNC_ACOS);
BIND_ENUM_CONSTANT(FUNC_ACOSH);
@@ -2773,7 +2733,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_EXP);
BIND_ENUM_CONSTANT(FUNC_EXP2);
BIND_ENUM_CONSTANT(FUNC_FLOOR);
- BIND_ENUM_CONSTANT(FUNC_FRAC);
+ BIND_ENUM_CONSTANT(FUNC_FRACT);
BIND_ENUM_CONSTANT(FUNC_INVERSE_SQRT);
BIND_ENUM_CONSTANT(FUNC_LOG);
BIND_ENUM_CONSTANT(FUNC_LOG2);
@@ -2799,6 +2759,9 @@ VisualShaderNodeVectorFunc::VisualShaderNodeVectorFunc() {
case OP_TYPE_VECTOR_3D: {
set_input_port_default_value(0, Vector3());
} break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion());
+ } break;
default:
break;
}
@@ -2846,6 +2809,25 @@ String VisualShaderNodeColorFunc::generate_code(Shader::Mode p_mode, VisualShade
code += " " + p_output_vars[0] + " = vec3(max2, max2, max2);\n";
code += " }\n";
break;
+ case FUNC_HSV2RGB:
+ code += " {\n";
+ code += " vec3 c = " + p_input_vars[0] + ";\n";
+ code += " vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n";
+ code += " vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n";
+ code += " " + p_output_vars[0] + " = c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n";
+ code += " }\n";
+ break;
+ case FUNC_RGB2HSV:
+ code += " {\n";
+ code += " vec3 c = " + p_input_vars[0] + ";\n";
+ code += " vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n";
+ code += " vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n";
+ code += " vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n";
+ code += " float d = q.x - min(q.w, q.y);\n";
+ code += " float e = 1.0e-10;\n";
+ code += " " + p_output_vars[0] + " = vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n";
+ code += " }\n";
+ break;
case FUNC_SEPIA:
code += " {\n";
code += " vec3 c = " + p_input_vars[0] + ";\n";
@@ -2885,9 +2867,11 @@ void VisualShaderNodeColorFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeColorFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeColorFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Grayscale,Sepia"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Grayscale,HSV2RGB,RGB2HSV,Sepia"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_GRAYSCALE);
+ BIND_ENUM_CONSTANT(FUNC_HSV2RGB);
+ BIND_ENUM_CONSTANT(FUNC_RGB2HSV);
BIND_ENUM_CONSTANT(FUNC_SEPIA);
BIND_ENUM_CONSTANT(FUNC_MAX);
}
@@ -3189,6 +3173,9 @@ void VisualShaderNodeVectorLen::set_op_type(OpType p_op_type) {
case OP_TYPE_VECTOR_3D: {
set_input_port_default_value(0, Vector3(), get_input_port_default_value(0));
} break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
+ } break;
default:
break;
}
@@ -3258,6 +3245,8 @@ VisualShaderNodeDerivativeFunc::PortType VisualShaderNodeDerivativeFunc::get_inp
return PORT_TYPE_VECTOR_2D;
case OP_TYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
default:
break;
}
@@ -3278,6 +3267,8 @@ VisualShaderNodeDerivativeFunc::PortType VisualShaderNodeDerivativeFunc::get_out
return PORT_TYPE_VECTOR_2D;
case OP_TYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
default:
break;
}
@@ -3315,6 +3306,9 @@ void VisualShaderNodeDerivativeFunc::set_op_type(OpType p_op_type) {
case OP_TYPE_VECTOR_3D: {
set_input_port_default_value(0, Vector3(), get_input_port_default_value(0));
} break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
+ } break;
default:
break;
}
@@ -3353,12 +3347,13 @@ void VisualShaderNodeDerivativeFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeDerivativeFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeDerivativeFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector3"), "set_op_type", "get_op_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector3,Vector4"), "set_op_type", "get_op_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sum,X,Y"), "set_function", "get_function");
BIND_ENUM_CONSTANT(OP_TYPE_SCALAR);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D);
+ BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D);
BIND_ENUM_CONSTANT(OP_TYPE_MAX);
BIND_ENUM_CONSTANT(FUNC_SUM);
@@ -3389,6 +3384,8 @@ VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_input_port_type(int p
return PORT_TYPE_VECTOR_2D;
case OP_TYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
default:
break;
}
@@ -3418,6 +3415,8 @@ VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_output_port_type(int
return PORT_TYPE_VECTOR_2D;
case OP_TYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
default:
break;
}
@@ -3458,6 +3457,11 @@ void VisualShaderNodeClamp::set_op_type(OpType p_op_type) {
set_input_port_default_value(1, Vector3(), get_input_port_default_value(1));
set_input_port_default_value(2, Vector3(), get_input_port_default_value(2));
break;
+ case OP_TYPE_VECTOR_4D:
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1));
+ set_input_port_default_value(2, Quaternion(), get_input_port_default_value(2));
+ break;
default:
break;
}
@@ -3479,12 +3483,13 @@ void VisualShaderNodeClamp::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_op_type", "op_type"), &VisualShaderNodeClamp::set_op_type);
ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeClamp::get_op_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector2,Vector3"), "set_op_type", "get_op_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector2,Vector3,Vector4"), "set_op_type", "get_op_type");
BIND_ENUM_CONSTANT(OP_TYPE_FLOAT);
BIND_ENUM_CONSTANT(OP_TYPE_INT);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D);
+ BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D);
BIND_ENUM_CONSTANT(OP_TYPE_MAX);
}
@@ -3541,6 +3546,11 @@ void VisualShaderNodeFaceForward::set_op_type(OpType p_op_type) {
set_input_port_default_value(1, Vector3(), get_input_port_default_value(1));
set_input_port_default_value(2, Vector3(), get_input_port_default_value(2));
} break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1));
+ set_input_port_default_value(2, Quaternion(), get_input_port_default_value(2));
+ } break;
default:
break;
}
@@ -3630,6 +3640,13 @@ VisualShaderNodeStep::PortType VisualShaderNodeStep::get_input_port_type(int p_p
return PORT_TYPE_VECTOR_3D;
}
break;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
+ case OP_TYPE_VECTOR_4D_SCALAR:
+ if (p_port == 1) {
+ return PORT_TYPE_VECTOR_4D;
+ }
+ break;
default:
break;
}
@@ -3660,6 +3677,10 @@ VisualShaderNodeStep::PortType VisualShaderNodeStep::get_output_port_type(int p_
return PORT_TYPE_VECTOR_3D;
case OP_TYPE_VECTOR_3D_SCALAR:
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
+ case OP_TYPE_VECTOR_4D_SCALAR:
+ return PORT_TYPE_VECTOR_4D;
default:
break;
}
@@ -3696,6 +3717,14 @@ void VisualShaderNodeStep::set_op_type(OpType p_op_type) {
set_input_port_default_value(0, 0.0, get_input_port_default_value(0));
set_input_port_default_value(1, Vector3(), get_input_port_default_value(1));
} break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1));
+ } break;
+ case OP_TYPE_VECTOR_4D_SCALAR: {
+ set_input_port_default_value(0, 0.0, get_input_port_default_value(0));
+ set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1));
+ } break;
default:
break;
}
@@ -3721,13 +3750,15 @@ void VisualShaderNodeStep::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_op_type", "op_type"), &VisualShaderNodeStep::set_op_type);
ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeStep::get_op_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector2Scalar,Vector3,Vector3Scalar"), "set_op_type", "get_op_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector2Scalar,Vector3,Vector3Scalar,Vector4,Vector4Scalar"), "set_op_type", "get_op_type");
BIND_ENUM_CONSTANT(OP_TYPE_SCALAR);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D_SCALAR);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D_SCALAR);
+ BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D);
+ BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D_SCALAR);
BIND_ENUM_CONSTANT(OP_TYPE_MAX);
}
@@ -3762,6 +3793,13 @@ VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_input_port_
return PORT_TYPE_VECTOR_3D; // x
}
break;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
+ case OP_TYPE_VECTOR_4D_SCALAR:
+ if (p_port == 2) {
+ return PORT_TYPE_VECTOR_4D; // x
+ }
+ break;
default:
break;
}
@@ -3794,6 +3832,10 @@ VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_output_port
return PORT_TYPE_VECTOR_3D;
case OP_TYPE_VECTOR_3D_SCALAR:
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
+ case OP_TYPE_VECTOR_4D_SCALAR:
+ return PORT_TYPE_VECTOR_4D;
default:
break;
}
@@ -3835,6 +3877,16 @@ void VisualShaderNodeSmoothStep::set_op_type(OpType p_op_type) {
set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); // edge1
set_input_port_default_value(2, Vector3(), get_input_port_default_value(2)); // x
break;
+ case OP_TYPE_VECTOR_4D:
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0)); // edge0
+ set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1)); // edge1
+ set_input_port_default_value(2, Quaternion(), get_input_port_default_value(2)); // x
+ break;
+ case OP_TYPE_VECTOR_4D_SCALAR:
+ set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); // edge0
+ set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); // edge1
+ set_input_port_default_value(2, Quaternion(), get_input_port_default_value(2)); // x
+ break;
default:
break;
}
@@ -3860,13 +3912,15 @@ void VisualShaderNodeSmoothStep::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_op_type", "op_type"), &VisualShaderNodeSmoothStep::set_op_type);
ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeSmoothStep::get_op_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector2Scalar,Vector3,Vector3Scalar"), "set_op_type", "get_op_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector2Scalar,Vector3,Vector3Scalar,Vector4,Vector4Scalar"), "set_op_type", "get_op_type");
BIND_ENUM_CONSTANT(OP_TYPE_SCALAR);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D_SCALAR);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D_SCALAR);
+ BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D);
+ BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D_SCALAR);
BIND_ENUM_CONSTANT(OP_TYPE_MAX);
}
@@ -3922,6 +3976,10 @@ void VisualShaderNodeVectorDistance::set_op_type(OpType p_op_type) {
set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); // a
set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); // b
} break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0)); // a
+ set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1)); // b
+ } break;
default:
break;
}
@@ -4016,6 +4074,13 @@ VisualShaderNodeMix::PortType VisualShaderNodeMix::get_input_port_type(int p_por
break;
}
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
+ case OP_TYPE_VECTOR_4D_SCALAR:
+ if (p_port == 2) {
+ break;
+ }
+ return PORT_TYPE_VECTOR_4D;
default:
break;
}
@@ -4046,6 +4111,10 @@ VisualShaderNodeMix::PortType VisualShaderNodeMix::get_output_port_type(int p_po
return PORT_TYPE_VECTOR_3D;
case OP_TYPE_VECTOR_3D_SCALAR:
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
+ case OP_TYPE_VECTOR_4D_SCALAR:
+ return PORT_TYPE_VECTOR_4D;
default:
break;
}
@@ -4087,6 +4156,16 @@ void VisualShaderNodeMix::set_op_type(OpType p_op_type) {
set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); // b
set_input_port_default_value(2, 0.0, get_input_port_default_value(2)); // weight
} break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0)); // a
+ set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1)); // b
+ set_input_port_default_value(2, Quaternion(), get_input_port_default_value(2)); // weight
+ } break;
+ case OP_TYPE_VECTOR_4D_SCALAR: {
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0)); // a
+ set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1)); // b
+ set_input_port_default_value(2, 0.0, get_input_port_default_value(2)); // weight
+ } break;
default:
break;
}
@@ -4112,13 +4191,15 @@ void VisualShaderNodeMix::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_op_type", "op_type"), &VisualShaderNodeMix::set_op_type);
ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeMix::get_op_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector2Scalar,Vector3,Vector3Scalar"), "set_op_type", "get_op_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector2Scalar,Vector3,Vector3Scalar,Vector4,Vector4Scalar"), "set_op_type", "get_op_type");
BIND_ENUM_CONSTANT(OP_TYPE_SCALAR);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D_SCALAR);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D_SCALAR);
+ BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D);
+ BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D_SCALAR);
BIND_ENUM_CONSTANT(OP_TYPE_MAX);
}
@@ -4140,6 +4221,8 @@ int VisualShaderNodeVectorCompose::get_input_port_count() const {
return 2;
case OP_TYPE_VECTOR_3D:
return 3;
+ case OP_TYPE_VECTOR_4D:
+ return 4;
default:
break;
}
@@ -4170,6 +4253,18 @@ String VisualShaderNodeVectorCompose::get_input_port_name(int p_port) const {
return "z";
}
} break;
+ case OP_TYPE_VECTOR_4D: {
+ switch (p_port) {
+ case 0:
+ return "x";
+ case 1:
+ return "y";
+ case 2:
+ return "z";
+ case 3:
+ return "w";
+ }
+ } break;
default:
break;
}
@@ -4205,6 +4300,15 @@ void VisualShaderNodeVectorCompose::set_op_type(OpType p_op_type) {
set_input_port_default_value(1, p2);
set_input_port_default_value(2, 0.0);
} break;
+ case OP_TYPE_VECTOR_4D: {
+ float p1 = get_input_port_default_value(0);
+ float p2 = get_input_port_default_value(1);
+
+ set_input_port_default_value(0, p1);
+ set_input_port_default_value(1, p2);
+ set_input_port_default_value(2, 0.0);
+ set_input_port_default_value(3, 0.0);
+ } break;
default:
break;
}
@@ -4221,6 +4325,9 @@ String VisualShaderNodeVectorCompose::generate_code(Shader::Mode p_mode, VisualS
case OP_TYPE_VECTOR_3D: {
code += " " + p_output_vars[0] + " = vec3(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n";
} break;
+ case OP_TYPE_VECTOR_4D: {
+ code += " " + p_output_vars[0] + " = vec4(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ", " + p_input_vars[3] + ");\n";
+ } break;
default:
break;
}
@@ -4301,6 +4408,8 @@ int VisualShaderNodeVectorDecompose::get_output_port_count() const {
return 2;
case OP_TYPE_VECTOR_3D:
return 3;
+ case OP_TYPE_VECTOR_4D:
+ return 4;
default:
break;
}
@@ -4331,6 +4440,18 @@ String VisualShaderNodeVectorDecompose::get_output_port_name(int p_port) const {
return "z";
}
} break;
+ case OP_TYPE_VECTOR_4D: {
+ switch (p_port) {
+ case 0:
+ return "x";
+ case 1:
+ return "y";
+ case 2:
+ return "z";
+ case 3:
+ return "w";
+ }
+ } break;
default:
break;
}
@@ -4349,6 +4470,9 @@ void VisualShaderNodeVectorDecompose::set_op_type(OpType p_op_type) {
case OP_TYPE_VECTOR_3D: {
set_input_port_default_value(0, Vector3(), get_input_port_default_value(0));
} break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
+ } break;
default:
break;
}
@@ -4368,6 +4492,12 @@ String VisualShaderNodeVectorDecompose::generate_code(Shader::Mode p_mode, Visua
code += " " + p_output_vars[1] + " = " + p_input_vars[0] + ".y;\n";
code += " " + p_output_vars[2] + " = " + p_input_vars[0] + ".z;\n";
} break;
+ case OP_TYPE_VECTOR_4D: {
+ code += " " + p_output_vars[0] + " = " + p_input_vars[0] + ".x;\n";
+ code += " " + p_output_vars[1] + " = " + p_input_vars[0] + ".y;\n";
+ code += " " + p_output_vars[2] + " = " + p_input_vars[0] + ".z;\n";
+ code += " " + p_output_vars[3] + " = " + p_input_vars[0] + ".w;\n";
+ } break;
default:
break;
}
@@ -4932,7 +5062,7 @@ int VisualShaderNodeColorUniform::get_input_port_count() const {
}
VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_input_port_type(int p_port) const {
- return PORT_TYPE_VECTOR_3D;
+ return PORT_TYPE_SCALAR;
}
String VisualShaderNodeColorUniform::get_input_port_name(int p_port) const {
@@ -4940,15 +5070,22 @@ String VisualShaderNodeColorUniform::get_input_port_name(int p_port) const {
}
int VisualShaderNodeColorUniform::get_output_port_count() const {
- return 2;
+ return 1;
}
VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_output_port_type(int p_port) const {
- return p_port == 0 ? PORT_TYPE_VECTOR_3D : PORT_TYPE_SCALAR;
+ return p_port == 0 ? PORT_TYPE_VECTOR_4D : PORT_TYPE_SCALAR;
}
String VisualShaderNodeColorUniform::get_output_port_name(int p_port) const {
- return p_port == 0 ? "color" : "alpha"; //no output port means the editor will be used as port
+ return "color";
+}
+
+bool VisualShaderNodeColorUniform::is_output_port_expandable(int p_port) const {
+ if (p_port == 0) {
+ return true;
+ }
+ return false;
}
void VisualShaderNodeColorUniform::set_default_value_enabled(bool p_enabled) {
@@ -4976,7 +5113,7 @@ Color VisualShaderNodeColorUniform::get_default_value() const {
}
String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform vec4 " + get_uniform_name() + " : hint_color";
+ String code = _get_qual_str() + "uniform vec4 " + get_uniform_name() + " : source_color";
if (default_value_enabled) {
code += vformat(" = vec4(%.6f, %.6f, %.6f, %.6f)", default_value.r, default_value.g, default_value.b, default_value.a);
}
@@ -4985,9 +5122,7 @@ String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, Visual
}
String VisualShaderNodeColorUniform::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) const {
- String code = " " + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n";
- code += " " + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n";
- return code;
+ return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
}
bool VisualShaderNodeColorUniform::is_show_prop_names() const {
@@ -5225,6 +5360,106 @@ Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const
VisualShaderNodeVec3Uniform::VisualShaderNodeVec3Uniform() {
}
+////////////// Vector4 Uniform
+
+String VisualShaderNodeVec4Uniform::get_caption() const {
+ return "Vector4Uniform";
+}
+
+int VisualShaderNodeVec4Uniform::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeVec4Uniform::PortType VisualShaderNodeVec4Uniform::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR_4D;
+}
+
+String VisualShaderNodeVec4Uniform::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeVec4Uniform::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeVec4Uniform::PortType VisualShaderNodeVec4Uniform::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR_4D;
+}
+
+String VisualShaderNodeVec4Uniform::get_output_port_name(int p_port) const {
+ return ""; // No output port means the editor will be used as port.
+}
+
+void VisualShaderNodeVec4Uniform::set_default_value_enabled(bool p_enabled) {
+ default_value_enabled = p_enabled;
+ emit_changed();
+}
+
+bool VisualShaderNodeVec4Uniform::is_default_value_enabled() const {
+ return default_value_enabled;
+}
+
+void VisualShaderNodeVec4Uniform::set_default_value(const Quaternion &p_value) {
+ default_value = p_value;
+ emit_changed();
+}
+
+Quaternion VisualShaderNodeVec4Uniform::get_default_value() const {
+ return default_value;
+}
+
+String VisualShaderNodeVec4Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform vec4 " + get_uniform_name();
+ if (default_value_enabled) {
+ code += vformat(" = vec4(%.6f, %.6f, %.6f, %.6f)", default_value.x, default_value.y, default_value.z, default_value.w);
+ }
+ code += ";\n";
+ return code;
+}
+
+String VisualShaderNodeVec4Uniform::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) const {
+ return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+}
+
+void VisualShaderNodeVec4Uniform::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec4Uniform::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec4Uniform::is_default_value_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec4Uniform::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec4Uniform::get_default_value);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "default_value"), "set_default_value", "get_default_value");
+}
+
+bool VisualShaderNodeVec4Uniform::is_show_prop_names() const {
+ return true;
+}
+
+bool VisualShaderNodeVec4Uniform::is_use_prop_slots() const {
+ return true;
+}
+
+bool VisualShaderNodeVec4Uniform::is_qualifier_supported(Qualifier p_qual) const {
+ return true; // All qualifiers are supported.
+}
+
+bool VisualShaderNodeVec4Uniform::is_convertible_to_constant() const {
+ return true; // Conversion is allowed.
+}
+
+Vector<StringName> VisualShaderNodeVec4Uniform::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+ props.push_back("default_value_enabled");
+ if (default_value_enabled) {
+ props.push_back("default_value");
+ }
+ return props;
+}
+
+VisualShaderNodeVec4Uniform::VisualShaderNodeVec4Uniform() {
+}
+
////////////// Transform Uniform
String VisualShaderNodeTransformUniform::get_caption() const {
@@ -5276,9 +5511,9 @@ Transform3D VisualShaderNodeTransformUniform::get_default_value() const {
String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform mat4 " + get_uniform_name();
if (default_value_enabled) {
- Vector3 row0 = default_value.basis.get_row(0);
- Vector3 row1 = default_value.basis.get_row(1);
- Vector3 row2 = default_value.basis.get_row(2);
+ Vector3 row0 = default_value.basis.rows[0];
+ Vector3 row1 = default_value.basis.rows[1];
+ Vector3 row2 = default_value.basis.rows[2];
Vector3 origin = default_value.origin;
code += " = mat4(" + vformat("vec4(%.6f, %.6f, %.6f, 0.0)", row0.x, row0.y, row0.z) + vformat(", vec4(%.6f, %.6f, %.6f, 0.0)", row1.x, row1.y, row1.z) + vformat(", vec4(%.6f, %.6f, %.6f, 0.0)", row2.x, row2.y, row2.z) + vformat(", vec4(%.6f, %.6f, %.6f, 1.0)", origin.x, origin.y, origin.z) + ")";
}
@@ -5332,79 +5567,32 @@ Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() c
VisualShaderNodeTransformUniform::VisualShaderNodeTransformUniform() {
}
-////////////// Texture Uniform
-
-String VisualShaderNodeTextureUniform::get_caption() const {
- return "TextureUniform";
-}
-
-int VisualShaderNodeTextureUniform::get_input_port_count() const {
- return 2;
-}
-
-VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_input_port_type(int p_port) const {
- return p_port == 0 ? PORT_TYPE_VECTOR_2D : PORT_TYPE_SCALAR;
-}
-
-String VisualShaderNodeTextureUniform::get_input_port_name(int p_port) const {
- return p_port == 0 ? "uv" : "lod";
-}
-
-int VisualShaderNodeTextureUniform::get_output_port_count() const {
- return 3;
-}
-
-VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_output_port_type(int p_port) const {
- switch (p_port) {
- case 0:
- return PORT_TYPE_VECTOR_3D;
- case 1:
- return PORT_TYPE_SCALAR;
- case 2:
- return PORT_TYPE_SAMPLER;
- default:
- return PORT_TYPE_SCALAR;
- }
-}
-
-String VisualShaderNodeTextureUniform::get_output_port_name(int p_port) const {
- switch (p_port) {
- case 0:
- return "rgb";
- case 1:
- return "alpha";
- case 2:
- return "sampler2D";
- default:
- return "";
- }
-}
+//////////////
-String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_type, VisualShaderNodeTextureUniform::ColorDefault p_color_default, VisualShaderNodeTextureUniform::TextureFilter p_texture_filter, VisualShaderNodeTextureUniform::TextureRepeat p_texture_repeat) {
+ String code;
bool has_colon = false;
- String code = _get_qual_str() + "uniform sampler2D " + get_uniform_name();
// type
{
String type_code;
- switch (texture_type) {
- case TYPE_DATA:
- if (color_default == COLOR_DEFAULT_BLACK) {
- type_code = "hint_black";
+ switch (p_texture_type) {
+ case VisualShaderNodeTextureUniform::TYPE_DATA:
+ if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) {
+ type_code = "hint_default_black";
}
break;
- case TYPE_COLOR:
- if (color_default == COLOR_DEFAULT_BLACK) {
- type_code = "hint_black_albedo";
- } else {
- type_code = "hint_albedo";
+ case VisualShaderNodeTextureUniform::TYPE_COLOR:
+ type_code = "source_color";
+ if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) {
+ type_code += ", hint_default_black";
}
break;
- case TYPE_NORMAL_MAP:
+ case VisualShaderNodeTextureUniform::TYPE_NORMAL_MAP:
type_code = "hint_normal";
break;
- case TYPE_ANISOTROPY:
+ case VisualShaderNodeTextureUniform::TYPE_ANISOTROPY:
type_code = "hint_anisotropy";
break;
default:
@@ -5421,23 +5609,23 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu
{
String filter_code;
- switch (texture_filter) {
- case FILTER_NEAREST:
+ switch (p_texture_filter) {
+ case VisualShaderNodeTextureUniform::FILTER_NEAREST:
filter_code = "filter_nearest";
break;
- case FILTER_LINEAR:
+ case VisualShaderNodeTextureUniform::FILTER_LINEAR:
filter_code = "filter_linear";
break;
- case FILTER_NEAREST_MIPMAP:
+ case VisualShaderNodeTextureUniform::FILTER_NEAREST_MIPMAP:
filter_code = "filter_nearest_mipmap";
break;
- case FILTER_LINEAR_MIPMAP:
+ case VisualShaderNodeTextureUniform::FILTER_LINEAR_MIPMAP:
filter_code = "filter_linear_mipmap";
break;
- case FILTER_NEAREST_MIPMAP_ANISOTROPIC:
+ case VisualShaderNodeTextureUniform::FILTER_NEAREST_MIPMAP_ANISOTROPIC:
filter_code = "filter_nearest_mipmap_anisotropic";
break;
- case FILTER_LINEAR_MIPMAP_ANISOTROPIC:
+ case VisualShaderNodeTextureUniform::FILTER_LINEAR_MIPMAP_ANISOTROPIC:
filter_code = "filter_linear_mipmap_anisotropic";
break;
default:
@@ -5459,11 +5647,11 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu
{
String repeat_code;
- switch (texture_repeat) {
- case REPEAT_ENABLED:
+ switch (p_texture_repeat) {
+ case VisualShaderNodeTextureUniform::REPEAT_ENABLED:
repeat_code = "repeat_enable";
break;
- case REPEAT_DISABLED:
+ case VisualShaderNodeTextureUniform::REPEAT_DISABLED:
repeat_code = "repeat_disable";
break;
default:
@@ -5480,43 +5668,60 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu
}
}
- code += ";\n";
return code;
}
-bool VisualShaderNodeTextureUniform::is_code_generated() const {
- return is_output_port_connected(0) || is_output_port_connected(1); // rgb or alpha
+////////////// Texture Uniform
+
+String VisualShaderNodeTextureUniform::get_caption() const {
+ return "TextureUniform";
+}
+
+int VisualShaderNodeTextureUniform::get_input_port_count() const {
+ return 0;
}
-String VisualShaderNodeTextureUniform::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) const {
- String default_uv;
- if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) {
- default_uv = "UV";
- } else {
- default_uv = "vec2(0.0)";
+VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeTextureUniform::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeTextureUniform::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_output_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_SAMPLER;
+ default:
+ return PORT_TYPE_SCALAR;
}
+}
- String id = get_uniform_name();
- String code = " {\n";
- if (p_input_vars[0].is_empty()) { // Use UV by default.
- if (p_input_vars[1].is_empty()) {
- code += " vec4 n_tex_read = texture(" + id + ", " + default_uv + ");\n";
- } else {
- code += " vec4 n_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n";
- }
- } else if (p_input_vars[1].is_empty()) {
- //no lod
- code += " vec4 n_tex_read = texture(" + id + ", " + p_input_vars[0] + ");\n";
- } else {
- code += " vec4 n_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
+String VisualShaderNodeTextureUniform::get_output_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "sampler2D";
+ default:
+ return "";
}
+}
- code += " " + p_output_vars[0] + " = n_tex_read.rgb;\n";
- code += " " + p_output_vars[1] + " = n_tex_read.a;\n";
- code += " }\n";
+String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform sampler2D " + get_uniform_name();
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += ";\n";
return code;
}
+String VisualShaderNodeTextureUniform::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) const {
+ return "";
+}
+
void VisualShaderNodeTextureUniform::set_texture_type(TextureType p_texture_type) {
ERR_FAIL_INDEX(int(p_texture_type), int(TYPE_MAX));
if (texture_type == p_texture_type) {
@@ -5584,8 +5789,8 @@ bool VisualShaderNodeTextureUniform::is_show_prop_names() const {
return true;
}
-Map<StringName, String> VisualShaderNodeTextureUniform::get_editable_properties_names() const {
- Map<StringName, String> names;
+HashMap<StringName, String> VisualShaderNodeTextureUniform::get_editable_properties_names() const {
+ HashMap<StringName, String> names;
names.insert("texture_type", RTR("Type"));
names.insert("color_default", RTR("Default Color"));
names.insert("texture_filter", RTR("Filter"));
@@ -5636,15 +5841,6 @@ void VisualShaderNodeTextureUniform::_bind_methods() {
BIND_ENUM_CONSTANT(REPEAT_MAX);
}
-bool VisualShaderNodeTextureUniform::is_input_port_default(int p_port, Shader::Mode p_mode) const {
- if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) {
- if (p_port == 0) {
- return true;
- }
- }
- return false;
-}
-
bool VisualShaderNodeTextureUniform::is_qualifier_supported(Qualifier p_qual) const {
switch (p_qual) {
case Qualifier::QUAL_NONE:
@@ -5664,7 +5860,6 @@ bool VisualShaderNodeTextureUniform::is_convertible_to_constant() const {
}
VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() {
- simple_decl = false;
}
////////////// Texture Uniform (Triplanar)
@@ -5677,7 +5872,7 @@ int VisualShaderNodeTextureUniformTriplanar::get_input_port_count() const {
return 2;
}
-VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniformTriplanar::get_input_port_type(int p_port) const {
+VisualShaderNodeTextureUniformTriplanar::PortType VisualShaderNodeTextureUniformTriplanar::get_input_port_type(int p_port) const {
if (p_port == 0 || p_port == 1) {
return PORT_TYPE_VECTOR_3D;
}
@@ -5693,6 +5888,32 @@ String VisualShaderNodeTextureUniformTriplanar::get_input_port_name(int p_port)
return "";
}
+int VisualShaderNodeTextureUniformTriplanar::get_output_port_count() const {
+ return 2;
+}
+
+VisualShaderNodeTextureUniformTriplanar::PortType VisualShaderNodeTextureUniformTriplanar::get_output_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR_4D;
+ case 1:
+ return PORT_TYPE_SAMPLER;
+ default:
+ return PORT_TYPE_SCALAR;
+ }
+}
+
+String VisualShaderNodeTextureUniformTriplanar::get_output_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "color";
+ case 1:
+ return "sampler2D";
+ default:
+ return "";
+ }
+}
+
String VisualShaderNodeTextureUniformTriplanar::generate_global_per_node(Shader::Mode p_mode, int p_id) const {
String code;
@@ -5733,22 +5954,18 @@ String VisualShaderNodeTextureUniformTriplanar::generate_global_per_func(Shader:
String VisualShaderNodeTextureUniformTriplanar::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) const {
String id = get_uniform_name();
- String code = " {\n";
+ String code;
if (p_input_vars[0].is_empty() && p_input_vars[1].is_empty()) {
- code += " vec4 n_tex_read = triplanar_texture(" + id + ", triplanar_power_normal, triplanar_pos);\n";
+ code += " " + p_output_vars[0] + " = triplanar_texture(" + id + ", triplanar_power_normal, triplanar_pos);\n";
} else if (!p_input_vars[0].is_empty() && p_input_vars[1].is_empty()) {
- code += " vec4 n_tex_read = triplanar_texture(" + id + ", " + p_input_vars[0] + ", triplanar_pos);\n";
+ code += " " + p_output_vars[0] + " = triplanar_texture(" + id + ", " + p_input_vars[0] + ", triplanar_pos);\n";
} else if (p_input_vars[0].is_empty() && !p_input_vars[1].is_empty()) {
- code += " vec4 n_tex_read = triplanar_texture(" + id + ", triplanar_power_normal, " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = triplanar_texture(" + id + ", triplanar_power_normal, " + p_input_vars[1] + ");\n";
} else {
- code += " vec4 n_tex_read = triplanar_texture(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = triplanar_texture(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
}
- code += " " + p_output_vars[0] + " = n_tex_read.rgb;\n";
- code += " " + p_output_vars[1] + " = n_tex_read.a;\n";
- code += " }\n";
-
return code;
}
@@ -5770,63 +5987,14 @@ String VisualShaderNodeTexture2DArrayUniform::get_caption() const {
return "Texture2DArrayUniform";
}
-int VisualShaderNodeTexture2DArrayUniform::get_output_port_count() const {
- return 1;
-}
-
-VisualShaderNodeTexture2DArrayUniform::PortType VisualShaderNodeTexture2DArrayUniform::get_output_port_type(int p_port) const {
- return PORT_TYPE_SAMPLER;
-}
-
String VisualShaderNodeTexture2DArrayUniform::get_output_port_name(int p_port) const {
return "sampler2DArray";
}
-int VisualShaderNodeTexture2DArrayUniform::get_input_port_count() const {
- return 0;
-}
-
-VisualShaderNodeTexture2DArrayUniform::PortType VisualShaderNodeTexture2DArrayUniform::get_input_port_type(int p_port) const {
- return PORT_TYPE_SCALAR;
-}
-
-String VisualShaderNodeTexture2DArrayUniform::get_input_port_name(int p_port) const {
- return "";
-}
-
-bool VisualShaderNodeTexture2DArrayUniform::is_input_port_default(int p_port, Shader::Mode p_mode) const {
- return false;
-}
-
String VisualShaderNodeTexture2DArrayUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform sampler2DArray " + get_uniform_name();
-
- switch (texture_type) {
- case TYPE_DATA:
- if (color_default == COLOR_DEFAULT_BLACK) {
- code += " : hint_black;\n";
- } else {
- code += ";\n";
- }
- break;
- case TYPE_COLOR:
- if (color_default == COLOR_DEFAULT_BLACK) {
- code += " : hint_black_albedo;\n";
- } else {
- code += " : hint_albedo;\n";
- }
- break;
- case TYPE_NORMAL_MAP:
- code += " : hint_normal;\n";
- break;
- case TYPE_ANISOTROPY:
- code += " : hint_anisotropy;\n";
- break;
- default:
- code += ";\n";
- break;
- }
-
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += ";\n";
return code;
}
@@ -5843,63 +6011,14 @@ String VisualShaderNodeTexture3DUniform::get_caption() const {
return "Texture3DUniform";
}
-int VisualShaderNodeTexture3DUniform::get_output_port_count() const {
- return 1;
-}
-
-VisualShaderNodeTexture3DUniform::PortType VisualShaderNodeTexture3DUniform::get_output_port_type(int p_port) const {
- return PORT_TYPE_SAMPLER;
-}
-
String VisualShaderNodeTexture3DUniform::get_output_port_name(int p_port) const {
return "sampler3D";
}
-int VisualShaderNodeTexture3DUniform::get_input_port_count() const {
- return 0;
-}
-
-VisualShaderNodeTexture3DUniform::PortType VisualShaderNodeTexture3DUniform::get_input_port_type(int p_port) const {
- return PORT_TYPE_SCALAR;
-}
-
-String VisualShaderNodeTexture3DUniform::get_input_port_name(int p_port) const {
- return "";
-}
-
-bool VisualShaderNodeTexture3DUniform::is_input_port_default(int p_port, Shader::Mode p_mode) const {
- return false;
-}
-
String VisualShaderNodeTexture3DUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform sampler3D " + get_uniform_name();
-
- switch (texture_type) {
- case TYPE_DATA:
- if (color_default == COLOR_DEFAULT_BLACK) {
- code += " : hint_black;\n";
- } else {
- code += ";\n";
- }
- break;
- case TYPE_COLOR:
- if (color_default == COLOR_DEFAULT_BLACK) {
- code += " : hint_black_albedo;\n";
- } else {
- code += " : hint_albedo;\n";
- }
- break;
- case TYPE_NORMAL_MAP:
- code += " : hint_normal;\n";
- break;
- case TYPE_ANISOTROPY:
- code += " : hint_anisotropy;\n";
- break;
- default:
- code += ";\n";
- break;
- }
-
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += ";\n";
return code;
}
@@ -5916,63 +6035,14 @@ String VisualShaderNodeCubemapUniform::get_caption() const {
return "CubemapUniform";
}
-int VisualShaderNodeCubemapUniform::get_output_port_count() const {
- return 1;
-}
-
-VisualShaderNodeCubemapUniform::PortType VisualShaderNodeCubemapUniform::get_output_port_type(int p_port) const {
- return PORT_TYPE_SAMPLER;
-}
-
String VisualShaderNodeCubemapUniform::get_output_port_name(int p_port) const {
return "samplerCube";
}
-int VisualShaderNodeCubemapUniform::get_input_port_count() const {
- return 0;
-}
-
-VisualShaderNodeCubemapUniform::PortType VisualShaderNodeCubemapUniform::get_input_port_type(int p_port) const {
- return PORT_TYPE_SCALAR;
-}
-
-String VisualShaderNodeCubemapUniform::get_input_port_name(int p_port) const {
- return "";
-}
-
-bool VisualShaderNodeCubemapUniform::is_input_port_default(int p_port, Shader::Mode p_mode) const {
- return false;
-}
-
String VisualShaderNodeCubemapUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform samplerCube " + get_uniform_name();
-
- switch (texture_type) {
- case TYPE_DATA:
- if (color_default == COLOR_DEFAULT_BLACK) {
- code += " : hint_black;\n";
- } else {
- code += ";\n";
- }
- break;
- case TYPE_COLOR:
- if (color_default == COLOR_DEFAULT_BLACK) {
- code += " : hint_black_albedo;\n";
- } else {
- code += " : hint_albedo;\n";
- }
- break;
- case TYPE_NORMAL_MAP:
- code += " : hint_normal;\n";
- break;
- case TYPE_ANISOTROPY:
- code += " : hint_anisotropy;\n";
- break;
- default:
- code += ";\n";
- break;
- }
-
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += ";\n";
return code;
}
@@ -6080,6 +6150,8 @@ VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_input_port_type(int
return PORT_TYPE_VECTOR_2D;
case OP_TYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
case OP_TYPE_BOOLEAN:
return PORT_TYPE_BOOLEAN;
case OP_TYPE_TRANSFORM:
@@ -6116,6 +6188,8 @@ VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_output_port_type(in
return PORT_TYPE_VECTOR_2D;
case OP_TYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
case OP_TYPE_BOOLEAN:
return PORT_TYPE_BOOLEAN;
case OP_TYPE_TRANSFORM:
@@ -6152,6 +6226,10 @@ void VisualShaderNodeSwitch::set_op_type(OpType p_op_type) {
set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0), get_input_port_default_value(1));
set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0), get_input_port_default_value(2));
break;
+ case OP_TYPE_VECTOR_4D:
+ set_input_port_default_value(1, Quaternion(1.0, 1.0, 1.0, 1.0), get_input_port_default_value(1));
+ set_input_port_default_value(2, Quaternion(0.0, 0.0, 0.0, 0.0), get_input_port_default_value(2));
+ break;
case OP_TYPE_BOOLEAN:
set_input_port_default_value(1, true);
set_input_port_default_value(2, false);
@@ -6181,12 +6259,13 @@ void VisualShaderNodeSwitch::_bind_methods() { // static
ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeSwitch::set_op_type);
ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeSwitch::get_op_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector2,Vector3,Boolean,Transform"), "set_op_type", "get_op_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector2,Vector3,Vector4,Boolean,Transform"), "set_op_type", "get_op_type");
BIND_ENUM_CONSTANT(OP_TYPE_FLOAT);
BIND_ENUM_CONSTANT(OP_TYPE_INT);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D);
+ BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D);
BIND_ENUM_CONSTANT(OP_TYPE_BOOLEAN);
BIND_ENUM_CONSTANT(OP_TYPE_TRANSFORM);
BIND_ENUM_CONSTANT(OP_TYPE_MAX);
@@ -6420,6 +6499,8 @@ VisualShaderNodeCompare::PortType VisualShaderNodeCompare::get_input_port_type(i
return PORT_TYPE_VECTOR_2D;
case CTYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
+ case CTYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
case CTYPE_BOOLEAN:
return PORT_TYPE_BOOLEAN;
case CTYPE_TRANSFORM:
@@ -6514,6 +6595,12 @@ String VisualShaderNodeCompare::generate_code(Shader::Mode p_mode, VisualShader:
code += " " + p_output_vars[0] + " = " + String(conditions[condition]).replace("$", "_bv") + ";\n";
code += " }\n";
} break;
+ case CTYPE_VECTOR_4D: {
+ code += " {\n";
+ code += " bvec4 _bv = " + String(functions[func]).replace("$", p_input_vars[0] + ", " + p_input_vars[1]) + ";\n";
+ code += " " + p_output_vars[0] + " = " + String(conditions[condition]).replace("$", "_bv") + ";\n";
+ code += " }\n";
+ } break;
case CTYPE_BOOLEAN: {
if (func > FUNC_NOT_EQUAL) {
return " " + p_output_vars[0] + " = false;\n";
@@ -6558,6 +6645,11 @@ void VisualShaderNodeCompare::set_comparison_type(ComparisonType p_comparison_ty
set_input_port_default_value(1, Vector3(), get_input_port_default_value(1));
simple_decl = false;
break;
+ case CTYPE_VECTOR_4D:
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1));
+ simple_decl = false;
+ break;
case CTYPE_BOOLEAN:
set_input_port_default_value(0, false);
set_input_port_default_value(1, false);
@@ -6609,7 +6701,7 @@ Vector<StringName> VisualShaderNodeCompare::get_editable_properties() const {
Vector<StringName> props;
props.push_back("type");
props.push_back("function");
- if (comparison_type == CTYPE_VECTOR_2D || comparison_type == CTYPE_VECTOR_3D) {
+ if (comparison_type == CTYPE_VECTOR_2D || comparison_type == CTYPE_VECTOR_3D || comparison_type == CTYPE_VECTOR_4D) {
props.push_back("condition");
}
return props;
@@ -6625,7 +6717,7 @@ void VisualShaderNodeCompare::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_condition", "condition"), &VisualShaderNodeCompare::set_condition);
ClassDB::bind_method(D_METHOD("get_condition"), &VisualShaderNodeCompare::get_condition);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, "Float,Int,Vector2,Vector3,Boolean,Transform"), "set_comparison_type", "get_comparison_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, "Float,Int,Vector2,Vector3,Vector4,Boolean,Transform"), "set_comparison_type", "get_comparison_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "a == b,a != b,a > b,a >= b,a < b,a <= b"), "set_function", "get_function");
ADD_PROPERTY(PropertyInfo(Variant::INT, "condition", PROPERTY_HINT_ENUM, "All,Any"), "set_condition", "get_condition");
@@ -6633,6 +6725,7 @@ void VisualShaderNodeCompare::_bind_methods() {
BIND_ENUM_CONSTANT(CTYPE_SCALAR_INT);
BIND_ENUM_CONSTANT(CTYPE_VECTOR_2D);
BIND_ENUM_CONSTANT(CTYPE_VECTOR_3D);
+ BIND_ENUM_CONSTANT(CTYPE_VECTOR_4D);
BIND_ENUM_CONSTANT(CTYPE_BOOLEAN);
BIND_ENUM_CONSTANT(CTYPE_TRANSFORM);
BIND_ENUM_CONSTANT(CTYPE_MAX);
@@ -6672,6 +6765,8 @@ VisualShaderNodeMultiplyAdd::PortType VisualShaderNodeMultiplyAdd::get_input_por
return PORT_TYPE_VECTOR_2D;
case OP_TYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
default:
break;
}
@@ -6699,6 +6794,8 @@ VisualShaderNodeMultiplyAdd::PortType VisualShaderNodeMultiplyAdd::get_output_po
return PORT_TYPE_VECTOR_2D;
case OP_TYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
+ case OP_TYPE_VECTOR_4D:
+ return PORT_TYPE_VECTOR_4D;
default:
break;
}
@@ -6734,6 +6831,11 @@ void VisualShaderNodeMultiplyAdd::set_op_type(OpType p_op_type) {
set_input_port_default_value(1, Vector3(), get_input_port_default_value(1));
set_input_port_default_value(2, Vector3(), get_input_port_default_value(2));
} break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1));
+ set_input_port_default_value(2, Quaternion(), get_input_port_default_value(2));
+ } break;
default:
break;
}
@@ -6755,11 +6857,12 @@ void VisualShaderNodeMultiplyAdd::_bind_methods() {
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, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector3"), "set_op_type", "get_op_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector3,Vector4"), "set_op_type", "get_op_type");
BIND_ENUM_CONSTANT(OP_TYPE_SCALAR);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D);
+ BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D);
BIND_ENUM_CONSTANT(OP_TYPE_MAX);
}
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index eeeb91a3ee..1eb7b7240f 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -44,6 +44,7 @@ public:
enum OpType {
OP_TYPE_VECTOR_2D,
OP_TYPE_VECTOR_3D,
+ OP_TYPE_VECTOR_4D,
OP_TYPE_MAX,
};
@@ -280,6 +281,36 @@ public:
///////////////////////////////////////
+class VisualShaderNodeVec4Constant : public VisualShaderNodeConstant {
+ GDCLASS(VisualShaderNodeVec4Constant, VisualShaderNodeConstant);
+ Quaternion constant;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ 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;
+
+ void set_constant(const Quaternion &p_constant);
+ Quaternion get_constant() const;
+
+ virtual Vector<StringName> get_editable_properties() const override;
+
+ VisualShaderNodeVec4Constant();
+};
+
+///////////////////////////////////////
+
class VisualShaderNodeTransformConstant : public VisualShaderNodeConstant {
GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNodeConstant);
Transform3D constant;
@@ -903,7 +934,7 @@ public:
FUNC_FLOOR,
FUNC_ROUND,
FUNC_CEIL,
- FUNC_FRAC,
+ FUNC_FRACT,
FUNC_SATURATE,
FUNC_NEGATE,
FUNC_ACOSH,
@@ -1008,8 +1039,6 @@ public:
FUNC_SATURATE,
FUNC_NEGATE,
FUNC_RECIPROCAL,
- FUNC_RGB2HSV,
- FUNC_HSV2RGB,
FUNC_ABS,
FUNC_ACOS,
FUNC_ACOSH,
@@ -1024,7 +1053,7 @@ public:
FUNC_EXP,
FUNC_EXP2,
FUNC_FLOOR,
- FUNC_FRAC,
+ FUNC_FRACT,
FUNC_INVERSE_SQRT,
FUNC_LOG,
FUNC_LOG2,
@@ -1064,7 +1093,6 @@ public:
Function get_function() const;
virtual Vector<StringName> get_editable_properties() const override;
- String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override;
VisualShaderNodeVectorFunc();
};
@@ -1081,6 +1109,8 @@ class VisualShaderNodeColorFunc : public VisualShaderNode {
public:
enum Function {
FUNC_GRAYSCALE,
+ FUNC_HSV2RGB,
+ FUNC_RGB2HSV,
FUNC_SEPIA,
FUNC_MAX,
};
@@ -1282,6 +1312,7 @@ public:
OP_TYPE_INT,
OP_TYPE_VECTOR_2D,
OP_TYPE_VECTOR_3D,
+ OP_TYPE_VECTOR_4D,
OP_TYPE_MAX,
};
@@ -1324,6 +1355,7 @@ public:
OP_TYPE_SCALAR,
OP_TYPE_VECTOR_2D,
OP_TYPE_VECTOR_3D,
+ OP_TYPE_VECTOR_4D,
OP_TYPE_MAX,
};
@@ -1427,6 +1459,8 @@ public:
OP_TYPE_VECTOR_2D_SCALAR,
OP_TYPE_VECTOR_3D,
OP_TYPE_VECTOR_3D_SCALAR,
+ OP_TYPE_VECTOR_4D,
+ OP_TYPE_VECTOR_4D_SCALAR,
OP_TYPE_MAX,
};
@@ -1471,6 +1505,8 @@ public:
OP_TYPE_VECTOR_2D_SCALAR,
OP_TYPE_VECTOR_3D,
OP_TYPE_VECTOR_3D_SCALAR,
+ OP_TYPE_VECTOR_4D,
+ OP_TYPE_VECTOR_4D_SCALAR,
OP_TYPE_MAX,
};
@@ -1561,6 +1597,8 @@ public:
OP_TYPE_VECTOR_2D_SCALAR,
OP_TYPE_VECTOR_3D,
OP_TYPE_VECTOR_3D_SCALAR,
+ OP_TYPE_VECTOR_4D,
+ OP_TYPE_VECTOR_4D_SCALAR,
OP_TYPE_MAX,
};
@@ -1883,6 +1921,8 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ bool is_output_port_expandable(int p_port) const override;
+
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
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;
@@ -1990,6 +2030,49 @@ public:
///////////////////////////////////////
+class VisualShaderNodeVec4Uniform : public VisualShaderNodeUniform {
+ GDCLASS(VisualShaderNodeVec4Uniform, VisualShaderNodeUniform);
+
+private:
+ bool default_value_enabled = false;
+ Quaternion default_value;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
+ 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;
+
+ virtual bool is_show_prop_names() const override;
+ virtual bool is_use_prop_slots() const override;
+
+ void set_default_value_enabled(bool p_enabled);
+ bool is_default_value_enabled() const;
+
+ void set_default_value(const Quaternion &p_value);
+ Quaternion get_default_value() const;
+
+ bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
+
+ virtual Vector<StringName> get_editable_properties() const override;
+
+ VisualShaderNodeVec4Uniform();
+};
+
+///////////////////////////////////////
+
class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform);
@@ -2084,7 +2167,6 @@ public:
virtual int get_input_port_count() const override;
virtual PortType get_input_port_type(int p_port) const override;
virtual String get_input_port_name(int p_port) const override;
- virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override;
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
@@ -2093,9 +2175,8 @@ public:
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
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;
- virtual Map<StringName, String> get_editable_properties_names() const override;
+ virtual HashMap<StringName, String> get_editable_properties_names() const override;
virtual bool is_show_prop_names() const override;
- virtual bool is_code_generated() const override;
Vector<StringName> get_editable_properties() const override;
@@ -2134,6 +2215,10 @@ public:
virtual PortType get_input_port_type(int p_port) const override;
virtual String get_input_port_name(int p_port) const override;
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override;
virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override;
@@ -2150,16 +2235,8 @@ class VisualShaderNodeTexture2DArrayUniform : public VisualShaderNodeTextureUnif
public:
virtual String get_caption() const override;
-
- virtual int get_input_port_count() const override;
- virtual PortType get_input_port_type(int p_port) const override;
- virtual String get_input_port_name(int p_port) const override;
-
- virtual int get_output_port_count() const override;
- virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
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;
@@ -2173,16 +2250,8 @@ class VisualShaderNodeTexture3DUniform : public VisualShaderNodeTextureUniform {
public:
virtual String get_caption() const override;
-
- virtual int get_input_port_count() const override;
- virtual PortType get_input_port_type(int p_port) const override;
- virtual String get_input_port_name(int p_port) const override;
-
- virtual int get_output_port_count() const override;
- virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
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;
@@ -2196,16 +2265,8 @@ class VisualShaderNodeCubemapUniform : public VisualShaderNodeTextureUniform {
public:
virtual String get_caption() const override;
-
- virtual int get_input_port_count() const override;
- virtual PortType get_input_port_type(int p_port) const override;
- virtual String get_input_port_name(int p_port) const override;
-
- virtual int get_output_port_count() const override;
- virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
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;
@@ -2248,6 +2309,7 @@ public:
OP_TYPE_INT,
OP_TYPE_VECTOR_2D,
OP_TYPE_VECTOR_3D,
+ OP_TYPE_VECTOR_4D,
OP_TYPE_BOOLEAN,
OP_TYPE_TRANSFORM,
OP_TYPE_MAX,
@@ -2362,6 +2424,7 @@ public:
CTYPE_SCALAR_INT,
CTYPE_VECTOR_2D,
CTYPE_VECTOR_3D,
+ CTYPE_VECTOR_4D,
CTYPE_BOOLEAN,
CTYPE_TRANSFORM,
CTYPE_MAX,
@@ -2431,6 +2494,7 @@ public:
OP_TYPE_SCALAR,
OP_TYPE_VECTOR_2D,
OP_TYPE_VECTOR_3D,
+ OP_TYPE_VECTOR_4D,
OP_TYPE_MAX,
};
diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp
index 0879f2e735..bdfbb59fa6 100644
--- a/scene/resources/visual_shader_particle_nodes.cpp
+++ b/scene/resources/visual_shader_particle_nodes.cpp
@@ -74,8 +74,8 @@ Vector<StringName> VisualShaderNodeParticleEmitter::get_editable_properties() co
return props;
}
-Map<StringName, String> VisualShaderNodeParticleEmitter::get_editable_properties_names() const {
- Map<StringName, String> names;
+HashMap<StringName, String> VisualShaderNodeParticleEmitter::get_editable_properties_names() const {
+ HashMap<StringName, String> names;
names.insert("mode_2d", RTR("2D Mode"));
return names;
}
@@ -470,7 +470,7 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector2>
image->set_pixel(i, 0, Color(v.x, v.y, 0));
}
if (r_texture->get_width() != p_array.size() || p_array.size() == 0) {
- r_texture->create_from_image(image);
+ r_texture->set_image(image);
} else {
r_texture->update(image);
}
@@ -491,7 +491,7 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector3>
image->set_pixel(i, 0, Color(v.x, v.y, v.z));
}
if (r_texture->get_width() != p_array.size() || p_array.size() == 0) {
- r_texture->create_from_image(image);
+ r_texture->set_image(image);
} else {
r_texture->update(image);
}
@@ -511,7 +511,7 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Color> &p
image->set_pixel(i, 0, p_array[i]);
}
if (r_texture->get_width() != p_array.size() || p_array.size() == 0) {
- r_texture->create_from_image(image);
+ r_texture->set_image(image);
} else {
r_texture->update(image);
}
@@ -704,8 +704,8 @@ Vector<StringName> VisualShaderNodeParticleMeshEmitter::get_editable_properties(
return props;
}
-Map<StringName, String> VisualShaderNodeParticleMeshEmitter::get_editable_properties_names() const {
- Map<StringName, String> names = VisualShaderNodeParticleEmitter::get_editable_properties_names();
+HashMap<StringName, String> VisualShaderNodeParticleMeshEmitter::get_editable_properties_names() const {
+ HashMap<StringName, String> names = VisualShaderNodeParticleEmitter::get_editable_properties_names();
names.insert("mesh", RTR("Mesh"));
names.insert("use_all_surfaces", RTR("Use All Surfaces"));
diff --git a/scene/resources/visual_shader_particle_nodes.h b/scene/resources/visual_shader_particle_nodes.h
index 0b91cba5e0..05a059373b 100644
--- a/scene/resources/visual_shader_particle_nodes.h
+++ b/scene/resources/visual_shader_particle_nodes.h
@@ -52,7 +52,7 @@ public:
bool is_mode_2d() const;
Vector<StringName> get_editable_properties() const override;
- virtual Map<StringName, String> get_editable_properties_names() const override;
+ virtual HashMap<StringName, String> get_editable_properties_names() const override;
bool is_show_prop_names() const override;
VisualShaderNodeParticleEmitter();
@@ -153,7 +153,7 @@ public:
int get_surface_index() const;
Vector<StringName> get_editable_properties() const override;
- Map<StringName, String> get_editable_properties_names() const override;
+ HashMap<StringName, String> get_editable_properties_names() const override;
Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override;
VisualShaderNodeParticleMeshEmitter();
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index 9d8e0f7547..4dfbe5f079 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -73,8 +73,8 @@ World2D::World2D() {
// Create and configure space2D to be more friendly with pixels than meters
space = PhysicsServer2D::get_singleton()->space_create();
PhysicsServer2D::get_singleton()->space_set_active(space, true);
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/2d/default_gravity", 980.0));
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/2d/default_gravity_vector", Vector2(0, 1)));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_DEF_BASIC("physics/2d/default_gravity", 980.0));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF_BASIC("physics/2d/default_gravity_vector", Vector2(0, 1)));
PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/2d/default_linear_damp", 0.1));
ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/default_linear_damp", PropertyInfo(Variant::FLOAT, "physics/2d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/2d/default_angular_damp", 1.0));
diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h
index 4a277c3d84..c04b8f6461 100644
--- a/scene/resources/world_2d.h
+++ b/scene/resources/world_2d.h
@@ -46,7 +46,7 @@ class World2D : public Resource {
RID space;
RID navigation_map;
- Set<Viewport *> viewports;
+ HashSet<Viewport *> viewports;
protected:
static void _bind_methods();
@@ -62,7 +62,7 @@ public:
PhysicsDirectSpaceState2D *get_direct_space_state();
- _FORCE_INLINE_ const Set<Viewport *> &get_viewports() { return viewports; }
+ _FORCE_INLINE_ const HashSet<Viewport *> &get_viewports() { return viewports; }
World2D();
~World2D();
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
index 0088236112..fb6dcd3d57 100644
--- a/scene/resources/world_3d.cpp
+++ b/scene/resources/world_3d.cpp
@@ -31,7 +31,6 @@
#include "world_3d.h"
#include "core/config/project_settings.h"
-#include "core/math/octree.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/visible_on_screen_notifier_3d.h"
#include "scene/scene_string_names.h"
@@ -141,8 +140,8 @@ World3D::World3D() {
scenario = RenderingServer::get_singleton()->scenario_create();
PhysicsServer3D::get_singleton()->space_set_active(space, true);
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/3d/default_gravity", 9.8));
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/3d/default_gravity_vector", Vector3(0, -1, 0)));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY, GLOBAL_DEF_BASIC("physics/3d/default_gravity", 9.8));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF_BASIC("physics/3d/default_gravity_vector", Vector3(0, -1, 0)));
PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/3d/default_linear_damp", 0.1));
ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/default_linear_damp", PropertyInfo(Variant::FLOAT, "physics/3d/default_linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"));
PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/3d/default_angular_damp", 0.1));
@@ -150,8 +149,8 @@ World3D::World3D() {
navigation_map = NavigationServer3D::get_singleton()->map_create();
NavigationServer3D::get_singleton()->map_set_active(navigation_map, true);
- NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.3));
- NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.3));
+ NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.25));
+ NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.25));
}
World3D::~World3D() {
diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h
index b34b7a2bfb..08bc050349 100644
--- a/scene/resources/world_3d.h
+++ b/scene/resources/world_3d.h
@@ -53,7 +53,7 @@ private:
Ref<Environment> fallback_environment;
Ref<CameraEffects> camera_effects;
- Set<Camera3D *> cameras;
+ HashSet<Camera3D *> cameras;
protected:
static void _bind_methods();
@@ -77,7 +77,7 @@ public:
void set_camera_effects(const Ref<CameraEffects> &p_camera_effects);
Ref<CameraEffects> get_camera_effects() const;
- _FORCE_INLINE_ const Set<Camera3D *> &get_cameras() const { return cameras; }
+ _FORCE_INLINE_ const HashSet<Camera3D *> &get_cameras() const { return cameras; }
PhysicsDirectSpaceState3D *get_direct_space_state();
diff --git a/scene/resources/world_boundary_shape_2d.cpp b/scene/resources/world_boundary_shape_2d.cpp
index ac5be79d24..013ffb9e24 100644
--- a/scene/resources/world_boundary_shape_2d.cpp
+++ b/scene/resources/world_boundary_shape_2d.cpp
@@ -108,7 +108,7 @@ void WorldBoundaryShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_distance"), &WorldBoundaryShape2D::get_distance);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "normal"), "set_normal", "get_normal");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_distance", "get_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:px"), "set_distance", "get_distance");
}
WorldBoundaryShape2D::WorldBoundaryShape2D() :
diff --git a/scene/resources/world_boundary_shape_3d.cpp b/scene/resources/world_boundary_shape_3d.cpp
index 09d41e8291..400cbae217 100644
--- a/scene/resources/world_boundary_shape_3d.cpp
+++ b/scene/resources/world_boundary_shape_3d.cpp
@@ -80,7 +80,7 @@ void WorldBoundaryShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_plane", "plane"), &WorldBoundaryShape3D::set_plane);
ClassDB::bind_method(D_METHOD("get_plane"), &WorldBoundaryShape3D::get_plane);
- ADD_PROPERTY(PropertyInfo(Variant::PLANE, "plane"), "set_plane", "get_plane");
+ ADD_PROPERTY(PropertyInfo(Variant::PLANE, "plane", PROPERTY_HINT_NONE, "suffix:m"), "set_plane", "get_plane");
}
WorldBoundaryShape3D::WorldBoundaryShape3D() :