diff options
Diffstat (limited to 'scene/resources')
44 files changed, 1080 insertions, 614 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index e045a379d2..a26aa10f42 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; } 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 5d92c3b0c6..2a581fb126 100644 --- a/scene/resources/animation_library.cpp +++ b/scene/resources/animation_library.cpp @@ -30,15 +30,15 @@ #include "animation_library.h" -bool AnimationLibrary::is_valid_name(const String &p_name) { +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("[")); } -String AnimationLibrary::validate_name(const String &p_name) { - if (p_name.is_empty()) { - return "_"; // Should always return a valid name. - } +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++) { @@ -48,7 +48,7 @@ String AnimationLibrary::validate_name(const String &p_name) { } Error AnimationLibrary::add_animation(const StringName &p_name, const Ref<Animation> &p_animation) { - ERR_FAIL_COND_V_MSG(!is_valid_name(p_name), 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)) { @@ -72,7 +72,7 @@ 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(!is_valid_name(p_new_name), "Invalid animation name: '" + String(p_new_name) + "'."); + ERR_FAIL_COND_MSG(!is_valid_animation_name(p_new_name), "Invalid animation name: '" + String(p_new_name) + "'."); ERR_FAIL_COND(animations.has(p_new_name)); animations.insert(p_new_name, animations[p_name]); diff --git a/scene/resources/animation_library.h b/scene/resources/animation_library.h index 0f327fb072..21f0162eb3 100644 --- a/scene/resources/animation_library.h +++ b/scene/resources/animation_library.h @@ -49,8 +49,9 @@ protected: static void _bind_methods(); public: - static bool is_valid_name(const String &p_name); - static String validate_name(const String &p_name); + 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); diff --git a/scene/resources/canvas_item_material.h b/scene/resources/canvas_item_material.h index e40e4392cb..b097d174f0 100644 --- a/scene/resources/canvas_item_material.h +++ b/scene/resources/canvas_item_material.h @@ -107,10 +107,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/curve.cpp b/scene/resources/curve.cpp index 6485c1ac77..c719455a0a 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -681,7 +681,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 +729,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 +767,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 +775,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 +808,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); @@ -829,13 +834,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 +872,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."); @@ -1009,11 +1014,7 @@ void Curve2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); } -Curve2D::Curve2D() { - /* add_point(Vector2(-1,0,0)); - add_point(Vector2(0,2,0)); - add_point(Vector2(0,3,5));*/ -} +Curve2D::Curve2D() {} /***********************************************************************************/ /***********************************************************************************/ @@ -1194,6 +1195,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 +1246,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 +1336,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 +1344,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 +1377,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 +1389,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 +1397,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 +1436,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 +1448,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]; - int idx = Math::floor((double)offset / (double)bake_interval); - real_t frac = Math::fmod(offset, bake_interval) / bake_interval; + 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"); + + 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 +1519,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 +1557,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."); @@ -1705,8 +1738,4 @@ void Curve3D::_bind_methods() { 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/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index f059ec2cf6..271cf61171 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -1026,7 +1026,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(); @@ -1051,9 +1051,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; diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h index a9e21dda3f..f777330a07 100644 --- a/scene/resources/default_theme/default_theme.h +++ b/scene/resources/default_theme/default_theme.h @@ -36,7 +36,7 @@ const int default_font_size = 16; void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &bold_font, const Ref<Font> &bold_italics_font, const Ref<Font> &italics_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale); -void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_subpixel, TextServer::Hinting p_hinting, bool p_aa); +void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_font_subpixel = TextServer::SUBPIXEL_POSITIONING_AUTO, TextServer::Hinting p_font_hinting = TextServer::HINTING_LIGHT, bool p_font_antialiased = true, bool p_font_msdf = false, bool p_font_generate_mipmaps = false); void clear_default_theme(); #endif diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index d92d34437e..5d1e07f6cd 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 diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index d6b2572628..d586abac14 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" @@ -963,7 +964,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++; 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..cca875f708 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -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); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 8e17ff35a9..27e1590940 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); } } @@ -3010,4 +3010,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 99e125f5b0..7edb8b7317 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -449,36 +449,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; @@ -486,29 +486,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; @@ -797,6 +797,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..253ba53c35 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1827,7 +1827,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); @@ -2092,3 +2092,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, ""), "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/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/packed_scene.cpp b/scene/resources/packed_scene.cpp index b991cb1abe..12d1dc9925 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,10 +49,7 @@ 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(); } @@ -113,6 +112,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { 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); @@ -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,6 +335,10 @@ 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) { @@ -324,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]) { @@ -485,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 overriden? 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)) { @@ -566,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) { + // Its a missing node (type non existant 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 @@ -866,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/particles_material.h b/scene/resources/particles_material.h index 57da344ce0..4c3a3ba16c 100644 --- a/scene/resources/particles_material.h +++ b/scene/resources/particles_material.h @@ -230,8 +230,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 +244,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..94e7f46ea5 100644 --- a/scene/resources/polygon_path_finder.cpp +++ b/scene/resources/polygon_path_finder.cpp @@ -137,7 +137,7 @@ 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()) { @@ -161,7 +161,7 @@ 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()) { @@ -489,7 +489,7 @@ 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()) { @@ -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; } diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 40edc5f198..c9a890194d 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -314,7 +314,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 +353,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 +393,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++; diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 8cd05c1740..6b0d5993a1 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -247,7 +247,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 +309,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 +358,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; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index b18456d464..ae321fd9a7 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" @@ -150,7 +151,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R if (ext_resources[id].cache.is_valid()) { r_res = ext_resources[id].cache; } else if (use_sub_threads) { - RES res = ResourceLoader::load_threaded_get(path); + Ref<Resource> res = ResourceLoader::load_threaded_get(path); if (res.is_null()) { if (ResourceLoader::get_abort_on_missing_resources()) { error = ERR_FILE_MISSING_DEPENDENCIES; @@ -171,7 +172,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); @@ -460,7 +461,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()) { @@ -535,6 +536,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 @@ -545,10 +548,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); @@ -572,6 +582,8 @@ Error ResourceLoaderText::load() { res->set_scene_unique_id(id); } + Dictionary missing_resource_properties; + while (true) { String assign; Variant value; @@ -585,7 +597,23 @@ Error ResourceLoaderText::load() { if (!assign.is_empty()) { if (do_assign) { - res->set(assign, value); + bool set_valid = true; + + if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) { + // If the property being set is a missing resource (and the parent is not), + // then setting it will most likely not work. + // Instead, save it as metadata. + + Ref<MissingResource> mr = value; + if (mr.is_valid()) { + missing_resource_properties[assign] = mr; + set_valid = false; + } + } + + if (set_valid) { + res->set(assign, value); + } } //it's assignment } else if (!next_tag.name.is_empty()) { @@ -599,6 +627,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); } @@ -624,13 +660,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); @@ -646,6 +691,8 @@ Error ResourceLoaderText::load() { resource_current++; + Dictionary missing_resource_properties; + while (true) { String assign; Variant value; @@ -668,7 +715,23 @@ Error ResourceLoaderText::load() { } if (!assign.is_empty()) { - resource->set(assign, value); + bool set_valid = true; + + if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) { + // If the property being set is a missing resource (and the parent is not), + // then setting it will most likely not work. + // Instead, save it as metadata. + + Ref<MissingResource> mr = value; + if (mr.is_valid()) { + missing_resource_properties[assign] = mr; + set_valid = false; + } + } + + if (set_valid) { + resource->set(assign, value); + } //it's assignment } else if (!next_tag.name.is_empty()) { error = ERR_FILE_CORRUPT; @@ -676,14 +739,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 @@ -890,7 +963,6 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String fw->store_8(c); c = f->get_8(); } - f.unref(); bool all_ok = fw->get_error() == OK; @@ -898,12 +970,6 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String return ERR_CANT_CREATE; } - fw.unref(); - - Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - da->remove(p_path); - da->rename(p_path + ".depren", p_path); - return OK; } @@ -1334,7 +1400,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; } @@ -1343,7 +1409,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; @@ -1360,7 +1426,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>(); } } @@ -1370,9 +1436,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"); } } @@ -1439,15 +1508,26 @@ void ResourceFormatLoaderText::get_dependencies(const String &p_path, List<Strin } 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 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; @@ -1477,12 +1557,12 @@ 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] + "\" )"; } else { @@ -1505,7 +1585,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; @@ -1542,7 +1622,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; @@ -1586,7 +1666,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; } @@ -1627,7 +1716,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(); @@ -1649,7 +1738,7 @@ 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) { + 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("_"); @@ -1665,7 +1754,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; } @@ -1687,14 +1776,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; @@ -1722,8 +1811,8 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r Set<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())) { @@ -1735,8 +1824,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); @@ -1751,7 +1840,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; @@ -1763,7 +1852,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); @@ -1775,12 +1864,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; @@ -1795,6 +1889,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 overriden? 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))) { @@ -1937,7 +2040,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; } @@ -1946,11 +2049,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..e67df72d7e 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; }; @@ -59,7 +59,7 @@ class ResourceLoaderText { bool ignore_resource_parsing = false; Map<String, ExtResource> ext_resources; - Map<String, RES> int_resources; + Map<String, Ref<Resource>> int_resources; int resources_total = 0; int resource_current = 0; @@ -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; + Map<Ref<Resource>, int> external_resources; + Map<String, Ref<Resource>> rev_external_resources; + Map<Ref<Resource>, int> resource_index_map; + Map<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); @@ -133,7 +133,7 @@ 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; @@ -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; + Map<NonPersistentKey, Ref<Resource>> non_persistent_map; - Set<RES> resource_set; - List<RES> saved_resources; - Map<RES, String> external_resources; - Map<RES, String> internal_resources; + Set<Ref<Resource>> resource_set; + List<Ref<Resource>> saved_resources; + Map<Ref<Resource>, String> external_resources; + Map<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/shader.cpp b/scene/resources/shader.cpp index 25a9278e66..6b1f89454f 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -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..3212dcd287 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -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/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_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/sky_material.cpp b/scene/resources/sky_material.cpp index 4681d3d6e3..7874d77298 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_dither_strength(float p_dither_strength) { + dither_strength = p_dither_strength; + RS::get_singleton()->material_set_param(_get_material(), "dither_strength", dither_strength); +} + +float ProceduralSkyMaterial::get_dither_strength() const { + return dither_strength; +} + 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_dither_strength", "strength"), &ProceduralSkyMaterial::set_dither_strength); + ClassDB::bind_method(D_METHOD("get_dither_strength"), &ProceduralSkyMaterial::get_dither_strength); + 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"); @@ -216,6 +228,9 @@ void ProceduralSkyMaterial::_bind_methods() { 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_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve"); + + ADD_GROUP("", ""); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dither_strength", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_dither_strength", "get_dither_strength"); } void ProceduralSkyMaterial::cleanup_shader() { @@ -247,6 +262,14 @@ 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 float dither_strength : hint_range(0, 10) = 1.0; + +// 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)); +} 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)); + + // Make optional, eliminates banding. + COLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.016 * dither_strength; } )"); } @@ -322,6 +348,7 @@ ProceduralSkyMaterial::ProceduralSkyMaterial() { set_sun_angle_max(30.0); set_sun_curve(0.15); + set_dither_strength(1.0); } ProceduralSkyMaterial::~ProceduralSkyMaterial() { diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h index 5c791a185a..8163a42519 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; + float dither_strength = 0.0f; 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_dither_strength(float p_dither_strength); + float get_dither_strength() 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; + float dither_strength = 0.0f; Ref<Texture2D> night_sky; static void _update_shader(); mutable bool shader_set = false; diff --git a/scene/resources/sphere_shape_3d.h b/scene/resources/sphere_shape_3d.h index ff6d883940..20887dd092 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 = 1.0f; protected: static void _bind_methods(); diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp index ece126791e..ff5a85392c 100644 --- a/scene/resources/sprite_frames.cpp +++ b/scene/resources/sprite_frames.cpp @@ -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/style_box.cpp b/scene/resources/style_box.cpp index fe52761482..f3cb2b9ea7 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -124,8 +124,8 @@ void StyleBox::_bind_methods() { 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_right", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_RIGHT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_BOTTOM); GDVIRTUAL_BIND(_get_style_margin, "side") @@ -316,19 +316,23 @@ void StyleBoxTexture::_bind_methods() { 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_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_RIGHT); 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_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_RIGHT); 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("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("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 +461,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 +555,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 +599,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 +682,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 +734,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 +783,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 +794,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 +808,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 +876,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,6 +900,7 @@ 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); @@ -901,8 +923,8 @@ void StyleBoxFlat::_bind_methods() { 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_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM); ADD_GROUP("Shadow", "shadow_"); 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..0e41eed570 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -1165,7 +1165,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; } diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 4c20e07976..5850d253e3 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -1058,7 +1058,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 +1066,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 +1416,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 +1424,7 @@ RES ResourceFormatLoaderCompressedTexture3D::load(const String &p_path, const St *r_error = err; } if (err != OK) { - return RES(); + return Ref<Resource>(); } return st; @@ -1717,8 +1717,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 +1739,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 +1761,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()); } @@ -2278,6 +2278,8 @@ Ref<Image> GradientTexture1D::get_image() const { return RenderingServer::get_singleton()->texture_2d_get(texture); } +////////////////// + GradientTexture2D::GradientTexture2D() { _queue_update(); } @@ -2299,7 +2301,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 { @@ -3240,7 +3243,7 @@ CompressedTextureLayered::~CompressedTextureLayered() { ///////////////////////////////////////////////// -RES ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { +Ref<Resource> ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { Ref<CompressedTextureLayered> ct; if (p_path.get_extension().to_lower() == "ctexarray") { Ref<CompressedTexture2DArray> c; @@ -3258,14 +3261,14 @@ RES ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, con if (r_error) { *r_error = ERR_FILE_UNRECOGNIZED; } - return RES(); + return Ref<Resource>(); } Error err = ct->load(p_path); if (r_error) { *r_error = err; } if (err != OK) { - return RES(); + return Ref<Resource>(); } return ct; @@ -3392,3 +3395,148 @@ CameraTexture::~CameraTexture() { RenderingServer::get_singleton()->free(_texture); } } + +/////////////////////////// + +void PlaceholderTexture2D::set_size(Size2 p_size) { + size = p_size; +} + +int PlaceholderTexture2D::get_width() const { + return size.width; +} + +int PlaceholderTexture2D::get_height() const { + return size.height; +} + +bool PlaceholderTexture2D::has_alpha() const { + return false; +} + +Ref<Image> PlaceholderTexture2D::get_image() const { + return Ref<Image>(); +} + +RID PlaceholderTexture2D::get_rid() const { + return rid; +} + +void PlaceholderTexture2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTexture2D::set_size); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "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"), "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"), "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..10806aef45 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -123,76 +123,50 @@ 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, HashMap<StringName, Ref<Texture2D>>> &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, HashMap<StringName, Ref<StyleBox>>> &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, HashMap<StringName, Ref<Font>>> &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, HashMap<StringName, int>> &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")); } } - 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, HashMap<StringName, Color>> &E : color_map) { + for (const KeyValue<StringName, Color> &F : E.value) { + list.push_back(PropertyInfo(Variant::INT, 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, HashMap<StringName, int>> &E : constant_map) { + for (const KeyValue<StringName, int> &F : E.value) { + list.push_back(PropertyInfo(Variant::INT, String() + E.key + "/constants/" + F.key)); } } @@ -261,6 +235,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 +321,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 +356,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,14 +388,14 @@ 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; } @@ -409,9 +409,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 +424,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, HashMap<StringName, Ref<Texture2D>>> &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 +466,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,14 +498,14 @@ 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; } @@ -516,9 +519,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 +534,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, HashMap<StringName, Ref<StyleBox>>> &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 +578,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,14 +610,14 @@ 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; } @@ -625,9 +631,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 +646,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, HashMap<StringName, Ref<Font>>> &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 +681,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,14 +709,14 @@ 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; } @@ -725,14 +734,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, HashMap<StringName, int>> &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 +767,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,14 +795,14 @@ 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; } @@ -807,14 +820,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, HashMap<StringName, Color>> &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 +853,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,14 +881,14 @@ 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; } @@ -889,9 +906,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, HashMap<StringName, int>> &E : constant_map) { + p_list->push_back(E.key); } } @@ -1154,6 +1170,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,52 +1264,12 @@ 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; - - // Icons. - while ((key = icon_map.next(key))) { - types.insert(*key); - } - - key = nullptr; - - // StyleBoxes. - while ((key = style_map.next(key))) { - types.insert(*key); - } - - key = nullptr; - - // Fonts. - while ((key = font_map.next(key))) { - types.insert(*key); - } - - key = nullptr; - - // Font sizes. - while ((key = font_size_map.next(key))) { - types.insert(*key); - } - - key = nullptr; - - // Colors. - while ((key = color_map.next(key))) { - types.insert(*key); - } - - key = nullptr; - - // Constants. - while ((key = constant_map.next(key))) { - types.insert(*key); - } - - for (Set<StringName>::Element *E = types.front(); E; E = E->next()) { - p_list->push_back(E->get()); - } + get_icon_type_list(p_list); + get_stylebox_type_list(p_list); + get_font_type_list(p_list); + get_font_size_type_list(p_list); + get_color_type_list(p_list); + get_constant_type_list(p_list); } void Theme::get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variation, List<StringName> *p_list) { @@ -1602,75 +1580,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, HashMap<StringName, Color>> &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, HashMap<StringName, int>> &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, HashMap<StringName, Ref<Font>>> &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, HashMap<StringName, int>> &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, HashMap<StringName, Ref<Texture2D>>> &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, HashMap<StringName, Ref<StyleBox>>> &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 +1645,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, HashMap<StringName, Ref<Texture2D>>> &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 +1656,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, HashMap<StringName, Ref<StyleBox>>> &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 +1667,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, HashMap<StringName, Ref<Font>>> &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)); } } diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 9afe05007d..f8f1e95634 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -137,6 +137,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/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 1368bf0382..6af34a8a82 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -2608,8 +2608,6 @@ String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShad "", // FUNC_SATURATE "-($)", "1.0 / ($)", - "", // FUNC_RGB2HSV - "", // FUNC_HSV2RGB "abs($)", "acos($)", "acosh($)", @@ -2667,43 +2665,7 @@ String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShad 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"; - } - if (op_type == OP_TYPE_VECTOR_4D) { // Not supported. - return " " + p_output_vars[0] + " = vec4(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"; - } - if (op_type == OP_TYPE_VECTOR_4D) { // Not supported. - return " " + p_output_vars[0] + " = vec4(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) { @@ -2733,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(); } @@ -2754,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 || op_type == OP_TYPE_VECTOR_4D) { - 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,Frac,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); @@ -2872,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"; @@ -2911,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); } @@ -5104,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 { @@ -5112,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) { @@ -5157,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 { @@ -5548,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) + ")"; } diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 26c98bd2ea..338f1157d3 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -1039,8 +1039,6 @@ public: FUNC_SATURATE, FUNC_NEGATE, FUNC_RECIPROCAL, - FUNC_RGB2HSV, - FUNC_HSV2RGB, FUNC_ABS, FUNC_ACOS, FUNC_ACOSH, @@ -1095,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(); }; @@ -1112,6 +1109,8 @@ class VisualShaderNodeColorFunc : public VisualShaderNode { public: enum Function { FUNC_GRAYSCALE, + FUNC_HSV2RGB, + FUNC_RGB2HSV, FUNC_SEPIA, FUNC_MAX, }; @@ -1922,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; |