summaryrefslogtreecommitdiff
path: root/scene/resources
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources')
-rw-r--r--scene/resources/animation.cpp16
-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/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.cpp477
-rw-r--r--scene/resources/curve.h24
-rw-r--r--scene/resources/cylinder_shape_3d.cpp4
-rw-r--r--scene/resources/default_theme/default_theme.cpp91
-rw-r--r--scene/resources/default_theme/default_theme.h2
-rw-r--r--scene/resources/default_theme/popup_menu_arrow_left.svg1
-rw-r--r--scene/resources/default_theme/popup_menu_arrow_right.svg1
-rw-r--r--scene/resources/environment.cpp11
-rw-r--r--scene/resources/fog_material.cpp6
-rw-r--r--scene/resources/font.cpp70
-rw-r--r--scene/resources/font.h12
-rw-r--r--scene/resources/gradient.cpp2
-rw-r--r--scene/resources/gradient.h2
-rw-r--r--scene/resources/immediate_mesh.cpp2
-rw-r--r--scene/resources/importer_mesh.cpp25
-rw-r--r--scene/resources/material.cpp201
-rw-r--r--scene/resources/material.h96
-rw-r--r--scene/resources/mesh.cpp93
-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.cpp100
-rw-r--r--scene/resources/navigation_mesh.h25
-rw-r--r--scene/resources/packed_scene.cpp142
-rw-r--r--scene/resources/packed_scene.h10
-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.cpp921
-rw-r--r--scene/resources/primitive_meshes.h144
-rw-r--r--scene/resources/rectangle_shape_2d.cpp2
-rw-r--r--scene/resources/resource_format_text.cpp233
-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/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.cpp46
-rw-r--r--scene/resources/sprite_frames.h14
-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_line.cpp28
-rw-r--r--scene/resources/text_line.h17
-rw-r--r--scene/resources/text_paragraph.cpp162
-rw-r--r--scene/resources/text_paragraph.h23
-rw-r--r--scene/resources/texture.cpp222
-rw-r--r--scene/resources/texture.h100
-rw-r--r--scene/resources/theme.cpp363
-rw-r--r--scene/resources/theme.h22
-rw-r--r--scene/resources/tile_set.cpp417
-rw-r--r--scene/resources/tile_set.h103
-rw-r--r--scene/resources/visual_shader.cpp651
-rw-r--r--scene/resources/visual_shader.h38
-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.cpp8
-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.cpp8
-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
97 files changed, 4822 insertions, 2210 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index e045a379d2..8ae4872d14 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -3455,7 +3455,7 @@ real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
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 +3481,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 +3531,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 +3827,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/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..c99f71b13e 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -49,6 +49,18 @@ const char *Curve::SIGNAL_RANGE_CHANGED = "range_changed";
Curve::Curve() {
}
+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());
+ }
+ }
+}
+
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
@@ -358,6 +370,7 @@ real_t Curve::interpolate_local_nocheck(int p_index, real_t p_local_offset) cons
void Curve::mark_dirty() {
_baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
+ notify_property_list_changed();
}
Array Curve::get_data() const {
@@ -409,7 +422,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;
@@ -490,8 +502,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 +618,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,6 +631,20 @@ int Curve2D::get_point_count() const {
return points.size();
}
+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();
+ baked_cache_dirty = true;
+ emit_signal(CoreStringNames::get_singleton()->changed);
+ } else {
+ for (int i = p_count - points.size(); i > 0; i--) {
+ add_point(Vector2());
+ }
+ }
+}
+
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;
@@ -546,16 +656,14 @@ 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::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 +675,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 +687,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 {
@@ -592,15 +698,13 @@ Vector2 Curve2D::get_point_out(int p_index) const {
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::clear_points() {
if (!points.is_empty()) {
points.clear();
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
}
@@ -632,7 +736,13 @@ 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);
+ notify_property_list_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);
@@ -681,7 +791,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++) {
@@ -728,15 +839,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 +877,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 +885,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 +918,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 +935,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 +943,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 +981,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.");
@@ -949,7 +1063,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 +1094,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 +1182,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,6 +1198,18 @@ int Curve3D::get_point_count() const {
return points.size();
}
+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());
+ }
+ }
+}
+
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;
@@ -1037,16 +1221,14 @@ 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::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 +1240,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 +1252,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 +1264,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 {
@@ -1096,15 +1275,13 @@ Vector3 Curve3D::get_point_out(int p_index) const {
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::clear_points() {
if (!points.is_empty()) {
points.clear();
- baked_cache_dirty = true;
- emit_signal(CoreStringNames::get_singleton()->changed);
+ mark_dirty();
}
}
@@ -1136,7 +1313,13 @@ 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);
+ notify_property_list_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);
@@ -1194,6 +1377,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);
@@ -1244,16 +1428,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 +1518,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 +1526,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 +1559,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 +1571,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 +1579,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 +1618,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 +1630,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 +1701,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 +1739,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 +1781,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 +1790,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 {
@@ -1635,7 +1848,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 +1877,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 +1982,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..834e7ffa07 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -76,6 +76,8 @@ 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,
@@ -126,6 +128,10 @@ 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();
@@ -164,19 +170,26 @@ 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;
+
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 +241,27 @@ 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;
+
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 eb71401a3a..5fcaf8f2c4 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -177,7 +177,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 +230,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 +252,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 +295,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 +335,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
@@ -582,8 +582,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 +605,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
@@ -649,11 +649,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("unchecked", "PopupMenu", icons["unchecked"]);
theme->set_icon("radio_checked", "PopupMenu", icons["radio_checked"]);
theme->set_icon("radio_unchecked", "PopupMenu", icons["radio_unchecked"]);
- theme->set_icon("submenu", "PopupMenu", icons["arrow_right"]);
- theme->set_icon("submenu_mirrored", "PopupMenu", icons["arrow_left"]);
+ theme->set_icon("submenu", "PopupMenu", icons["popup_menu_arrow_right"]);
+ theme->set_icon("submenu_mirrored", "PopupMenu", icons["popup_menu_arrow_left"]);
theme->set_font("font", "PopupMenu", Ref<Font>());
+ theme->set_font("font_separator", "PopupMenu", Ref<Font>());
theme->set_font_size("font_size", "PopupMenu", -1);
+ theme->set_font_size("font_separator_size", "PopupMenu", -1);
theme->set_color("font_color", "PopupMenu", control_font_color);
theme->set_color("font_accelerator_color", "PopupMenu", Color(0.7, 0.7, 0.7, 0.8));
@@ -661,10 +663,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_hover_color", "PopupMenu", control_font_color);
theme->set_color("font_separator_color", "PopupMenu", control_font_color);
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);
theme->set_constant("item_end_padding", "PopupMenu", 2 * scale);
@@ -682,13 +686,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"]);
@@ -700,6 +706,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
@@ -742,8 +749,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);
@@ -760,8 +767,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);
@@ -842,7 +849,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
@@ -892,7 +899,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
@@ -952,8 +959,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);
@@ -972,16 +979,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));
@@ -997,13 +1004,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);
@@ -1022,7 +1027,7 @@ 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();
@@ -1047,9 +1052,12 @@ void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPos
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_data->set_subpixel_positioning(p_font_subpixel);
+ dynamic_font_data->set_hinting(p_font_hinting);
+ dynamic_font_data->set_antialiased(p_font_antialiased);
+ dynamic_font_data->set_multichannel_signed_distance_field(p_font_msdf);
+ dynamic_font_data->set_generate_mipmaps(p_font_generate_mipmaps);
+
dynamic_font->add_data(dynamic_font_data);
default_font = dynamic_font;
@@ -1059,6 +1067,7 @@ void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPos
bold_font.instantiate();
for (int i = 0; i < default_font->get_data_count(); i++) {
Ref<FontData> data = default_font->get_data(i)->duplicate();
+ // Try to match OpenSans ExtraBold.
data->set_embolden(1.2);
bold_font->add_data(data);
}
@@ -1066,15 +1075,17 @@ void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPos
bold_italics_font.instantiate();
for (int i = 0; i < default_font->get_data_count(); i++) {
Ref<FontData> data = default_font->get_data(i)->duplicate();
+ // Try to match OpenSans ExtraBold Italic.
data->set_embolden(1.2);
- data->set_transform(Transform2D(1.0, 0.4, 0.0, 1.0, 0.0, 0.0));
+ data->set_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
bold_italics_font->add_data(data);
}
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));
+ // Try to match OpenSans Italic.
+ data->set_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
italics_font->add_data(data);
}
}
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/default_theme/popup_menu_arrow_left.svg b/scene/resources/default_theme/popup_menu_arrow_left.svg
new file mode 100644
index 0000000000..8fae265a3b
--- /dev/null
+++ b/scene/resources/default_theme/popup_menu_arrow_left.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" height="16" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 8 16" width="8" xmlns="http://www.w3.org/2000/svg"><path d="m5.4999793 11-3-3 3-3" fill="none" stroke="#b2b2b2" stroke-opacity=".45" stroke-width="2"/></svg>
diff --git a/scene/resources/default_theme/popup_menu_arrow_right.svg b/scene/resources/default_theme/popup_menu_arrow_right.svg
new file mode 100644
index 0000000000..03f05fc46e
--- /dev/null
+++ b/scene/resources/default_theme/popup_menu_arrow_right.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" height="16" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 8 16" width="8" xmlns="http://www.w3.org/2000/svg"><path d="m2.5000207 11 3-3-3-3" fill="none" stroke="#b2b2b2" stroke-opacity=".45" stroke-width="2"/></svg>
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..46f23424dd 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -33,6 +33,7 @@
#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"
@@ -53,7 +54,9 @@ _FORCE_INLINE_ void FontData::_ensure_rid(int p_cache_index) const {
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_face_index(cache[p_cache_index], face_index);
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);
@@ -74,9 +77,17 @@ void FontData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_data", "data"), &FontData::set_data);
ClassDB::bind_method(D_METHOD("get_data"), &FontData::get_data);
+ ClassDB::bind_method(D_METHOD("set_face_index", "face_index"), &FontData::set_face_index);
+ ClassDB::bind_method(D_METHOD("get_face_index"), &FontData::get_face_index);
+
+ ClassDB::bind_method(D_METHOD("get_face_count"), &FontData::get_face_count);
+
ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased);
ClassDB::bind_method(D_METHOD("is_antialiased"), &FontData::is_antialiased);
+ ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "generate_mipmaps"), &FontData::set_generate_mipmaps);
+ ClassDB::bind_method(D_METHOD("get_generate_mipmaps"), &FontData::get_generate_mipmaps);
+
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);
@@ -212,6 +223,8 @@ void FontData::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_supported_variation_list"), &FontData::get_supported_variation_list);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_data", "get_data");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "face_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_face_index", "get_face_index");
+ 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");
@@ -439,9 +452,11 @@ void FontData::reset_state() {
data.clear();
data_ptr = nullptr;
data_size = 0;
+ face_index = 0;
cache.clear();
antialiased = true;
+ mipmaps = false;
msdf = false;
force_autohinter = false;
hinting = TextServer::HINTING_LIGHT;
@@ -735,6 +750,7 @@ Error FontData::load_bitmap_font(const String &p_path) {
reset_state();
antialiased = false;
+ mipmaps = false;
msdf = false;
force_autohinter = false;
hinting = TextServer::HINTING_NONE;
@@ -956,7 +972,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++;
@@ -1236,6 +1252,31 @@ void FontData::set_data(const PackedByteArray &p_data) {
}
}
+void FontData::set_face_index(int64_t p_index) {
+ ERR_FAIL_COND(p_index < 0);
+ ERR_FAIL_COND(p_index >= 0x7FFF);
+
+ if (face_index != p_index) {
+ face_index = p_index;
+ if (data_ptr != nullptr) {
+ for (int i = 0; i < cache.size(); i++) {
+ if (cache[i].is_valid()) {
+ TS->font_set_face_index(cache[i], face_index);
+ }
+ }
+ }
+ }
+}
+
+int64_t FontData::get_face_index() const {
+ return face_index;
+}
+
+int64_t FontData::get_face_count() const {
+ _ensure_rid(0);
+ return TS->font_get_face_count(cache[0]);
+}
+
PackedByteArray FontData::get_data() const {
if (unlikely((size_t)data.size() != data_size)) {
PackedByteArray *data_w = const_cast<PackedByteArray *>(&data);
@@ -1290,6 +1331,21 @@ bool FontData::is_antialiased() const {
return antialiased;
}
+void FontData::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 FontData::get_generate_mipmaps() const {
+ return mipmaps;
+}
+
void FontData::set_multichannel_signed_distance_field(bool p_msdf) {
if (msdf != p_msdf) {
msdf = p_msdf;
@@ -1900,8 +1956,8 @@ void Font::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_spacing", "spacing"), &Font::get_spacing);
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);
+ 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);
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));
@@ -2217,7 +2273,7 @@ Size2 Font::get_string_size(const String &p_text, int p_size, HorizontalAlignmen
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(hash_murmur3_one_float(p_width), hash);
hash = hash_djb2_one_64(p_flags, hash);
}
hash = hash_djb2_one_64(p_size, hash);
@@ -2241,7 +2297,7 @@ Size2 Font::get_multiline_string_size(const String &p_text, float p_width, int p
}
uint64_t hash = p_text.hash64();
- uint64_t wrp_hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash);
+ uint64_t wrp_hash = hash_djb2_one_64(hash_murmur3_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);
@@ -2279,7 +2335,7 @@ void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_t
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(hash_murmur3_one_float(p_width), hash);
hash = hash_djb2_one_64(p_flags, hash);
}
hash = hash_djb2_one_64(p_size, hash);
@@ -2318,7 +2374,7 @@ void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const S
}
uint64_t hash = p_text.hash64();
- uint64_t wrp_hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash);
+ uint64_t wrp_hash = hash_djb2_one_64(hash_murmur3_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);
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 2aa12dd2de..950959e054 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -33,7 +33,7 @@
#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"
@@ -46,9 +46,11 @@ class FontData : public Resource {
// Font source data.
const uint8_t *data_ptr = nullptr;
size_t data_size = 0;
+ int face_index = 0;
PackedByteArray data;
bool antialiased = true;
+ bool mipmaps = false;
bool msdf = false;
int msdf_pixel_range = 16;
int msdf_size = 48;
@@ -90,6 +92,11 @@ public:
virtual void set_data(const PackedByteArray &p_data);
virtual PackedByteArray get_data() const;
+ virtual void set_face_index(int64_t p_index);
+ virtual int64_t get_face_index() const;
+
+ virtual int64_t get_face_count() const;
+
// Common properties.
virtual void set_font_name(const String &p_name);
virtual String get_font_name() const;
@@ -103,6 +110,9 @@ public:
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;
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..a3d3449099 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();
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..71640357b9 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++) {
@@ -706,15 +706,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 +898,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 +960,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 +1023,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);
@@ -1185,7 +1185,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 +1238,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/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..b8c83ac89e 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -161,32 +161,45 @@ 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);
Vector3 *facesw = faces.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;
}
@@ -202,14 +215,30 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
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];
+ }
}
}
}
@@ -455,7 +484,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 +503,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 +528,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 +1856,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 +2096,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 +2121,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..c8bfb73b2d 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 | PROPERTY_USAGE_EDITOR_HELPER));
}
}
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..784ecc3a4d 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;
}
@@ -338,7 +340,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 +358,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;
@@ -484,29 +486,36 @@ 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");
BIND_ENUM_CONSTANT(SAMPLE_PARTITION_WATERSHED);
BIND_ENUM_CONSTANT(SAMPLE_PARTITION_MONOTONE);
@@ -540,4 +549,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..93c1c11876 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;
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index b1c2702a1e..b90f396110 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -33,11 +33,13 @@
#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 "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
@@ -47,14 +49,11 @@ bool SceneState::can_instantiate() const {
}
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 +106,13 @@ 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;
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 +120,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 +132,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 +187,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,6 +226,8 @@ 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);
@@ -243,10 +257,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 +284,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 +335,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 +357,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]) {
@@ -390,7 +430,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 +450,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 +522,36 @@ 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 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);
- if (!pinned_props.has(name) && forced_value.get_type() == Variant::NIL) {
+ 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)) {
@@ -563,11 +606,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 +672,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 +879,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 +913,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());
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 96222937d0..05abb23284 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;
@@ -83,8 +83,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;
@@ -225,7 +225,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..b2fd8eb895 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,8 +435,8 @@ 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");
}
@@ -691,7 +696,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 +745,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 +806,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 +842,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 +897,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 +957,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 +1053,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 +1324,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 +1437,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 +1564,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 +1943,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 +2170,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 +2182,843 @@ void RibbonTrailMesh::_bind_methods() {
RibbonTrailMesh::RibbonTrailMesh() {
}
+
+/*************************************************************************/
+/* TextMesh */
+/*************************************************************************/
+
+void TextMesh::_generate_glyph_mesh_data(uint32_t p_hash, const Glyph &p_gl) const {
+ if (cache.has(p_hash)) {
+ return;
+ }
+
+ GlyphMeshData &gl_data = cache[p_hash];
+
+ 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, opentype_features, language);
+
+ 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, opentype_features);
+ }
+
+ 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()) {
+ uint32_t hash = hash_one_uint64(glyphs[i].font_rid.get_id());
+ hash = hash_murmur3_one_32(glyphs[i].index, hash);
+
+ _generate_glyph_mesh_data(hash, glyphs[i]);
+ GlyphMeshData &gl_data = cache[hash];
+
+ 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()) {
+ uint32_t hash = hash_one_uint64(glyphs[i].font_rid.get_id());
+ hash = hash_murmur3_one_32(glyphs[i].index, hash);
+
+ const GlyphMeshData &gl_data = cache[hash];
+
+ 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_opentype_feature", "tag", "value"), &TextMesh::set_opentype_feature);
+ ClassDB::bind_method(D_METHOD("get_opentype_feature", "tag"), &TextMesh::get_opentype_feature);
+ ClassDB::bind_method(D_METHOD("clear_opentype_features"), &TextMesh::clear_opentype_features);
+
+ 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,127,1,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_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");
+
+ 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("Locale", "");
+ 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");
+}
+
+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;
+ }
+}
+
+bool TextMesh::_set(const StringName &p_name, const Variant &p_value) {
+ String str = p_name;
+ if (str.begins_with("opentype_features/")) {
+ String name = str.get_slicec('/', 1);
+ int32_t tag = TS->name_to_tag(name);
+ int value = p_value;
+ if (value == -1) {
+ if (opentype_features.has(tag)) {
+ opentype_features.erase(tag);
+ dirty_font = true;
+ _request_update();
+ }
+ } else {
+ if (!opentype_features.has(tag) || (int)opentype_features[tag] != value) {
+ opentype_features[tag] = value;
+ dirty_font = true;
+ _request_update();
+ }
+ }
+ notify_property_list_changed();
+ return true;
+ }
+
+ return false;
+}
+
+bool TextMesh::_get(const StringName &p_name, Variant &r_ret) const {
+ String str = p_name;
+ if (str.begins_with("opentype_features/")) {
+ String name = str.get_slicec('/', 1);
+ int32_t tag = TS->name_to_tag(name);
+ if (opentype_features.has(tag)) {
+ r_ret = opentype_features[tag];
+ return true;
+ } else {
+ r_ret = -1;
+ return true;
+ }
+ }
+ return false;
+}
+
+void TextMesh::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (const Variant *ftr = opentype_features.next(nullptr); ftr != nullptr; ftr = opentype_features.next(ftr)) {
+ String name = TS->tag_to_name(*ftr);
+ p_list->push_back(PropertyInfo(Variant::INT, "opentype_features/" + name));
+ }
+ p_list->push_back(PropertyInfo(Variant::NIL, "opentype_features/_new", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+}
+
+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() && font_override->get_data_count() > 0) {
+ 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::clear_opentype_features() {
+ opentype_features.clear();
+ dirty_font = true;
+ _request_update();
+}
+
+void TextMesh::set_opentype_feature(const String &p_name, int p_value) {
+ int32_t tag = TS->name_to_tag(p_name);
+ if (!opentype_features.has(tag) || (int)opentype_features[tag] != p_value) {
+ opentype_features[tag] = p_value;
+ dirty_font = true;
+ _request_update();
+ }
+}
+
+int TextMesh::get_opentype_feature(const String &p_name) const {
+ int32_t tag = TS->name_to_tag(p_name);
+ if (!opentype_features.has(tag)) {
+ return -1;
+ }
+ return opentype_features[tag];
+}
+
+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..38cc7db5fe 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,129 @@ 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 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<uint32_t, GlyphMeshData> 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;
+ Dictionary opentype_features;
+ 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(uint32_t p_hash, 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;
+
+ 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;
+
+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_opentype_feature(const String &p_name, int p_value);
+ int get_opentype_feature(const String &p_name) const;
+ void clear_opentype_features();
+
+ 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 adeca4be9d..dba53338eb 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"
@@ -148,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;
@@ -169,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);
@@ -458,7 +459,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()) {
@@ -533,6 +534,8 @@ Error ResourceLoaderText::load() {
}
}
+ 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
//cached, do not assign
@@ -543,10 +546,17 @@ Error ResourceLoaderText::load() {
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);
@@ -570,6 +580,8 @@ Error ResourceLoaderText::load() {
res->set_scene_unique_id(id);
}
+ Dictionary missing_resource_properties;
+
while (true) {
String assign;
Variant value;
@@ -583,7 +595,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()) {
@@ -597,6 +625,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);
}
@@ -622,13 +658,22 @@ Error ResourceLoaderText::load() {
}
}
+ 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);
@@ -644,6 +689,8 @@ Error ResourceLoaderText::load() {
resource_current++;
+ Dictionary missing_resource_properties;
+
while (true) {
String assign;
Variant value;
@@ -666,7 +713,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;
@@ -674,14 +737,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
@@ -792,7 +865,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;
@@ -888,7 +961,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;
@@ -896,10 +968,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;
}
@@ -1173,7 +1241,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++;
@@ -1235,7 +1303,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++;
@@ -1342,7 +1410,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;
}
@@ -1351,7 +1419,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;
@@ -1368,7 +1436,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>();
}
}
@@ -1378,9 +1446,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");
}
}
@@ -1446,16 +1517,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;
@@ -1485,24 +1567,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
@@ -1513,7 +1595,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;
@@ -1550,7 +1632,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;
@@ -1594,7 +1676,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;
}
@@ -1635,7 +1726,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();
@@ -1656,8 +1747,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("_");
@@ -1673,7 +1764,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;
}
@@ -1695,14 +1786,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;
@@ -1728,10 +1819,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())) {
@@ -1743,8 +1834,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);
@@ -1759,7 +1850,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;
@@ -1771,7 +1862,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);
@@ -1783,12 +1874,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;
@@ -1803,6 +1899,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))) {
@@ -1945,7 +2050,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;
}
@@ -1954,11 +2059,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/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..ba21b9fd17 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();
}
@@ -124,37 +124,37 @@ 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;
+ return E->value.loop;
}
void SpriteFrames::_set_frames(const Array &p_frames) {
clear_all();
- Map<StringName, Anim>::Element *E = animations.find(SceneStringNames::get_singleton()->_default);
+ HashMap<StringName, Anim>::Iterator 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];
+ E->value.frames.resize(p_frames.size());
+ for (int i = 0; i < E->value.frames.size(); i++) {
+ E->value.frames.write[i] = p_frames[i];
}
}
@@ -195,7 +195,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);
}
diff --git a/scene/resources/sprite_frames.h b/scene/resources/sprite_frames.h
index 12b69afde1..e32ccc1336 100644
--- a/scene/resources/sprite_frames.h
+++ b/scene/resources/sprite_frames.h
@@ -42,7 +42,7 @@ class SpriteFrames : public Resource {
Vector<Ref<Texture2D>> frames;
};
- Map<StringName, Anim> animations;
+ HashMap<StringName, Anim> animations;
Array _get_frames() const;
void _set_frames(const Array &p_frames);
@@ -73,24 +73,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_line.cpp b/scene/resources/text_line.cpp
index 337776fd47..d6e7ca3478 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);
@@ -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,26 +106,26 @@ 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) {
+ uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIM;
+ if (overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
switch (overrun_behavior) {
- case OVERRUN_TRIM_WORD_ELLIPSIS:
+ case TextServer::OVERRUN_TRIM_WORD_ELLIPSIS:
overrun_flags |= TextServer::OVERRUN_TRIM;
overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
break;
- case OVERRUN_TRIM_ELLIPSIS:
+ case TextServer::OVERRUN_TRIM_ELLIPSIS:
overrun_flags |= TextServer::OVERRUN_TRIM;
overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
break;
- case OVERRUN_TRIM_WORD:
+ case TextServer::OVERRUN_TRIM_WORD:
overrun_flags |= TextServer::OVERRUN_TRIM;
overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
break;
- case OVERRUN_TRIM_CHAR:
+ case TextServer::OVERRUN_TRIM_CHAR:
overrun_flags |= TextServer::OVERRUN_TRIM;
break;
- case OVERRUN_NO_TRIMMING:
+ case TextServer::OVERRUN_NO_TRIMMING:
break;
}
@@ -259,20 +253,20 @@ uint16_t 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;
}
}
diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h
index c5762db0f2..784ee8ef26 100644
--- a/scene/resources/text_line.h
+++ b/scene/resources/text_line.h
@@ -39,15 +39,6 @@
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;
@@ -58,7 +49,7 @@ private:
float width = -1.0;
uint16_t 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;
@@ -98,8 +89,8 @@ public:
void set_flags(uint16_t p_flags);
uint16_t 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;
@@ -125,6 +116,4 @@ public:
~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..874992ea3d 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -129,17 +129,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();
@@ -190,26 +184,26 @@ void TextParagraph::_shape_lines() {
lines_rid.push_back(line);
}
- uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
- if (overrun_behavior != OVERRUN_NO_TRIMMING) {
+ uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIM;
+ if (overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
switch (overrun_behavior) {
- case OVERRUN_TRIM_WORD_ELLIPSIS:
+ case TextServer::OVERRUN_TRIM_WORD_ELLIPSIS:
overrun_flags |= TextServer::OVERRUN_TRIM;
overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
break;
- case OVERRUN_TRIM_ELLIPSIS:
+ case TextServer::OVERRUN_TRIM_ELLIPSIS:
overrun_flags |= TextServer::OVERRUN_TRIM;
overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
break;
- case OVERRUN_TRIM_WORD:
+ case TextServer::OVERRUN_TRIM_WORD:
overrun_flags |= TextServer::OVERRUN_TRIM;
overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
break;
- case OVERRUN_TRIM_CHAR:
+ case TextServer::OVERRUN_TRIM_CHAR:
overrun_flags |= TextServer::OVERRUN_TRIM;
break;
- case OVERRUN_NO_TRIMMING:
+ case TextServer::OVERRUN_NO_TRIMMING:
break;
}
}
@@ -218,14 +212,14 @@ void TextParagraph::_shape_lines() {
// 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;
}
if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
- for (int i = 0; i < lines_rid.size(); i++) {
- if (i < visible_lines - 1 || lines_rid.size() == 1) {
+ 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, flags);
} else if (i == (visible_lines - 1)) {
TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
@@ -238,7 +232,7 @@ 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;
@@ -258,8 +252,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 +264,11 @@ RID TextParagraph::get_dropcap_rid() const {
}
void TextParagraph::clear() {
+ _THREAD_SAFE_METHOD_
+
spacing_top = 0;
spacing_bottom = 0;
- 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();
@@ -279,57 +277,79 @@ 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) {
+ _THREAD_SAFE_METHOD_
+
ERR_FAIL_COND_V(p_fonts.is_null(), false);
TS->shaped_text_clear(dropcap_rid);
dropcap_margins = p_dropcap_margins;
@@ -339,12 +359,16 @@ bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_fonts,
}
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) {
+ _THREAD_SAFE_METHOD_
+
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);
@@ -362,23 +386,31 @@ int TextParagraph::get_spacing_bottom() const {
}
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,11 +426,15 @@ 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) {
+ _THREAD_SAFE_METHOD_
+
if (flags != p_flags) {
flags = p_flags;
lines_dirty = true;
@@ -409,18 +445,22 @@ uint16_t TextParagraph::get_flags() const {
return 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,6 +472,8 @@ 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);
@@ -441,9 +483,11 @@ Size2 TextParagraph::get_non_wrapped_size() const {
}
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) {
@@ -458,11 +502,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,14 +522,18 @@ 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]);
@@ -495,8 +547,10 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
}
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);
} else {
@@ -505,42 +559,56 @@ Size2 TextParagraph::get_line_size(int p_line) const {
}
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);
+ 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]) + spacing_top;
}
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);
+ 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]) + spacing_bottom;
}
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 +617,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,7 +641,7 @@ 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;
@@ -650,6 +720,8 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
}
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,7 +745,7 @@ 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;
@@ -750,6 +822,8 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
}
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,7 +835,7 @@ 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);
@@ -778,6 +852,8 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
}
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 +876,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,8 +900,10 @@ 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;
@@ -836,8 +916,10 @@ void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, co
}
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) {
@@ -862,7 +944,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..bdcc2b5701 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,7 +47,7 @@ private:
Rect2 dropcap_margins;
RID rid;
- Vector<RID> lines_rid;
+ LocalVector<RID> lines_rid;
int spacing_top = 0;
int spacing_bottom = 0;
@@ -64,7 +57,7 @@ private:
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;
+ TextServer::OverrunBehavior overrun_behavior = TextServer::OVERRUN_NO_TRIMMING;
HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT;
@@ -114,8 +107,8 @@ public:
void set_flags(uint16_t p_flags);
uint16_t 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;
@@ -156,11 +149,11 @@ public:
int hit_test(const Point2 &p_coords) const;
+ Mutex &get_mutex() const { return _thread_safe_; };
+
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);
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..f31a71eada 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -150,33 +150,21 @@ 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;
+ 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) {
@@ -625,7 +613,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 +1046,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 +1054,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 +1404,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 +1412,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 +1533,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 +1705,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 +1727,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 +1749,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 +1775,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 +1794,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 +1942,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");
@@ -2161,7 +2149,7 @@ 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::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 +2237,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 +2266,8 @@ Ref<Image> GradientTexture1D::get_image() const {
return RenderingServer::get_singleton()->texture_2d_get(texture);
}
+//////////////////
+
GradientTexture2D::GradientTexture2D() {
_queue_update();
}
@@ -2299,7 +2289,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 +2401,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 +2411,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 +2505,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 +2826,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);
@@ -3240,7 +3233,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 +3251,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 +3385,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..317756e313 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -287,7 +287,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 +552,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 +673,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 +1011,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..8976aa17d2 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;
}
@@ -1730,7 +1825,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 +1878,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 +1920,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 +1954,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 +2022,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 +2064,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 +2098,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 +2144,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 +2208,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 +2279,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 +2296,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 +2336,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 +2383,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 +2394,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 +2428,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 +2520,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 +2612,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 +2700,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 +2751,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 +3228,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 +3304,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 +3393,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 --
@@ -4279,9 +4402,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
@@ -5120,36 +5243,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 +5437,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 +5599,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 +5675,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,7 +5698,7 @@ 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::INT, "z_index"), "set_z_index", "get_z_index");
@@ -5566,6 +5706,7 @@ void TileData::_bind_methods() {
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..181782e5af 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;
@@ -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();
@@ -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
@@ -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..b8eac6de00 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -74,6 +74,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 +98,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 +123,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 +148,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 +294,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 +345,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 +404,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 +712,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 +732,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 +801,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 +830,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 +1140,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 +1184,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 +1204,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 +1509,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 +1524,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 +1538,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 +1573,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 +1691,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 +1712,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 +1738,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 +1756,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 +1779,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 +1837,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 +1865,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 +1880,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 +1910,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 +1930,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 +1955,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 +1975,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 +1989,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 +2011,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 +2030,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 +2095,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 +2143,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 +2163,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 +2213,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 +2231,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 +2244,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 +2276,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 +2519,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 +2548,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 +2558,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 +2580,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 +2623,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 +2642,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 +2650,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 +2670,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 +2698,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 +2706,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 +2723,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 +2760,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 +2774,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 +2788,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 +2804,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 +2821,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 +2839,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 +2866,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 +2887,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 +2898,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 +2958,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 +2969,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 +3017,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;
@@ -3186,6 +3236,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 +3262,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 +3293,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:
@@ -3311,6 +3367,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 +3438,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 +3569,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 +3602,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 +3755,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 +4467,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 +4608,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 +4626,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 +4788,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..afd84e49cc 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,
@@ -676,9 +670,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..54df935168 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;
}
@@ -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..a84ee773b4 100644
--- a/scene/resources/world_3d.cpp
+++ b/scene/resources/world_3d.cpp
@@ -141,8 +141,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 +150,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() :