diff options
Diffstat (limited to 'scene/resources')
27 files changed, 417 insertions, 97 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 50f3015814..bfbc92a8d4 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -127,6 +127,10 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { } } return true; + } else if (what == "use_blend") { + if (track_get_type(track) == TYPE_AUDIO) { + audio_track_set_use_blend(track, p_value); + } } else if (what == "interp") { track_set_interpolation_type(track, InterpolationType(p_value.operator int())); } else if (what == "loop_wrap") { @@ -528,7 +532,10 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { } return true; - + } else if (what == "use_blend") { + if (track_get_type(track) == TYPE_AUDIO) { + r_ret = audio_track_is_use_blend(track); + } } else if (what == "interp") { r_ret = track_get_interpolation_type(track); } else if (what == "loop_wrap") { @@ -834,6 +841,9 @@ void Animation::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/loop_wrap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::ARRAY, "tracks/" + itos(i) + "/keys", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); } + if (track_get_type(i) == TYPE_AUDIO) { + p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/use_blend", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); + } } } @@ -3581,6 +3591,27 @@ real_t Animation::audio_track_get_key_end_offset(int p_track, int p_key) const { return at->values[p_key].value.end_offset; } +void Animation::audio_track_set_use_blend(int p_track, bool p_enable) { + ERR_FAIL_INDEX(p_track, tracks.size()); + Track *t = tracks[p_track]; + ERR_FAIL_COND(t->type != TYPE_AUDIO); + + AudioTrack *at = static_cast<AudioTrack *>(t); + + at->use_blend = p_enable; + emit_changed(); +} + +bool Animation::audio_track_is_use_blend(int p_track) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), false); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_AUDIO, false); + + AudioTrack *at = static_cast<AudioTrack *>(t); + + return at->use_blend; +} + // int Animation::animation_track_insert_key(int p_track, double p_time, const StringName &p_animation) { @@ -3813,6 +3844,8 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("audio_track_get_key_stream", "track_idx", "key_idx"), &Animation::audio_track_get_key_stream); ClassDB::bind_method(D_METHOD("audio_track_get_key_start_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_start_offset); ClassDB::bind_method(D_METHOD("audio_track_get_key_end_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_end_offset); + ClassDB::bind_method(D_METHOD("audio_track_set_use_blend", "track_idx", "enable"), &Animation::audio_track_set_use_blend); + ClassDB::bind_method(D_METHOD("audio_track_is_use_blend", "track_idx"), &Animation::audio_track_is_use_blend); ClassDB::bind_method(D_METHOD("animation_track_insert_key", "track_idx", "time", "animation"), &Animation::animation_track_insert_key); ClassDB::bind_method(D_METHOD("animation_track_set_key_animation", "track_idx", "key_idx", "animation"), &Animation::animation_track_set_key_animation); @@ -4691,6 +4724,7 @@ void Animation::compress(uint32_t p_page_size, uint32_t p_fps, float p_split_tol data_tracks.resize(tracks_to_compress.size()); time_tracks.resize(tracks_to_compress.size()); + uint32_t needed_min_page_size = base_page_size; for (uint32_t i = 0; i < data_tracks.size(); i++) { data_tracks[i].split_tolerance = p_split_tolerance; if (track_get_type(tracks_to_compress[i]) == TYPE_BLEND_SHAPE) { @@ -4698,7 +4732,12 @@ void Animation::compress(uint32_t p_page_size, uint32_t p_fps, float p_split_tol } else { data_tracks[i].components = 3; } + needed_min_page_size += data_tracks[i].data.size() + data_tracks[i].get_temp_packet_size(); + } + for (uint32_t i = 0; i < time_tracks.size(); i++) { + needed_min_page_size += time_tracks[i].packets.size() * 4; // time packet is 32 bits } + ERR_FAIL_COND_MSG(p_page_size < needed_min_page_size, "Cannot compress with the given page size"); while (true) { // Begin by finding the keyframe in all tracks with the time closest to the current time diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 00a0761e0a..2c2ddb7095 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -213,6 +213,7 @@ private: struct AudioTrack : public Track { Vector<TKey<AudioKey>> values; + bool use_blend = true; AudioTrack() { type = TYPE_AUDIO; @@ -447,6 +448,8 @@ public: 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; + void audio_track_set_use_blend(int p_track, bool p_enable); + bool audio_track_is_use_blend(int p_track) const; int animation_track_insert_key(int p_track, double p_time, const StringName &p_animation); void animation_track_set_key_animation(int p_track, int p_key, const StringName &p_animation); diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp index 5dc4e64c2e..5309e54846 100644 --- a/scene/resources/capsule_shape_2d.cpp +++ b/scene/resources/capsule_shape_2d.cpp @@ -88,8 +88,10 @@ void CapsuleShape2D::draw(const RID &p_to_rid, const Color &p_color) { Vector<Vector2> points = _get_points(); Vector<Color> col = { p_color }; RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col); + if (is_collision_outline_enabled()) { points.push_back(points[0]); + col = { Color(p_color, 1.0) }; RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col); } } diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp index a15dfc0a54..0b207c33ca 100644 --- a/scene/resources/circle_shape_2d.cpp +++ b/scene/resources/circle_shape_2d.cpp @@ -84,6 +84,7 @@ void CircleShape2D::draw(const RID &p_to_rid, const Color &p_color) { if (is_collision_outline_enabled()) { points.push_back(points[0]); + col = { Color(p_color, 1.0) }; RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col); } } diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp index e51b48a4b1..7f19dd63e6 100644 --- a/scene/resources/convex_polygon_shape_2d.cpp +++ b/scene/resources/convex_polygon_shape_2d.cpp @@ -76,13 +76,14 @@ void ConvexPolygonShape2D::draw(const RID &p_to_rid, const Color &p_color) { return; } - Vector<Color> col; - col.push_back(p_color); + Vector<Color> col = { p_color }; RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col); + if (is_collision_outline_enabled()) { + col = { Color(p_color, 1.0) }; RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col); - // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`. - RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color, 1.0); + // Draw the last segment. + RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], Color(p_color, 1.0)); } } diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index deee187e8e..e5a1adff20 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -2868,6 +2868,12 @@ void SystemFont::_bind_methods() { ClassDB::bind_method(D_METHOD("set_multichannel_signed_distance_field", "msdf"), &SystemFont::set_multichannel_signed_distance_field); ClassDB::bind_method(D_METHOD("is_multichannel_signed_distance_field"), &SystemFont::is_multichannel_signed_distance_field); + ClassDB::bind_method(D_METHOD("set_msdf_pixel_range", "msdf_pixel_range"), &SystemFont::set_msdf_pixel_range); + ClassDB::bind_method(D_METHOD("get_msdf_pixel_range"), &SystemFont::get_msdf_pixel_range); + + ClassDB::bind_method(D_METHOD("set_msdf_size", "msdf_size"), &SystemFont::set_msdf_size); + ClassDB::bind_method(D_METHOD("get_msdf_size"), &SystemFont::get_msdf_size); + ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &SystemFont::set_oversampling); ClassDB::bind_method(D_METHOD("get_oversampling"), &SystemFont::get_oversampling); @@ -2890,6 +2896,8 @@ void SystemFont::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel"), "set_subpixel_positioning", "get_subpixel_positioning"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field"), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_pixel_range"), "set_msdf_pixel_range", "get_msdf_pixel_range"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_size"), "set_msdf_size", "get_msdf_size"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), "set_oversampling", "get_oversampling"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("Font")), "set_fallbacks", "get_fallbacks"); } @@ -2987,6 +2995,8 @@ void SystemFont::_update_base_font() { file->set_hinting(hinting); file->set_subpixel_positioning(subpixel_positioning); file->set_multichannel_signed_distance_field(msdf); + file->set_msdf_pixel_range(msdf_pixel_range); + file->set_msdf_size(msdf_size); file->set_oversampling(oversampling); base_font = file; @@ -3186,6 +3196,34 @@ bool SystemFont::is_multichannel_signed_distance_field() const { return msdf; } +void SystemFont::set_msdf_pixel_range(int p_msdf_pixel_range) { + if (msdf_pixel_range != p_msdf_pixel_range) { + msdf_pixel_range = p_msdf_pixel_range; + if (base_font.is_valid()) { + base_font->set_msdf_pixel_range(msdf_pixel_range); + } + emit_changed(); + } +} + +int SystemFont::get_msdf_pixel_range() const { + return msdf_pixel_range; +} + +void SystemFont::set_msdf_size(int p_msdf_size) { + if (msdf_size != p_msdf_size) { + msdf_size = p_msdf_size; + if (base_font.is_valid()) { + base_font->set_msdf_size(msdf_size); + } + emit_changed(); + } +} + +int SystemFont::get_msdf_size() const { + return msdf_size; +} + void SystemFont::set_oversampling(real_t p_oversampling) { if (oversampling != p_oversampling) { oversampling = p_oversampling; diff --git a/scene/resources/font.h b/scene/resources/font.h index 4d468a8841..ef79f8bd02 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -452,6 +452,8 @@ class SystemFont : public Font { TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; real_t oversampling = 0.f; bool msdf = false; + int msdf_pixel_range = 16; + int msdf_size = 48; protected: static void _bind_methods(); @@ -488,6 +490,12 @@ public: virtual void set_multichannel_signed_distance_field(bool p_msdf); virtual bool is_multichannel_signed_distance_field() const; + virtual void set_msdf_pixel_range(int p_msdf_pixel_range); + virtual int get_msdf_pixel_range() const; + + virtual void set_msdf_size(int p_msdf_size); + virtual int get_msdf_size() const; + virtual void set_font_names(const PackedStringArray &p_names); virtual PackedStringArray get_font_names() const; diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp index 84c147b4b4..65b1653293 100644 --- a/scene/resources/rectangle_shape_2d.cpp +++ b/scene/resources/rectangle_shape_2d.cpp @@ -79,11 +79,7 @@ void RectangleShape2D::draw(const RID &p_to_rid, const Color &p_color) { stroke_points.write[3] = Vector2(-size.x, size.y) * 0.5; stroke_points.write[4] = -size * 0.5; - Vector<Color> stroke_colors; - stroke_colors.resize(5); - for (int i = 0; i < 5; i++) { - stroke_colors.write[i] = (p_color); - } + Vector<Color> stroke_colors = { Color(p_color, 1.0) }; RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, stroke_points, stroke_colors); } diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index a09dbd50cf..fd2be9ba22 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -55,6 +55,12 @@ void Shader::set_path(const String &p_path, bool p_take_over) { RS::get_singleton()->shader_set_path_hint(shader, p_path); } +void Shader::set_include_path(const String &p_path) { + // Used only if the shader does not have a resource path set, + // for example during loading stage or when created by code. + include_path = p_path; +} + void Shader::set_code(const String &p_code) { for (Ref<ShaderInclude> E : include_dependencies) { E->disconnect(SNAME("changed"), callable_mp(this, &Shader::_dependency_changed)); @@ -80,11 +86,15 @@ void Shader::set_code(const String &p_code) { HashSet<Ref<ShaderInclude>> new_include_dependencies; { + String path = get_path(); + if (path.is_empty()) { + path = include_path; + } // Preprocessor must run here and not in the server because: // 1) Need to keep track of include dependencies at resource level // 2) Server does not do interaction with Resource filetypes, this is a scene level feature. ShaderPreprocessor preprocessor; - preprocessor.preprocess(p_code, "", pp_code, nullptr, nullptr, nullptr, &new_include_dependencies); + preprocessor.preprocess(p_code, path, pp_code, nullptr, nullptr, nullptr, &new_include_dependencies); } // This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower) @@ -231,6 +241,7 @@ Ref<Resource> ResourceFormatLoaderShader::load(const String &p_path, const Strin String str; str.parse_utf8((const char *)buffer.ptr(), buffer.size()); + shader->set_include_path(p_path); shader->set_code(str); if (r_error) { diff --git a/scene/resources/shader.h b/scene/resources/shader.h index 55608b6c11..ca889940ef 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -56,6 +56,7 @@ private: Mode mode = MODE_SPATIAL; HashSet<Ref<ShaderInclude>> include_dependencies; String code; + String include_path; HashMap<StringName, HashMap<int, Ref<Texture2D>>> default_textures; @@ -72,6 +73,7 @@ public: virtual Mode get_mode() const; virtual void set_path(const String &p_path, bool p_take_over = false) override; + void set_include_path(const String &p_path); void set_code(const String &p_code); String get_code() const; diff --git a/scene/resources/shader_include.cpp b/scene/resources/shader_include.cpp index cd5e9861f7..68137cbec0 100644 --- a/scene/resources/shader_include.cpp +++ b/scene/resources/shader_include.cpp @@ -45,9 +45,14 @@ void ShaderInclude::set_code(const String &p_code) { } { + String path = get_path(); + if (path.is_empty()) { + path = include_path; + } + String pp_code; ShaderPreprocessor preprocessor; - preprocessor.preprocess(p_code, "", pp_code, nullptr, nullptr, nullptr, &new_dependencies); + preprocessor.preprocess(p_code, path, pp_code, nullptr, nullptr, nullptr, &new_dependencies); } // This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower) @@ -64,6 +69,10 @@ String ShaderInclude::get_code() const { return code; } +void ShaderInclude::set_include_path(const String &p_path) { + include_path = p_path; +} + void ShaderInclude::_bind_methods() { ClassDB::bind_method(D_METHOD("set_code", "code"), &ShaderInclude::set_code); ClassDB::bind_method(D_METHOD("get_code"), &ShaderInclude::get_code); @@ -86,6 +95,7 @@ Ref<Resource> ResourceFormatLoaderShaderInclude::load(const String &p_path, cons String str; str.parse_utf8((const char *)buffer.ptr(), buffer.size()); + shader_inc->set_include_path(p_path); shader_inc->set_code(str); if (r_error) { diff --git a/scene/resources/shader_include.h b/scene/resources/shader_include.h index 04f4f5cf84..a8949b327e 100644 --- a/scene/resources/shader_include.h +++ b/scene/resources/shader_include.h @@ -42,6 +42,7 @@ class ShaderInclude : public Resource { private: String code; + String include_path; HashSet<Ref<ShaderInclude>> dependencies; void _dependency_changed(); @@ -51,6 +52,8 @@ protected: public: void set_code(const String &p_text); String get_code() const; + + void set_include_path(const String &p_path); }; class ResourceFormatLoaderShaderInclude : public ResourceFormatLoader { diff --git a/scene/resources/skeleton_modification_2d_stackholder.cpp b/scene/resources/skeleton_modification_2d_stackholder.cpp index 121108965b..34d31bac8a 100644 --- a/scene/resources/skeleton_modification_2d_stackholder.cpp +++ b/scene/resources/skeleton_modification_2d_stackholder.cpp @@ -64,7 +64,7 @@ bool SkeletonModification2DStackHolder::_get(const StringName &p_path, Variant & } void SkeletonModification2DStackHolder::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::OBJECT, "held_modification_stack", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonModificationStack2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); + p_list->push_back(PropertyInfo(Variant::OBJECT, "held_modification_stack", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonModificationStack2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ALWAYS_DUPLICATE)); #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { diff --git a/scene/resources/skeleton_modification_stack_2d.cpp b/scene/resources/skeleton_modification_stack_2d.cpp index 4fa287e7b6..71ddbc0898 100644 --- a/scene/resources/skeleton_modification_stack_2d.cpp +++ b/scene/resources/skeleton_modification_stack_2d.cpp @@ -37,7 +37,7 @@ void SkeletonModificationStack2D::_get_property_list(List<PropertyInfo> *p_list) PropertyInfo(Variant::OBJECT, "modifications/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "SkeletonModification2D", - PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); + PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_ALWAYS_DUPLICATE)); } } diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp index c101974248..818be38681 100644 --- a/scene/resources/sprite_frames.cpp +++ b/scene/resources/sprite_frames.cpp @@ -36,7 +36,7 @@ void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture2D> &p_t HashMap<StringName, Anim>::Iterator E = animations.find(p_anim); ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); - p_duration = MAX(0.0, p_duration); + p_duration = MAX(SPRITE_FRAME_MINIMUM_DURATION, p_duration); Frame frame = { p_texture, p_duration }; @@ -57,7 +57,7 @@ void SpriteFrames::set_frame(const StringName &p_anim, int p_idx, const Ref<Text return; } - p_duration = MAX(0.0, p_duration); + p_duration = MAX(SPRITE_FRAME_MINIMUM_DURATION, p_duration); Frame frame = { p_texture, p_duration }; @@ -214,7 +214,7 @@ void SpriteFrames::_set_animations(const Array &p_animations) { ERR_CONTINUE(!f.has("texture")); ERR_CONTINUE(!f.has("duration")); - Frame frame = { f["texture"], f["duration"] }; + Frame frame = { f["texture"], MAX(SPRITE_FRAME_MINIMUM_DURATION, (float)f["duration"]) }; anim.frames.push_back(frame); } diff --git a/scene/resources/sprite_frames.h b/scene/resources/sprite_frames.h index 61bead6948..6de2b4a37b 100644 --- a/scene/resources/sprite_frames.h +++ b/scene/resources/sprite_frames.h @@ -33,6 +33,8 @@ #include "scene/resources/texture.h" +static const float SPRITE_FRAME_MINIMUM_DURATION = 0.01; + class SpriteFrames : public Resource { GDCLASS(SpriteFrames, Resource); @@ -89,10 +91,10 @@ public: _FORCE_INLINE_ float get_frame_duration(const StringName &p_anim, int p_idx) const { HashMap<StringName, Anim>::ConstIterator E = animations.find(p_anim); - ERR_FAIL_COND_V_MSG(!E, 0.0, "Animation '" + String(p_anim) + "' doesn't exist."); - ERR_FAIL_COND_V(p_idx < 0, 0.0); + ERR_FAIL_COND_V_MSG(!E, 1.0, "Animation '" + String(p_anim) + "' doesn't exist."); + ERR_FAIL_COND_V(p_idx < 0, 1.0); if (p_idx >= E->value.frames.size()) { - return 0.0; + return 1.0; } return E->value.frames[p_idx].duration; diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 4f16986392..9e0b856ecd 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -151,11 +151,6 @@ void StyleBoxTexture::set_texture(Ref<Texture2D> p_texture) { return; } texture = p_texture; - if (p_texture.is_null()) { - region_rect = Rect2(0, 0, 0, 0); - } else { - region_rect = Rect2(Point2(), texture->get_size()); - } emit_changed(); } @@ -231,22 +226,6 @@ bool StyleBoxTexture::is_draw_center_enabled() const { return draw_center; } -Size2 StyleBoxTexture::get_minimum_size() const { - Size2 min_size = StyleBox::get_minimum_size(); - - // Make sure that the min size is no smaller than the used texture region. - if (texture.is_valid()) { - if (min_size.x < region_rect.size.x) { - min_size.x = region_rect.size.x; - } - if (min_size.y < region_rect.size.y) { - min_size.y = region_rect.size.y; - } - } - - return min_size; -} - void StyleBoxTexture::set_expand_margin(Side p_side, float p_size) { ERR_FAIL_INDEX((int)p_side, 4); expand_margin[p_side] = p_size; @@ -1028,7 +1007,7 @@ void StyleBoxLine::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_begin", PROPERTY_HINT_RANGE, "-300,300,1,suffix:px"), "set_grow_begin", "get_grow_begin"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_end", PROPERTY_HINT_RANGE, "-300,300,1,suffix:px"), "set_grow_end", "get_grow_end"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "thickness", PROPERTY_HINT_RANGE, "0,10,suffix:px"), "set_thickness", "get_thickness"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "thickness", PROPERTY_HINT_RANGE, "0,100,suffix:px"), "set_thickness", "get_thickness"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical"); } diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index 91033617ab..17acfd773e 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -107,8 +107,6 @@ protected: static void _bind_methods(); public: - virtual Size2 get_minimum_size() const override; - void set_expand_margin(Side p_expand_side, float p_size); void set_expand_margin_all(float p_expand_margin_size); void set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom); diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 17e92ddfca..5a2b917b9a 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -146,6 +146,25 @@ uint32_t SurfaceTool::VertexHasher::hash(const Vertex &p_vtx) { return h; } +bool SurfaceTool::SmoothGroupVertex::operator==(const SmoothGroupVertex &p_vertex) const { + if (vertex != p_vertex.vertex) { + return false; + } + + if (smooth_group != p_vertex.smooth_group) { + return false; + } + + return true; +} + +uint32_t SurfaceTool::SmoothGroupVertexHasher::hash(const SmoothGroupVertex &p_vtx) { + uint32_t h = hash_djb2_buffer((const uint8_t *)&p_vtx.vertex, sizeof(real_t) * 3); + h = hash_murmur3_one_32(p_vtx.smooth_group, h); + h = hash_fmix32(h); + return h; +} + uint32_t SurfaceTool::TriangleHasher::hash(const int *p_triangle) { int t0 = p_triangle[0]; int t1 = p_triangle[1]; @@ -1152,7 +1171,7 @@ void SurfaceTool::generate_normals(bool p_flip) { ERR_FAIL_COND((vertex_array.size() % 3) != 0); - HashMap<Vertex, Vector3, VertexHasher> vertex_hash; + HashMap<SmoothGroupVertex, Vector3, SmoothGroupVertexHasher> smooth_hash; for (uint32_t vi = 0; vi < vertex_array.size(); vi += 3) { Vertex *v = &vertex_array[vi]; @@ -1165,21 +1184,28 @@ 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.insert(v[i], normal); + // Add face normal to smooth vertex influence if vertex is member of a smoothing group + if (v[i].smooth_group != UINT32_MAX) { + Vector3 *lv = smooth_hash.getptr(v[i]); + if (!lv) { + smooth_hash.insert(v[i], normal); + } else { + (*lv) += normal; + } } else { - (*lv) += normal; + v[i].normal = normal; } } } for (Vertex &vertex : vertex_array) { - Vector3 *lv = vertex_hash.getptr(vertex); - if (!lv) { - vertex.normal = Vector3(); - } else { - vertex.normal = lv->normalized(); + if (vertex.smooth_group != UINT32_MAX) { + Vector3 *lv = smooth_hash.getptr(vertex); + if (!lv) { + vertex.normal = Vector3(); + } else { + vertex.normal = lv->normalized(); + } } } diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h index 25e078d2ff..00438c4a53 100644 --- a/scene/resources/surface_tool.h +++ b/scene/resources/surface_tool.h @@ -97,6 +97,21 @@ private: static _FORCE_INLINE_ uint32_t hash(const Vertex &p_vtx); }; + struct SmoothGroupVertex { + Vector3 vertex; + uint32_t smooth_group = 0; + bool operator==(const SmoothGroupVertex &p_vertex) const; + + SmoothGroupVertex(const Vertex &p_vertex) { + vertex = p_vertex.vertex; + smooth_group = p_vertex.smooth_group; + }; + }; + + struct SmoothGroupVertexHasher { + static _FORCE_INLINE_ uint32_t hash(const SmoothGroupVertex &p_vtx); + }; + struct TriangleHasher { static _FORCE_INLINE_ uint32_t hash(const int *p_triangle); static _FORCE_INLINE_ bool compare(const int *p_lhs, const int *p_rhs); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 85e21d6056..7e3156d2ff 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -653,7 +653,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si uint32_t mipmaps = f->get_32(); Image::Format format = Image::Format(f->get_32()); - if (data_format == DATA_FORMAT_PNG || data_format == DATA_FORMAT_WEBP || data_format == DATA_FORMAT_BASIS_UNIVERSAL) { + if (data_format == DATA_FORMAT_PNG || data_format == DATA_FORMAT_WEBP) { //look for a PNG or WebP file inside int sw = w; @@ -684,9 +684,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si } Ref<Image> img; - if (data_format == DATA_FORMAT_BASIS_UNIVERSAL && Image::basis_universal_unpacker) { - img = Image::basis_universal_unpacker(pv); - } else if (data_format == DATA_FORMAT_PNG && Image::png_unpacker) { + if (data_format == DATA_FORMAT_PNG && Image::png_unpacker) { img = Image::png_unpacker(pv); } else if (data_format == DATA_FORMAT_WEBP && Image::webp_unpacker) { img = Image::webp_unpacker(pv); @@ -745,6 +743,32 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si return image; } + } else if (data_format == DATA_FORMAT_BASIS_UNIVERSAL) { + int sw = w; + int sh = h; + uint32_t size = f->get_32(); + if (p_size_limit > 0 && (sw > p_size_limit || sh > p_size_limit)) { + //can't load this due to size limit + sw = MAX(sw >> 1, 1); + sh = MAX(sh >> 1, 1); + f->seek(f->get_position() + size); + return Ref<Image>(); + } + Vector<uint8_t> pv; + pv.resize(size); + { + uint8_t *wr = pv.ptrw(); + f->get_buffer(wr, size); + } + Ref<Image> img; + img = Image::basis_universal_unpacker(pv); + if (img.is_null() || img->is_empty()) { + ERR_FAIL_COND_V(img.is_null() || img->is_empty(), Ref<Image>()); + } + format = img->get_format(); + sw = MAX(sw >> 1, 1); + sh = MAX(sh >> 1, 1); + return img; } else if (data_format == DATA_FORMAT_IMAGE) { int size = Image::get_image_data_size(w, h, format, mipmaps ? true : false); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index b5a68ef14b..58a638804d 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -991,6 +991,28 @@ uint32_t TileSet::get_navigation_layer_layers(int p_layer_index) const { return navigation_layers[p_layer_index].layers; } +void TileSet::set_navigation_layer_layer_value(int p_layer_index, int p_layer_number, bool p_value) { + ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive."); + ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive."); + + uint32_t _navigation_layers = get_navigation_layer_layers(p_layer_index); + + if (p_value) { + _navigation_layers |= 1 << (p_layer_number - 1); + } else { + _navigation_layers &= ~(1 << (p_layer_number - 1)); + } + + set_navigation_layer_layers(p_layer_index, _navigation_layers); +} + +bool TileSet::get_navigation_layer_layer_value(int p_layer_index, int p_layer_number) const { + ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive."); + ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive."); + + return get_navigation_layer_layers(p_layer_index) & (1 << (p_layer_number - 1)); +} + // Custom data. int TileSet::get_custom_data_layers_count() const { return custom_data_layers.size(); @@ -2533,6 +2555,11 @@ void TileSet::_compatibility_conversion() { bool flip_v = flags & 2; bool transpose = flags & 4; + Transform2D xform; + xform = flip_h ? xform.scaled(Size2(-1, 1)) : xform; + xform = flip_v ? xform.scaled(Size2(1, -1)) : xform; + xform = transpose ? xform.rotated(Math_PI).scaled(Size2(-1, -1)) : xform; + int alternative_tile = 0; if (!atlas_source->has_tile(coords)) { atlas_source->create_tile(coords); @@ -2569,14 +2596,26 @@ void TileSet::_compatibility_conversion() { if (ctd->occluder.is_valid()) { if (get_occlusion_layers_count() < 1) { add_occlusion_layer(); + }; + Ref<OccluderPolygon2D> occluder = ctd->occluder->duplicate(); + Vector<Vector2> polygon = ctd->occluder->get_polygon(); + for (int index = 0; index < polygon.size(); index++) { + polygon.write[index] = xform.xform(polygon[index] - ctd->region.get_size() / 2.0); } - tile_data->set_occluder(0, ctd->occluder); + occluder->set_polygon(polygon); + tile_data->set_occluder(0, occluder); } if (ctd->navigation.is_valid()) { if (get_navigation_layers_count() < 1) { add_navigation_layer(); } - tile_data->set_navigation_polygon(0, ctd->autotile_navpoly_map[coords]); + Ref<NavigationPolygon> navigation = ctd->navigation->duplicate(); + Vector<Vector2> vertices = navigation->get_vertices(); + for (int index = 0; index < vertices.size(); index++) { + vertices.write[index] = xform.xform(vertices[index] - ctd->region.get_size() / 2.0); + } + navigation->set_vertices(vertices); + tile_data->set_navigation_polygon(0, navigation); } tile_data->set_z_index(ctd->z_index); @@ -2594,7 +2633,7 @@ void TileSet::_compatibility_conversion() { if (convex_shape.is_valid()) { Vector<Vector2> polygon = convex_shape->get_points(); for (int point_index = 0; point_index < polygon.size(); point_index++) { - polygon.write[point_index] = csd.transform.xform(polygon[point_index]); + polygon.write[point_index] = xform.xform(csd.transform.xform(polygon[point_index]) - ctd->region.get_size() / 2.0); } tile_data->set_collision_polygons_count(0, tile_data->get_collision_polygons_count(0) + 1); int index = tile_data->get_collision_polygons_count(0) - 1; @@ -2605,9 +2644,15 @@ void TileSet::_compatibility_conversion() { } } } + // Update the size count. + if (!compatibility_size_count.has(ctd->region.get_size())) { + compatibility_size_count[ctd->region.get_size()] = 0; + } + compatibility_size_count[ctd->region.get_size()]++; } break; case COMPATIBILITY_TILE_MODE_AUTO_TILE: { // Not supported. It would need manual conversion. + WARN_PRINT_ONCE("Could not convert 3.x autotiles to 4.x. This operation cannot be done automatically, autotiles must be re-created using the terrain system."); } break; case COMPATIBILITY_TILE_MODE_ATLAS_TILE: { atlas_source->set_margins(ctd->region.get_position()); @@ -2624,6 +2669,11 @@ void TileSet::_compatibility_conversion() { bool flip_v = flags & 2; bool transpose = flags & 4; + Transform2D xform; + xform = flip_h ? xform.scaled(Size2(-1, 1)) : xform; + xform = flip_v ? xform.scaled(Size2(1, -1)) : xform; + xform = transpose ? xform.rotated(Math_PI).scaled(Size2(-1, -1)) : xform; + int alternative_tile = 0; if (!atlas_source->has_tile(coords)) { atlas_source->create_tile(coords); @@ -2661,13 +2711,25 @@ void TileSet::_compatibility_conversion() { if (get_occlusion_layers_count() < 1) { add_occlusion_layer(); } - tile_data->set_occluder(0, ctd->autotile_occluder_map[coords]); + Ref<OccluderPolygon2D> occluder = ctd->autotile_occluder_map[coords]->duplicate(); + Vector<Vector2> polygon = ctd->occluder->get_polygon(); + for (int index = 0; index < polygon.size(); index++) { + polygon.write[index] = xform.xform(polygon[index] - ctd->region.get_size() / 2.0); + } + occluder->set_polygon(polygon); + tile_data->set_occluder(0, occluder); } if (ctd->autotile_navpoly_map.has(coords)) { if (get_navigation_layers_count() < 1) { add_navigation_layer(); } - tile_data->set_navigation_polygon(0, ctd->autotile_navpoly_map[coords]); + Ref<NavigationPolygon> navigation = ctd->autotile_navpoly_map[coords]->duplicate(); + Vector<Vector2> vertices = navigation->get_vertices(); + for (int index = 0; index < vertices.size(); index++) { + vertices.write[index] = xform.xform(vertices[index] - ctd->region.get_size() / 2.0); + } + navigation->set_vertices(vertices); + tile_data->set_navigation_polygon(0, navigation); } if (ctd->autotile_priority_map.has(coords)) { tile_data->set_probability(ctd->autotile_priority_map[coords]); @@ -2689,7 +2751,7 @@ void TileSet::_compatibility_conversion() { if (convex_shape.is_valid()) { Vector<Vector2> polygon = convex_shape->get_points(); for (int point_index = 0; point_index < polygon.size(); point_index++) { - polygon.write[point_index] = csd.transform.xform(polygon[point_index]); + polygon.write[point_index] = xform.xform(csd.transform.xform(polygon[point_index]) - ctd->autotile_tile_size / 2.0); } tile_data->set_collision_polygons_count(0, tile_data->get_collision_polygons_count(0) + 1); int index = tile_data->get_collision_polygons_count(0) - 1; @@ -2712,6 +2774,12 @@ void TileSet::_compatibility_conversion() { } } } + + // Update the size count. + if (!compatibility_size_count.has(ctd->region.get_size())) { + compatibility_size_count[ctd->autotile_tile_size] = 0; + } + compatibility_size_count[ctd->autotile_tile_size] += atlas_size.x * atlas_size.y; } break; } @@ -2728,7 +2796,18 @@ void TileSet::_compatibility_conversion() { } } - // Reset compatibility data + // Update the TileSet tile_size according to the most common size found. + Vector2i max_size = get_tile_size(); + int max_count = 0; + for (KeyValue<Vector2i, int> kv : compatibility_size_count) { + if (kv.value > max_count) { + max_size = kv.key; + max_count = kv.value; + } + } + set_tile_size(max_size); + + // Reset compatibility data (besides the histogram counts) for (const KeyValue<int, CompatibilityTileData *> &E : compatibility_data) { memdelete(E.value); } @@ -2909,6 +2988,10 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { } ctd->shapes.push_back(csd); } + } else if (what == "occluder") { + ctd->occluder = p_value; + } else if (what == "navigation") { + ctd->navigation = p_value; /* // IGNORED FOR NOW, they seem duplicated data compared to the shapes array @@ -3387,6 +3470,8 @@ void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_navigation_layer", "layer_index"), &TileSet::remove_navigation_layer); ClassDB::bind_method(D_METHOD("set_navigation_layer_layers", "layer_index", "layers"), &TileSet::set_navigation_layer_layers); ClassDB::bind_method(D_METHOD("get_navigation_layer_layers", "layer_index"), &TileSet::get_navigation_layer_layers); + ClassDB::bind_method(D_METHOD("set_navigation_layer_layer_value", "layer_index", "layer_number", "value"), &TileSet::set_navigation_layer_layer_value); + ClassDB::bind_method(D_METHOD("get_navigation_layer_layer_value", "layer_index", "layer_number"), &TileSet::get_navigation_layer_layer_value); // Custom data ClassDB::bind_method(D_METHOD("get_custom_data_layers_count"), &TileSet::get_custom_data_layers_count); @@ -4282,19 +4367,11 @@ Rect2i TileSetAtlasSource::get_tile_texture_region(Vector2i p_atlas_coords, int return Rect2(origin, region_size); } -Vector2i TileSetAtlasSource::get_tile_effective_texture_offset(Vector2i p_atlas_coords, int p_alternative_tile) const { - ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Vector2i(), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); - ERR_FAIL_COND_V_MSG(!has_alternative_tile(p_atlas_coords, p_alternative_tile), Vector2i(), vformat("TileSetAtlasSource has no alternative tile with id %d at %s.", p_alternative_tile, String(p_atlas_coords))); - ERR_FAIL_COND_V(!tile_set, Vector2i()); +bool TileSetAtlasSource::is_position_in_tile_texture_region(const Vector2i p_atlas_coords, int p_alternative_tile, Vector2 p_position) const { + Size2 size = get_tile_texture_region(p_atlas_coords).size; + Rect2 rect = Rect2(-size / 2 - get_tile_data(p_atlas_coords, p_alternative_tile)->get_texture_origin(), size); - Vector2 margin = (get_tile_texture_region(p_atlas_coords).size - tile_set->get_tile_size()) / 2; - margin = Vector2i(MAX(0, margin.x), MAX(0, margin.y)); - Vector2i effective_texture_offset = get_tile_data(p_atlas_coords, p_alternative_tile)->get_texture_offset(); - if (ABS(effective_texture_offset.x) > margin.x || ABS(effective_texture_offset.y) > margin.y) { - effective_texture_offset = effective_texture_offset.clamp(-margin, margin); - } - - return effective_texture_offset; + return rect.has_point(p_position); } // Getters for texture and tile region (padded or not) @@ -5046,7 +5123,7 @@ TileData *TileData::duplicate() { output->flip_h = flip_h; output->flip_v = flip_v; output->transpose = transpose; - output->tex_offset = tex_offset; + output->texture_origin = texture_origin; output->material = material; output->modulate = modulate; output->z_index = z_index; @@ -5096,13 +5173,13 @@ bool TileData::get_transpose() const { return transpose; } -void TileData::set_texture_offset(Vector2i p_texture_offset) { - tex_offset = p_texture_offset; +void TileData::set_texture_origin(Vector2i p_texture_origin) { + texture_origin = p_texture_origin; emit_signal(SNAME("changed")); } -Vector2i TileData::get_texture_offset() const { - return tex_offset; +Vector2i TileData::get_texture_origin() const { + return texture_origin; } void TileData::set_material(Ref<Material> p_material) { @@ -5390,6 +5467,13 @@ Variant TileData::get_custom_data_by_layer_id(int p_layer_id) const { } bool TileData::_set(const StringName &p_name, const Variant &p_value) { +#ifndef DISABLE_DEPRECATED + if (p_name == "texture_offset") { + texture_origin = p_value; + return true; + } +#endif + Vector<String> components = String(p_name).split("/", true, 2); if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) { @@ -5511,6 +5595,13 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) { } bool TileData::_get(const StringName &p_name, Variant &r_ret) const { +#ifndef DISABLE_DEPRECATED + if (p_name == "texture_offset") { + r_ret = texture_origin; + return true; + } +#endif + Vector<String> components = String(p_name).split("/", true, 2); if (tile_set) { @@ -5692,8 +5783,8 @@ void TileData::_bind_methods() { ClassDB::bind_method(D_METHOD("get_transpose"), &TileData::get_transpose); ClassDB::bind_method(D_METHOD("set_material", "material"), &TileData::set_material); ClassDB::bind_method(D_METHOD("get_material"), &TileData::get_material); - ClassDB::bind_method(D_METHOD("set_texture_offset", "texture_offset"), &TileData::set_texture_offset); - ClassDB::bind_method(D_METHOD("get_texture_offset"), &TileData::get_texture_offset); + ClassDB::bind_method(D_METHOD("set_texture_origin", "texture_origin"), &TileData::set_texture_origin); + ClassDB::bind_method(D_METHOD("get_texture_origin"), &TileData::get_texture_origin); ClassDB::bind_method(D_METHOD("set_modulate", "modulate"), &TileData::set_modulate); ClassDB::bind_method(D_METHOD("get_modulate"), &TileData::get_modulate); ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &TileData::set_z_index); @@ -5746,7 +5837,7 @@ void TileData::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "get_flip_h"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "get_flip_v"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transpose"), "set_transpose", "get_transpose"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_texture_offset", "get_texture_offset"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_origin", PROPERTY_HINT_NONE, "suffix:px"), "set_texture_origin", "get_texture_origin"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial,ShaderMaterial"), "set_material", "get_material"); ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index"), "set_z_index", "get_z_index"); diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index c2ed798f2b..ad25629a1c 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -198,6 +198,7 @@ private: HashMap<int, CompatibilityTileData *> compatibility_data; HashMap<int, int> compatibility_tilemap_mapping_tile_modes; HashMap<int, RBMap<Array, Array>> compatibility_tilemap_mapping; + HashMap<Vector2i, int> compatibility_size_count; void _compatibility_conversion(); @@ -475,6 +476,8 @@ public: void remove_navigation_layer(int p_index); void set_navigation_layer_layers(int p_layer_index, uint32_t p_layers); uint32_t get_navigation_layer_layers(int p_layer_index) const; + void set_navigation_layer_layer_value(int p_layer_index, int p_layer_number, bool p_value); + bool get_navigation_layer_layer_value(int p_layer_index, int p_layer_number) const; // Custom data int get_custom_data_layers_count() const; @@ -719,7 +722,7 @@ public: // Helpers. Vector2i get_atlas_grid_size() const; Rect2i get_tile_texture_region(Vector2i p_atlas_coords, int p_frame = 0) const; - Vector2i get_tile_effective_texture_offset(Vector2i p_atlas_coords, int p_alternative_tile) const; + bool is_position_in_tile_texture_region(const Vector2i p_atlas_coords, int p_alternative_tile, Vector2 p_position) const; // Getters for texture and tile region (padded or not) Ref<Texture2D> get_runtime_texture() const; @@ -785,7 +788,7 @@ private: bool flip_h = false; bool flip_v = false; bool transpose = false; - Vector2i tex_offset; + Vector2i texture_origin; Ref<Material> material = Ref<Material>(); Color modulate = Color(1.0, 1.0, 1.0, 1.0); int z_index = 0; @@ -864,8 +867,8 @@ public: void set_transpose(bool p_transpose); bool get_transpose() const; - void set_texture_offset(Vector2i p_texture_offset); - Vector2i get_texture_offset() const; + void set_texture_origin(Vector2i p_texture_origin); + Vector2i get_texture_origin() const; void set_material(Ref<Material> p_material); Ref<Material> get_material() const; void set_modulate(Color p_modulate); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 1cbeaae428..bfcf5cb137 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -1561,7 +1561,7 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const { prop_name += "/" + itos(E.key); if (E.key != NODE_ID_OUTPUT) { - p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "VisualShaderNode", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); + p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "VisualShaderNode", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_ALWAYS_DUPLICATE)); } p_list->push_back(PropertyInfo(Variant::VECTOR2, prop_name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR)); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index e78d9b924d..12be0f46a6 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -3690,16 +3690,47 @@ String VisualShaderNodeDerivativeFunc::get_output_port_name(int p_port) const { String VisualShaderNodeDerivativeFunc::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 { static const char *functions[FUNC_MAX] = { - "fwidth($)", - "dFdx($)", - "dFdy($)" + "fwidth$($)", + "dFdx$($)", + "dFdy$($)" + }; + + static const char *precisions[PRECISION_MAX] = { + "", + "Coarse", + "Fine" }; String code; - code += " " + p_output_vars[0] + " = " + String(functions[func]).replace("$", p_input_vars[0]) + ";\n"; + if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") { + code += " " + p_output_vars[0] + " = " + String(functions[func]).replace_first("$", "").replace_first("$", p_input_vars[0]) + ";\n"; + return code; + } + + code += " " + p_output_vars[0] + " = " + String(functions[func]).replace_first("$", String(precisions[precision])).replace_first("$", p_input_vars[0]) + ";\n"; return code; } +String VisualShaderNodeDerivativeFunc::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const { + if (precision != PRECISION_NONE && OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") { + String precision_str; + switch (precision) { + case PRECISION_COARSE: { + precision_str = "Coarse"; + } break; + case PRECISION_FINE: { + precision_str = "Fine"; + } break; + default: { + } break; + } + + return vformat(RTR("`%s` precision mode is not available for `gl_compatibility` profile.\nReverted to `None` precision."), precision_str); + } + + return String(); +} + void VisualShaderNodeDerivativeFunc::set_op_type(OpType p_op_type) { ERR_FAIL_INDEX((int)p_op_type, int(OP_TYPE_MAX)); if (op_type == p_op_type) { @@ -3742,10 +3773,24 @@ VisualShaderNodeDerivativeFunc::Function VisualShaderNodeDerivativeFunc::get_fun return func; } +void VisualShaderNodeDerivativeFunc::set_precision(Precision p_precision) { + ERR_FAIL_INDEX(int(p_precision), int(PRECISION_MAX)); + if (precision == p_precision) { + return; + } + precision = p_precision; + emit_changed(); +} + +VisualShaderNodeDerivativeFunc::Precision VisualShaderNodeDerivativeFunc::get_precision() const { + return precision; +} + Vector<StringName> VisualShaderNodeDerivativeFunc::get_editable_properties() const { Vector<StringName> props; props.push_back("op_type"); props.push_back("function"); + props.push_back("precision"); return props; } @@ -3756,8 +3801,12 @@ void VisualShaderNodeDerivativeFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeDerivativeFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeDerivativeFunc::get_function); + ClassDB::bind_method(D_METHOD("set_precision", "precision"), &VisualShaderNodeDerivativeFunc::set_precision); + ClassDB::bind_method(D_METHOD("get_precision"), &VisualShaderNodeDerivativeFunc::get_precision); + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector3,Vector4"), "set_op_type", "get_op_type"); ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sum,X,Y"), "set_function", "get_function"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "precision", PROPERTY_HINT_ENUM, "None,Coarse,Fine"), "set_precision", "get_precision"); BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D); @@ -3769,6 +3818,11 @@ void VisualShaderNodeDerivativeFunc::_bind_methods() { BIND_ENUM_CONSTANT(FUNC_X); BIND_ENUM_CONSTANT(FUNC_Y); BIND_ENUM_CONSTANT(FUNC_MAX); + + BIND_ENUM_CONSTANT(PRECISION_NONE); + BIND_ENUM_CONSTANT(PRECISION_COARSE); + BIND_ENUM_CONSTANT(PRECISION_FINE); + BIND_ENUM_CONSTANT(PRECISION_MAX); } VisualShaderNodeDerivativeFunc::VisualShaderNodeDerivativeFunc() { diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index e3b101cf84..fa6b134526 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -1536,9 +1536,17 @@ public: FUNC_MAX, }; + enum Precision { + PRECISION_NONE, + PRECISION_COARSE, + PRECISION_FINE, + PRECISION_MAX, + }; + protected: OpType op_type = OP_TYPE_SCALAR; Function func = FUNC_SUM; + Precision precision = PRECISION_NONE; protected: static void _bind_methods(); @@ -1555,6 +1563,7 @@ public: virtual String get_output_port_name(int p_port) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; void set_op_type(OpType p_op_type); OpType get_op_type() const; @@ -1562,6 +1571,9 @@ public: void set_function(Function p_func); Function get_function() const; + void set_precision(Precision p_precision); + Precision get_precision() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeDerivativeFunc(); @@ -1569,6 +1581,7 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeDerivativeFunc::OpType) VARIANT_ENUM_CAST(VisualShaderNodeDerivativeFunc::Function) +VARIANT_ENUM_CAST(VisualShaderNodeDerivativeFunc::Precision) /////////////////////////////////////// /// FACEFORWARD diff --git a/scene/resources/world_boundary_shape_2d.cpp b/scene/resources/world_boundary_shape_2d.cpp index 49f0873a3e..35cb8ef13d 100644 --- a/scene/resources/world_boundary_shape_2d.cpp +++ b/scene/resources/world_boundary_shape_2d.cpp @@ -76,11 +76,12 @@ real_t WorldBoundaryShape2D::get_distance() const { void WorldBoundaryShape2D::draw(const RID &p_to_rid, const Color &p_color) { Vector2 point = get_distance() * get_normal(); + real_t line_width = 3.0; Vector2 l1[2] = { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }; - RS::get_singleton()->canvas_item_add_line(p_to_rid, l1[0], l1[1], p_color, 3); - Vector2 l2[2] = { point, point + get_normal() * 30 }; - RS::get_singleton()->canvas_item_add_line(p_to_rid, l2[0], l2[1], p_color, 3); + RS::get_singleton()->canvas_item_add_line(p_to_rid, l1[0], l1[1], p_color, line_width); + Vector2 l2[2] = { point + get_normal().normalized() * (0.5 * line_width), point + get_normal() * 30 }; + RS::get_singleton()->canvas_item_add_line(p_to_rid, l2[0], l2[1], p_color, line_width); } Rect2 WorldBoundaryShape2D::get_rect() const { |