diff options
Diffstat (limited to 'scene')
240 files changed, 7559 insertions, 3614 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index 3268544519..0f98fad824 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -31,11 +31,9 @@ #include "animated_sprite_2d.h" #include "core/os/os.h" +#include "scene/main/viewport.h" #include "scene/scene_string_names.h" -#define NORMAL_SUFFIX "_normal" -#define SPECULAR_SUFFIX "_specular" - #ifdef TOOLS_ENABLED Dictionary AnimatedSprite2D::_edit_get_state() const { Dictionary state = Node2D::_edit_get_state(); @@ -152,8 +150,6 @@ void SpriteFrames::add_animation(const StringName &p_anim) { ERR_FAIL_COND_MSG(animations.has(p_anim), "SpriteFrames already has animation '" + p_anim + "'."); animations[p_anim] = Anim(); - animations[p_anim].normal_name = String(p_anim) + NORMAL_SUFFIX; - animations[p_anim].specular_name = String(p_anim) + SPECULAR_SUFFIX; } bool SpriteFrames::has_animation(const StringName &p_anim) const { @@ -171,8 +167,6 @@ void SpriteFrames::rename_animation(const StringName &p_prev, const StringName & Anim anim = animations[p_prev]; animations.erase(p_prev); animations[p_next] = anim; - animations[p_next].normal_name = String(p_next) + NORMAL_SUFFIX; - animations[p_next].specular_name = String(p_next) + SPECULAR_SUFFIX; } Vector<String> SpriteFrames::_get_animation_list() const { @@ -441,9 +435,6 @@ void AnimatedSprite2D::_notification(int p_what) { return; } - Ref<Texture2D> normal = frames->get_normal_frame(animation, frame); - Ref<Texture2D> specular = frames->get_specular_frame(animation, frame); - RID ci = get_canvas_item(); Size2i s; @@ -453,7 +444,7 @@ void AnimatedSprite2D::_notification(int p_what) { ofs -= s / 2; } - if (Engine::get_singleton()->get_use_pixel_snap()) { + if (get_viewport() && get_viewport()->is_snap_2d_transforms_to_pixel_enabled()) { ofs = ofs.floor(); } Rect2 dst_rect(ofs, s); @@ -465,7 +456,7 @@ void AnimatedSprite2D::_notification(int p_what) { dst_rect.size.y = -dst_rect.size.y; } - texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false, normal, specular, Color(specular_color.r, specular_color.g, specular_color.b, shininess)); + texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false); } break; } @@ -660,29 +651,16 @@ StringName AnimatedSprite2D::get_animation() const { } String AnimatedSprite2D::get_configuration_warning() const { + String warning = Node2D::get_configuration_warning(); + if (frames.is_null()) { - return TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames."); } - return String(); -} - -void AnimatedSprite2D::set_specular_color(const Color &p_color) { - specular_color = p_color; - update(); -} - -Color AnimatedSprite2D::get_specular_color() const { - return specular_color; -} - -void AnimatedSprite2D::set_shininess(float p_shininess) { - shininess = CLAMP(p_shininess, 0.0, 1.0); - update(); -} - -float AnimatedSprite2D::get_shininess() const { - return shininess; + return warning; } void AnimatedSprite2D::_bind_methods() { @@ -717,12 +695,6 @@ void AnimatedSprite2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_speed_scale", "speed_scale"), &AnimatedSprite2D::set_speed_scale); ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedSprite2D::get_speed_scale); - ClassDB::bind_method(D_METHOD("set_specular_color", "color"), &AnimatedSprite2D::set_specular_color); - ClassDB::bind_method(D_METHOD("get_specular_color"), &AnimatedSprite2D::get_specular_color); - - ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &AnimatedSprite2D::set_shininess); - ClassDB::bind_method(D_METHOD("get_shininess"), &AnimatedSprite2D::get_shininess); - ADD_SIGNAL(MethodInfo("frame_changed")); ADD_SIGNAL(MethodInfo("animation_finished")); @@ -732,9 +704,6 @@ void AnimatedSprite2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing"); - ADD_GROUP("Lighting", ""); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess"); ADD_GROUP("Offset", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); @@ -754,6 +723,4 @@ AnimatedSprite2D::AnimatedSprite2D() { animation = "default"; timeout = 0; is_over = false; - specular_color = Color(1, 1, 1, 1); - shininess = 1.0; } diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h index cefed56620..fddbf39be2 100644 --- a/scene/2d/animated_sprite_2d.h +++ b/scene/2d/animated_sprite_2d.h @@ -46,14 +46,8 @@ class SpriteFrames : public Resource { loop = true; speed = 5; } - - StringName normal_name; - StringName specular_name; }; - Color specular_color; - float shininess; - Map<StringName, Anim> animations; Array _get_frames() const; @@ -95,34 +89,6 @@ public: return E->get().frames[p_idx]; } - _FORCE_INLINE_ Ref<Texture2D> get_normal_frame(const StringName &p_anim, int p_idx) const { - const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist."); - ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>()); - - const Map<StringName, Anim>::Element *EN = animations.find(E->get().normal_name); - - if (!EN || p_idx >= EN->get().frames.size()) { - return Ref<Texture2D>(); - } - - return EN->get().frames[p_idx]; - } - - _FORCE_INLINE_ Ref<Texture2D> get_specular_frame(const StringName &p_anim, int p_idx) const { - const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V(!E, Ref<Texture2D>()); - ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>()); - - const Map<StringName, Anim>::Element *EN = animations.find(E->get().specular_name); - - if (!EN || p_idx >= EN->get().frames.size()) { - return Ref<Texture2D>(); - } - - return EN->get().frames[p_idx]; - } - void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_frame) { Map<StringName, Anim>::Element *E = animations.find(p_anim); ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); @@ -166,9 +132,6 @@ class AnimatedSprite2D : public Node2D { bool _is_playing() const; Rect2 _get_rect() const; - Color specular_color; - float shininess; - protected: static void _bind_methods(); void _notification(int p_what); @@ -216,12 +179,6 @@ public: void set_flip_v(bool p_flip); bool is_flipped_v() const; - void set_specular_color(const Color &p_color); - Color get_specular_color() const; - - void set_shininess(float p_shininess); - float get_shininess() const; - virtual String get_configuration_warning() const override; AnimatedSprite2D(); }; diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index ebfcb9cad6..d51ee3f9a8 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -180,26 +180,20 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i E->get().shapes.erase(ShapePair(p_body_shape, p_area_shape)); } - bool eraseit = false; - + bool in_tree = E->get().in_tree; if (E->get().rc == 0) { + body_map.erase(E); if (node) { node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area2D::_body_enter_tree)); node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area2D::_body_exit_tree)); - if (E->get().in_tree) { + if (in_tree) { emit_signal(SceneStringNames::get_singleton()->body_exited, obj); } } - - eraseit = true; } - if (!node || E->get().in_tree) { + if (!node || in_tree) { emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, obj, p_body_shape, p_area_shape); } - - if (eraseit) { - body_map.erase(E); - } } locked = false; @@ -278,26 +272,20 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i E->get().shapes.erase(AreaShapePair(p_area_shape, p_self_shape)); } - bool eraseit = false; - + bool in_tree = E->get().in_tree; if (E->get().rc == 0) { + area_map.erase(E); if (node) { node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area2D::_area_enter_tree)); node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area2D::_area_exit_tree)); - if (E->get().in_tree) { + if (in_tree) { emit_signal(SceneStringNames::get_singleton()->area_exited, obj); } } - - eraseit = true; } - if (!node || E->get().in_tree) { + if (!node || in_tree) { emit_signal(SceneStringNames::get_singleton()->area_shape_exited, objid, obj, p_area_shape, p_self_shape); } - - if (eraseit) { - area_map.erase(E); - } } locked = false; diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h index 32226ef5a4..01426db999 100644 --- a/scene/2d/area_2d.h +++ b/scene/2d/area_2d.h @@ -31,7 +31,7 @@ #ifndef AREA_2D_H #define AREA_2D_H -#include "core/vset.h" +#include "core/templates/vset.h" #include "scene/2d/collision_object_2d.h" class Area2D : public CollisionObject2D { diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 5b89ac15b1..9bd716aeaa 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -30,7 +30,7 @@ #include "audio_stream_player_2d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "scene/2d/area_2d.h" #include "scene/main/window.h" diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 68e99445d8..e22b24c16f 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -30,7 +30,7 @@ #include "camera_2d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "core/math/math_funcs.h" #include "scene/scene_string_names.h" #include "servers/rendering_server.h" @@ -56,7 +56,7 @@ void Camera2D::_update_scroll() { viewport->set_canvas_transform(xform); - Size2 screen_size = viewport->get_visible_rect().size; + Size2 screen_size = _get_camera_screen_size(); Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5) : Point2()); get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_camera_moved", xform, screen_offset); @@ -94,7 +94,7 @@ Transform2D Camera2D::get_camera_transform() { ERR_FAIL_COND_V(custom_viewport && !ObjectDB::get_instance(custom_viewport_id), Transform2D()); - Size2 screen_size = viewport->get_visible_rect().size; + Size2 screen_size = _get_camera_screen_size(); Point2 new_camera_pos = get_global_transform().get_origin(); Point2 ret_camera_pos; @@ -274,7 +274,7 @@ void Camera2D::_notification(int p_what) { } Transform2D inv_camera_transform = get_camera_transform().affine_inverse(); - Size2 screen_size = get_viewport_rect().size; + Size2 screen_size = _get_camera_screen_size(); Vector2 screen_endpoints[4] = { inv_camera_transform.xform(Vector2(0, 0)), @@ -321,7 +321,7 @@ void Camera2D::_notification(int p_what) { } Transform2D inv_camera_transform = get_camera_transform().affine_inverse(); - Size2 screen_size = get_viewport_rect().size; + Size2 screen_size = _get_camera_screen_size(); Vector2 margin_endpoints[4] = { inv_camera_transform.xform(Vector2((screen_size.width / 2) - ((screen_size.width / 2) * drag_margin[MARGIN_LEFT]), (screen_size.height / 2) - ((screen_size.height / 2) * drag_margin[MARGIN_TOP]))), @@ -469,7 +469,7 @@ void Camera2D::reset_smoothing() { void Camera2D::align() { ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id)); - Size2 screen_size = viewport->get_visible_rect().size; + Size2 screen_size = _get_camera_screen_size(); Point2 current_camera_pos = get_global_transform().get_origin(); if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) { @@ -507,6 +507,14 @@ Point2 Camera2D::get_camera_screen_center() const { return camera_screen_center; } +Size2 Camera2D::_get_camera_screen_size() const { + // special case if the camera2D is in the root viewport + if (Engine::get_singleton()->is_editor_hint() && get_viewport()->get_parent_viewport() == get_tree()->get_root()) { + return Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")); + } + return get_viewport_rect().size; +} + void Camera2D::set_h_drag_enabled(bool p_enabled) { h_drag_enabled = p_enabled; } diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index 0a4e269c40..867a5562b2 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -94,6 +94,8 @@ protected: Camera2DProcessMode process_mode; + Size2 _get_camera_screen_size() const; + protected: virtual Transform2D get_camera_transform(); void _notification(int p_what); diff --git a/scene/2d/canvas_group.cpp b/scene/2d/canvas_group.cpp new file mode 100644 index 0000000000..39cae8e0c6 --- /dev/null +++ b/scene/2d/canvas_group.cpp @@ -0,0 +1,87 @@ +/*************************************************************************/ +/* canvas_group.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "canvas_group.h" + +void CanvasGroup::set_fit_margin(float p_fit_margin) { + ERR_FAIL_COND(p_fit_margin < 0.0); + + fit_margin = p_fit_margin; + RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CANVAS_GROUP_MODE_TRANSPARENT, clear_margin, true, fit_margin, use_mipmaps); + + update(); +} + +float CanvasGroup::get_fit_margin() const { + return fit_margin; +} + +void CanvasGroup::set_clear_margin(float p_clear_margin) { + ERR_FAIL_COND(p_clear_margin < 0.0); + + clear_margin = p_clear_margin; + RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CANVAS_GROUP_MODE_TRANSPARENT, clear_margin, true, clear_margin, use_mipmaps); + + update(); +} + +float CanvasGroup::get_clear_margin() const { + return clear_margin; +} + +void CanvasGroup::set_use_mipmaps(bool p_use_mipmaps) { + use_mipmaps = p_use_mipmaps; + RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CANVAS_GROUP_MODE_TRANSPARENT, clear_margin, true, fit_margin, use_mipmaps); +} +bool CanvasGroup::is_using_mipmaps() const { + return use_mipmaps; +} + +void CanvasGroup::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_fit_margin", "fit_margin"), &CanvasGroup::set_fit_margin); + ClassDB::bind_method(D_METHOD("get_fit_margin"), &CanvasGroup::get_fit_margin); + + ClassDB::bind_method(D_METHOD("set_clear_margin", "clear_margin"), &CanvasGroup::set_clear_margin); + ClassDB::bind_method(D_METHOD("get_clear_margin"), &CanvasGroup::get_clear_margin); + + ClassDB::bind_method(D_METHOD("set_use_mipmaps", "use_mipmaps"), &CanvasGroup::set_use_mipmaps); + ClassDB::bind_method(D_METHOD("is_using_mipmaps"), &CanvasGroup::is_using_mipmaps); + + ADD_GROUP("Tweaks", ""); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fit_margin", PROPERTY_HINT_RANGE, "0,1024,1.0,or_greater"), "set_fit_margin", "get_fit_margin"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "clear_margin", PROPERTY_HINT_RANGE, "0,1024,1.0,or_greater"), "set_clear_margin", "get_clear_margin"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_mipmaps"), "set_use_mipmaps", "is_using_mipmaps"); +} + +CanvasGroup::CanvasGroup() { + set_fit_margin(10.0); //sets things +} +CanvasGroup::~CanvasGroup() { +} diff --git a/scene/2d/canvas_group.h b/scene/2d/canvas_group.h new file mode 100644 index 0000000000..19630befc7 --- /dev/null +++ b/scene/2d/canvas_group.h @@ -0,0 +1,59 @@ +/*************************************************************************/ +/* canvas_group.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CANVASGROUP_H +#define CANVASGROUP_H + +#include "scene/2d/node_2d.h" + +class CanvasGroup : public Node2D { + GDCLASS(CanvasGroup, Node2D) + float fit_margin = 10.0; + float clear_margin = 10.0; + bool use_mipmaps = false; + +protected: + static void _bind_methods(); + +public: + void set_fit_margin(float p_fit_margin); + float get_fit_margin() const; + + void set_clear_margin(float p_clear_margin); + float get_clear_margin() const; + + void set_use_mipmaps(bool p_use_mipmaps); + bool is_using_mipmaps() const; + + CanvasGroup(); + ~CanvasGroup(); +}; + +#endif // CANVASGROUP_H diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp index 56643542a8..8fb16534e8 100644 --- a/scene/2d/canvas_modulate.cpp +++ b/scene/2d/canvas_modulate.cpp @@ -78,14 +78,19 @@ String CanvasModulate::get_configuration_warning() const { return String(); } + String warning = Node2D::get_configuration_warning(); + List<Node *> nodes; get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes); if (nodes.size() > 1) { - return TTR("Only one visible CanvasModulate is allowed per scene (or set of instanced scenes). The first created one will work, while the rest will be ignored."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("Only one visible CanvasModulate is allowed per scene (or set of instanced scenes). The first created one will work, while the rest will be ignored."); } - return String(); + return warning; } CanvasModulate::CanvasModulate() { diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index d23398713a..64d82d715c 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -31,7 +31,7 @@ #include "collision_polygon_2d.h" #include "collision_object_2d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "core/math/geometry_2d.h" #include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" @@ -230,15 +230,23 @@ bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, doubl #endif String CollisionPolygon2D::get_configuration_warning() const { + String warning = Node2D::get_configuration_warning(); + if (!Object::cast_to<CollisionObject2D>(get_parent())) { - return TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); } if (polygon.empty()) { - return TTR("An empty CollisionPolygon2D has no effect on collision."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("An empty CollisionPolygon2D has no effect on collision."); } - return String(); + return warning; } void CollisionPolygon2D::set_disabled(bool p_disabled) { diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index d022c857f3..a5cd624235 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -31,7 +31,7 @@ #include "collision_shape_2d.h" #include "collision_object_2d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "scene/resources/capsule_shape_2d.h" #include "scene/resources/circle_shape_2d.h" #include "scene/resources/concave_polygon_shape_2d.h" diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 526951976e..ef2a9a4911 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -228,15 +228,6 @@ Ref<Texture2D> CPUParticles2D::get_texture() const { return texture; } -void CPUParticles2D::set_normalmap(const Ref<Texture2D> &p_normalmap) { - normalmap = p_normalmap; - update(); -} - -Ref<Texture2D> CPUParticles2D::get_normalmap() const { - return normalmap; -} - void CPUParticles2D::set_fixed_fps(int p_count) { fixed_fps = p_count; } @@ -254,7 +245,7 @@ bool CPUParticles2D::get_fractional_delta() const { } String CPUParticles2D::get_configuration_warning() const { - String warnings; + String warnings = Node2D::get_configuration_warning(); CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr()); @@ -749,7 +740,11 @@ void CPUParticles2D::_particles_process(float p_delta) { p.transform[2] = emission_points.get(random_idx); if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) { - p.velocity = emission_normals.get(random_idx); + Vector2 normal = emission_normals.get(random_idx); + Transform2D m2; + m2.set_axis(0, normal); + m2.set_axis(1, normal.tangent()); + p.velocity = m2.basis_xform(p.velocity); } if (emission_colors.size() == pc) { @@ -1056,12 +1051,7 @@ void CPUParticles2D::_notification(int p_what) { texrid = texture->get_rid(); } - RID normrid; - if (normalmap.is_valid()) { - normrid = normalmap->get_rid(); - } - - RS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid, normrid); + RS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid); } if (p_what == NOTIFICATION_INTERNAL_PROCESS) { @@ -1210,9 +1200,6 @@ void CPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture", "texture"), &CPUParticles2D::set_texture); ClassDB::bind_method(D_METHOD("get_texture"), &CPUParticles2D::get_texture); - ClassDB::bind_method(D_METHOD("set_normalmap", "normalmap"), &CPUParticles2D::set_normalmap); - ClassDB::bind_method(D_METHOD("get_normalmap"), &CPUParticles2D::get_normalmap); - ClassDB::bind_method(D_METHOD("restart"), &CPUParticles2D::restart); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); @@ -1232,7 +1219,6 @@ void CPUParticles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normalmap", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normalmap", "get_normalmap"); BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX); BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME); @@ -1287,7 +1273,7 @@ void CPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles2D::convert_from_particles); ADD_GROUP("Emission Shape", "emission_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "emission_rect_extents"), "set_emission_rect_extents", "get_emission_rect_extents"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "emission_points"), "set_emission_points", "get_emission_points"); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index dfc875ceb0..2296e0434e 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -31,7 +31,7 @@ #ifndef CPU_PARTICLES_2D_H #define CPU_PARTICLES_2D_H -#include "core/rid.h" +#include "core/templates/rid.h" #include "scene/2d/node_2d.h" #include "scene/resources/texture.h" @@ -147,7 +147,6 @@ private: DrawOrder draw_order; Ref<Texture2D> texture; - Ref<Texture2D> normalmap; //////// @@ -232,9 +231,6 @@ public: void set_texture(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_texture() const; - void set_normalmap(const Ref<Texture2D> &p_normalmap); - Ref<Texture2D> get_normalmap() const; - /////////////////// void set_direction(Vector2 p_direction); diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index 0814fbb549..a4a930455b 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -35,7 +35,7 @@ #include "scene/scene_string_names.h" #ifdef TOOLS_ENABLED -#include "core/engine.h" +#include "core/config/engine.h" #endif void GPUParticles2D::set_emitting(bool p_emitting) { @@ -222,7 +222,7 @@ String GPUParticles2D::get_configuration_warning() const { return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles2D\" option for this purpose."); } - String warnings; + String warnings = Node2D::get_configuration_warning(); if (process_material.is_null()) { if (warnings != String()) { @@ -267,15 +267,6 @@ Ref<Texture2D> GPUParticles2D::get_texture() const { return texture; } -void GPUParticles2D::set_normal_map(const Ref<Texture2D> &p_normal_map) { - normal_map = p_normal_map; - update(); -} - -Ref<Texture2D> GPUParticles2D::get_normal_map() const { - return normal_map; -} - void GPUParticles2D::_validate_property(PropertyInfo &property) const { } @@ -290,12 +281,8 @@ void GPUParticles2D::_notification(int p_what) { if (texture.is_valid()) { texture_rid = texture->get_rid(); } - RID normal_rid; - if (normal_map.is_valid()) { - normal_rid = normal_map->get_rid(); - } - RS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid); + RS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid); #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() && (this == get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) { @@ -359,9 +346,6 @@ void GPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture", "texture"), &GPUParticles2D::set_texture); ClassDB::bind_method(D_METHOD("get_texture"), &GPUParticles2D::get_texture); - ClassDB::bind_method(D_METHOD("set_normal_map", "texture"), &GPUParticles2D::set_normal_map); - ClassDB::bind_method(D_METHOD("get_normal_map"), &GPUParticles2D::get_normal_map); - ClassDB::bind_method(D_METHOD("capture_rect"), &GPUParticles2D::capture_rect); ClassDB::bind_method(D_METHOD("restart"), &GPUParticles2D::restart); @@ -385,7 +369,6 @@ void GPUParticles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material"); ADD_GROUP("Textures", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map"); BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX); BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME); diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index 3258237f92..0d1b82d93e 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -31,7 +31,7 @@ #ifndef PARTICLES_2D_H #define PARTICLES_2D_H -#include "core/rid.h" +#include "core/templates/rid.h" #include "scene/2d/node_2d.h" #include "scene/resources/texture.h" @@ -65,7 +65,6 @@ private: DrawOrder draw_order; Ref<Texture2D> texture; - Ref<Texture2D> normal_map; void _update_particle_emission_transform(); @@ -111,9 +110,6 @@ public: void set_texture(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_texture() const; - void set_normal_map(const Ref<Texture2D> &p_normal_map); - Ref<Texture2D> get_normal_map() const; - virtual String get_configuration_warning() const override; void restart(); diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp index 8df72d7aac..0e4b1836da 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -30,7 +30,7 @@ #include "joints_2d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "physics_body_2d.h" #include "servers/physics_server_2d.h" diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 1e7e9f6b6a..2b373a669b 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -30,57 +30,9 @@ #include "light_2d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "servers/rendering_server.h" -#ifdef TOOLS_ENABLED -Dictionary Light2D::_edit_get_state() const { - Dictionary state = Node2D::_edit_get_state(); - state["offset"] = get_texture_offset(); - return state; -} - -void Light2D::_edit_set_state(const Dictionary &p_state) { - Node2D::_edit_set_state(p_state); - set_texture_offset(p_state["offset"]); -} - -void Light2D::_edit_set_pivot(const Point2 &p_pivot) { - set_position(get_transform().xform(p_pivot)); - set_texture_offset(get_texture_offset() - p_pivot); -} - -Point2 Light2D::_edit_get_pivot() const { - return Vector2(); -} - -bool Light2D::_edit_use_pivot() const { - return true; -} - -Rect2 Light2D::_edit_get_rect() const { - if (texture.is_null()) { - return Rect2(); - } - - Size2 s = texture->get_size() * _scale; - return Rect2(texture_offset - s / 2.0, s); -} - -bool Light2D::_edit_use_rect() const { - return !texture.is_null(); -} -#endif - -Rect2 Light2D::get_anchorable_rect() const { - if (texture.is_null()) { - return Rect2(); - } - - Size2 s = texture->get_size() * _scale; - return Rect2(texture_offset - s / 2.0, s); -} - void Light2D::_update_light_visibility() { if (!is_inside_tree()) { return; @@ -123,32 +75,6 @@ bool Light2D::is_editor_only() const { return editor_only; } -void Light2D::set_texture(const Ref<Texture2D> &p_texture) { - texture = p_texture; - if (texture.is_valid()) { - RS::get_singleton()->canvas_light_set_texture(canvas_light, texture->get_rid()); - } else { - RS::get_singleton()->canvas_light_set_texture(canvas_light, RID()); - } - - update_configuration_warning(); -} - -Ref<Texture2D> Light2D::get_texture() const { - return texture; -} - -void Light2D::set_texture_offset(const Vector2 &p_offset) { - texture_offset = p_offset; - RS::get_singleton()->canvas_light_set_texture_offset(canvas_light, texture_offset); - item_rect_changed(); - _change_notify("offset"); -} - -Vector2 Light2D::get_texture_offset() const { - return texture_offset; -} - void Light2D::set_color(const Color &p_color) { color = p_color; RS::get_singleton()->canvas_light_set_color(canvas_light, color); @@ -176,20 +102,6 @@ float Light2D::get_energy() const { return energy; } -void Light2D::set_texture_scale(float p_scale) { - _scale = p_scale; - // Avoid having 0 scale values, can lead to errors in physics and rendering. - if (_scale == 0) { - _scale = CMP_EPSILON; - } - RS::get_singleton()->canvas_light_set_scale(canvas_light, _scale); - item_rect_changed(); -} - -float Light2D::get_texture_scale() const { - return _scale; -} - void Light2D::set_z_range_min(int p_min_z) { z_min = p_min_z; RS::get_singleton()->canvas_light_set_z_range(canvas_light, z_min, z_max); @@ -244,15 +156,6 @@ int Light2D::get_item_shadow_cull_mask() const { return item_shadow_mask; } -void Light2D::set_mode(Mode p_mode) { - mode = p_mode; - RS::get_singleton()->canvas_light_set_mode(canvas_light, RS::CanvasLightMode(p_mode)); -} - -Light2D::Mode Light2D::get_mode() const { - return mode; -} - void Light2D::set_shadow_enabled(bool p_enabled) { shadow = p_enabled; RS::get_singleton()->canvas_light_set_shadow_enabled(canvas_light, shadow); @@ -262,15 +165,6 @@ bool Light2D::is_shadow_enabled() const { return shadow; } -void Light2D::set_shadow_buffer_size(int p_size) { - shadow_buffer_size = p_size; - RS::get_singleton()->canvas_light_set_shadow_buffer_size(canvas_light, shadow_buffer_size); -} - -int Light2D::get_shadow_buffer_size() const { - return shadow_buffer_size; -} - void Light2D::set_shadow_filter(ShadowFilter p_filter) { ERR_FAIL_INDEX(p_filter, SHADOW_FILTER_MAX); shadow_filter = p_filter; @@ -290,6 +184,15 @@ Color Light2D::get_shadow_color() const { return shadow_color; } +void Light2D::set_blend_mode(BlendMode p_mode) { + blend_mode = p_mode; + RS::get_singleton()->canvas_light_set_blend_mode(_get_light(), RS::CanvasLightBlendMode(p_mode)); +} + +Light2D::BlendMode Light2D::get_blend_mode() const { + return blend_mode; +} + void Light2D::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, get_canvas()); @@ -309,14 +212,6 @@ void Light2D::_notification(int p_what) { } } -String Light2D::get_configuration_warning() const { - if (!texture.is_valid()) { - return TTR("A texture with the shape of the light must be supplied to the \"Texture\" property."); - } - - return String(); -} - void Light2D::set_shadow_smooth(float p_amount) { shadow_smooth = p_amount; RS::get_singleton()->canvas_light_set_shadow_smooth(canvas_light, shadow_smooth); @@ -333,24 +228,12 @@ void Light2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_editor_only", "editor_only"), &Light2D::set_editor_only); ClassDB::bind_method(D_METHOD("is_editor_only"), &Light2D::is_editor_only); - ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Light2D::set_texture); - ClassDB::bind_method(D_METHOD("get_texture"), &Light2D::get_texture); - - ClassDB::bind_method(D_METHOD("set_texture_offset", "texture_offset"), &Light2D::set_texture_offset); - ClassDB::bind_method(D_METHOD("get_texture_offset"), &Light2D::get_texture_offset); - ClassDB::bind_method(D_METHOD("set_color", "color"), &Light2D::set_color); ClassDB::bind_method(D_METHOD("get_color"), &Light2D::get_color); - ClassDB::bind_method(D_METHOD("set_height", "height"), &Light2D::set_height); - ClassDB::bind_method(D_METHOD("get_height"), &Light2D::get_height); - ClassDB::bind_method(D_METHOD("set_energy", "energy"), &Light2D::set_energy); ClassDB::bind_method(D_METHOD("get_energy"), &Light2D::get_energy); - ClassDB::bind_method(D_METHOD("set_texture_scale", "texture_scale"), &Light2D::set_texture_scale); - ClassDB::bind_method(D_METHOD("get_texture_scale"), &Light2D::get_texture_scale); - ClassDB::bind_method(D_METHOD("set_z_range_min", "z"), &Light2D::set_z_range_min); ClassDB::bind_method(D_METHOD("get_z_range_min"), &Light2D::get_z_range_min); @@ -369,15 +252,9 @@ void Light2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_item_shadow_cull_mask", "item_shadow_cull_mask"), &Light2D::set_item_shadow_cull_mask); ClassDB::bind_method(D_METHOD("get_item_shadow_cull_mask"), &Light2D::get_item_shadow_cull_mask); - ClassDB::bind_method(D_METHOD("set_mode", "mode"), &Light2D::set_mode); - ClassDB::bind_method(D_METHOD("get_mode"), &Light2D::get_mode); - ClassDB::bind_method(D_METHOD("set_shadow_enabled", "enabled"), &Light2D::set_shadow_enabled); ClassDB::bind_method(D_METHOD("is_shadow_enabled"), &Light2D::is_shadow_enabled); - ClassDB::bind_method(D_METHOD("set_shadow_buffer_size", "size"), &Light2D::set_shadow_buffer_size); - ClassDB::bind_method(D_METHOD("get_shadow_buffer_size"), &Light2D::get_shadow_buffer_size); - ClassDB::bind_method(D_METHOD("set_shadow_smooth", "smooth"), &Light2D::set_shadow_smooth); ClassDB::bind_method(D_METHOD("get_shadow_smooth"), &Light2D::get_shadow_smooth); @@ -387,16 +264,18 @@ void Light2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shadow_color", "shadow_color"), &Light2D::set_shadow_color); ClassDB::bind_method(D_METHOD("get_shadow_color"), &Light2D::get_shadow_color); + ClassDB::bind_method(D_METHOD("set_blend_mode", "mode"), &Light2D::set_blend_mode); + ClassDB::bind_method(D_METHOD("get_blend_mode"), &Light2D::get_blend_mode); + + ClassDB::bind_method(D_METHOD("set_height", "height"), &Light2D::set_height); + ClassDB::bind_method(D_METHOD("get_height"), &Light2D::get_height); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_texture_offset", "get_texture_offset"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_scale", PROPERTY_HINT_RANGE, "0.01,50,0.01"), "set_texture_scale", "get_texture_scale"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_energy", "get_energy"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Add,Sub,Mix,Mask"), "set_mode", "get_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Add,Sub,Mix"), "set_blend_mode", "get_blend_mode"); ADD_GROUP("Range", "range_"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "range_height", PROPERTY_HINT_RANGE, "-2048,2048,0.1,or_lesser,or_greater"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_min", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_min", "get_z_range_min"); ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_max", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_max", "get_z_range_max"); ADD_PROPERTY(PropertyInfo(Variant::INT, "range_layer_min", PROPERTY_HINT_RANGE, "-512,512,1"), "set_layer_range_min", "get_layer_range_min"); @@ -406,19 +285,17 @@ void Light2D::_bind_methods() { ADD_GROUP("Shadow", "shadow_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_enabled"), "set_shadow_enabled", "is_shadow_enabled"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_buffer_size", PROPERTY_HINT_RANGE, "32,16384,1"), "set_shadow_buffer_size", "get_shadow_buffer_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_filter", PROPERTY_HINT_ENUM, "None,PCF5,PCF13"), "set_shadow_filter", "get_shadow_filter"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shadow_filter_smooth", PROPERTY_HINT_RANGE, "0,64,0.1"), "set_shadow_smooth", "get_shadow_smooth"); ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_item_cull_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_item_shadow_cull_mask", "get_item_shadow_cull_mask"); - BIND_ENUM_CONSTANT(MODE_ADD); - BIND_ENUM_CONSTANT(MODE_SUB); - BIND_ENUM_CONSTANT(MODE_MIX); - BIND_ENUM_CONSTANT(MODE_MASK); - BIND_ENUM_CONSTANT(SHADOW_FILTER_NONE); BIND_ENUM_CONSTANT(SHADOW_FILTER_PCF5); BIND_ENUM_CONSTANT(SHADOW_FILTER_PCF13); + + BIND_ENUM_CONSTANT(BLEND_MODE_ADD); + BIND_ENUM_CONSTANT(BLEND_MODE_SUB); + BIND_ENUM_CONSTANT(BLEND_MODE_MIX); } Light2D::Light2D() { @@ -428,23 +305,168 @@ Light2D::Light2D() { shadow = false; color = Color(1, 1, 1); height = 0; - _scale = 1.0; z_min = -1024; z_max = 1024; layer_min = 0; layer_max = 0; item_mask = 1; item_shadow_mask = 1; - mode = MODE_ADD; - shadow_buffer_size = 2048; energy = 1.0; shadow_color = Color(0, 0, 0, 0); shadow_filter = SHADOW_FILTER_NONE; shadow_smooth = 0; - + blend_mode = BLEND_MODE_ADD; set_notify_transform(true); } Light2D::~Light2D() { RenderingServer::get_singleton()->free(canvas_light); } + +////////////////////////////// + +#ifdef TOOLS_ENABLED + +Dictionary PointLight2D::_edit_get_state() const { + Dictionary state = Node2D::_edit_get_state(); + state["offset"] = get_texture_offset(); + return state; +} + +void PointLight2D::_edit_set_state(const Dictionary &p_state) { + Node2D::_edit_set_state(p_state); + set_texture_offset(p_state["offset"]); +} + +void PointLight2D::_edit_set_pivot(const Point2 &p_pivot) { + set_position(get_transform().xform(p_pivot)); + set_texture_offset(get_texture_offset() - p_pivot); +} + +Point2 PointLight2D::_edit_get_pivot() const { + return Vector2(); +} + +bool PointLight2D::_edit_use_pivot() const { + return true; +} + +Rect2 PointLight2D::_edit_get_rect() const { + if (texture.is_null()) { + return Rect2(); + } + + Size2 s = texture->get_size() * _scale; + return Rect2(texture_offset - s / 2.0, s); +} + +bool PointLight2D::_edit_use_rect() const { + return !texture.is_null(); +} +#endif + +Rect2 PointLight2D::get_anchorable_rect() const { + if (texture.is_null()) { + return Rect2(); + } + + Size2 s = texture->get_size() * _scale; + return Rect2(texture_offset - s / 2.0, s); +} + +void PointLight2D::set_texture(const Ref<Texture2D> &p_texture) { + texture = p_texture; + if (texture.is_valid()) { + RS::get_singleton()->canvas_light_set_texture(_get_light(), texture->get_rid()); + } else { + RS::get_singleton()->canvas_light_set_texture(_get_light(), RID()); + } + + update_configuration_warning(); +} + +Ref<Texture2D> PointLight2D::get_texture() const { + return texture; +} + +void PointLight2D::set_texture_offset(const Vector2 &p_offset) { + texture_offset = p_offset; + RS::get_singleton()->canvas_light_set_texture_offset(_get_light(), texture_offset); + item_rect_changed(); + _change_notify("offset"); +} + +Vector2 PointLight2D::get_texture_offset() const { + return texture_offset; +} + +String PointLight2D::get_configuration_warning() const { + String warning = Node2D::get_configuration_warning(); + + if (!texture.is_valid()) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("A texture with the shape of the light must be supplied to the \"Texture\" property."); + } + + return warning; +} + +void PointLight2D::set_texture_scale(float p_scale) { + _scale = p_scale; + // Avoid having 0 scale values, can lead to errors in physics and rendering. + if (_scale == 0) { + _scale = CMP_EPSILON; + } + RS::get_singleton()->canvas_light_set_texture_scale(_get_light(), _scale); + item_rect_changed(); +} + +float PointLight2D::get_texture_scale() const { + return _scale; +} + +void PointLight2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_texture", "texture"), &PointLight2D::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &PointLight2D::get_texture); + + ClassDB::bind_method(D_METHOD("set_texture_offset", "texture_offset"), &PointLight2D::set_texture_offset); + ClassDB::bind_method(D_METHOD("get_texture_offset"), &PointLight2D::get_texture_offset); + + ClassDB::bind_method(D_METHOD("set_texture_scale", "texture_scale"), &PointLight2D::set_texture_scale); + ClassDB::bind_method(D_METHOD("get_texture_scale"), &PointLight2D::get_texture_scale); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_texture_offset", "get_texture_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_scale", PROPERTY_HINT_RANGE, "0.01,50,0.01"), "set_texture_scale", "get_texture_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1024,1,or_greater"), "set_height", "get_height"); +} + +PointLight2D::PointLight2D() { + RS::get_singleton()->canvas_light_set_mode(_get_light(), RS::CANVAS_LIGHT_MODE_POINT); +} + +////////// + +void DirectionalLight2D::set_max_distance(float p_distance) { + max_distance = p_distance; + RS::get_singleton()->canvas_light_set_directional_distance(_get_light(), max_distance); +} + +float DirectionalLight2D::get_max_distance() const { + return max_distance; +} + +void DirectionalLight2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_max_distance", "pixels"), &DirectionalLight2D::set_max_distance); + ClassDB::bind_method(D_METHOD("get_max_distance"), &DirectionalLight2D::get_max_distance); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,16384.0,1.0,or_greater"), "set_max_distance", "get_max_distance"); +} + +DirectionalLight2D::DirectionalLight2D() { + RS::get_singleton()->canvas_light_set_mode(_get_light(), RS::CANVAS_LIGHT_MODE_DIRECTIONAL); + set_max_distance(max_distance); // Update RenderingServer. +} diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index 45444800fe..7dfeddc8e5 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -37,13 +37,6 @@ class Light2D : public Node2D { GDCLASS(Light2D, Node2D); public: - enum Mode { - MODE_ADD, - MODE_SUB, - MODE_MIX, - MODE_MASK, - }; - enum ShadowFilter { SHADOW_FILTER_NONE, SHADOW_FILTER_PCF5, @@ -51,6 +44,12 @@ public: SHADOW_FILTER_MAX }; + enum BlendMode { + BLEND_MODE_ADD, + BLEND_MODE_SUB, + BLEND_MODE_MIX, + }; + private: RID canvas_light; bool enabled; @@ -59,7 +58,6 @@ private: Color color; Color shadow_color; float height; - float _scale; float energy; int z_min; int z_max; @@ -67,45 +65,26 @@ private: int layer_max; int item_mask; int item_shadow_mask; - int shadow_buffer_size; float shadow_smooth; - Mode mode; Ref<Texture2D> texture; Vector2 texture_offset; ShadowFilter shadow_filter; + BlendMode blend_mode; void _update_light_visibility(); protected: + _FORCE_INLINE_ RID _get_light() const { return canvas_light; } void _notification(int p_what); static void _bind_methods(); public: -#ifdef TOOLS_ENABLED - virtual Dictionary _edit_get_state() const override; - virtual void _edit_set_state(const Dictionary &p_state) override; - - virtual void _edit_set_pivot(const Point2 &p_pivot) override; - virtual Point2 _edit_get_pivot() const override; - virtual bool _edit_use_pivot() const override; - virtual Rect2 _edit_get_rect() const override; - virtual bool _edit_use_rect() const override; -#endif - - virtual Rect2 get_anchorable_rect() const override; - void set_enabled(bool p_enabled); bool is_enabled() const; void set_editor_only(bool p_editor_only); bool is_editor_only() const; - void set_texture(const Ref<Texture2D> &p_texture); - Ref<Texture2D> get_texture() const; - - void set_texture_offset(const Vector2 &p_offset); - Vector2 get_texture_offset() const; - void set_color(const Color &p_color); Color get_color() const; @@ -115,9 +94,6 @@ public: void set_energy(float p_energy); float get_energy() const; - void set_texture_scale(float p_scale); - float get_texture_scale() const; - void set_z_range_min(int p_min_z); int get_z_range_min() const; @@ -136,15 +112,9 @@ public: void set_item_shadow_cull_mask(int p_mask); int get_item_shadow_cull_mask() const; - void set_mode(Mode p_mode); - Mode get_mode() const; - void set_shadow_enabled(bool p_enabled); bool is_shadow_enabled() const; - void set_shadow_buffer_size(int p_size); - int get_shadow_buffer_size() const; - void set_shadow_filter(ShadowFilter p_filter); ShadowFilter get_shadow_filter() const; @@ -154,13 +124,68 @@ public: void set_shadow_smooth(float p_amount); float get_shadow_smooth() const; - String get_configuration_warning() const override; + void set_blend_mode(BlendMode p_mode); + BlendMode get_blend_mode() const; Light2D(); ~Light2D(); }; -VARIANT_ENUM_CAST(Light2D::Mode); VARIANT_ENUM_CAST(Light2D::ShadowFilter); +VARIANT_ENUM_CAST(Light2D::BlendMode); + +class PointLight2D : public Light2D { + GDCLASS(PointLight2D, Light2D); + +private: + float _scale = 1.0; + Ref<Texture2D> texture; + Vector2 texture_offset; + +protected: + static void _bind_methods(); + +public: +#ifdef TOOLS_ENABLED + virtual Dictionary _edit_get_state() const override; + virtual void _edit_set_state(const Dictionary &p_state) override; + + virtual void _edit_set_pivot(const Point2 &p_pivot) override; + virtual Point2 _edit_get_pivot() const override; + virtual bool _edit_use_pivot() const override; + virtual Rect2 _edit_get_rect() const override; + virtual bool _edit_use_rect() const override; +#endif + + virtual Rect2 get_anchorable_rect() const override; + + void set_texture(const Ref<Texture2D> &p_texture); + Ref<Texture2D> get_texture() const; + + void set_texture_offset(const Vector2 &p_offset); + Vector2 get_texture_offset() const; + + void set_texture_scale(float p_scale); + float get_texture_scale() const; + + String get_configuration_warning() const override; + + PointLight2D(); +}; + +class DirectionalLight2D : public Light2D { + GDCLASS(DirectionalLight2D, Light2D); + + float max_distance = 10000.0; + +protected: + static void _bind_methods(); + +public: + void set_max_distance(float p_distance); + float get_max_distance() const; + + DirectionalLight2D(); +}; #endif // LIGHT_2D_H diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index 023cfa6d03..0531762ed8 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -31,7 +31,7 @@ #include "light_occluder_2d.h" #include "core/math/geometry_2d.h" -#include "core/engine.h" +#include "core/config/engine.h" #define LINE_GRAB_WIDTH 8 @@ -246,15 +246,23 @@ int LightOccluder2D::get_occluder_light_mask() const { } String LightOccluder2D::get_configuration_warning() const { + String warning = Node2D::get_configuration_warning(); + if (!occluder_polygon.is_valid()) { - return TTR("An occluder polygon must be set (or drawn) for this occluder to take effect."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("An occluder polygon must be set (or drawn) for this occluder to take effect."); } if (occluder_polygon.is_valid() && occluder_polygon->get_polygon().size() == 0) { - return TTR("The occluder polygon for this occluder is empty. Please draw a polygon."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The occluder polygon for this occluder is empty. Please draw a polygon."); } - return String(); + return warning; } void LightOccluder2D::_bind_methods() { diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index b120b115b0..e990e9f53e 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -177,7 +177,7 @@ void Line2D::set_gradient(const Ref<Gradient> &p_gradient) { _gradient = p_gradient; - // Connect to the gradient so the line will update when the ColorRamp is changed + // Connect to the gradient so the line will update when the Gradient is changed if (_gradient.is_valid()) { _gradient->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Line2D::_gradient_changed)); } diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h index 9e3dbbd6c1..0e033d9be1 100644 --- a/scene/2d/line_builder.h +++ b/scene/2d/line_builder.h @@ -31,7 +31,7 @@ #ifndef LINE_BUILDER_H #define LINE_BUILDER_H -#include "core/color.h" +#include "core/math/color.h" #include "core/math/vector2.h" #include "line_2d.h" #include "scene/resources/gradient.h" diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp index 897595ad1f..037e423ce9 100644 --- a/scene/2d/mesh_instance_2d.cpp +++ b/scene/2d/mesh_instance_2d.cpp @@ -33,7 +33,7 @@ void MeshInstance2D::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { if (mesh.is_valid()) { - draw_mesh(mesh, texture, normal_map); + draw_mesh(mesh, texture); } } } diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp index b99c0a3fa9..c258e30eab 100644 --- a/scene/2d/multimesh_instance_2d.cpp +++ b/scene/2d/multimesh_instance_2d.cpp @@ -33,7 +33,7 @@ void MultiMeshInstance2D::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { if (multimesh.is_valid()) { - draw_multimesh(multimesh, texture, normal_map); + draw_multimesh(multimesh, texture); } } } diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index e5cdade4a4..1c7063d0d3 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -30,7 +30,7 @@ #include "navigation_agent_2d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "core/math/geometry_2d.h" #include "scene/2d/navigation_2d.h" #include "servers/navigation_server_2d.h" @@ -271,11 +271,16 @@ void NavigationAgent2D::_avoidance_done(Vector3 p_new_velocity) { } String NavigationAgent2D::get_configuration_warning() const { + String warning = Node::get_configuration_warning(); + if (!Object::cast_to<Node2D>(get_parent())) { - return TTR("The NavigationAgent2D can be used only under a Node2D node"); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The NavigationAgent2D can be used only under a Node2D node"); } - return String(); + return warning; } void NavigationAgent2D::update_navigation() { diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h index 9474392ddf..1f2377837b 100644 --- a/scene/2d/navigation_agent_2d.h +++ b/scene/2d/navigation_agent_2d.h @@ -31,7 +31,7 @@ #ifndef NAVIGATION_AGENT_2D_H #define NAVIGATION_AGENT_2D_H -#include "core/vector.h" +#include "core/templates/vector.h" #include "scene/main/node.h" class Node2D; diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp index 568023bbe2..252d7cbb96 100644 --- a/scene/2d/navigation_obstacle_2d.cpp +++ b/scene/2d/navigation_obstacle_2d.cpp @@ -106,11 +106,16 @@ Node *NavigationObstacle2D::get_navigation_node() const { } String NavigationObstacle2D::get_configuration_warning() const { + String warning = Node::get_configuration_warning(); + if (!Object::cast_to<Node2D>(get_parent())) { - return TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object."); } - return String(); + return warning; } void NavigationObstacle2D::update_agent_shape() { diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 671bda558d..98817ec03e 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -30,8 +30,8 @@ #include "navigation_region_2d.h" +#include "core/config/engine.h" #include "core/core_string_names.h" -#include "core/engine.h" #include "core/math/geometry_2d.h" #include "core/os/mutex.h" #include "navigation_2d.h" @@ -500,19 +500,26 @@ String NavigationRegion2D::get_configuration_warning() const { return String(); } + String warning = Node2D::get_configuration_warning(); + if (!navpoly.is_valid()) { - return TTR("A NavigationPolygon resource must be set or created for this node to work. Please set a property or draw a polygon."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("A NavigationPolygon resource must be set or created for this node to work. Please set a property or draw a polygon."); } const Node2D *c = this; while (c) { if (Object::cast_to<Navigation2D>(c)) { - return String(); + return warning; } c = Object::cast_to<Node2D>(c->get_parent()); } - - return TTR("NavigationRegion2D must be a child or grandchild to a Navigation2D node. It only provides navigation data."); + if (!warning.empty()) { + warning += "\n\n"; + } + return warning + TTR("NavigationRegion2D must be a child or grandchild to a Navigation2D node. It only provides navigation data."); } void NavigationRegion2D::_bind_methods() { diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 72250e96b3..42c2585487 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -30,7 +30,7 @@ #include "node_2d.h" -#include "core/message_queue.h" +#include "core/object/message_queue.h" #include "scene/gui/control.h" #include "scene/main/window.h" #include "servers/rendering_server.h" diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp index 416622e6d5..8c9432f2fa 100644 --- a/scene/2d/parallax_background.cpp +++ b/scene/2d/parallax_background.cpp @@ -101,7 +101,7 @@ void ParallaxBackground::_update_scroll() { } if (ignore_camera_zoom) { - l->set_base_offset_and_scale(ofs, 1.0, screen_offset); + l->set_base_offset_and_scale((ofs + screen_offset * (scale - 1)) / scale, 1.0, screen_offset); } else { l->set_base_offset_and_scale(ofs, scale, screen_offset); } diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index 4ed335dec8..01aa5838b4 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -30,7 +30,7 @@ #include "parallax_layer.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "parallax_background.h" void ParallaxLayer::set_motion_scale(const Size2 &p_scale) { @@ -136,11 +136,16 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, float p_sc } String ParallaxLayer::get_configuration_warning() const { + String warning = Node2D::get_configuration_warning(); + if (!Object::cast_to<ParallaxBackground>(get_parent())) { - return TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node."); } - return String(); + return warning; } void ParallaxLayer::_bind_methods() { diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index f2f549e851..d305f2805e 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -30,7 +30,7 @@ #include "path_2d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "core/math/geometry_2d.h" #include "scene/scene_string_names.h" @@ -254,11 +254,16 @@ String PathFollow2D::get_configuration_warning() const { return String(); } + String warning = Node2D::get_configuration_warning(); + if (!Object::cast_to<Path2D>(get_parent())) { - return TTR("PathFollow2D only works when set as a child of a Path2D node."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("PathFollow2D only works when set as a child of a Path2D node."); } - return String(); + return warning; } void PathFollow2D::_bind_methods() { diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 0a9de20664..300799ff9d 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -30,27 +30,17 @@ #include "physics_body_2d.h" +#include "core/config/engine.h" #include "core/core_string_names.h" -#include "core/engine.h" -#include "core/list.h" #include "core/math/math_funcs.h" -#include "core/method_bind_ext.gen.inc" -#include "core/object.h" -#include "core/rid.h" +#include "core/object/class_db.h" +#include "core/templates/list.h" +#include "core/templates/rid.h" #include "scene/scene_string_names.h" void PhysicsBody2D::_notification(int p_what) { } -void PhysicsBody2D::_set_layers(uint32_t p_mask) { - set_collision_layer(p_mask); - set_collision_mask(p_mask); -} - -uint32_t PhysicsBody2D::_get_layers() const { - return get_collision_layer(); -} - void PhysicsBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &PhysicsBody2D::set_collision_layer); ClassDB::bind_method(D_METHOD("get_collision_layer"), &PhysicsBody2D::get_collision_layer); @@ -63,13 +53,9 @@ void PhysicsBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &PhysicsBody2D::set_collision_layer_bit); ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &PhysicsBody2D::get_collision_layer_bit); - ClassDB::bind_method(D_METHOD("_set_layers", "mask"), &PhysicsBody2D::_set_layers); - ClassDB::bind_method(D_METHOD("_get_layers"), &PhysicsBody2D::_get_layers); - ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with); ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody2D::remove_collision_exception_with); - ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_2D_PHYSICS, "", 0), "_set_layers", "_get_layers"); //for backwards compat ADD_GROUP("Collision", "collision_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer"); @@ -748,7 +734,7 @@ String RigidBody2D::get_configuration_warning() const { String warning = CollisionObject2D::get_configuration_warning(); if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.elements[0].length() - 1.0) > 0.05 || ABS(t.elements[1].length() - 1.0) > 0.05)) { - if (warning != String()) { + if (!warning.empty()) { warning += "\n\n"; } warning += TTR("Size changes to RigidBody2D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."); diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index e83ab6557d..1db2d23bb8 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -31,7 +31,7 @@ #ifndef PHYSICS_BODY_2D_H #define PHYSICS_BODY_2D_H -#include "core/vset.h" +#include "core/templates/vset.h" #include "scene/2d/collision_object_2d.h" #include "scene/resources/physics_material.h" #include "servers/physics_server_2d.h" @@ -44,9 +44,6 @@ class PhysicsBody2D : public CollisionObject2D { uint32_t collision_layer; uint32_t collision_mask; - void _set_layers(uint32_t p_mask); - uint32_t _get_layers() const; - protected: void _notification(int p_what); PhysicsBody2D(PhysicsServer2D::BodyMode p_mode); diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index 13b62816a4..26340bb861 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -302,7 +302,7 @@ void Polygon2D::_notification(int p_what) { if (invert || polygons.size() == 0) { Vector<int> indices = Geometry2D::triangulate_polygon(points); if (indices.size()) { - RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID(), -1, normal_map.is_valid() ? normal_map->get_rid() : RID(), specular_map.is_valid() ? specular_map->get_rid() : RID(), Color(specular_color.r, specular_color.g, specular_color.b, shininess)); + RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID(), -1); } } else { //draw individual polygons @@ -417,42 +417,6 @@ Ref<Texture2D> Polygon2D::get_texture() const { return texture; } -void Polygon2D::set_normal_map(const Ref<Texture2D> &p_normal_map) { - normal_map = p_normal_map; - update(); -} - -Ref<Texture2D> Polygon2D::get_normal_map() const { - return normal_map; -} - -void Polygon2D::set_specular_map(const Ref<Texture2D> &p_specular_map) { - specular_map = p_specular_map; - update(); -} - -Ref<Texture2D> Polygon2D::get_specular_map() const { - return specular_map; -} - -void Polygon2D::set_specular_color(const Color &p_specular_color) { - specular_color = p_specular_color; - update(); -} - -Color Polygon2D::get_specular_color() const { - return specular_color; -} - -void Polygon2D::set_shininess(float p_shininess) { - shininess = CLAMP(p_shininess, 0.0, 1.0); - update(); -} - -float Polygon2D::get_shininess() const { - return shininess; -} - void Polygon2D::set_texture_offset(const Vector2 &p_offset) { tex_ofs = p_offset; update(); @@ -616,18 +580,6 @@ void Polygon2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Polygon2D::set_texture); ClassDB::bind_method(D_METHOD("get_texture"), &Polygon2D::get_texture); - ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &Polygon2D::set_normal_map); - ClassDB::bind_method(D_METHOD("get_normal_map"), &Polygon2D::get_normal_map); - - ClassDB::bind_method(D_METHOD("set_specular_map", "specular_map"), &Polygon2D::set_specular_map); - ClassDB::bind_method(D_METHOD("get_specular_map"), &Polygon2D::get_specular_map); - - ClassDB::bind_method(D_METHOD("set_specular_color", "specular_color"), &Polygon2D::set_specular_color); - ClassDB::bind_method(D_METHOD("get_specular_color"), &Polygon2D::get_specular_color); - - ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &Polygon2D::set_shininess); - ClassDB::bind_method(D_METHOD("get_shininess"), &Polygon2D::get_shininess); - ClassDB::bind_method(D_METHOD("set_texture_offset", "texture_offset"), &Polygon2D::set_texture_offset); ClassDB::bind_method(D_METHOD("get_texture_offset"), &Polygon2D::get_texture_offset); @@ -680,11 +632,6 @@ void Polygon2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale"), "set_texture_scale", "get_texture_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater"), "set_texture_rotation_degrees", "get_texture_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_rotation", PROPERTY_HINT_NONE, "", 0), "set_texture_rotation", "get_texture_rotation"); - ADD_GROUP("Lighting", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "specular_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_specular_map", "get_specular_map"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess"); ADD_GROUP("Skeleton", ""); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton"); @@ -711,7 +658,4 @@ Polygon2D::Polygon2D() { color = Color(1, 1, 1); rect_cache_dirty = true; internal_vertices = 0; - - specular_color = Color(1, 1, 1, 1); - shininess = 1.0; } diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h index c5ff05aace..e2a8db414a 100644 --- a/scene/2d/polygon_2d.h +++ b/scene/2d/polygon_2d.h @@ -51,10 +51,6 @@ class Polygon2D : public Node2D { Color color; Ref<Texture2D> texture; - Ref<Texture2D> normal_map; - Ref<Texture2D> specular_map; - Color specular_color; - float shininess; Size2 tex_scale; Vector2 tex_ofs; @@ -115,18 +111,6 @@ public: void set_texture(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_texture() const; - void set_normal_map(const Ref<Texture2D> &p_normal_map); - Ref<Texture2D> get_normal_map() const; - - void set_specular_map(const Ref<Texture2D> &p_specular_map); - Ref<Texture2D> get_specular_map() const; - - void set_specular_color(const Color &p_specular_color); - Color get_specular_color() const; - - void set_shininess(float p_shininess); - float get_shininess() const; - void set_texture_offset(const Vector2 &p_offset); Vector2 get_texture_offset() const; diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp index a94a9f7085..8e4165cf50 100644 --- a/scene/2d/position_2d.cpp +++ b/scene/2d/position_2d.cpp @@ -30,7 +30,7 @@ #include "position_2d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "scene/resources/texture.h" const float DEFAULT_GIZMO_EXTENTS = 10.0; diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index 9fd24b5294..e53f89c46d 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -31,19 +31,19 @@ #include "ray_cast_2d.h" #include "collision_object_2d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "physics_body_2d.h" #include "servers/physics_server_2d.h" -void RayCast2D::set_cast_to(const Vector2 &p_point) { - cast_to = p_point; +void RayCast2D::set_target_position(const Vector2 &p_point) { + target_position = p_point; if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) { update(); } } -Vector2 RayCast2D::get_cast_to() const { - return cast_to; +Vector2 RayCast2D::get_target_position() const { + return target_position; } void RayCast2D::set_collision_mask(uint32_t p_mask) { @@ -160,8 +160,8 @@ void RayCast2D::_notification(int p_what) { break; } Transform2D xf; - xf.rotate(cast_to.angle()); - xf.translate(Vector2(cast_to.length(), 0)); + xf.rotate(target_position.angle()); + xf.translate(Vector2(target_position.length(), 0)); // Draw an arrow indicating where the RayCast is pointing to Color draw_col = get_tree()->get_debug_collisions_color(); @@ -171,7 +171,7 @@ void RayCast2D::_notification(int p_what) { draw_col.g = g; draw_col.b = g; } - draw_line(Vector2(), cast_to, draw_col, 2); + draw_line(Vector2(), target_position, draw_col, 2); Vector<Vector2> pts; float tsize = 8; pts.push_back(xf.xform(Vector2(tsize, 0))); @@ -206,7 +206,7 @@ void RayCast2D::_update_raycast_state() { Transform2D gt = get_global_transform(); - Vector2 to = cast_to; + Vector2 to = target_position; if (to == Vector2()) { to = Vector2(0, 0.01); } @@ -280,8 +280,8 @@ void RayCast2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast2D::set_enabled); ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast2D::is_enabled); - ClassDB::bind_method(D_METHOD("set_cast_to", "local_point"), &RayCast2D::set_cast_to); - ClassDB::bind_method(D_METHOD("get_cast_to"), &RayCast2D::get_cast_to); + ClassDB::bind_method(D_METHOD("set_target_position", "local_point"), &RayCast2D::set_target_position); + ClassDB::bind_method(D_METHOD("get_target_position"), &RayCast2D::get_target_position); ClassDB::bind_method(D_METHOD("is_colliding"), &RayCast2D::is_colliding); ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast2D::force_raycast_update); @@ -316,7 +316,7 @@ void RayCast2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cast_to"), "set_cast_to", "get_cast_to"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_position"), "set_target_position", "get_target_position"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); ADD_GROUP("Collide With", "collide_with"); @@ -329,7 +329,7 @@ RayCast2D::RayCast2D() { collided = false; against_shape = 0; collision_mask = 1; - cast_to = Vector2(0, 50); + target_position = Vector2(0, 50); exclude_parent_body = true; collide_with_bodies = true; collide_with_areas = false; diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h index 6accc264a0..14932f782b 100644 --- a/scene/2d/ray_cast_2d.h +++ b/scene/2d/ray_cast_2d.h @@ -46,7 +46,7 @@ class RayCast2D : public Node2D { uint32_t collision_mask; bool exclude_parent_body; - Vector2 cast_to; + Vector2 target_position; bool collide_with_areas; bool collide_with_bodies; @@ -66,8 +66,8 @@ public: void set_enabled(bool p_enabled); bool is_enabled() const; - void set_cast_to(const Vector2 &p_point); - Vector2 get_cast_to() const; + void set_target_position(const Vector2 &p_point); + Vector2 get_target_position() const; void set_collision_mask(uint32_t p_mask); uint32_t get_collision_mask() const; diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp index 3104436dbe..7655416ce2 100644 --- a/scene/2d/remote_transform_2d.cpp +++ b/scene/2d/remote_transform_2d.cpp @@ -186,11 +186,16 @@ void RemoteTransform2D::force_update_cache() { } String RemoteTransform2D::get_configuration_warning() const { + String warning = Node2D::get_configuration_warning(); + if (!has_node(remote_node) || !Object::cast_to<Node2D>(get_node(remote_node))) { - return TTR("Path property must point to a valid Node2D node to work."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("Path property must point to a valid Node2D node to work."); } - return String(); + return warning; } void RemoteTransform2D::_bind_methods() { diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index ea37c8dfe7..ea1d9f5930 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -136,7 +136,7 @@ int Bone2D::get_index_in_skeleton() const { String Bone2D::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); if (!skeleton) { - if (warning != String()) { + if (!warning.empty()) { warning += "\n\n"; } if (parent_bone) { @@ -147,7 +147,7 @@ String Bone2D::get_configuration_warning() const { } if (rest == Transform2D(0, 0, 0, 0, 0, 0)) { - if (warning != String()) { + if (!warning.empty()) { warning += "\n\n"; } warning += TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."); diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index 7e07019578..a065565a0f 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -99,7 +99,8 @@ void Sprite2D::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_c if (centered) { dest_offset -= frame_size / 2; } - if (Engine::get_singleton()->get_use_pixel_snap()) { + + if (get_viewport() && get_viewport()->is_snap_2d_transforms_to_pixel_enabled()) { dest_offset = dest_offset.floor(); } @@ -130,8 +131,8 @@ void Sprite2D::_notification(int p_what) { Rect2 src_rect, dst_rect; bool filter_clip; _get_rects(src_rect, dst_rect, filter_clip); - texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map, specular, Color(specular_color.r, specular_color.g, specular_color.b, shininess), RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, filter_clip); + texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, filter_clip); } break; } } @@ -157,42 +158,6 @@ void Sprite2D::set_texture(const Ref<Texture2D> &p_texture) { _change_notify("texture"); } -void Sprite2D::set_normal_map(const Ref<Texture2D> &p_texture) { - normal_map = p_texture; - update(); -} - -Ref<Texture2D> Sprite2D::get_normal_map() const { - return normal_map; -} - -void Sprite2D::set_specular_map(const Ref<Texture2D> &p_texture) { - specular = p_texture; - update(); -} - -Ref<Texture2D> Sprite2D::get_specular_map() const { - return specular; -} - -void Sprite2D::set_specular_color(const Color &p_color) { - specular_color = p_color; - update(); -} - -Color Sprite2D::get_specular_color() const { - return specular_color; -} - -void Sprite2D::set_shininess(float p_shininess) { - shininess = CLAMP(p_shininess, 0.0, 1.0); - update(); -} - -float Sprite2D::get_shininess() const { - return shininess; -} - Ref<Texture2D> Sprite2D::get_texture() const { return texture; } @@ -403,6 +368,10 @@ Rect2 Sprite2D::get_rect() const { ofs -= Size2(s) / 2; } + if (get_viewport() && get_viewport()->is_snap_2d_transforms_to_pixel_enabled()) { + ofs = ofs.floor(); + } + if (s == Size2(0, 0)) { s = Size2(1, 1); } @@ -434,18 +403,6 @@ void Sprite2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Sprite2D::set_texture); ClassDB::bind_method(D_METHOD("get_texture"), &Sprite2D::get_texture); - ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &Sprite2D::set_normal_map); - ClassDB::bind_method(D_METHOD("get_normal_map"), &Sprite2D::get_normal_map); - - ClassDB::bind_method(D_METHOD("set_specular_map", "specular_map"), &Sprite2D::set_specular_map); - ClassDB::bind_method(D_METHOD("get_specular_map"), &Sprite2D::get_specular_map); - - ClassDB::bind_method(D_METHOD("set_specular_color", "specular_color"), &Sprite2D::set_specular_color); - ClassDB::bind_method(D_METHOD("get_specular_color"), &Sprite2D::get_specular_color); - - ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &Sprite2D::set_shininess); - ClassDB::bind_method(D_METHOD("get_shininess"), &Sprite2D::get_shininess); - ClassDB::bind_method(D_METHOD("set_centered", "centered"), &Sprite2D::set_centered); ClassDB::bind_method(D_METHOD("is_centered"), &Sprite2D::is_centered); @@ -487,19 +444,14 @@ void Sprite2D::_bind_methods() { ADD_SIGNAL(MethodInfo("texture_changed")); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); - ADD_GROUP("Lighting", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "specular_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_specular_map", "get_specular_map"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess"); ADD_GROUP("Offset", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v"); ADD_GROUP("Animation", ""); - ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes"); ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes"); ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords"); @@ -515,8 +467,6 @@ Sprite2D::Sprite2D() { vflip = false; region = false; region_filter_clip = false; - shininess = 1.0; - specular_color = Color(1, 1, 1, 1); frame = 0; diff --git a/scene/2d/sprite_2d.h b/scene/2d/sprite_2d.h index f6b752575f..2875d333bb 100644 --- a/scene/2d/sprite_2d.h +++ b/scene/2d/sprite_2d.h @@ -38,8 +38,6 @@ class Sprite2D : public Node2D { GDCLASS(Sprite2D, Node2D); Ref<Texture2D> texture; - Ref<Texture2D> normal_map; - Ref<Texture2D> specular; Color specular_color; float shininess; @@ -87,18 +85,6 @@ public: void set_texture(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_texture() const; - void set_normal_map(const Ref<Texture2D> &p_texture); - Ref<Texture2D> get_normal_map() const; - - void set_specular_map(const Ref<Texture2D> &p_texture); - Ref<Texture2D> get_specular_map() const; - - void set_specular_color(const Color &p_color); - Color get_specular_color() const; - - void set_shininess(float p_shininess); - float get_shininess() const; - void set_centered(bool p_center); bool is_centered() const; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index c7a809f6d8..bff191a2bf 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -32,7 +32,6 @@ #include "collision_object_2d.h" #include "core/io/marshalls.h" -#include "core/method_bind_ext.gen.inc" #include "core/os/os.h" #include "scene/2d/area_2d.h" #include "servers/navigation_server_2d.h" @@ -412,6 +411,9 @@ void TileMap::update_dirty_quadrants() { vs->canvas_item_set_light_mask(canvas_item, get_light_mask()); vs->canvas_item_set_z_index(canvas_item, z_index); + vs->canvas_item_set_default_texture_filter(canvas_item, RS::CanvasItemTextureFilter(CanvasItem::get_texture_filter())); + vs->canvas_item_set_default_texture_repeat(canvas_item, RS::CanvasItemTextureRepeat(CanvasItem::get_texture_repeat())); + q.canvas_items.push_back(canvas_item); if (debug_shapes) { @@ -526,15 +528,14 @@ void TileMap::update_dirty_quadrants() { rect.position += tile_ofs; } - Ref<Texture2D> normal_map = tile_set->tile_get_normal_map(c.id); Color modulate = tile_set->tile_get_modulate(c.id); Color self_modulate = get_self_modulate(); modulate = Color(modulate.r * self_modulate.r, modulate.g * self_modulate.g, modulate.b * self_modulate.b, modulate.a * self_modulate.a); if (r == Rect2()) { - tex->draw_rect(canvas_item, rect, false, modulate, c.transpose, normal_map); + tex->draw_rect(canvas_item, rect, false, modulate, c.transpose); } else { - tex->draw_rect_region(canvas_item, rect, r, modulate, c.transpose, normal_map, Ref<Texture2D>(), Color(1, 1, 1, 1), RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, clip_uv); + tex->draw_rect_region(canvas_item, rect, r, modulate, c.transpose, clip_uv); } Vector<TileSet::ShapeData> shapes = tile_set->tile_get_shapes(c.id); @@ -1687,6 +1688,28 @@ bool TileMap::get_clip_uv() const { return clip_uv; } +void TileMap::set_texture_filter(TextureFilter p_texture_filter) { + CanvasItem::set_texture_filter(p_texture_filter); + for (Map<PosKey, Quadrant>::Element *F = quadrant_map.front(); F; F = F->next()) { + Quadrant &q = F->get(); + for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) { + RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(E->get(), RS::CanvasItemTextureFilter(p_texture_filter)); + _make_quadrant_dirty(F); + } + } +} + +void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) { + CanvasItem::set_texture_repeat(p_texture_repeat); + for (Map<PosKey, Quadrant>::Element *F = quadrant_map.front(); F; F = F->next()) { + Quadrant &q = F->get(); + for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) { + RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(E->get(), RS::CanvasItemTextureRepeat(p_texture_repeat)); + _make_quadrant_dirty(F); + } + } +} + String TileMap::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 7a2a3e412c..22b615a379 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -31,8 +31,8 @@ #ifndef TILE_MAP_H #define TILE_MAP_H -#include "core/self_list.h" -#include "core/vset.h" +#include "core/templates/self_list.h" +#include "core/templates/vset.h" #include "scene/2d/navigation_2d.h" #include "scene/2d/node_2d.h" #include "scene/resources/tile_set.h" @@ -342,6 +342,10 @@ public: String get_configuration_warning() const override; + virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override; + + virtual void set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) override; + void fix_invalid_tiles(); void clear(); diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp index 75154c7acb..e217f2a394 100644 --- a/scene/2d/visibility_notifier_2d.cpp +++ b/scene/2d/visibility_notifier_2d.cpp @@ -30,7 +30,7 @@ #include "visibility_notifier_2d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "gpu_particles_2d.h" #include "scene/2d/animated_sprite_2d.h" #include "scene/2d/physics_body_2d.h" @@ -313,12 +313,17 @@ void VisibilityEnabler2D::_node_removed(Node *p_node) { } String VisibilityEnabler2D::get_configuration_warning() const { + String warning = VisibilityNotifier2D::get_configuration_warning(); + #ifdef TOOLS_ENABLED if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) { - return TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent."); } #endif - return String(); + return warning; } void VisibilityEnabler2D::_bind_methods() { diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp index a024757927..b1ffe76662 100644 --- a/scene/3d/area_3d.cpp +++ b/scene/3d/area_3d.cpp @@ -180,26 +180,20 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i E->get().shapes.erase(ShapePair(p_body_shape, p_area_shape)); } - bool eraseit = false; - + bool in_tree = E->get().in_tree; if (E->get().rc == 0) { + body_map.erase(E); if (node) { node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree)); node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree)); - if (E->get().in_tree) { + if (in_tree) { emit_signal(SceneStringNames::get_singleton()->body_exited, obj); } } - - eraseit = true; } - if (node && E->get().in_tree) { + if (node && in_tree) { emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, obj, p_body_shape, p_area_shape); } - - if (eraseit) { - body_map.erase(E); - } } locked = false; @@ -222,6 +216,9 @@ void Area3D::_clear_monitoring() { } //ERR_CONTINUE(!node); + node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree)); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree)); + if (!E->get().in_tree) { continue; } @@ -231,9 +228,6 @@ void Area3D::_clear_monitoring() { } emit_signal(SceneStringNames::get_singleton()->body_exited, node); - - node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree)); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree)); } } @@ -251,6 +245,9 @@ void Area3D::_clear_monitoring() { } //ERR_CONTINUE(!node); + node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree)); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree)); + if (!E->get().in_tree) { continue; } @@ -260,9 +257,6 @@ void Area3D::_clear_monitoring() { } emit_signal(SceneStringNames::get_singleton()->area_exited, obj); - - node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree)); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree)); } } } @@ -366,26 +360,20 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i E->get().shapes.erase(AreaShapePair(p_area_shape, p_self_shape)); } - bool eraseit = false; - + bool in_tree = E->get().in_tree; if (E->get().rc == 0) { + area_map.erase(E); if (node) { node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree)); node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree)); - if (E->get().in_tree) { + if (in_tree) { emit_signal(SceneStringNames::get_singleton()->area_exited, obj); } } - - eraseit = true; } - if (!node || E->get().in_tree) { + if (!node || in_tree) { emit_signal(SceneStringNames::get_singleton()->area_shape_exited, objid, obj, p_area_shape, p_self_shape); } - - if (eraseit) { - area_map.erase(E); - } } locked = false; diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h index 07d24f39a7..7d1f030baf 100644 --- a/scene/3d/area_3d.h +++ b/scene/3d/area_3d.h @@ -31,7 +31,7 @@ #ifndef AREA_3D_H #define AREA_3D_H -#include "core/vset.h" +#include "core/templates/vset.h" #include "scene/3d/collision_object_3d.h" class Area3D : public CollisionObject3D { diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 6e4db8f382..b093788d75 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -30,7 +30,7 @@ #include "audio_stream_player_3d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "scene/3d/area_3d.h" #include "scene/3d/camera_3d.h" #include "scene/3d/listener_3d.h" diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index e867891ec0..38c9e96fbc 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -37,7 +37,7 @@ #include "core/os/dir_access.h" #include "core/os/file_access.h" #include "core/os/os.h" -#include "core/sort_array.h" +#include "core/templates/sort_array.h" #include "lightmap_probe.h" void BakedLightmapData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) { diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h index bebb579252..8808569215 100644 --- a/scene/3d/baked_lightmap.h +++ b/scene/3d/baked_lightmap.h @@ -31,7 +31,7 @@ #ifndef BAKED_LIGHTMAP_H #define BAKED_LIGHTMAP_H -#include "core/local_vector.h" +#include "core/templates/local_vector.h" #include "scene/3d/light_3d.h" #include "scene/3d/lightmapper.h" #include "scene/3d/mesh_instance_3d.h" diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index ecbaca7bd1..a6433f8f58 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -31,7 +31,7 @@ #include "camera_3d.h" #include "collision_object_3d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "core/math/camera_matrix.h" #include "scene/resources/material.h" #include "scene/resources/surface_tool.h" diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp index e2d11c740a..b8a4ab74ee 100644 --- a/scene/3d/collision_polygon_3d.cpp +++ b/scene/3d/collision_polygon_3d.cpp @@ -156,15 +156,23 @@ bool CollisionPolygon3D::is_disabled() const { } String CollisionPolygon3D::get_configuration_warning() const { + String warning = Node3D::get_configuration_warning(); + if (!Object::cast_to<CollisionObject3D>(get_parent())) { - return TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."); } if (polygon.empty()) { - return TTR("An empty CollisionPolygon3D has no effect on collision."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("An empty CollisionPolygon3D has no effect on collision."); } - return String(); + return warning; } bool CollisionPolygon3D::_is_editable_3d_polygon() const { diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp index 56367e9bdd..e1c691b89a 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/collision_shape_3d.cpp @@ -44,23 +44,36 @@ //TODO: Implement CylinderShape and HeightMapShape? -void CollisionShape3D::make_convex_from_brothers() { +void CollisionShape3D::make_convex_from_siblings() { Node *p = get_parent(); if (!p) { return; } + Vector<Vector3> vertices; + for (int i = 0; i < p->get_child_count(); i++) { Node *n = p->get_child(i); MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(n); if (mi) { Ref<Mesh> m = mi->get_mesh(); if (m.is_valid()) { - Ref<Shape3D> s = m->create_convex_shape(); - set_shape(s); + for (int j = 0; j < m->get_surface_count(); j++) { + Array a = m->surface_get_arrays(j); + if (!a.empty()) { + Vector<Vector3> v = a[RenderingServer::ARRAY_VERTEX]; + for (int k = 0; k < v.size(); k++) { + vertices.append(mi->get_transform().xform(v[k])); + } + } + } } } } + + Ref<ConvexPolygonShape3D> shape = memnew(ConvexPolygonShape3D); + shape->set_points(vertices); + set_shape(shape); } void CollisionShape3D::_update_in_shape_owner(bool p_xform_only) { @@ -111,23 +124,33 @@ void CollisionShape3D::resource_changed(RES res) { } String CollisionShape3D::get_configuration_warning() const { + String warning = Node3D::get_configuration_warning(); + if (!Object::cast_to<CollisionObject3D>(get_parent())) { - return TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."); } if (!shape.is_valid()) { - return TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it."); } - if (Object::cast_to<RigidBody3D>(get_parent())) { - if (Object::cast_to<ConcavePolygonShape3D>(*shape)) { - if (Object::cast_to<RigidBody3D>(get_parent())->get_mode() != RigidBody3D::MODE_STATIC) { - return TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."); - } + if (shape.is_valid() && + Object::cast_to<RigidBody3D>(get_parent()) && + Object::cast_to<ConcavePolygonShape3D>(*shape) && + Object::cast_to<RigidBody3D>(get_parent())->get_mode() != RigidBody3D::MODE_STATIC) { + if (!warning.empty()) { + warning += "\n\n"; } + warning += TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."); } - return String(); + return warning; } void CollisionShape3D::_bind_methods() { @@ -137,8 +160,8 @@ void CollisionShape3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_shape"), &CollisionShape3D::get_shape); ClassDB::bind_method(D_METHOD("set_disabled", "enable"), &CollisionShape3D::set_disabled); ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionShape3D::is_disabled); - ClassDB::bind_method(D_METHOD("make_convex_from_brothers"), &CollisionShape3D::make_convex_from_brothers); - ClassDB::set_method_flags("CollisionShape3D", "make_convex_from_brothers", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); + ClassDB::bind_method(D_METHOD("make_convex_from_siblings"), &CollisionShape3D::make_convex_from_siblings); + ClassDB::set_method_flags("CollisionShape3D", "make_convex_from_siblings", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ClassDB::bind_method(D_METHOD("_update_debug_shape"), &CollisionShape3D::_update_debug_shape); diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h index a32a3efeb6..35f40d27b1 100644 --- a/scene/3d/collision_shape_3d.h +++ b/scene/3d/collision_shape_3d.h @@ -60,7 +60,7 @@ protected: static void _bind_methods(); public: - void make_convex_from_brothers(); + void make_convex_from_siblings(); void set_shape(const Ref<Shape3D> &p_shape); Ref<Shape3D> get_shape() const; diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index 4244a11592..c977e0d4aa 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -189,7 +189,7 @@ bool CPUParticles3D::get_fractional_delta() const { } String CPUParticles3D::get_configuration_warning() const { - String warnings; + String warnings = GeometryInstance3D::get_configuration_warning(); bool mesh_found = false; bool anim_material_found = false; @@ -726,13 +726,15 @@ void CPUParticles3D::_particles_process(float p_delta) { if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) { if (flags[FLAG_DISABLE_Z]) { - /* - mat2 rotm; - "; - rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy; - rotm[1] = rotm[0].yx * vec2(1.0, -1.0); - VELOCITY.xy = rotm * VELOCITY.xy; - */ + Vector3 normal = emission_normals.get(random_idx); + Vector2 normal_2d(normal.x, normal.y); + Transform2D m2; + m2.set_axis(0, normal_2d); + m2.set_axis(1, normal_2d.tangent()); + Vector2 velocity_2d(p.velocity.x, p.velocity.y); + velocity_2d = m2.basis_xform(velocity_2d); + p.velocity.x = velocity_2d.x; + p.velocity.y = velocity_2d.y; } else { Vector3 normal = emission_normals.get(random_idx); Vector3 v0 = Math::abs(normal.z) < 0.999 ? Vector3(0.0, 0.0, 1.0) : Vector3(0, 1.0, 0.0); @@ -1343,7 +1345,7 @@ void CPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles3D::convert_from_particles); ADD_GROUP("Emission Shape", "emission_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points"); diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index f44d0dfcfa..078861011b 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -31,7 +31,7 @@ #ifndef CPU_PARTICLES_H #define CPU_PARTICLES_H -#include "core/rid.h" +#include "core/templates/rid.h" #include "scene/3d/visual_instance_3d.h" class CPUParticles3D : public GeometryInstance3D { diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 1b6f9b45b9..fd592012f8 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -32,7 +32,6 @@ #include "core/os/os.h" -#include "core/method_bind_ext.gen.inc" #include "mesh_instance_3d.h" #include "voxelizer.h" @@ -514,10 +513,15 @@ Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const { } String GIProbe::get_configuration_warning() const { + String warning = VisualInstance3D::get_configuration_warning(); + if (RenderingServer::get_singleton()->is_low_end()) { - return TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead."); } - return String(); + return warning; } void GIProbe::_bind_methods() { diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index c4480e3ed2..ec33d7bcab 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -124,6 +124,11 @@ void GPUParticles3D::set_speed_scale(float p_scale) { RS::get_singleton()->particles_set_speed_scale(particles, p_scale); } +void GPUParticles3D::set_collision_base_size(float p_size) { + collision_base_size = p_size; + RS::get_singleton()->particles_set_collision_base_size(particles, p_size); +} + bool GPUParticles3D::is_emitting() const { return RS::get_singleton()->particles_get_emitting(particles); } @@ -168,6 +173,10 @@ float GPUParticles3D::get_speed_scale() const { return speed_scale; } +float GPUParticles3D::get_collision_base_size() const { + return collision_base_size; +} + void GPUParticles3D::set_draw_order(DrawOrder p_order) { draw_order = p_order; RS::get_singleton()->particles_set_draw_order(particles, RS::ParticlesDrawOrder(p_order)); @@ -232,7 +241,7 @@ String GPUParticles3D::get_configuration_warning() const { return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose."); } - String warnings; + String warnings = GeometryInstance3D::get_configuration_warning(); bool meshes_found = false; bool anim_material_found = false; @@ -301,6 +310,36 @@ void GPUParticles3D::_validate_property(PropertyInfo &property) const { } } +void GPUParticles3D::emit_particle(const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { + RS::get_singleton()->particles_emit(particles, p_transform, p_velocity, p_color, p_custom, p_emit_flags); +} + +void GPUParticles3D::_attach_sub_emitter() { + Node *n = get_node_or_null(sub_emitter); + if (n) { + GPUParticles3D *sen = Object::cast_to<GPUParticles3D>(n); + if (sen && sen != this) { + RS::get_singleton()->particles_set_subemitter(particles, sen->particles); + } + } +} + +void GPUParticles3D::set_sub_emitter(const NodePath &p_path) { + if (is_inside_tree()) { + RS::get_singleton()->particles_set_subemitter(particles, RID()); + } + + sub_emitter = p_path; + + if (is_inside_tree() && sub_emitter != NodePath()) { + _attach_sub_emitter(); + } +} + +NodePath GPUParticles3D::get_sub_emitter() const { + return sub_emitter; +} + void GPUParticles3D::_notification(int p_what) { if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) { if (can_process()) { @@ -319,6 +358,16 @@ void GPUParticles3D::_notification(int p_what) { } } + if (p_what == NOTIFICATION_ENTER_TREE) { + if (sub_emitter != NodePath()) { + _attach_sub_emitter(); + } + } + + if (p_what == NOTIFICATION_EXIT_TREE) { + RS::get_singleton()->particles_set_subemitter(particles, RID()); + } + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { // make sure particles are updated before rendering occurs if they were active before if (is_visible_in_tree() && !RS::get_singleton()->particles_is_inactive(particles)) { @@ -341,6 +390,7 @@ void GPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &GPUParticles3D::set_fractional_delta); ClassDB::bind_method(D_METHOD("set_process_material", "material"), &GPUParticles3D::set_process_material); ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &GPUParticles3D::set_speed_scale); + ClassDB::bind_method(D_METHOD("set_collision_base_size", "size"), &GPUParticles3D::set_collision_base_size); ClassDB::bind_method(D_METHOD("is_emitting"), &GPUParticles3D::is_emitting); ClassDB::bind_method(D_METHOD("get_amount"), &GPUParticles3D::get_amount); @@ -355,6 +405,7 @@ void GPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_fractional_delta"), &GPUParticles3D::get_fractional_delta); ClassDB::bind_method(D_METHOD("get_process_material"), &GPUParticles3D::get_process_material); ClassDB::bind_method(D_METHOD("get_speed_scale"), &GPUParticles3D::get_speed_scale); + ClassDB::bind_method(D_METHOD("get_collision_base_size"), &GPUParticles3D::get_collision_base_size); ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &GPUParticles3D::set_draw_order); @@ -369,8 +420,14 @@ void GPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("restart"), &GPUParticles3D::restart); ClassDB::bind_method(D_METHOD("capture_aabb"), &GPUParticles3D::capture_aabb); + ClassDB::bind_method(D_METHOD("set_sub_emitter", "path"), &GPUParticles3D::set_sub_emitter); + ClassDB::bind_method(D_METHOD("get_sub_emitter"), &GPUParticles3D::get_sub_emitter); + + ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles3D::emit_particle); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles3D"), "set_sub_emitter", "get_sub_emitter"); ADD_GROUP("Time", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); @@ -380,6 +437,8 @@ void GPUParticles3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); + ADD_GROUP("Collision", "collision_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_base_size", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_collision_base_size", "get_collision_base_size"); ADD_GROUP("Drawing", ""); ADD_PROPERTY(PropertyInfo(Variant::AABB, "visibility_aabb"), "set_visibility_aabb", "get_visibility_aabb"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); @@ -396,6 +455,12 @@ void GPUParticles3D::_bind_methods() { BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME); BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH); + BIND_ENUM_CONSTANT(EMIT_FLAG_POSITION); + BIND_ENUM_CONSTANT(EMIT_FLAG_ROTATION_SCALE); + BIND_ENUM_CONSTANT(EMIT_FLAG_VELOCITY); + BIND_ENUM_CONSTANT(EMIT_FLAG_COLOR); + BIND_ENUM_CONSTANT(EMIT_FLAG_CUSTOM); + BIND_CONSTANT(MAX_DRAW_PASSES); } @@ -417,6 +482,7 @@ GPUParticles3D::GPUParticles3D() { set_draw_passes(1); set_draw_order(DRAW_ORDER_INDEX); set_speed_scale(1); + set_collision_base_size(0.01); } GPUParticles3D::~GPUParticles3D() { diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index e04473727d..f0e5f05e5b 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -31,7 +31,7 @@ #ifndef PARTICLES_H #define PARTICLES_H -#include "core/rid.h" +#include "core/templates/rid.h" #include "scene/3d/visual_instance_3d.h" #include "scene/resources/material.h" @@ -64,6 +64,8 @@ private: bool local_coords; int fixed_fps; bool fractional_delta; + NodePath sub_emitter; + float collision_base_size; Ref<Material> process_material; @@ -71,6 +73,8 @@ private: Vector<Ref<Mesh>> draw_passes; + void _attach_sub_emitter(); + protected: static void _bind_methods(); void _notification(int p_what); @@ -91,6 +95,7 @@ public: void set_use_local_coordinates(bool p_enable); void set_process_material(const Ref<Material> &p_material); void set_speed_scale(float p_scale); + void set_collision_base_size(float p_ratio); bool is_emitting() const; int get_amount() const; @@ -103,6 +108,7 @@ public: bool get_use_local_coordinates() const; Ref<Material> get_process_material() const; float get_speed_scale() const; + float get_collision_base_size() const; void set_fixed_fps(int p_count); int get_fixed_fps() const; @@ -121,13 +127,27 @@ public: virtual String get_configuration_warning() const override; + void set_sub_emitter(const NodePath &p_path); + NodePath get_sub_emitter() const; + void restart(); + enum EmitFlags { + EMIT_FLAG_POSITION = RS::PARTICLES_EMIT_FLAG_POSITION, + EMIT_FLAG_ROTATION_SCALE = RS::PARTICLES_EMIT_FLAG_ROTATION_SCALE, + EMIT_FLAG_VELOCITY = RS::PARTICLES_EMIT_FLAG_VELOCITY, + EMIT_FLAG_COLOR = RS::PARTICLES_EMIT_FLAG_COLOR, + EMIT_FLAG_CUSTOM = RS::PARTICLES_EMIT_FLAG_CUSTOM + }; + + void emit_particle(const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags); + AABB capture_aabb() const; GPUParticles3D(); ~GPUParticles3D(); }; VARIANT_ENUM_CAST(GPUParticles3D::DrawOrder) +VARIANT_ENUM_CAST(GPUParticles3D::EmitFlags) #endif // PARTICLES_H diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp new file mode 100644 index 0000000000..1f0d5d587d --- /dev/null +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -0,0 +1,901 @@ +/*************************************************************************/ +/* gpu_particles_collision_3d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "gpu_particles_collision_3d.h" + +#include "core/templates/thread_work_pool.h" +#include "mesh_instance_3d.h" +#include "scene/3d/camera_3d.h" +#include "scene/main/viewport.h" + +void GPUParticlesCollision3D::set_cull_mask(uint32_t p_cull_mask) { + cull_mask = p_cull_mask; + RS::get_singleton()->particles_collision_set_cull_mask(collision, p_cull_mask); +} + +uint32_t GPUParticlesCollision3D::get_cull_mask() const { + return cull_mask; +} + +void GPUParticlesCollision3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_cull_mask", "mask"), &GPUParticlesCollision3D::set_cull_mask); + ClassDB::bind_method(D_METHOD("get_cull_mask"), &GPUParticlesCollision3D::get_cull_mask); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); +} + +GPUParticlesCollision3D::GPUParticlesCollision3D(RS::ParticlesCollisionType p_type) { + collision = RS::get_singleton()->particles_collision_create(); + RS::get_singleton()->particles_collision_set_collision_type(collision, p_type); + set_base(collision); +} + +GPUParticlesCollision3D::~GPUParticlesCollision3D() { + RS::get_singleton()->free(collision); +} + +///////////////////////////////// + +void GPUParticlesCollisionSphere::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_radius", "radius"), &GPUParticlesCollisionSphere::set_radius); + ClassDB::bind_method(D_METHOD("get_radius"), &GPUParticlesCollisionSphere::get_radius); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_radius", "get_radius"); +} + +void GPUParticlesCollisionSphere::set_radius(float p_radius) { + radius = p_radius; + RS::get_singleton()->particles_collision_set_sphere_radius(_get_collision(), radius); + update_gizmo(); +} + +float GPUParticlesCollisionSphere::get_radius() const { + return radius; +} + +AABB GPUParticlesCollisionSphere::get_aabb() const { + return AABB(Vector3(-radius, -radius, -radius), Vector3(radius * 2, radius * 2, radius * 2)); +} + +GPUParticlesCollisionSphere::GPUParticlesCollisionSphere() : + GPUParticlesCollision3D(RS::PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE) { +} + +GPUParticlesCollisionSphere::~GPUParticlesCollisionSphere() { +} + +/////////////////////////// + +void GPUParticlesCollisionBox::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesCollisionBox::set_extents); + ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesCollisionBox::get_extents); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents"); +} + +void GPUParticlesCollisionBox::set_extents(const Vector3 &p_extents) { + extents = p_extents; + RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents); + update_gizmo(); +} + +Vector3 GPUParticlesCollisionBox::get_extents() const { + return extents; +} + +AABB GPUParticlesCollisionBox::get_aabb() const { + return AABB(-extents, extents * 2); +} + +GPUParticlesCollisionBox::GPUParticlesCollisionBox() : + GPUParticlesCollision3D(RS::PARTICLES_COLLISION_TYPE_BOX_COLLIDE) { +} + +GPUParticlesCollisionBox::~GPUParticlesCollisionBox() { +} + +/////////////////////////////// +/////////////////////////// + +void GPUParticlesCollisionSDF::_find_meshes(const AABB &p_aabb, Node *p_at_node, List<PlotMesh> &plot_meshes) { + MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node); + if (mi && mi->is_visible_in_tree()) { + Ref<Mesh> mesh = mi->get_mesh(); + if (mesh.is_valid()) { + AABB aabb = mesh->get_aabb(); + + Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform(); + + if (p_aabb.intersects(xf.xform(aabb))) { + PlotMesh pm; + pm.local_xform = xf; + pm.mesh = mesh; + plot_meshes.push_back(pm); + } + } + } + + Node3D *s = Object::cast_to<Node3D>(p_at_node); + if (s) { + if (s->is_visible_in_tree()) { + Array meshes = p_at_node->call("get_meshes"); + for (int i = 0; i < meshes.size(); i += 2) { + Transform mxf = meshes[i]; + Ref<Mesh> mesh = meshes[i + 1]; + if (!mesh.is_valid()) { + continue; + } + + AABB aabb = mesh->get_aabb(); + + Transform xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf); + + if (p_aabb.intersects(xf.xform(aabb))) { + PlotMesh pm; + pm.local_xform = xf; + pm.mesh = mesh; + plot_meshes.push_back(pm); + } + } + } + } + + for (int i = 0; i < p_at_node->get_child_count(); i++) { + Node *child = p_at_node->get_child(i); + _find_meshes(p_aabb, child, plot_meshes); + } +} + +uint32_t GPUParticlesCollisionSDF::_create_bvh(LocalVector<BVH> &bvh_tree, FacePos *p_faces, uint32_t p_face_count, const Face3 *p_triangles, float p_thickness) { + if (p_face_count == 1) { + return BVH::LEAF_BIT | p_faces[0].index; + } + + uint32_t index = bvh_tree.size(); + { + BVH bvh; + + for (uint32_t i = 0; i < p_face_count; i++) { + const Face3 &f = p_triangles[p_faces[i].index]; + AABB aabb(f.vertex[0], Vector3()); + aabb.expand_to(f.vertex[1]); + aabb.expand_to(f.vertex[2]); + if (p_thickness > 0.0) { + Vector3 normal = p_triangles[p_faces[i].index].get_plane().normal; + aabb.expand_to(f.vertex[0] - normal * p_thickness); + aabb.expand_to(f.vertex[1] - normal * p_thickness); + aabb.expand_to(f.vertex[2] - normal * p_thickness); + } + if (i == 0) { + bvh.bounds = aabb; + } else { + bvh.bounds.merge_with(aabb); + } + } + bvh_tree.push_back(bvh); + } + + uint32_t middle = p_face_count / 2; + + SortArray<FacePos, FaceSort> s; + s.compare.axis = bvh_tree[index].bounds.get_longest_axis_index(); + s.sort(p_faces, p_face_count); + + uint32_t left = _create_bvh(bvh_tree, p_faces, middle, p_triangles, p_thickness); + uint32_t right = _create_bvh(bvh_tree, p_faces + middle, p_face_count - middle, p_triangles, p_thickness); + + bvh_tree[index].children[0] = left; + bvh_tree[index].children[1] = right; + + return index; +} + +static _FORCE_INLINE_ float Vector3_dot2(const Vector3 &p_vec3) { + return p_vec3.dot(p_vec3); +} + +void GPUParticlesCollisionSDF::_find_closest_distance(const Vector3 &p_pos, const BVH *bvh, uint32_t p_bvh_cell, const Face3 *triangles, float thickness, float &closest_distance) { + if (p_bvh_cell & BVH::LEAF_BIT) { + p_bvh_cell &= BVH::LEAF_MASK; //remove bit + + Vector3 point = p_pos; + Plane p = triangles[p_bvh_cell].get_plane(); + float d = p.distance_to(point); + float inside_d = 1e20; + if (d < 0 && d > -thickness) { + //inside planes, do this in 2D + + Vector3 x_axis = (triangles[p_bvh_cell].vertex[0] - triangles[p_bvh_cell].vertex[1]).normalized(); + Vector3 y_axis = p.normal.cross(x_axis).normalized(); + + Vector2 points[3]; + for (int i = 0; i < 3; i++) { + points[i] = Vector2(x_axis.dot(triangles[p_bvh_cell].vertex[i]), y_axis.dot(triangles[p_bvh_cell].vertex[i])); + } + + Vector2 p2d = Vector2(x_axis.dot(point), y_axis.dot(point)); + + { + // https://www.shadertoy.com/view/XsXSz4 + + Vector2 e0 = points[1] - points[0]; + Vector2 e1 = points[2] - points[1]; + Vector2 e2 = points[0] - points[2]; + + Vector2 v0 = p2d - points[0]; + Vector2 v1 = p2d - points[1]; + Vector2 v2 = p2d - points[2]; + + Vector2 pq0 = v0 - e0 * CLAMP(v0.dot(e0) / e0.dot(e0), 0.0, 1.0); + Vector2 pq1 = v1 - e1 * CLAMP(v1.dot(e1) / e1.dot(e1), 0.0, 1.0); + Vector2 pq2 = v2 - e2 * CLAMP(v2.dot(e2) / e2.dot(e2), 0.0, 1.0); + + float s = SGN(e0.x * e2.y - e0.y * e2.x); + Vector2 d2 = Vector2(pq0.dot(pq0), s * (v0.x * e0.y - v0.y * e0.x)).min(Vector2(pq1.dot(pq1), s * (v1.x * e1.y - v1.y * e1.x))).min(Vector2(pq2.dot(pq2), s * (v2.x * e2.y - v2.y * e2.x))); + + inside_d = -Math::sqrt(d2.x) * SGN(d2.y); + } + + //make sure distance to planes is not shorter if inside + if (inside_d < 0) { + inside_d = MAX(inside_d, d); + inside_d = MAX(inside_d, -(thickness + d)); + } + + closest_distance = MIN(closest_distance, inside_d); + } else { + if (d < 0) { + point -= p.normal * thickness; //flatten + } + + // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm + Vector3 a = triangles[p_bvh_cell].vertex[0]; + Vector3 b = triangles[p_bvh_cell].vertex[1]; + Vector3 c = triangles[p_bvh_cell].vertex[2]; + + Vector3 ba = b - a; + Vector3 pa = point - a; + Vector3 cb = c - b; + Vector3 pb = point - b; + Vector3 ac = a - c; + Vector3 pc = point - c; + Vector3 nor = ba.cross(ac); + + inside_d = Math::sqrt( + (SGN(ba.cross(nor).dot(pa)) + + SGN(cb.cross(nor).dot(pb)) + + SGN(ac.cross(nor).dot(pc)) < + 2.0) ? + MIN(MIN( + Vector3_dot2(ba * CLAMP(ba.dot(pa) / Vector3_dot2(ba), 0.0, 1.0) - pa), + Vector3_dot2(cb * CLAMP(cb.dot(pb) / Vector3_dot2(cb), 0.0, 1.0) - pb)), + Vector3_dot2(ac * CLAMP(ac.dot(pc) / Vector3_dot2(ac), 0.0, 1.0) - pc)) : + nor.dot(pa) * nor.dot(pa) / Vector3_dot2(nor)); + + closest_distance = MIN(closest_distance, inside_d); + } + + } else { + bool pass = true; + if (!bvh[p_bvh_cell].bounds.has_point(p_pos)) { + //outside, find closest point + Vector3 he = bvh[p_bvh_cell].bounds.size * 0.5; + Vector3 center = bvh[p_bvh_cell].bounds.position + he; + + Vector3 rel = (p_pos - center).abs(); + Vector3 closest(MIN(rel.x, he.x), MIN(rel.y, he.y), MIN(rel.z, he.z)); + float d = rel.distance_to(closest); + + if (d >= closest_distance) { + pass = false; //already closer than this aabb, discard + } + } + + if (pass) { + _find_closest_distance(p_pos, bvh, bvh[p_bvh_cell].children[0], triangles, thickness, closest_distance); + _find_closest_distance(p_pos, bvh, bvh[p_bvh_cell].children[1], triangles, thickness, closest_distance); + } + } +} + +void GPUParticlesCollisionSDF::_compute_sdf_z(uint32_t p_z, ComputeSDFParams *params) { + int32_t z_ofs = p_z * params->size.y * params->size.x; + for (int32_t y = 0; y < params->size.y; y++) { + int32_t y_ofs = z_ofs + y * params->size.x; + for (int32_t x = 0; x < params->size.x; x++) { + int32_t x_ofs = y_ofs + x; + float &cell = params->cells[x_ofs]; + + Vector3 pos = params->cell_offset + Vector3(x, y, p_z) * params->cell_size; + + cell = 1e20; + + _find_closest_distance(pos, params->bvh, 0, params->triangles, params->thickness, cell); + } + } +} + +void GPUParticlesCollisionSDF::_compute_sdf(ComputeSDFParams *params) { + ThreadWorkPool work_pool; + work_pool.init(); + work_pool.begin_work(params->size.z, this, &GPUParticlesCollisionSDF::_compute_sdf_z, params); + while (work_pool.get_work_index() < (uint32_t)params->size.z) { + OS::get_singleton()->delay_usec(10000); + bake_step_function(work_pool.get_work_index() * 100 / params->size.z, "Baking SDF"); + } + work_pool.end_work(); + work_pool.finish(); +} + +Vector3i GPUParticlesCollisionSDF::get_estimated_cell_size() const { + static const int subdivs[RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 }; + int subdiv = subdivs[get_resolution()]; + + AABB aabb(-extents, extents * 2); + + float cell_size = aabb.get_longest_axis_size() / float(subdiv); + + Vector3i sdf_size = Vector3i(aabb.size / cell_size); + sdf_size.x = MAX(1, sdf_size.x); + sdf_size.y = MAX(1, sdf_size.y); + sdf_size.z = MAX(1, sdf_size.z); + return sdf_size; +} + +Ref<Image> GPUParticlesCollisionSDF::bake() { + static const int subdivs[RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 }; + int subdiv = subdivs[get_resolution()]; + + AABB aabb(-extents, extents * 2); + + float cell_size = aabb.get_longest_axis_size() / float(subdiv); + + Vector3i sdf_size = Vector3i(aabb.size / cell_size); + sdf_size.x = MAX(1, sdf_size.x); + sdf_size.y = MAX(1, sdf_size.y); + sdf_size.z = MAX(1, sdf_size.z); + + if (bake_begin_function) { + bake_begin_function(100); + } + + aabb.size = Vector3(sdf_size) * cell_size; + + List<PlotMesh> plot_meshes; + _find_meshes(aabb, get_parent(), plot_meshes); + + LocalVector<Face3> faces; + + if (bake_step_function) { + bake_step_function(0, "Finding Meshes"); + } + + for (List<PlotMesh>::Element *E = plot_meshes.front(); E; E = E->next()) { + const PlotMesh &pm = E->get(); + + for (int i = 0; i < pm.mesh->get_surface_count(); i++) { + if (pm.mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) { + continue; //only triangles + } + + Array a = pm.mesh->surface_get_arrays(i); + + Vector<Vector3> vertices = a[Mesh::ARRAY_VERTEX]; + const Vector3 *vr = vertices.ptr(); + Vector<int> index = a[Mesh::ARRAY_INDEX]; + + if (index.size()) { + int facecount = index.size() / 3; + const int *ir = index.ptr(); + + for (int j = 0; j < facecount; j++) { + Face3 face; + + for (int k = 0; k < 3; k++) { + face.vertex[k] = pm.local_xform.xform(vr[ir[j * 3 + k]]); + } + + //test against original bounds + if (!Geometry3D::triangle_box_overlap(aabb.position + aabb.size * 0.5, aabb.size * 0.5, face.vertex)) { + continue; + } + + faces.push_back(face); + } + + } else { + int facecount = vertices.size() / 3; + + for (int j = 0; j < facecount; j++) { + Face3 face; + + for (int k = 0; k < 3; k++) { + face.vertex[k] = pm.local_xform.xform(vr[j * 3 + k]); + } + + //test against original bounds + if (!Geometry3D::triangle_box_overlap(aabb.position + aabb.size * 0.5, aabb.size * 0.5, face.vertex)) { + continue; + } + + faces.push_back(face); + } + } + } + } + + //compute bvh + + ERR_FAIL_COND_V(faces.size() <= 1, Ref<Image>()); + + LocalVector<FacePos> face_pos; + + face_pos.resize(faces.size()); + + float th = cell_size * thickness; + + for (uint32_t i = 0; i < faces.size(); i++) { + face_pos[i].index = i; + face_pos[i].center = (faces[i].vertex[0] + faces[i].vertex[1] + faces[i].vertex[2]) / 2; + if (th > 0.0) { + face_pos[i].center -= faces[i].get_plane().normal * th * 0.5; + } + } + + if (bake_step_function) { + bake_step_function(0, "Creating BVH"); + } + + LocalVector<BVH> bvh; + + _create_bvh(bvh, face_pos.ptr(), face_pos.size(), faces.ptr(), th); + + Vector<uint8_t> data; + data.resize(sdf_size.z * sdf_size.y * sdf_size.x * sizeof(float)); + + if (bake_step_function) { + bake_step_function(0, "Baking SDF"); + } + + ComputeSDFParams params; + params.cells = (float *)data.ptrw(); + params.size = sdf_size; + params.cell_size = cell_size; + params.cell_offset = aabb.position + Vector3(cell_size * 0.5, cell_size * 0.5, cell_size * 0.5); + params.bvh = bvh.ptr(); + params.triangles = faces.ptr(); + params.thickness = th; + _compute_sdf(¶ms); + + Ref<Image> ret; + ret.instance(); + ret->create(sdf_size.x, sdf_size.y * sdf_size.z, false, Image::FORMAT_RF, data); + ret->convert(Image::FORMAT_RH); //convert to half, save space + ret->set_meta("depth", sdf_size.z); //hack, make sure to add to the docs of this function + + if (bake_end_function) { + bake_end_function(); + } + + return ret; +} + +void GPUParticlesCollisionSDF::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesCollisionSDF::set_extents); + ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesCollisionSDF::get_extents); + + ClassDB::bind_method(D_METHOD("set_resolution", "resolution"), &GPUParticlesCollisionSDF::set_resolution); + ClassDB::bind_method(D_METHOD("get_resolution"), &GPUParticlesCollisionSDF::get_resolution); + + ClassDB::bind_method(D_METHOD("set_texture", "texture"), &GPUParticlesCollisionSDF::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &GPUParticlesCollisionSDF::get_texture); + + ClassDB::bind_method(D_METHOD("set_thickness", "thickness"), &GPUParticlesCollisionSDF::set_thickness); + ClassDB::bind_method(D_METHOD("get_thickness"), &GPUParticlesCollisionSDF::get_thickness); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "16,32,64,128,256,512"), "set_resolution", "get_resolution"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "thickness", PROPERTY_HINT_RANGE, "0.0,2.0,0.01"), "set_thickness", "get_thickness"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture"); + + BIND_ENUM_CONSTANT(RESOLUTION_16); + BIND_ENUM_CONSTANT(RESOLUTION_32); + BIND_ENUM_CONSTANT(RESOLUTION_64); + BIND_ENUM_CONSTANT(RESOLUTION_128); + BIND_ENUM_CONSTANT(RESOLUTION_256); + BIND_ENUM_CONSTANT(RESOLUTION_512); + BIND_ENUM_CONSTANT(RESOLUTION_MAX); +} + +void GPUParticlesCollisionSDF::set_thickness(float p_thickness) { + thickness = p_thickness; +} + +float GPUParticlesCollisionSDF::get_thickness() const { + return thickness; +} + +void GPUParticlesCollisionSDF::set_extents(const Vector3 &p_extents) { + extents = p_extents; + RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents); + update_gizmo(); +} + +Vector3 GPUParticlesCollisionSDF::get_extents() const { + return extents; +} + +void GPUParticlesCollisionSDF::set_resolution(Resolution p_resolution) { + resolution = p_resolution; + update_gizmo(); +} + +GPUParticlesCollisionSDF::Resolution GPUParticlesCollisionSDF::get_resolution() const { + return resolution; +} + +void GPUParticlesCollisionSDF::set_texture(const Ref<Texture3D> &p_texture) { + texture = p_texture; + RID tex = texture.is_valid() ? texture->get_rid() : RID(); + RS::get_singleton()->particles_collision_set_field_texture(_get_collision(), tex); +} + +Ref<Texture3D> GPUParticlesCollisionSDF::get_texture() const { + return texture; +} + +AABB GPUParticlesCollisionSDF::get_aabb() const { + return AABB(-extents, extents * 2); +} + +GPUParticlesCollisionSDF::BakeBeginFunc GPUParticlesCollisionSDF::bake_begin_function = nullptr; +GPUParticlesCollisionSDF::BakeStepFunc GPUParticlesCollisionSDF::bake_step_function = nullptr; +GPUParticlesCollisionSDF::BakeEndFunc GPUParticlesCollisionSDF::bake_end_function = nullptr; + +GPUParticlesCollisionSDF::GPUParticlesCollisionSDF() : + GPUParticlesCollision3D(RS::PARTICLES_COLLISION_TYPE_SDF_COLLIDE) { +} + +GPUParticlesCollisionSDF::~GPUParticlesCollisionSDF() { +} + +//////////////////////////// +//////////////////////////// + +void GPUParticlesCollisionHeightField::_notification(int p_what) { + if (p_what == NOTIFICATION_INTERNAL_PROCESS) { + if (update_mode == UPDATE_MODE_ALWAYS) { + RS::get_singleton()->particles_collision_height_field_update(_get_collision()); + } + + if (follow_camera_mode && get_viewport()) { + Camera3D *cam = get_viewport()->get_camera(); + if (cam) { + Transform xform = get_global_transform(); + Vector3 x_axis = xform.basis.get_axis(Vector3::AXIS_X).normalized(); + Vector3 z_axis = xform.basis.get_axis(Vector3::AXIS_Z).normalized(); + float x_len = xform.basis.get_scale().x; + float z_len = xform.basis.get_scale().z; + + Vector3 cam_pos = cam->get_global_transform().origin; + Transform new_xform = xform; + + while (x_axis.dot(cam_pos - new_xform.origin) > x_len) { + new_xform.origin += x_axis * x_len; + } + while (x_axis.dot(cam_pos - new_xform.origin) < -x_len) { + new_xform.origin -= x_axis * x_len; + } + + while (z_axis.dot(cam_pos - new_xform.origin) > z_len) { + new_xform.origin += z_axis * z_len; + } + while (z_axis.dot(cam_pos - new_xform.origin) < -z_len) { + new_xform.origin -= z_axis * z_len; + } + + if (new_xform != xform) { + set_global_transform(new_xform); + RS::get_singleton()->particles_collision_height_field_update(_get_collision()); + } + } + } + } + + if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { + RS::get_singleton()->particles_collision_height_field_update(_get_collision()); + } +} + +void GPUParticlesCollisionHeightField::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesCollisionHeightField::set_extents); + ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesCollisionHeightField::get_extents); + + ClassDB::bind_method(D_METHOD("set_resolution", "resolution"), &GPUParticlesCollisionHeightField::set_resolution); + ClassDB::bind_method(D_METHOD("get_resolution"), &GPUParticlesCollisionHeightField::get_resolution); + + ClassDB::bind_method(D_METHOD("set_update_mode", "update_mode"), &GPUParticlesCollisionHeightField::set_update_mode); + ClassDB::bind_method(D_METHOD("get_update_mode"), &GPUParticlesCollisionHeightField::get_update_mode); + + ClassDB::bind_method(D_METHOD("set_follow_camera_mode", "enabled"), &GPUParticlesCollisionHeightField::set_follow_camera_mode); + ClassDB::bind_method(D_METHOD("is_follow_camera_mode_enabled"), &GPUParticlesCollisionHeightField::is_follow_camera_mode_enabled); + + ClassDB::bind_method(D_METHOD("set_follow_camera_push_ratio", "ratio"), &GPUParticlesCollisionHeightField::set_follow_camera_push_ratio); + ClassDB::bind_method(D_METHOD("get_follow_camera_push_ratio"), &GPUParticlesCollisionHeightField::get_follow_camera_push_ratio); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "256,512,1024,2048,4096,8192"), "set_resolution", "get_resolution"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "WhenMoved,Always"), "set_update_mode", "get_update_mode"); + ADD_GROUP("Folow Camera", "follow_camera_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_camera_enabled"), "set_follow_camera_mode", "is_follow_camera_mode_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_camera_push_ratio", PROPERTY_HINT_RANGE, "0.01,1,0.01"), "set_follow_camera_push_ratio", "get_follow_camera_push_ratio"); + + BIND_ENUM_CONSTANT(RESOLUTION_256); + BIND_ENUM_CONSTANT(RESOLUTION_512); + BIND_ENUM_CONSTANT(RESOLUTION_1024); + BIND_ENUM_CONSTANT(RESOLUTION_2048); + BIND_ENUM_CONSTANT(RESOLUTION_4096); + BIND_ENUM_CONSTANT(RESOLUTION_8192); + BIND_ENUM_CONSTANT(RESOLUTION_MAX); + + BIND_ENUM_CONSTANT(UPDATE_MODE_WHEN_MOVED); + BIND_ENUM_CONSTANT(UPDATE_MODE_ALWAYS); +} + +void GPUParticlesCollisionHeightField::set_follow_camera_push_ratio(float p_follow_camera_push_ratio) { + follow_camera_push_ratio = p_follow_camera_push_ratio; +} + +float GPUParticlesCollisionHeightField::get_follow_camera_push_ratio() const { + return follow_camera_push_ratio; +} + +void GPUParticlesCollisionHeightField::set_extents(const Vector3 &p_extents) { + extents = p_extents; + RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents); + update_gizmo(); + RS::get_singleton()->particles_collision_height_field_update(_get_collision()); +} + +Vector3 GPUParticlesCollisionHeightField::get_extents() const { + return extents; +} + +void GPUParticlesCollisionHeightField::set_resolution(Resolution p_resolution) { + resolution = p_resolution; + RS::get_singleton()->particles_collision_set_height_field_resolution(_get_collision(), RS::ParticlesCollisionHeightfieldResolution(resolution)); + update_gizmo(); + RS::get_singleton()->particles_collision_height_field_update(_get_collision()); +} + +GPUParticlesCollisionHeightField::Resolution GPUParticlesCollisionHeightField::get_resolution() const { + return resolution; +} + +void GPUParticlesCollisionHeightField::set_update_mode(UpdateMode p_update_mode) { + update_mode = p_update_mode; + set_process_internal(follow_camera_mode || update_mode == UPDATE_MODE_ALWAYS); +} + +GPUParticlesCollisionHeightField::UpdateMode GPUParticlesCollisionHeightField::get_update_mode() const { + return update_mode; +} + +void GPUParticlesCollisionHeightField::set_follow_camera_mode(bool p_enabled) { + follow_camera_mode = p_enabled; + set_process_internal(follow_camera_mode || update_mode == UPDATE_MODE_ALWAYS); +} + +bool GPUParticlesCollisionHeightField::is_follow_camera_mode_enabled() const { + return follow_camera_mode; +} + +AABB GPUParticlesCollisionHeightField::get_aabb() const { + return AABB(-extents, extents * 2); +} + +GPUParticlesCollisionHeightField::GPUParticlesCollisionHeightField() : + GPUParticlesCollision3D(RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE) { +} + +GPUParticlesCollisionHeightField::~GPUParticlesCollisionHeightField() { +} + +//////////////////////////// +//////////////////////////// + +void GPUParticlesAttractor3D::set_cull_mask(uint32_t p_cull_mask) { + cull_mask = p_cull_mask; + RS::get_singleton()->particles_collision_set_cull_mask(collision, p_cull_mask); +} + +uint32_t GPUParticlesAttractor3D::get_cull_mask() const { + return cull_mask; +} + +void GPUParticlesAttractor3D::set_strength(float p_strength) { + strength = p_strength; + RS::get_singleton()->particles_collision_set_attractor_strength(collision, p_strength); +} + +float GPUParticlesAttractor3D::get_strength() const { + return strength; +} + +void GPUParticlesAttractor3D::set_attenuation(float p_attenuation) { + attenuation = p_attenuation; + RS::get_singleton()->particles_collision_set_attractor_attenuation(collision, p_attenuation); +} + +float GPUParticlesAttractor3D::get_attenuation() const { + return attenuation; +} + +void GPUParticlesAttractor3D::set_directionality(float p_directionality) { + directionality = p_directionality; + RS::get_singleton()->particles_collision_set_attractor_directionality(collision, p_directionality); + update_gizmo(); +} + +float GPUParticlesAttractor3D::get_directionality() const { + return directionality; +} + +void GPUParticlesAttractor3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_cull_mask", "mask"), &GPUParticlesAttractor3D::set_cull_mask); + ClassDB::bind_method(D_METHOD("get_cull_mask"), &GPUParticlesAttractor3D::get_cull_mask); + + ClassDB::bind_method(D_METHOD("set_strength", "strength"), &GPUParticlesAttractor3D::set_strength); + ClassDB::bind_method(D_METHOD("get_strength"), &GPUParticlesAttractor3D::get_strength); + + ClassDB::bind_method(D_METHOD("set_attenuation", "attenuation"), &GPUParticlesAttractor3D::set_attenuation); + ClassDB::bind_method(D_METHOD("get_attenuation"), &GPUParticlesAttractor3D::get_attenuation); + + ClassDB::bind_method(D_METHOD("set_directionality", "amount"), &GPUParticlesAttractor3D::set_directionality); + ClassDB::bind_method(D_METHOD("get_directionality"), &GPUParticlesAttractor3D::get_directionality); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "-128,128,0.01,or_greater,or_lesser"), "set_strength", "get_strength"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation", PROPERTY_HINT_EXP_EASING, "0,8,0.01"), "set_attenuation", "get_attenuation"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "directionality", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_directionality", "get_directionality"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); +} + +GPUParticlesAttractor3D::GPUParticlesAttractor3D(RS::ParticlesCollisionType p_type) { + collision = RS::get_singleton()->particles_collision_create(); + RS::get_singleton()->particles_collision_set_collision_type(collision, p_type); + set_base(collision); +} +GPUParticlesAttractor3D::~GPUParticlesAttractor3D() { + RS::get_singleton()->free(collision); +} + +///////////////////////////////// + +void GPUParticlesAttractorSphere::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_radius", "radius"), &GPUParticlesAttractorSphere::set_radius); + ClassDB::bind_method(D_METHOD("get_radius"), &GPUParticlesAttractorSphere::get_radius); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_radius", "get_radius"); +} + +void GPUParticlesAttractorSphere::set_radius(float p_radius) { + radius = p_radius; + RS::get_singleton()->particles_collision_set_sphere_radius(_get_collision(), radius); + update_gizmo(); +} + +float GPUParticlesAttractorSphere::get_radius() const { + return radius; +} + +AABB GPUParticlesAttractorSphere::get_aabb() const { + return AABB(Vector3(-radius, -radius, -radius), Vector3(radius * 2, radius * 2, radius * 2)); +} + +GPUParticlesAttractorSphere::GPUParticlesAttractorSphere() : + GPUParticlesAttractor3D(RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT) { +} + +GPUParticlesAttractorSphere::~GPUParticlesAttractorSphere() { +} + +/////////////////////////// + +void GPUParticlesAttractorBox::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesAttractorBox::set_extents); + ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesAttractorBox::get_extents); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents"); +} + +void GPUParticlesAttractorBox::set_extents(const Vector3 &p_extents) { + extents = p_extents; + RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents); + update_gizmo(); +} + +Vector3 GPUParticlesAttractorBox::get_extents() const { + return extents; +} + +AABB GPUParticlesAttractorBox::get_aabb() const { + return AABB(-extents, extents * 2); +} + +GPUParticlesAttractorBox::GPUParticlesAttractorBox() : + GPUParticlesAttractor3D(RS::PARTICLES_COLLISION_TYPE_BOX_ATTRACT) { +} + +GPUParticlesAttractorBox::~GPUParticlesAttractorBox() { +} + +/////////////////////////// + +void GPUParticlesAttractorVectorField::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesAttractorVectorField::set_extents); + ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesAttractorVectorField::get_extents); + + ClassDB::bind_method(D_METHOD("set_texture", "texture"), &GPUParticlesAttractorVectorField::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &GPUParticlesAttractorVectorField::get_texture); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture"); +} + +void GPUParticlesAttractorVectorField::set_extents(const Vector3 &p_extents) { + extents = p_extents; + RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents); + update_gizmo(); +} + +Vector3 GPUParticlesAttractorVectorField::get_extents() const { + return extents; +} + +void GPUParticlesAttractorVectorField::set_texture(const Ref<Texture3D> &p_texture) { + texture = p_texture; + RID tex = texture.is_valid() ? texture->get_rid() : RID(); + RS::get_singleton()->particles_collision_set_field_texture(_get_collision(), tex); +} + +Ref<Texture3D> GPUParticlesAttractorVectorField::get_texture() const { + return texture; +} + +AABB GPUParticlesAttractorVectorField::get_aabb() const { + return AABB(-extents, extents * 2); +} + +GPUParticlesAttractorVectorField::GPUParticlesAttractorVectorField() : + GPUParticlesAttractor3D(RS::PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT) { +} + +GPUParticlesAttractorVectorField::~GPUParticlesAttractorVectorField() { +} diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h new file mode 100644 index 0000000000..9b644ade6b --- /dev/null +++ b/scene/3d/gpu_particles_collision_3d.h @@ -0,0 +1,342 @@ +/*************************************************************************/ +/* gpu_particles_collision_3d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GPU_PARTICLES_COLLISION_3D_H +#define GPU_PARTICLES_COLLISION_3D_H + +#include "core/templates/local_vector.h" +#include "core/templates/rid.h" +#include "scene/3d/visual_instance_3d.h" +#include "scene/resources/material.h" + +class GPUParticlesCollision3D : public VisualInstance3D { + GDCLASS(GPUParticlesCollision3D, VisualInstance3D); + + uint32_t cull_mask = 0xFFFFFFFF; + RID collision; + +protected: + _FORCE_INLINE_ RID _get_collision() { return collision; } + static void _bind_methods(); + + GPUParticlesCollision3D(RS::ParticlesCollisionType p_type); + +public: + void set_cull_mask(uint32_t p_cull_mask); + uint32_t get_cull_mask() const; + + virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override { return Vector<Face3>(); } + + ~GPUParticlesCollision3D(); +}; + +class GPUParticlesCollisionSphere : public GPUParticlesCollision3D { + GDCLASS(GPUParticlesCollisionSphere, GPUParticlesCollision3D); + + float radius = 1.0; + +protected: + static void _bind_methods(); + +public: + void set_radius(float p_radius); + float get_radius() const; + + virtual AABB get_aabb() const override; + + GPUParticlesCollisionSphere(); + ~GPUParticlesCollisionSphere(); +}; + +class GPUParticlesCollisionBox : public GPUParticlesCollision3D { + GDCLASS(GPUParticlesCollisionBox, GPUParticlesCollision3D); + + Vector3 extents = Vector3(1, 1, 1); + +protected: + static void _bind_methods(); + +public: + void set_extents(const Vector3 &p_extents); + Vector3 get_extents() const; + + virtual AABB get_aabb() const override; + + GPUParticlesCollisionBox(); + ~GPUParticlesCollisionBox(); +}; + +class GPUParticlesCollisionSDF : public GPUParticlesCollision3D { + GDCLASS(GPUParticlesCollisionSDF, GPUParticlesCollision3D); + +public: + enum Resolution { + RESOLUTION_16, + RESOLUTION_32, + RESOLUTION_64, + RESOLUTION_128, + RESOLUTION_256, + RESOLUTION_512, + RESOLUTION_MAX, + }; + + typedef void (*BakeBeginFunc)(int); + typedef void (*BakeStepFunc)(int, const String &); + typedef void (*BakeEndFunc)(); + +private: + Vector3 extents = Vector3(1, 1, 1); + Resolution resolution = RESOLUTION_64; + Ref<Texture3D> texture; + float thickness = 1.0; + + struct PlotMesh { + Ref<Mesh> mesh; + Transform local_xform; + }; + + void _find_meshes(const AABB &p_aabb, Node *p_at_node, List<PlotMesh> &plot_meshes); + + struct BVH { + enum { + LEAF_BIT = 1 << 30, + LEAF_MASK = LEAF_BIT - 1 + }; + AABB bounds; + uint32_t children[2]; + }; + + struct FacePos { + Vector3 center; + uint32_t index; + }; + + struct FaceSort { + uint32_t axis; + bool operator()(const FacePos &p_left, const FacePos &p_right) const { + return p_left.center[axis] < p_right.center[axis]; + } + }; + + uint32_t _create_bvh(LocalVector<BVH> &bvh_tree, FacePos *p_faces, uint32_t p_face_count, const Face3 *p_triangles, float p_thickness); + + struct ComputeSDFParams { + float *cells; + Vector3i size; + float cell_size; + Vector3 cell_offset; + const BVH *bvh; + const Face3 *triangles; + float thickness; + }; + + void _find_closest_distance(const Vector3 &p_pos, const BVH *bvh, uint32_t p_bvh_cell, const Face3 *triangles, float thickness, float &closest_distance); + void _compute_sdf_z(uint32_t p_z, ComputeSDFParams *params); + void _compute_sdf(ComputeSDFParams *params); + +protected: + static void _bind_methods(); + +public: + void set_thickness(float p_thickness); + float get_thickness() const; + + void set_extents(const Vector3 &p_extents); + Vector3 get_extents() const; + + void set_resolution(Resolution p_resolution); + Resolution get_resolution() const; + + void set_texture(const Ref<Texture3D> &p_texture); + Ref<Texture3D> get_texture() const; + + Vector3i get_estimated_cell_size() const; + Ref<Image> bake(); + + virtual AABB get_aabb() const override; + + static BakeBeginFunc bake_begin_function; + static BakeStepFunc bake_step_function; + static BakeEndFunc bake_end_function; + + GPUParticlesCollisionSDF(); + ~GPUParticlesCollisionSDF(); +}; + +VARIANT_ENUM_CAST(GPUParticlesCollisionSDF::Resolution) + +class GPUParticlesCollisionHeightField : public GPUParticlesCollision3D { + GDCLASS(GPUParticlesCollisionHeightField, GPUParticlesCollision3D); + +public: + enum Resolution { + RESOLUTION_256, + RESOLUTION_512, + RESOLUTION_1024, + RESOLUTION_2048, + RESOLUTION_4096, + RESOLUTION_8192, + RESOLUTION_MAX, + }; + + enum UpdateMode { + UPDATE_MODE_WHEN_MOVED, + UPDATE_MODE_ALWAYS, + }; + +private: + Vector3 extents = Vector3(1, 1, 1); + Resolution resolution = RESOLUTION_1024; + bool follow_camera_mode = false; + float follow_camera_push_ratio = 0.1; + + UpdateMode update_mode = UPDATE_MODE_WHEN_MOVED; + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_extents(const Vector3 &p_extents); + Vector3 get_extents() const; + + void set_resolution(Resolution p_resolution); + Resolution get_resolution() const; + + void set_update_mode(UpdateMode p_update_mode); + UpdateMode get_update_mode() const; + + void set_follow_camera_mode(bool p_enabled); + bool is_follow_camera_mode_enabled() const; + + void set_follow_camera_push_ratio(float p_ratio); + float get_follow_camera_push_ratio() const; + + virtual AABB get_aabb() const override; + + GPUParticlesCollisionHeightField(); + ~GPUParticlesCollisionHeightField(); +}; + +VARIANT_ENUM_CAST(GPUParticlesCollisionHeightField::Resolution) +VARIANT_ENUM_CAST(GPUParticlesCollisionHeightField::UpdateMode) + +class GPUParticlesAttractor3D : public VisualInstance3D { + GDCLASS(GPUParticlesAttractor3D, VisualInstance3D); + + uint32_t cull_mask = 0xFFFFFFFF; + RID collision; + float strength = 1.0; + float attenuation = 1.0; + float directionality = 0.0; + +protected: + _FORCE_INLINE_ RID _get_collision() { return collision; } + static void _bind_methods(); + + GPUParticlesAttractor3D(RS::ParticlesCollisionType p_type); + +public: + void set_cull_mask(uint32_t p_cull_mask); + uint32_t get_cull_mask() const; + + void set_strength(float p_strength); + float get_strength() const; + + void set_attenuation(float p_attenuation); + float get_attenuation() const; + + void set_directionality(float p_directionality); + float get_directionality() const; + + virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override { return Vector<Face3>(); } + + ~GPUParticlesAttractor3D(); +}; + +class GPUParticlesAttractorSphere : public GPUParticlesAttractor3D { + GDCLASS(GPUParticlesAttractorSphere, GPUParticlesAttractor3D); + + float radius = 1.0; + +protected: + static void _bind_methods(); + +public: + void set_radius(float p_radius); + float get_radius() const; + + virtual AABB get_aabb() const override; + + GPUParticlesAttractorSphere(); + ~GPUParticlesAttractorSphere(); +}; + +class GPUParticlesAttractorBox : public GPUParticlesAttractor3D { + GDCLASS(GPUParticlesAttractorBox, GPUParticlesAttractor3D); + + Vector3 extents = Vector3(1, 1, 1); + +protected: + static void _bind_methods(); + +public: + void set_extents(const Vector3 &p_extents); + Vector3 get_extents() const; + + virtual AABB get_aabb() const override; + + GPUParticlesAttractorBox(); + ~GPUParticlesAttractorBox(); +}; + +class GPUParticlesAttractorVectorField : public GPUParticlesAttractor3D { + GDCLASS(GPUParticlesAttractorVectorField, GPUParticlesAttractor3D); + + Vector3 extents = Vector3(1, 1, 1); + Ref<Texture3D> texture; + +protected: + static void _bind_methods(); + +public: + void set_extents(const Vector3 &p_extents); + Vector3 get_extents() const; + + void set_texture(const Ref<Texture3D> &p_texture); + Ref<Texture3D> get_texture() const; + + virtual AABB get_aabb() const override; + + GPUParticlesAttractorVectorField(); + ~GPUParticlesAttractorVectorField(); +}; + +#endif // GPU_PARTICLES_COLLISION_3D_H diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index cc1622722e..2dc3cd3230 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -30,8 +30,8 @@ #include "light_3d.h" -#include "core/engine.h" -#include "core/project_settings.h" +#include "core/config/engine.h" +#include "core/config/project_settings.h" #include "scene/resources/surface_tool.h" bool Light3D::_can_gizmo_scale() const { @@ -270,6 +270,7 @@ void Light3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_normal_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_fog_fade", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_param", "get_param", PARAM_SHADOW_VOLUMETRIC_FOG_FADE); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0.1,8,0.01"), "set_param", "get_param", PARAM_SHADOW_BLUR); ADD_GROUP("Editor", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only"); @@ -292,6 +293,7 @@ void Light3D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS); BIND_ENUM_CONSTANT(PARAM_SHADOW_PANCAKE_SIZE); BIND_ENUM_CONSTANT(PARAM_SHADOW_BLUR); + BIND_ENUM_CONSTANT(PARAM_SHADOW_VOLUMETRIC_FOG_FADE); BIND_ENUM_CONSTANT(PARAM_TRANSMITTANCE_BIAS); BIND_ENUM_CONSTANT(PARAM_MAX); @@ -345,6 +347,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) { set_param(PARAM_SHADOW_BIAS, 0.02); set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0); set_param(PARAM_TRANSMITTANCE_BIAS, 0.05); + set_param(PARAM_SHADOW_VOLUMETRIC_FOG_FADE, 1.0); set_param(PARAM_SHADOW_FADE_START, 1); set_disable_scale(true); } @@ -445,7 +448,7 @@ String OmniLight3D::get_configuration_warning() const { String warning = Light3D::get_configuration_warning(); if (!has_shadow() && get_projector().is_valid()) { - if (warning != String()) { + if (!warning.empty()) { warning += "\n\n"; } warning += TTR("Projector texture only works with shadows active."); @@ -479,15 +482,14 @@ String SpotLight3D::get_configuration_warning() const { String warning = Light3D::get_configuration_warning(); if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) { - if (warning != String()) { + if (!warning.empty()) { warning += "\n\n"; } - warning += TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows."); } if (!has_shadow() && get_projector().is_valid()) { - if (warning != String()) { + if (!warning.empty()) { warning += "\n\n"; } warning += TTR("Projector texture only works with shadows active."); diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index f106151472..69c0478b86 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -58,6 +58,7 @@ public: PARAM_SHADOW_BIAS = RS::LIGHT_PARAM_SHADOW_BIAS, PARAM_SHADOW_PANCAKE_SIZE = RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE, PARAM_SHADOW_BLUR = RS::LIGHT_PARAM_SHADOW_BLUR, + PARAM_SHADOW_VOLUMETRIC_FOG_FADE = RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE, PARAM_TRANSMITTANCE_BIAS = RS::LIGHT_PARAM_TRANSMITTANCE_BIAS, PARAM_MAX = RS::LIGHT_PARAM_MAX }; diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index e179261002..f9f8f276a3 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -30,7 +30,7 @@ #include "navigation_agent_3d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "scene/3d/navigation_3d.h" #include "servers/navigation_server_3d.h" @@ -287,11 +287,16 @@ void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) { } String NavigationAgent3D::get_configuration_warning() const { + String warning = Node::get_configuration_warning(); + if (!Object::cast_to<Node3D>(get_parent())) { - return TTR("The NavigationAgent3D can be used only under a spatial node."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The NavigationAgent3D can be used only under a spatial node."); } - return String(); + return warning; } void NavigationAgent3D::update_navigation() { diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h index e80367ea50..dcfd302561 100644 --- a/scene/3d/navigation_agent_3d.h +++ b/scene/3d/navigation_agent_3d.h @@ -31,7 +31,7 @@ #ifndef NAVIGATION_AGENT_H #define NAVIGATION_AGENT_H -#include "core/vector.h" +#include "core/templates/vector.h" #include "scene/main/node.h" class Node3D; diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp index 69fd5b02fc..adbff06ed6 100644 --- a/scene/3d/navigation_obstacle_3d.cpp +++ b/scene/3d/navigation_obstacle_3d.cpp @@ -113,11 +113,16 @@ Node *NavigationObstacle3D::get_navigation_node() const { } String NavigationObstacle3D::get_configuration_warning() const { + String warning = Node::get_configuration_warning(); + if (!Object::cast_to<Node3D>(get_parent())) { - return TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object."); } - return String(); + return warning; } void NavigationObstacle3D::update_agent_shape() { diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 15ed448a65..3d3467583d 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -189,19 +189,28 @@ String NavigationRegion3D::get_configuration_warning() const { return String(); } + String warning = Node3D::get_configuration_warning(); + if (!navmesh.is_valid()) { - return TTR("A NavigationMesh resource must be set or created for this node to work."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("A NavigationMesh resource must be set or created for this node to work."); } + const Node3D *c = this; while (c) { if (Object::cast_to<Navigation3D>(c)) { - return String(); + return warning; } c = Object::cast_to<Node3D>(c->get_parent()); } - return TTR("NavigationRegion3D must be a child or grandchild to a Navigation3D node. It only provides navigation data."); + if (!warning.empty()) { + warning += "\n\n"; + } + return warning + TTR("NavigationRegion3D must be a child or grandchild to a Navigation3D node. It only provides navigation data."); } void NavigationRegion3D::_bind_methods() { diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index bd9e4f5bde..e8005f38ed 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -30,8 +30,8 @@ #include "node_3d.h" -#include "core/engine.h" -#include "core/message_queue.h" +#include "core/config/engine.h" +#include "core/object/message_queue.h" #include "scene/main/scene_tree.h" #include "scene/main/window.h" #include "scene/scene_string_names.h" @@ -103,8 +103,8 @@ void Node3D::_propagate_transform_changed(Node3D *p_origin) { data.children_lock++; for (List<Node3D *>::Element *E = data.children.front(); E; E = E->next()) { - if (E->get()->data.toplevel_active) { - continue; //don't propagate to a toplevel + if (E->get()->data.top_level_active) { + continue; //don't propagate to a top_level } E->get()->_propagate_transform_changed(p_origin); } @@ -136,12 +136,12 @@ void Node3D::_notification(int p_what) { data.C = nullptr; } - if (data.toplevel && !Engine::get_singleton()->is_editor_hint()) { + if (data.top_level && !Engine::get_singleton()->is_editor_hint()) { if (data.parent) { data.local_transform = data.parent->get_global_transform() * get_transform(); data.dirty = DIRTY_VECTORS; //global is always dirty upon entering a scene } - data.toplevel_active = true; + data.top_level_active = true; } data.dirty |= DIRTY_GLOBAL; //global is always dirty upon entering a scene @@ -160,7 +160,7 @@ void Node3D::_notification(int p_what) { } data.parent = nullptr; data.C = nullptr; - data.toplevel_active = false; + data.top_level_active = false; } break; case NOTIFICATION_ENTER_WORLD: { data.inside_world = true; @@ -238,7 +238,7 @@ void Node3D::set_transform(const Transform &p_transform) { void Node3D::set_global_transform(const Transform &p_transform) { Transform xform = - (data.parent && !data.toplevel_active) ? + (data.parent && !data.top_level_active) ? data.parent->get_global_transform().affine_inverse() * p_transform : p_transform; @@ -261,7 +261,7 @@ Transform Node3D::get_global_transform() const { _update_local_transform(); } - if (data.parent && !data.toplevel_active) { + if (data.parent && !data.top_level_active) { data.global_transform = data.parent->get_global_transform() * data.local_transform; } else { data.global_transform = data.local_transform; @@ -462,8 +462,8 @@ bool Node3D::is_scale_disabled() const { return data.disable_scale; } -void Node3D::set_as_toplevel(bool p_enabled) { - if (data.toplevel == p_enabled) { +void Node3D::set_as_top_level(bool p_enabled) { + if (data.top_level == p_enabled) { return; } if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) { @@ -473,16 +473,16 @@ void Node3D::set_as_toplevel(bool p_enabled) { set_transform(data.parent->get_global_transform().affine_inverse() * get_global_transform()); } - data.toplevel = p_enabled; - data.toplevel_active = p_enabled; + data.top_level = p_enabled; + data.top_level_active = p_enabled; } else { - data.toplevel = p_enabled; + data.top_level = p_enabled; } } -bool Node3D::is_set_as_toplevel() const { - return data.toplevel; +bool Node3D::is_set_as_top_level() const { + return data.top_level; } Ref<World3D> Node3D::get_world_3d() const { @@ -715,8 +715,8 @@ void Node3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_global_transform"), &Node3D::get_global_transform); ClassDB::bind_method(D_METHOD("get_parent_spatial"), &Node3D::get_parent_spatial); ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Node3D::set_ignore_transform_notification); - ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &Node3D::set_as_toplevel); - ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &Node3D::is_set_as_toplevel); + ClassDB::bind_method(D_METHOD("set_as_top_level", "enable"), &Node3D::set_as_top_level); + ClassDB::bind_method(D_METHOD("is_set_as_top_level"), &Node3D::is_set_as_top_level); ClassDB::bind_method(D_METHOD("set_disable_scale", "disable"), &Node3D::set_disable_scale); ClassDB::bind_method(D_METHOD("is_scale_disabled"), &Node3D::is_scale_disabled); ClassDB::bind_method(D_METHOD("get_world_3d"), &Node3D::get_world_3d); @@ -773,6 +773,7 @@ void Node3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level"); ADD_GROUP("Matrix", ""); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform"); ADD_GROUP("Visibility", ""); @@ -788,8 +789,8 @@ Node3D::Node3D() : data.children_lock = 0; data.ignore_notification = false; - data.toplevel = false; - data.toplevel_active = false; + data.top_level = false; + data.top_level_active = false; data.scale = Vector3(1, 1, 1); data.viewport = nullptr; data.inside_world = false; diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index 327d4671e9..229e0f2c8c 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -71,8 +71,8 @@ class Node3D : public Node { Viewport *viewport; - bool toplevel_active; - bool toplevel; + bool top_level_active; + bool top_level; bool inside_world; int children_lock; @@ -144,8 +144,8 @@ public: virtual Transform get_local_gizmo_transform() const; #endif - void set_as_toplevel(bool p_enabled); - bool is_set_as_toplevel() const; + void set_as_top_level(bool p_enabled); + bool is_set_as_top_level() const; void set_disable_scale(bool p_enabled); bool is_scale_disabled() const; diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index bf69a8598d..f25a64c567 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -30,7 +30,7 @@ #include "path_3d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "scene/scene_string_names.h" void Path3D::_notification(int p_what) { @@ -250,16 +250,24 @@ String PathFollow3D::get_configuration_warning() const { return String(); } + String warning = Node3D::get_configuration_warning(); + if (!Object::cast_to<Path3D>(get_parent())) { - return TTR("PathFollow3D only works when set as a child of a Path3D node."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("PathFollow3D only works when set as a child of a Path3D node."); } else { Path3D *path = Object::cast_to<Path3D>(get_parent()); if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) { - return TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource."); } } - return String(); + return warning; } void PathFollow3D::_bind_methods() { diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index fc021e5532..a3e00d2cc3 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -30,12 +30,11 @@ #include "physics_body_3d.h" +#include "core/config/engine.h" #include "core/core_string_names.h" -#include "core/engine.h" -#include "core/list.h" -#include "core/method_bind_ext.gen.inc" -#include "core/object.h" -#include "core/rid.h" +#include "core/object/class_db.h" +#include "core/templates/list.h" +#include "core/templates/rid.h" #include "scene/3d/collision_shape_3d.h" #include "scene/scene_string_names.h" #include "servers/navigation_server_3d.h" @@ -130,15 +129,6 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) { PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid()); } -void PhysicsBody3D::_set_layers(uint32_t p_mask) { - set_collision_layer(p_mask); - set_collision_mask(p_mask); -} - -uint32_t PhysicsBody3D::_get_layers() const { - return get_collision_layer(); -} - void PhysicsBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &PhysicsBody3D::set_collision_layer); ClassDB::bind_method(D_METHOD("get_collision_layer"), &PhysicsBody3D::get_collision_layer); @@ -152,9 +142,6 @@ void PhysicsBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &PhysicsBody3D::set_collision_layer_bit); ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &PhysicsBody3D::get_collision_layer_bit); - ClassDB::bind_method(D_METHOD("_set_layers", "mask"), &PhysicsBody3D::_set_layers); - ClassDB::bind_method(D_METHOD("_get_layers"), &PhysicsBody3D::_get_layers); - ADD_GROUP("Collision", "collision_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); @@ -737,7 +724,7 @@ String RigidBody3D::get_configuration_warning() const { String warning = CollisionObject3D::get_configuration_warning(); if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) { - if (warning != String()) { + if (!warning.empty()) { warning += "\n\n"; } warning += TTR("Size changes to RigidBody3D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."); @@ -2606,7 +2593,7 @@ void PhysicalBone3D::_start_physics_simulation() { PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); - set_as_toplevel(true); + set_as_top_level(true); _internal_simulate_physics = true; } @@ -2626,7 +2613,7 @@ void PhysicalBone3D::_stop_physics_simulation() { if (_internal_simulate_physics) { PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), nullptr, ""); parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false); - set_as_toplevel(false); + set_as_top_level(false); _internal_simulate_physics = false; } } diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 9830a55183..da947ba02e 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -31,7 +31,7 @@ #ifndef PHYSICS_BODY_3D_H #define PHYSICS_BODY_3D_H -#include "core/vset.h" +#include "core/templates/vset.h" #include "scene/3d/collision_object_3d.h" #include "scene/resources/physics_material.h" #include "servers/physics_server_3d.h" @@ -43,9 +43,6 @@ class PhysicsBody3D : public CollisionObject3D { uint32_t collision_layer; uint32_t collision_mask; - void _set_layers(uint32_t p_mask); - uint32_t _get_layers() const; - protected: static void _bind_methods(); PhysicsBody3D(PhysicsServer3D::BodyMode p_mode); diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp index 2a922e3cda..811e8a331b 100644 --- a/scene/3d/ray_cast_3d.cpp +++ b/scene/3d/ray_cast_3d.cpp @@ -31,12 +31,12 @@ #include "ray_cast_3d.h" #include "collision_object_3d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "mesh_instance_3d.h" #include "servers/physics_server_3d.h" -void RayCast3D::set_cast_to(const Vector3 &p_point) { - cast_to = p_point; +void RayCast3D::set_target_position(const Vector3 &p_point) { + target_position = p_point; if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) { update_gizmo(); } @@ -45,8 +45,8 @@ void RayCast3D::set_cast_to(const Vector3 &p_point) { } } -Vector3 RayCast3D::get_cast_to() const { - return cast_to; +Vector3 RayCast3D::get_target_position() const { + return target_position; } void RayCast3D::set_collision_mask(uint32_t p_mask) { @@ -202,7 +202,7 @@ void RayCast3D::_update_raycast_state() { Transform gt = get_global_transform(); - Vector3 to = cast_to; + Vector3 to = target_position; if (to == Vector3()) { to = Vector3(0, 0.01, 0); } @@ -276,8 +276,8 @@ void RayCast3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast3D::set_enabled); ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast3D::is_enabled); - ClassDB::bind_method(D_METHOD("set_cast_to", "local_point"), &RayCast3D::set_cast_to); - ClassDB::bind_method(D_METHOD("get_cast_to"), &RayCast3D::get_cast_to); + ClassDB::bind_method(D_METHOD("set_target_position", "local_point"), &RayCast3D::set_target_position); + ClassDB::bind_method(D_METHOD("get_target_position"), &RayCast3D::get_target_position); ClassDB::bind_method(D_METHOD("is_colliding"), &RayCast3D::is_colliding); ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast3D::force_raycast_update); @@ -312,7 +312,7 @@ void RayCast3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cast_to"), "set_cast_to", "get_cast_to"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position"), "set_target_position", "get_target_position"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); ADD_GROUP("Collide With", "collide_with"); @@ -360,7 +360,7 @@ void RayCast3D::_update_debug_shape() { Vector<Vector3> verts; verts.push_back(Vector3()); - verts.push_back(cast_to); + verts.push_back(target_position); a[Mesh::ARRAY_VERTEX] = verts; mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a); @@ -387,7 +387,7 @@ RayCast3D::RayCast3D() { collided = false; against_shape = 0; collision_mask = 1; - cast_to = Vector3(0, -1, 0); + target_position = Vector3(0, -1, 0); debug_shape = nullptr; exclude_parent_body = true; collide_with_areas = false; diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h index 8f617e5491..f4fe7ba621 100644 --- a/scene/3d/ray_cast_3d.h +++ b/scene/3d/ray_cast_3d.h @@ -43,7 +43,7 @@ class RayCast3D : public Node3D { Vector3 collision_point; Vector3 collision_normal; - Vector3 cast_to; + Vector3 target_position; Set<RID> exclude; uint32_t collision_mask; @@ -74,8 +74,8 @@ public: void set_enabled(bool p_enabled); bool is_enabled() const; - void set_cast_to(const Vector3 &p_point); - Vector3 get_cast_to() const; + void set_target_position(const Vector3 &p_point); + Vector3 get_target_position() const; void set_collision_mask(uint32_t p_mask); uint32_t get_collision_mask() const; diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp index 95fce6b802..358f9346f8 100644 --- a/scene/3d/remote_transform_3d.cpp +++ b/scene/3d/remote_transform_3d.cpp @@ -180,11 +180,16 @@ void RemoteTransform3D::force_update_cache() { } String RemoteTransform3D::get_configuration_warning() const { + String warning = Node3D::get_configuration_warning(); + if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) { - return TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work."); } - return String(); + return warning; } void RemoteTransform3D::_bind_methods() { diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 6723ca04b9..0ae1c0e3b6 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -30,10 +30,10 @@ #include "skeleton_3d.h" -#include "core/engine.h" -#include "core/message_queue.h" -#include "core/project_settings.h" -#include "core/type_info.h" +#include "core/config/engine.h" +#include "core/config/project_settings.h" +#include "core/object/message_queue.h" +#include "core/variant/type_info.h" #include "scene/3d/physics_body_3d.h" #include "scene/resources/surface_tool.h" #include "scene/scene_string_names.h" diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index a21891a32e..95c49750fa 100644 --- a/scene/3d/skeleton_3d.h +++ b/scene/3d/skeleton_3d.h @@ -31,7 +31,7 @@ #ifndef SKELETON_3D_H #define SKELETON_3D_H -#include "core/rid.h" +#include "core/templates/rid.h" #include "scene/3d/node_3d.h" #include "scene/resources/skin.h" diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index a267c57f5e..132c35771b 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -30,10 +30,10 @@ #include "soft_body_3d.h" -#include "core/list.h" -#include "core/object.h" +#include "core/object/class_db.h" #include "core/os/os.h" -#include "core/rid.h" +#include "core/templates/list.h" +#include "core/templates/rid.h" #include "scene/3d/collision_object_3d.h" #include "scene/3d/physics_body_3d.h" #include "scene/3d/skeleton_3d.h" @@ -106,7 +106,7 @@ SoftBody3D::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) { offset = obj_tocopy.offset; } -SoftBody3D::PinnedPoint SoftBody3D::PinnedPoint::operator=(const PinnedPoint &obj) { +SoftBody3D::PinnedPoint &SoftBody3D::PinnedPoint::operator=(const PinnedPoint &obj) { point_index = obj.point_index; spatial_attachment_path = obj.spatial_attachment_path; spatial_attachment = obj.spatial_attachment; @@ -282,7 +282,7 @@ void SoftBody3D::_notification(int p_what) { set_notify_transform(false); // Required to be top level with Transform at center of world in order to modify RenderingServer only to support custom Transform - set_as_toplevel(true); + set_as_top_level(true); set_transform(Transform()); set_notify_transform(true); @@ -425,7 +425,7 @@ void SoftBody3D::_draw_soft_mesh() { /// Necessary in order to render the mesh correctly (Soft body nodes are in global space) simulation_started = true; - call_deferred("set_as_toplevel", true); + call_deferred("set_as_top_level", true); call_deferred("set_transform", Transform()); } diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h index 85cfb81637..c59a0b3aa3 100644 --- a/scene/3d/soft_body_3d.h +++ b/scene/3d/soft_body_3d.h @@ -74,7 +74,7 @@ public: PinnedPoint(); PinnedPoint(const PinnedPoint &obj_tocopy); - PinnedPoint operator=(const PinnedPoint &obj); + PinnedPoint &operator=(const PinnedPoint &obj); }; private: diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp index 9775ecc6c6..287d760db0 100644 --- a/scene/3d/spring_arm_3d.cpp +++ b/scene/3d/spring_arm_3d.cpp @@ -30,7 +30,7 @@ #include "spring_arm_3d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "scene/3d/collision_object_3d.h" #include "scene/resources/sphere_shape_3d.h" #include "servers/physics_server_3d.h" diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 3b76cb6499..9f4d64cb32 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -667,8 +667,8 @@ void Sprite3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); ADD_GROUP("Animation", ""); - ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes"); ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes"); ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords"); ADD_GROUP("Region", "region_"); @@ -1074,11 +1074,16 @@ StringName AnimatedSprite3D::get_animation() const { } String AnimatedSprite3D::get_configuration_warning() const { + String warning = SpriteBase3D::get_configuration_warning(); + if (frames.is_null()) { - return TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames."); } - return String(); + return warning; } void AnimatedSprite3D::_bind_methods() { diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp index 4c71ab470b..b58f313c16 100644 --- a/scene/3d/vehicle_body_3d.cpp +++ b/scene/3d/vehicle_body_3d.cpp @@ -103,11 +103,16 @@ void VehicleWheel3D::_notification(int p_what) { } String VehicleWheel3D::get_configuration_warning() const { + String warning = Node3D::get_configuration_warning(); + if (!Object::cast_to<VehicleBody3D>(get_parent())) { - return TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D."); } - return String(); + return warning; } void VehicleWheel3D::_update(PhysicsDirectBodyState3D *s) { diff --git a/scene/3d/velocity_tracker_3d.cpp b/scene/3d/velocity_tracker_3d.cpp index db10f3273b..eba7d44c16 100644 --- a/scene/3d/velocity_tracker_3d.cpp +++ b/scene/3d/velocity_tracker_3d.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "velocity_tracker_3d.h" -#include "core/engine.h" +#include "core/config/engine.h" void VelocityTracker3D::set_track_physics_step(bool p_track_physics_step) { physics_step = p_track_physics_step; diff --git a/scene/3d/visibility_notifier_3d.cpp b/scene/3d/visibility_notifier_3d.cpp index a64b0df1cc..9f5c40caf4 100644 --- a/scene/3d/visibility_notifier_3d.cpp +++ b/scene/3d/visibility_notifier_3d.cpp @@ -30,7 +30,7 @@ #include "visibility_notifier_3d.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "scene/3d/camera_3d.h" #include "scene/3d/physics_body_3d.h" #include "scene/animation/animation_player.h" diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index 195674f62d..51bcb411da 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -32,7 +32,7 @@ #define VISUAL_INSTANCE_H #include "core/math/face3.h" -#include "core/rid.h" +#include "core/templates/rid.h" #include "scene/3d/node_3d.h" #include "scene/resources/material.h" diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp index 5e73e460ed..3c12d4991e 100644 --- a/scene/3d/world_environment.cpp +++ b/scene/3d/world_environment.cpp @@ -110,22 +110,30 @@ Ref<CameraEffects> WorldEnvironment::get_camera_effects() const { } String WorldEnvironment::get_configuration_warning() const { + String warning = Node::get_configuration_warning(); + if (!environment.is_valid()) { - return TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect."); } if (!is_inside_tree()) { - return String(); + return warning; } List<Node *> nodes; get_tree()->get_nodes_in_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), &nodes); if (nodes.size() > 1) { - return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."); } - return String(); + return warning; } void WorldEnvironment::_bind_methods() { diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index f4a514cdd6..c0015aa338 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -60,13 +60,18 @@ String XRCamera3D::get_configuration_warning() const { return String(); } + String warning = Camera3D::get_configuration_warning(); + // must be child node of XROrigin3D! XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); if (origin == nullptr) { - return TTR("XRCamera3D must have an XROrigin3D node as its parent."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("XRCamera3D must have an XROrigin3D node as its parent."); }; - return String(); + return warning; }; Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const { @@ -362,17 +367,25 @@ String XRController3D::get_configuration_warning() const { return String(); } + String warning = Node3D::get_configuration_warning(); + // must be child node of XROrigin! XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); if (origin == nullptr) { - return TTR("XRController3D must have an XROrigin3D node as its parent."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("XRController3D must have an XROrigin3D node as its parent."); }; if (controller_id == 0) { - return TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller."); }; - return String(); + return warning; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -479,17 +492,25 @@ String XRAnchor3D::get_configuration_warning() const { return String(); } + String warning = Node3D::get_configuration_warning(); + // must be child node of XROrigin3D! XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); if (origin == nullptr) { - return TTR("XRAnchor3D must have an XROrigin3D node as its parent."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("XRAnchor3D must have an XROrigin3D node as its parent."); }; if (anchor_id == 0) { - return TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor."); }; - return String(); + return warning; }; Plane XRAnchor3D::get_plane() const { @@ -512,11 +533,16 @@ String XROrigin3D::get_configuration_warning() const { return String(); } + String warning = Node3D::get_configuration_warning(); + if (tracked_camera == nullptr) { - return TTR("XROrigin3D requires an XRCamera3D child node."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("XROrigin3D requires an XRCamera3D child node."); } - return String(); + return warning; }; void XROrigin3D::_bind_methods() { diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 66c587e2d4..e9e17148d6 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -30,8 +30,8 @@ #include "animation_player.h" -#include "core/engine.h" -#include "core/message_queue.h" +#include "core/config/engine.h" +#include "core/object/message_queue.h" #include "scene/scene_string_names.h" #include "servers/audio/audio_stream.h" @@ -762,12 +762,10 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, f next_pos = len; } - // fix delta - delta = next_pos - cd.pos; + bool backwards = signbit(delta); // Negative zero means playing backwards too + delta = next_pos - cd.pos; // Fix delta (after determination of backwards because negative zero is lost here) if (&cd == &playback.current) { - bool backwards = delta < 0; - if (!backwards && cd.pos <= len && next_pos == len /*&& playback.blend.empty()*/) { //playback finished end_reached = true; @@ -1294,12 +1292,12 @@ bool AnimationPlayer::is_valid() const { } float AnimationPlayer::get_current_animation_position() const { - ERR_FAIL_COND_V(!playback.current.from, 0); + ERR_FAIL_COND_V_MSG(!playback.current.from, 0, "AnimationPlayer has no current animation"); return playback.current.pos; } float AnimationPlayer::get_current_animation_length() const { - ERR_FAIL_COND_V(!playback.current.from, 0); + ERR_FAIL_COND_V_MSG(!playback.current.from, 0, "AnimationPlayer has no current animation"); return playback.current.from->animation->get_length(); } diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 466536db10..2ef3ba87b2 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -31,8 +31,7 @@ #include "animation_tree.h" #include "animation_blend_tree.h" -#include "core/engine.h" -#include "core/method_bind_ext.gen.inc" +#include "core/config/engine.h" #include "scene/scene_string_names.h" #include "servers/audio/audio_stream.h" @@ -1288,39 +1287,31 @@ String AnimationTree::get_configuration_warning() const { String warning = Node::get_configuration_warning(); if (!root.is_valid()) { - if (warning != String()) { + if (!warning.empty()) { warning += "\n\n"; } warning += TTR("No root AnimationNode for the graph is set."); } if (!has_node(animation_player)) { - if (warning != String()) { + if (!warning.empty()) { warning += "\n\n"; } - warning += TTR("Path to an AnimationPlayer node containing animations is not set."); - return warning; - } - - AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player)); - - if (!player) { - if (warning != String()) { - warning += "\n\n"; - } - - warning += TTR("Path set for AnimationPlayer does not lead to an AnimationPlayer node."); - return warning; - } + } else { + AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player)); - if (!player->has_node(player->get_root())) { - if (warning != String()) { - warning += "\n\n"; + if (!player) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("Path set for AnimationPlayer does not lead to an AnimationPlayer node."); + } else if (!player->has_node(player->get_root())) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The AnimationPlayer root node is not a valid node."); } - - warning += TTR("The AnimationPlayer root node is not a valid node."); - return warning; } return warning; diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index bd4396d680..1a2a97ada8 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -30,8 +30,6 @@ #include "tween.h" -#include "core/method_bind_ext.gen.inc" - void Tween::_add_pending_command(StringName p_key, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5, const Variant &p_arg6, const Variant &p_arg7, const Variant &p_arg8, const Variant &p_arg9, const Variant &p_arg10) { // Add a new pending command and reference it pending_commands.push_back(PendingCommand()); diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index 48f70e88cb..14aae9c7bf 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -30,7 +30,7 @@ #include "audio_stream_player.h" -#include "core/engine.h" +#include "core/config/engine.h" void AudioStreamPlayer::_mix_to_bus(const AudioFrame *p_frames, int p_amount) { int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus); diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp index f57c8e58db..f848fc3e68 100644 --- a/scene/debugger/scene_debugger.cpp +++ b/scene/debugger/scene_debugger.cpp @@ -32,7 +32,7 @@ #include "core/debugger/engine_debugger.h" #include "core/io/marshalls.h" -#include "core/script_language.h" +#include "core/object/script_language.h" #include "scene/main/scene_tree.h" #include "scene/main/window.h" #include "scene/resources/packed_scene.h" diff --git a/scene/debugger/scene_debugger.h b/scene/debugger/scene_debugger.h index a2bafde039..af2d8904b5 100644 --- a/scene/debugger/scene_debugger.h +++ b/scene/debugger/scene_debugger.h @@ -31,10 +31,10 @@ #ifndef SCENE_DEBUGGER_H #define SCENE_DEBUGGER_H -#include "core/array.h" -#include "core/object.h" -#include "core/pair.h" -#include "core/ustring.h" +#include "core/object/class_db.h" +#include "core/string/ustring.h" +#include "core/templates/pair.h" +#include "core/variant/array.h" class Script; diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index 6fef44481a..1a19c75d27 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -60,7 +60,7 @@ void BaseButton::_gui_input(Ref<InputEvent> p_event) { Ref<InputEventMouseButton> mouse_button = p_event; bool ui_accept = p_event->is_action("ui_accept") && !p_event->is_echo(); - bool button_masked = mouse_button.is_valid() && ((1 << (mouse_button->get_button_index() - 1)) & button_mask) > 0; + bool button_masked = mouse_button.is_valid() && ((1 << (mouse_button->get_button_index() - 1)) & button_mask) != 0; if (button_masked || ui_accept) { on_action_event(p_event); return; @@ -307,17 +307,6 @@ int BaseButton::get_button_mask() const { return button_mask; } -void BaseButton::set_enabled_focus_mode(FocusMode p_mode) { - enabled_focus_mode = p_mode; - if (!status.disabled) { - set_focus_mode(p_mode); - } -} - -Control::FocusMode BaseButton::get_enabled_focus_mode() const { - return enabled_focus_mode; -} - void BaseButton::set_keep_pressed_outside(bool p_on) { keep_pressed_outside = p_on; } @@ -326,12 +315,12 @@ bool BaseButton::is_keep_pressed_outside() const { return keep_pressed_outside; } -void BaseButton::set_shortcut(const Ref<ShortCut> &p_shortcut) { +void BaseButton::set_shortcut(const Ref<Shortcut> &p_shortcut) { shortcut = p_shortcut; set_process_unhandled_input(shortcut.is_valid()); } -Ref<ShortCut> BaseButton::get_shortcut() const { +Ref<Shortcut> BaseButton::get_shortcut() const { return shortcut; } @@ -345,7 +334,7 @@ String BaseButton::get_tooltip(const Point2 &p_pos) const { String tooltip = Control::get_tooltip(p_pos); if (shortcut_in_tooltip && shortcut.is_valid() && shortcut->is_valid()) { String text = shortcut->get_name() + " (" + shortcut->get_as_text() + ")"; - if (shortcut->get_name().nocasecmp_to(tooltip) != 0) { + if (tooltip != String() && shortcut->get_name().nocasecmp_to(tooltip) != 0) { text += "\n" + tooltip; } tooltip = text; @@ -388,8 +377,6 @@ void BaseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_button_mask", "mask"), &BaseButton::set_button_mask); ClassDB::bind_method(D_METHOD("get_button_mask"), &BaseButton::get_button_mask); ClassDB::bind_method(D_METHOD("get_draw_mode"), &BaseButton::get_draw_mode); - ClassDB::bind_method(D_METHOD("set_enabled_focus_mode", "mode"), &BaseButton::set_enabled_focus_mode); - ClassDB::bind_method(D_METHOD("get_enabled_focus_mode"), &BaseButton::get_enabled_focus_mode); ClassDB::bind_method(D_METHOD("set_keep_pressed_outside", "enabled"), &BaseButton::set_keep_pressed_outside); ClassDB::bind_method(D_METHOD("is_keep_pressed_outside"), &BaseButton::is_keep_pressed_outside); @@ -412,10 +399,9 @@ void BaseButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed"); ADD_PROPERTY(PropertyInfo(Variant::INT, "action_mode", PROPERTY_HINT_ENUM, "Button Press,Button Release"), "set_action_mode", "get_action_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "button_mask", PROPERTY_HINT_FLAGS, "Mouse Left, Mouse Right, Mouse Middle"), "set_button_mask", "get_button_mask"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_enabled_focus_mode", "get_enabled_focus_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_pressed_outside"), "set_keep_pressed_outside", "is_keep_pressed_outside"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "ShortCut"), "set_shortcut", "get_shortcut"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "Shortcut"), "set_shortcut", "get_shortcut"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "button_group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group"); BIND_ENUM_CONSTANT(DRAW_NORMAL); BIND_ENUM_CONSTANT(DRAW_PRESSED); @@ -437,7 +423,6 @@ BaseButton::BaseButton() { status.pressing_inside = false; status.disabled = false; set_focus_mode(FOCUS_ALL); - enabled_focus_mode = FOCUS_ALL; action_mode = ACTION_MODE_BUTTON_RELEASE; button_mask = BUTTON_MASK_LEFT; } diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index 12272446d5..33f19949cd 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -49,8 +49,7 @@ private: bool toggle_mode; bool shortcut_in_tooltip; bool keep_pressed_outside; - FocusMode enabled_focus_mode; - Ref<ShortCut> shortcut; + Ref<Shortcut> shortcut; ActionMode action_mode; struct Status { @@ -115,11 +114,8 @@ public: void set_button_mask(int p_mask); int get_button_mask() const; - void set_enabled_focus_mode(FocusMode p_mode); - FocusMode get_enabled_focus_mode() const; - - void set_shortcut(const Ref<ShortCut> &p_shortcut); - Ref<ShortCut> get_shortcut() const; + void set_shortcut(const Ref<Shortcut> &p_shortcut); + Ref<Shortcut> get_shortcut() const; virtual String get_tooltip(const Point2 &p_pos) const override; diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index f130726837..33e030a573 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -57,7 +57,7 @@ void BoxContainer::_resort() { if (!c || !c->is_visible_in_tree()) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } @@ -111,7 +111,7 @@ void BoxContainer::_resort() { if (!c || !c->is_visible_in_tree()) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } @@ -172,7 +172,7 @@ void BoxContainer::_resort() { if (!c || !c->is_visible_in_tree()) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } @@ -224,7 +224,7 @@ Size2 BoxContainer::get_minimum_size() const { if (!c) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index e400801b66..e86ad09aa6 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -30,7 +30,7 @@ #include "button.h" -#include "core/translation.h" +#include "core/string/translation.h" #include "servers/rendering_server.h" Size2 Button::get_minimum_size() const { diff --git a/scene/gui/center_container.cpp b/scene/gui/center_container.cpp index f8f9bec3d7..1a72f3ca4d 100644 --- a/scene/gui/center_container.cpp +++ b/scene/gui/center_container.cpp @@ -40,7 +40,7 @@ Size2 CenterContainer::get_minimum_size() const { if (!c) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } if (!c->is_visible()) { @@ -77,7 +77,7 @@ void CenterContainer::_notification(int p_what) { if (!c) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp index 1ddc730dd1..790faeb4fd 100644 --- a/scene/gui/check_button.cpp +++ b/scene/gui/check_button.cpp @@ -30,7 +30,7 @@ #include "check_button.h" -#include "core/print_string.h" +#include "core/string/print_string.h" #include "servers/rendering_server.h" Size2 CheckButton::get_icon_size() const { diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp new file mode 100644 index 0000000000..f6f52fbf55 --- /dev/null +++ b/scene/gui/code_edit.cpp @@ -0,0 +1,450 @@ +/*************************************************************************/ +/* code_edit.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "code_edit.h" + +void CodeEdit::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_ENTER_TREE: { + set_gutter_width(main_gutter, cache.row_height); + set_gutter_width(line_number_gutter, (line_number_digits + 1) * cache.font->get_char_size('0').width); + set_gutter_width(fold_gutter, cache.row_height / 1.2); + + breakpoint_color = get_theme_color("breakpoint_color"); + breakpoint_icon = get_theme_icon("breakpoint"); + + bookmark_color = get_theme_color("bookmark_color"); + bookmark_icon = get_theme_icon("bookmark"); + + executing_line_color = get_theme_color("executing_line_color"); + executing_line_icon = get_theme_icon("executing_line"); + + line_number_color = get_theme_color("line_number_color"); + + folding_color = get_theme_color("code_folding_color"); + can_fold_icon = get_theme_icon("can_fold"); + folded_icon = get_theme_icon("folded"); + } break; + case NOTIFICATION_DRAW: { + } break; + } +} + +/* Main Gutter */ +void CodeEdit::_update_draw_main_gutter() { + set_gutter_draw(main_gutter, draw_breakpoints || draw_bookmarks || draw_executing_lines); +} + +void CodeEdit::set_draw_breakpoints_gutter(bool p_draw) { + draw_breakpoints = p_draw; + set_gutter_clickable(main_gutter, p_draw); + _update_draw_main_gutter(); +} + +bool CodeEdit::is_drawing_breakpoints_gutter() const { + return draw_breakpoints; +} + +void CodeEdit::set_draw_bookmarks_gutter(bool p_draw) { + draw_bookmarks = p_draw; + _update_draw_main_gutter(); +} + +bool CodeEdit::is_drawing_bookmarks_gutter() const { + return draw_bookmarks; +} + +void CodeEdit::set_draw_executing_lines_gutter(bool p_draw) { + draw_executing_lines = p_draw; + _update_draw_main_gutter(); +} + +bool CodeEdit::is_drawing_executing_lines_gutter() const { + return draw_executing_lines; +} + +void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) { + if (draw_breakpoints && is_line_breakpointed(p_line)) { + int padding = p_region.size.x / 6; + + Rect2 breakpoint_region = p_region; + breakpoint_region.position += Point2(padding, padding); + breakpoint_region.size -= Point2(padding, padding) * 2; + breakpoint_icon->draw_rect(get_canvas_item(), breakpoint_region, false, breakpoint_color); + } + + if (draw_bookmarks && is_line_bookmarked(p_line)) { + int horizontal_padding = p_region.size.x / 2; + int vertical_padding = p_region.size.y / 4; + + Rect2 bookmark_region = p_region; + bookmark_region.position += Point2(horizontal_padding, 0); + bookmark_region.size -= Point2(horizontal_padding * 1.1, vertical_padding); + bookmark_icon->draw_rect(get_canvas_item(), bookmark_region, false, bookmark_color); + } + + if (draw_executing_lines && is_line_executing(p_line)) { + int horizontal_padding = p_region.size.x / 10; + int vertical_padding = p_region.size.y / 4; + + Rect2 executing_line_region = p_region; + executing_line_region.position += Point2(horizontal_padding, vertical_padding); + executing_line_region.size -= Point2(horizontal_padding, vertical_padding) * 2; + executing_line_icon->draw_rect(get_canvas_item(), executing_line_region, false, executing_line_color); + } +} + +// Breakpoints +void CodeEdit::set_line_as_breakpoint(int p_line, bool p_breakpointed) { + int mask = get_line_gutter_metadata(p_line, main_gutter); + set_line_gutter_metadata(p_line, main_gutter, p_breakpointed ? mask | MAIN_GUTTER_BREAKPOINT : mask & ~MAIN_GUTTER_BREAKPOINT); + if (p_breakpointed) { + breakpointed_lines[p_line] = true; + } else if (breakpointed_lines.has(p_line)) { + breakpointed_lines.erase(p_line); + } + emit_signal("breakpoint_toggled", p_line); + update(); +} + +bool CodeEdit::is_line_breakpointed(int p_line) const { + return (int)get_line_gutter_metadata(p_line, main_gutter) & MAIN_GUTTER_BREAKPOINT; +} + +void CodeEdit::clear_breakpointed_lines() { + for (int i = 0; i < get_line_count(); i++) { + if (is_line_breakpointed(i)) { + set_line_as_breakpoint(i, false); + } + } +} + +Array CodeEdit::get_breakpointed_lines() const { + Array ret; + for (int i = 0; i < get_line_count(); i++) { + if (is_line_breakpointed(i)) { + ret.append(i); + } + } + return ret; +} + +// Bookmarks +void CodeEdit::set_line_as_bookmarked(int p_line, bool p_bookmarked) { + int mask = get_line_gutter_metadata(p_line, main_gutter); + set_line_gutter_metadata(p_line, main_gutter, p_bookmarked ? mask | MAIN_GUTTER_BOOKMARK : mask & ~MAIN_GUTTER_BOOKMARK); + update(); +} + +bool CodeEdit::is_line_bookmarked(int p_line) const { + return (int)get_line_gutter_metadata(p_line, main_gutter) & MAIN_GUTTER_BOOKMARK; +} + +void CodeEdit::clear_bookmarked_lines() { + for (int i = 0; i < get_line_count(); i++) { + if (is_line_bookmarked(i)) { + set_line_as_bookmarked(i, false); + } + } +} + +Array CodeEdit::get_bookmarked_lines() const { + Array ret; + for (int i = 0; i < get_line_count(); i++) { + if (is_line_bookmarked(i)) { + ret.append(i); + } + } + return ret; +} + +// executing lines +void CodeEdit::set_line_as_executing(int p_line, bool p_executing) { + int mask = get_line_gutter_metadata(p_line, main_gutter); + set_line_gutter_metadata(p_line, main_gutter, p_executing ? mask | MAIN_GUTTER_EXECUTING : mask & ~MAIN_GUTTER_EXECUTING); + update(); +} + +bool CodeEdit::is_line_executing(int p_line) const { + return (int)get_line_gutter_metadata(p_line, main_gutter) & MAIN_GUTTER_EXECUTING; +} + +void CodeEdit::clear_executing_lines() { + for (int i = 0; i < get_line_count(); i++) { + if (is_line_executing(i)) { + set_line_as_executing(i, false); + } + } +} + +Array CodeEdit::get_executing_lines() const { + Array ret; + for (int i = 0; i < get_line_count(); i++) { + if (is_line_executing(i)) { + ret.append(i); + } + } + return ret; +} + +/* Line numbers */ +void CodeEdit::set_draw_line_numbers(bool p_draw) { + set_gutter_draw(line_number_gutter, p_draw); +} + +bool CodeEdit::is_draw_line_numbers_enabled() const { + return is_gutter_drawn(line_number_gutter); +} + +void CodeEdit::set_line_numbers_zero_padded(bool p_zero_padded) { + p_zero_padded ? line_number_padding = "0" : line_number_padding = " "; + update(); +} + +bool CodeEdit::is_line_numbers_zero_padded() const { + return line_number_padding == "0"; +} + +void CodeEdit::_line_number_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) { + String fc = String::num(p_line + 1).lpad(line_number_digits, line_number_padding); + + int yofs = p_region.position.y + (cache.row_height - cache.font->get_height()) / 2; + Color number_color = get_line_gutter_item_color(p_line, line_number_gutter); + if (number_color == Color(1, 1, 1)) { + number_color = line_number_color; + } + cache.font->draw(get_canvas_item(), Point2(p_region.position.x, yofs + cache.font->get_ascent()), fc, number_color); +} + +/* Fold Gutter */ +void CodeEdit::set_draw_fold_gutter(bool p_draw) { + set_gutter_draw(fold_gutter, p_draw); +} + +bool CodeEdit::is_drawing_fold_gutter() const { + return is_gutter_drawn(fold_gutter); +} + +void CodeEdit::_fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_region) { + if (!can_fold(p_line) && !is_folded(p_line)) { + set_line_gutter_clickable(p_line, fold_gutter, false); + return; + } + set_line_gutter_clickable(p_line, fold_gutter, true); + + int horizontal_padding = p_region.size.x / 10; + int vertical_padding = p_region.size.y / 6; + + p_region.position += Point2(horizontal_padding, vertical_padding); + p_region.size -= Point2(horizontal_padding, vertical_padding) * 2; + + if (can_fold(p_line)) { + can_fold_icon->draw_rect(get_canvas_item(), p_region, false, folding_color); + return; + } + folded_icon->draw_rect(get_canvas_item(), p_region, false, folding_color); +} + +void CodeEdit::_bind_methods() { + /* Main Gutter */ + ClassDB::bind_method(D_METHOD("_main_gutter_draw_callback"), &CodeEdit::_main_gutter_draw_callback); + + ClassDB::bind_method(D_METHOD("set_draw_breakpoints_gutter", "enable"), &CodeEdit::set_draw_breakpoints_gutter); + ClassDB::bind_method(D_METHOD("is_drawing_breakpoints_gutter"), &CodeEdit::is_drawing_breakpoints_gutter); + + ClassDB::bind_method(D_METHOD("set_draw_bookmarks_gutter", "enable"), &CodeEdit::set_draw_bookmarks_gutter); + ClassDB::bind_method(D_METHOD("is_drawing_bookmarks_gutter"), &CodeEdit::is_drawing_bookmarks_gutter); + + ClassDB::bind_method(D_METHOD("set_draw_executing_lines_gutter", "enable"), &CodeEdit::set_draw_executing_lines_gutter); + ClassDB::bind_method(D_METHOD("is_drawing_executing_lines_gutter"), &CodeEdit::is_drawing_executing_lines_gutter); + + // Breakpoints + ClassDB::bind_method(D_METHOD("set_line_as_breakpoint", "line", "breakpointed"), &CodeEdit::set_line_as_breakpoint); + ClassDB::bind_method(D_METHOD("is_line_breakpointed", "line"), &CodeEdit::is_line_breakpointed); + ClassDB::bind_method(D_METHOD("clear_breakpointed_lines"), &CodeEdit::clear_breakpointed_lines); + ClassDB::bind_method(D_METHOD("get_breakpointed_lines"), &CodeEdit::get_breakpointed_lines); + + // Bookmarks + ClassDB::bind_method(D_METHOD("set_line_as_bookmarked", "line", "bookmarked"), &CodeEdit::set_line_as_bookmarked); + ClassDB::bind_method(D_METHOD("is_line_bookmarked", "line"), &CodeEdit::is_line_bookmarked); + ClassDB::bind_method(D_METHOD("clear_bookmarked_lines"), &CodeEdit::clear_bookmarked_lines); + ClassDB::bind_method(D_METHOD("get_bookmarked_lines"), &CodeEdit::get_bookmarked_lines); + + // executing lines + ClassDB::bind_method(D_METHOD("set_line_as_executing", "line", "executing"), &CodeEdit::set_line_as_executing); + ClassDB::bind_method(D_METHOD("is_line_executing", "line"), &CodeEdit::is_line_executing); + ClassDB::bind_method(D_METHOD("clear_executing_lines"), &CodeEdit::clear_executing_lines); + ClassDB::bind_method(D_METHOD("get_executing_lines"), &CodeEdit::get_executing_lines); + + /* Line numbers */ + ClassDB::bind_method(D_METHOD("_line_number_draw_callback"), &CodeEdit::_line_number_draw_callback); + + ClassDB::bind_method(D_METHOD("set_draw_line_numbers", "enable"), &CodeEdit::set_draw_line_numbers); + ClassDB::bind_method(D_METHOD("is_draw_line_numbers_enabled"), &CodeEdit::is_draw_line_numbers_enabled); + ClassDB::bind_method(D_METHOD("set_line_numbers_zero_padded", "enable"), &CodeEdit::set_line_numbers_zero_padded); + ClassDB::bind_method(D_METHOD("is_line_numbers_zero_padded"), &CodeEdit::is_line_numbers_zero_padded); + + /* Fold Gutter */ + ClassDB::bind_method(D_METHOD("_fold_gutter_draw_callback"), &CodeEdit::_fold_gutter_draw_callback); + + ClassDB::bind_method(D_METHOD("set_draw_fold_gutter", "enable"), &CodeEdit::set_draw_fold_gutter); + ClassDB::bind_method(D_METHOD("is_drawing_fold_gutter"), &CodeEdit::is_drawing_fold_gutter); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_breakpoints_gutter"), "set_draw_breakpoints_gutter", "is_drawing_breakpoints_gutter"); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_bookmarks"), "set_draw_bookmarks_gutter", "is_drawing_bookmarks_gutter"); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_executing_lines"), "set_draw_executing_lines_gutter", "is_drawing_executing_lines_gutter"); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_line_numbers"), "set_draw_line_numbers", "is_draw_line_numbers_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "zero_pad_line_numbers"), "set_line_numbers_zero_padded", "is_line_numbers_zero_padded"); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_fold_gutter"), "set_draw_fold_gutter", "is_drawing_fold_gutter"); + + ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::INT, "line"))); +} + +void CodeEdit::_gutter_clicked(int p_line, int p_gutter) { + if (p_gutter == main_gutter) { + if (draw_breakpoints) { + set_line_as_breakpoint(p_line, !is_line_breakpointed(p_line)); + } + return; + } + + if (p_gutter == line_number_gutter) { + set_selection_mode(TextEdit::SelectionMode::SELECTION_MODE_LINE, p_line, 0); + select(p_line, 0, p_line + 1, 0); + cursor_set_line(p_line + 1); + cursor_set_column(0); + return; + } + + if (p_gutter == fold_gutter) { + if (is_folded(p_line)) { + unfold_line(p_line); + } else if (can_fold(p_line)) { + fold_line(p_line); + } + return; + } +} + +void CodeEdit::_lines_edited_from(int p_from_line, int p_to_line) { + if (p_from_line == p_to_line) { + return; + } + + int lc = get_line_count(); + line_number_digits = 1; + while (lc /= 10) { + line_number_digits++; + } + set_gutter_width(line_number_gutter, (line_number_digits + 1) * cache.font->get_char_size('0').width); + + int from_line = MIN(p_from_line, p_to_line); + int line_count = (p_to_line - p_from_line); + List<int> breakpoints; + breakpointed_lines.get_key_list(&breakpoints); + for (const List<int>::Element *E = breakpoints.front(); E; E = E->next()) { + int line = E->get(); + if (line <= from_line) { + continue; + } + breakpointed_lines.erase(line); + + emit_signal("breakpoint_toggled", line); + if (line_count > 0 || line >= p_from_line) { + emit_signal("breakpoint_toggled", line + line_count); + breakpointed_lines[line + line_count] = true; + continue; + } + } +} + +void CodeEdit::_update_gutter_indexes() { + for (int i = 0; i < get_gutter_count(); i++) { + if (get_gutter_name(i) == "main_gutter") { + main_gutter = i; + continue; + } + + if (get_gutter_name(i) == "line_numbers") { + line_number_gutter = i; + continue; + } + + if (get_gutter_name(i) == "fold_gutter") { + fold_gutter = i; + continue; + } + } +} + +CodeEdit::CodeEdit() { + /* Gutters */ + int gutter_idx = 0; + + /* Main Gutter */ + add_gutter(); + set_gutter_name(gutter_idx, "main_gutter"); + set_gutter_draw(gutter_idx, false); + set_gutter_overwritable(gutter_idx, true); + set_gutter_type(gutter_idx, GUTTER_TPYE_CUSTOM); + set_gutter_custom_draw(gutter_idx, this, "_main_gutter_draw_callback"); + gutter_idx++; + + /* Line numbers */ + add_gutter(); + set_gutter_name(gutter_idx, "line_numbers"); + set_gutter_draw(gutter_idx, false); + set_gutter_type(gutter_idx, GUTTER_TPYE_CUSTOM); + set_gutter_custom_draw(gutter_idx, this, "_line_number_draw_callback"); + gutter_idx++; + + /* Fold Gutter */ + add_gutter(); + set_gutter_name(gutter_idx, "fold_gutter"); + set_gutter_draw(gutter_idx, false); + set_gutter_type(gutter_idx, GUTTER_TPYE_CUSTOM); + set_gutter_custom_draw(gutter_idx, this, "_fold_gutter_draw_callback"); + gutter_idx++; + + connect("lines_edited_from", callable_mp(this, &CodeEdit::_lines_edited_from)); + connect("gutter_clicked", callable_mp(this, &CodeEdit::_gutter_clicked)); + + connect("gutter_added", callable_mp(this, &CodeEdit::_update_gutter_indexes)); + connect("gutter_removed", callable_mp(this, &CodeEdit::_update_gutter_indexes)); + _update_gutter_indexes(); +} + +CodeEdit::~CodeEdit() { +} diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h new file mode 100644 index 0000000000..c989e5ed79 --- /dev/null +++ b/scene/gui/code_edit.h @@ -0,0 +1,135 @@ +/*************************************************************************/ +/* code_edit.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CODEEDIT_H +#define CODEEDIT_H + +#include "scene/gui/text_edit.h" + +class CodeEdit : public TextEdit { + GDCLASS(CodeEdit, TextEdit) + +private: + /* Main Gutter */ + enum MainGutterType { + MAIN_GUTTER_BREAKPOINT = 0x01, + MAIN_GUTTER_BOOKMARK = 0x02, + MAIN_GUTTER_EXECUTING = 0x04 + }; + + int main_gutter = -1; + void _update_draw_main_gutter(); + void _main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region); + + // breakpoints + HashMap<int, bool> breakpointed_lines; + bool draw_breakpoints = false; + Color breakpoint_color = Color(1, 1, 1); + Ref<Texture2D> breakpoint_icon = Ref<Texture2D>(); + + // bookmarks + bool draw_bookmarks = false; + Color bookmark_color = Color(1, 1, 1); + Ref<Texture2D> bookmark_icon = Ref<Texture2D>(); + + // executing lines + bool draw_executing_lines = false; + Color executing_line_color = Color(1, 1, 1); + Ref<Texture2D> executing_line_icon = Ref<Texture2D>(); + + /* Line numbers */ + int line_number_gutter = -1; + int line_number_digits = 0; + String line_number_padding = " "; + Color line_number_color = Color(1, 1, 1); + void _line_number_draw_callback(int p_line, int p_gutter, const Rect2 &p_region); + + /* Fold Gutter */ + int fold_gutter = -1; + bool draw_fold_gutter = false; + Color folding_color = Color(1, 1, 1); + Ref<Texture2D> can_fold_icon = Ref<Texture2D>(); + Ref<Texture2D> folded_icon = Ref<Texture2D>(); + void _fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_region); + + void _gutter_clicked(int p_line, int p_gutter); + void _lines_edited_from(int p_from_line, int p_to_line); + + void _update_gutter_indexes(); + +protected: + void _notification(int p_what); + + static void _bind_methods(); + +public: + /* Main Gutter */ + void set_draw_breakpoints_gutter(bool p_draw); + bool is_drawing_breakpoints_gutter() const; + + void set_draw_bookmarks_gutter(bool p_draw); + bool is_drawing_bookmarks_gutter() const; + + void set_draw_executing_lines_gutter(bool p_draw); + bool is_drawing_executing_lines_gutter() const; + + // breakpoints + void set_line_as_breakpoint(int p_line, bool p_breakpointed); + bool is_line_breakpointed(int p_line) const; + void clear_breakpointed_lines(); + Array get_breakpointed_lines() const; + + // bookmarks + void set_line_as_bookmarked(int p_line, bool p_bookmarked); + bool is_line_bookmarked(int p_line) const; + void clear_bookmarked_lines(); + Array get_bookmarked_lines() const; + + // executing lines + void set_line_as_executing(int p_line, bool p_executing); + bool is_line_executing(int p_line) const; + void clear_executing_lines(); + Array get_executing_lines() const; + + /* Line numbers */ + void set_draw_line_numbers(bool p_draw); + bool is_draw_line_numbers_enabled() const; + void set_line_numbers_zero_padded(bool p_zero_padded); + bool is_line_numbers_zero_padded() const; + + /* Fold gutter */ + void set_draw_fold_gutter(bool p_draw); + bool is_drawing_fold_gutter() const; + + CodeEdit(); + ~CodeEdit(); +}; + +#endif // CODEEDIT_H diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index fafbb298b7..f8a67d154b 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -610,7 +610,7 @@ void ColorPicker::_screen_pick_pressed() { if (!screen) { screen = memnew(Control); r->add_child(screen); - screen->set_as_toplevel(true); + screen->set_as_top_level(true); screen->set_anchors_and_margins_preset(Control::PRESET_WIDE); screen->set_default_cursor_shape(CURSOR_POINTING_HAND); screen->connect("gui_input", callable_mp(this, &ColorPicker::_screen_input)); @@ -873,6 +873,7 @@ void ColorPickerButton::_color_changed(const Color &p_color) { void ColorPickerButton::_modal_closed() { emit_signal("popup_closed"); + set_pressed(false); } void ColorPickerButton::pressed() { @@ -976,9 +977,8 @@ void ColorPickerButton::_update_picker() { popup->add_child(picker); add_child(popup); picker->connect("color_changed", callable_mp(this, &ColorPickerButton::_color_changed)); - popup->connect("modal_closed", callable_mp(this, &ColorPickerButton::_modal_closed)); popup->connect("about_to_popup", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(true)); - popup->connect("popup_hide", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(false)); + popup->connect("popup_hide", callable_mp(this, &ColorPickerButton::_modal_closed)); picker->set_pick_color(color); picker->set_edit_alpha(edit_alpha); emit_signal("picker_created"); diff --git a/scene/gui/color_rect.cpp b/scene/gui/color_rect.cpp index 627e589c02..0c38b93c60 100644 --- a/scene/gui/color_rect.cpp +++ b/scene/gui/color_rect.cpp @@ -30,12 +30,12 @@ #include "color_rect.h" -void ColorRect::set_frame_color(const Color &p_color) { +void ColorRect::set_color(const Color &p_color) { color = p_color; update(); } -Color ColorRect::get_frame_color() const { +Color ColorRect::get_color() const { return color; } @@ -46,12 +46,8 @@ void ColorRect::_notification(int p_what) { } void ColorRect::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_frame_color", "color"), &ColorRect::set_frame_color); - ClassDB::bind_method(D_METHOD("get_frame_color"), &ColorRect::get_frame_color); + ClassDB::bind_method(D_METHOD("set_color", "color"), &ColorRect::set_color); + ClassDB::bind_method(D_METHOD("get_color"), &ColorRect::get_color); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_frame_color", "get_frame_color"); -} - -ColorRect::ColorRect() { - color = Color(1, 1, 1); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); } diff --git a/scene/gui/color_rect.h b/scene/gui/color_rect.h index 3df44b9334..61d57f7cca 100644 --- a/scene/gui/color_rect.h +++ b/scene/gui/color_rect.h @@ -36,17 +36,15 @@ class ColorRect : public Control { GDCLASS(ColorRect, Control); - Color color; + Color color = Color(1, 1, 1); protected: void _notification(int p_what); static void _bind_methods(); public: - void set_frame_color(const Color &p_color); - Color get_frame_color() const; - - ColorRect(); + void set_color(const Color &p_color); + Color get_color() const; }; #endif // COLOR_RECT_H diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index a89eef6209..5643110b89 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "container.h" -#include "core/message_queue.h" +#include "core/object/message_queue.h" #include "scene/scene_string_names.h" void Container::_child_minsize_changed() { @@ -168,7 +168,7 @@ String Container::get_configuration_warning() const { String warning = Control::get_configuration_warning(); if (get_class() == "Container" && get_script().is_null()) { - if (warning != String()) { + if (!warning.empty()) { warning += "\n\n"; } warning += TTR("Container by itself serves no purpose unless a script configures its children placement behavior.\nIf you don't intend to add a script, use a plain Control node instead."); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 2cdee4641e..50d29a3a02 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -30,12 +30,12 @@ #include "control.h" +#include "core/config/project_settings.h" #include "core/math/geometry_2d.h" -#include "core/message_queue.h" +#include "core/object/message_queue.h" #include "core/os/keyboard.h" #include "core/os/os.h" -#include "core/print_string.h" -#include "core/project_settings.h" +#include "core/string/print_string.h" #include "scene/gui/label.h" #include "scene/gui/panel.h" #include "scene/main/canvas_layer.h" @@ -493,7 +493,7 @@ void Control::_notification(int p_notification) { } CanvasItem *ci = Object::cast_to<CanvasItem>(parent); - if (ci && ci->is_set_as_toplevel()) { + if (ci && ci->is_set_as_top_level()) { subwindow = true; break; } @@ -509,13 +509,13 @@ void Control::_notification(int p_notification) { } if (parent_control && !subwindow) { - //do nothing, has a parent control and not toplevel + //do nothing, has a parent control and not top_level if (data.theme.is_null() && parent_control->data.theme_owner) { data.theme_owner = parent_control->data.theme_owner; notification(NOTIFICATION_THEME_CHANGED); } } else { - //is a regular root control or toplevel + //is a regular root control or top_level data.RI = get_viewport()->_gui_add_root_control(this); } @@ -532,7 +532,7 @@ void Control::_notification(int p_notification) { if (data.parent_canvas_item) { data.parent_canvas_item->disconnect("item_rect_changed", callable_mp(this, &Control::_size_changed)); data.parent_canvas_item = nullptr; - } else if (!is_set_as_toplevel()) { + } else if (!is_set_as_top_level()) { //disconnect viewport get_viewport()->disconnect("size_changed", callable_mp(this, &Control::_size_changed)); } @@ -591,7 +591,7 @@ void Control::_notification(int p_notification) { case NOTIFICATION_VISIBILITY_CHANGED: { if (!is_visible_in_tree()) { if (get_viewport() != nullptr) { - get_viewport()->_gui_hid_control(this); + get_viewport()->_gui_hide_control(this); } //remove key focus @@ -728,13 +728,13 @@ Size2 Control::get_minimum_size() const { } template <class T> -bool Control::_find_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, T &r_ret, T (Theme::*get_func)(const StringName &, const StringName &) const, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_type) { +bool Control::_find_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, T &r_ret, T (Theme::*get_func)(const StringName &, const StringName &) const, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_node_type) { // try with custom themes Control *theme_owner = p_theme_owner; Window *theme_owner_window = p_theme_owner_window; while (theme_owner || theme_owner_window) { - StringName class_name = p_type; + StringName class_name = p_node_type; while (class_name != StringName()) { if (theme_owner && (theme_owner->data.theme.operator->()->*has_func)(p_name, class_name)) { @@ -771,13 +771,13 @@ bool Control::_find_theme_item(Control *p_theme_owner, Window *p_theme_owner_win return false; } -bool Control::_has_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_type) { +bool Control::_has_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_node_type) { // try with custom themes Control *theme_owner = p_theme_owner; Window *theme_owner_window = p_theme_owner_window; while (theme_owner || theme_owner_window) { - StringName class_name = p_type; + StringName class_name = p_node_type; while (class_name != StringName()) { if (theme_owner && (theme_owner->data.theme.operator->()->*has_func)(p_name, class_name)) { @@ -812,176 +812,176 @@ bool Control::_has_theme_item(Control *p_theme_owner, Window *p_theme_owner_wind return false; } -Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == get_class_name()) { +Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringName &p_node_type) const { + if (p_node_type == StringName() || p_node_type == get_class_name()) { const Ref<Texture2D> *tex = data.icon_override.getptr(p_name); if (tex) { return *tex; } } - StringName type = p_type ? p_type : get_class_name(); + StringName type = p_node_type ? p_node_type : get_class_name(); return get_icons(data.theme_owner, data.theme_owner_window, p_name, type); } -Ref<Texture2D> Control::get_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { +Ref<Texture2D> Control::get_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { Ref<Texture2D> icon; - if (_find_theme_item(p_theme_owner, p_theme_owner_window, icon, &Theme::get_icon, &Theme::has_icon, p_name, p_type)) { + if (_find_theme_item(p_theme_owner, p_theme_owner_window, icon, &Theme::get_icon, &Theme::has_icon, p_name, p_node_type)) { return icon; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_icon(p_name, p_type)) { - return Theme::get_project_default()->get_icon(p_name, p_type); + if (Theme::get_project_default()->has_icon(p_name, p_node_type)) { + return Theme::get_project_default()->get_icon(p_name, p_node_type); } } - return Theme::get_default()->get_icon(p_name, p_type); + return Theme::get_default()->get_icon(p_name, p_node_type); } -Ref<Shader> Control::get_theme_shader(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == get_class_name()) { +Ref<Shader> Control::get_theme_shader(const StringName &p_name, const StringName &p_node_type) const { + if (p_node_type == StringName() || p_node_type == get_class_name()) { const Ref<Shader> *sdr = data.shader_override.getptr(p_name); if (sdr) { return *sdr; } } - StringName type = p_type ? p_type : get_class_name(); + StringName type = p_node_type ? p_node_type : get_class_name(); return get_shaders(data.theme_owner, data.theme_owner_window, p_name, type); } -Ref<Shader> Control::get_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { +Ref<Shader> Control::get_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { Ref<Shader> shader; - if (_find_theme_item(p_theme_owner, p_theme_owner_window, shader, &Theme::get_shader, &Theme::has_shader, p_name, p_type)) { + if (_find_theme_item(p_theme_owner, p_theme_owner_window, shader, &Theme::get_shader, &Theme::has_shader, p_name, p_node_type)) { return shader; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_shader(p_name, p_type)) { - return Theme::get_project_default()->get_shader(p_name, p_type); + if (Theme::get_project_default()->has_shader(p_name, p_node_type)) { + return Theme::get_project_default()->get_shader(p_name, p_node_type); } } - return Theme::get_default()->get_shader(p_name, p_type); + return Theme::get_default()->get_shader(p_name, p_node_type); } -Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == get_class_name()) { +Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const StringName &p_node_type) const { + if (p_node_type == StringName() || p_node_type == get_class_name()) { const Ref<StyleBox> *style = data.style_override.getptr(p_name); if (style) { return *style; } } - StringName type = p_type ? p_type : get_class_name(); + StringName type = p_node_type ? p_node_type : get_class_name(); return get_styleboxs(data.theme_owner, data.theme_owner_window, p_name, type); } -Ref<StyleBox> Control::get_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { +Ref<StyleBox> Control::get_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { Ref<StyleBox> stylebox; - if (_find_theme_item(p_theme_owner, p_theme_owner_window, stylebox, &Theme::get_stylebox, &Theme::has_stylebox, p_name, p_type)) { + if (_find_theme_item(p_theme_owner, p_theme_owner_window, stylebox, &Theme::get_stylebox, &Theme::has_stylebox, p_name, p_node_type)) { return stylebox; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_stylebox(p_name, p_type)) { - return Theme::get_project_default()->get_stylebox(p_name, p_type); + if (Theme::get_project_default()->has_stylebox(p_name, p_node_type)) { + return Theme::get_project_default()->get_stylebox(p_name, p_node_type); } } - return Theme::get_default()->get_stylebox(p_name, p_type); + return Theme::get_default()->get_stylebox(p_name, p_node_type); } -Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == get_class_name()) { +Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_node_type) const { + if (p_node_type == StringName() || p_node_type == get_class_name()) { const Ref<Font> *font = data.font_override.getptr(p_name); if (font) { return *font; } } - StringName type = p_type ? p_type : get_class_name(); + StringName type = p_node_type ? p_node_type : get_class_name(); return get_fonts(data.theme_owner, data.theme_owner_window, p_name, type); } -Ref<Font> Control::get_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { +Ref<Font> Control::get_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { Ref<Font> font; - if (_find_theme_item(p_theme_owner, p_theme_owner_window, font, &Theme::get_font, &Theme::has_font, p_name, p_type)) { + if (_find_theme_item(p_theme_owner, p_theme_owner_window, font, &Theme::get_font, &Theme::has_font, p_name, p_node_type)) { return font; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_font(p_name, p_type)) { - return Theme::get_project_default()->get_font(p_name, p_type); + if (Theme::get_project_default()->has_font(p_name, p_node_type)) { + return Theme::get_project_default()->get_font(p_name, p_node_type); } } - return Theme::get_default()->get_font(p_name, p_type); + return Theme::get_default()->get_font(p_name, p_node_type); } -Color Control::get_theme_color(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == get_class_name()) { +Color Control::get_theme_color(const StringName &p_name, const StringName &p_node_type) const { + if (p_node_type == StringName() || p_node_type == get_class_name()) { const Color *color = data.color_override.getptr(p_name); if (color) { return *color; } } - StringName type = p_type ? p_type : get_class_name(); + StringName type = p_node_type ? p_node_type : get_class_name(); return get_colors(data.theme_owner, data.theme_owner_window, p_name, type); } -Color Control::get_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { +Color Control::get_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { Color color; - if (_find_theme_item(p_theme_owner, p_theme_owner_window, color, &Theme::get_color, &Theme::has_color, p_name, p_type)) { + if (_find_theme_item(p_theme_owner, p_theme_owner_window, color, &Theme::get_color, &Theme::has_color, p_name, p_node_type)) { return color; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_color(p_name, p_type)) { - return Theme::get_project_default()->get_color(p_name, p_type); + if (Theme::get_project_default()->has_color(p_name, p_node_type)) { + return Theme::get_project_default()->get_color(p_name, p_node_type); } } - return Theme::get_default()->get_color(p_name, p_type); + return Theme::get_default()->get_color(p_name, p_node_type); } -int Control::get_theme_constant(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == get_class_name()) { +int Control::get_theme_constant(const StringName &p_name, const StringName &p_node_type) const { + if (p_node_type == StringName() || p_node_type == get_class_name()) { const int *constant = data.constant_override.getptr(p_name); if (constant) { return *constant; } } - StringName type = p_type ? p_type : get_class_name(); + StringName type = p_node_type ? p_node_type : get_class_name(); return get_constants(data.theme_owner, data.theme_owner_window, p_name, type); } -int Control::get_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { +int Control::get_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { int constant; - if (_find_theme_item(p_theme_owner, p_theme_owner_window, constant, &Theme::get_constant, &Theme::has_constant, p_name, p_type)) { + if (_find_theme_item(p_theme_owner, p_theme_owner_window, constant, &Theme::get_constant, &Theme::has_constant, p_name, p_node_type)) { return constant; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_constant(p_name, p_type)) { - return Theme::get_project_default()->get_constant(p_name, p_type); + if (Theme::get_project_default()->has_constant(p_name, p_node_type)) { + return Theme::get_project_default()->get_constant(p_name, p_node_type); } } - return Theme::get_default()->get_constant(p_name, p_type); + return Theme::get_default()->get_constant(p_name, p_node_type); } bool Control::has_theme_icon_override(const StringName &p_name) const { @@ -1014,154 +1014,154 @@ bool Control::has_theme_constant_override(const StringName &p_name) const { return constant != nullptr; } -bool Control::has_theme_icon(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == get_class_name()) { +bool Control::has_theme_icon(const StringName &p_name, const StringName &p_node_type) const { + if (p_node_type == StringName() || p_node_type == get_class_name()) { if (has_theme_icon_override(p_name)) { return true; } } - StringName type = p_type ? p_type : get_class_name(); + StringName type = p_node_type ? p_node_type : get_class_name(); return has_icons(data.theme_owner, data.theme_owner_window, p_name, type); } -bool Control::has_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_icon, p_name, p_type)) { +bool Control::has_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { + if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_icon, p_name, p_node_type)) { return true; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_color(p_name, p_type)) { + if (Theme::get_project_default()->has_color(p_name, p_node_type)) { return true; } } - return Theme::get_default()->has_icon(p_name, p_type); + return Theme::get_default()->has_icon(p_name, p_node_type); } -bool Control::has_theme_shader(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == get_class_name()) { +bool Control::has_theme_shader(const StringName &p_name, const StringName &p_node_type) const { + if (p_node_type == StringName() || p_node_type == get_class_name()) { if (has_theme_shader_override(p_name)) { return true; } } - StringName type = p_type ? p_type : get_class_name(); + StringName type = p_node_type ? p_node_type : get_class_name(); return has_shaders(data.theme_owner, data.theme_owner_window, p_name, type); } -bool Control::has_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_shader, p_name, p_type)) { +bool Control::has_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { + if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_shader, p_name, p_node_type)) { return true; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_shader(p_name, p_type)) { + if (Theme::get_project_default()->has_shader(p_name, p_node_type)) { return true; } } - return Theme::get_default()->has_shader(p_name, p_type); + return Theme::get_default()->has_shader(p_name, p_node_type); } -bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == get_class_name()) { +bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_node_type) const { + if (p_node_type == StringName() || p_node_type == get_class_name()) { if (has_theme_stylebox_override(p_name)) { return true; } } - StringName type = p_type ? p_type : get_class_name(); + StringName type = p_node_type ? p_node_type : get_class_name(); return has_styleboxs(data.theme_owner, data.theme_owner_window, p_name, type); } -bool Control::has_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_stylebox, p_name, p_type)) { +bool Control::has_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { + if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_stylebox, p_name, p_node_type)) { return true; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_stylebox(p_name, p_type)) { + if (Theme::get_project_default()->has_stylebox(p_name, p_node_type)) { return true; } } - return Theme::get_default()->has_stylebox(p_name, p_type); + return Theme::get_default()->has_stylebox(p_name, p_node_type); } -bool Control::has_theme_font(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == get_class_name()) { +bool Control::has_theme_font(const StringName &p_name, const StringName &p_node_type) const { + if (p_node_type == StringName() || p_node_type == get_class_name()) { if (has_theme_font_override(p_name)) { return true; } } - StringName type = p_type ? p_type : get_class_name(); + StringName type = p_node_type ? p_node_type : get_class_name(); return has_fonts(data.theme_owner, data.theme_owner_window, p_name, type); } -bool Control::has_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_font, p_name, p_type)) { +bool Control::has_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { + if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_font, p_name, p_node_type)) { return true; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_font(p_name, p_type)) { + if (Theme::get_project_default()->has_font(p_name, p_node_type)) { return true; } } - return Theme::get_default()->has_font(p_name, p_type); + return Theme::get_default()->has_font(p_name, p_node_type); } -bool Control::has_theme_color(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == get_class_name()) { +bool Control::has_theme_color(const StringName &p_name, const StringName &p_node_type) const { + if (p_node_type == StringName() || p_node_type == get_class_name()) { if (has_theme_color_override(p_name)) { return true; } } - StringName type = p_type ? p_type : get_class_name(); + StringName type = p_node_type ? p_node_type : get_class_name(); return has_colors(data.theme_owner, data.theme_owner_window, p_name, type); } -bool Control::has_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_color, p_name, p_type)) { +bool Control::has_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { + if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_color, p_name, p_node_type)) { return true; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_color(p_name, p_type)) { + if (Theme::get_project_default()->has_color(p_name, p_node_type)) { return true; } } - return Theme::get_default()->has_color(p_name, p_type); + return Theme::get_default()->has_color(p_name, p_node_type); } -bool Control::has_theme_constant(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == get_class_name()) { +bool Control::has_theme_constant(const StringName &p_name, const StringName &p_node_type) const { + if (p_node_type == StringName() || p_node_type == get_class_name()) { if (has_theme_constant_override(p_name)) { return true; } } - StringName type = p_type ? p_type : get_class_name(); + StringName type = p_node_type ? p_node_type : get_class_name(); - return has_constants(data.theme_owner, data.theme_owner_window, p_name, p_type); + return has_constants(data.theme_owner, data.theme_owner_window, p_name, p_node_type); } -bool Control::has_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) { - if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_constant, p_name, p_type)) { +bool Control::has_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { + if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_constant, p_name, p_node_type)) { return true; } if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_constant(p_name, p_type)) { + if (Theme::get_project_default()->has_constant(p_name, p_node_type)) { return true; } } - return Theme::get_default()->has_constant(p_name, p_type); + return Theme::get_default()->has_constant(p_name, p_node_type); } Rect2 Control::get_parent_anchorable_rect() const { @@ -1816,7 +1816,7 @@ void Control::set_focus_mode(FocusMode p_focus_mode) { } static Control *_next_control(Control *p_from) { - if (p_from->is_set_as_toplevel()) { + if (p_from->is_set_as_top_level()) { return nullptr; // can't go above } @@ -1830,7 +1830,7 @@ static Control *_next_control(Control *p_from) { ERR_FAIL_INDEX_V(next, parent->get_child_count(), nullptr); for (int i = (next + 1); i < parent->get_child_count(); i++) { Control *c = Object::cast_to<Control>(parent->get_child(i)); - if (!c || !c->is_visible_in_tree() || c->is_set_as_toplevel()) { + if (!c || !c->is_visible_in_tree() || c->is_set_as_top_level()) { continue; } @@ -1867,7 +1867,7 @@ Control *Control::find_next_valid_focus() const { for (int i = 0; i < from->get_child_count(); i++) { Control *c = Object::cast_to<Control>(from->get_child(i)); - if (!c || !c->is_visible_in_tree() || c->is_set_as_toplevel()) { + if (!c || !c->is_visible_in_tree() || c->is_set_as_top_level()) { continue; } @@ -1879,7 +1879,7 @@ Control *Control::find_next_valid_focus() const { next_child = _next_control(from); if (!next_child) { //nothing else.. go up and find either window or subwindow next_child = const_cast<Control *>(this); - while (next_child && !next_child->is_set_as_toplevel()) { + while (next_child && !next_child->is_set_as_top_level()) { next_child = cast_to<Control>(next_child->get_parent()); } @@ -1915,7 +1915,7 @@ static Control *_prev_control(Control *p_from) { Control *child = nullptr; for (int i = p_from->get_child_count() - 1; i >= 0; i--) { Control *c = Object::cast_to<Control>(p_from->get_child(i)); - if (!c || !c->is_visible_in_tree() || c->is_set_as_toplevel()) { + if (!c || !c->is_visible_in_tree() || c->is_set_as_top_level()) { continue; } @@ -1955,7 +1955,7 @@ Control *Control::find_prev_valid_focus() const { Control *prev_child = nullptr; - if (from->is_set_as_toplevel() || !Object::cast_to<Control>(from->get_parent())) { + if (from->is_set_as_top_level() || !Object::cast_to<Control>(from->get_parent())) { //find last of the children prev_child = _prev_control(from); @@ -1964,7 +1964,7 @@ Control *Control::find_prev_valid_focus() const { for (int i = (from->get_index() - 1); i >= 0; i--) { Control *c = Object::cast_to<Control>(from->get_parent()->get_child(i)); - if (!c || !c->is_visible_in_tree() || c->is_set_as_toplevel()) { + if (!c || !c->is_visible_in_tree() || c->is_set_as_top_level()) { continue; } @@ -2023,8 +2023,8 @@ void Control::release_focus() { update(); } -bool Control::is_toplevel_control() const { - return is_inside_tree() && (!data.parent_canvas_item && !data.RI && is_set_as_toplevel()); +bool Control::is_top_level_control() const { + return is_inside_tree() && (!data.parent_canvas_item && !data.RI && is_set_as_top_level()); } void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign) { @@ -2374,7 +2374,7 @@ void Control::minimum_size_changed() { //invalidate cache upwards while (invalidate && invalidate->data.minimum_size_valid) { invalidate->data.minimum_size_valid = false; - if (invalidate->is_set_as_toplevel()) { + if (invalidate->is_set_as_top_level()) { break; // do not go further up } if (!invalidate->data.parent && get_parent()) { @@ -2499,7 +2499,7 @@ Control *Control::get_root_parent_control() const { if (c) { root = c; - if (c->data.RI || c->is_toplevel_control()) { + if (c->data.RI || c->is_top_level_control()) { break; } } @@ -2560,7 +2560,7 @@ String Control::get_configuration_warning() const { String warning = CanvasItem::get_configuration_warning(); if (data.mouse_filter == MOUSE_FILTER_IGNORE && data.tooltip != "") { - if (warning != String()) { + if (!warning.empty()) { warning += "\n\n"; } warning += TTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."); @@ -2738,7 +2738,9 @@ void Control::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data"))); BIND_VMETHOD(MethodInfo("drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data"))); - BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_make_custom_tooltip", PropertyInfo(Variant::STRING, "for_text"))); + BIND_VMETHOD(MethodInfo( + PropertyInfo(Variant::OBJECT, "control", PROPERTY_HINT_RESOURCE_TYPE, "Control"), + "_make_custom_tooltip", PropertyInfo(Variant::STRING, "for_text"))); BIND_VMETHOD(MethodInfo(Variant::BOOL, "_clips_input")); ADD_GROUP("Anchor", "anchor_"); diff --git a/scene/gui/control.h b/scene/gui/control.h index 15e10df0c6..3be839a5fb 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -32,7 +32,7 @@ #define CONTROL_H #include "core/math/transform_2d.h" -#include "core/rid.h" +#include "core/templates/rid.h" #include "scene/gui/shortcut.h" #include "scene/main/canvas_item.h" #include "scene/main/node.h" @@ -236,23 +236,23 @@ private: static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign = true); template <class T> - _FORCE_INLINE_ static bool _find_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, T &, T (Theme::*get_func)(const StringName &, const StringName &) const, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_type); + _FORCE_INLINE_ static bool _find_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, T &, T (Theme::*get_func)(const StringName &, const StringName &) const, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_node_type); - _FORCE_INLINE_ static bool _has_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_type); + _FORCE_INLINE_ static bool _has_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_node_type); - static Ref<Texture2D> get_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); - static Ref<Shader> get_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); - static Ref<StyleBox> get_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); - static Ref<Font> get_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); - static Color get_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); - static int get_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); + static Ref<Texture2D> get_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); + static Ref<Shader> get_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); + static Ref<StyleBox> get_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); + static Ref<Font> get_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); + static Color get_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); + static int get_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); - static bool has_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); - static bool has_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); - static bool has_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); - static bool has_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); - static bool has_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); - static bool has_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName()); + static bool has_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); + static bool has_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); + static bool has_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); + static bool has_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); + static bool has_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); + static bool has_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); protected: virtual void add_child_notify(Node *p_child) override; @@ -429,12 +429,12 @@ public: void add_theme_color_override(const StringName &p_name, const Color &p_color); void add_theme_constant_override(const StringName &p_name, int p_constant); - Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const; - Ref<Shader> get_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const; - Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const; - Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const; - Color get_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const; - int get_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const; + Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_node_type = StringName()) const; + Ref<Shader> get_theme_shader(const StringName &p_name, const StringName &p_node_type = StringName()) const; + Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_node_type = StringName()) const; + Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_node_type = StringName()) const; + Color get_theme_color(const StringName &p_name, const StringName &p_node_type = StringName()) const; + int get_theme_constant(const StringName &p_name, const StringName &p_node_type = StringName()) const; bool has_theme_icon_override(const StringName &p_name) const; bool has_theme_shader_override(const StringName &p_name) const; @@ -443,12 +443,12 @@ public: bool has_theme_color_override(const StringName &p_name) const; bool has_theme_constant_override(const StringName &p_name) const; - bool has_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const; - bool has_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const; - bool has_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const; - bool has_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const; - bool has_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const; - bool has_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const; + bool has_theme_icon(const StringName &p_name, const StringName &p_node_type = StringName()) const; + bool has_theme_shader(const StringName &p_name, const StringName &p_node_type = StringName()) const; + bool has_theme_stylebox(const StringName &p_name, const StringName &p_node_type = StringName()) const; + bool has_theme_font(const StringName &p_name, const StringName &p_node_type = StringName()) const; + bool has_theme_color(const StringName &p_name, const StringName &p_node_type = StringName()) const; + bool has_theme_constant(const StringName &p_name, const StringName &p_node_type = StringName()) const; /* TOOLTIP */ @@ -464,7 +464,7 @@ public: virtual Transform2D get_transform() const override; - bool is_toplevel_control() const; + bool is_top_level_control() const; Size2 get_parent_area_size() const; Rect2 get_parent_anchorable_rect() const; diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 9077bfa4ba..4f59f4a36a 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -31,8 +31,8 @@ #include "dialogs.h" #include "core/os/keyboard.h" -#include "core/print_string.h" -#include "core/translation.h" +#include "core/string/print_string.h" +#include "core/string/translation.h" #include "line_edit.h" #ifdef TOOLS_ENABLED @@ -181,7 +181,7 @@ void AcceptDialog::_update_child_rects() { continue; } - if (c == hbc || c == label || c == bg || c->is_set_as_toplevel()) { + if (c == hbc || c == label || c == bg || c->is_set_as_top_level()) { continue; } @@ -209,7 +209,7 @@ Size2 AcceptDialog::_get_contents_minimum_size() const { continue; } - if (c == hbc || c == label || c->is_set_as_toplevel()) { + if (c == hbc || c == label || c->is_set_as_top_level()) { continue; } diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 4aea2928f4..7ce4e90f28 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -31,7 +31,7 @@ #include "file_dialog.h" #include "core/os/keyboard.h" -#include "core/print_string.h" +#include "core/string/print_string.h" #include "scene/gui/label.h" FileDialog::GetIconFunc FileDialog::get_icon_func = nullptr; @@ -936,7 +936,7 @@ FileDialog::FileDialog() { filter->connect("item_selected", callable_mp(this, &FileDialog::_filter_selected)); confirm_save = memnew(ConfirmationDialog); - // confirm_save->set_as_toplevel(true); + // confirm_save->set_as_top_level(true); add_child(confirm_save); confirm_save->connect("confirmed", callable_mp(this, &FileDialog::_save_confirm_pressed)); diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp index ecd4ad17ea..53d7ead548 100644 --- a/scene/gui/gradient_edit.cpp +++ b/scene/gui/gradient_edit.cpp @@ -357,7 +357,7 @@ void GradientEdit::_notification(int p_what) { //Draw point markers for (int i = 0; i < points.size(); i++) { - Color col = points[i].color.contrasted(); + Color col = points[i].color.inverted(); col.a = 0.9; draw_line(Vector2(points[i].offset * total_w, 0), Vector2(points[i].offset * total_w, h / 2), col); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 11b4c9e857..ad02aaade5 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -262,6 +262,7 @@ void GraphEdit::remove_child_notify(Node *p_child) { if (gn) { gn->disconnect("offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved)); gn->disconnect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised)); + gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update)); } } @@ -546,7 +547,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { } bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &pos) { - if (p_control->is_set_as_toplevel() || !p_control->is_visible()) { + if (p_control->is_set_as_top_level() || !p_control->is_visible()) { return false; } @@ -774,6 +775,11 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { } if (mm.is_valid() && dragging) { + if (!moving_selection) { + emit_signal("begin_node_move"); + moving_selection = true; + } + just_selected = true; drag_accum += mm->get_relative(); for (int i = get_child_count() - 1; i >= 0; i--) { @@ -880,16 +886,17 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { } if (drag_accum != Vector2()) { - emit_signal("_begin_node_move"); - for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); if (gn && gn->is_selected()) { gn->set_drag(false); } } + } - emit_signal("_end_node_move"); + if (moving_selection) { + emit_signal("end_node_move"); + moving_selection = false; } dragging = false; @@ -1280,8 +1287,8 @@ void GraphEdit::_bind_methods() { ADD_SIGNAL(MethodInfo("connection_to_empty", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::VECTOR2, "release_position"))); ADD_SIGNAL(MethodInfo("connection_from_empty", PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot"), PropertyInfo(Variant::VECTOR2, "release_position"))); ADD_SIGNAL(MethodInfo("delete_nodes_request")); - ADD_SIGNAL(MethodInfo("_begin_node_move")); - ADD_SIGNAL(MethodInfo("_end_node_move")); + ADD_SIGNAL(MethodInfo("begin_node_move")); + ADD_SIGNAL(MethodInfo("end_node_move")); ADD_SIGNAL(MethodInfo("scroll_offset_changed", PropertyInfo(Variant::VECTOR2, "ofs"))); } diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index 37cb5989e9..d87bd41f27 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -98,6 +98,7 @@ private: bool dragging; bool just_selected; + bool moving_selection; Vector2 drag_accum; float zoom; diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 01b54ddaa8..4454e87017 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -30,8 +30,6 @@ #include "graph_node.h" -#include "core/method_bind_ext.gen.inc" - bool GraphNode::_set(const StringName &p_name, const Variant &p_value) { if (!p_name.operator String().begins_with("slot/")) { return false; @@ -102,7 +100,7 @@ void GraphNode::_get_property_list(List<PropertyInfo> *p_list) const { int idx = 0; for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); - if (!c || c->is_set_as_toplevel()) { + if (!c || c->is_set_as_top_level()) { continue; } @@ -131,7 +129,7 @@ void GraphNode::_resort() { if (!c) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } @@ -156,7 +154,7 @@ void GraphNode::_resort() { if (!c) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } @@ -388,7 +386,7 @@ Size2 GraphNode::get_minimum_size() const { if (!c) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } @@ -477,7 +475,7 @@ void GraphNode::_connpos_update() { if (!c) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 54150d130d..6708b18e0a 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "item_list.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" void ItemList::add_item(const String &p_item, const Ref<Texture2D> &p_texture, bool p_selectable) { Item item; diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index f49acc1b96..9df63a3c71 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -30,9 +30,9 @@ #include "label.h" -#include "core/print_string.h" -#include "core/project_settings.h" -#include "core/translation.h" +#include "core/config/project_settings.h" +#include "core/string/print_string.h" +#include "core/string/translation.h" void Label::set_autowrap(bool p_autowrap) { if (autowrap == p_autowrap) { @@ -188,7 +188,7 @@ void Label::_notification(int p_what) { int spaces = 0; while (to && to->char_pos >= 0) { taken += to->pixel_width; - if (to != from && to->space_count) { + if (to->space_count) { spaces += to->space_count; } to = to->next; @@ -235,8 +235,8 @@ void Label::_notification(int p_what) { float x_ofs_shadow = x_ofs; for (int i = 0; i < from->word_len; i++) { if (visible_chars < 0 || chars_total_shadow < visible_chars) { - CharType c = xl_text[i + pos]; - CharType n = xl_text[i + pos + 1]; + char32_t c = xl_text[i + pos]; + char32_t n = xl_text[i + pos + 1]; if (uppercase) { c = String::char_uppercase(c); n = String::char_uppercase(n); @@ -255,8 +255,8 @@ void Label::_notification(int p_what) { } for (int i = 0; i < from->word_len; i++) { if (visible_chars < 0 || chars_total < visible_chars) { - CharType c = xl_text[i + pos]; - CharType n = xl_text[i + pos + 1]; + char32_t c = xl_text[i + pos]; + char32_t n = xl_text[i + pos + 1]; if (uppercase) { c = String::char_uppercase(c); n = String::char_uppercase(n); @@ -308,7 +308,7 @@ int Label::get_longest_line_width() const { real_t line_width = 0; for (int i = 0; i < xl_text.size(); i++) { - CharType current = xl_text[i]; + char32_t current = xl_text[i]; if (uppercase) { current = String::char_uppercase(current); } @@ -390,7 +390,7 @@ void Label::regenerate_word_cache() { WordCache *last = nullptr; for (int i = 0; i <= xl_text.length(); i++) { - CharType current = i < xl_text.length() ? xl_text[i] : L' '; //always a space at the end, so the algo works + char32_t current = i < xl_text.length() ? xl_text[i] : L' '; //always a space at the end, so the algo works if (uppercase) { current = String::char_uppercase(current); @@ -420,6 +420,22 @@ void Label::regenerate_word_cache() { wc->space_count = space_count; current_word_size = 0; space_count = 0; + } else if ((i == xl_text.length() || current == '\n') && last != nullptr && space_count != 0) { + //in case there are trailing white spaces we add a placeholder word cache with just the spaces + WordCache *wc = memnew(WordCache); + if (word_cache) { + last->next = wc; + } else { + word_cache = wc; + } + last = wc; + + wc->pixel_width = 0; + wc->char_pos = 0; + wc->word_len = 0; + wc->space_count = space_count; + current_word_size = 0; + space_count = 0; } if (current == '\n') { diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 5afc1f438e..649f5a5f66 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -30,11 +30,11 @@ #include "line_edit.h" -#include "core/message_queue.h" +#include "core/object/message_queue.h" #include "core/os/keyboard.h" #include "core/os/os.h" -#include "core/print_string.h" -#include "core/translation.h" +#include "core/string/print_string.h" +#include "core/string/translation.h" #include "label.h" #include "servers/display_server.h" #ifdef TOOLS_ENABLED @@ -42,7 +42,7 @@ #include "editor/editor_settings.h" #endif #include "scene/main/window.h" -static bool _is_text_char(CharType c) { +static bool _is_text_char(char32_t c) { return !is_symbol(c); } @@ -313,7 +313,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { DisplayServer::get_singleton()->virtual_keyboard_hide(); } - return; } break; case KEY_BACKSPACE: { @@ -578,11 +577,11 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (handled) { accept_event(); - } else if (!k->get_command()) { + } else if (!k->get_command() || (k->get_command() && k->get_alt())) { if (k->get_unicode() >= 32 && k->get_keycode() != KEY_DELETE) { if (editable) { selection_delete(); - CharType ucodestr[2] = { (CharType)k->get_unicode(), 0 }; + char32_t ucodestr[2] = { (char32_t)k->get_unicode(), 0 }; int prev_len = text.length(); append_at_cursor(ucodestr); if (text.length() != prev_len) { @@ -680,7 +679,7 @@ void LineEdit::_notification(int p_what) { } break; #endif case NOTIFICATION_RESIZED: { - window_pos = 0; + scroll_offset = 0; set_cursor_position(get_cursor_position()); } break; @@ -736,7 +735,7 @@ void LineEdit::_notification(int p_what) { x_ofs = style->get_offset().x; } break; case ALIGN_CENTER: { - if (window_pos != 0) { + if (scroll_offset != 0) { x_ofs = style->get_offset().x; } else { x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - (cached_text_width)) / 2); @@ -748,7 +747,7 @@ void LineEdit::_notification(int p_what) { } int ofs_max = width - style->get_margin(MARGIN_RIGHT); - int char_ofs = window_pos; + int char_ofs = scroll_offset; int y_area = height - style->get_minimum_size().height; int y_ofs = style->get_offset().y + (y_area - font->get_height()) / 2; @@ -781,7 +780,7 @@ void LineEdit::_notification(int p_what) { r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon); if (align == ALIGN_CENTER) { - if (window_pos == 0) { + if (scroll_offset == 0) { x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - cached_text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2); } } else { @@ -807,8 +806,8 @@ void LineEdit::_notification(int p_what) { break; } - CharType cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs]; - CharType next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1]; + char32_t cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs]; + char32_t next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1]; int im_char_width = font->get_char_size(cchar, next).width; if ((x_ofs + im_char_width) > ofs_max) { @@ -830,8 +829,8 @@ void LineEdit::_notification(int p_what) { } } - CharType cchar = (pass && !text.empty()) ? secret_character[0] : t[char_ofs]; - CharType next = (pass && !text.empty()) ? secret_character[0] : t[char_ofs + 1]; + char32_t cchar = (pass && !text.empty()) ? secret_character[0] : t[char_ofs]; + char32_t next = (pass && !text.empty()) ? secret_character[0] : t[char_ofs + 1]; int char_width = font->get_char_size(cchar, next).width; // End of widget, break. @@ -870,8 +869,8 @@ void LineEdit::_notification(int p_what) { break; } - CharType cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs]; - CharType next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1]; + char32_t cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs]; + char32_t next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1]; int im_char_width = font->get_char_size(cchar, next).width; if ((x_ofs + im_char_width) > ofs_max) { @@ -1024,7 +1023,7 @@ void LineEdit::undo() { TextOperation op = undo_stack_pos->get(); text = op.text; cached_width = op.cached_width; - window_pos = op.window_pos; + scroll_offset = op.scroll_offset; set_cursor_position(op.cursor_pos); if (expand_to_text_length) { @@ -1045,7 +1044,7 @@ void LineEdit::redo() { TextOperation op = undo_stack_pos->get(); text = op.text; cached_width = op.cached_width; - window_pos = op.window_pos; + scroll_offset = op.scroll_offset; set_cursor_position(op.cursor_pos); if (expand_to_text_length) { @@ -1072,7 +1071,7 @@ void LineEdit::shift_selection_check_post(bool p_shift) { void LineEdit::set_cursor_at_pixel_pos(int p_x) { Ref<Font> font = get_theme_font("font"); - int ofs = window_pos; + int ofs = scroll_offset; Ref<StyleBox> style = get_theme_stylebox("normal"); int pixel_ofs = 0; Size2 size = get_size(); @@ -1085,7 +1084,7 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) { pixel_ofs = int(style->get_offset().x); } break; case ALIGN_CENTER: { - if (window_pos != 0) { + if (scroll_offset != 0) { pixel_ofs = int(style->get_offset().x); } else { pixel_ofs = int(size.width - (cached_width)) / 2; @@ -1123,7 +1122,7 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) { int LineEdit::get_cursor_pixel_pos() { Ref<Font> font = get_theme_font("font"); - int ofs = window_pos; + int ofs = scroll_offset; Ref<StyleBox> style = get_theme_stylebox("normal"); int pixel_ofs = 0; Size2 size = get_size(); @@ -1136,7 +1135,7 @@ int LineEdit::get_cursor_pixel_pos() { pixel_ofs = int(style->get_offset().x); } break; case ALIGN_CENTER: { - if (window_pos != 0) { + if (scroll_offset != 0) { pixel_ofs = int(style->get_offset().x); } else { pixel_ofs = int(size.width - (cached_width)) / 2; @@ -1237,7 +1236,7 @@ void LineEdit::delete_char() { set_cursor_position(get_cursor_position() - 1); if (align == ALIGN_CENTER || align == ALIGN_RIGHT) { - window_pos = CLAMP(window_pos - 1, 0, MAX(text.length() - 1, 0)); + scroll_offset = CLAMP(scroll_offset - 1, 0, MAX(text.length() - 1, 0)); } _text_changed(); @@ -1263,12 +1262,12 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) { if (cursor_pos >= text.length()) { cursor_pos = text.length(); } - if (window_pos > cursor_pos) { - window_pos = cursor_pos; + if (scroll_offset > cursor_pos) { + scroll_offset = cursor_pos; } if (align == ALIGN_CENTER || align == ALIGN_RIGHT) { - window_pos = CLAMP(window_pos - (p_to_column - p_from_column), 0, MAX(text.length() - 1, 0)); + scroll_offset = CLAMP(scroll_offset - (p_to_column - p_from_column), 0, MAX(text.length() - 1, 0)); } if (!text_changed_dirty) { @@ -1289,7 +1288,7 @@ void LineEdit::set_text(String p_text) { update(); cursor_pos = 0; - window_pos = 0; + scroll_offset = 0; } void LineEdit::clear() { @@ -1333,16 +1332,16 @@ void LineEdit::set_cursor_position(int p_pos) { cursor_pos = p_pos; if (!is_inside_tree()) { - window_pos = cursor_pos; + scroll_offset = cursor_pos; return; } Ref<StyleBox> style = get_theme_stylebox("normal"); Ref<Font> font = get_theme_font("font"); - if (cursor_pos <= window_pos) { + if (cursor_pos <= scroll_offset) { // Adjust window if cursor goes too much to the left. - set_window_pos(MAX(0, cursor_pos - 1)); + set_scroll_offset(MAX(0, cursor_pos - 1)); } else { // Adjust window if cursor goes too much to the right. int window_width = get_size().width - style->get_minimum_size().width; @@ -1355,12 +1354,12 @@ void LineEdit::set_cursor_position(int p_pos) { if (window_width < 0) { return; } - int wp = window_pos; + int wp = scroll_offset; if (font.is_valid()) { int accum_width = 0; - for (int i = cursor_pos; i >= window_pos; i--) { + for (int i = cursor_pos; i >= scroll_offset; i--) { if (i >= text.length()) { // Do not do this, because if the cursor is at the end, its just fine that it takes no space. // accum_width = font->get_char_size(' ').width; @@ -1379,8 +1378,8 @@ void LineEdit::set_cursor_position(int p_pos) { } } - if (wp != window_pos) { - set_window_pos(wp); + if (wp != scroll_offset) { + set_scroll_offset(wp); } } update(); @@ -1390,13 +1389,17 @@ int LineEdit::get_cursor_position() const { return cursor_pos; } -void LineEdit::set_window_pos(int p_pos) { - window_pos = p_pos; - if (window_pos < 0) { - window_pos = 0; +void LineEdit::set_scroll_offset(int p_pos) { + scroll_offset = p_pos; + if (scroll_offset < 0) { + scroll_offset = 0; } } +int LineEdit::get_scroll_offset() const { + return scroll_offset; +} + void LineEdit::append_at_cursor(String p_text) { if ((max_length <= 0) || (text.length() + p_text.length() <= max_length)) { String pre = text.substr(0, cursor_pos); @@ -1414,7 +1417,7 @@ void LineEdit::clear_internal() { _clear_undo_stack(); cached_width = 0; cursor_pos = 0; - window_pos = 0; + scroll_offset = 0; undo_text = ""; text = ""; update(); @@ -1645,7 +1648,7 @@ void LineEdit::_editor_settings_changed() { void LineEdit::set_expand_to_text_length(bool p_enabled) { expand_to_text_length = p_enabled; minimum_size_changed(); - set_window_pos(0); + set_scroll_offset(0); } bool LineEdit::get_expand_to_text_length() const { @@ -1772,7 +1775,7 @@ void LineEdit::_create_undo_state() { op.text = text; op.cached_width = cached_width; op.cursor_pos = cursor_pos; - op.window_pos = window_pos; + op.scroll_offset = scroll_offset; undo_stack.push_back(op); } @@ -1817,6 +1820,7 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_placeholder_alpha"), &LineEdit::get_placeholder_alpha); ClassDB::bind_method(D_METHOD("set_cursor_position", "position"), &LineEdit::set_cursor_position); ClassDB::bind_method(D_METHOD("get_cursor_position"), &LineEdit::get_cursor_position); + ClassDB::bind_method(D_METHOD("get_scroll_offset"), &LineEdit::get_scroll_offset); ClassDB::bind_method(D_METHOD("set_expand_to_text_length", "enabled"), &LineEdit::set_expand_to_text_length); ClassDB::bind_method(D_METHOD("get_expand_to_text_length"), &LineEdit::get_expand_to_text_length); ClassDB::bind_method(D_METHOD("cursor_set_blink_enabled", "enabled"), &LineEdit::cursor_set_blink_enabled); @@ -1899,7 +1903,7 @@ LineEdit::LineEdit() { cached_width = 0; cached_placeholder_width = 0; cursor_pos = 0; - window_pos = 0; + scroll_offset = 0; window_has_focus = true; max_length = 0; pass = false; diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index d6cc1f1f11..a5e5b6988f 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -80,7 +80,7 @@ private: PopupMenu *menu; int cursor_pos; - int window_pos; + int scroll_offset; int max_length; // 0 for no maximum. int cached_width; @@ -106,7 +106,7 @@ private: struct TextOperation { int cursor_pos; - int window_pos; + int scroll_offset; int cached_width; String text; }; @@ -144,7 +144,8 @@ private: void shift_selection_check_post(bool); void selection_fill_at_cursor(); - void set_window_pos(int p_pos); + void set_scroll_offset(int p_pos); + int get_scroll_offset() const; void set_cursor_at_pixel_pos(int p_x); int get_cursor_pixel_pos(); diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index f8c8bd4caf..27a60945c8 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -127,6 +127,5 @@ void LinkButton::_bind_methods() { LinkButton::LinkButton() { underline_mode = UNDERLINE_MODE_ALWAYS; - set_enabled_focus_mode(FOCUS_NONE); set_default_cursor_shape(CURSOR_POINTING_HAND); } diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp index 0299065f77..b674b492d8 100644 --- a/scene/gui/margin_container.cpp +++ b/scene/gui/margin_container.cpp @@ -43,7 +43,7 @@ Size2 MarginContainer::get_minimum_size() const { if (!c) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } if (!c->is_visible()) { @@ -80,7 +80,7 @@ void MarginContainer::_notification(int p_what) { if (!c) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index aa69fb39e7..d65e98ea46 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -53,17 +53,9 @@ void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) { } void MenuButton::pressed() { - { - Window *w = Object::cast_to<Window>(get_viewport()); - if (w && !w->is_embedding_subwindows()) { - print_line("windowpos: " + w->get_position()); - } - } Size2 size = get_size(); Point2 gp = get_screen_position(); - - print_line("screenpos: " + gp); gp.y += get_size().y; popup->set_position(gp); @@ -130,7 +122,6 @@ MenuButton::MenuButton() { set_flat(true); set_toggle_mode(true); set_disable_shortcuts(false); - set_enabled_focus_mode(FOCUS_NONE); set_process_unhandled_key_input(true); set_action_mode(ACTION_MODE_BUTTON_PRESS); diff --git a/scene/gui/nine_patch_rect.h b/scene/gui/nine_patch_rect.h index 487fe4c860..a539ad43c0 100644 --- a/scene/gui/nine_patch_rect.h +++ b/scene/gui/nine_patch_rect.h @@ -79,4 +79,5 @@ public: }; VARIANT_ENUM_CAST(NinePatchRect::AxisStretchMode) + #endif // NINE_PATCH_RECT_H diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 5780cc5e71..f0e69a94a4 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -30,7 +30,7 @@ #include "option_button.h" -#include "core/print_string.h" +#include "core/string/print_string.h" Size2 OptionButton::get_minimum_size() const { Size2 minsize = Button::get_minimum_size(); diff --git a/scene/gui/panel.cpp b/scene/gui/panel.cpp index d8d9beca2b..acbb6d7ab5 100644 --- a/scene/gui/panel.cpp +++ b/scene/gui/panel.cpp @@ -30,7 +30,7 @@ #include "panel.h" -#include "core/print_string.h" +#include "core/string/print_string.h" void Panel::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp index 9abdfac009..051b4de825 100644 --- a/scene/gui/panel_container.cpp +++ b/scene/gui/panel_container.cpp @@ -45,7 +45,7 @@ Size2 PanelContainer::get_minimum_size() const { if (!c || !c->is_visible()) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } @@ -95,7 +95,7 @@ void PanelContainer::_notification(int p_what) { if (!c || !c->is_visible_in_tree()) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 5fc5f9b669..791c78e2b4 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -30,7 +30,7 @@ #include "popup.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "core/os/keyboard.h" #include "scene/gui/panel.h" @@ -41,62 +41,90 @@ void Popup::_input_from_window(const Ref<InputEvent> &p_event) { } } -void Popup::_parent_focused() { - _close_pressed(); +void Popup::_initialize_visible_parents() { + visible_parents.clear(); + + Window *parent_window = this; + while (parent_window) { + parent_window = parent_window->get_parent_visible_window(); + if (parent_window) { + visible_parents.push_back(parent_window); + parent_window->connect("focus_entered", callable_mp(this, &Popup::_parent_focused)); + parent_window->connect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents)); + } + } +} + +void Popup::_deinitialize_visible_parents() { + for (uint32_t i = 0; i < visible_parents.size(); ++i) { + visible_parents[i]->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused)); + visible_parents[i]->disconnect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents)); + } + + visible_parents.clear(); } void Popup::_notification(int p_what) { switch (p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { if (is_visible()) { - parent_visible = get_parent_visible_window(); - if (parent_visible) { - parent_visible->connect("focus_entered", callable_mp(this, &Popup::_parent_focused)); - } + _initialize_visible_parents(); } else { - if (parent_visible) { - parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused)); - parent_visible = nullptr; - } - + _deinitialize_visible_parents(); emit_signal("popup_hide"); } } break; - case NOTIFICATION_EXIT_TREE: { - if (parent_visible) { - parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused)); - parent_visible = nullptr; + case NOTIFICATION_WM_WINDOW_FOCUS_IN: { + if (has_focus()) { + popped_up = true; } } break; + case NOTIFICATION_EXIT_TREE: { + _deinitialize_visible_parents(); + } break; case NOTIFICATION_WM_CLOSE_REQUEST: { _close_pressed(); - + } break; + case NOTIFICATION_APPLICATION_FOCUS_OUT: { + _close_pressed(); } break; } } -void Popup::_close_pressed() { - Window *parent_window = parent_visible; - if (parent_visible) { - parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused)); - parent_visible = nullptr; +void Popup::_parent_focused() { + if (popped_up && close_on_parent_focus) { + _close_pressed(); } +} + +void Popup::_close_pressed() { + popped_up = false; + + _deinitialize_visible_parents(); call_deferred("hide"); emit_signal("cancelled"); - - if (parent_window) { - //parent_window->grab_focus(); - } } void Popup::set_as_minsize() { set_size(get_contents_minimum_size()); } +void Popup::set_close_on_parent_focus(bool p_close) { + close_on_parent_focus = p_close; +} + +bool Popup::get_close_on_parent_focus() { + return close_on_parent_focus; +} + void Popup::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_close_on_parent_focus", "close"), &Popup::set_close_on_parent_focus); + ClassDB::bind_method(D_METHOD("get_close_on_parent_focus"), &Popup::get_close_on_parent_focus); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "close_on_parent_focus"), "set_close_on_parent_focus", "get_close_on_parent_focus"); + ADD_SIGNAL(MethodInfo("popup_hide")); } @@ -126,12 +154,32 @@ Rect2i Popup::_popup_adjust_rect() const { current.position.y = parent.position.y; } + if (current.size.y > parent.size.y) { + current.size.y = parent.size.y; + } + + if (current.size.x > parent.size.x) { + current.size.x = parent.size.x; + } + + // Early out if max size not set. + Size2i max_size = get_max_size(); + if (max_size <= Size2()) { + return current; + } + + if (current.size.x > max_size.x) { + current.size.x = max_size.x; + } + + if (current.size.y > max_size.y) { + current.size.y = max_size.y; + } + return current; } Popup::Popup() { - parent_visible = nullptr; - set_wrap_controls(true); set_visible(false); set_transient(true); @@ -155,7 +203,7 @@ Size2 PopupPanel::_get_contents_minimum_size() const { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } @@ -179,7 +227,7 @@ void PopupPanel::_update_child_rects() { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } diff --git a/scene/gui/popup.h b/scene/gui/popup.h index 97c08095d3..48e7ea9452 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -33,12 +33,20 @@ #include "scene/main/window.h" +#include "core/templates/local_vector.h" + class Popup : public Window { GDCLASS(Popup, Window); - Window *parent_visible; + LocalVector<Window *> visible_parents; + bool popped_up = false; + bool close_on_parent_focus = true; void _input_from_window(const Ref<InputEvent> &p_event); + + void _initialize_visible_parents(); + void _deinitialize_visible_parents(); + void _parent_focused(); protected: @@ -50,6 +58,10 @@ protected: public: void set_as_minsize(); + + void set_close_on_parent_focus(bool p_close); + bool get_close_on_parent_focus(); + Popup(); ~Popup(); }; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 6e19b820e0..7baf32173f 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -33,9 +33,8 @@ #include "core/input/input.h" #include "core/os/keyboard.h" #include "core/os/os.h" -#include "core/print_string.h" -#include "core/translation.h" -#include "scene/gui/control.h" +#include "core/string/print_string.h" +#include "core/string/translation.h" String PopupMenu::_get_accel_text(int p_item) const { ERR_FAIL_INDEX_V(p_item, items.size(), String()); @@ -52,7 +51,8 @@ Size2 PopupMenu::_get_contents_minimum_size() const { int vseparation = get_theme_constant("vseparation"); int hseparation = get_theme_constant("hseparation"); - Size2 minsize = get_theme_stylebox("panel")->get_minimum_size(); + Size2 minsize = get_theme_stylebox("panel")->get_minimum_size(); // Accounts for margin in the margin container + minsize.x += scroll_container->get_v_scrollbar()->get_size().width * 2; // Adds a buffer so that the scrollbar does not render over the top of content Ref<Font> font = get_theme_font("font"); float max_w = 0; @@ -64,13 +64,10 @@ Size2 PopupMenu::_get_contents_minimum_size() const { for (int i = 0; i < items.size(); i++) { Size2 size; - if (!items[i].icon.is_null()) { - Size2 icon_size = items[i].icon->get_size(); - size.height = MAX(icon_size.height, font_h); - icon_w = MAX(icon_size.width + hseparation, icon_w); - } else { - size.height = font_h; - } + + Size2 icon_size = items[i].get_icon_size(); + size.height = MAX(icon_size.height, font_h); + icon_w = MAX(icon_size.width, icon_w); size.width += items[i].h_ofs; @@ -104,39 +101,71 @@ Size2 PopupMenu::_get_contents_minimum_size() const { minsize.width += check_w; } + if (is_inside_tree()) { + int height_limit = get_usable_parent_rect().size.height; + if (minsize.height > height_limit) { + minsize.height = height_limit; + } + } + return minsize; } +int PopupMenu::_get_items_total_height() const { + int font_height = get_theme_font("font")->get_height(); + int vsep = get_theme_constant("vseparation"); + + // Get total height of all items by taking max of icon height and font height + int items_total_height = 0; + for (int i = 0; i < items.size(); i++) { + items_total_height += MAX(items[i].get_icon_size().height, font_height) + vsep; + } + + // Subtract a separator which is not needed for the last item. + return items_total_height - vsep; +} + +void PopupMenu::_scroll_to_item(int p_item) { + ERR_FAIL_INDEX(p_item, items.size()); + ERR_FAIL_COND(p_item < 0); + + // Scroll item into view (upwards) + if (items[p_item]._ofs_cache < -control->get_position().y) { + int amnt_over = items[p_item]._ofs_cache + control->get_position().y; + scroll_container->set_v_scroll(scroll_container->get_v_scroll() + amnt_over); + } + + // Scroll item into view (downwards) + if (items[p_item]._ofs_cache + items[p_item]._height_cache > -control->get_position().y + scroll_container->get_size().height) { + int amnt_over = items[p_item]._ofs_cache + items[p_item]._height_cache + control->get_position().y - scroll_container->get_size().height; + scroll_container->set_v_scroll(scroll_container->get_v_scroll() + amnt_over); + } +} + int PopupMenu::_get_mouse_over(const Point2 &p_over) const { if (p_over.x < 0 || p_over.x >= get_size().width) { return -1; } - Ref<StyleBox> style = get_theme_stylebox("panel"); + Ref<StyleBox> style = get_theme_stylebox("panel"); // Accounts for margin in the margin container - Point2 ofs = style->get_offset(); + int vseparation = get_theme_constant("vseparation"); + float font_h = get_theme_font("font")->get_height(); + + Point2 ofs = style->get_offset() + Point2(0, vseparation / 2); if (ofs.y > p_over.y) { return -1; } - Ref<Font> font = get_theme_font("font"); - int vseparation = get_theme_constant("vseparation"); - float font_h = font->get_height(); - for (int i = 0; i < items.size(); i++) { - ofs.y += vseparation; - float h; - - if (!items[i].icon.is_null()) { - Size2 icon_size = items[i].icon->get_size(); - h = MAX(icon_size.height, font_h); - } else { - h = font_h; + if (i > 0) { + ofs.y += vseparation; } - ofs.y += h; - if (p_over.y < ofs.y) { + ofs.y += MAX(items[i].get_icon_size().height, font_h); + + if (p_over.y - control->get_position().y < ofs.y) { return i; } } @@ -144,46 +173,55 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const { return -1; } -void PopupMenu::_activate_submenu(int over) { - Node *n = get_node(items[over].submenu); - ERR_FAIL_COND_MSG(!n, "Item subnode does not exist: " + items[over].submenu + "."); - Popup *pm = Object::cast_to<Popup>(n); - ERR_FAIL_COND_MSG(!pm, "Item subnode is not a Popup: " + items[over].submenu + "."); - if (pm->is_visible()) { +void PopupMenu::_activate_submenu(int p_over) { + Node *n = get_node(items[p_over].submenu); + ERR_FAIL_COND_MSG(!n, "Item subnode does not exist: " + items[p_over].submenu + "."); + Popup *submenu_popup = Object::cast_to<Popup>(n); + ERR_FAIL_COND_MSG(!submenu_popup, "Item subnode is not a Popup: " + items[p_over].submenu + "."); + if (submenu_popup->is_visible()) { return; //already visible! } - Point2 p = get_position(); - Rect2 pr(p, get_size()); Ref<StyleBox> style = get_theme_stylebox("panel"); + int vsep = get_theme_constant("vseparation"); + + Point2 this_pos = get_position(); + Rect2 this_rect(this_pos, get_size()); + + float scroll_offset = control->get_position().y; - Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y); - Size2 size = pm->get_size(); - // fix pos - if (pos.x + size.width > get_parent_rect().size.width) { - pos.x = p.x - size.width; + Point2 submenu_pos = this_pos + Point2(this_rect.size.width, items[p_over]._ofs_cache + scroll_offset); + Size2 submenu_size = submenu_popup->get_size(); + + // Fix pos if going outside parent rect + if (submenu_pos.x + submenu_size.width > get_parent_rect().size.width) { + submenu_pos.x = this_pos.x - submenu_size.width; } - pm->set_position(pos); - // pm->set_scale(get_global_transform().get_scale()); - pm->popup(); - - PopupMenu *pum = Object::cast_to<PopupMenu>(pm); - if (pum) { - pr.position -= pum->get_position(); - pum->clear_autohide_areas(); - pum->add_autohide_area(Rect2(pr.position.x, pr.position.y, pr.size.x, items[over]._ofs_cache)); - if (over < items.size() - 1) { - int from = items[over + 1]._ofs_cache; - pum->add_autohide_area(Rect2(pr.position.x, pr.position.y + from, pr.size.x, pr.size.y - from)); + submenu_popup->set_close_on_parent_focus(false); + submenu_popup->set_position(submenu_pos); + submenu_popup->set_as_minsize(); // Shrink the popup size to it's contents. + submenu_popup->popup(); + + // Set autohide areas + PopupMenu *submenu_pum = Object::cast_to<PopupMenu>(submenu_popup); + if (submenu_pum) { + // Make the position of the parent popup relative to submenu popup + this_rect.position = this_rect.position - submenu_pum->get_position(); + + // Autohide area above the submenu item + submenu_pum->clear_autohide_areas(); + submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y, this_rect.size.x, items[p_over]._ofs_cache + scroll_offset + style->get_offset().height - vsep / 2)); + + // If there is an area below the submenu item, add an autohide area there. + if (items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset <= control->get_size().height) { + int from = items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset + vsep / 2 + style->get_offset().height; + submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y + from, this_rect.size.x, this_rect.size.y - from)); } } } void PopupMenu::_submenu_timeout() { - //if (!has_focus()) { - // return; //do not activate if not has focus - //} if (mouse_over == submenu_over) { _activate_submenu(mouse_over); } @@ -191,70 +229,34 @@ void PopupMenu::_submenu_timeout() { submenu_over = -1; } -void PopupMenu::_scroll(float p_factor, const Point2 &p_over) { - int vseparation = get_theme_constant("vseparation"); - Ref<Font> font = get_theme_font("font"); - - Rect2 visible_rect = get_usable_parent_rect(); - - int dy = (vseparation + font->get_height()) * 3 * p_factor; - if (dy > 0) { - const float global_top = get_position().y; - const float limit = global_top < visible_rect.position.y ? visible_rect.position.y - global_top : 0; - dy = MIN(dy, limit); - } else if (dy < 0) { - const float global_bottom = get_position().y + get_size().y; - const float viewport_height = visible_rect.position.y + visible_rect.size.y; - const float limit = global_bottom > viewport_height ? global_bottom - viewport_height : 0; - dy = -MIN(-dy, limit); - } - - if (dy == 0) { - return; - } - - set_position(get_position() + Vector2(0, dy)); - - Ref<InputEventMouseMotion> ie; - ie.instance(); - ie->set_position(p_over - Vector2(0, dy)); - _gui_input(ie); -} - void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { - if (p_event->is_action("ui_down") && p_event->is_pressed()) { + if (p_event->is_action("ui_down") && p_event->is_pressed() && mouse_over != items.size() - 1) { int search_from = mouse_over + 1; if (search_from >= items.size()) { search_from = 0; } for (int i = search_from; i < items.size(); i++) { - if (i < 0 || i >= items.size()) { - continue; - } - if (!items[i].separator && !items[i].disabled) { mouse_over = i; emit_signal("id_focused", i); + _scroll_to_item(i); control->update(); set_input_as_handled(); break; } } - } else if (p_event->is_action("ui_up") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_up") && p_event->is_pressed() && mouse_over != 0) { int search_from = mouse_over - 1; if (search_from < 0) { search_from = items.size() - 1; } for (int i = search_from; i >= 0; i--) { - if (i >= items.size()) { - continue; - } - if (!items[i].separator && !items[i].disabled) { mouse_over = i; emit_signal("id_focused", i); + _scroll_to_item(i); control->update(); set_input_as_handled(); break; @@ -282,65 +284,61 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { } } + // Make an area which does not include v scrollbar, so that items are not activated when dragging scrollbar. + Rect2 item_clickable_area = scroll_container->get_rect(); + if (scroll_container->get_v_scrollbar()->is_visible_in_tree()) { + item_clickable_area.size.width -= scroll_container->get_v_scrollbar()->get_size().width; + } + Ref<InputEventMouseButton> b = p_event; if (b.is_valid()) { - if (b->is_pressed()) { + if (!item_clickable_area.has_point(b->get_position())) { return; } int button_idx = b->get_button_index(); - switch (button_idx) { - case BUTTON_WHEEL_DOWN: { - _scroll(-b->get_factor(), b->get_position()); - } break; - case BUTTON_WHEEL_UP: { - _scroll(b->get_factor(), b->get_position()); - } break; - default: { - // Allow activating item by releasing the LMB or any that was down when the popup appeared - if (button_idx == BUTTON_LEFT || (initial_button_mask & (1 << (button_idx - 1)))) { - bool was_during_grabbed_click = during_grabbed_click; - during_grabbed_click = false; - initial_button_mask = 0; - - int over = _get_mouse_over(b->get_position()); - - if (invalidated_click) { - invalidated_click = false; - break; - } - if (over < 0) { - if (!was_during_grabbed_click) { - hide(); - } - break; //non-activable - } + if (b->is_pressed() || (!b->is_pressed() && during_grabbed_click)) { + // Allow activating item by releasing the LMB or any that was down when the popup appeared. + // However, if button was not held when opening menu, do not allow release to activate item. + if (button_idx == BUTTON_LEFT || (initial_button_mask & (1 << (button_idx - 1)))) { + bool was_during_grabbed_click = during_grabbed_click; + during_grabbed_click = false; + initial_button_mask = 0; + + // Disable clicks under a time threshold to avoid selection right when opening the popup. + uint64_t now = OS::get_singleton()->get_ticks_msec(); + uint64_t diff = now - popup_time_msec; + if (diff < 100) { + return; + } - if (items[over].separator || items[over].disabled) { - break; + int over = _get_mouse_over(b->get_position()); + if (over < 0) { + if (!was_during_grabbed_click) { + hide(); } + return; + } - if (items[over].submenu != "") { - _activate_submenu(over); - return; - } - activate_item(over); + if (items[over].separator || items[over].disabled) { + return; + } + + if (items[over].submenu != "") { + _activate_submenu(over); + return; } + activate_item(over); } } - - //control->update(); } Ref<InputEventMouseMotion> m = p_event; if (m.is_valid()) { - if (invalidated_click) { - moved += m->get_relative(); - if (moved.length() > 4) { - invalidated_click = false; - } + if (!item_clickable_area.has_point(m->get_position())) { + return; } for (List<Rect2>::Element *E = autohide_areas.front(); E; E = E->next()) { @@ -370,11 +368,6 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { } } - Ref<InputEventPanGesture> pan_gesture = p_event; - if (pan_gesture.is_valid()) { - _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position()); - } - Ref<InputEventKey> k = p_event; if (allow_search && k.is_valid() && k->get_unicode() && k->is_pressed()) { @@ -407,6 +400,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { if (items[i].text.findn(search_string) == 0) { mouse_over = i; emit_signal("id_focused", i); + _scroll_to_item(i); control->update(); set_input_as_handled(); break; @@ -415,9 +409,13 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { } } -void PopupMenu::_draw() { +void PopupMenu::_draw_items() { + control->set_custom_minimum_size(Size2(0, _get_items_total_height())); RID ci = control->get_canvas_item(); - Size2 size = get_size(); + + Size2 margin_size; + margin_size.width = margin_container->get_theme_constant("margin_right") + margin_container->get_theme_constant("margin_left"); + margin_size.height = margin_container->get_theme_constant("margin_top") + margin_container->get_theme_constant("margin_bottom"); Ref<StyleBox> style = get_theme_stylebox("panel"); Ref<StyleBox> hover = get_theme_stylebox("hover"); @@ -430,8 +428,6 @@ void PopupMenu::_draw() { Ref<StyleBox> labeled_separator_left = get_theme_stylebox("labeled_separator_left"); Ref<StyleBox> labeled_separator_right = get_theme_stylebox("labeled_separator_right"); - style->draw(ci, Rect2(Point2(), get_size())); - Point2 ofs = style->get_offset(); int vseparation = get_theme_constant("vseparation"); int hseparation = get_theme_constant("hseparation"); Color font_color = get_theme_color("font_color"); @@ -440,13 +436,14 @@ void PopupMenu::_draw() { Color font_color_hover = get_theme_color("font_color_hover"); float font_h = font->get_height(); - // Add the check and the wider icon to the offset of all items. + float scroll_width = scroll_container->get_v_scrollbar()->is_visible_in_tree() ? scroll_container->get_v_scrollbar()->get_size().width : 0; + float display_width = control->get_size().width - scroll_width; + + // Find the widest icon and whether any items have a checkbox, and store the offsets for each. float icon_ofs = 0.0; bool has_check = false; for (int i = 0; i < items.size(); i++) { - if (!items[i].icon.is_null()) { - icon_ofs = MAX(items[i].icon->get_size().width, icon_ofs); - } + icon_ofs = MAX(items[i].get_icon_size().width, icon_ofs); if (items[i].checkable_type) { has_check = true; @@ -461,65 +458,68 @@ void PopupMenu::_draw() { check_ofs = MAX(get_theme_icon("checked")->get_width(), get_theme_icon("radio_checked")->get_width()) + hseparation; } + Point2 ofs = Point2(); + + // Loop through all items and draw each. for (int i = 0; i < items.size(); i++) { + // If not the first item, add the separation space between items. if (i > 0) { ofs.y += vseparation; } - Point2 item_ofs = ofs; - Size2 icon_size; - float h; - if (!items[i].icon.is_null()) { - icon_size = items[i].icon->get_size(); - h = MAX(icon_size.height, font_h); - } else { - h = font_h; - } + Point2 item_ofs = ofs; + Size2 icon_size = items[i].get_icon_size(); + float h = MAX(icon_size.height, font_h); if (i == mouse_over) { - hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation))); + hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(display_width + hseparation * 2, h + vseparation))); } String text = items[i].xl_text; + // Separator item_ofs.x += items[i].h_ofs; if (items[i].separator) { int sep_h = separator->get_center_size().height + separator->get_minimum_size().height; if (text != String()) { - int ss = font->get_string_size(text).width; - int center = (get_size().width) / 2; - int l = center - ss / 2; - int r = center + ss / 2; - if (l > item_ofs.x) { - labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, l - item_ofs.x), sep_h))); + int text_size = font->get_string_size(text).width; + int text_center = display_width / 2; + int text_left = text_center - text_size / 2; + int text_right = text_center + text_size / 2; + if (text_left > item_ofs.x) { + labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, text_left - item_ofs.x), sep_h))); } - if (r < get_size().width - style->get_margin(MARGIN_RIGHT)) { - labeled_separator_right->draw(ci, Rect2(Point2(r, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, get_size().width - style->get_margin(MARGIN_RIGHT) - r), sep_h))); + if (text_right < display_width) { + labeled_separator_right->draw(ci, Rect2(Point2(text_right, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, display_width - text_right), sep_h))); } } else { - separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(get_size().width - style->get_minimum_size().width, sep_h))); + separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(display_width, sep_h))); } } Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1); + // Checkboxes if (items[i].checkable_type) { Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr(); icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon->get_height()) / 2.0)), icon_color); } + // Icon if (!items[i].icon.is_null()) { items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color); } + // Submenu arrow on right hand side if (items[i].submenu != "") { - submenu->draw(ci, Point2(size.width - style->get_margin(MARGIN_RIGHT) - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color); + submenu->draw(ci, Point2(display_width - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color); } + // Text item_ofs.y += font->get_ascent(); if (items[i].separator) { if (text != String()) { - int center = (get_size().width - font->get_string_size(text).width) / 2; + int center = (display_width - font->get_string_size(text).width) / 2; font->draw(ci, Point2(center, item_ofs.y + Math::floor((h - font_h) / 2.0)), text, font_color_disabled); } } else { @@ -527,19 +527,52 @@ void PopupMenu::_draw() { font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, items[i].disabled ? font_color_disabled : (i == mouse_over ? font_color_hover : font_color)); } + // Accelerator / Shortcut if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) { - //accelerator - String text2 = _get_accel_text(i); - item_ofs.x = size.width - style->get_margin(MARGIN_RIGHT) - font->get_string_size(text2).width; - font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text2, i == mouse_over ? font_color_hover : font_color_accel); + String sc_text = _get_accel_text(i); + item_ofs.x = display_width - font->get_string_size(sc_text).width; + font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), sc_text, i == mouse_over ? font_color_hover : font_color_accel); } + // Cache the item vertical offset from the first item and the height items.write[i]._ofs_cache = ofs.y; + items.write[i]._height_cache = h; ofs.y += h; } } +void PopupMenu::_draw_background() { + Ref<StyleBox> style = get_theme_stylebox("panel"); + RID ci2 = margin_container->get_canvas_item(); + style->draw(ci2, Rect2(Point2(), margin_container->get_size())); +} + +void PopupMenu::_minimum_lifetime_timeout() { + close_allowed = true; + // If the mouse still isn't in this popup after timer expires, close. + if (!get_visible_rect().has_point(get_mouse_position())) { + _close_pressed(); + } +} + +void PopupMenu::_close_pressed() { + // Only apply minimum lifetime to submenus. + PopupMenu *parent_pum = Object::cast_to<PopupMenu>(get_parent()); + if (!parent_pum) { + Popup::_close_pressed(); + return; + } + + // If the timer has expired, close. If timer is still running, do nothing. + if (close_allowed) { + close_allowed = false; + Popup::_close_pressed(); + } else if (minimum_lifetime_timer->is_stopped()) { + minimum_lifetime_timer->start(); + } +} + void PopupMenu::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -559,7 +592,7 @@ void PopupMenu::_notification(int p_what) { control->update(); } break; case NOTIFICATION_WM_MOUSE_ENTER: { - //grab_focus(); + grab_focus(); } break; case NOTIFICATION_WM_MOUSE_EXIT: { if (mouse_over >= 0 && (items[mouse_over].submenu == "" || submenu_over != -1)) { @@ -617,6 +650,13 @@ void PopupMenu::_notification(int p_what) { if (get_window_id() != DisplayServer::INVALID_WINDOW_ID) { set_process_internal(true); } + + // Set margin on the margin container + Ref<StyleBox> panel_style = get_theme_stylebox("panel"); + margin_container->add_theme_constant_override("margin_top", panel_style->get_margin(Margin::MARGIN_TOP)); + margin_container->add_theme_constant_override("margin_bottom", panel_style->get_margin(Margin::MARGIN_BOTTOM)); + margin_container->add_theme_constant_override("margin_left", panel_style->get_margin(Margin::MARGIN_LEFT)); + margin_container->add_theme_constant_override("margin_right", panel_style->get_margin(Margin::MARGIN_RIGHT)); } } break; } @@ -698,7 +738,7 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int } #define ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global) \ - ERR_FAIL_COND_MSG(p_shortcut.is_null(), "Cannot add item with invalid ShortCut."); \ + ERR_FAIL_COND_MSG(p_shortcut.is_null(), "Cannot add item with invalid Shortcut."); \ _ref_shortcut(p_shortcut); \ item.text = p_shortcut->get_name(); \ item.xl_text = tr(item.text); \ @@ -706,7 +746,7 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int item.shortcut = p_shortcut; \ item.shortcut_is_global = p_global; -void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { +void PopupMenu::add_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) { Item item; ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); items.push_back(item); @@ -714,7 +754,7 @@ void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_g child_controls_changed(); } -void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { +void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) { Item item; ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); item.icon = p_icon; @@ -723,7 +763,7 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortC child_controls_changed(); } -void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { +void PopupMenu::add_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) { Item item; ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; @@ -732,7 +772,7 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bo child_controls_changed(); } -void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { +void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) { Item item; ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); item.icon = p_icon; @@ -742,7 +782,7 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref< child_controls_changed(); } -void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { +void PopupMenu::add_radio_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) { Item item; ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; @@ -751,7 +791,7 @@ void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ child_controls_changed(); } -void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { +void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) { Item item; ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); item.icon = p_icon; @@ -912,8 +952,8 @@ String PopupMenu::get_item_tooltip(int p_idx) const { return items[p_idx].tooltip; } -Ref<ShortCut> PopupMenu::get_item_shortcut(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, items.size(), Ref<ShortCut>()); +Ref<Shortcut> PopupMenu::get_item_shortcut(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, items.size(), Ref<Shortcut>()); return items[p_idx].shortcut; } @@ -951,7 +991,7 @@ void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) { control->update(); } -void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bool p_global) { +void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bool p_global) { ERR_FAIL_INDEX(p_idx, items.size()); if (items[p_idx].shortcut.is_valid()) { _unref_shortcut(items[p_idx].shortcut); @@ -1190,7 +1230,7 @@ Array PopupMenu::_get_items() const { return items; } -void PopupMenu::_ref_shortcut(Ref<ShortCut> p_sc) { +void PopupMenu::_ref_shortcut(Ref<Shortcut> p_sc) { if (!shortcut_refcount.has(p_sc)) { shortcut_refcount[p_sc] = 1; p_sc->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update)); @@ -1199,7 +1239,7 @@ void PopupMenu::_ref_shortcut(Ref<ShortCut> p_sc) { } } -void PopupMenu::_unref_shortcut(Ref<ShortCut> p_sc) { +void PopupMenu::_unref_shortcut(Ref<Shortcut> p_sc) { ERR_FAIL_COND(!shortcut_refcount.has(p_sc)); shortcut_refcount[p_sc]--; if (shortcut_refcount[p_sc] == 0) { @@ -1424,23 +1464,38 @@ void PopupMenu::_bind_methods() { void PopupMenu::popup(const Rect2 &p_bounds) { moved = Vector2(); - invalidated_click = true; + popup_time_msec = OS::get_singleton()->get_ticks_msec(); + set_as_minsize(); Popup::popup(p_bounds); } PopupMenu::PopupMenu() { + // Margin Container + margin_container = memnew(MarginContainer); + margin_container->set_anchors_and_margins_preset(Control::PRESET_WIDE); + add_child(margin_container); + margin_container->connect("draw", callable_mp(this, &PopupMenu::_draw_background)); + + // Scroll Container + scroll_container = memnew(ScrollContainer); + scroll_container->set_clip_contents(true); + margin_container->add_child(scroll_container); + + // The control which will display the items control = memnew(Control); - add_child(control); - + control->set_clip_contents(false); control->set_anchors_and_margins_preset(Control::PRESET_WIDE); + control->set_h_size_flags(Control::SIZE_EXPAND_FILL); + control->set_v_size_flags(Control::SIZE_EXPAND_FILL); + scroll_container->add_child(control); + control->connect("draw", callable_mp(this, &PopupMenu::_draw_items)); + connect("window_input", callable_mp(this, &PopupMenu::_gui_input)); - control->connect("draw", callable_mp(this, &PopupMenu::_draw)); mouse_over = -1; submenu_over = -1; initial_button_mask = 0; during_grabbed_click = false; - invalidated_click = false; allow_search = true; search_time_msec = 0; @@ -1455,6 +1510,12 @@ PopupMenu::PopupMenu() { submenu_timer->set_one_shot(true); submenu_timer->connect("timeout", callable_mp(this, &PopupMenu::_submenu_timeout)); add_child(submenu_timer); + + minimum_lifetime_timer = memnew(Timer); + minimum_lifetime_timer->set_wait_time(0.3); + minimum_lifetime_timer->set_one_shot(true); + minimum_lifetime_timer->connect("timeout", callable_mp(this, &PopupMenu::_minimum_lifetime_timeout)); + add_child(minimum_lifetime_timer); } PopupMenu::~PopupMenu() { diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index 43cd7a54e9..a2e7d7e6cd 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -31,7 +31,9 @@ #ifndef POPUP_MENU_H #define POPUP_MENU_H +#include "scene/gui/margin_container.h" #include "scene/gui/popup.h" +#include "scene/gui/scroll_container.h" #include "scene/gui/shortcut.h" class PopupMenu : public Popup { @@ -57,11 +59,17 @@ class PopupMenu : public Popup { String tooltip; uint32_t accel; int _ofs_cache; + int _height_cache; int h_ofs; - Ref<ShortCut> shortcut; + Ref<Shortcut> shortcut; bool shortcut_is_global; bool shortcut_is_disabled; + // Returns (0,0) if icon is null. + Size2 get_icon_size() const { + return icon.is_null() ? Size2() : icon->get_size(); + } + Item() { checked = false; checkable_type = CHECKABLE_TYPE_NONE; @@ -71,12 +79,16 @@ class PopupMenu : public Popup { accel = 0; disabled = false; _ofs_cache = 0; + _height_cache = 0; h_ofs = 0; shortcut_is_global = false; shortcut_is_disabled = false; } }; + bool close_allowed = false; + + Timer *minimum_lifetime_timer = nullptr; Timer *submenu_timer; List<Rect2> autohide_areas; Vector<Item> items; @@ -88,12 +100,15 @@ class PopupMenu : public Popup { String _get_accel_text(int p_item) const; int _get_mouse_over(const Point2 &p_over) const; virtual Size2 _get_contents_minimum_size() const override; - void _scroll(float p_factor, const Point2 &p_over); + + int _get_items_total_height() const; + void _scroll_to_item(int p_item); + void _gui_input(const Ref<InputEvent> &p_event); - void _activate_submenu(int over); + void _activate_submenu(int p_over); void _submenu_timeout(); - bool invalidated_click; + uint64_t popup_time_msec = 0; bool hide_on_item_selection; bool hide_on_checkable_item_selection; bool hide_on_multistate_item_selection; @@ -102,18 +117,24 @@ class PopupMenu : public Popup { Array _get_items() const; void _set_items(const Array &p_items); - Map<Ref<ShortCut>, int> shortcut_refcount; + Map<Ref<Shortcut>, int> shortcut_refcount; - void _ref_shortcut(Ref<ShortCut> p_sc); - void _unref_shortcut(Ref<ShortCut> p_sc); + void _ref_shortcut(Ref<Shortcut> p_sc); + void _unref_shortcut(Ref<Shortcut> p_sc); bool allow_search; uint64_t search_time_msec; String search_string; + MarginContainer *margin_container; + ScrollContainer *scroll_container; Control *control; - void _draw(); + void _draw_items(); + void _draw_background(); + + void _minimum_lifetime_timeout(); + void _close_pressed(); protected: friend class MenuButton; @@ -130,12 +151,12 @@ public: void add_multistate_item(const String &p_label, int p_max_states, int p_default_state = 0, int p_id = -1, uint32_t p_accel = 0); - void add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); - void add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); - void add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); - void add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); - void add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); - void add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_shortcut(const Ref<Shortcut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_radio_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id = -1, bool p_global = false); void add_submenu_item(const String &p_label, const String &p_submenu, int p_id = -1); @@ -151,7 +172,7 @@ public: void set_item_as_checkable(int p_idx, bool p_checkable); void set_item_as_radio_checkable(int p_idx, bool p_radio_checkable); void set_item_tooltip(int p_idx, const String &p_tooltip); - void set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bool p_global = false); + void set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bool p_global = false); void set_item_h_offset(int p_idx, int p_offset); void set_item_multistate(int p_idx, int p_state); void toggle_item_multistate(int p_idx); @@ -174,7 +195,7 @@ public: bool is_item_radio_checkable(int p_idx) const; bool is_item_shortcut_disabled(int p_idx) const; String get_item_tooltip(int p_idx) const; - Ref<ShortCut> get_item_shortcut(int p_idx) const; + Ref<Shortcut> get_item_shortcut(int p_idx) const; int get_item_state(int p_idx) const; int get_current_index() const; diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index 59e26d9e38..bdb9f408f0 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -34,7 +34,7 @@ String Range::get_configuration_warning() const { String warning = Control::get_configuration_warning(); if (shared->exp_ratio && shared->min <= 0) { - if (warning != String()) { + if (!warning.empty()) { warning += "\n\n"; } warning += TTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."); diff --git a/scene/gui/reference_rect.cpp b/scene/gui/reference_rect.cpp index 27c57c684a..773acb2713 100644 --- a/scene/gui/reference_rect.cpp +++ b/scene/gui/reference_rect.cpp @@ -30,7 +30,7 @@ #include "reference_rect.h" -#include "core/engine.h" +#include "core/config/engine.h" void ReferenceRect::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { @@ -38,7 +38,7 @@ void ReferenceRect::_notification(int p_what) { return; } if (Engine::get_singleton()->is_editor_hint() || !editor_only) { - draw_rect(Rect2(Point2(), get_size()), border_color, false); + draw_rect(Rect2(Point2(), get_size()), border_color, false, border_width); } } } @@ -52,6 +52,15 @@ Color ReferenceRect::get_border_color() const { return border_color; } +void ReferenceRect::set_border_width(float p_width) { + border_width = MAX(0.0, p_width); + update(); +} + +float ReferenceRect::get_border_width() const { + return border_width; +} + void ReferenceRect::set_editor_only(const bool &p_enabled) { editor_only = p_enabled; update(); @@ -65,14 +74,13 @@ void ReferenceRect::_bind_methods() { ClassDB::bind_method(D_METHOD("get_border_color"), &ReferenceRect::get_border_color); ClassDB::bind_method(D_METHOD("set_border_color", "color"), &ReferenceRect::set_border_color); + ClassDB::bind_method(D_METHOD("get_border_width"), &ReferenceRect::get_border_width); + ClassDB::bind_method(D_METHOD("set_border_width", "width"), &ReferenceRect::set_border_width); + ClassDB::bind_method(D_METHOD("get_editor_only"), &ReferenceRect::get_editor_only); ClassDB::bind_method(D_METHOD("set_editor_only", "enabled"), &ReferenceRect::set_editor_only); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "border_color"), "set_border_color", "get_border_color"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "border_width", PROPERTY_HINT_RANGE, "0.0,5.0,0.1,or_greater"), "set_border_width", "get_border_width"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "get_editor_only"); } - -ReferenceRect::ReferenceRect() { - border_color = Color(1, 0, 0); - editor_only = true; -} diff --git a/scene/gui/reference_rect.h b/scene/gui/reference_rect.h index db2f4269f3..becbbf47c5 100644 --- a/scene/gui/reference_rect.h +++ b/scene/gui/reference_rect.h @@ -35,19 +35,22 @@ class ReferenceRect : public Control { GDCLASS(ReferenceRect, Control); - Color border_color; - bool editor_only; + + Color border_color = Color(1, 0, 0); + float border_width = 1.0; + bool editor_only = true; protected: void _notification(int p_what); static void _bind_methods(); public: - ReferenceRect(); - void set_border_color(const Color &p_color); Color get_border_color() const; + void set_border_width(float p_width); + float get_border_width() const; + void set_editor_only(const bool &p_enabled); bool get_editor_only() const; }; diff --git a/scene/gui/rich_text_effect.cpp b/scene/gui/rich_text_effect.cpp index 2628e5ab0f..76ca8abcc7 100644 --- a/scene/gui/rich_text_effect.cpp +++ b/scene/gui/rich_text_effect.cpp @@ -30,7 +30,7 @@ #include "rich_text_effect.h" -#include "core/script_language.h" +#include "core/object/script_language.h" void RichTextEffect::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::BOOL, "_process_custom_fx", PropertyInfo(Variant::OBJECT, "char_fx", PROPERTY_HINT_RESOURCE_TYPE, "CharFXTransform"))); diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h index 77c82aa780..e6b9f09e4d 100644 --- a/scene/gui/rich_text_effect.h +++ b/scene/gui/rich_text_effect.h @@ -31,7 +31,7 @@ #ifndef RICH_TEXT_EFFECT_H #define RICH_TEXT_EFFECT_H -#include "core/resource.h" +#include "core/io/resource.h" class RichTextEffect : public Resource { GDCLASS(RichTextEffect, Resource); @@ -59,7 +59,7 @@ public: bool visibility; Point2 offset; Color color; - CharType character; + char32_t character; float elapsed_time; Dictionary environment; @@ -79,7 +79,7 @@ public: Color get_color() { return color; } void set_color(Color p_color) { color = p_color; } int get_character() { return (int)character; } - void set_character(int p_char) { character = (CharType)p_char; } + void set_character(int p_char) { character = (char32_t)p_char; } Dictionary get_environment() { return environment; } void set_environment(Dictionary p_environment) { environment = p_environment; } }; diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 41cd67dbf1..e8acac172c 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -188,7 +188,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & wofs += line_ofs; } - int begin = wofs; + int begin = margin; Ref<Font> cfont = _find_font(it); if (cfont.is_null()) { @@ -256,7 +256,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & lh = line < l.height_caches.size() ? l.height_caches[line] : 1; \ line_ascent = line < l.ascent_caches.size() ? l.ascent_caches[line] : 1; \ line_descent = line < l.descent_caches.size() ? l.descent_caches[line] : 1; \ - if ((p_mode == PROCESS_DRAW) && (align != ALIGN_FILL)) { \ + if (align != ALIGN_FILL) { \ if (line < l.offset_caches.size()) { \ wofs = l.offset_caches[line]; \ } \ @@ -354,8 +354,8 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & font = p_base_font; } - const CharType *c = text->text.c_str(); - const CharType *cf = c; + const char32_t *c = text->text.get_data(); + const char32_t *cf = c; int ascent = font->get_ascent(); int descent = font->get_descent(); @@ -461,7 +461,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & bool selected = false; Color fx_color = Color(color); Point2 fx_offset; - CharType fx_char = c[i]; + char32_t fx_char = c[i]; if (selection.active) { int cofs = (&c[i]) - cf; @@ -2529,9 +2529,9 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p return false; } -void RichTextLabel::selection_copy() { +String RichTextLabel::get_selected_text() { if (!selection.active || !selection.enabled) { - return; + return ""; } String text; @@ -2561,6 +2561,12 @@ void RichTextLabel::selection_copy() { item = _get_next_item(item, true); } + return text; +} + +void RichTextLabel::selection_copy() { + String text = get_selected_text(); + if (text != "") { DisplayServer::get_singleton()->clipboard_set(text); } diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 2bda7c7fce..c5ed1cb3ef 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -475,6 +475,7 @@ public: void set_selection_enabled(bool p_enabled); bool is_selection_enabled() const; + String get_selected_text(); void selection_copy(); Error parse_bbcode(const String &p_bbcode); diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 0e9ef71892..9340d98ede 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -32,7 +32,7 @@ #include "core/os/keyboard.h" #include "core/os/os.h" -#include "core/print_string.h" +#include "core/string/print_string.h" #include "scene/main/window.h" bool ScrollBar::focus_by_default = false; diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index b72b913af0..f4e31c45d2 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -45,7 +45,7 @@ Size2 ScrollContainer::get_minimum_size() const { if (!c) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } if (c == h_scroll || c == v_scroll) { @@ -285,7 +285,7 @@ void ScrollContainer::_notification(int p_what) { if (!c) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } if (c == h_scroll || c == v_scroll) { @@ -520,6 +520,8 @@ void ScrollContainer::set_follow_focus(bool p_follow) { } String ScrollContainer::get_configuration_warning() const { + String warning = Container::get_configuration_warning(); + int found = 0; for (int i = 0; i < get_child_count(); i++) { @@ -527,7 +529,7 @@ String ScrollContainer::get_configuration_warning() const { if (!c) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } if (c == h_scroll || c == v_scroll) { @@ -538,10 +540,12 @@ String ScrollContainer::get_configuration_warning() const { } if (found != 1) { - return TTR("ScrollContainer is intended to work with a single child control.\nUse a container as child (VBox, HBox, etc.), or a Control and set the custom minimum size manually."); - } else { - return ""; + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("ScrollContainer is intended to work with a single child control.\nUse a container as child (VBox, HBox, etc.), or a Control and set the custom minimum size manually."); } + return warning; } HScrollBar *ScrollContainer::get_h_scrollbar() { diff --git a/scene/gui/shortcut.cpp b/scene/gui/shortcut.cpp index 9f5b9c40c2..f8c7bc44a7 100644 --- a/scene/gui/shortcut.cpp +++ b/scene/gui/shortcut.cpp @@ -32,20 +32,20 @@ #include "core/os/keyboard.h" -void ShortCut::set_shortcut(const Ref<InputEvent> &p_shortcut) { +void Shortcut::set_shortcut(const Ref<InputEvent> &p_shortcut) { shortcut = p_shortcut; emit_changed(); } -Ref<InputEvent> ShortCut::get_shortcut() const { +Ref<InputEvent> Shortcut::get_shortcut() const { return shortcut; } -bool ShortCut::is_shortcut(const Ref<InputEvent> &p_event) const { +bool Shortcut::is_shortcut(const Ref<InputEvent> &p_event) const { return shortcut.is_valid() && shortcut->shortcut_match(p_event); } -String ShortCut::get_as_text() const { +String Shortcut::get_as_text() const { if (shortcut.is_valid()) { return shortcut->as_text(); } else { @@ -53,21 +53,21 @@ String ShortCut::get_as_text() const { } } -bool ShortCut::is_valid() const { +bool Shortcut::is_valid() const { return shortcut.is_valid(); } -void ShortCut::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_shortcut", "event"), &ShortCut::set_shortcut); - ClassDB::bind_method(D_METHOD("get_shortcut"), &ShortCut::get_shortcut); +void Shortcut::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_shortcut", "event"), &Shortcut::set_shortcut); + ClassDB::bind_method(D_METHOD("get_shortcut"), &Shortcut::get_shortcut); - ClassDB::bind_method(D_METHOD("is_valid"), &ShortCut::is_valid); + ClassDB::bind_method(D_METHOD("is_valid"), &Shortcut::is_valid); - ClassDB::bind_method(D_METHOD("is_shortcut", "event"), &ShortCut::is_shortcut); - ClassDB::bind_method(D_METHOD("get_as_text"), &ShortCut::get_as_text); + ClassDB::bind_method(D_METHOD("is_shortcut", "event"), &Shortcut::is_shortcut); + ClassDB::bind_method(D_METHOD("get_as_text"), &Shortcut::get_as_text); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), "set_shortcut", "get_shortcut"); } -ShortCut::ShortCut() { +Shortcut::Shortcut() { } diff --git a/scene/gui/shortcut.h b/scene/gui/shortcut.h index 063d4e43dc..176958b397 100644 --- a/scene/gui/shortcut.h +++ b/scene/gui/shortcut.h @@ -32,10 +32,10 @@ #define SHORTCUT_H #include "core/input/input_event.h" -#include "core/resource.h" +#include "core/io/resource.h" -class ShortCut : public Resource { - GDCLASS(ShortCut, Resource); +class Shortcut : public Resource { + GDCLASS(Shortcut, Resource); Ref<InputEvent> shortcut; @@ -50,7 +50,7 @@ public: String get_as_text() const; - ShortCut(); + Shortcut(); }; #endif // SHORTCUT_H diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 3670f13705..ae2f99e91d 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -62,8 +62,8 @@ void SpinBox::_text_entered(const String &p_string) { Variant value = expr->execute(Array(), nullptr, false); if (value.get_type() != Variant::NIL) { set_value(value); - _value_changed(0); } + _value_changed(0); } LineEdit *SpinBox::get_line_edit() { diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index 5c60153d91..6508be1e43 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -41,7 +41,7 @@ Control *SplitContainer::_getch(int p_idx) const { if (!c || !c->is_visible_in_tree()) { continue; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { continue; } diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index 4e1ad2ae05..c5f56fe8e2 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -30,7 +30,7 @@ #include "subviewport_container.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "scene/main/viewport.h" Size2 SubViewportContainer::get_minimum_size() const { diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 41b8fad49d..d92f41af2d 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -30,7 +30,7 @@ #include "tab_container.h" -#include "core/message_queue.h" +#include "core/object/message_queue.h" #include "scene/gui/box_container.h" #include "scene/gui/label.h" #include "scene/gui/texture_rect.h" @@ -282,7 +282,6 @@ void TabContainer::_notification(int p_what) { Color font_color_bg = get_theme_color("font_color_bg"); Color font_color_disabled = get_theme_color("font_color_disabled"); int side_margin = get_theme_constant("side_margin"); - int icon_text_distance = get_theme_constant("icon_separation"); // Find out start and width of the header area. int header_x = side_margin; @@ -348,61 +347,35 @@ void TabContainer::_notification(int p_what) { break; } - // Draw the tab area. - panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height)); - - // Draw all visible tabs. + // Draw unselected tabs in back int x = 0; + int x_current = 0; for (int i = 0; i < tab_widths.size(); i++) { if (get_tab_hidden(i)) { continue; } - Ref<StyleBox> tab_style; - Color font_color; + + int tab_width = tab_widths[i]; if (get_tab_disabled(i + first_tab_cache)) { - tab_style = tab_disabled; - font_color = font_color_disabled; + _draw_tab(tab_disabled, font_color_disabled, i, tabs_ofs_cache + x); } else if (i + first_tab_cache == current) { - tab_style = tab_fg; - font_color = font_color_fg; + x_current = x; } else { - tab_style = tab_bg; - font_color = font_color_bg; - } - - // Draw the tab background. - int tab_width = tab_widths[i]; - Rect2 tab_rect(tabs_ofs_cache + x, 0, tab_width, header_height); - tab_style->draw(canvas, tab_rect); - - // Draw the tab contents. - Control *control = Object::cast_to<Control>(tabs[i + first_tab_cache]); - String text = control->has_meta("_tab_name") ? String(tr(String(control->get_meta("_tab_name")))) : String(tr(control->get_name())); - - int x_content = tab_rect.position.x + tab_style->get_margin(MARGIN_LEFT); - int top_margin = tab_style->get_margin(MARGIN_TOP); - int y_center = top_margin + (tab_rect.size.y - tab_style->get_minimum_size().y) / 2; - - // Draw the tab icon. - if (control->has_meta("_tab_icon")) { - Ref<Texture2D> icon = control->get_meta("_tab_icon"); - if (icon.is_valid()) { - int y = y_center - (icon->get_height() / 2); - icon->draw(canvas, Point2i(x_content, y)); - if (text != "") { - x_content += icon->get_width() + icon_text_distance; - } - } + _draw_tab(tab_bg, font_color_bg, i, tabs_ofs_cache + x); } - // Draw the tab text. - Point2i text_pos(x_content, y_center - (font->get_height() / 2) + font->get_ascent()); - font->draw(canvas, text_pos, text, font_color); - x += tab_width; last_tab_cache = i + first_tab_cache; } + // Draw the tab area. + panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height)); + + // Draw selected tab in front. Need to check tabs.size() in case of no contents at all. + if (tabs.size() > 0) { + _draw_tab(tab_fg, font_color_fg, current, tabs_ofs_cache + x_current); + } + // Draw the popup menu. x = get_size().width; if (popup) { @@ -438,6 +411,43 @@ void TabContainer::_notification(int p_what) { } } +void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x) { + Vector<Control *> tabs = _get_tabs(); + RID canvas = get_canvas_item(); + Ref<Font> font = get_theme_font("font"); + int icon_text_distance = get_theme_constant("icon_separation"); + int tab_width = _get_tab_width(p_index); + int header_height = _get_top_margin(); + + // Draw the tab background. + Rect2 tab_rect(p_x, 0, tab_width, header_height); + p_tab_style->draw(canvas, tab_rect); + + // Draw the tab contents. + Control *control = Object::cast_to<Control>(tabs[p_index + first_tab_cache]); + String text = control->has_meta("_tab_name") ? String(tr(String(control->get_meta("_tab_name")))) : String(tr(control->get_name())); + + int x_content = tab_rect.position.x + p_tab_style->get_margin(MARGIN_LEFT); + int top_margin = p_tab_style->get_margin(MARGIN_TOP); + int y_center = top_margin + (tab_rect.size.y - p_tab_style->get_minimum_size().y) / 2; + + // Draw the tab icon. + if (control->has_meta("_tab_icon")) { + Ref<Texture2D> icon = control->get_meta("_tab_icon"); + if (icon.is_valid()) { + int y = y_center - (icon->get_height() / 2); + icon->draw(canvas, Point2i(x_content, y)); + if (text != "") { + x_content += icon->get_width() + icon_text_distance; + } + } + } + + // Draw the tab text. + Point2i text_pos(x_content, y_center - (font->get_height() / 2) + font->get_ascent()); + font->draw(canvas, text_pos, text, p_font_color); +} + void TabContainer::_on_theme_changed() { if (get_tab_count() > 0) { _repaint(); @@ -478,7 +488,7 @@ void TabContainer::_on_mouse_exited() { int TabContainer::_get_tab_width(int p_index) const { ERR_FAIL_INDEX_V(p_index, get_tab_count(), 0); Control *control = Object::cast_to<Control>(_get_tabs()[p_index]); - if (!control || control->is_set_as_toplevel() || get_tab_hidden(p_index)) { + if (!control || control->is_set_as_top_level() || get_tab_hidden(p_index)) { return 0; } @@ -517,7 +527,7 @@ Vector<Control *> TabContainer::_get_tabs() const { Vector<Control *> controls; for (int i = 0; i < get_child_count(); i++) { Control *control = Object::cast_to<Control>(get_child(i)); - if (!control || control->is_toplevel_control()) { + if (!control || control->is_top_level_control()) { continue; } @@ -537,7 +547,7 @@ void TabContainer::add_child_notify(Node *p_child) { if (!c) { return; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { return; } diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index 7ea667d60f..6ac07b5845 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -68,6 +68,7 @@ private: void _repaint(); void _on_mouse_exited(); void _update_current_tab(); + void _draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x); protected: void _child_renamed_callback(); diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 8f71aa7cab..eefe8cc3bc 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -30,7 +30,7 @@ #include "tabs.h" -#include "core/message_queue.h" +#include "core/object/message_queue.h" #include "scene/gui/box_container.h" #include "scene/gui/label.h" #include "scene/gui/texture_rect.h" @@ -388,6 +388,7 @@ void Tabs::set_current_tab(int p_current) { } ERR_FAIL_INDEX(p_current, get_tab_count()); + previous = current; current = p_current; _change_notify("current_tab"); @@ -401,6 +402,10 @@ int Tabs::get_current_tab() const { return current; } +int Tabs::get_previous_tab() const { + return previous; +} + int Tabs::get_hovered_tab() const { return hover; } @@ -588,6 +593,7 @@ void Tabs::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) { void Tabs::clear_tabs() { tabs.clear(); current = 0; + previous = 0; call_deferred("_update_hover"); update(); } @@ -605,6 +611,7 @@ void Tabs::remove_tab(int p_idx) { if (current < 0) { current = 0; + previous = 0; } if (current >= tabs.size()) { current = tabs.size() - 1; @@ -917,6 +924,7 @@ void Tabs::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tab_count"), &Tabs::get_tab_count); ClassDB::bind_method(D_METHOD("set_current_tab", "tab_idx"), &Tabs::set_current_tab); ClassDB::bind_method(D_METHOD("get_current_tab"), &Tabs::get_current_tab); + ClassDB::bind_method(D_METHOD("get_previous_tab"), &Tabs::get_previous_tab); ClassDB::bind_method(D_METHOD("set_tab_title", "tab_idx", "title"), &Tabs::set_tab_title); ClassDB::bind_method(D_METHOD("get_tab_title", "tab_idx"), &Tabs::get_tab_title); ClassDB::bind_method(D_METHOD("set_tab_icon", "tab_idx", "icon"), &Tabs::set_tab_icon); @@ -970,6 +978,7 @@ void Tabs::_bind_methods() { Tabs::Tabs() { current = 0; + previous = 0; tab_align = ALIGN_CENTER; rb_hover = -1; rb_pressing = false; diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h index 8d7f1aa37d..b94c4a37a1 100644 --- a/scene/gui/tabs.h +++ b/scene/gui/tabs.h @@ -77,6 +77,7 @@ private: bool missing_right; Vector<Tab> tabs; int current; + int previous; int _get_top_margin() const; TabAlign tab_align; int rb_hover; @@ -138,6 +139,7 @@ public: int get_tab_count() const; void set_current_tab(int p_current); int get_current_tab() const; + int get_previous_tab() const; int get_hovered_tab() const; int get_tab_offset() const; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index b974dc2897..77ac3d6702 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -30,12 +30,12 @@ #include "text_edit.h" +#include "core/config/project_settings.h" #include "core/input/input.h" -#include "core/message_queue.h" +#include "core/object/message_queue.h" +#include "core/object/script_language.h" #include "core/os/keyboard.h" #include "core/os/os.h" -#include "core/project_settings.h" -#include "core/script_language.h" #include "scene/main/window.h" #ifdef TOOLS_ENABLED @@ -44,23 +44,23 @@ #define TAB_PIXELS -inline bool _is_symbol(CharType c) { +inline bool _is_symbol(char32_t c) { return is_symbol(c); } -static bool _is_text_char(CharType c) { +static bool _is_text_char(char32_t c) { return !is_symbol(c); } -static bool _is_whitespace(CharType c) { +static bool _is_whitespace(char32_t c) { return c == '\t' || c == ' '; } -static bool _is_char(CharType c) { +static bool _is_char(char32_t c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; } -static bool _is_pair_right_symbol(CharType c) { +static bool _is_pair_right_symbol(char32_t c) { return c == '"' || c == '\'' || c == ')' || @@ -68,7 +68,7 @@ static bool _is_pair_right_symbol(CharType c) { c == '}'; } -static bool _is_pair_left_symbol(CharType c) { +static bool _is_pair_left_symbol(char32_t c) { return c == '"' || c == '\'' || c == '(' || @@ -76,11 +76,11 @@ static bool _is_pair_left_symbol(CharType c) { c == '{'; } -static bool _is_pair_symbol(CharType c) { +static bool _is_pair_symbol(char32_t c) { return _is_pair_left_symbol(c) || _is_pair_right_symbol(c); } -static CharType _get_right_pair_symbol(CharType c) { +static char32_t _get_right_pair_symbol(char32_t c) { if (c == '"') { return '"'; } @@ -107,6 +107,8 @@ static int _find_first_non_whitespace_column_of_line(const String &line) { return left; } +/////////////////////////////////////////////////////////////////////////////// + void TextEdit::Text::set_font(const Ref<Font> &p_font) { font = p_font; } @@ -119,7 +121,7 @@ void TextEdit::Text::_update_line_cache(int p_line) const { int w = 0; int len = text[p_line].data.length(); - const CharType *str = text[p_line].data.c_str(); + const char32_t *str = text[p_line].data.get_data(); // Update width. @@ -165,12 +167,6 @@ void TextEdit::Text::clear_wrap_cache() { } } -void TextEdit::Text::clear_info_icons() { - for (int i = 0; i < text.size(); i++) { - text.write[i].has_info = false; - } -} - void TextEdit::Text::clear() { text.clear(); insert(0, ""); @@ -198,12 +194,9 @@ void TextEdit::Text::set(int p_line, const String &p_text) { void TextEdit::Text::insert(int p_at, const String &p_text) { Line line; + line.gutters.resize(gutter_count); line.marked = false; - line.safe = false; - line.breakpoint = false; - line.bookmark = false; line.hidden = false; - line.has_info = false; line.width_cache = -1; line.wrap_amount_cache = -1; line.data = p_text; @@ -214,7 +207,7 @@ void TextEdit::Text::remove(int p_at) { text.remove(p_at); } -int TextEdit::Text::get_char_width(CharType c, CharType next_c, int px) const { +int TextEdit::Text::get_char_width(char32_t c, char32_t next_c, int px) const { int tab_w = font->get_char_size(' ').width * indent_size; int w = 0; @@ -231,6 +224,32 @@ int TextEdit::Text::get_char_width(CharType c, CharType next_c, int px) const { return w; } +void TextEdit::Text::add_gutter(int p_at) { + for (int i = 0; i < text.size(); i++) { + if (p_at < 0 || p_at > gutter_count) { + text.write[i].gutters.push_back(Gutter()); + } else { + text.write[i].gutters.insert(p_at, Gutter()); + } + } + gutter_count++; +} + +void TextEdit::Text::remove_gutter(int p_gutter) { + for (int i = 0; i < text.size(); i++) { + text.write[i].gutters.remove(p_gutter); + } + gutter_count--; +} + +void TextEdit::Text::move_gutters(int p_from_line, int p_to_line) { + text.write[p_to_line].gutters = text[p_from_line].gutters; + text.write[p_from_line].gutters.clear(); + text.write[p_from_line].gutters.resize(gutter_count); +} + +//////////////////////////////////////////////////////////////////////////////// + void TextEdit::_update_scrollbars() { Size2 size = get_size(); Size2 hmin = h_scroll->get_combined_minimum_size(); @@ -249,23 +268,7 @@ void TextEdit::_update_scrollbars() { } int visible_width = size.width - cache.style_normal->get_minimum_size().width; - int total_width = text.get_max_width(true) + vmin.x; - - if (line_numbers) { - total_width += cache.line_number_w; - } - - if (draw_breakpoint_gutter || draw_bookmark_gutter) { - total_width += cache.breakpoint_gutter_width; - } - - if (draw_info_gutter) { - total_width += cache.info_gutter_width; - } - - if (draw_fold_gutter) { - total_width += cache.fold_gutter_width; - } + int total_width = text.get_max_width(true) + vmin.x + gutters_width + gutter_padding; if (draw_minimap) { total_width += cache.minimap_width; @@ -315,15 +318,15 @@ void TextEdit::_click_selection_held() { // Warning: is_mouse_button_pressed(BUTTON_LEFT) returns false for double+ clicks, so this doesn't work for MODE_WORD // and MODE_LINE. However, moving the mouse triggers _gui_input, which calls these functions too, so that's not a huge problem. // I'm unsure if there's an actual fix that doesn't have a ton of side effects. - if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && selection.selecting_mode != Selection::MODE_NONE) { + if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && selection.selecting_mode != SelectionMode::SELECTION_MODE_NONE) { switch (selection.selecting_mode) { - case Selection::MODE_POINTER: { + case SelectionMode::SELECTION_MODE_POINTER: { _update_selection_mode_pointer(); } break; - case Selection::MODE_WORD: { + case SelectionMode::SELECTION_MODE_WORD: { _update_selection_mode_word(); } break; - case Selection::MODE_LINE: { + case SelectionMode::SELECTION_MODE_LINE: { _update_selection_mode_line(); } break; default: { @@ -557,54 +560,16 @@ void TextEdit::_notification(int p_what) { draw_caret = false; } - if (draw_breakpoint_gutter || draw_bookmark_gutter) { - breakpoint_gutter_width = (get_row_height() * 55) / 100; - cache.breakpoint_gutter_width = breakpoint_gutter_width; - } else { - cache.breakpoint_gutter_width = 0; - } - - if (draw_info_gutter) { - info_gutter_width = (get_row_height()); - cache.info_gutter_width = info_gutter_width; - } else { - cache.info_gutter_width = 0; - } - - if (draw_fold_gutter) { - fold_gutter_width = (get_row_height() * 55) / 100; - cache.fold_gutter_width = fold_gutter_width; - } else { - cache.fold_gutter_width = 0; - } - cache.minimap_width = 0; if (draw_minimap) { cache.minimap_width = minimap_width; } - int line_number_char_count = 0; - - { - int lc = text.size(); - cache.line_number_w = 0; - while (lc) { - cache.line_number_w += 1; - lc /= 10; - }; - - if (line_numbers) { - line_number_char_count = cache.line_number_w; - cache.line_number_w = (cache.line_number_w + 1) * cache.font->get_char_size('0').width; - } else { - cache.line_number_w = 0; - } - } _update_scrollbars(); RID ci = get_canvas_item(); RenderingServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true); - int xmargin_beg = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width; + int xmargin_beg = cache.style_normal->get_margin(MARGIN_LEFT) + gutters_width + gutter_padding; int xmargin_end = size.width - cache.style_normal->get_margin(MARGIN_RIGHT) - cache.minimap_width; // Let's do it easy for now. @@ -654,8 +619,8 @@ void TextEdit::_notification(int p_what) { if (brace_matching_enabled && cursor.line >= 0 && cursor.line < text.size() && cursor.column >= 0) { if (cursor.column < text[cursor.line].length()) { // Check for open. - CharType c = text[cursor.line][cursor.column]; - CharType closec = 0; + char32_t c = text[cursor.line][cursor.column]; + char32_t closec = 0; if (c == '[') { closec = ']'; @@ -671,10 +636,10 @@ void TextEdit::_notification(int p_what) { for (int i = cursor.line; i < text.size(); i++) { int from = i == cursor.line ? cursor.column + 1 : 0; for (int j = from; j < text[i].length(); j++) { - CharType cc = text[i][j]; + char32_t cc = text[i][j]; // Ignore any brackets inside a string. if (cc == '"' || cc == '\'') { - CharType quotation = cc; + char32_t quotation = cc; do { j++; if (!(j < text[i].length())) { @@ -720,8 +685,8 @@ void TextEdit::_notification(int p_what) { } if (cursor.column > 0) { - CharType c = text[cursor.line][cursor.column - 1]; - CharType closec = 0; + char32_t c = text[cursor.line][cursor.column - 1]; + char32_t closec = 0; if (c == ']') { closec = '['; @@ -737,10 +702,10 @@ void TextEdit::_notification(int p_what) { for (int i = cursor.line; i >= 0; i--) { int from = i == cursor.line ? cursor.column - 2 : text[i].length() - 1; for (int j = from; j >= 0; j--) { - CharType cc = text[i][j]; + char32_t cc = text[i][j]; // Ignore any brackets inside a string. if (cc == '"' || cc == '\'') { - CharType quotation = cc; + char32_t quotation = cc; do { j--; if (!(j >= 0)) { @@ -795,8 +760,6 @@ void TextEdit::_notification(int p_what) { // Check if highlighted words contains only whitespaces (tabs or spaces). bool only_whitespaces_highlighted = highlighted_text.strip_edges() == String(); - String line_num_padding = line_numbers_zero_padded ? "0" : " "; - int cursor_wrap_index = get_cursor_wrap_index(); FontDrawer drawer(cache.font, Color(1, 1, 1)); @@ -1053,103 +1016,52 @@ void TextEdit::_notification(int p_what) { if (line_wrap_index == 0) { // Only do these if we are on the first wrapped part of a line. - if (text.is_breakpoint(line) && !draw_breakpoint_gutter) { -#ifdef TOOLS_ENABLED - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.breakpoint_color); -#else - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.breakpoint_color); -#endif - } - - // Draw bookmark marker. - if (text.is_bookmark(line)) { - if (draw_bookmark_gutter) { - int vertical_gap = (get_row_height() * 40) / 100; - int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100; - int marker_radius = get_row_height() - (vertical_gap * 2); - RenderingServer::get_singleton()->canvas_item_add_circle(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2 + marker_radius / 2, ofs_y + vertical_gap + marker_radius / 2), marker_radius, Color(cache.bookmark_color.r, cache.bookmark_color.g, cache.bookmark_color.b)); - } - } + int gutter_offset = cache.style_normal->get_margin(MARGIN_LEFT); + for (int g = 0; g < gutters.size(); g++) { + const GutterInfo gutter = gutters[g]; - // Draw breakpoint marker. - if (text.is_breakpoint(line)) { - if (draw_breakpoint_gutter) { - int vertical_gap = (get_row_height() * 40) / 100; - int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100; - int marker_height = get_row_height() - (vertical_gap * 2); - int marker_width = cache.breakpoint_gutter_width - (horizontal_gap * 2); - // No transparency on marker. - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2, ofs_y + vertical_gap, marker_width, marker_height), Color(cache.breakpoint_color.r, cache.breakpoint_color.g, cache.breakpoint_color.b)); + if (!gutter.draw || gutter.width <= 0) { + continue; } - } - // Draw info icons. - if (draw_info_gutter && text.has_info_icon(line)) { - int vertical_gap = (get_row_height() * 40) / 100; - int horizontal_gap = (cache.info_gutter_width * 30) / 100; - int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width; - - Ref<Texture2D> info_icon = text.get_info_icon(line); - // Ensure the icon fits the gutter size. - Size2i icon_size = info_icon->get_size(); - if (icon_size.width > cache.info_gutter_width - horizontal_gap) { - icon_size.width = cache.info_gutter_width - horizontal_gap; - } - if (icon_size.height > get_row_height() - horizontal_gap) { - icon_size.height = get_row_height() - horizontal_gap; - } + switch (gutter.type) { + case GUTTER_TYPE_STRING: { + const String &text = get_line_gutter_text(line, g); + if (text == "") { + break; + } - Size2i icon_pos; - int xofs = horizontal_gap - (info_icon->get_width() / 4); - int yofs = vertical_gap - (info_icon->get_height() / 4); - icon_pos.x = gutter_left + xofs + ofs_x; - icon_pos.y = ofs_y + yofs; + int yofs = ofs_y + (get_row_height() - cache.font->get_height()) / 2; + cache.font->draw(ci, Point2(gutter_offset + ofs_x, yofs + cache.font->get_ascent()), text, get_line_gutter_item_color(line, g)); + } break; + case GUTTER_TPYE_ICON: { + const Ref<Texture2D> icon = get_line_gutter_icon(line, g); + if (icon.is_null()) { + break; + } - draw_texture_rect(info_icon, Rect2(icon_pos, icon_size)); - } + Rect2i gutter_rect = Rect2i(Point2i(gutter_offset, ofs_y), Size2i(gutter.width, get_row_height())); - // Draw execution marker. - if (executing_line == line) { - if (draw_breakpoint_gutter) { - int icon_extra_size = 4; - int vertical_gap = (get_row_height() * 40) / 100; - int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100; - int marker_height = get_row_height() - (vertical_gap * 2) + icon_extra_size; - int marker_width = cache.breakpoint_gutter_width - (horizontal_gap * 2) + icon_extra_size; - cache.executing_icon->draw_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2 - icon_extra_size / 2, ofs_y + vertical_gap - icon_extra_size / 2, marker_width, marker_height), false, Color(cache.executing_line_color.r, cache.executing_line_color.g, cache.executing_line_color.b)); - } else { -#ifdef TOOLS_ENABLED - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.executing_line_color); -#else - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.executing_line_color); -#endif - } - } + int horizontal_padding = gutter_rect.size.x / 6; + int vertical_padding = gutter_rect.size.y / 6; - // Draw fold markers. - if (draw_fold_gutter) { - int horizontal_gap = (cache.fold_gutter_width * 30) / 100; - int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.line_number_w + cache.info_gutter_width; - if (is_folded(line)) { - int xofs = horizontal_gap - (cache.can_fold_icon->get_width()) / 2; - int yofs = (get_row_height() - cache.folded_icon->get_height()) / 2; - cache.folded_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), cache.code_folding_color); - } else if (can_fold(line)) { - int xofs = -cache.can_fold_icon->get_width() / 2 - horizontal_gap + 3; - int yofs = (get_row_height() - cache.can_fold_icon->get_height()) / 2; - cache.can_fold_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), cache.code_folding_color); - } - } + gutter_rect.position += Point2(horizontal_padding, vertical_padding); + gutter_rect.size -= Point2(horizontal_padding, vertical_padding) * 2; - // Draw line numbers. - if (cache.line_number_w) { - int yofs = ofs_y + (get_row_height() - cache.font->get_height()) / 2; - String fc = String::num(line + 1); - while (fc.length() < line_number_char_count) { - fc = line_num_padding + fc; + icon->draw_rect(ci, gutter_rect, false, get_line_gutter_item_color(line, g)); + } break; + case GUTTER_TPYE_CUSTOM: { + if (gutter.custom_draw_obj.is_valid()) { + Object *cdo = ObjectDB::get_instance(gutter.custom_draw_obj); + if (cdo) { + Rect2i gutter_rect = Rect2i(Point2i(gutter_offset, ofs_y), Size2i(gutter.width, get_row_height())); + cdo->call(gutter.custom_draw_callback, line, g, Rect2(gutter_rect)); + } + } + } break; } - cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.info_gutter_width + ofs_x, yofs + cache.font->get_ascent()), fc, text.is_safe(line) ? cache.safe_line_number_color : cache.line_number_color); + gutter_offset += gutter.width; } } @@ -1303,8 +1215,8 @@ void TextEdit::_notification(int p_what) { break; } - CharType cchar = ime_text[ofs]; - CharType next = ime_text[ofs + 1]; + char32_t cchar = ime_text[ofs]; + char32_t next = ime_text[ofs + 1]; int im_char_width = cache.font->get_char_size(cchar, next).width; if ((char_ofs + char_margin + im_char_width) >= xmargin_end) { @@ -1399,8 +1311,8 @@ void TextEdit::_notification(int p_what) { break; } - CharType cchar = ime_text[ofs]; - CharType next = ime_text[ofs + 1]; + char32_t cchar = ime_text[ofs]; + char32_t next = ime_text[ofs + 1]; int im_char_width = cache.font->get_char_size(cchar, next).width; if ((char_ofs + char_margin + im_char_width) >= xmargin_end) { @@ -1477,6 +1389,17 @@ void TextEdit::_notification(int p_what) { Size2 icon_area_size(get_row_height(), get_row_height()); w += icon_area_size.width + icon_hsep; + int line_from = CLAMP(completion_index - lines / 2, 0, completion_options_size - lines); + + for (int i = 0; i < lines; i++) { + int l = line_from + i; + ERR_CONTINUE(l < 0 || l >= completion_options_size); + if (completion_options[l].default_value.get_type() == Variant::COLOR) { + w += icon_area_size.width; + break; + } + } + int th = h + csb->get_minimum_size().y; if (cursor_pos.y + get_row_height() + th > get_size().height) { @@ -1503,7 +1426,6 @@ void TextEdit::_notification(int p_what) { if (cache.completion_background_color.a > 0.01) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(completion_rect.position, completion_rect.size + Size2(scrollw, 0)), cache.completion_background_color); } - int line_from = CLAMP(completion_index - lines / 2, 0, completion_options_size - lines); RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(completion_rect.position.x, completion_rect.position.y + (completion_index - line_from) * get_row_height()), Size2(completion_rect.size.width, get_row_height())), cache.completion_selected_color); draw_rect(Rect2(completion_rect.position + Vector2(icon_area_size.x + icon_hsep, 0), Size2(MIN(nofs, completion_rect.size.width - (icon_area_size.x + icon_hsep)), completion_rect.size.height)), cache.completion_existing_color); @@ -1525,6 +1447,11 @@ void TextEdit::_notification(int p_what) { } title_pos.x = icon_area.position.x + icon_area.size.width + icon_hsep; + + if (completion_options[l].default_value.get_type() == Variant::COLOR) { + draw_rect(Rect2(Point2(completion_rect.position.x + completion_rect.size.width - icon_area_size.x, icon_area.position.y), icon_area_size), (Color)completion_options[l].default_value); + } + draw_string(cache.font, title_pos, completion_options[l].display, completion_options[l].font_color, completion_rect.size.width - (icon_area_size.x + icon_hsep)); } @@ -1631,8 +1558,20 @@ void TextEdit::_notification(int p_what) { DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos, get_viewport()->get_window_id()); } - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) { - DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), true); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { + String text = _base_get_text(0, 0, selection.selecting_line, selection.selecting_column); + int cursor_start = text.length(); + int cursor_end = -1; + + if (selection.active) { + String selected_text = _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); + + if (selected_text.length() > 0) { + cursor_end = cursor_start + selected_text.length(); + } + } + + DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), true, -1, cursor_start, cursor_end); } } break; case NOTIFICATION_FOCUS_EXIT: { @@ -1647,7 +1586,7 @@ void TextEdit::_notification(int p_what) { ime_text = ""; ime_selection = Point2(); - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) { + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { DisplayServer::get_singleton()->virtual_keyboard_hide(); } } break; @@ -1661,12 +1600,12 @@ void TextEdit::_notification(int p_what) { } } -void TextEdit::_consume_pair_symbol(CharType ch) { +void TextEdit::_consume_pair_symbol(char32_t ch) { int cursor_position_to_move = cursor_get_column() + 1; - CharType ch_single[2] = { ch, 0 }; - CharType ch_single_pair[2] = { _get_right_pair_symbol(ch), 0 }; - CharType ch_pair[3] = { ch, _get_right_pair_symbol(ch), 0 }; + char32_t ch_single[2] = { ch, 0 }; + char32_t ch_single_pair[2] = { _get_right_pair_symbol(ch), 0 }; + char32_t ch_pair[3] = { ch, _get_right_pair_symbol(ch), 0 }; if (is_selection_active()) { int new_column, new_line; @@ -1771,8 +1710,8 @@ void TextEdit::_consume_backspace_for_pair_symbol(int prev_line, int prev_column bool remove_right_symbol = false; if (cursor.column < text[cursor.line].length() && cursor.column > 0) { - CharType left_char = text[cursor.line][cursor.column - 1]; - CharType right_char = text[cursor.line][cursor.column]; + char32_t left_char = text[cursor.line][cursor.column - 1]; + char32_t right_char = text[cursor.line][cursor.column]; if (right_char == _get_right_pair_symbol(left_char)) { remove_right_symbol = true; @@ -1797,18 +1736,34 @@ void TextEdit::backspace_at_cursor() { int prev_line = cursor.column ? cursor.line : cursor.line - 1; int prev_column = cursor.column ? (cursor.column - 1) : (text[cursor.line - 1].length()); - if (is_line_hidden(cursor.line)) { - set_line_as_hidden(prev_line, true); - } - if (is_line_set_as_breakpoint(cursor.line)) { - if (!text.is_breakpoint(prev_line)) { - emit_signal("breakpoint_toggled", prev_line); + if (cursor.line != prev_line) { + for (int i = 0; i < gutters.size(); i++) { + if (!gutters[i].overwritable) { + continue; + } + + if (text.get_line_gutter_text(cursor.line, i) != "") { + text.set_line_gutter_text(prev_line, i, text.get_line_gutter_text(cursor.line, i)); + text.set_line_gutter_item_color(prev_line, i, text.get_line_gutter_item_color(cursor.line, i)); + } + + if (text.get_line_gutter_icon(cursor.line, i).is_valid()) { + text.set_line_gutter_icon(prev_line, i, text.get_line_gutter_icon(cursor.line, i)); + text.set_line_gutter_item_color(prev_line, i, text.get_line_gutter_item_color(cursor.line, i)); + } + + if (text.get_line_gutter_metadata(cursor.line, i) != "") { + text.set_line_gutter_metadata(prev_line, i, text.get_line_gutter_metadata(cursor.line, i)); + } + + if (text.is_line_gutter_clickable(cursor.line, i)) { + text.set_line_gutter_clickable(prev_line, i, true); + } } - set_line_as_breakpoint(prev_line, true); } - if (text.has_info_icon(cursor.line)) { - set_line_info_icon(prev_line, text.get_info_icon(cursor.line), text.get_info(cursor.line)); + if (is_line_hidden(cursor.line)) { + set_line_as_hidden(prev_line, true); } if (auto_brace_completion_enabled && @@ -1872,6 +1827,9 @@ void TextEdit::indent_right() { for (int i = start_line; i <= end_line; i++) { String line_text = get_line(i); + if (line_text.size() == 0 && is_selection_active()) { + continue; + } if (indent_using_spaces) { // We don't really care where selection is - we just need to know indentation level at the beginning of the line. int left = _find_first_non_whitespace_column_of_line(line_text); @@ -1995,7 +1953,7 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co row = text.size() - 1; col = text[row].size(); } else { - int colx = p_mouse.x - (cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width); + int colx = p_mouse.x - (cache.style_normal->get_margin(MARGIN_LEFT) + gutters_width + gutter_padding); colx += cursor.x_ofs; col = get_char_pos_for_line(colx, row, wrap_index); if (is_wrap_enabled() && wrap_index < times_line_wraps(row)) { @@ -2040,7 +1998,7 @@ Vector2i TextEdit::_get_cursor_pixel_pos() { // Calculate final pixel position int y = (row - get_v_scroll_offset() + 1 /*Bottom of line*/) * get_row_height(); - int x = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width - cursor.x_ofs; + int x = cache.style_normal->get_margin(MARGIN_LEFT) + gutters_width + gutter_padding - cursor.x_ofs; int ix = 0; while (ix < rows2[0].size() && ix < cursor.column) { if (cache.font != nullptr) { @@ -2175,45 +2133,24 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { int row, col; _get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col); - // Toggle breakpoint on gutter click. - if (draw_breakpoint_gutter) { - int gutter = cache.style_normal->get_margin(MARGIN_LEFT); - if (mb->get_position().x > gutter - 6 && mb->get_position().x <= gutter + cache.breakpoint_gutter_width - 3) { - set_line_as_breakpoint(row, !is_line_set_as_breakpoint(row)); - emit_signal("breakpoint_toggled", row); - return; + int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); + for (int i = 0; i < gutters.size(); i++) { + if (!gutters[i].draw || gutters[i].width <= 0) { + continue; } - } - // Emit info clicked. - if (draw_info_gutter && text.has_info_icon(row)) { - int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); - int gutter_left = left_margin + cache.breakpoint_gutter_width; - if (mb->get_position().x > gutter_left - 6 && mb->get_position().x <= gutter_left + cache.info_gutter_width - 3) { - emit_signal("info_clicked", row, text.get_info(row)); + if (mb->get_position().x > left_margin && mb->get_position().x <= (left_margin + gutters[i].width) - 3) { + emit_signal("gutter_clicked", row, i); return; } - } - // Toggle fold on gutter click if can. - if (draw_fold_gutter) { - int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); - int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.line_number_w + cache.info_gutter_width; - if (mb->get_position().x > gutter_left - 6 && mb->get_position().x <= gutter_left + cache.fold_gutter_width - 3) { - if (is_folded(row)) { - unfold_line(row); - } else if (can_fold(row)) { - fold_line(row); - } - return; - } + left_margin += gutters[i].width; } // Unfold on folded icon click. if (is_folded(row)) { - int line_width = text.get_line_width(row); - line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.info_gutter_width + cache.fold_gutter_width - cursor.x_ofs; - if (mb->get_position().x > line_width - 3 && mb->get_position().x <= line_width + cache.folded_eol_icon->get_width() + 3) { + left_margin += gutter_padding + text.get_line_width(row) - cursor.x_ofs; + if (mb->get_position().x > left_margin && mb->get_position().x <= left_margin + cache.folded_eol_icon->get_width() + 3) { unfold_line(row); return; } @@ -2236,7 +2173,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->get_shift() && (cursor.column != prev_col || cursor.line != prev_line)) { if (!selection.active) { selection.active = true; - selection.selecting_mode = Selection::MODE_POINTER; + selection.selecting_mode = SelectionMode::SELECTION_MODE_POINTER; selection.from_column = prev_col; selection.from_line = prev_line; selection.to_column = cursor.column; @@ -2280,19 +2217,19 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else { selection.active = false; - selection.selecting_mode = Selection::MODE_POINTER; + selection.selecting_mode = SelectionMode::SELECTION_MODE_POINTER; selection.selecting_line = row; selection.selecting_column = col; } if (!mb->is_doubleclick() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < 600 && cursor.line == prev_line) { // Triple-click select line. - selection.selecting_mode = Selection::MODE_LINE; + selection.selecting_mode = SelectionMode::SELECTION_MODE_LINE; _update_selection_mode_line(); last_dblclk = 0; } else if (mb->is_doubleclick() && text[cursor.line].length()) { // Double-click select word. - selection.selecting_mode = Selection::MODE_WORD; + selection.selecting_mode = SelectionMode::SELECTION_MODE_WORD; _update_selection_mode_word(); last_dblclk = OS::get_singleton()->get_ticks_msec(); } @@ -2392,13 +2329,13 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (!dragging_minimap) { switch (selection.selecting_mode) { - case Selection::MODE_POINTER: { + case SelectionMode::SELECTION_MODE_POINTER: { _update_selection_mode_pointer(); } break; - case Selection::MODE_WORD: { + case SelectionMode::SELECTION_MODE_WORD: { _update_selection_mode_word(); } break; - case Selection::MODE_LINE: { + case SelectionMode::SELECTION_MODE_LINE: { _update_selection_mode_line(); } break; default: { @@ -2537,7 +2474,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (k->get_unicode() > 32) { _reset_caret_blink_timer(); - const CharType chr[2] = { (CharType)k->get_unicode(), 0 }; + const char32_t chr[2] = { (char32_t)k->get_unicode(), 0 }; if (auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { _consume_pair_symbol(chr[0]); } else { @@ -2675,7 +2612,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (unselect) { selection.active = false; - selection.selecting_mode = Selection::MODE_NONE; + selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE; update(); } if (clear) { @@ -2781,7 +2718,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } // No need to move the brace below if we are not taking the text with us. - char closing_char = _get_right_pair_symbol(indent_char); + char32_t closing_char = _get_right_pair_symbol(indent_char); if ((closing_char != 0) && (closing_char == text[cursor.line][cursor.column]) && !k->get_command()) { brace_indent = true; ins += "\n" + ins.substr(1, ins.length() - 2); @@ -3309,7 +3246,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { // Compute whitespace symbols seq length. int current_line_whitespace_len = 0; while (current_line_whitespace_len < text[cursor.line].length()) { - CharType c = text[cursor.line][current_line_whitespace_len]; + char32_t c = text[cursor.line][current_line_whitespace_len]; if (c != '\t' && c != ' ') { break; } @@ -3455,7 +3392,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { int current_line_whitespace_len = 0; while (current_line_whitespace_len < text[cursor.line].length()) { - CharType c = text[cursor.line][current_line_whitespace_len]; + char32_t c = text[cursor.line][current_line_whitespace_len]; if (c != '\t' && c != ' ') break; current_line_whitespace_len++; @@ -3604,7 +3541,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { return; } - if (!keycode_handled && !k->get_command()) { // For German keyboards. + if (!keycode_handled && (!k->get_command() || (k->get_command() && k->get_alt()))) { // For German keyboards. if (k->get_unicode() >= 32) { if (readonly) { @@ -3621,7 +3558,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } - const CharType chr[2] = { (CharType)k->get_unicode(), 0 }; + const char32_t chr[2] = { (char32_t)k->get_unicode(), 0 }; if (completion_hint != "" && k->get_unicode() == ')') { completion_hint = ""; @@ -3703,17 +3640,17 @@ void TextEdit::_scroll_down(real_t p_delta) { } void TextEdit::_pre_shift_selection() { - if (!selection.active || selection.selecting_mode == Selection::MODE_NONE) { + if (!selection.active || selection.selecting_mode == SelectionMode::SELECTION_MODE_NONE) { selection.selecting_line = cursor.line; selection.selecting_column = cursor.column; selection.active = true; } - selection.selecting_mode = Selection::MODE_SHIFT; + selection.selecting_mode = SelectionMode::SELECTION_MODE_SHIFT; } void TextEdit::_post_shift_selection() { - if (selection.active && selection.selecting_mode == Selection::MODE_SHIFT) { + if (selection.active && selection.selecting_mode == SelectionMode::SELECTION_MODE_SHIFT) { select(selection.selecting_line, selection.selecting_column, cursor.line, cursor.column); update(); } @@ -3772,30 +3709,15 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i Vector<String> substrings = p_text.replace("\r", "").split("\n"); - /* STEP 2: Fire breakpoint_toggled signals. */ - // Is this just a new empty line? bool shift_first_line = p_char == 0 && p_text.replace("\r", "") == "\n"; - int i = p_line + !shift_first_line; - int lines = substrings.size() - 1; - for (; i < text.size(); i++) { - if (text.is_breakpoint(i)) { - if ((i - lines < p_line || !text.is_breakpoint(i - lines)) || (i - lines == p_line && !shift_first_line)) { - emit_signal("breakpoint_toggled", i); - } - if (i + lines >= text.size() || !text.is_breakpoint(i + lines)) { - emit_signal("breakpoint_toggled", i + lines); - } - } - } - - /* STEP 3: Add spaces if the char is greater than the end of the line. */ + /* STEP 2: Add spaces if the char is greater than the end of the line. */ while (p_char > text[p_line].length()) { text.set(p_line, text[p_line] + String::chr(' ')); } - /* STEP 4: Separate dest string in pre and post text. */ + /* STEP 3: Separate dest string in pre and post text. */ String preinsert_text = text[p_line].substr(0, p_char); String postinsert_text = text[p_line].substr(p_char, text[p_line].size()); @@ -3815,15 +3737,10 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i } if (shift_first_line) { - text.set_breakpoint(p_line + 1, text.is_breakpoint(p_line)); + text.move_gutters(p_line, p_line + 1); text.set_hidden(p_line + 1, text.is_hidden(p_line)); - if (text.has_info_icon(p_line)) { - text.set_info_icon(p_line + 1, text.get_info_icon(p_line), text.get_info(p_line)); - } - text.set_breakpoint(p_line, false); text.set_hidden(p_line, false); - text.set_info_icon(p_line, nullptr, ""); } text.set_line_wrap_amount(p_line, -1); @@ -3837,7 +3754,7 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i } text_changed_dirty = true; } - emit_signal("line_edited_from", p_line); + emit_signal("lines_edited_from", p_line, r_end_line); } String TextEdit::_base_get_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) const { @@ -3874,19 +3791,6 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li String pre_text = text[p_from_line].substr(0, p_from_column); String post_text = text[p_to_line].substr(p_to_column, text[p_to_line].length()); - int lines = p_to_line - p_from_line; - - for (int i = p_from_line + 1; i < text.size(); i++) { - if (text.is_breakpoint(i)) { - if (i + lines >= text.size() || !text.is_breakpoint(i + lines)) { - emit_signal("breakpoint_toggled", i); - } - if (i > p_to_line && (i - lines < 0 || !text.is_breakpoint(i - lines))) { - emit_signal("breakpoint_toggled", i - lines); - } - } - } - for (int i = p_from_line; i < p_to_line; i++) { text.remove(p_from_line + 1); } @@ -3900,7 +3804,7 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li } text_changed_dirty = true; } - emit_signal("line_edited_from", p_from_line); + emit_signal("lines_edited_from", p_to_line, p_from_line); } void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r_end_line, int *r_end_char) { @@ -4094,7 +3998,7 @@ int TextEdit::get_total_visible_rows() const { } void TextEdit::_update_wrap_at() { - wrap_at = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width - cache.minimap_width - wrap_right_offset; + wrap_at = get_size().width - cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding - cache.minimap_width - wrap_right_offset; update_cursor_wrap_offset(); text.clear_wrap_cache(); @@ -4129,7 +4033,7 @@ void TextEdit::adjust_viewport_to_cursor() { set_line_as_last_visible(cur_line, cur_wrap); } - int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width - cache.minimap_width; + int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding - cache.minimap_width; if (v_scroll->is_visible_in_tree()) { visible_width -= v_scroll->get_combined_minimum_size().width; } @@ -4164,7 +4068,7 @@ void TextEdit::center_viewport_to_cursor() { } set_line_as_center_visible(cursor.line, get_cursor_wrap_index()); - int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width - cache.minimap_width; + int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding - cache.minimap_width; if (v_scroll->is_visible_in_tree()) { visible_width -= v_scroll->get_combined_minimum_size().width; } @@ -4248,7 +4152,7 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const { } while (col < line_text.length()) { - CharType c = line_text[col]; + char32_t c = line_text[col]; int w = text.get_char_width(c, line_text[col + 1], px + word_px); int indent_ofs = (cur_wrap_index != 0 ? tab_offset_px : 0); @@ -4456,6 +4360,30 @@ bool TextEdit::is_right_click_moving_caret() const { return right_click_moves_caret; } +TextEdit::SelectionMode TextEdit::get_selection_mode() const { + return selection.selecting_mode; +} + +void TextEdit::set_selection_mode(SelectionMode p_mode, int p_line, int p_column) { + selection.selecting_mode = p_mode; + if (p_line >= 0) { + ERR_FAIL_INDEX(p_line, text.size()); + selection.selecting_line = p_line; + } + if (p_column >= 0) { + ERR_FAIL_INDEX(p_line, text[selection.selecting_line].length()); + selection.selecting_column = p_column; + } +} + +int TextEdit::get_selection_line() const { + return selection.selecting_line; +}; + +int TextEdit::get_selection_column() const { + return selection.selecting_column; +}; + void TextEdit::_v_scroll_input() { scrolling = false; minimap_clicked = false; @@ -4599,7 +4527,7 @@ void TextEdit::insert_text_at_cursor(const String &p_text) { _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); selection.active = false; - selection.selecting_mode = Selection::MODE_NONE; + selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE; } _insert_text_at_cursor(p_text); @@ -4611,54 +4539,41 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { return CURSOR_POINTING_HAND; } - int gutter = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width; if ((completion_active && completion_rect.has_point(p_pos))) { return CURSOR_ARROW; } - if (p_pos.x < gutter) { - int row, col; - _get_mouse_pos(p_pos, row, col); - int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); - // Breakpoint icon. - if (draw_breakpoint_gutter && p_pos.x > left_margin - 6 && p_pos.x <= left_margin + cache.breakpoint_gutter_width - 3) { - return CURSOR_POINTING_HAND; - } + int row, col; + _get_mouse_pos(p_pos, row, col); - // Info icons. - int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.info_gutter_width; - if (draw_info_gutter && p_pos.x > left_margin + cache.breakpoint_gutter_width - 6 && p_pos.x <= gutter_left - 3) { - if (text.has_info_icon(row)) { - return CURSOR_POINTING_HAND; + int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); + int gutter = left_margin + gutters_width; + if (p_pos.x < gutter) { + for (int i = 0; i < gutters.size(); i++) { + if (!gutters[i].draw) { + continue; } - return CURSOR_ARROW; - } - // Fold icon. - if (draw_fold_gutter && p_pos.x > gutter_left + cache.line_number_w - 6 && p_pos.x <= gutter_left + cache.line_number_w + cache.fold_gutter_width - 3) { - if (is_folded(row) || can_fold(row)) { - return CURSOR_POINTING_HAND; - } else { - return CURSOR_ARROW; + if (p_pos.x > left_margin && p_pos.x <= (left_margin + gutters[i].width) - 3) { + if (gutters[i].clickable || is_line_gutter_clickable(row, i)) { + return CURSOR_POINTING_HAND; + } } + left_margin += gutters[i].width; } + return CURSOR_ARROW; + } + int xmargin_end = get_size().width - cache.style_normal->get_margin(MARGIN_RIGHT); + if (draw_minimap && p_pos.x > xmargin_end - minimap_width && p_pos.x <= xmargin_end) { return CURSOR_ARROW; - } else { - int xmargin_end = get_size().width - cache.style_normal->get_margin(MARGIN_RIGHT); - if (draw_minimap && p_pos.x > xmargin_end - minimap_width && p_pos.x <= xmargin_end) { - return CURSOR_ARROW; - } - - int row, col; - _get_mouse_pos(p_pos, row, col); - // EOL fold icon. - if (is_folded(row)) { - int line_width = text.get_line_width(row); - line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width - cursor.x_ofs; - if (p_pos.x > line_width - 3 && p_pos.x <= line_width + cache.folded_eol_icon->get_width() + 3) { - return CURSOR_POINTING_HAND; - } + } + + // EOL fold icon. + if (is_folded(row)) { + gutter += gutter_padding + text.get_line_width(row) - cursor.x_ofs; + if (p_pos.x > gutter - 3 && p_pos.x <= gutter + cache.folded_eol_icon->get_width() + 3) { + return CURSOR_POINTING_HAND; } } @@ -4858,8 +4773,6 @@ void TextEdit::_update_caches() { cache.font = get_theme_font("font"); cache.caret_color = get_theme_color("caret_color"); cache.caret_background_color = get_theme_color("caret_background_color"); - cache.line_number_color = get_theme_color("line_number_color"); - cache.safe_line_number_color = get_theme_color("safe_line_number_color"); cache.font_color = get_theme_color("font_color"); cache.font_color_selected = get_theme_color("font_color_selected"); cache.font_color_readonly = get_theme_color("font_color_readonly"); @@ -4867,9 +4780,6 @@ void TextEdit::_update_caches() { cache.mark_color = get_theme_color("mark_color"); cache.current_line_color = get_theme_color("current_line_color"); cache.line_length_guideline_color = get_theme_color("line_length_guideline_color"); - cache.bookmark_color = get_theme_color("bookmark_color"); - cache.breakpoint_color = get_theme_color("breakpoint_color"); - cache.executing_line_color = get_theme_color("executing_line_color"); cache.code_folding_color = get_theme_color("code_folding_color"); cache.brace_mismatch_color = get_theme_color("brace_mismatch_color"); cache.word_highlighted_color = get_theme_color("word_highlighted_color"); @@ -4884,10 +4794,7 @@ void TextEdit::_update_caches() { cache.row_height = cache.font->get_height() + cache.line_spacing; cache.tab_icon = get_theme_icon("tab"); cache.space_icon = get_theme_icon("space"); - cache.folded_icon = get_theme_icon("folded"); - cache.can_fold_icon = get_theme_icon("fold"); cache.folded_eol_icon = get_theme_icon("GuiEllipsis", "EditorIcons"); - cache.executing_icon = get_theme_icon("MainPlay", "EditorIcons"); text.set_font(cache.font); text.clear_width_cache(); @@ -4896,6 +4803,7 @@ void TextEdit::_update_caches() { } } +/* Syntax Highlighting. */ Ref<SyntaxHighlighter> TextEdit::get_syntax_highlighter() { return syntax_highlighter; } @@ -4908,6 +4816,187 @@ void TextEdit::set_syntax_highlighter(Ref<SyntaxHighlighter> p_syntax_highlighte update(); } +/* Gutters. */ +void TextEdit::_update_gutter_width() { + gutters_width = 0; + for (int i = 0; i < gutters.size(); i++) { + if (gutters[i].draw) { + gutters_width += gutters[i].width; + } + } + if (gutters_width > 0) { + gutter_padding = 2; + } + update(); +} + +void TextEdit::add_gutter(int p_at) { + if (p_at < 0 || p_at > gutters.size()) { + gutters.push_back(GutterInfo()); + } else { + gutters.insert(p_at, GutterInfo()); + } + + for (int i = 0; i < text.size() + 1; i++) { + text.add_gutter(p_at); + } + emit_signal("gutter_added"); + update(); +} + +void TextEdit::remove_gutter(int p_gutter) { + ERR_FAIL_INDEX(p_gutter, gutters.size()); + + gutters.remove(p_gutter); + + for (int i = 0; i < text.size() + 1; i++) { + text.remove_gutter(p_gutter); + } + emit_signal("gutter_removed"); + update(); +} + +int TextEdit::get_gutter_count() const { + return gutters.size(); +} + +void TextEdit::set_gutter_name(int p_gutter, const String &p_name) { + ERR_FAIL_INDEX(p_gutter, gutters.size()); + gutters.write[p_gutter].name = p_name; +} + +String TextEdit::get_gutter_name(int p_gutter) const { + ERR_FAIL_INDEX_V(p_gutter, gutters.size(), ""); + return gutters[p_gutter].name; +} + +void TextEdit::set_gutter_type(int p_gutter, GutterType p_type) { + ERR_FAIL_INDEX(p_gutter, gutters.size()); + gutters.write[p_gutter].type = p_type; + update(); +} + +TextEdit::GutterType TextEdit::get_gutter_type(int p_gutter) const { + ERR_FAIL_INDEX_V(p_gutter, gutters.size(), GUTTER_TYPE_STRING); + return gutters[p_gutter].type; +} + +void TextEdit::set_gutter_width(int p_gutter, int p_width) { + ERR_FAIL_INDEX(p_gutter, gutters.size()); + gutters.write[p_gutter].width = p_width; + _update_gutter_width(); +} + +int TextEdit::get_gutter_width(int p_gutter) const { + ERR_FAIL_INDEX_V(p_gutter, gutters.size(), -1); + return gutters[p_gutter].width; +} + +void TextEdit::set_gutter_draw(int p_gutter, bool p_draw) { + ERR_FAIL_INDEX(p_gutter, gutters.size()); + gutters.write[p_gutter].draw = p_draw; + _update_gutter_width(); +} + +bool TextEdit::is_gutter_drawn(int p_gutter) const { + ERR_FAIL_INDEX_V(p_gutter, gutters.size(), false); + return gutters[p_gutter].draw; +} + +void TextEdit::set_gutter_clickable(int p_gutter, bool p_clickable) { + ERR_FAIL_INDEX(p_gutter, gutters.size()); + gutters.write[p_gutter].clickable = p_clickable; + update(); +} + +bool TextEdit::is_gutter_clickable(int p_gutter) const { + ERR_FAIL_INDEX_V(p_gutter, gutters.size(), false); + return gutters[p_gutter].clickable; +} + +void TextEdit::set_gutter_overwritable(int p_gutter, bool p_overwritable) { + ERR_FAIL_INDEX(p_gutter, gutters.size()); + gutters.write[p_gutter].overwritable = p_overwritable; +} + +bool TextEdit::is_gutter_overwritable(int p_gutter) const { + ERR_FAIL_INDEX_V(p_gutter, gutters.size(), false); + return gutters[p_gutter].overwritable; +} + +void TextEdit::set_gutter_custom_draw(int p_gutter, Object *p_object, const StringName &p_callback) { + ERR_FAIL_INDEX(p_gutter, gutters.size()); + ERR_FAIL_NULL(p_object); + + gutters.write[p_gutter].custom_draw_obj = p_object->get_instance_id(); + gutters.write[p_gutter].custom_draw_callback = p_callback; + update(); +} + +// Line gutters. +void TextEdit::set_line_gutter_metadata(int p_line, int p_gutter, const Variant &p_metadata) { + ERR_FAIL_INDEX(p_line, text.size()); + ERR_FAIL_INDEX(p_gutter, gutters.size()); + text.set_line_gutter_metadata(p_line, p_gutter, p_metadata); +} + +Variant TextEdit::get_line_gutter_metadata(int p_line, int p_gutter) const { + ERR_FAIL_INDEX_V(p_line, text.size(), ""); + ERR_FAIL_INDEX_V(p_gutter, gutters.size(), ""); + return text.get_line_gutter_metadata(p_line, p_gutter); +} + +void TextEdit::set_line_gutter_text(int p_line, int p_gutter, const String &p_text) { + ERR_FAIL_INDEX(p_line, text.size()); + ERR_FAIL_INDEX(p_gutter, gutters.size()); + text.set_line_gutter_text(p_line, p_gutter, p_text); + update(); +} + +String TextEdit::get_line_gutter_text(int p_line, int p_gutter) const { + ERR_FAIL_INDEX_V(p_line, text.size(), ""); + ERR_FAIL_INDEX_V(p_gutter, gutters.size(), ""); + return text.get_line_gutter_text(p_line, p_gutter); +} + +void TextEdit::set_line_gutter_icon(int p_line, int p_gutter, Ref<Texture2D> p_icon) { + ERR_FAIL_INDEX(p_line, text.size()); + ERR_FAIL_INDEX(p_gutter, gutters.size()); + text.set_line_gutter_icon(p_line, p_gutter, p_icon); + update(); +} + +Ref<Texture2D> TextEdit::get_line_gutter_icon(int p_line, int p_gutter) const { + ERR_FAIL_INDEX_V(p_line, text.size(), Ref<Texture2D>()); + ERR_FAIL_INDEX_V(p_gutter, gutters.size(), Ref<Texture2D>()); + return text.get_line_gutter_icon(p_line, p_gutter); +} + +void TextEdit::set_line_gutter_item_color(int p_line, int p_gutter, const Color &p_color) { + ERR_FAIL_INDEX(p_line, text.size()); + ERR_FAIL_INDEX(p_gutter, gutters.size()); + text.set_line_gutter_item_color(p_line, p_gutter, p_color); + update(); +} + +Color TextEdit::get_line_gutter_item_color(int p_line, int p_gutter) { + ERR_FAIL_INDEX_V(p_line, text.size(), Color()); + ERR_FAIL_INDEX_V(p_gutter, gutters.size(), Color()); + return text.get_line_gutter_item_color(p_line, p_gutter); +} + +void TextEdit::set_line_gutter_clickable(int p_line, int p_gutter, bool p_clickable) { + ERR_FAIL_INDEX(p_line, text.size()); + ERR_FAIL_INDEX(p_gutter, gutters.size()); + text.set_line_gutter_clickable(p_line, p_gutter, p_clickable); +} + +bool TextEdit::is_line_gutter_clickable(int p_line, int p_gutter) const { + ERR_FAIL_INDEX_V(p_line, text.size(), false); + ERR_FAIL_INDEX_V(p_gutter, gutters.size(), false); + return text.is_line_gutter_clickable(p_line, p_gutter); +} + void TextEdit::add_keyword(const String &p_keyword) { keywords.insert(p_keyword); } @@ -4947,7 +5036,7 @@ void TextEdit::cut() { cursor_set_column(selection.from_column); selection.active = false; - selection.selecting_mode = Selection::MODE_NONE; + selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE; update(); cut_copy_line = ""; } @@ -4973,7 +5062,7 @@ void TextEdit::paste() { begin_complex_operation(); if (selection.active) { selection.active = false; - selection.selecting_mode = Selection::MODE_NONE; + selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE; _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); cursor_set_line(selection.from_line); cursor_set_column(selection.from_column); @@ -5005,7 +5094,7 @@ void TextEdit::select_all() { selection.selecting_column = 0; selection.to_line = text.size() - 1; selection.to_column = text[selection.to_line].length(); - selection.selecting_mode = Selection::MODE_SHIFT; + selection.selecting_mode = SelectionMode::SELECTION_MODE_SHIFT; selection.shiftclick_left = true; cursor_set_line(selection.to_line, false); cursor_set_column(selection.to_column, false); @@ -5338,106 +5427,6 @@ void TextEdit::set_line_as_marked(int p_line, bool p_marked) { update(); } -void TextEdit::set_line_as_safe(int p_line, bool p_safe) { - ERR_FAIL_INDEX(p_line, text.size()); - text.set_safe(p_line, p_safe); - update(); -} - -bool TextEdit::is_line_set_as_safe(int p_line) const { - ERR_FAIL_INDEX_V(p_line, text.size(), false); - return text.is_safe(p_line); -} - -void TextEdit::set_executing_line(int p_line) { - ERR_FAIL_INDEX(p_line, text.size()); - executing_line = p_line; - update(); -} - -void TextEdit::clear_executing_line() { - executing_line = -1; - update(); -} - -bool TextEdit::is_line_set_as_bookmark(int p_line) const { - ERR_FAIL_INDEX_V(p_line, text.size(), false); - return text.is_bookmark(p_line); -} - -void TextEdit::set_line_as_bookmark(int p_line, bool p_bookmark) { - ERR_FAIL_INDEX(p_line, text.size()); - text.set_bookmark(p_line, p_bookmark); - update(); -} - -void TextEdit::get_bookmarks(List<int> *p_bookmarks) const { - for (int i = 0; i < text.size(); i++) { - if (text.is_bookmark(i)) { - p_bookmarks->push_back(i); - } - } -} - -Array TextEdit::get_bookmarks_array() const { - Array arr; - for (int i = 0; i < text.size(); i++) { - if (text.is_bookmark(i)) { - arr.append(i); - } - } - return arr; -} - -bool TextEdit::is_line_set_as_breakpoint(int p_line) const { - ERR_FAIL_INDEX_V(p_line, text.size(), false); - return text.is_breakpoint(p_line); -} - -void TextEdit::set_line_as_breakpoint(int p_line, bool p_breakpoint) { - ERR_FAIL_INDEX(p_line, text.size()); - text.set_breakpoint(p_line, p_breakpoint); - update(); -} - -void TextEdit::get_breakpoints(List<int> *p_breakpoints) const { - for (int i = 0; i < text.size(); i++) { - if (text.is_breakpoint(i)) { - p_breakpoints->push_back(i); - } - } -} - -Array TextEdit::get_breakpoints_array() const { - Array arr; - for (int i = 0; i < text.size(); i++) { - if (text.is_breakpoint(i)) { - arr.append(i); - } - } - return arr; -} - -void TextEdit::remove_breakpoints() { - for (int i = 0; i < text.size(); i++) { - if (text.is_breakpoint(i)) { - /* Should "breakpoint_toggled" be fired when breakpoints are removed this way? */ - text.set_breakpoint(i, false); - } - } -} - -void TextEdit::set_line_info_icon(int p_line, Ref<Texture2D> p_icon, String p_info) { - ERR_FAIL_INDEX(p_line, text.size()); - text.set_info_icon(p_line, p_icon, p_info); - update(); -} - -void TextEdit::clear_info_icons() { - text.clear_info_icons(); - update(); -} - void TextEdit::set_line_as_hidden(int p_line, bool p_hidden) { ERR_FAIL_INDEX(p_line, text.size()); if (is_hiding_enabled() || !p_hidden) { @@ -6112,9 +6101,9 @@ void TextEdit::_confirm_completion() { // When inserted into the middle of an existing string/method, don't add an unnecessary quote/bracket. String line = text[cursor.line]; - CharType next_char = line[cursor.column]; - CharType last_completion_char = completion_current.insert_text[completion_current.insert_text.length() - 1]; - CharType last_completion_char_display = completion_current.display[completion_current.display.length() - 1]; + char32_t next_char = line[cursor.column]; + char32_t last_completion_char = completion_current.insert_text[completion_current.insert_text.length() - 1]; + char32_t last_completion_char_display = completion_current.display[completion_current.display.length() - 1]; if ((last_completion_char == '"' || last_completion_char == '\'') && (last_completion_char == next_char || last_completion_char_display == next_char)) { _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1); @@ -6158,7 +6147,7 @@ void TextEdit::_cancel_completion() { update(); } -static bool _is_completable(CharType c) { +static bool _is_completable(char32_t c) { return !_is_symbol(c) || c == '"' || c == '\''; } @@ -6289,14 +6278,14 @@ void TextEdit::_update_completion_candidates() { String display_lower = option.display.to_lower(); - const CharType *ssq = &s[0]; - const CharType *ssq_lower = &s_lower[0]; + const char32_t *ssq = &s[0]; + const char32_t *ssq_lower = &s_lower[0]; - const CharType *tgt = &option.display[0]; - const CharType *tgt_lower = &display_lower[0]; + const char32_t *tgt = &option.display[0]; + const char32_t *tgt_lower = &display_lower[0]; - const CharType *ssq_last_tgt = nullptr; - const CharType *ssq_lower_last_tgt = nullptr; + const char32_t *ssq_last_tgt = nullptr; + const char32_t *ssq_lower_last_tgt = nullptr; for (; *tgt; tgt++, tgt_lower++) { if (*ssq == *tgt) { @@ -6413,7 +6402,7 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const { int beg, end; if (select_word(s, col, beg, end)) { bool inside_quotes = false; - CharType selected_quote = '\0'; + char32_t selected_quote = '\0'; int qbegin = 0, qend = 0; for (int i = 0; i < s.length(); i++) { if (s[i] == '"' || s[i] == '\'') { @@ -6468,7 +6457,7 @@ void TextEdit::set_tooltip_request_func(Object *p_obj, const StringName &p_funct } void TextEdit::set_line(int line, String new_text) { - if (line < 0 || line > text.size()) { + if (line < 0 || line >= text.size()) { return; } _remove_text(line, 0, line, text[line].length()); @@ -6499,20 +6488,6 @@ void TextEdit::insert_at(const String &p_text, int at) { } } -void TextEdit::set_show_line_numbers(bool p_show) { - line_numbers = p_show; - update(); -} - -void TextEdit::set_line_numbers_zero_padded(bool p_zero_padded) { - line_numbers_zero_padded = p_zero_padded; - update(); -} - -bool TextEdit::is_show_line_numbers_enabled() const { - return line_numbers; -} - void TextEdit::set_show_line_length_guidelines(bool p_show) { line_length_guidelines = p_show; update(); @@ -6528,69 +6503,6 @@ void TextEdit::set_line_length_guideline_hard_column(int p_column) { update(); } -void TextEdit::set_bookmark_gutter_enabled(bool p_draw) { - draw_bookmark_gutter = p_draw; - update(); -} - -bool TextEdit::is_bookmark_gutter_enabled() const { - return draw_bookmark_gutter; -} - -void TextEdit::set_breakpoint_gutter_enabled(bool p_draw) { - draw_breakpoint_gutter = p_draw; - update(); -} - -bool TextEdit::is_breakpoint_gutter_enabled() const { - return draw_breakpoint_gutter; -} - -void TextEdit::set_breakpoint_gutter_width(int p_gutter_width) { - breakpoint_gutter_width = p_gutter_width; - update(); -} - -int TextEdit::get_breakpoint_gutter_width() const { - return cache.breakpoint_gutter_width; -} - -void TextEdit::set_draw_fold_gutter(bool p_draw) { - draw_fold_gutter = p_draw; - update(); -} - -bool TextEdit::is_drawing_fold_gutter() const { - return draw_fold_gutter; -} - -void TextEdit::set_fold_gutter_width(int p_gutter_width) { - fold_gutter_width = p_gutter_width; - update(); -} - -int TextEdit::get_fold_gutter_width() const { - return cache.fold_gutter_width; -} - -void TextEdit::set_draw_info_gutter(bool p_draw) { - draw_info_gutter = p_draw; - update(); -} - -bool TextEdit::is_drawing_info_gutter() const { - return draw_info_gutter; -} - -void TextEdit::set_info_gutter_width(int p_gutter_width) { - info_gutter_width = p_gutter_width; - update(); -} - -int TextEdit::get_info_gutter_width() const { - return info_gutter_width; -} - void TextEdit::set_draw_minimap(bool p_draw) { draw_minimap = p_draw; update(); @@ -6693,6 +6605,10 @@ void TextEdit::set_shortcut_keys_enabled(bool p_enabled) { _generate_context_menu(); } +void TextEdit::set_virtual_keyboard_enabled(bool p_enable) { + virtual_keyboard_enabled = p_enable; +} + void TextEdit::set_selecting_enabled(bool p_enabled) { selecting_enabled = p_enabled; @@ -6711,6 +6627,10 @@ bool TextEdit::is_shortcut_keys_enabled() const { return shortcut_keys_enabled; } +bool TextEdit::is_virtual_keyboard_enabled() const { + return virtual_keyboard_enabled; +} + PopupMenu *TextEdit::get_menu() const { return menu; } @@ -6725,6 +6645,12 @@ void TextEdit::_bind_methods() { BIND_ENUM_CONSTANT(SEARCH_WHOLE_WORDS); BIND_ENUM_CONSTANT(SEARCH_BACKWARDS); + BIND_ENUM_CONSTANT(SELECTION_MODE_NONE); + BIND_ENUM_CONSTANT(SELECTION_MODE_SHIFT); + BIND_ENUM_CONSTANT(SELECTION_MODE_POINTER); + BIND_ENUM_CONSTANT(SELECTION_MODE_WORD); + BIND_ENUM_CONSTANT(SELECTION_MODE_LINE); + /* ClassDB::bind_method(D_METHOD("delete_char"),&TextEdit::delete_char); ClassDB::bind_method(D_METHOD("delete_line"),&TextEdit::delete_line); @@ -6754,6 +6680,11 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_right_click_moves_caret", "enable"), &TextEdit::set_right_click_moves_caret); ClassDB::bind_method(D_METHOD("is_right_click_moving_caret"), &TextEdit::is_right_click_moving_caret); + ClassDB::bind_method(D_METHOD("get_selection_mode"), &TextEdit::get_selection_mode); + ClassDB::bind_method(D_METHOD("set_selection_mode", "mode", "line", "column"), &TextEdit::set_selection_mode, DEFVAL(-1), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("get_selection_line"), &TextEdit::get_selection_line); + ClassDB::bind_method(D_METHOD("get_selection_column"), &TextEdit::get_selection_column); + ClassDB::bind_method(D_METHOD("set_readonly", "enable"), &TextEdit::set_readonly); ClassDB::bind_method(D_METHOD("is_readonly"), &TextEdit::is_readonly); @@ -6763,6 +6694,8 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &TextEdit::is_context_menu_enabled); ClassDB::bind_method(D_METHOD("set_shortcut_keys_enabled", "enable"), &TextEdit::set_shortcut_keys_enabled); ClassDB::bind_method(D_METHOD("is_shortcut_keys_enabled"), &TextEdit::is_shortcut_keys_enabled); + ClassDB::bind_method(D_METHOD("set_virtual_keyboard_enabled", "enable"), &TextEdit::set_virtual_keyboard_enabled); + ClassDB::bind_method(D_METHOD("is_virtual_keyboard_enabled"), &TextEdit::is_virtual_keyboard_enabled); ClassDB::bind_method(D_METHOD("set_selecting_enabled", "enable"), &TextEdit::set_selecting_enabled); ClassDB::bind_method(D_METHOD("is_selecting_enabled"), &TextEdit::is_selecting_enabled); @@ -6787,16 +6720,10 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("redo"), &TextEdit::redo); ClassDB::bind_method(D_METHOD("clear_undo_history"), &TextEdit::clear_undo_history); - ClassDB::bind_method(D_METHOD("set_show_line_numbers", "enable"), &TextEdit::set_show_line_numbers); - ClassDB::bind_method(D_METHOD("is_show_line_numbers_enabled"), &TextEdit::is_show_line_numbers_enabled); ClassDB::bind_method(D_METHOD("set_draw_tabs"), &TextEdit::set_draw_tabs); ClassDB::bind_method(D_METHOD("is_drawing_tabs"), &TextEdit::is_drawing_tabs); ClassDB::bind_method(D_METHOD("set_draw_spaces"), &TextEdit::set_draw_spaces); ClassDB::bind_method(D_METHOD("is_drawing_spaces"), &TextEdit::is_drawing_spaces); - ClassDB::bind_method(D_METHOD("set_breakpoint_gutter_enabled", "enable"), &TextEdit::set_breakpoint_gutter_enabled); - ClassDB::bind_method(D_METHOD("is_breakpoint_gutter_enabled"), &TextEdit::is_breakpoint_gutter_enabled); - ClassDB::bind_method(D_METHOD("set_draw_fold_gutter"), &TextEdit::set_draw_fold_gutter); - ClassDB::bind_method(D_METHOD("is_drawing_fold_gutter"), &TextEdit::is_drawing_fold_gutter); ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled); ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled); @@ -6819,6 +6746,40 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_syntax_highlighter", "syntax_highlighter"), &TextEdit::set_syntax_highlighter); ClassDB::bind_method(D_METHOD("get_syntax_highlighter"), &TextEdit::get_syntax_highlighter); + /* Gutters. */ + BIND_ENUM_CONSTANT(GUTTER_TYPE_STRING); + BIND_ENUM_CONSTANT(GUTTER_TPYE_ICON); + BIND_ENUM_CONSTANT(GUTTER_TPYE_CUSTOM); + + ClassDB::bind_method(D_METHOD("add_gutter", "at"), &TextEdit::add_gutter, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("remove_gutter", "gutter"), &TextEdit::remove_gutter); + ClassDB::bind_method(D_METHOD("get_gutter_count"), &TextEdit::get_gutter_count); + ClassDB::bind_method(D_METHOD("set_gutter_name", "gutter", "name"), &TextEdit::set_gutter_name); + ClassDB::bind_method(D_METHOD("get_gutter_name", "gutter"), &TextEdit::get_gutter_name); + ClassDB::bind_method(D_METHOD("set_gutter_type", "gutter", "type"), &TextEdit::set_gutter_type); + ClassDB::bind_method(D_METHOD("get_gutter_type", "gutter"), &TextEdit::get_gutter_type); + ClassDB::bind_method(D_METHOD("set_gutter_width", "gutter", "width"), &TextEdit::set_gutter_width); + ClassDB::bind_method(D_METHOD("get_gutter_width", "gutter"), &TextEdit::get_gutter_width); + ClassDB::bind_method(D_METHOD("set_gutter_draw", "gutter", "draw"), &TextEdit::set_gutter_draw); + ClassDB::bind_method(D_METHOD("is_gutter_drawn", "gutter"), &TextEdit::is_gutter_drawn); + ClassDB::bind_method(D_METHOD("set_gutter_clickable", "gutter", "clickable"), &TextEdit::set_gutter_clickable); + ClassDB::bind_method(D_METHOD("is_gutter_clickable", "gutter"), &TextEdit::is_gutter_clickable); + ClassDB::bind_method(D_METHOD("set_gutter_overwritable", "gutter", "overwritable"), &TextEdit::set_gutter_overwritable); + ClassDB::bind_method(D_METHOD("is_gutter_overwritable", "gutter"), &TextEdit::is_gutter_overwritable); + ClassDB::bind_method(D_METHOD("set_gutter_custom_draw", "column", "object", "callback"), &TextEdit::set_gutter_custom_draw); + + // Line gutters. + ClassDB::bind_method(D_METHOD("set_line_gutter_metadata", "line", "gutter", "metadata"), &TextEdit::set_line_gutter_metadata); + ClassDB::bind_method(D_METHOD("get_line_gutter_metadata", "line", "gutter"), &TextEdit::get_line_gutter_metadata); + ClassDB::bind_method(D_METHOD("set_line_gutter_text", "line", "gutter", "text"), &TextEdit::set_line_gutter_text); + ClassDB::bind_method(D_METHOD("get_line_gutter_text", "line", "gutter"), &TextEdit::get_line_gutter_text); + ClassDB::bind_method(D_METHOD("set_line_gutter_icon", "line", "gutter", "icon"), &TextEdit::set_line_gutter_icon); + ClassDB::bind_method(D_METHOD("get_line_gutter_icon", "line", "gutter"), &TextEdit::get_line_gutter_icon); + ClassDB::bind_method(D_METHOD("set_line_gutter_item_color", "line", "gutter", "color"), &TextEdit::set_line_gutter_item_color); + ClassDB::bind_method(D_METHOD("get_line_gutter_item_color", "line", "gutter"), &TextEdit::get_line_gutter_item_color); + ClassDB::bind_method(D_METHOD("set_line_gutter_clickable", "line", "gutter", "clickable"), &TextEdit::set_line_gutter_clickable); + ClassDB::bind_method(D_METHOD("is_line_gutter_clickable", "line", "gutter"), &TextEdit::is_line_gutter_clickable); + ClassDB::bind_method(D_METHOD("set_highlight_current_line", "enabled"), &TextEdit::set_highlight_current_line); ClassDB::bind_method(D_METHOD("is_highlight_current_line_enabled"), &TextEdit::is_highlight_current_line_enabled); @@ -6834,9 +6795,6 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("menu_option", "option"), &TextEdit::menu_option); ClassDB::bind_method(D_METHOD("get_menu"), &TextEdit::get_menu); - ClassDB::bind_method(D_METHOD("get_breakpoints"), &TextEdit::get_breakpoints_array); - ClassDB::bind_method(D_METHOD("remove_breakpoints"), &TextEdit::remove_breakpoints); - ClassDB::bind_method(D_METHOD("draw_minimap", "draw"), &TextEdit::set_draw_minimap); ClassDB::bind_method(D_METHOD("is_drawing_minimap"), &TextEdit::is_drawing_minimap); ClassDB::bind_method(D_METHOD("set_minimap_width", "width"), &TextEdit::set_minimap_width); @@ -6845,15 +6803,13 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT), "set_text", "get_text"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "readonly"), "set_readonly", "is_readonly"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_current_line"), "set_highlight_current_line", "is_highlight_current_line_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_line_numbers"), "set_show_line_numbers", "is_show_line_numbers_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_tabs"), "set_draw_tabs", "is_drawing_tabs"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_spaces"), "set_draw_spaces", "is_drawing_spaces"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "breakpoint_gutter"), "set_breakpoint_gutter_enabled", "is_breakpoint_gutter_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fold_gutter"), "set_draw_fold_gutter", "is_drawing_fold_gutter"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), "set_highlight_all_occurrences", "is_highlight_all_occurrences_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_scrolling"), "set_smooth_scroll_enable", "is_smooth_scroll_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_scroll_speed"), "set_v_scroll_speed", "get_v_scroll_speed"); @@ -6876,11 +6832,12 @@ void TextEdit::_bind_methods() { ADD_SIGNAL(MethodInfo("cursor_changed")); ADD_SIGNAL(MethodInfo("text_changed")); - ADD_SIGNAL(MethodInfo("line_edited_from", PropertyInfo(Variant::INT, "line"))); + ADD_SIGNAL(MethodInfo("lines_edited_from", PropertyInfo(Variant::INT, "from_line"), PropertyInfo(Variant::INT, "to_line"))); ADD_SIGNAL(MethodInfo("request_completion")); - ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::INT, "row"))); + ADD_SIGNAL(MethodInfo("gutter_clicked", PropertyInfo(Variant::INT, "line"), PropertyInfo(Variant::INT, "gutter"))); + ADD_SIGNAL(MethodInfo("gutter_added")); + ADD_SIGNAL(MethodInfo("gutter_removed")); ADD_SIGNAL(MethodInfo("symbol_lookup", PropertyInfo(Variant::STRING, "symbol"), PropertyInfo(Variant::INT, "row"), PropertyInfo(Variant::INT, "column"))); - ADD_SIGNAL(MethodInfo("info_clicked", PropertyInfo(Variant::INT, "row"), PropertyInfo(Variant::STRING, "info"))); ADD_SIGNAL(MethodInfo("symbol_validate", PropertyInfo(Variant::STRING, "symbol"))); BIND_ENUM_CONSTANT(MENU_CUT); @@ -6913,13 +6870,6 @@ TextEdit::TextEdit() { _update_caches(); cache.row_height = 1; cache.line_spacing = 1; - cache.line_number_w = 1; - cache.breakpoint_gutter_width = 0; - breakpoint_gutter_width = 0; - cache.fold_gutter_width = 0; - fold_gutter_width = 0; - info_gutter_width = 0; - cache.info_gutter_width = 0; set_default_cursor_shape(CURSOR_IBEAM); indent_size = 4; @@ -6943,7 +6893,7 @@ TextEdit::TextEdit() { cursor_changed_dirty = false; text_changed_dirty = false; - selection.selecting_mode = Selection::MODE_NONE; + selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE; selection.selecting_line = 0; selection.selecting_column = 0; selection.selecting_text = false; @@ -6983,15 +6933,9 @@ TextEdit::TextEdit() { completion_active = false; completion_line_ofs = 0; tooltip_obj = nullptr; - line_numbers = false; - line_numbers_zero_padded = false; line_length_guidelines = false; line_length_guideline_soft_col = 80; line_length_guideline_hard_col = 100; - draw_bookmark_gutter = false; - draw_breakpoint_gutter = false; - draw_fold_gutter = false; - draw_info_gutter = false; hiding_enabled = false; next_operation_is_complex = false; scroll_past_end_of_file_enabled = false; @@ -7029,8 +6973,6 @@ TextEdit::TextEdit() { set_readonly(false); menu->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); first_draw = true; - - executing_line = -1; } TextEdit::~TextEdit() { diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 5a6ed99845..5cfa70bc55 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -41,28 +41,61 @@ class TextEdit : public Control { GDCLASS(TextEdit, Control); public: + enum GutterType { + GUTTER_TYPE_STRING, + GUTTER_TPYE_ICON, + GUTTER_TPYE_CUSTOM + }; + + enum SelectionMode { + SELECTION_MODE_NONE, + SELECTION_MODE_SHIFT, + SELECTION_MODE_POINTER, + SELECTION_MODE_WORD, + SELECTION_MODE_LINE + }; + +private: + struct GutterInfo { + GutterType type = GutterType::GUTTER_TYPE_STRING; + String name = ""; + int width = 24; + bool draw = true; + bool clickable = false; + bool overwritable = false; + + ObjectID custom_draw_obj = ObjectID(); + StringName custom_draw_callback; + }; + Vector<GutterInfo> gutters; + int gutters_width = 0; + int gutter_padding = 0; + + void _update_gutter_width(); + class Text { public: + struct Gutter { + Variant metadata; + bool clickable = false; + + Ref<Texture2D> icon = Ref<Texture2D>(); + String text = ""; + Color color = Color(1, 1, 1); + }; + struct Line { - int width_cache : 24; - bool marked : 1; - bool breakpoint : 1; - bool bookmark : 1; - bool hidden : 1; - bool safe : 1; - bool has_info : 1; - int wrap_amount_cache : 24; - Ref<Texture2D> info_icon; - String info; + Vector<Gutter> gutters; + + int32_t width_cache; + bool marked; + bool hidden; + int32_t wrap_amount_cache; String data; Line() { width_cache = 0; marked = false; - breakpoint = false; - bookmark = false; hidden = false; - safe = false; - has_info = false; wrap_amount_cache = 0; } }; @@ -70,7 +103,8 @@ public: private: mutable Vector<Line> text; Ref<Font> font; - int indent_size; + int indent_size = 4; + int gutter_count = 0; void _update_line_cache(int p_line) const; @@ -79,44 +113,43 @@ public: void set_font(const Ref<Font> &p_font); int get_line_width(int p_line) const; int get_max_width(bool p_exclude_hidden = false) const; - int get_char_width(CharType c, CharType next_c, int px) const; + int get_char_width(char32_t c, char32_t next_c, int px) const; void set_line_wrap_amount(int p_line, int p_wrap_amount) const; int get_line_wrap_amount(int p_line) const; void set(int p_line, const String &p_text); void set_marked(int p_line, bool p_marked) { text.write[p_line].marked = p_marked; } bool is_marked(int p_line) const { return text[p_line].marked; } - void set_bookmark(int p_line, bool p_bookmark) { text.write[p_line].bookmark = p_bookmark; } - bool is_bookmark(int p_line) const { return text[p_line].bookmark; } - void set_breakpoint(int p_line, bool p_breakpoint) { text.write[p_line].breakpoint = p_breakpoint; } - bool is_breakpoint(int p_line) const { return text[p_line].breakpoint; } void set_hidden(int p_line, bool p_hidden) { text.write[p_line].hidden = p_hidden; } bool is_hidden(int p_line) const { return text[p_line].hidden; } - void set_safe(int p_line, bool p_safe) { text.write[p_line].safe = p_safe; } - bool is_safe(int p_line) const { return text[p_line].safe; } - void set_info_icon(int p_line, Ref<Texture2D> p_icon, String p_info) { - if (p_icon.is_null()) { - text.write[p_line].has_info = false; - return; - } - text.write[p_line].info_icon = p_icon; - text.write[p_line].info = p_info; - text.write[p_line].has_info = true; - } - bool has_info_icon(int p_line) const { return text[p_line].has_info; } - const Ref<Texture2D> &get_info_icon(int p_line) const { return text[p_line].info_icon; } - const String &get_info(int p_line) const { return text[p_line].info; } void insert(int p_at, const String &p_text); void remove(int p_at); int size() const { return text.size(); } void clear(); void clear_width_cache(); void clear_wrap_cache(); - void clear_info_icons(); _FORCE_INLINE_ const String &operator[](int p_line) const { return text[p_line].data; } - Text() { indent_size = 4; } + + /* Gutters. */ + void add_gutter(int p_at); + void remove_gutter(int p_gutter); + void move_gutters(int p_from_line, int p_to_line); + + void set_line_gutter_metadata(int p_line, int p_gutter, const Variant &p_metadata) { text.write[p_line].gutters.write[p_gutter].metadata = p_metadata; } + const Variant &get_line_gutter_metadata(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].metadata; } + + void set_line_gutter_text(int p_line, int p_gutter, const String &p_text) { text.write[p_line].gutters.write[p_gutter].text = p_text; } + const String &get_line_gutter_text(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].text; } + + void set_line_gutter_icon(int p_line, int p_gutter, Ref<Texture2D> p_icon) { text.write[p_line].gutters.write[p_gutter].icon = p_icon; } + const Ref<Texture2D> &get_line_gutter_icon(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].icon; } + + void set_line_gutter_item_color(int p_line, int p_gutter, const Color &p_color) { text.write[p_line].gutters.write[p_gutter].color = p_color; } + const Color &get_line_gutter_item_color(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].color; } + + void set_line_gutter_clickable(int p_line, int p_gutter, bool p_clickable) { text.write[p_line].gutters.write[p_gutter].clickable = p_clickable; } + bool is_line_gutter_clickable(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].clickable; } }; -private: struct Cursor { int last_fit_x; int line, column; ///< cursor @@ -132,16 +165,7 @@ private: } cursor; struct Selection { - enum Mode { - - MODE_NONE, - MODE_SHIFT, - MODE_POINTER, - MODE_WORD, - MODE_LINE - }; - - Mode selecting_mode; + SelectionMode selecting_mode; int selecting_line, selecting_column; int selected_word_beg, selected_word_end, selected_word_origin; bool selecting_text; @@ -153,7 +177,7 @@ private: bool shiftclick_left; Selection() { - selecting_mode = MODE_NONE; + selecting_mode = SelectionMode::SELECTION_MODE_NONE; selecting_line = 0; selecting_column = 0; selected_word_beg = 0; @@ -169,60 +193,6 @@ private: } } selection; - struct Cache { - Ref<Texture2D> tab_icon; - Ref<Texture2D> space_icon; - Ref<Texture2D> can_fold_icon; - Ref<Texture2D> folded_icon; - Ref<Texture2D> folded_eol_icon; - Ref<Texture2D> executing_icon; - Ref<StyleBox> style_normal; - Ref<StyleBox> style_focus; - Ref<StyleBox> style_readonly; - Ref<Font> font; - Color completion_background_color; - Color completion_selected_color; - Color completion_existing_color; - Color completion_font_color; - Color caret_color; - Color caret_background_color; - Color line_number_color; - Color safe_line_number_color; - Color font_color; - Color font_color_selected; - Color font_color_readonly; - Color selection_color; - Color mark_color; - Color bookmark_color; - Color breakpoint_color; - Color executing_line_color; - Color code_folding_color; - Color current_line_color; - Color line_length_guideline_color; - Color brace_mismatch_color; - Color word_highlighted_color; - Color search_result_color; - Color search_result_border_color; - Color background_color; - - int row_height; - int line_spacing; - int line_number_w; - int breakpoint_gutter_width; - int fold_gutter_width; - int info_gutter_width; - int minimap_width; - Cache() { - row_height = 0; - line_spacing = 0; - line_number_w = 0; - breakpoint_gutter_width = 0; - fold_gutter_width = 0; - info_gutter_width = 0; - minimap_width = 0; - } - } cache; - Map<int, Dictionary> syntax_highlighting_cache; struct TextOperation { @@ -318,19 +288,10 @@ private: bool cursor_changed_dirty; bool text_changed_dirty; bool undo_enabled; - bool line_numbers; - bool line_numbers_zero_padded; bool line_length_guidelines; int line_length_guideline_soft_col; int line_length_guideline_hard_col; - bool draw_bookmark_gutter; - bool draw_breakpoint_gutter; - int breakpoint_gutter_width; - bool draw_fold_gutter; - int fold_gutter_width; bool hiding_enabled; - bool draw_info_gutter; - int info_gutter_width; bool draw_minimap; int minimap_width; Point2 minimap_char_size; @@ -385,8 +346,7 @@ private: bool context_menu_enabled; bool shortcut_keys_enabled; - - int executing_line; + bool virtual_keyboard_enabled = true; void _generate_context_menu(); @@ -445,8 +405,6 @@ private: Size2 get_minimum_size() const override; int _get_control_height() const; - int get_row_height() const; - void _reset_caret_blink_timer(); void _toggle_draw_caret(); @@ -478,6 +436,44 @@ private: int _calculate_spaces_till_next_right_indent(int column); protected: + struct Cache { + Ref<Texture2D> tab_icon; + Ref<Texture2D> space_icon; + Ref<Texture2D> folded_eol_icon; + Ref<StyleBox> style_normal; + Ref<StyleBox> style_focus; + Ref<StyleBox> style_readonly; + Ref<Font> font; + Color completion_background_color; + Color completion_selected_color; + Color completion_existing_color; + Color completion_font_color; + Color caret_color; + Color caret_background_color; + Color font_color; + Color font_color_selected; + Color font_color_readonly; + Color selection_color; + Color mark_color; + Color code_folding_color; + Color current_line_color; + Color line_length_guideline_color; + Color brace_mismatch_color; + Color word_highlighted_color; + Color search_result_color; + Color search_result_border_color; + Color background_color; + + int row_height; + int line_spacing; + int minimap_width; + Cache() { + row_height = 0; + line_spacing = 0; + minimap_width = 0; + } + } cache; + virtual String get_tooltip(const Point2 &p_pos) const override; void _insert_text(int p_line, int p_char, const String &p_text, int *r_end_line = nullptr, int *r_end_char = nullptr); @@ -486,15 +482,57 @@ protected: void _gui_input(const Ref<InputEvent> &p_gui_input); void _notification(int p_what); - void _consume_pair_symbol(CharType ch); + void _consume_pair_symbol(char32_t ch); void _consume_backspace_for_pair_symbol(int prev_line, int prev_column); static void _bind_methods(); public: + /* Syntax Highlighting. */ Ref<SyntaxHighlighter> get_syntax_highlighter(); void set_syntax_highlighter(Ref<SyntaxHighlighter> p_syntax_highlighter); + /* Gutters. */ + void add_gutter(int p_at = -1); + void remove_gutter(int p_gutter); + int get_gutter_count() const; + + void set_gutter_name(int p_gutter, const String &p_name); + String get_gutter_name(int p_gutter) const; + + void set_gutter_type(int p_gutter, GutterType p_type); + GutterType get_gutter_type(int p_gutter) const; + + void set_gutter_width(int p_gutter, int p_width); + int get_gutter_width(int p_gutter) const; + + void set_gutter_draw(int p_gutter, bool p_draw); + bool is_gutter_drawn(int p_gutter) const; + + void set_gutter_clickable(int p_gutter, bool p_clickable); + bool is_gutter_clickable(int p_gutter) const; + + void set_gutter_overwritable(int p_gutter, bool p_overwritable); + bool is_gutter_overwritable(int p_gutter) const; + + void set_gutter_custom_draw(int p_gutter, Object *p_object, const StringName &p_callback); + + // Line gutters. + void set_line_gutter_metadata(int p_line, int p_gutter, const Variant &p_metadata); + Variant get_line_gutter_metadata(int p_line, int p_gutter) const; + + void set_line_gutter_text(int p_line, int p_gutter, const String &p_text); + String get_line_gutter_text(int p_line, int p_gutter) const; + + void set_line_gutter_icon(int p_line, int p_gutter, Ref<Texture2D> p_icon); + Ref<Texture2D> get_line_gutter_icon(int p_line, int p_gutter) const; + + void set_line_gutter_item_color(int p_line, int p_gutter, const Color &p_color); + Color get_line_gutter_item_color(int p_line, int p_gutter); + + void set_line_gutter_clickable(int p_line, int p_gutter, bool p_clickable); + bool is_line_gutter_clickable(int p_line, int p_gutter) const; + enum MenuItems { MENU_CUT, MENU_COPY, @@ -532,22 +570,6 @@ public: void insert_at(const String &p_text, int at); int get_line_count() const; void set_line_as_marked(int p_line, bool p_marked); - void set_line_as_bookmark(int p_line, bool p_bookmark); - bool is_line_set_as_bookmark(int p_line) const; - void get_bookmarks(List<int> *p_bookmarks) const; - Array get_bookmarks_array() const; - void set_line_as_breakpoint(int p_line, bool p_breakpoint); - bool is_line_set_as_breakpoint(int p_line) const; - void set_executing_line(int p_line); - void clear_executing_line(); - void set_line_as_safe(int p_line, bool p_safe); - bool is_line_set_as_safe(int p_line) const; - void get_breakpoints(List<int> *p_breakpoints) const; - Array get_breakpoints_array() const; - void remove_breakpoints(); - - void set_line_info_icon(int p_line, Ref<Texture2D> p_icon, String p_info = ""); - void clear_info_icons(); void set_line_as_hidden(int p_line, bool p_hidden); bool is_line_hidden(int p_line) const; @@ -567,6 +589,7 @@ public: String get_text(); String get_line(int line) const; void set_line(int line, String new_text); + int get_row_height() const; void backspace_at_cursor(); void indent_left(); @@ -612,6 +635,11 @@ public: void set_right_click_moves_caret(bool p_enable); bool is_right_click_moving_caret() const; + SelectionMode get_selection_mode() const; + void set_selection_mode(SelectionMode p_mode, int p_line = -1, int p_column = -1); + int get_selection_line() const; + int get_selection_column() const; + void set_readonly(bool p_readonly); bool is_readonly() const; @@ -688,39 +716,13 @@ public: void menu_option(int p_option); - void set_show_line_numbers(bool p_show); - bool is_show_line_numbers_enabled() const; - void set_highlight_current_line(bool p_enabled); bool is_highlight_current_line_enabled() const; - void set_line_numbers_zero_padded(bool p_zero_padded); - void set_show_line_length_guidelines(bool p_show); void set_line_length_guideline_soft_column(int p_column); void set_line_length_guideline_hard_column(int p_column); - void set_bookmark_gutter_enabled(bool p_draw); - bool is_bookmark_gutter_enabled() const; - - void set_breakpoint_gutter_enabled(bool p_draw); - bool is_breakpoint_gutter_enabled() const; - - void set_breakpoint_gutter_width(int p_gutter_width); - int get_breakpoint_gutter_width() const; - - void set_draw_fold_gutter(bool p_draw); - bool is_drawing_fold_gutter() const; - - void set_fold_gutter_width(int p_gutter_width); - int get_fold_gutter_width() const; - - void set_draw_info_gutter(bool p_draw); - bool is_drawing_info_gutter() const; - - void set_info_gutter_width(int p_gutter_width); - int get_info_gutter_width() const; - void set_draw_minimap(bool p_draw); bool is_drawing_minimap() const; @@ -749,6 +751,9 @@ public: void set_shortcut_keys_enabled(bool p_enabled); bool is_shortcut_keys_enabled() const; + void set_virtual_keyboard_enabled(bool p_enable); + bool is_virtual_keyboard_enabled() const; + PopupMenu *get_menu() const; String get_text_for_completion(); @@ -759,6 +764,8 @@ public: ~TextEdit(); }; +VARIANT_ENUM_CAST(TextEdit::GutterType); +VARIANT_ENUM_CAST(TextEdit::SelectionMode); VARIANT_ENUM_CAST(TextEdit::MenuItems); VARIANT_ENUM_CAST(TextEdit::SearchFlags); diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp index 484b14d11c..e0d98d1c22 100644 --- a/scene/gui/texture_progress.cpp +++ b/scene/gui/texture_progress.cpp @@ -30,7 +30,7 @@ #include "texture_progress.h" -#include "core/engine.h" +#include "core/config/engine.h" void TextureProgress::set_under_texture(const Ref<Texture2D> &p_texture) { under = p_texture; diff --git a/scene/gui/texture_rect.h b/scene/gui/texture_rect.h index efd3f0698a..e39545f679 100644 --- a/scene/gui/texture_rect.h +++ b/scene/gui/texture_rect.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef TEXTURE_FRAME_H -#define TEXTURE_FRAME_H +#ifndef TEXTURE_RECT_H +#define TEXTURE_RECT_H #include "scene/gui/control.h" @@ -83,4 +83,5 @@ public: }; VARIANT_ENUM_CAST(TextureRect::StretchMode); -#endif // TEXTURE_FRAME_H + +#endif // TEXTURE_RECT_H diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 5057f84192..bcb375d786 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -30,12 +30,12 @@ #include "tree.h" +#include "core/config/project_settings.h" #include "core/input/input.h" #include "core/math/math_funcs.h" #include "core/os/keyboard.h" #include "core/os/os.h" -#include "core/print_string.h" -#include "core/project_settings.h" +#include "core/string/print_string.h" #include "scene/main/window.h" #include "box_container.h" @@ -1173,6 +1173,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (p_item->cells[i].text.size() > 0) { float icon_width = p_item->cells[i].get_icon_size().width; + if (p_item->get_icon_max_width(i) > 0) { + icon_width = p_item->get_icon_max_width(i); + } r.position.x += icon_width; r.size.x -= icon_width; } @@ -1208,8 +1211,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (drop_mode_flags && drop_mode_over == p_item) { Rect2 r = cell_rect; + bool has_parent = p_item->get_children() != nullptr; - if (drop_mode_section == -1 || drop_mode_section == 0) { + if (drop_mode_section == -1 || has_parent || drop_mode_section == 0) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), cache.drop_position_color); } @@ -1218,7 +1222,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x + r.size.x - 1, r.position.y, 1, r.size.y), cache.drop_position_color); } - if (drop_mode_section == 1 || drop_mode_section == 0) { + if ((drop_mode_section == 1 && !has_parent) || drop_mode_section == 0) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y, r.size.x, 1), cache.drop_position_color); } } @@ -2403,11 +2407,16 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { cache.hover_cell = col; if (it != old_it || col != old_col) { - // Only need to update if mouse enters/exits a button - bool was_over_button = old_it && old_it->cells[old_col].custom_button; - bool is_over_button = it && it->cells[col].custom_button; - if (was_over_button || is_over_button) { + if (old_it && old_col >= old_it->cells.size()) { + // Columns may have changed since last update(). update(); + } else { + // Only need to update if mouse enters/exits a button + bool was_over_button = old_it && old_it->cells[old_col].custom_button; + bool is_over_button = it && it->cells[col].custom_button; + if (was_over_button || is_over_button) { + update(); + } } } } @@ -3886,7 +3895,7 @@ Tree::Tree() { popup_menu = memnew(PopupMenu); popup_menu->hide(); add_child(popup_menu); - // popup_menu->set_as_toplevel(true); + // popup_menu->set_as_top_level(true); popup_editor = memnew(Popup); popup_editor->set_wrap_controls(true); diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index d6d1134cc9..e6c35352f5 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -31,8 +31,8 @@ #include "canvas_item.h" #include "core/input/input.h" -#include "core/message_queue.h" -#include "core/method_bind_ext.gen.inc" +#include "core/object/message_queue.h" +#include "scene/2d/canvas_group.h" #include "scene/main/canvas_layer.h" #include "scene/main/viewport.h" #include "scene/main/window.h" @@ -371,7 +371,7 @@ void CanvasItem::_propagate_visibility_changed(bool p_visible) { for (int i = 0; i < get_child_count(); i++) { CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i)); - if (c && c->visible) { //should the toplevels stop propagation? i think so but.. + if (c && c->visible) { //should the top_levels stop propagation? i think so but.. c->_propagate_visibility_changed(p_visible); } } @@ -486,7 +486,7 @@ Transform2D CanvasItem::get_global_transform() const { return global_transform; } -void CanvasItem::_toplevel_raise_self() { +void CanvasItem::_top_level_raise_self() { if (!is_inside_tree()) { return; } @@ -499,7 +499,7 @@ void CanvasItem::_toplevel_raise_self() { } void CanvasItem::_enter_canvas() { - if ((!Object::cast_to<CanvasItem>(get_parent())) || toplevel) { + if ((!Object::cast_to<CanvasItem>(get_parent())) || top_level) { Node *n = this; canvas_layer = nullptr; @@ -533,7 +533,7 @@ void CanvasItem::_enter_canvas() { get_viewport()->gui_reset_canvas_sort_index(); } - get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_toplevel_raise_self"); + get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_top_level_raise_self"); } else { CanvasItem *parent = get_parent_item(); @@ -599,7 +599,7 @@ void CanvasItem::_notification(int p_what) { } if (group != "") { - get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_toplevel_raise_self"); + get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_top_level_raise_self"); } else { CanvasItem *p = get_parent_item(); ERR_FAIL_COND(!p); @@ -674,27 +674,29 @@ Color CanvasItem::get_modulate() const { return modulate; } -void CanvasItem::set_as_toplevel(bool p_toplevel) { - if (toplevel == p_toplevel) { +void CanvasItem::set_as_top_level(bool p_top_level) { + if (top_level == p_top_level) { return; } if (!is_inside_tree()) { - toplevel = p_toplevel; + top_level = p_top_level; return; } _exit_canvas(); - toplevel = p_toplevel; + top_level = p_top_level; _enter_canvas(); + + _notify_transform(); } -bool CanvasItem::is_set_as_toplevel() const { - return toplevel; +bool CanvasItem::is_set_as_top_level() const { + return top_level; } CanvasItem *CanvasItem::get_parent_item() const { - if (toplevel) { + if (top_level) { return nullptr; } @@ -832,25 +834,25 @@ void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color); } -void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) { +void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); ERR_FAIL_COND(p_texture.is_null()); - p_texture->draw(canvas_item, p_pos, p_modulate, false, p_normal_map, p_specular_map, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat)); + p_texture->draw(canvas_item, p_pos, p_modulate, false); } -void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) { +void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); ERR_FAIL_COND(p_texture.is_null()); - p_texture->draw_rect(canvas_item, p_rect, p_tile, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat)); + p_texture->draw_rect(canvas_item, p_rect, p_tile, p_modulate, p_transpose); } -void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, bool p_clip_uv, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) { +void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); ERR_FAIL_COND(p_texture.is_null()); - p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat), p_clip_uv); + p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_clip_uv); } void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) { @@ -861,14 +863,11 @@ void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p p_style_box->draw(canvas_item, p_rect); } -void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, float p_width, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) { +void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, float p_width) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); - RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - - RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width, rid_normal, rid_specular, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat)); + RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width); } void CanvasItem::draw_set_transform(const Point2 &p_offset, float p_rot, const Size2 &p_scale) { @@ -885,44 +884,34 @@ void CanvasItem::draw_set_transform_matrix(const Transform2D &p_matrix) { RenderingServer::get_singleton()->canvas_item_add_set_transform(canvas_item, p_matrix); } -void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) { +void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); - RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, rid, rid_normal, rid_specular, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat)); + RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, rid); } -void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) { +void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); Vector<Color> colors; colors.push_back(p_color); RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); - RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - - RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid, rid_normal, rid_specular, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat)); + RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid); } -void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, const Transform2D &p_transform, const Color &p_modulate, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) { +void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Transform2D &p_transform, const Color &p_modulate) { ERR_FAIL_COND(p_mesh.is_null()); RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); - RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_map_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), p_transform, p_modulate, texture_rid, normal_map_rid, specular_map_rid, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat)); + RenderingServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), p_transform, p_modulate, texture_rid); } -void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) { +void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture) { ERR_FAIL_COND(p_multimesh.is_null()); RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); - RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_map_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - - RenderingServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid, normal_map_rid, specular_map_rid, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat)); + RenderingServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid); } void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate, int p_clip_w) { @@ -939,9 +928,9 @@ float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const ERR_FAIL_COND_V(p_font.is_null(), 0); if (p_font->has_outline()) { - p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], Color(1, 1, 1), true); + p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.get_data()[0], Color(1, 1, 1), true); } - return p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], p_modulate); + return p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.get_data()[0], p_modulate); } void CanvasItem::_notify_transform(CanvasItem *p_node) { @@ -967,7 +956,7 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) { for (List<CanvasItem *>::Element *E = p_node->children_items.front(); E; E = E->next()) { CanvasItem *ci = E->get(); - if (ci->toplevel) { + if (ci->top_level) { continue; } _notify_transform(ci); @@ -997,9 +986,9 @@ ObjectID CanvasItem::get_canvas_layer_instance_id() const { } } -CanvasItem *CanvasItem::get_toplevel() const { +CanvasItem *CanvasItem::get_top_level() const { CanvasItem *ci = const_cast<CanvasItem *>(this); - while (!ci->toplevel && Object::cast_to<CanvasItem>(ci->get_parent())) { + while (!ci->top_level && Object::cast_to<CanvasItem>(ci->get_parent())) { ci = Object::cast_to<CanvasItem>(ci->get_parent()); } @@ -1009,7 +998,7 @@ CanvasItem *CanvasItem::get_toplevel() const { Ref<World2D> CanvasItem::get_world_2d() const { ERR_FAIL_COND_V(!is_inside_tree(), Ref<World2D>()); - CanvasItem *tl = get_toplevel(); + CanvasItem *tl = get_top_level(); if (tl->get_viewport()) { return tl->get_viewport()->find_world_2d(); @@ -1104,7 +1093,7 @@ void CanvasItem::force_update_transform() { } void CanvasItem::_bind_methods() { - ClassDB::bind_method(D_METHOD("_toplevel_raise_self"), &CanvasItem::_toplevel_raise_self); + ClassDB::bind_method(D_METHOD("_top_level_raise_self"), &CanvasItem::_top_level_raise_self); ClassDB::bind_method(D_METHOD("_update_callback"), &CanvasItem::_update_callback); #ifdef TOOLS_ENABLED @@ -1136,8 +1125,8 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("update"), &CanvasItem::update); - ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &CanvasItem::set_as_toplevel); - ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &CanvasItem::is_set_as_toplevel); + ClassDB::bind_method(D_METHOD("set_as_top_level", "enable"), &CanvasItem::set_as_top_level); + ClassDB::bind_method(D_METHOD("is_set_as_top_level"), &CanvasItem::is_set_as_top_level); ClassDB::bind_method(D_METHOD("set_light_mask", "light_mask"), &CanvasItem::set_light_mask); ClassDB::bind_method(D_METHOD("get_light_mask"), &CanvasItem::get_light_mask); @@ -1162,17 +1151,17 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle); - ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE)); - ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE)); - ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "normal_map", "specular_map", "specular_shininess", "clip_uv", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(true), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE)); + ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1))); + ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box); - ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE)); - ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE)); - ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_colored_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE)); + ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0)); + ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>())); + ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture"), &CanvasItem::draw_colored_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>())); ClassDB::bind_method(D_METHOD("draw_string", "font", "position", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("draw_char", "font", "position", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1, 1))); - ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "specular_map", "specular_shininess", "transform", "modulate", "texture_filter", "texture_repeat"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE)); - ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_multimesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE)); + ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "transform", "modulate"), &CanvasItem::draw_mesh, DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1, 1))); + ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture"), &CanvasItem::draw_multimesh); ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform, DEFVAL(0.0), DEFVAL(Size2(1.0, 1.0))); ClassDB::bind_method(D_METHOD("draw_set_transform_matrix", "xform"), &CanvasItem::draw_set_transform_matrix); @@ -1211,6 +1200,9 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture_repeat", "mode"), &CanvasItem::set_texture_repeat); ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasItem::get_texture_repeat); + ClassDB::bind_method(D_METHOD("set_clip_children", "enable"), &CanvasItem::set_clip_children); + ClassDB::bind_method(D_METHOD("is_clipping_children"), &CanvasItem::is_clipping_children); + BIND_VMETHOD(MethodInfo("_draw")); ADD_GROUP("Visibility", ""); @@ -1218,7 +1210,9 @@ void CanvasItem::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_on_top", PROPERTY_HINT_NONE, "", 0), "_set_on_top", "_is_on_top"); //compatibility + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_children"), "set_clip_children", "is_clipping_children"); ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask"); ADD_GROUP("Texture", "texture_"); @@ -1228,8 +1222,6 @@ void CanvasItem::_bind_methods() { ADD_GROUP("Material", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material"); - //exporting these things doesn't really make much sense i think - // ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toplevel", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_as_toplevel", "is_set_as_toplevel"); // ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),"set_transform_notify","is_transform_notify_enabled"); ADD_SIGNAL(MethodInfo("draw")); @@ -1329,23 +1321,7 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) { if (parent_item) { texture_filter_cache = parent_item->texture_filter_cache; } else { - //from viewport - switch (get_viewport()->get_default_canvas_item_texture_filter()) { - case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST: - texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST; - break; - case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR: - texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; - break; - case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: - texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS; - break; - case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: - texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS; - break; - default: { - } - } + texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT; } } else { texture_filter_cache = RS::CanvasItemTextureFilter(texture_filter); @@ -1355,7 +1331,7 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) { if (p_propagate) { for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) { - if (!E->get()->toplevel && E->get()->texture_filter == TEXTURE_FILTER_PARENT_NODE) { + if (!E->get()->top_level && E->get()->texture_filter == TEXTURE_FILTER_PARENT_NODE) { E->get()->_update_texture_filter_changed(true); } } @@ -1369,6 +1345,7 @@ void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) { } texture_filter = p_texture_filter; _update_texture_filter_changed(true); + _change_notify(); } CanvasItem::TextureFilter CanvasItem::get_texture_filter() const { @@ -1385,20 +1362,7 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) { if (parent_item) { texture_repeat_cache = parent_item->texture_repeat_cache; } else { - //from viewport - switch (get_viewport()->get_default_canvas_item_texture_repeat()) { - case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: - texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; - break; - case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: - texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED; - break; - case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: - texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR; - break; - default: { - } - } + texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT; } } else { texture_repeat_cache = RS::CanvasItemTextureRepeat(texture_repeat); @@ -1407,7 +1371,7 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) { update(); if (p_propagate) { for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) { - if (!E->get()->toplevel && E->get()->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) { + if (!E->get()->top_level && E->get()->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) { E->get()->_update_texture_repeat_changed(true); } } @@ -1421,6 +1385,23 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) { } texture_repeat = p_texture_repeat; _update_texture_repeat_changed(true); + _change_notify(); +} + +void CanvasItem::set_clip_children(bool p_enabled) { + if (clip_children == p_enabled) { + return; + } + clip_children = p_enabled; + + if (Object::cast_to<CanvasGroup>(this) != nullptr) { + //avoid accidental bugs, make this not work on CanvasGroup + return; + } + RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), clip_children ? RS::CANVAS_GROUP_MODE_OPAQUE : RS::CANVAS_GROUP_MODE_DISABLED); +} +bool CanvasItem::is_clipping_children() const { + return clip_children; } CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const { @@ -1435,10 +1416,11 @@ CanvasItem::CanvasItem() : pending_update = false; modulate = Color(1, 1, 1, 1); self_modulate = Color(1, 1, 1, 1); - toplevel = false; + top_level = false; first_draw = false; drawing = false; behind = false; + clip_children = false; block_transform_notify = false; canvas_layer = nullptr; use_parent_material = false; @@ -1457,3 +1439,154 @@ CanvasItem::CanvasItem() : CanvasItem::~CanvasItem() { RenderingServer::get_singleton()->free(canvas_item); } + +/////////////////////////////////////////////////////////////////// + +void CanvasTexture::set_diffuse_texture(const Ref<Texture2D> &p_diffuse) { + ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_diffuse.ptr()) != nullptr, "Cant self-assign a CanvasTexture"); + diffuse_texture = p_diffuse; + + RID tex_rid = diffuse_texture.is_valid() ? diffuse_texture->get_rid() : RID(); + RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_DIFFUSE, tex_rid); + emit_changed(); +} +Ref<Texture2D> CanvasTexture::get_diffuse_texture() const { + return diffuse_texture; +} + +void CanvasTexture::set_normal_texture(const Ref<Texture2D> &p_normal) { + ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_normal.ptr()) != nullptr, "Cant self-assign a CanvasTexture"); + normal_texture = p_normal; + RID tex_rid = normal_texture.is_valid() ? normal_texture->get_rid() : RID(); + RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_NORMAL, tex_rid); +} +Ref<Texture2D> CanvasTexture::get_normal_texture() const { + return normal_texture; +} + +void CanvasTexture::set_specular_texture(const Ref<Texture2D> &p_specular) { + ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_specular.ptr()) != nullptr, "Cant self-assign a CanvasTexture"); + specular_texture = p_specular; + RID tex_rid = specular_texture.is_valid() ? specular_texture->get_rid() : RID(); + RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_SPECULAR, tex_rid); +} +Ref<Texture2D> CanvasTexture::get_specular_texture() const { + return specular_texture; +} + +void CanvasTexture::set_specular_color(const Color &p_color) { + specular = p_color; + RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess); +} +Color CanvasTexture::get_specular_color() const { + return specular; +} + +void CanvasTexture::set_specular_shininess(float p_shininess) { + shininess = p_shininess; + RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess); +} +float CanvasTexture::get_specular_shininess() const { + return shininess; +} + +void CanvasTexture::set_texture_filter(CanvasItem::TextureFilter p_filter) { + texture_filter = p_filter; + RS::get_singleton()->canvas_texture_set_texture_filter(canvas_texture, RS::CanvasItemTextureFilter(p_filter)); +} +CanvasItem::TextureFilter CanvasTexture::get_texture_filter() const { + return texture_filter; +} + +void CanvasTexture::set_texture_repeat(CanvasItem::TextureRepeat p_repeat) { + texture_repeat = p_repeat; + RS::get_singleton()->canvas_texture_set_texture_repeat(canvas_texture, RS::CanvasItemTextureRepeat(p_repeat)); +} +CanvasItem::TextureRepeat CanvasTexture::get_texture_repeat() const { + return texture_repeat; +} + +int CanvasTexture::get_width() const { + if (diffuse_texture.is_valid()) { + return diffuse_texture->get_width(); + } else { + return 1; + } +} +int CanvasTexture::get_height() const { + if (diffuse_texture.is_valid()) { + return diffuse_texture->get_height(); + } else { + return 1; + } +} + +bool CanvasTexture::is_pixel_opaque(int p_x, int p_y) const { + if (diffuse_texture.is_valid()) { + return diffuse_texture->is_pixel_opaque(p_x, p_y); + } else { + return false; + } +} + +bool CanvasTexture::has_alpha() const { + if (diffuse_texture.is_valid()) { + return diffuse_texture->has_alpha(); + } else { + return false; + } +} + +Ref<Image> CanvasTexture::get_data() const { + if (diffuse_texture.is_valid()) { + return diffuse_texture->get_data(); + } else { + return Ref<Image>(); + } +} + +RID CanvasTexture::get_rid() const { + return canvas_texture; +} + +void CanvasTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_diffuse_texture", "texture"), &CanvasTexture::set_diffuse_texture); + ClassDB::bind_method(D_METHOD("get_diffuse_texture"), &CanvasTexture::get_diffuse_texture); + + ClassDB::bind_method(D_METHOD("set_normal_texture", "texture"), &CanvasTexture::set_normal_texture); + ClassDB::bind_method(D_METHOD("get_normal_texture"), &CanvasTexture::get_normal_texture); + + ClassDB::bind_method(D_METHOD("set_specular_texture", "texture"), &CanvasTexture::set_specular_texture); + ClassDB::bind_method(D_METHOD("get_specular_texture"), &CanvasTexture::get_specular_texture); + + ClassDB::bind_method(D_METHOD("set_specular_color", "color"), &CanvasTexture::set_specular_color); + ClassDB::bind_method(D_METHOD("get_specular_color"), &CanvasTexture::get_specular_color); + + ClassDB::bind_method(D_METHOD("set_specular_shininess", "shininess"), &CanvasTexture::set_specular_shininess); + ClassDB::bind_method(D_METHOD("get_specular_shininess"), &CanvasTexture::get_specular_shininess); + + ClassDB::bind_method(D_METHOD("set_texture_filter", "filter"), &CanvasTexture::set_texture_filter); + ClassDB::bind_method(D_METHOD("get_texture_filter"), &CanvasTexture::get_texture_filter); + + ClassDB::bind_method(D_METHOD("set_texture_repeat", "repeat"), &CanvasTexture::set_texture_repeat); + ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasTexture::get_texture_repeat); + + ADD_GROUP("Diffuse", "diffuse_"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "diffuse_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_diffuse_texture", "get_diffuse_texture"); + ADD_GROUP("Normalmap", "normal_"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_texture", "get_normal_texture"); + ADD_GROUP("Specular", "specular_"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "specular_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_specular_texture", "get_specular_texture"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "specular_shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_specular_shininess", "get_specular_shininess"); + ADD_GROUP("Texture", "texture_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat"); +} + +CanvasTexture::CanvasTexture() { + canvas_texture = RS::get_singleton()->canvas_texture_create(); +} +CanvasTexture::~CanvasTexture() { + RS::get_singleton()->free(canvas_texture); +} diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index d9ffe770ff..412ef8079b 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -200,8 +200,9 @@ private: Window *window; bool first_draw; bool visible; + bool clip_children; bool pending_update; - bool toplevel; + bool top_level; bool drawing; bool block_transform_notify; bool behind; @@ -220,7 +221,7 @@ private: mutable Transform2D global_transform; mutable bool global_invalid; - void _toplevel_raise_self(); + void _top_level_raise_self(); void _propagate_visibility_changed(bool p_visible); @@ -315,6 +316,9 @@ public: void update(); + void set_clip_children(bool p_enabled); + bool is_clipping_children() const; + virtual void set_light_mask(int p_light_mask); int get_light_mask() const; @@ -334,16 +338,16 @@ public: void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0); void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, float p_width = 1.0); void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color); - void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE); - void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE); - void draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), bool p_clip_uv = false, TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE); + void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1)); + void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false); + void draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false); void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect); - void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), float p_width = 1, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE); - void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE); - void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE); + void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), float p_width = 1); + void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>()); + void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>()); - void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE); - void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE); + void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1)); + void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture); void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1); float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", const Color &p_modulate = Color(1, 1, 1)); @@ -355,8 +359,8 @@ public: /* RECT / TRANSFORM */ - void set_as_toplevel(bool p_toplevel); - bool is_set_as_toplevel() const; + void set_as_top_level(bool p_top_level); + bool is_set_as_top_level() const; void set_draw_behind_parent(bool p_enable); bool is_draw_behind_parent_enabled() const; @@ -369,7 +373,7 @@ public: virtual Transform2D get_global_transform_with_canvas() const; virtual Transform2D get_screen_transform() const; - CanvasItem *get_toplevel() const; + CanvasItem *get_top_level() const; _FORCE_INLINE_ RID get_canvas_item() const { return canvas_item; } @@ -405,10 +409,10 @@ public: void force_update_transform(); - void set_texture_filter(TextureFilter p_texture_filter); + virtual void set_texture_filter(TextureFilter p_texture_filter); TextureFilter get_texture_filter() const; - void set_texture_repeat(TextureRepeat p_texture_repeat); + virtual void set_texture_repeat(TextureRepeat p_texture_repeat); TextureRepeat get_texture_repeat() const; // Used by control nodes to retrieve the parent's anchorable area @@ -423,4 +427,58 @@ public: VARIANT_ENUM_CAST(CanvasItem::TextureFilter) VARIANT_ENUM_CAST(CanvasItem::TextureRepeat) +class CanvasTexture : public Texture2D { + GDCLASS(CanvasTexture, Texture2D); + OBJ_SAVE_TYPE(Texture2D); // Saves derived classes with common type so they can be interchanged. + + Ref<Texture2D> diffuse_texture; + Ref<Texture2D> normal_texture; + Ref<Texture2D> specular_texture; + Color specular = Color(1, 1, 1, 1); + float shininess = 1.0; + + RID canvas_texture; + + CanvasItem::TextureFilter texture_filter = CanvasItem::TEXTURE_FILTER_PARENT_NODE; + CanvasItem::TextureRepeat texture_repeat = CanvasItem::TEXTURE_REPEAT_PARENT_NODE; + +protected: + static void _bind_methods(); + +public: + void set_diffuse_texture(const Ref<Texture2D> &p_diffuse); + Ref<Texture2D> get_diffuse_texture() const; + + void set_normal_texture(const Ref<Texture2D> &p_normal); + Ref<Texture2D> get_normal_texture() const; + + void set_specular_texture(const Ref<Texture2D> &p_specular); + Ref<Texture2D> get_specular_texture() const; + + void set_specular_color(const Color &p_color); + Color get_specular_color() const; + + void set_specular_shininess(float p_shininess); + float get_specular_shininess() const; + + void set_texture_filter(CanvasItem::TextureFilter p_filter); + CanvasItem::TextureFilter get_texture_filter() const; + + void set_texture_repeat(CanvasItem::TextureRepeat p_repeat); + CanvasItem::TextureRepeat get_texture_repeat() const; + + virtual int get_width() const override; + virtual int get_height() const override; + + virtual bool is_pixel_opaque(int p_x, int p_y) const override; + virtual bool has_alpha() const override; + + virtual Ref<Image> get_data() const override; + + virtual RID get_rid() const override; + + CanvasTexture(); + ~CanvasTexture(); +}; + #endif // CANVAS_ITEM_H diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 82ee4dde50..f484d25dc1 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -29,6 +29,8 @@ /*************************************************************************/ #include "http_request.h" +#include "core/io/compression.h" +#include "core/string/ustring.h" void HTTPRequest::_redirect_request(const String &p_new_url) { } @@ -82,7 +84,51 @@ Error HTTPRequest::_parse_url(const String &p_url) { return OK; } +bool HTTPRequest::has_header(const PackedStringArray &p_headers, const String &p_header_name) { + bool exists = false; + + String lower_case_header_name = p_header_name.to_lower(); + for (int i = 0; i < p_headers.size() && !exists; i++) { + String sanitized = p_headers[i].strip_edges().to_lower(); + if (sanitized.begins_with(lower_case_header_name)) { + exists = true; + } + } + + return exists; +} + +String HTTPRequest::get_header_value(const PackedStringArray &p_headers, const String &p_header_name) { + String value = ""; + + String lowwer_case_header_name = p_header_name.to_lower(); + for (int i = 0; i < p_headers.size(); i++) { + if (p_headers[i].find(":", 0) >= 0) { + Vector<String> parts = p_headers[i].split(":", false, 1); + if (parts[0].strip_edges().to_lower() == lowwer_case_header_name) { + value = parts[1].strip_edges(); + break; + } + } + } + + return value; +} + Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const String &p_request_data) { + // Copy the string into a raw buffer + Vector<uint8_t> raw_data; + + CharString charstr = p_request_data.utf8(); + size_t len = charstr.length(); + raw_data.resize(len); + uint8_t *w = raw_data.ptrw(); + copymem(w, charstr.ptr(), len); + + return request_raw(p_url, p_custom_headers, p_ssl_validate_domain, p_method, raw_data); +} + +Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const Vector<uint8_t> &p_request_data_raw) { ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED); ERR_FAIL_COND_V_MSG(requesting, ERR_BUSY, "HTTPRequest is processing a request. Wait for completion or cancel it before attempting a new one."); @@ -102,7 +148,14 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h headers = p_custom_headers; - request_data = p_request_data; + if (accept_gzip) { + // If the user has specified a different Accept-Encoding, don't overwrite it + if (!has_header(headers, "Accept-Encoding")) { + headers.push_back("Accept-Encoding: gzip, deflate"); + } + } + + request_data = p_request_data_raw; requesting = true; @@ -288,7 +341,7 @@ bool HTTPRequest::_update_connection() { } else { // Did not request yet, do request - Error err = client->request(method, request_string, headers, request_data); + Error err = client->request_raw(method, request_string, headers, request_data); if (err != OK) { call_deferred("_request_done", RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray()); return true; @@ -382,9 +435,47 @@ bool HTTPRequest::_update_connection() { ERR_FAIL_V(false); } -void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data) { +void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data) { cancel_request(); - emit_signal("request_completed", p_status, p_code, headers, p_data); + + // Determine if the request body is compressed + bool is_compressed; + String content_encoding = get_header_value(p_headers, "Content-Encoding").to_lower(); + Compression::Mode mode; + if (content_encoding == "gzip") { + mode = Compression::Mode::MODE_GZIP; + is_compressed = true; + } else if (content_encoding == "deflate") { + mode = Compression::Mode::MODE_DEFLATE; + is_compressed = true; + } else { + is_compressed = false; + } + + const PackedByteArray *data = NULL; + + if (accept_gzip && is_compressed && p_data.size() > 0) { + // Decompress request body + PackedByteArray *decompressed = memnew(PackedByteArray); + int result = Compression::decompress_dynamic(decompressed, body_size_limit, p_data.ptr(), p_data.size(), mode); + if (result == OK) { + data = decompressed; + } else if (result == -5) { + WARN_PRINT("Decompressed size of HTTP response body exceeded body_size_limit"); + p_status = RESULT_BODY_SIZE_LIMIT_EXCEEDED; + // Just return the raw data if we failed to decompress it + data = &p_data; + } else { + WARN_PRINT("Failed to decompress HTTP response body"); + p_status = RESULT_BODY_DECOMPRESS_FAILED; + // Just return the raw data if we failed to decompress it + data = &p_data; + } + } else { + data = &p_data; + } + + emit_signal("request_completed", p_status, p_code, p_headers, *data); } void HTTPRequest::_notification(int p_what) { @@ -415,6 +506,14 @@ bool HTTPRequest::is_using_threads() const { return use_threads; } +void HTTPRequest::set_accept_gzip(bool p_gzip) { + accept_gzip = p_gzip; +} + +bool HTTPRequest::is_accepting_gzip() const { + return accept_gzip; +} + void HTTPRequest::set_body_size_limit(int p_bytes) { ERR_FAIL_COND(get_http_client_status() != HTTPClient::STATUS_DISCONNECTED); @@ -481,6 +580,7 @@ void HTTPRequest::_timeout() { void HTTPRequest::_bind_methods() { ClassDB::bind_method(D_METHOD("request", "url", "custom_headers", "ssl_validate_domain", "method", "request_data"), &HTTPRequest::request, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(String())); + ClassDB::bind_method(D_METHOD("request_raw", "url", "custom_headers", "ssl_validate_domain", "method", "request_data_raw"), &HTTPRequest::request_raw, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(PackedByteArray())); ClassDB::bind_method(D_METHOD("cancel_request"), &HTTPRequest::cancel_request); ClassDB::bind_method(D_METHOD("get_http_client_status"), &HTTPRequest::get_http_client_status); @@ -488,6 +588,9 @@ void HTTPRequest::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_threads", "enable"), &HTTPRequest::set_use_threads); ClassDB::bind_method(D_METHOD("is_using_threads"), &HTTPRequest::is_using_threads); + ClassDB::bind_method(D_METHOD("set_accept_gzip", "enable"), &HTTPRequest::set_accept_gzip); + ClassDB::bind_method(D_METHOD("is_accepting_gzip"), &HTTPRequest::is_accepting_gzip); + ClassDB::bind_method(D_METHOD("set_body_size_limit", "bytes"), &HTTPRequest::set_body_size_limit); ClassDB::bind_method(D_METHOD("get_body_size_limit"), &HTTPRequest::get_body_size_limit); @@ -512,6 +615,7 @@ void HTTPRequest::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "download_file", PROPERTY_HINT_FILE), "set_download_file", "get_download_file"); ADD_PROPERTY(PropertyInfo(Variant::INT, "download_chunk_size", PROPERTY_HINT_RANGE, "256,16777216"), "set_download_chunk_size", "get_download_chunk_size"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_threads"), "set_use_threads", "is_using_threads"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "accept_gzip"), "set_accept_gzip", "is_accepting_gzip"); ADD_PROPERTY(PropertyInfo(Variant::INT, "body_size_limit", PROPERTY_HINT_RANGE, "-1,2000000000"), "set_body_size_limit", "get_body_size_limit"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_redirects", PROPERTY_HINT_RANGE, "-1,64"), "set_max_redirects", "get_max_redirects"); ADD_PROPERTY(PropertyInfo(Variant::INT, "timeout", PROPERTY_HINT_RANGE, "0,86400"), "set_timeout", "get_timeout"); @@ -527,6 +631,7 @@ void HTTPRequest::_bind_methods() { BIND_ENUM_CONSTANT(RESULT_SSL_HANDSHAKE_ERROR); BIND_ENUM_CONSTANT(RESULT_NO_RESPONSE); BIND_ENUM_CONSTANT(RESULT_BODY_SIZE_LIMIT_EXCEEDED); + BIND_ENUM_CONSTANT(RESULT_BODY_DECOMPRESS_FAILED); BIND_ENUM_CONSTANT(RESULT_REQUEST_FAILED); BIND_ENUM_CONSTANT(RESULT_DOWNLOAD_FILE_CANT_OPEN); BIND_ENUM_CONSTANT(RESULT_DOWNLOAD_FILE_WRITE_ERROR); @@ -544,6 +649,7 @@ HTTPRequest::HTTPRequest() { got_response = false; validate_ssl = false; use_ssl = false; + accept_gzip = true; response_code = 0; request_sent = false; requesting = false; diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 1409965d45..2e8931120b 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -50,6 +50,7 @@ public: RESULT_SSL_HANDSHAKE_ERROR, RESULT_NO_RESPONSE, RESULT_BODY_SIZE_LIMIT_EXCEEDED, + RESULT_BODY_DECOMPRESS_FAILED, RESULT_REQUEST_FAILED, RESULT_DOWNLOAD_FILE_CANT_OPEN, RESULT_DOWNLOAD_FILE_WRITE_ERROR, @@ -68,12 +69,13 @@ private: bool validate_ssl; bool use_ssl; HTTPClient::Method method; - String request_data; + Vector<uint8_t> request_data; bool request_sent; Ref<HTTPClient> client; PackedByteArray body; volatile bool use_threads; + bool accept_gzip; bool got_response; int response_code; @@ -102,12 +104,15 @@ private: Error _parse_url(const String &p_url); Error _request(); + bool has_header(const PackedStringArray &p_headers, const String &p_header_name); + String get_header_value(const PackedStringArray &p_headers, const String &header_name); + volatile bool thread_done; volatile bool thread_request_quit; Thread *thread; - void _request_done(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data); + void _request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data); static void _thread_func(void *p_userdata); protected: @@ -116,12 +121,16 @@ protected: public: Error request(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_ssl_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const String &p_request_data = ""); //connects to a full url and perform request + Error request_raw(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_ssl_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const Vector<uint8_t> &p_request_data_raw = Vector<uint8_t>()); //connects to a full url and perform request void cancel_request(); HTTPClient::Status get_http_client_status() const; void set_use_threads(bool p_use); bool is_using_threads() const; + void set_accept_gzip(bool p_gzip); + bool is_accepting_gzip() const; + void set_download_file(const String &p_file); String get_download_file() const; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 4dcfcd9d96..38baa6c97e 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -32,8 +32,8 @@ #include "core/core_string_names.h" #include "core/io/resource_loader.h" -#include "core/message_queue.h" -#include "core/print_string.h" +#include "core/object/message_queue.h" +#include "core/string/print_string.h" #include "instance_placeholder.h" #include "scene/debugger/scene_debugger.h" #include "scene/resources/packed_scene.h" @@ -1094,7 +1094,7 @@ String increase_numeric_string(const String &s) { if (!carry) { break; } - CharType n = s[i]; + char32_t n = s[i]; if (n == '9') { // keep carry as true: 9 + 1 res[i] = '0'; } else { @@ -1155,7 +1155,7 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co String name_string = name; String nums; for (int i = name_string.length() - 1; i >= 0; i--) { - CharType n = name_string[i]; + char32_t n = name_string[i]; if (n >= '0' && n <= '9') { nums = String::chr(name_string[i]) + nums; } else { @@ -1327,6 +1327,9 @@ int Node::get_child_count() const { } Node *Node::get_child(int p_index) const { + if (p_index < 0) { + p_index += data.children.size(); + } ERR_FAIL_INDEX_V(p_index, data.children.size(), nullptr); return data.children[p_index]; @@ -2852,6 +2855,7 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_PATH_CHANGED); BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS); BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS); + BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE); BIND_CONSTANT(NOTIFICATION_WM_MOUSE_ENTER); BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT); @@ -2885,7 +2889,6 @@ void Node::_bind_methods() { ADD_SIGNAL(MethodInfo("tree_exiting")); ADD_SIGNAL(MethodInfo("tree_exited")); - ADD_GROUP("Pause", "pause_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "pause_mode", PROPERTY_HINT_ENUM, "Inherit,Stop,Process"), "set_pause_mode", "get_pause_mode"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "name", PROPERTY_HINT_NONE, "", 0), "set_name", "get_name"); diff --git a/scene/main/node.h b/scene/main/node.h index 2928466cd0..2f8a0673e9 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -31,13 +31,12 @@ #ifndef NODE_H #define NODE_H -#include "core/class_db.h" -#include "core/map.h" -#include "core/node_path.h" -#include "core/object.h" -#include "core/project_settings.h" -#include "core/script_language.h" -#include "core/typed_array.h" +#include "core/config/project_settings.h" +#include "core/object/class_db.h" +#include "core/object/script_language.h" +#include "core/string/node_path.h" +#include "core/templates/map.h" +#include "core/variant/typed_array.h" #include "scene/main/scene_tree.h" class Viewport; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 2449b3bd35..cffd1126ee 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -30,16 +30,16 @@ #include "scene_tree.h" +#include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" #include "core/input/input.h" #include "core/io/marshalls.h" #include "core/io/resource_loader.h" -#include "core/message_queue.h" +#include "core/object/message_queue.h" #include "core/os/dir_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" -#include "core/print_string.h" -#include "core/project_settings.h" +#include "core/string/print_string.h" #include "node.h" #include "scene/debugger/scene_debugger.h" #include "scene/resources/dynamic_font.h" @@ -880,7 +880,10 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p if (n->get_script_instance()) { n->get_script_instance()->call(p_method, (const Variant **)v, 1, err); } - n->call(p_method, (const Variant **)v, 1, err); + MethodBind *method = ClassDB::get_method(n->get_class_name(), p_method); + if (method) { + method->call(n, (const Variant **)v, 1, err); + } } call_lock--; @@ -1380,14 +1383,23 @@ SceneTree::SceneTree() { root->set_as_audio_listener_2d(true); current_scene = nullptr; - int msaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/msaa", 0); + const int msaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/msaa", 0); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/msaa", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Fast),4x (Average),8x (Slow),16x (Slower)")); root->set_msaa(Viewport::MSAA(msaa_mode)); - int ssaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/screen_space_aa", 0); + const int ssaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/screen_space_aa", 0); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_aa", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)")); root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode)); + const bool use_debanding = GLOBAL_DEF("rendering/quality/screen_filters/use_debanding", false); + root->set_use_debanding(use_debanding); + + bool snap_2d_transforms = GLOBAL_DEF("rendering/quality/2d/snap_2d_transforms_to_pixel", false); + root->set_snap_2d_transforms_to_pixel(snap_2d_transforms); + + bool snap_2d_vertices = GLOBAL_DEF("rendering/quality/2d/snap_2d_vertices_to_pixel", false); + root->set_snap_2d_vertices_to_pixel(snap_2d_vertices); + { //load default fallback environment //get possible extensions List<String> exts; diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 0f74f2e973..3e5802ce2e 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SCENE_MAIN_LOOP_H -#define SCENE_MAIN_LOOP_H +#ifndef SCENE_TREE_H +#define SCENE_TREE_H #include "core/io/multiplayer_api.h" #include "core/os/main_loop.h" #include "core/os/thread_safe.h" -#include "core/self_list.h" +#include "core/templates/self_list.h" #include "scene/resources/mesh.h" #include "scene/resources/world_2d.h" #include "scene/resources/world_3d.h" @@ -354,4 +354,4 @@ public: VARIANT_ENUM_CAST(SceneTree::GroupCallFlags); -#endif +#endif // SCENE_TREE_H diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp index 726dcb58de..432fb5b4fb 100644 --- a/scene/main/shader_globals_override.cpp +++ b/scene/main/shader_globals_override.cpp @@ -202,7 +202,7 @@ void ShaderGlobalsOverride::_get_property_list(List<PropertyInfo> *p_list) const Override o; o.in_use = false; Callable::CallError ce; - o.override = Variant::construct(pinfo.type, nullptr, 0, ce); + Variant::construct(pinfo.type, o.override, nullptr, 0, ce); overrides[variables[i]] = o; } @@ -261,11 +261,16 @@ void ShaderGlobalsOverride::_notification(int p_what) { } String ShaderGlobalsOverride::get_configuration_warning() const { + String warning = Node::get_configuration_warning(); + if (!active) { - return TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene."); } - return String(); + return warning; } void ShaderGlobalsOverride::_bind_methods() { diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp index fb55892b54..c9fce2f6c2 100644 --- a/scene/main/timer.cpp +++ b/scene/main/timer.cpp @@ -30,7 +30,7 @@ #include "timer.h" -#include "core/engine.h" +#include "core/config/engine.h" void Timer::_notification(int p_what) { switch (p_what) { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index d962171555..17411bb490 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -30,11 +30,11 @@ #include "viewport.h" +#include "core/config/project_settings.h" #include "core/core_string_names.h" #include "core/debugger/engine_debugger.h" #include "core/input/input.h" #include "core/os/os.h" -#include "core/project_settings.h" #include "scene/2d/collision_object_2d.h" #include "scene/3d/camera_3d.h" #include "scene/3d/collision_object_3d.h" @@ -161,6 +161,11 @@ ViewportTexture::~ViewportTexture() { ///////////////////////////////////// +// Aliases used to provide custom styles to tooltips in the default +// theme and editor theme. +// TooltipPanel is also used for custom tooltips, while TooltipLabel +// is only relevant for default tooltips. + class TooltipPanel : public PopupPanel { GDCLASS(TooltipPanel, PopupPanel); @@ -175,6 +180,8 @@ public: TooltipLabel() {} }; +///////////////////////////////////// + Viewport::GUI::GUI() { embed_subwindows_hint = false; embedding_subwindows = false; @@ -188,7 +195,7 @@ Viewport::GUI::GUI() { mouse_over = nullptr; drag_mouse_over = nullptr; - tooltip = nullptr; + tooltip_control = nullptr; tooltip_popup = nullptr; tooltip_label = nullptr; } @@ -814,7 +821,14 @@ void Viewport::_notification(int p_what) { } } break; - case NOTIFICATION_WM_MOUSE_EXIT: + case NOTIFICATION_WM_MOUSE_EXIT: { + _drop_physics_mouseover(); + + // Unlike on loss of focus (NOTIFICATION_WM_WINDOW_FOCUS_OUT), do not + // drop the gui mouseover here, as a scrollbar may be dragged while the + // mouse is outside the window (without the window having lost focus). + // See bug #39634 + } break; case NOTIFICATION_WM_WINDOW_FOCUS_OUT: { _drop_physics_mouseover(); @@ -1465,7 +1479,7 @@ void Viewport::_gui_sort_roots() { } void Viewport::_gui_cancel_tooltip() { - gui.tooltip = nullptr; + gui.tooltip_control = nullptr; gui.tooltip_timer = -1; if (gui.tooltip_popup) { gui.tooltip_popup->queue_delete(); @@ -1474,29 +1488,34 @@ void Viewport::_gui_cancel_tooltip() { } } -String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which) { +String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_tooltip_owner) { Vector2 pos = p_pos; String tooltip; while (p_control) { tooltip = p_control->get_tooltip(pos); - if (r_which) { - *r_which = p_control; + if (r_tooltip_owner) { + *r_tooltip_owner = p_control; } - if (tooltip != String()) { + // If we found a tooltip, we stop here. + if (!tooltip.empty()) { break; } - pos = p_control->get_transform().xform(pos); + + // Otherwise, we check parent controls unless some conditions prevent it. if (p_control->data.mouse_filter == Control::MOUSE_FILTER_STOP) { break; } - if (p_control->is_set_as_toplevel()) { + if (p_control->is_set_as_top_level()) { break; } + // Transform cursor pos for parent control. + pos = p_control->get_transform().xform(pos); + p_control = p_control->get_parent_control(); } @@ -1504,34 +1523,40 @@ String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Cont } void Viewport::_gui_show_tooltip() { - if (!gui.tooltip) { + if (!gui.tooltip_control) { return; } - Control *which = nullptr; - String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.tooltip_pos), &which); - tooltip = tooltip.strip_edges(); - if (tooltip.length() == 0) { - return; // bye + // Get the Control under cursor and the relevant tooltip text, if any. + Control *tooltip_owner = nullptr; + String tooltip_text = _gui_get_tooltip( + gui.tooltip_control, + gui.tooltip_control->get_global_transform().xform_inv(gui.last_mouse_pos), + &tooltip_owner); + tooltip_text.strip_edges(); + if (tooltip_text.empty()) { + return; // Nothing to show. } + // Remove previous popup if we change something. if (gui.tooltip_popup) { memdelete(gui.tooltip_popup); gui.tooltip_popup = nullptr; gui.tooltip_label = nullptr; } - if (!which) { + if (!tooltip_owner) { return; } - Control *rp = which; - - Control *base_tooltip = which->make_custom_tooltip(tooltip); + // Controls can implement `make_custom_tooltip` to provide their own tooltip. + // This should be a Control node which will be added as child to a TooltipPanel. + Control *base_tooltip = tooltip_owner->make_custom_tooltip(tooltip_text); + // If no custom tooltip is given, use a default implementation. if (!base_tooltip) { gui.tooltip_label = memnew(TooltipLabel); - gui.tooltip_label->set_text(tooltip); + gui.tooltip_label->set_text(tooltip_text); base_tooltip = gui.tooltip_label; } @@ -1545,10 +1570,7 @@ void Viewport::_gui_show_tooltip() { gui.tooltip_popup = panel; - rp->add_child(gui.tooltip_popup); - - //if (gui.tooltip) // Avoids crash when rapidly switching controls. - // gui.tooltip_popup->set_scale(gui.tooltip->get_global_transform().get_scale()); + tooltip_owner->add_child(gui.tooltip_popup); Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset"); Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_contents_minimum_size()); @@ -1620,7 +1642,7 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu } } - if (!control->is_inside_tree() || control->is_set_as_toplevel()) { + if (!control->is_inside_tree() || control->is_set_as_top_level()) { break; } if (gui.key_event_accepted) { @@ -1631,7 +1653,7 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu } } - if (ci->is_set_as_toplevel()) { + if (ci->is_set_as_top_level()) { break; } @@ -1655,7 +1677,7 @@ void Viewport::_gui_call_notification(Control *p_control, int p_what) { break; } - if (!control->is_inside_tree() || control->is_set_as_toplevel()) { + if (!control->is_inside_tree() || control->is_set_as_top_level()) { break; } if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP) { @@ -1663,7 +1685,7 @@ void Viewport::_gui_call_notification(Control *p_control, int p_what) { } } - if (ci->is_set_as_toplevel()) { + if (ci->is_set_as_top_level()) { break; } @@ -1721,7 +1743,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ if (!c || !c->clips_input() || c->has_point(matrix.affine_inverse().xform(p_global))) { for (int i = p_node->get_child_count() - 1; i >= 0; i--) { CanvasItem *ci = Object::cast_to<CanvasItem>(p_node->get_child(i)); - if (!ci || ci->is_set_as_toplevel()) { + if (!ci || ci->is_set_as_top_level()) { continue; } @@ -1768,7 +1790,7 @@ bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_che p_at_pos = ci->get_transform().xform(p_at_pos); - if (ci->is_set_as_toplevel()) { + if (ci->is_set_as_top_level()) { break; } @@ -1794,6 +1816,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (mb.is_valid()) { gui.key_event_accepted = false; + Control *over = nullptr; + Point2 mpos = mb->get_position(); if (mb->is_pressed()) { Size2 pos = mpos; @@ -1865,7 +1889,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } } - if (ci->is_set_as_toplevel()) { + if (ci->is_set_as_top_level()) { break; } @@ -1897,8 +1921,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } _gui_cancel_tooltip(); - //gui.tooltip_popup->hide(); - } else { if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) { if (gui.drag_mouse_over) { @@ -1948,6 +1970,31 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.drag_data=Variant(); //always clear }*/ + // In case the mouse was released after for example dragging a scrollbar, + // check whether the current control is different from the stored one. If + // it is different, rather than wait for it to be updated the next time the + // mouse is moved, notify the control so that it can e.g. drop the highlight. + // This code is duplicated from the mm.is_valid()-case further below. + if (gui.mouse_focus) { + over = gui.mouse_focus; + } else { + over = _gui_find_control(mpos); + } + + if (gui.mouse_focus_mask == 0 && over != gui.mouse_over) { + if (gui.mouse_over) { + _gui_call_notification(gui.mouse_over, Control::NOTIFICATION_MOUSE_EXIT); + } + + _gui_cancel_tooltip(); + + if (over) { + _gui_call_notification(over, Control::NOTIFICATION_MOUSE_ENTER); + } + } + + gui.mouse_over = over; + set_input_as_handled(); } } @@ -1993,7 +2040,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } } - if (ci->is_set_as_toplevel()) { + if (ci->is_set_as_top_level()) { break; } @@ -2008,10 +2055,11 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } } + // These sections of code are reused in the mb.is_valid() case further up + // for the purpose of notifying controls about potential changes in focus + // when the mousebutton is released. if (gui.mouse_focus) { over = gui.mouse_focus; - //recompute focus_inv_xform again here - } else { over = _gui_find_control(mpos); } @@ -2052,8 +2100,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { bool is_tooltip_shown = false; if (gui.tooltip_popup) { - if (can_tooltip && gui.tooltip) { - String tooltip = _gui_get_tooltip(over, gui.tooltip->get_global_transform().xform_inv(mpos)); + if (can_tooltip && gui.tooltip_control) { + String tooltip = _gui_get_tooltip(over, gui.tooltip_control->get_global_transform().xform_inv(mpos)); if (tooltip.length() == 0) { _gui_cancel_tooltip(); @@ -2078,14 +2126,12 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } if (can_tooltip && !is_tooltip_shown) { - gui.tooltip = over; - gui.tooltip_pos = over->get_screen_transform().xform(pos); //(parent_xform * get_transform()).affine_inverse().xform(pos); + gui.tooltip_control = over; + gui.tooltip_pos = over->get_screen_transform().xform(pos); gui.tooltip_timer = gui.tooltip_delay; } } - //pos = gui.focus_inv_xform.xform(pos); - mm->set_position(pos); Control::CursorShape cursor_shape = Control::CURSOR_ARROW; @@ -2105,7 +2151,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (c->data.mouse_filter == Control::MOUSE_FILTER_STOP) { break; } - if (c->is_set_as_toplevel()) { + if (c->is_set_as_top_level()) { break; } c = c->get_parent_control(); @@ -2404,7 +2450,7 @@ void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) { if (gui.drag_preview) { memdelete(gui.drag_preview); } - p_control->set_as_toplevel(true); + p_control->set_as_top_level(true); p_control->set_position(gui.last_mouse_pos); p_base->get_root_parent_control()->add_child(p_control); //add as child of viewport p_control->raise(); @@ -2422,7 +2468,7 @@ void Viewport::_gui_unfocus_control(Control *p_control) { } } -void Viewport::_gui_hid_control(Control *p_control) { +void Viewport::_gui_hide_control(Control *p_control) { if (gui.mouse_focus == p_control) { _drop_mouse_focus(); } @@ -2436,7 +2482,7 @@ void Viewport::_gui_hid_control(Control *p_control) { if (gui.drag_mouse_over == p_control) { gui.drag_mouse_over = nullptr; } - if (gui.tooltip == p_control) { + if (gui.tooltip_control == p_control) { _gui_cancel_tooltip(); } } @@ -2459,8 +2505,8 @@ void Viewport::_gui_remove_control(Control *p_control) { if (gui.drag_mouse_over == p_control) { gui.drag_mouse_over = nullptr; } - if (gui.tooltip == p_control) { - gui.tooltip = nullptr; + if (gui.tooltip_control == p_control) { + gui.tooltip_control = nullptr; } } @@ -3093,10 +3139,15 @@ String Viewport::get_configuration_warning() const { return TTR("This viewport is not set as render target. If you intend for it to display its contents directly to the screen, make it a child of a Control so it can obtain a size. Otherwise, make it a RenderTarget and assign its internal texture to some node for display."); }*/ + String warning = Node::get_configuration_warning(); + if (size.x == 0 || size.y == 0) { - return TTR("Viewport size must be greater than 0 to render anything."); + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("Viewport size must be greater than 0 to render anything."); } - return String(); + return warning; } void Viewport::gui_reset_canvas_sort_index() { @@ -3133,6 +3184,17 @@ Viewport::ScreenSpaceAA Viewport::get_screen_space_aa() const { return screen_space_aa; } +void Viewport::set_use_debanding(bool p_use_debanding) { + if (use_debanding == p_use_debanding) + return; + use_debanding = p_use_debanding; + RS::get_singleton()->viewport_set_use_debanding(viewport, p_use_debanding); +} + +bool Viewport::is_using_debanding() const { + return use_debanding; +} + void Viewport::set_debug_draw(DebugDraw p_debug_draw) { debug_draw = p_debug_draw; RS::get_singleton()->viewport_set_debug_draw(viewport, RS::ViewportDebugDraw(p_debug_draw)); @@ -3154,6 +3216,24 @@ bool Viewport::is_snap_controls_to_pixels_enabled() const { return snap_controls_to_pixels; } +void Viewport::set_snap_2d_transforms_to_pixel(bool p_enable) { + snap_2d_transforms_to_pixel = p_enable; + RS::get_singleton()->viewport_set_snap_2d_transforms_to_pixel(viewport, snap_2d_transforms_to_pixel); +} + +bool Viewport::is_snap_2d_transforms_to_pixel_enabled() const { + return snap_2d_transforms_to_pixel; +} + +void Viewport::set_snap_2d_vertices_to_pixel(bool p_enable) { + snap_2d_vertices_to_pixel = p_enable; + RS::get_singleton()->viewport_set_snap_2d_vertices_to_pixel(viewport, snap_2d_vertices_to_pixel); +} + +bool Viewport::is_snap_2d_vertices_to_pixel_enabled() const { + return snap_2d_vertices_to_pixel; +} + bool Viewport::gui_is_dragging() const { return gui.dragging; } @@ -3208,11 +3288,28 @@ void Viewport::_validate_property(PropertyInfo &property) const { } void Viewport::set_default_canvas_item_texture_filter(DefaultCanvasItemTextureFilter p_filter) { + ERR_FAIL_INDEX(p_filter, DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_MAX); + if (default_canvas_item_texture_filter == p_filter) { return; } default_canvas_item_texture_filter = p_filter; - _propagate_update_default_filter(this); + switch (default_canvas_item_texture_filter) { + case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST: + RS::get_singleton()->viewport_set_default_canvas_item_texture_filter(viewport, RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST); + break; + case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR: + RS::get_singleton()->viewport_set_default_canvas_item_texture_filter(viewport, RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR); + break; + case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: + RS::get_singleton()->viewport_set_default_canvas_item_texture_filter(viewport, RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS); + break; + case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: + RS::get_singleton()->viewport_set_default_canvas_item_texture_filter(viewport, RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS); + break; + default: { + } + } } Viewport::DefaultCanvasItemTextureFilter Viewport::get_default_canvas_item_texture_filter() const { @@ -3220,37 +3317,31 @@ Viewport::DefaultCanvasItemTextureFilter Viewport::get_default_canvas_item_textu } void Viewport::set_default_canvas_item_texture_repeat(DefaultCanvasItemTextureRepeat p_repeat) { + ERR_FAIL_INDEX(p_repeat, DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX); + if (default_canvas_item_texture_repeat == p_repeat) { return; } - default_canvas_item_texture_repeat = p_repeat; - _propagate_update_default_repeat(this); -} - -Viewport::DefaultCanvasItemTextureRepeat Viewport::get_default_canvas_item_texture_repeat() const { - return default_canvas_item_texture_repeat; -} -void Viewport::_propagate_update_default_filter(Node *p_node) { - CanvasItem *ci = Object::cast_to<CanvasItem>(p_node); - if (ci) { - ci->_update_texture_filter_changed(false); - } + default_canvas_item_texture_repeat = p_repeat; - for (int i = 0; i < p_node->get_child_count(); i++) { - _propagate_update_default_filter(p_node->get_child(i)); + switch (default_canvas_item_texture_repeat) { + case DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: + RS::get_singleton()->viewport_set_default_canvas_item_texture_repeat(viewport, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + break; + case DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: + RS::get_singleton()->viewport_set_default_canvas_item_texture_repeat(viewport, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + break; + case DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: + RS::get_singleton()->viewport_set_default_canvas_item_texture_repeat(viewport, RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR); + break; + default: { + } } } -void Viewport::_propagate_update_default_repeat(Node *p_node) { - CanvasItem *ci = Object::cast_to<CanvasItem>(p_node); - if (ci) { - ci->_update_texture_repeat_changed(false); - } - - for (int i = 0; i < p_node->get_child_count(); i++) { - _propagate_update_default_repeat(p_node->get_child(i)); - } +Viewport::DefaultCanvasItemTextureRepeat Viewport::get_default_canvas_item_texture_repeat() const { + return default_canvas_item_texture_repeat; } DisplayServer::WindowID Viewport::get_window_id() const { @@ -3319,6 +3410,9 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_screen_space_aa", "screen_space_aa"), &Viewport::set_screen_space_aa); ClassDB::bind_method(D_METHOD("get_screen_space_aa"), &Viewport::get_screen_space_aa); + ClassDB::bind_method(D_METHOD("set_use_debanding", "enable"), &Viewport::set_use_debanding); + ClassDB::bind_method(D_METHOD("is_using_debanding"), &Viewport::is_using_debanding); + ClassDB::bind_method(D_METHOD("set_debug_draw", "debug_draw"), &Viewport::set_debug_draw); ClassDB::bind_method(D_METHOD("get_debug_draw"), &Viewport::get_debug_draw); @@ -3365,6 +3459,12 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_snap_controls_to_pixels", "enabled"), &Viewport::set_snap_controls_to_pixels); ClassDB::bind_method(D_METHOD("is_snap_controls_to_pixels_enabled"), &Viewport::is_snap_controls_to_pixels_enabled); + ClassDB::bind_method(D_METHOD("set_snap_2d_transforms_to_pixel", "enabled"), &Viewport::set_snap_2d_transforms_to_pixel); + ClassDB::bind_method(D_METHOD("is_snap_2d_transforms_to_pixel_enabled"), &Viewport::is_snap_2d_transforms_to_pixel_enabled); + + ClassDB::bind_method(D_METHOD("set_snap_2d_vertices_to_pixel", "enabled"), &Viewport::set_snap_2d_vertices_to_pixel); + ClassDB::bind_method(D_METHOD("is_snap_2d_vertices_to_pixel_enabled"), &Viewport::is_snap_2d_vertices_to_pixel_enabled); + ClassDB::bind_method(D_METHOD("set_shadow_atlas_quadrant_subdiv", "quadrant", "subdiv"), &Viewport::set_shadow_atlas_quadrant_subdiv); ClassDB::bind_method(D_METHOD("get_shadow_atlas_quadrant_subdiv", "quadrant"), &Viewport::get_shadow_atlas_quadrant_subdiv); @@ -3389,9 +3489,12 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transparent_bg"), "set_transparent_background", "has_transparent_background"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_transforms_to_pixel"), "set_snap_2d_transforms_to_pixel", "is_snap_2d_transforms_to_pixel_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_vertices_to_pixel"), "set_snap_2d_vertices_to_pixel", "is_snap_2d_vertices_to_pixel_enabled"); ADD_GROUP("Rendering", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"), "set_msaa", "get_msaa"); ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA"), "set_screen_space_aa", "get_screen_space_aa"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding"); ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw"); ADD_GROUP("Canvas Items", "canvas_item_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,MipmapLinear,MipmapNearest"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter"); @@ -3522,14 +3625,13 @@ Viewport::Viewport() { disable_input = false; - //window tooltip + // Window tooltip. gui.tooltip_timer = -1; - //gui.tooltip_timer->force_parent_owned(); gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.5); ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::FLOAT, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers - gui.tooltip = nullptr; + gui.tooltip_control = nullptr; gui.tooltip_label = nullptr; gui.drag_preview = nullptr; gui.drag_attempted = false; @@ -3546,6 +3648,9 @@ Viewport::Viewport() { debug_draw = DEBUG_DRAW_DISABLED; snap_controls_to_pixels = true; + snap_2d_transforms_to_pixel = false; + snap_2d_vertices_to_pixel = false; + physics_last_mouse_state.alt = false; physics_last_mouse_state.control = false; physics_last_mouse_state.shift = false; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 52145a7761..8e7f2cecdc 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -225,6 +225,8 @@ private: bool gen_mipmaps; bool snap_controls_to_pixels; + bool snap_2d_transforms_to_pixel; + bool snap_2d_vertices_to_pixel; bool physics_object_picking; List<Ref<InputEvent>> physics_picking_events; @@ -279,6 +281,7 @@ private: MSAA msaa; ScreenSpaceAA screen_space_aa; + bool use_debanding = false; Ref<ViewportTexture> default_texture; Set<ViewportTexture *> viewport_textures; @@ -320,7 +323,7 @@ private: Control *mouse_over; Control *drag_mouse_over; Vector2 drag_mouse_over_pos; - Control *tooltip; + Control *tooltip_control; Window *tooltip_popup; Label *tooltip_label; Point2 tooltip_pos; @@ -356,9 +359,6 @@ private: DefaultCanvasItemTextureFilter default_canvas_item_texture_filter; DefaultCanvasItemTextureRepeat default_canvas_item_texture_repeat; - void _propagate_update_default_filter(Node *p_node); - void _propagate_update_default_repeat(Node *p_node); - bool disable_input; void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input); @@ -382,12 +382,12 @@ private: void _gui_remove_root_control(List<Control *>::Element *RI); - String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which = nullptr); + String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_tooltip_owner = nullptr); void _gui_cancel_tooltip(); void _gui_show_tooltip(); void _gui_remove_control(Control *p_control); - void _gui_hid_control(Control *p_control); + void _gui_hide_control(Control *p_control); void _gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control); void _gui_set_drag_preview(Control *p_base, Control *p_control); @@ -521,6 +521,9 @@ public: void set_screen_space_aa(ScreenSpaceAA p_screen_space_aa); ScreenSpaceAA get_screen_space_aa() const; + void set_use_debanding(bool p_use_debanding); + bool is_using_debanding() const; + Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const; Vector2 get_camera_rect_size() const; @@ -555,6 +558,12 @@ public: void set_snap_controls_to_pixels(bool p_enable); bool is_snap_controls_to_pixels_enabled() const; + void set_snap_2d_transforms_to_pixel(bool p_enable); + bool is_snap_2d_transforms_to_pixel_enabled() const; + + void set_snap_2d_vertices_to_pixel(bool p_enable); + bool is_snap_2d_vertices_to_pixel_enabled() const; + void set_input_as_handled(); bool is_input_handled() const; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index a5c5be8a44..4116d5ce10 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -246,6 +246,8 @@ void Window::_make_window() { } } + _update_window_callbacks(); + RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE); DisplayServer::get_singleton()->show_window(window_id); } @@ -379,7 +381,6 @@ void Window::set_visible(bool p_visible) { } if (p_visible && window_id == DisplayServer::INVALID_WINDOW_ID) { _make_window(); - _update_window_callbacks(); } } else { if (visible) { @@ -738,7 +739,6 @@ void Window::_notification(int p_what) { //create if (visible) { _make_window(); - _update_window_callbacks(); } } } @@ -895,11 +895,11 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) { if (exclusive_child != nullptr) { Window *focus_target = exclusive_child; + focus_target->grab_focus(); while (focus_target->exclusive_child != nullptr) { - focus_target->grab_focus(); focus_target = focus_target->exclusive_child; + focus_target->grab_focus(); } - focus_target->grab_focus(); if (!is_embedding_subwindows()) { //not embedding, no need for event return; @@ -983,7 +983,7 @@ void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio Rect2i popup_rect; popup_rect.size = Vector2i(MIN(size_ratio.x, p_size.x), MIN(size_ratio.y, p_size.y)); - popup_rect.position = (parent_rect.size - popup_rect.size) / 2; + popup_rect.position = parent_rect.position + (parent_rect.size - popup_rect.size) / 2; popup(popup_rect); } @@ -1009,7 +1009,7 @@ void Window::popup_centered(const Size2i &p_minsize) { } else { popup_rect.size = p_minsize; } - popup_rect.position = (parent_rect.size - popup_rect.size) / 2; + popup_rect.position = parent_rect.position + (parent_rect.size - popup_rect.size) / 2; popup(popup_rect); } @@ -1031,7 +1031,7 @@ void Window::popup_centered_ratio(float p_ratio) { Rect2i popup_rect; popup_rect.size = parent_rect.size * p_ratio; - popup_rect.position = (parent_rect.size - popup_rect.size) / 2; + popup_rect.position = parent_rect.position + (parent_rect.size - popup_rect.size) / 2; popup(popup_rect); } diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 47b8b6073b..7997dc12e1 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -30,14 +30,15 @@ #include "register_scene_types.h" -#include "core/class_db.h" +#include "core/config/project_settings.h" +#include "core/object/class_db.h" #include "core/os/os.h" -#include "core/project_settings.h" #include "scene/2d/animated_sprite_2d.h" #include "scene/2d/area_2d.h" #include "scene/2d/audio_stream_player_2d.h" #include "scene/2d/back_buffer_copy.h" #include "scene/2d/camera_2d.h" +#include "scene/2d/canvas_group.h" #include "scene/2d/canvas_modulate.h" #include "scene/2d/collision_polygon_2d.h" #include "scene/2d/collision_shape_2d.h" @@ -81,6 +82,7 @@ #include "scene/gui/center_container.h" #include "scene/gui/check_box.h" #include "scene/gui/check_button.h" +#include "scene/gui/code_edit.h" #include "scene/gui/color_picker.h" #include "scene/gui/color_rect.h" #include "scene/gui/control.h" @@ -193,6 +195,7 @@ #include "scene/3d/decal.h" #include "scene/3d/gi_probe.h" #include "scene/3d/gpu_particles_3d.h" +#include "scene/3d/gpu_particles_collision_3d.h" #include "scene/3d/immediate_geometry_3d.h" #include "scene/3d/light_3d.h" #include "scene/3d/lightmap_probe.h" @@ -230,6 +233,7 @@ static Ref<ResourceFormatLoaderDynamicFont> resource_loader_dynamic_font; static Ref<ResourceFormatLoaderStreamTexture2D> resource_loader_stream_texture; static Ref<ResourceFormatLoaderStreamTextureLayered> resource_loader_texture_layered; +static Ref<ResourceFormatLoaderStreamTexture3D> resource_loader_texture_3d; static Ref<ResourceFormatLoaderBMFont> resource_loader_bmfont; @@ -252,6 +256,9 @@ void register_scene_types() { resource_loader_texture_layered.instance(); ResourceLoader::add_resource_format_loader(resource_loader_texture_layered); + resource_loader_texture_3d.instance(); + ResourceLoader::add_resource_format_loader(resource_loader_texture_3d); + resource_saver_text.instance(); ResourceSaver::add_resource_format_saver(resource_saver_text, true); @@ -291,7 +298,7 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init - ClassDB::register_class<ShortCut>(); + ClassDB::register_class<Shortcut>(); ClassDB::register_class<Control>(); ClassDB::register_class<Button>(); ClassDB::register_class<Label>(); @@ -347,6 +354,7 @@ void register_scene_types() { ClassDB::register_class<Tree>(); ClassDB::register_class<TextEdit>(); + ClassDB::register_class<CodeEdit>(); ClassDB::register_class<SyntaxHighlighter>(); ClassDB::register_class<CodeHighlighter>(); @@ -372,7 +380,11 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init - AcceptDialog::set_swap_cancel_ok(GLOBAL_DEF_NOVAL("gui/common/swap_cancel_ok", bool(DisplayServer::get_singleton()->get_swap_cancel_ok()))); + bool swap_cancel_ok = false; + if (DisplayServer::get_singleton()) { + swap_cancel_ok = GLOBAL_DEF_NOVAL("gui/common/swap_cancel_ok", bool(DisplayServer::get_singleton()->get_swap_cancel_ok())); + } + AcceptDialog::set_swap_cancel_ok(swap_cancel_ok); #endif /* REGISTER 3D */ @@ -440,6 +452,15 @@ void register_scene_types() { ClassDB::register_class<LightmapProbe>(); ClassDB::register_virtual_class<Lightmapper>(); ClassDB::register_class<GPUParticles3D>(); + ClassDB::register_virtual_class<GPUParticlesCollision3D>(); + ClassDB::register_class<GPUParticlesCollisionBox>(); + ClassDB::register_class<GPUParticlesCollisionSphere>(); + ClassDB::register_class<GPUParticlesCollisionSDF>(); + ClassDB::register_class<GPUParticlesCollisionHeightField>(); + ClassDB::register_virtual_class<GPUParticlesAttractor3D>(); + ClassDB::register_class<GPUParticlesAttractorBox>(); + ClassDB::register_class<GPUParticlesAttractorSphere>(); + ClassDB::register_class<GPUParticlesAttractorVectorField>(); ClassDB::register_class<CPUParticles3D>(); ClassDB::register_class<Position3D>(); @@ -502,7 +523,8 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeCustom>(); ClassDB::register_class<VisualShaderNodeInput>(); ClassDB::register_virtual_class<VisualShaderNodeOutput>(); - ClassDB::register_class<VisualShaderNodeGroupBase>(); + ClassDB::register_virtual_class<VisualShaderNodeResizableBase>(); + ClassDB::register_virtual_class<VisualShaderNodeGroupBase>(); ClassDB::register_class<VisualShaderNodeFloatConstant>(); ClassDB::register_class<VisualShaderNodeIntConstant>(); ClassDB::register_class<VisualShaderNodeBooleanConstant>(); @@ -543,8 +565,10 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeVectorDecompose>(); ClassDB::register_class<VisualShaderNodeTransformDecompose>(); ClassDB::register_class<VisualShaderNodeTexture>(); + ClassDB::register_class<VisualShaderNodeCurveTexture>(); ClassDB::register_virtual_class<VisualShaderNodeSample3D>(); ClassDB::register_class<VisualShaderNodeTexture2DArray>(); + ClassDB::register_class<VisualShaderNodeTexture3D>(); ClassDB::register_class<VisualShaderNodeCubemap>(); ClassDB::register_virtual_class<VisualShaderNodeUniform>(); ClassDB::register_class<VisualShaderNodeUniformRef>(); @@ -557,6 +581,7 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeTextureUniform>(); ClassDB::register_class<VisualShaderNodeTextureUniformTriplanar>(); ClassDB::register_class<VisualShaderNodeTexture2DArrayUniform>(); + ClassDB::register_class<VisualShaderNodeTexture3DUniform>(); ClassDB::register_class<VisualShaderNodeCubemapUniform>(); ClassDB::register_class<VisualShaderNodeIf>(); ClassDB::register_class<VisualShaderNodeSwitch>(); @@ -570,6 +595,7 @@ void register_scene_types() { ClassDB::register_class<ShaderMaterial>(); ClassDB::register_virtual_class<CanvasItem>(); + ClassDB::register_class<CanvasTexture>(); ClassDB::register_class<CanvasItemMaterial>(); SceneTree::add_idle_callback(CanvasItemMaterial::flush_changes); CanvasItemMaterial::init_shaders(); @@ -577,6 +603,7 @@ void register_scene_types() { /* REGISTER 2D */ ClassDB::register_class<Node2D>(); + ClassDB::register_class<CanvasGroup>(); ClassDB::register_class<CPUParticles2D>(); ClassDB::register_class<GPUParticles2D>(); ClassDB::register_class<Sprite2D>(); @@ -601,7 +628,9 @@ void register_scene_types() { ClassDB::register_class<Polygon2D>(); ClassDB::register_class<Skeleton2D>(); ClassDB::register_class<Bone2D>(); - ClassDB::register_class<Light2D>(); + ClassDB::register_virtual_class<Light2D>(); + ClassDB::register_class<PointLight2D>(); + ClassDB::register_class<DirectionalLight2D>(); ClassDB::register_class<LightOccluder2D>(); ClassDB::register_class<OccluderPolygon2D>(); ClassDB::register_class<YSort>(); @@ -697,6 +726,9 @@ void register_scene_types() { ClassDB::register_class<CameraTexture>(); ClassDB::register_virtual_class<TextureLayered>(); ClassDB::register_virtual_class<ImageTextureLayered>(); + ClassDB::register_virtual_class<Texture3D>(); + ClassDB::register_class<ImageTexture3D>(); + ClassDB::register_class<StreamTexture3D>(); ClassDB::register_class<Cubemap>(); ClassDB::register_class<CubemapArray>(); ClassDB::register_class<Texture2DArray>(); @@ -860,6 +892,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("RemoteTransform", "RemoteTransform3D"); ClassDB::add_compatibility_class("RigidBody", "RigidBody3D"); ClassDB::add_compatibility_class("Shape", "Shape3D"); + ClassDB::add_compatibility_class("ShortCut", "Shortcut"); ClassDB::add_compatibility_class("Skeleton", "Skeleton3D"); ClassDB::add_compatibility_class("SkeletonIK", "SkeletonIK3D"); ClassDB::add_compatibility_class("SliderJoint", "SliderJoint3D"); @@ -876,6 +909,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("VehicleBody", "VehicleBody3D"); ClassDB::add_compatibility_class("VehicleWheel", "VehicleWheel3D"); ClassDB::add_compatibility_class("ViewportContainer", "SubViewportContainer"); + ClassDB::add_compatibility_class("Viewport", "SubViewport"); ClassDB::add_compatibility_class("VisibilityEnabler", "VisibilityEnabler3D"); ClassDB::add_compatibility_class("VisibilityNotifier", "VisibilityNotifier3D"); ClassDB::add_compatibility_class("VisualServer", "RenderingServer"); @@ -885,6 +919,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("VisualShaderNodeScalarUniform", "VisualShaderNodeFloatUniform"); ClassDB::add_compatibility_class("World", "World3D"); ClassDB::add_compatibility_class("StreamTexture", "StreamTexture2D"); + ClassDB::add_compatibility_class("Light2D", "PointLight2D"); #endif @@ -912,8 +947,10 @@ void register_scene_types() { } } - // Always make the default theme to avoid invalid default font/icon/style in the given theme - make_default_theme(default_theme_hidpi, font); + // Always make the default theme to avoid invalid default font/icon/style in the given theme. + if (RenderingServer::get_singleton()) { + make_default_theme(default_theme_hidpi, font); + } if (theme_path != String()) { Ref<Theme> theme = ResourceLoader::load(theme_path); @@ -939,6 +976,9 @@ void unregister_scene_types() { ResourceLoader::remove_resource_format_loader(resource_loader_texture_layered); resource_loader_texture_layered.unref(); + ResourceLoader::remove_resource_format_loader(resource_loader_texture_3d); + resource_loader_texture_3d.unref(); + ResourceLoader::remove_resource_format_loader(resource_loader_stream_texture); resource_loader_stream_texture.unref(); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index b8edd70712..92103f3b1d 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -2633,6 +2633,7 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("value_track_get_update_mode", "track_idx"), &Animation::value_track_get_update_mode); ClassDB::bind_method(D_METHOD("value_track_get_key_indices", "track_idx", "time_sec", "delta"), &Animation::_value_track_get_key_indices); + ClassDB::bind_method(D_METHOD("value_track_interpolate", "track_idx", "time_sec"), &Animation::value_track_interpolate); ClassDB::bind_method(D_METHOD("method_track_get_key_indices", "track_idx", "time_sec", "delta"), &Animation::_method_track_get_key_indices); ClassDB::bind_method(D_METHOD("method_track_get_name", "track_idx", "key_idx"), &Animation::method_track_get_name); diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 722a400fd6..c52431f5f6 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -31,7 +31,7 @@ #ifndef ANIMATION_H #define ANIMATION_H -#include "core/resource.h" +#include "core/io/resource.h" class Animation : public Resource { GDCLASS(Animation, Resource); diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h index 59f3b4dc3c..56ff72c094 100644 --- a/scene/resources/bit_map.h +++ b/scene/resources/bit_map.h @@ -31,9 +31,9 @@ #ifndef BIT_MAP_H #define BIT_MAP_H -#include "core/image.h" +#include "core/io/image.h" +#include "core/io/resource.h" #include "core/io/resource_loader.h" -#include "core/resource.h" class BitMap : public Resource { GDCLASS(BitMap, Resource); diff --git a/scene/resources/box_shape_3d.cpp b/scene/resources/box_shape_3d.cpp index 69339faf76..e1c8a377c0 100644 --- a/scene/resources/box_shape_3d.cpp +++ b/scene/resources/box_shape_3d.cpp @@ -31,7 +31,7 @@ #include "box_shape_3d.h" #include "servers/physics_server_3d.h" -Vector<Vector3> BoxShape3D::get_debug_mesh_lines() { +Vector<Vector3> BoxShape3D::get_debug_mesh_lines() const { Vector<Vector3> lines; AABB aabb; aabb.position = -get_extents(); diff --git a/scene/resources/box_shape_3d.h b/scene/resources/box_shape_3d.h index 99b6410799..fe634ce568 100644 --- a/scene/resources/box_shape_3d.h +++ b/scene/resources/box_shape_3d.h @@ -46,7 +46,7 @@ public: void set_extents(const Vector3 &p_extents); Vector3 get_extents() const; - virtual Vector<Vector3> get_debug_mesh_lines() override; + virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override; BoxShape3D(); diff --git a/scene/resources/camera_effects.h b/scene/resources/camera_effects.h index 99fd4eb37c..9a26f3d0b2 100644 --- a/scene/resources/camera_effects.h +++ b/scene/resources/camera_effects.h @@ -31,8 +31,8 @@ #ifndef CAMERA_EFFECTS_H #define CAMERA_EFFECTS_H -#include "core/resource.h" -#include "core/rid.h" +#include "core/io/resource.h" +#include "core/templates/rid.h" class CameraEffects : public Resource { GDCLASS(CameraEffects, Resource); diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp index 28fc0d470c..9d1355eec6 100644 --- a/scene/resources/capsule_shape_3d.cpp +++ b/scene/resources/capsule_shape_3d.cpp @@ -31,7 +31,7 @@ #include "capsule_shape_3d.h" #include "servers/physics_server_3d.h" -Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() { +Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const { float radius = get_radius(); float height = get_height(); diff --git a/scene/resources/capsule_shape_3d.h b/scene/resources/capsule_shape_3d.h index a638618c48..432ca5654e 100644 --- a/scene/resources/capsule_shape_3d.h +++ b/scene/resources/capsule_shape_3d.h @@ -49,7 +49,7 @@ public: void set_height(float p_height); float get_height() const; - virtual Vector<Vector3> get_debug_mesh_lines() override; + virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override; CapsuleShape3D(); diff --git a/scene/resources/concave_polygon_shape_3d.cpp b/scene/resources/concave_polygon_shape_3d.cpp index 7315945c03..7cbafcbc4d 100644 --- a/scene/resources/concave_polygon_shape_3d.cpp +++ b/scene/resources/concave_polygon_shape_3d.cpp @@ -32,7 +32,7 @@ #include "servers/physics_server_3d.h" -Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() { +Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const { Set<DrawEdge> edges; Vector<Vector3> data = get_faces(); diff --git a/scene/resources/concave_polygon_shape_3d.h b/scene/resources/concave_polygon_shape_3d.h index a3c10adce2..c17765b9ef 100644 --- a/scene/resources/concave_polygon_shape_3d.h +++ b/scene/resources/concave_polygon_shape_3d.h @@ -65,7 +65,7 @@ public: void set_faces(const Vector<Vector3> &p_faces); Vector<Vector3> get_faces() const; - virtual Vector<Vector3> get_debug_mesh_lines() override; + virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override; ConcavePolygonShape3D(); diff --git a/scene/resources/convex_polygon_shape_3d.cpp b/scene/resources/convex_polygon_shape_3d.cpp index affeb05a8f..29549e1114 100644 --- a/scene/resources/convex_polygon_shape_3d.cpp +++ b/scene/resources/convex_polygon_shape_3d.cpp @@ -32,7 +32,7 @@ #include "core/math/quick_hull.h" #include "servers/physics_server_3d.h" -Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() { +Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const { Vector<Vector3> points = get_points(); if (points.size() > 3) { diff --git a/scene/resources/convex_polygon_shape_3d.h b/scene/resources/convex_polygon_shape_3d.h index 43d8b90740..f436d2f5d4 100644 --- a/scene/resources/convex_polygon_shape_3d.h +++ b/scene/resources/convex_polygon_shape_3d.h @@ -46,7 +46,7 @@ public: void set_points(const Vector<Vector3> &p_points); Vector<Vector3> get_points() const; - virtual Vector<Vector3> get_debug_mesh_lines() override; + virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override; ConvexPolygonShape3D(); diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 57ddaf897d..6c5f4b7057 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -31,7 +31,7 @@ #ifndef CURVE_H #define CURVE_H -#include "core/resource.h" +#include "core/io/resource.h" // y(x) curve class Curve : public Resource { diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp index 44786d6025..ad64541247 100644 --- a/scene/resources/cylinder_shape_3d.cpp +++ b/scene/resources/cylinder_shape_3d.cpp @@ -31,7 +31,7 @@ #include "cylinder_shape_3d.h" #include "servers/physics_server_3d.h" -Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() { +Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() const { float radius = get_radius(); float height = get_height(); diff --git a/scene/resources/cylinder_shape_3d.h b/scene/resources/cylinder_shape_3d.h index 2564a04a97..e579e1f7cf 100644 --- a/scene/resources/cylinder_shape_3d.h +++ b/scene/resources/cylinder_shape_3d.h @@ -48,7 +48,7 @@ public: void set_height(float p_height); float get_height() const; - virtual Vector<Vector3> get_debug_mesh_lines() override; + virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override; CylinderShape3D(); diff --git a/scene/resources/default_theme/bookmark.png b/scene/resources/default_theme/bookmark.png Binary files differnew file mode 100644 index 0000000000..9718cf53b6 --- /dev/null +++ b/scene/resources/default_theme/bookmark.png diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 9008f6d5b9..f65f78b332 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -382,8 +382,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("tab", "TextEdit", make_icon(tab_png)); theme->set_icon("space", "TextEdit", make_icon(space_png)); - theme->set_icon("folded", "TextEdit", make_icon(arrow_right_png)); - theme->set_icon("fold", "TextEdit", make_icon(arrow_down_png)); theme->set_font("font", "TextEdit", Ref<Font>()); @@ -398,16 +396,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_color_readonly", "TextEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); theme->set_color("selection_color", "TextEdit", font_color_selection); theme->set_color("mark_color", "TextEdit", Color(1.0, 0.4, 0.4, 0.4)); - theme->set_color("bookmark_color", "TextEdit", Color(0.08, 0.49, 0.98)); - theme->set_color("breakpoint_color", "TextEdit", Color(0.8, 0.8, 0.4, 0.2)); - theme->set_color("executing_line_color", "TextEdit", Color(0.2, 0.8, 0.2, 0.4)); theme->set_color("code_folding_color", "TextEdit", Color(0.8, 0.8, 0.8, 0.8)); theme->set_color("current_line_color", "TextEdit", Color(0.25, 0.25, 0.26, 0.8)); theme->set_color("caret_color", "TextEdit", control_font_color); theme->set_color("caret_background_color", "TextEdit", Color(0, 0, 0)); theme->set_color("brace_mismatch_color", "TextEdit", Color(1, 0.2, 0.2)); - theme->set_color("line_number_color", "TextEdit", Color(0.67, 0.67, 0.67, 0.4)); - theme->set_color("safe_line_number_color", "TextEdit", Color(0.67, 0.78, 0.67, 0.6)); theme->set_color("word_highlighted_color", "TextEdit", Color(0.8, 0.9, 0.9, 0.15)); theme->set_constant("completion_lines", "TextEdit", 7); @@ -415,6 +408,50 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("completion_scroll_width", "TextEdit", 3); theme->set_constant("line_spacing", "TextEdit", 4 * scale); + // CodeEdit + theme->set_stylebox("normal", "CodeEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0)); + theme->set_stylebox("focus", "CodeEdit", focus); + theme->set_stylebox("read_only", "CodeEdit", make_stylebox(tree_bg_disabled_png, 4, 4, 4, 4, 0, 0, 0, 0)); + theme->set_stylebox("completion", "CodeEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0)); + + theme->set_icon("tab", "CodeEdit", make_icon(tab_png)); + theme->set_icon("space", "CodeEdit", make_icon(space_png)); + theme->set_icon("breakpoint", "CodeEdit", make_icon(graph_port_png)); + theme->set_icon("bookmark", "CodeEdit", make_icon(bookmark_png)); + theme->set_icon("executing_line", "CodeEdit", make_icon(arrow_right_png)); + theme->set_icon("can_fold", "CodeEdit", make_icon(arrow_down_png)); + theme->set_icon("folded", "CodeEdit", make_icon(arrow_right_png)); + + theme->set_font("font", "CodeEdit", Ref<Font>()); + + theme->set_color("background_color", "CodeEdit", Color(0, 0, 0, 0)); + theme->set_color("completion_background_color", "CodeEdit", Color(0.17, 0.16, 0.2)); + theme->set_color("completion_selected_color", "CodeEdit", Color(0.26, 0.26, 0.27)); + theme->set_color("completion_existing_color", "CodeEdit", Color(0.87, 0.87, 0.87, 0.13)); + theme->set_color("completion_scroll_color", "CodeEdit", control_font_color_pressed); + theme->set_color("completion_font_color", "CodeEdit", Color(0.67, 0.67, 0.67)); + theme->set_color("font_color", "CodeEdit", control_font_color); + theme->set_color("font_color_selected", "CodeEdit", Color(0, 0, 0)); + theme->set_color("font_color_readonly", "CodeEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); + theme->set_color("selection_color", "CodeEdit", font_color_selection); + theme->set_color("mark_color", "CodeEdit", Color(1.0, 0.4, 0.4, 0.4)); + theme->set_color("bookmark_color", "CodeEdit", Color(0.5, 0.64, 1, 0.8)); + theme->set_color("breakpoint_color", "CodeEdit", Color(0.9, 0.29, 0.3)); + theme->set_color("executing_line_color", "CodeEdit", Color(0.98, 0.89, 0.27)); + theme->set_color("code_folding_color", "CodeEdit", Color(0.8, 0.8, 0.8, 0.8)); + theme->set_color("current_line_color", "CodeEdit", Color(0.25, 0.25, 0.26, 0.8)); + theme->set_color("caret_color", "CodeEdit", control_font_color); + theme->set_color("caret_background_color", "CodeEdit", Color(0, 0, 0)); + theme->set_color("brace_mismatch_color", "CodeEdit", Color(1, 0.2, 0.2)); + theme->set_color("line_number_color", "CodeEdit", Color(0.67, 0.67, 0.67, 0.4)); + theme->set_color("safe_line_number_color", "CodeEdit", Color(0.67, 0.78, 0.67, 0.6)); + theme->set_color("word_highlighted_color", "CodeEdit", Color(0.8, 0.9, 0.9, 0.15)); + + theme->set_constant("completion_lines", "CodeEdit", 7); + theme->set_constant("completion_max_width", "CodeEdit", 50); + theme->set_constant("completion_scroll_width", "CodeEdit", 3); + theme->set_constant("line_spacing", "CodeEdit", 4 * scale); + Ref<Texture2D> empty_icon = memnew(ImageTexture); // HScrollBar diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index edcdb90db9..a15efb593a 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -10,6 +10,10 @@ static const unsigned char arrow_right_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x17, 0x3c, 0xf8, 0xf, 0x82, 0xf7, 0x13, 0x70, 0x48, 0x3c, 0xf8, 0xf2, 0x50, 0x1b, 0x43, 0x2, 0xa, 0xaf, 0xbe, 0xe0, 0xc6, 0x2e, 0xf1, 0xff, 0xe1, 0x7c, 0x12, 0x24, 0x10, 0x46, 0x11, 0xb6, 0x1c, 0xe1, 0x5c, 0xa, 0x0, 0x0, 0xe0, 0x14, 0x48, 0xb1, 0x3d, 0x1b, 0x7a, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char bookmark_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x57, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xed, 0x93, 0x31, 0xa, 0xc0, 0x30, 0xc, 0x3, 0xa5, 0xd0, 0xff, 0x7f, 0x59, 0x1d, 0x8a, 0x42, 0x8, 0x9, 0x95, 0xc9, 0xd2, 0xa1, 0x9a, 0x8c, 0xf1, 0xdd, 0x62, 0x1b, 0x38, 0xc, 0x87, 0x5a, 0x5, 0xae, 0x79, 0xde, 0x2, 0x1, 0x80, 0x94, 0x39, 0x48, 0x76, 0x49, 0x17, 0xa4, 0xf0, 0x24, 0x61, 0x2b, 0x51, 0x8b, 0xfc, 0x82, 0xcf, 0xb, 0x48, 0x7a, 0xdf, 0x75, 0x81, 0xf, 0xe5, 0x29, 0xf7, 0x92, 0x6b, 0x3, 0x1a, 0x1e, 0xda, 0x7c, 0x3d, 0x77, 0x21, 0x7b, 0xa8, 0x74, 0x2e, 0xcb, 0xd, 0xc8, 0x75, 0x13, 0x28, 0x9, 0xed, 0xc2, 0xc8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char button_disabled_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xc7, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0xd0, 0x81, 0x66, 0x43, 0x31, 0x14, 0x87, 0xf1, 0xf, 0x5, 0x17, 0xb8, 0x28, 0x2e, 0x8, 0x71, 0xf3, 0x6, 0x19, 0xb6, 0xb9, 0xcb, 0xac, 0x95, 0xa4, 0xb7, 0xad, 0x6a, 0xd5, 0x68, 0x5f, 0xe4, 0x3e, 0x76, 0x1e, 0xe1, 0xbf, 0x21, 0xa6, 0xab, 0xf8, 0x1, 0x7c, 0x9c, 0x73, 0xe, 0xac, 0xe8, 0xe8, 0x19, 0x30, 0x58, 0xc6, 0xca, 0x62, 0x18, 0xe8, 0xe9, 0x58, 0x41, 0xc7, 0x1a, 0x87, 0x27, 0x10, 0x49, 0xe4, 0x5f, 0x89, 0x48, 0xc0, 0xe3, 0x58, 0xd3, 0x41, 0x8f, 0xb, 0xcb, 0xbd, 0x7c, 0xeb, 0xbf, 0x7b, 0x9, 0xb, 0x8e, 0x1e, 0x6, 0xfc, 0xad, 0x64, 0x6d, 0xb5, 0x79, 0xb0, 0x55, 0xd6, 0xad, 0xe0, 0x19, 0xc0, 0x10, 0xae, 0xda, 0x34, 0x5c, 0x45, 0xc0, 0x80, 0x25, 0x5e, 0xf4, 0xd5, 0x70, 0x11, 0x11, 0xb, 0x23, 0xe9, 0xac, 0xcf, 0x86, 0xb3, 0x48, 0x8c, 0x30, 0x92, 0x4f, 0xa, 0xd, 0x27, 0x91, 0x6b, 0x70, 0xd4, 0x47, 0xc3, 0xf1, 0x2f, 0x48, 0x7, 0x4d, 0xd, 0x87, 0x3a, 0xc2, 0x12, 0x67, 0xbd, 0x37, 0xcc, 0x75, 0x49, 0x43, 0xd8, 0xe9, 0xad, 0x61, 0x57, 0xcf, 0x1c, 0xf0, 0xfb, 0x32, 0xe9, 0xf5, 0xc9, 0xa4, 0x7d, 0x7d, 0x54, 0x8f, 0x7b, 0x59, 0xe6, 0x92, 0x14, 0x1f, 0x24, 0xcd, 0x3f, 0x7b, 0x6b, 0xa, 0xe, 0x6a, 0x82, 0x91, 0x45, 0x30, 0xba, 0x1, 0x4a, 0x51, 0xc4, 0x35, 0x1f, 0xe5, 0xa1, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index 99f87dd6ed..d76d364737 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -239,7 +239,7 @@ float DynamicFontAtSize::get_underline_thickness() const { return underline_thickness; } -const Pair<const DynamicFontAtSize::Character *, DynamicFontAtSize *> DynamicFontAtSize::_find_char_with_font(CharType p_char, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const { +const Pair<const DynamicFontAtSize::Character *, DynamicFontAtSize *> DynamicFontAtSize::_find_char_with_font(char32_t p_char, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const { const Character *chr = char_map.getptr(p_char); ERR_FAIL_COND_V(!chr, (Pair<const Character *, DynamicFontAtSize *>(nullptr, nullptr))); @@ -271,7 +271,7 @@ const Pair<const DynamicFontAtSize::Character *, DynamicFontAtSize *> DynamicFon return Pair<const Character *, DynamicFontAtSize *>(chr, const_cast<DynamicFontAtSize *>(this)); } -Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const { +Size2 DynamicFontAtSize::get_char_size(char32_t p_char, char32_t p_next, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const { if (!valid) { return Size2(1, 1); } @@ -297,7 +297,7 @@ String DynamicFontAtSize::get_available_chars() const { FT_ULong charcode = FT_Get_First_Char(face, &gindex); while (gindex != 0) { if (charcode != 0) { - chars += CharType(charcode); + chars += char32_t(charcode); } charcode = FT_Get_Next_Char(face, charcode, &gindex); } @@ -305,7 +305,7 @@ String DynamicFontAtSize::get_available_chars() const { return chars; } -float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only, bool p_outline) const { +float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only, bool p_outline) const { if (!valid) { return 0; } @@ -347,7 +347,7 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT modulate.r = modulate.g = modulate.b = 1.0; } RID texture = font->textures[ch->texture_idx].texture->get_rid(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), texture, ch->rect_uv, modulate, false, RID(), RID(), Color(1, 1, 1, 1), false); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), texture, ch->rect_uv, modulate, false, false); } advance = ch->advance; @@ -458,8 +458,21 @@ DynamicFontAtSize::TexturePosition DynamicFontAtSize::_find_texture_pos_for_glyp //zero texture uint8_t *w = tex.imgdata.ptrw(); ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.size(), ret); - for (int i = 0; i < texsize * texsize * p_color_size; i++) { - w[i] = 0; + + // Initialize the texture to all-white pixels to prevent artifacts when the + // font is displayed at a non-default scale with filtering enabled. + if (p_color_size == 2) { + for (int i = 0; i < texsize * texsize * p_color_size; i += 2) { + w[i + 0] = 255; + w[i + 1] = 0; + } + } else { + for (int i = 0; i < texsize * texsize * p_color_size; i += 4) { + w[i + 0] = 255; + w[i + 1] = 255; + w[i + 2] = 255; + w[i + 3] = 0; + } } } tex.offsets.resize(texsize); @@ -560,7 +573,7 @@ DynamicFontAtSize::Character DynamicFontAtSize::_bitmap_to_character(FT_Bitmap b return chr; } -DynamicFontAtSize::Character DynamicFontAtSize::_make_outline_char(CharType p_char) { +DynamicFontAtSize::Character DynamicFontAtSize::_make_outline_char(char32_t p_char) { Character ret = Character::not_found(); if (FT_Load_Char(face, p_char, FT_LOAD_NO_BITMAP | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)) != 0) { @@ -596,7 +609,7 @@ cleanup_stroker: return ret; } -void DynamicFontAtSize::_update_char(CharType p_char) { +void DynamicFontAtSize::_update_char(char32_t p_char) { if (char_map.has(p_char)) { return; } @@ -849,7 +862,7 @@ float DynamicFont::get_underline_thickness() const { return data_at_size->get_underline_thickness(); } -Size2 DynamicFont::get_char_size(CharType p_char, CharType p_next) const { +Size2 DynamicFont::get_char_size(char32_t p_char, char32_t p_next) const { if (!data_at_size.is_valid()) { return Size2(1, 1); } @@ -891,7 +904,7 @@ bool DynamicFont::has_outline() const { return outline_cache_id.outline_size > 0; } -float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const { +float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next, const Color &p_modulate, bool p_outline) const { const Ref<DynamicFontAtSize> &font_at_size = p_outline && outline_cache_id.outline_size > 0 ? outline_data_at_size : data_at_size; if (!font_at_size.is_valid()) { diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h index e8637e7e34..73ba42f8a7 100644 --- a/scene/resources/dynamic_font.h +++ b/scene/resources/dynamic_font.h @@ -37,7 +37,7 @@ #include "core/io/resource_loader.h" #include "core/os/mutex.h" #include "core/os/thread_safe.h" -#include "core/pair.h" +#include "core/templates/pair.h" #include "scene/resources/font.h" #include <ft2build.h> @@ -159,17 +159,17 @@ class DynamicFontAtSize : public Reference { int y; }; - const Pair<const Character *, DynamicFontAtSize *> _find_char_with_font(CharType p_char, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const; - Character _make_outline_char(CharType p_char); + const Pair<const Character *, DynamicFontAtSize *> _find_char_with_font(char32_t p_char, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const; + Character _make_outline_char(char32_t p_char); TexturePosition _find_texture_pos_for_glyph(int p_color_size, Image::Format p_image_format, int p_width, int p_height); Character _bitmap_to_character(FT_Bitmap bitmap, int yofs, int xofs, float advance); static unsigned long _ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count); static void _ft_stream_close(FT_Stream stream); - HashMap<CharType, Character> char_map; + HashMap<char32_t, Character> char_map; - _FORCE_INLINE_ void _update_char(CharType p_char); + _FORCE_INLINE_ void _update_char(char32_t p_char); friend class DynamicFontData; Ref<DynamicFontData> font; @@ -188,10 +188,10 @@ public: float get_underline_position() const; float get_underline_thickness() const; - Size2 get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const; + Size2 get_char_size(char32_t p_char, char32_t p_next, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const; String get_available_chars() const; - float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only = false, bool p_outline = false) const; + float draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only = false, bool p_outline = false) const; void set_texture_flags(uint32_t p_flags); void update_oversampling(); @@ -277,14 +277,14 @@ public: virtual float get_underline_position() const override; virtual float get_underline_thickness() const override; - virtual Size2 get_char_size(CharType p_char, CharType p_next = 0) const override; + virtual Size2 get_char_size(char32_t p_char, char32_t p_next = 0) const override; String get_available_chars() const; virtual bool is_distance_field_hint() const override; virtual bool has_outline() const override; - virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const override; + virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const override; SelfList<DynamicFont> font_list; diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 94629a77b9..bacdb6be54 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -30,7 +30,7 @@ #include "environment.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" #include "servers/rendering_server.h" #include "texture.h" @@ -44,6 +44,9 @@ void Environment::set_background(BGMode p_bg) { bg_mode = p_bg; RS::get_singleton()->environment_set_background(environment, RS::EnvironmentBG(p_bg)); _change_notify(); + if (bg_mode != BG_SKY) { + set_fog_aerial_perspective(0.0); + } } Environment::BGMode Environment::get_background() const { @@ -134,6 +137,7 @@ Color Environment::get_ambient_light_color() const { void Environment::set_ambient_source(AmbientSource p_source) { ambient_source = p_source; _update_ambient_light(); + _change_notify(); } Environment::AmbientSource Environment::get_ambient_source() const { @@ -161,6 +165,7 @@ float Environment::get_ambient_light_sky_contribution() const { void Environment::set_reflection_source(ReflectionSource p_source) { reflection_source = p_source; _update_ambient_light(); + _change_notify(); } Environment::ReflectionSource Environment::get_reflection_source() const { @@ -576,22 +581,28 @@ bool Environment::is_glow_enabled() const { return glow_enabled; } -void Environment::set_glow_level_enabled(int p_level, bool p_enabled) { +void Environment::set_glow_level(int p_level, float p_intensity) { ERR_FAIL_INDEX(p_level, RS::MAX_GLOW_LEVELS); - if (p_enabled) { - glow_levels |= (1 << p_level); - } else { - glow_levels &= ~(1 << p_level); - } + glow_levels.write[p_level] = p_intensity; _update_glow(); } -bool Environment::is_glow_level_enabled(int p_level) const { +float Environment::get_glow_level(int p_level) const { ERR_FAIL_INDEX_V(p_level, RS::MAX_GLOW_LEVELS, false); - return glow_levels & (1 << p_level); + return glow_levels[p_level]; +} + +void Environment::set_glow_normalized(bool p_normalized) { + glow_normalize_levels = p_normalized; + + _update_glow(); +} + +bool Environment::is_glow_normalized() const { + return glow_normalize_levels; } void Environment::set_glow_intensity(float p_intensity) { @@ -668,10 +679,24 @@ float Environment::get_glow_hdr_luminance_cap() const { } void Environment::_update_glow() { + Vector<float> normalized_levels; + if (glow_normalize_levels) { + normalized_levels.resize(7); + float size = 0.0; + for (int i = 0; i < glow_levels.size(); i++) { + size += glow_levels[i]; + } + for (int i = 0; i < glow_levels.size(); i++) { + normalized_levels.write[i] = glow_levels[i] / size; + } + } else { + normalized_levels = glow_levels; + } + RS::get_singleton()->environment_set_glow( environment, glow_enabled, - glow_levels, + normalized_levels, glow_intensity, glow_strength, glow_mix, @@ -694,150 +719,137 @@ bool Environment::is_fog_enabled() const { return fog_enabled; } -void Environment::set_fog_color(const Color &p_color) { - fog_color = p_color; +void Environment::set_fog_light_color(const Color &p_light_color) { + fog_light_color = p_light_color; _update_fog(); } - -Color Environment::get_fog_color() const { - return fog_color; +Color Environment::get_fog_light_color() const { + return fog_light_color; } - -void Environment::set_fog_sun_color(const Color &p_color) { - fog_sun_color = p_color; +void Environment::set_fog_light_energy(float p_amount) { + fog_light_energy = p_amount; _update_fog(); } - -Color Environment::get_fog_sun_color() const { - return fog_sun_color; +float Environment::get_fog_light_energy() const { + return fog_light_energy; } - -void Environment::set_fog_sun_amount(float p_amount) { - fog_sun_amount = p_amount; +void Environment::set_fog_sun_scatter(float p_amount) { + fog_sun_scatter = p_amount; _update_fog(); } - -float Environment::get_fog_sun_amount() const { - return fog_sun_amount; +float Environment::get_fog_sun_scatter() const { + return fog_sun_scatter; } - -void Environment::_update_fog() { - RS::get_singleton()->environment_set_fog( - environment, - fog_enabled, - fog_color, - fog_sun_color, - fog_sun_amount); +void Environment::set_fog_density(float p_amount) { + fog_density = p_amount; + _update_fog(); } - -void Environment::set_fog_depth_enabled(bool p_enabled) { - fog_depth_enabled = p_enabled; - _update_fog_depth(); +float Environment::get_fog_density() const { + return fog_density; } - -bool Environment::is_fog_depth_enabled() const { - return fog_depth_enabled; +void Environment::set_fog_height(float p_amount) { + fog_height = p_amount; + _update_fog(); } - -void Environment::set_fog_depth_begin(float p_distance) { - fog_depth_begin = p_distance; - _update_fog_depth(); +float Environment::get_fog_height() const { + return fog_height; } - -float Environment::get_fog_depth_begin() const { - return fog_depth_begin; +void Environment::set_fog_height_density(float p_amount) { + fog_height_density = p_amount; + _update_fog(); } - -void Environment::set_fog_depth_end(float p_distance) { - fog_depth_end = p_distance; - _update_fog_depth(); +float Environment::get_fog_height_density() const { + return fog_height_density; } -float Environment::get_fog_depth_end() const { - return fog_depth_end; +void Environment::set_fog_aerial_perspective(float p_aerial_perspective) { + fog_aerial_perspective = p_aerial_perspective; + _update_fog(); } - -void Environment::set_fog_depth_curve(float p_curve) { - fog_depth_curve = p_curve; - _update_fog_depth(); +float Environment::get_fog_aerial_perspective() const { + return fog_aerial_perspective; } -float Environment::get_fog_depth_curve() const { - return fog_depth_curve; +void Environment::_update_fog() { + RS::get_singleton()->environment_set_fog( + environment, + fog_enabled, + fog_light_color, + fog_light_energy, + fog_sun_scatter, + fog_density, + fog_height, + fog_height_density, + fog_aerial_perspective); } -void Environment::set_fog_transmit_enabled(bool p_enabled) { - fog_transmit_enabled = p_enabled; - _update_fog_depth(); -} +// Volumetric Fog -bool Environment::is_fog_transmit_enabled() const { - return fog_transmit_enabled; +void Environment::_update_volumetric_fog() { + RS::get_singleton()->environment_set_volumetric_fog(environment, volumetric_fog_enabled, volumetric_fog_density, volumetric_fog_light, volumetric_fog_light_energy, volumetric_fog_length, volumetric_fog_detail_spread, volumetric_fog_gi_inject, RS::EnvVolumetricFogShadowFilter(volumetric_fog_shadow_filter)); } -void Environment::set_fog_transmit_curve(float p_curve) { - fog_transmit_curve = p_curve; - _update_fog_depth(); +void Environment::set_volumetric_fog_enabled(bool p_enable) { + volumetric_fog_enabled = p_enable; + _update_volumetric_fog(); + _change_notify(); } -float Environment::get_fog_transmit_curve() const { - return fog_transmit_curve; +bool Environment::is_volumetric_fog_enabled() const { + return volumetric_fog_enabled; } - -void Environment::_update_fog_depth() { - RS::get_singleton()->environment_set_fog_depth( - environment, - fog_depth_enabled, - fog_depth_begin, - fog_depth_end, - fog_depth_curve, - fog_transmit_enabled, - fog_transmit_curve); +void Environment::set_volumetric_fog_density(float p_density) { + p_density = CLAMP(p_density, 0.0000001, 1.0); + volumetric_fog_density = p_density; + _update_volumetric_fog(); } - -void Environment::set_fog_height_enabled(bool p_enabled) { - fog_height_enabled = p_enabled; - _update_fog_height(); +float Environment::get_volumetric_fog_density() const { + return volumetric_fog_density; } - -bool Environment::is_fog_height_enabled() const { - return fog_height_enabled; +void Environment::set_volumetric_fog_light(Color p_color) { + volumetric_fog_light = p_color; + _update_volumetric_fog(); } - -void Environment::set_fog_height_min(float p_distance) { - fog_height_min = p_distance; - _update_fog_height(); +Color Environment::get_volumetric_fog_light() const { + return volumetric_fog_light; } - -float Environment::get_fog_height_min() const { - return fog_height_min; +void Environment::set_volumetric_fog_light_energy(float p_begin) { + volumetric_fog_light_energy = p_begin; + _update_volumetric_fog(); } - -void Environment::set_fog_height_max(float p_distance) { - fog_height_max = p_distance; - _update_fog_height(); +float Environment::get_volumetric_fog_light_energy() const { + return volumetric_fog_light_energy; } - -float Environment::get_fog_height_max() const { - return fog_height_max; +void Environment::set_volumetric_fog_length(float p_length) { + volumetric_fog_length = p_length; + _update_volumetric_fog(); +} +float Environment::get_volumetric_fog_length() const { + return volumetric_fog_length; +} +void Environment::set_volumetric_fog_detail_spread(float p_detail_spread) { + volumetric_fog_detail_spread = p_detail_spread; + _update_volumetric_fog(); +} +float Environment::get_volumetric_fog_detail_spread() const { + return volumetric_fog_detail_spread; } -void Environment::set_fog_height_curve(float p_distance) { - fog_height_curve = p_distance; - _update_fog_height(); +void Environment::set_volumetric_fog_gi_inject(float p_gi_inject) { + volumetric_fog_gi_inject = p_gi_inject; + _update_volumetric_fog(); +} +float Environment::get_volumetric_fog_gi_inject() const { + return volumetric_fog_gi_inject; } -float Environment::get_fog_height_curve() const { - return fog_height_curve; +void Environment::set_volumetric_fog_shadow_filter(VolumetricFogShadowFilter p_filter) { + volumetric_fog_shadow_filter = p_filter; + _update_volumetric_fog(); } -void Environment::_update_fog_height() { - RS::get_singleton()->environment_set_fog_height( - environment, - fog_height_enabled, - fog_height_min, - fog_height_max, - fog_height_curve); +Environment::VolumetricFogShadowFilter Environment::get_volumetric_fog_shadow_filter() const { + return volumetric_fog_shadow_filter; } // Adjustment @@ -907,6 +919,12 @@ void Environment::_validate_property(PropertyInfo &property) const { } } + if (property.name == "fog_aerial_perspective") { + if (bg_mode != BG_SKY) { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } + } + if (property.name == "glow_intensity" && glow_blend_mode == GLOW_BLEND_MODE_MIX) { property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; } @@ -935,6 +953,7 @@ void Environment::_validate_property(PropertyInfo &property) const { static const char *hide_prefixes[] = { "fog_", + "volumetric_fog_", "auto_exposure_", "ss_reflections_", "ssao_", @@ -1181,8 +1200,10 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("set_glow_enabled", "enabled"), &Environment::set_glow_enabled); ClassDB::bind_method(D_METHOD("is_glow_enabled"), &Environment::is_glow_enabled); - ClassDB::bind_method(D_METHOD("set_glow_level_enabled", "idx", "enabled"), &Environment::set_glow_level_enabled); - ClassDB::bind_method(D_METHOD("is_glow_level_enabled", "idx"), &Environment::is_glow_level_enabled); + ClassDB::bind_method(D_METHOD("set_glow_level", "idx", "intensity"), &Environment::set_glow_level); + ClassDB::bind_method(D_METHOD("get_glow_level", "idx"), &Environment::get_glow_level); + ClassDB::bind_method(D_METHOD("set_glow_normalized", "normalize"), &Environment::set_glow_normalized); + ClassDB::bind_method(D_METHOD("is_glow_normalized"), &Environment::is_glow_normalized); ClassDB::bind_method(D_METHOD("set_glow_intensity", "intensity"), &Environment::set_glow_intensity); ClassDB::bind_method(D_METHOD("get_glow_intensity"), &Environment::get_glow_intensity); ClassDB::bind_method(D_METHOD("set_glow_strength", "strength"), &Environment::set_glow_strength); @@ -1202,13 +1223,14 @@ void Environment::_bind_methods() { ADD_GROUP("Glow", "glow_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "glow_enabled"), "set_glow_enabled", "is_glow_enabled"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/1"), "set_glow_level_enabled", "is_glow_level_enabled", 0); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/2"), "set_glow_level_enabled", "is_glow_level_enabled", 1); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/3"), "set_glow_level_enabled", "is_glow_level_enabled", 2); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/4"), "set_glow_level_enabled", "is_glow_level_enabled", 3); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/5"), "set_glow_level_enabled", "is_glow_level_enabled", 4); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/6"), "set_glow_level_enabled", "is_glow_level_enabled", 5); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/7"), "set_glow_level_enabled", "is_glow_level_enabled", 6); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/1", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 0); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/2", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 1); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/3", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 2); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/4", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 3); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/5", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 4); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/6", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 5); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/7", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 6); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "glow_normalized"), "set_glow_normalized", "is_glow_normalized"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_intensity", PROPERTY_HINT_RANGE, "0.0,8.0,0.01"), "set_glow_intensity", "get_glow_intensity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_strength", PROPERTY_HINT_RANGE, "0.0,2.0,0.01"), "set_glow_strength", "get_glow_strength"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_mix", PROPERTY_HINT_RANGE, "0.0,1.0,0.001"), "set_glow_mix", "get_glow_mix"); @@ -1222,52 +1244,62 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("set_fog_enabled", "enabled"), &Environment::set_fog_enabled); ClassDB::bind_method(D_METHOD("is_fog_enabled"), &Environment::is_fog_enabled); - ClassDB::bind_method(D_METHOD("set_fog_color", "color"), &Environment::set_fog_color); - ClassDB::bind_method(D_METHOD("get_fog_color"), &Environment::get_fog_color); - ClassDB::bind_method(D_METHOD("set_fog_sun_color", "color"), &Environment::set_fog_sun_color); - ClassDB::bind_method(D_METHOD("get_fog_sun_color"), &Environment::get_fog_sun_color); - ClassDB::bind_method(D_METHOD("set_fog_sun_amount", "amount"), &Environment::set_fog_sun_amount); - ClassDB::bind_method(D_METHOD("get_fog_sun_amount"), &Environment::get_fog_sun_amount); - - ClassDB::bind_method(D_METHOD("set_fog_depth_enabled", "enabled"), &Environment::set_fog_depth_enabled); - ClassDB::bind_method(D_METHOD("is_fog_depth_enabled"), &Environment::is_fog_depth_enabled); - ClassDB::bind_method(D_METHOD("set_fog_depth_begin", "distance"), &Environment::set_fog_depth_begin); - ClassDB::bind_method(D_METHOD("get_fog_depth_begin"), &Environment::get_fog_depth_begin); - ClassDB::bind_method(D_METHOD("set_fog_depth_end", "distance"), &Environment::set_fog_depth_end); - ClassDB::bind_method(D_METHOD("get_fog_depth_end"), &Environment::get_fog_depth_end); - ClassDB::bind_method(D_METHOD("set_fog_depth_curve", "curve"), &Environment::set_fog_depth_curve); - ClassDB::bind_method(D_METHOD("get_fog_depth_curve"), &Environment::get_fog_depth_curve); - ClassDB::bind_method(D_METHOD("set_fog_transmit_enabled", "enabled"), &Environment::set_fog_transmit_enabled); - ClassDB::bind_method(D_METHOD("is_fog_transmit_enabled"), &Environment::is_fog_transmit_enabled); - ClassDB::bind_method(D_METHOD("set_fog_transmit_curve", "curve"), &Environment::set_fog_transmit_curve); - ClassDB::bind_method(D_METHOD("get_fog_transmit_curve"), &Environment::get_fog_transmit_curve); - - ClassDB::bind_method(D_METHOD("set_fog_height_enabled", "enabled"), &Environment::set_fog_height_enabled); - ClassDB::bind_method(D_METHOD("is_fog_height_enabled"), &Environment::is_fog_height_enabled); - ClassDB::bind_method(D_METHOD("set_fog_height_min", "height"), &Environment::set_fog_height_min); - ClassDB::bind_method(D_METHOD("get_fog_height_min"), &Environment::get_fog_height_min); - ClassDB::bind_method(D_METHOD("set_fog_height_max", "height"), &Environment::set_fog_height_max); - ClassDB::bind_method(D_METHOD("get_fog_height_max"), &Environment::get_fog_height_max); - ClassDB::bind_method(D_METHOD("set_fog_height_curve", "curve"), &Environment::set_fog_height_curve); - ClassDB::bind_method(D_METHOD("get_fog_height_curve"), &Environment::get_fog_height_curve); + ClassDB::bind_method(D_METHOD("set_fog_light_color", "light_color"), &Environment::set_fog_light_color); + ClassDB::bind_method(D_METHOD("get_fog_light_color"), &Environment::get_fog_light_color); + ClassDB::bind_method(D_METHOD("set_fog_light_energy", "light_energy"), &Environment::set_fog_light_energy); + ClassDB::bind_method(D_METHOD("get_fog_light_energy"), &Environment::get_fog_light_energy); + ClassDB::bind_method(D_METHOD("set_fog_sun_scatter", "sun_scatter"), &Environment::set_fog_sun_scatter); + ClassDB::bind_method(D_METHOD("get_fog_sun_scatter"), &Environment::get_fog_sun_scatter); + + ClassDB::bind_method(D_METHOD("set_fog_density", "density"), &Environment::set_fog_density); + ClassDB::bind_method(D_METHOD("get_fog_density"), &Environment::get_fog_density); + + ClassDB::bind_method(D_METHOD("set_fog_height", "height"), &Environment::set_fog_height); + ClassDB::bind_method(D_METHOD("get_fog_height"), &Environment::get_fog_height); + + ClassDB::bind_method(D_METHOD("set_fog_height_density", "height_density"), &Environment::set_fog_height_density); + ClassDB::bind_method(D_METHOD("get_fog_height_density"), &Environment::get_fog_height_density); + + ClassDB::bind_method(D_METHOD("set_fog_aerial_perspective", "aerial_perspective"), &Environment::set_fog_aerial_perspective); + ClassDB::bind_method(D_METHOD("get_fog_aerial_perspective"), &Environment::get_fog_aerial_perspective); ADD_GROUP("Fog", "fog_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_enabled"), "set_fog_enabled", "is_fog_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_color"), "set_fog_color", "get_fog_color"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_sun_color"), "set_fog_sun_color", "get_fog_sun_color"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_sun_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_fog_sun_amount", "get_fog_sun_amount"); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_depth_enabled"), "set_fog_depth_enabled", "is_fog_depth_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_depth_begin", PROPERTY_HINT_RANGE, "0,4000,0.1"), "set_fog_depth_begin", "get_fog_depth_begin"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_depth_end", PROPERTY_HINT_RANGE, "0,4000,0.1,or_greater"), "set_fog_depth_end", "get_fog_depth_end"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_depth_curve", PROPERTY_HINT_EXP_EASING), "set_fog_depth_curve", "get_fog_depth_curve"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_transmit_enabled"), "set_fog_transmit_enabled", "is_fog_transmit_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_transmit_curve", PROPERTY_HINT_EXP_EASING), "set_fog_transmit_curve", "get_fog_transmit_curve"); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_height_enabled"), "set_fog_height_enabled", "is_fog_height_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_min", PROPERTY_HINT_RANGE, "-4000,4000,0.1,or_lesser,or_greater"), "set_fog_height_min", "get_fog_height_min"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_max", PROPERTY_HINT_RANGE, "-4000,4000,0.1,or_lesser,or_greater"), "set_fog_height_max", "get_fog_height_max"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_curve", PROPERTY_HINT_EXP_EASING), "set_fog_height_curve", "get_fog_height_curve"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_fog_light_color", "get_fog_light_color"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_fog_light_energy", "get_fog_light_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_sun_scatter", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater"), "set_fog_sun_scatter", "get_fog_sun_scatter"); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_density", PROPERTY_HINT_RANGE, "0,16,0.0001"), "set_fog_density", "get_fog_density"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_aerial_perspective", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_fog_aerial_perspective", "get_fog_aerial_perspective"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_lesser,or_greater"), "set_fog_height", "get_fog_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_density", PROPERTY_HINT_RANGE, "0,128,0.001,or_greater"), "set_fog_height_density", "get_fog_height_density"); + + ClassDB::bind_method(D_METHOD("set_volumetric_fog_enabled", "enabled"), &Environment::set_volumetric_fog_enabled); + ClassDB::bind_method(D_METHOD("is_volumetric_fog_enabled"), &Environment::is_volumetric_fog_enabled); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_light", "color"), &Environment::set_volumetric_fog_light); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_light"), &Environment::get_volumetric_fog_light); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_density", "density"), &Environment::set_volumetric_fog_density); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_density"), &Environment::get_volumetric_fog_density); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_light_energy", "begin"), &Environment::set_volumetric_fog_light_energy); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_light_energy"), &Environment::get_volumetric_fog_light_energy); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_length", "length"), &Environment::set_volumetric_fog_length); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_length"), &Environment::get_volumetric_fog_length); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_detail_spread", "detail_spread"), &Environment::set_volumetric_fog_detail_spread); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_detail_spread"), &Environment::get_volumetric_fog_detail_spread); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_gi_inject", "gi_inject"), &Environment::set_volumetric_fog_gi_inject); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_gi_inject"), &Environment::get_volumetric_fog_gi_inject); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_shadow_filter", "shadow_filter"), &Environment::set_volumetric_fog_shadow_filter); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_shadow_filter"), &Environment::get_volumetric_fog_shadow_filter); + + ADD_GROUP("Volumetric Fog", "volumetric_fog_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_enabled"), "set_volumetric_fog_enabled", "is_volumetric_fog_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_density", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater"), "set_volumetric_fog_density", "get_volumetric_fog_density"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "volumetric_fog_light", PROPERTY_HINT_COLOR_NO_ALPHA), "set_volumetric_fog_light", "get_volumetric_fog_light"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_light_energy", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_light_energy", "get_volumetric_fog_light_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_gi_inject", PROPERTY_HINT_EXP_RANGE, "0.00,16,0.01"), "set_volumetric_fog_gi_inject", "get_volumetric_fog_gi_inject"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_length", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_length", "get_volumetric_fog_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING, "0.01,16,0.01"), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "volumetric_fog_shadow_filter", PROPERTY_HINT_ENUM, "Disabled,Low,Medium,High"), "set_volumetric_fog_shadow_filter", "get_volumetric_fog_shadow_filter"); // Adjustment @@ -1331,12 +1363,27 @@ void Environment::_bind_methods() { BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_DISABLED); BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_75_PERCENT); BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_50_PERCENT); + + BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED); + BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_LOW); + BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM); + BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_HIGH); } Environment::Environment() { environment = RS::get_singleton()->environment_create(); set_camera_feed_id(bg_camera_feed_id); + + glow_levels.resize(7); + glow_levels.write[0] = 0.0; + glow_levels.write[1] = 0.0; + glow_levels.write[2] = 1.0; + glow_levels.write[3] = 0.0; + glow_levels.write[4] = 1.0; + glow_levels.write[5] = 0.0; + glow_levels.write[6] = 0.0; + _update_ambient_light(); _update_tonemap(); _update_ssr(); @@ -1344,10 +1391,8 @@ Environment::Environment() { _update_sdfgi(); _update_glow(); _update_fog(); - _update_fog_depth(); - _update_fog_height(); _update_adjustment(); - + _update_volumetric_fog(); _change_notify(); } diff --git a/scene/resources/environment.h b/scene/resources/environment.h index f334d22115..23c7f5180c 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -31,7 +31,7 @@ #ifndef ENVIRONMENT_H #define ENVIRONMENT_H -#include "core/resource.h" +#include "core/io/resource.h" #include "scene/resources/sky.h" #include "scene/resources/texture.h" #include "servers/rendering_server.h" @@ -97,6 +97,13 @@ public: GLOW_BLEND_MODE_MIX, }; + enum VolumetricFogShadowFilter { + VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED, + VOLUMETRIC_FOG_SHADOW_FILTER_LOW, + VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM, + VOLUMETRIC_FOG_SHADOW_FILTER_HIGH, + }; + private: RID environment; @@ -164,7 +171,8 @@ private: // Glow bool glow_enabled = false; - int glow_levels = (1 << 2) | (1 << 4); + Vector<float> glow_levels; + bool glow_normalize_levels = false; float glow_intensity = 0.8; float glow_strength = 1.0; float glow_mix = 0.05; @@ -177,24 +185,26 @@ private: // Fog bool fog_enabled = false; - Color fog_color = Color(0.5, 0.6, 0.7); - Color fog_sun_color = Color(1.0, 0.9, 0.7); - float fog_sun_amount = 0.0; - void _update_fog(); + Color fog_light_color = Color(0.5, 0.6, 0.7); + float fog_light_energy = 1.0; + float fog_sun_scatter = 0.0; + float fog_density = 0.001; + float fog_height = 0.0; + float fog_height_density = 0.0; //can be negative to invert effect + float fog_aerial_perspective = 0.0; - bool fog_depth_enabled = true; - float fog_depth_begin = 10.0; - float fog_depth_end = 100.0; - float fog_depth_curve = 1.0; - bool fog_transmit_enabled = false; - float fog_transmit_curve = 1.0; - void _update_fog_depth(); + void _update_fog(); - bool fog_height_enabled = false; - float fog_height_min = 10.0; - float fog_height_max = 0.0; - float fog_height_curve = 1.0; - void _update_fog_height(); + // Volumetric Fog + bool volumetric_fog_enabled = false; + float volumetric_fog_density = 0.01; + Color volumetric_fog_light = Color(0.0, 0.0, 0.0); + float volumetric_fog_light_energy = 1.0; + float volumetric_fog_length = 64.0; + float volumetric_fog_detail_spread = 2.0; + VolumetricFogShadowFilter volumetric_fog_shadow_filter = VOLUMETRIC_FOG_SHADOW_FILTER_LOW; + float volumetric_fog_gi_inject = 0.0; + void _update_volumetric_fog(); // Adjustment bool adjustment_enabled = false; @@ -324,8 +334,10 @@ public: // Glow void set_glow_enabled(bool p_enabled); bool is_glow_enabled() const; - void set_glow_level_enabled(int p_level, bool p_enabled); - bool is_glow_level_enabled(int p_level) const; + void set_glow_level(int p_level, float p_intensity); + float get_glow_level(int p_level) const; + void set_glow_normalized(bool p_normalized); + bool is_glow_normalized() const; void set_glow_intensity(float p_intensity); float get_glow_intensity() const; void set_glow_strength(float p_strength); @@ -344,36 +356,42 @@ public: float get_glow_hdr_luminance_cap() const; // Fog + void set_fog_enabled(bool p_enabled); bool is_fog_enabled() const; - void set_fog_color(const Color &p_color); - Color get_fog_color() const; - void set_fog_sun_color(const Color &p_color); - Color get_fog_sun_color() const; - void set_fog_sun_amount(float p_amount); - float get_fog_sun_amount() const; - - void set_fog_depth_enabled(bool p_enabled); - bool is_fog_depth_enabled() const; - void set_fog_depth_begin(float p_distance); - float get_fog_depth_begin() const; - void set_fog_depth_end(float p_distance); - float get_fog_depth_end() const; - void set_fog_depth_curve(float p_curve); - float get_fog_depth_curve() const; - void set_fog_transmit_enabled(bool p_enabled); - bool is_fog_transmit_enabled() const; - void set_fog_transmit_curve(float p_curve); - float get_fog_transmit_curve() const; - - void set_fog_height_enabled(bool p_enabled); - bool is_fog_height_enabled() const; - void set_fog_height_min(float p_distance); - float get_fog_height_min() const; - void set_fog_height_max(float p_distance); - float get_fog_height_max() const; - void set_fog_height_curve(float p_distance); - float get_fog_height_curve() const; + void set_fog_light_color(const Color &p_light_color); + Color get_fog_light_color() const; + void set_fog_light_energy(float p_amount); + float get_fog_light_energy() const; + void set_fog_sun_scatter(float p_amount); + float get_fog_sun_scatter() const; + + void set_fog_density(float p_amount); + float get_fog_density() const; + void set_fog_height(float p_amount); + float get_fog_height() const; + void set_fog_height_density(float p_amount); + float get_fog_height_density() const; + void set_fog_aerial_perspective(float p_aerial_perspective); + float get_fog_aerial_perspective() const; + + // Volumetric Fog + void set_volumetric_fog_enabled(bool p_enable); + bool is_volumetric_fog_enabled() const; + void set_volumetric_fog_density(float p_density); + float get_volumetric_fog_density() const; + void set_volumetric_fog_light(Color p_color); + Color get_volumetric_fog_light() const; + void set_volumetric_fog_light_energy(float p_begin); + float get_volumetric_fog_light_energy() const; + void set_volumetric_fog_length(float p_length); + float get_volumetric_fog_length() const; + void set_volumetric_fog_detail_spread(float p_detail_spread); + float get_volumetric_fog_detail_spread() const; + void set_volumetric_fog_shadow_filter(VolumetricFogShadowFilter p_filter); + VolumetricFogShadowFilter get_volumetric_fog_shadow_filter() const; + void set_volumetric_fog_gi_inject(float p_gi_inject); + float get_volumetric_fog_gi_inject() const; // Adjustment void set_adjustment_enabled(bool p_enabled); @@ -399,5 +417,6 @@ VARIANT_ENUM_CAST(Environment::SSAOBlur) VARIANT_ENUM_CAST(Environment::SDFGICascades) VARIANT_ENUM_CAST(Environment::SDFGIYScale) VARIANT_ENUM_CAST(Environment::GlowBlendMode) +VARIANT_ENUM_CAST(Environment::VolumetricFogShadowFilter) #endif // ENVIRONMENT_H diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index ccab88a153..7bda889e46 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -31,7 +31,6 @@ #include "font.h" #include "core/io/resource_loader.h" -#include "core/method_bind_ext.gen.inc" #include "core/os/file_access.h" void Font::draw_halign(RID p_canvas_item, const Point2 &p_pos, HAlign p_align, float p_width, const String &p_text, const Color &p_modulate, const Color &p_outline_modulate) const { @@ -125,7 +124,7 @@ void BitmapFont::_set_chars(const Vector<int> &p_chars) { Vector<int> BitmapFont::_get_chars() const { Vector<int> chars; - const CharType *key = nullptr; + const char32_t *key = nullptr; while ((key = char_map.next(key))) { const Character *c = char_map.getptr(*key); @@ -272,7 +271,7 @@ Error BitmapFont::create_from_fnt(const String &p_file) { } } } else if (type == "char") { - CharType idx = 0; + char32_t idx = 0; if (keys.has("id")) { idx = keys["id"].to_int(); } @@ -313,7 +312,7 @@ Error BitmapFont::create_from_fnt(const String &p_file) { add_char(idx, texture, rect, ofs, advance); } else if (type == "kerning") { - CharType first = 0, second = 0; + char32_t first = 0, second = 0; int k = 0; if (keys.has("first")) { @@ -385,10 +384,10 @@ int BitmapFont::get_character_count() const { return char_map.size(); }; -Vector<CharType> BitmapFont::get_char_keys() const { - Vector<CharType> chars; +Vector<char32_t> BitmapFont::get_char_keys() const { + Vector<char32_t> chars; chars.resize(char_map.size()); - const CharType *ct = nullptr; + const char32_t *ct = nullptr; int count = 0; while ((ct = char_map.next(ct))) { chars.write[count++] = *ct; @@ -397,7 +396,7 @@ Vector<CharType> BitmapFont::get_char_keys() const { return chars; }; -BitmapFont::Character BitmapFont::get_character(CharType p_char) const { +BitmapFont::Character BitmapFont::get_character(char32_t p_char) const { if (!char_map.has(p_char)) { ERR_FAIL_V(Character()); }; @@ -405,7 +404,7 @@ BitmapFont::Character BitmapFont::get_character(CharType p_char) const { return char_map[p_char]; }; -void BitmapFont::add_char(CharType p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) { +void BitmapFont::add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) { if (p_advance < 0) { p_advance = p_rect.size.width; } @@ -420,7 +419,7 @@ void BitmapFont::add_char(CharType p_char, int p_texture_idx, const Rect2 &p_rec char_map[p_char] = c; } -void BitmapFont::add_kerning_pair(CharType p_A, CharType p_B, int p_kerning) { +void BitmapFont::add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) { KerningPairKey kpk; kpk.A = p_A; kpk.B = p_B; @@ -444,7 +443,7 @@ Vector<BitmapFont::KerningPairKey> BitmapFont::get_kerning_pair_keys() const { return ret; } -int BitmapFont::get_kerning_pair(CharType p_A, CharType p_B) const { +int BitmapFont::get_kerning_pair(char32_t p_A, char32_t p_B) const { KerningPairKey kpk; kpk.A = p_A; kpk.B = p_B; @@ -482,7 +481,7 @@ Size2 Font::get_string_size(const String &p_string) const { if (l == 0) { return Size2(0, get_height()); } - const CharType *sptr = &p_string[0]; + const char32_t *sptr = &p_string[0]; for (int i = 0; i < l; i++) { w += get_char_size(sptr[i], sptr[i + 1]).width; @@ -534,7 +533,7 @@ Ref<BitmapFont> BitmapFont::get_fallback() const { return fallback; } -float BitmapFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const { +float BitmapFont::draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next, const Color &p_modulate, bool p_outline) const { const Character *c = char_map.getptr(p_char); if (!c) { @@ -550,13 +549,13 @@ float BitmapFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_c cpos.x += c->h_align; cpos.y -= ascent; cpos.y += c->v_align; - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx]->get_rid(), c->rect, p_modulate, false, RID(), RID(), Color(1, 1, 1, 1), false); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx]->get_rid(), c->rect, p_modulate, false, false); } return get_char_size(p_char, p_next).width; } -Size2 BitmapFont::get_char_size(CharType p_char, CharType p_next) const { +Size2 BitmapFont::get_char_size(char32_t p_char, char32_t p_next) const { const Character *c = char_map.getptr(p_char); if (!c) { diff --git a/scene/resources/font.h b/scene/resources/font.h index e6b296800b..d8c350bb41 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -31,8 +31,8 @@ #ifndef FONT_H #define FONT_H -#include "core/map.h" -#include "core/resource.h" +#include "core/io/resource.h" +#include "core/templates/map.h" #include "scene/resources/texture.h" class Font : public Resource { @@ -49,7 +49,7 @@ public: virtual float get_underline_position() const = 0; virtual float get_underline_thickness() const = 0; - virtual Size2 get_char_size(CharType p_char, CharType p_next = 0) const = 0; + virtual Size2 get_char_size(char32_t p_char, char32_t p_next = 0) const = 0; Size2 get_string_size(const String &p_string) const; Size2 get_wordwrap_string_size(const String &p_string, float p_width) const; @@ -59,7 +59,7 @@ public: void draw_halign(RID p_canvas_item, const Point2 &p_pos, HAlign p_align, float p_width, const String &p_text, const Color &p_modulate = Color(1, 1, 1), const Color &p_outline_modulate = Color(1, 1, 1)) const; virtual bool has_outline() const { return false; } - virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const = 0; + virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const = 0; void update_changes(); Font(); @@ -74,8 +74,8 @@ class FontDrawer { struct PendingDraw { RID canvas_item; Point2 pos; - CharType chr; - CharType next; + char32_t chr; + char32_t next; Color modulate; }; @@ -88,7 +88,7 @@ public: has_outline = p_font->has_outline(); } - float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1)) { + float draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next = 0, const Color &p_modulate = Color(1, 1, 1)) { if (has_outline) { PendingDraw draw = { p_canvas_item, p_pos, p_char, p_next, p_modulate }; pending_draws.push_back(draw); @@ -137,7 +137,7 @@ public: }; private: - HashMap<CharType, Character> char_map; + HashMap<char32_t, Character> char_map; Map<KerningPairKey, int> kerning_map; float height; @@ -169,20 +169,20 @@ public: float get_underline_thickness() const override; void add_texture(const Ref<Texture2D> &p_texture); - void add_char(CharType p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance = -1); + void add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance = -1); int get_character_count() const; - Vector<CharType> get_char_keys() const; - Character get_character(CharType p_char) const; + Vector<char32_t> get_char_keys() const; + Character get_character(char32_t p_char) const; int get_texture_count() const; Ref<Texture2D> get_texture(int p_idx) const; - void add_kerning_pair(CharType p_A, CharType p_B, int p_kerning); - int get_kerning_pair(CharType p_A, CharType p_B) const; + void add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning); + int get_kerning_pair(char32_t p_A, char32_t p_B) const; Vector<KerningPairKey> get_kerning_pair_keys() const; - Size2 get_char_size(CharType p_char, CharType p_next = 0) const override; + Size2 get_char_size(char32_t p_char, char32_t p_next = 0) const override; void set_fallback(const Ref<BitmapFont> &p_fallback); Ref<BitmapFont> get_fallback() const; @@ -192,7 +192,7 @@ public: void set_distance_field_hint(bool p_distance_field); bool is_distance_field_hint() const override; - float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const override; + float draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const override; BitmapFont(); ~BitmapFont(); diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp index d271c906ff..6b41b97e45 100644 --- a/scene/resources/gradient.cpp +++ b/scene/resources/gradient.cpp @@ -32,14 +32,8 @@ #include "core/core_string_names.h" -//setter and getter names for property serialization -#define COLOR_RAMP_GET_OFFSETS "get_offsets" -#define COLOR_RAMP_GET_COLORS "get_colors" -#define COLOR_RAMP_SET_OFFSETS "set_offsets" -#define COLOR_RAMP_SET_COLORS "set_colors" - Gradient::Gradient() { - //Set initial color ramp transition from black to white + //Set initial gradient transition from black to white points.resize(2); points.write[0].color = Color(0, 0, 0, 1); points.write[0].offset = 0; @@ -65,14 +59,14 @@ void Gradient::_bind_methods() { ClassDB::bind_method(D_METHOD("get_point_count"), &Gradient::get_points_count); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_OFFSETS, "offsets"), &Gradient::set_offsets); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_OFFSETS), &Gradient::get_offsets); + ClassDB::bind_method(D_METHOD("set_offsets", "offsets"), &Gradient::set_offsets); + ClassDB::bind_method(D_METHOD("get_offsets"), &Gradient::get_offsets); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_COLORS, "colors"), &Gradient::set_colors); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_COLORS), &Gradient::get_colors); + ClassDB::bind_method(D_METHOD("set_colors", "colors"), &Gradient::set_colors); + ClassDB::bind_method(D_METHOD("get_colors"), &Gradient::get_colors); - ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "offsets"), COLOR_RAMP_SET_OFFSETS, COLOR_RAMP_GET_OFFSETS); - ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "colors"), COLOR_RAMP_SET_COLORS, COLOR_RAMP_GET_COLORS); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "offsets"), "set_offsets", "get_offsets"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "colors"), "set_colors", "get_colors"); } Vector<float> Gradient::get_offsets() const { @@ -129,7 +123,7 @@ void Gradient::add_point(float p_offset, const Color &p_color) { void Gradient::remove_point(int p_index) { ERR_FAIL_INDEX(p_index, points.size()); - ERR_FAIL_COND(points.size() <= 2); + ERR_FAIL_COND(points.size() <= 1); points.remove(p_index); emit_signal(CoreStringNames::get_singleton()->changed); } @@ -141,32 +135,29 @@ void Gradient::set_points(Vector<Gradient::Point> &p_points) { } void Gradient::set_offset(int pos, const float offset) { - ERR_FAIL_COND(pos < 0); - if (points.size() <= pos) { - points.resize(pos + 1); - } + ERR_FAIL_INDEX(pos, points.size()); + _update_sorting(); points.write[pos].offset = offset; is_sorted = false; emit_signal(CoreStringNames::get_singleton()->changed); } -float Gradient::get_offset(int pos) const { +float Gradient::get_offset(int pos) { ERR_FAIL_INDEX_V(pos, points.size(), 0.0); + _update_sorting(); return points[pos].offset; } void Gradient::set_color(int pos, const Color &color) { - ERR_FAIL_COND(pos < 0); - if (points.size() <= pos) { - points.resize(pos + 1); - is_sorted = false; - } + ERR_FAIL_INDEX(pos, points.size()); + _update_sorting(); points.write[pos].color = color; emit_signal(CoreStringNames::get_singleton()->changed); } -Color Gradient::get_color(int pos) const { +Color Gradient::get_color(int pos) { ERR_FAIL_INDEX_V(pos, points.size(), Color()); + _update_sorting(); return points[pos].color; } diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h index d40dcc8d44..e839909770 100644 --- a/scene/resources/gradient.h +++ b/scene/resources/gradient.h @@ -31,7 +31,7 @@ #ifndef GRADIENT_H #define GRADIENT_H -#include "core/resource.h" +#include "core/io/resource.h" class Gradient : public Resource { GDCLASS(Gradient, Resource); @@ -49,6 +49,12 @@ public: private: Vector<Point> points; bool is_sorted; + _FORCE_INLINE_ void _update_sorting() { + if (!is_sorted) { + points.sort(); + is_sorted = true; + } + } protected: static void _bind_methods(); @@ -64,10 +70,10 @@ public: Vector<Point> &get_points(); void set_offset(int pos, const float offset); - float get_offset(int pos) const; + float get_offset(int pos); void set_color(int pos, const Color &color); - Color get_color(int pos) const; + Color get_color(int pos); void set_offsets(const Vector<float> &p_offsets); Vector<float> get_offsets() const; @@ -80,10 +86,7 @@ public: return Color(0, 0, 0, 1); } - if (!is_sorted) { - points.sort(); - is_sorted = true; - } + _update_sorting(); //binary search int low = 0; diff --git a/scene/resources/height_map_shape_3d.cpp b/scene/resources/height_map_shape_3d.cpp index e112c6b436..2ae47bcf3c 100644 --- a/scene/resources/height_map_shape_3d.cpp +++ b/scene/resources/height_map_shape_3d.cpp @@ -31,7 +31,7 @@ #include "height_map_shape_3d.h" #include "servers/physics_server_3d.h" -Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() { +Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const { Vector<Vector3> points; if ((map_width != 0) && (map_depth != 0)) { diff --git a/scene/resources/height_map_shape_3d.h b/scene/resources/height_map_shape_3d.h index c5715a57b1..9ee8b49689 100644 --- a/scene/resources/height_map_shape_3d.h +++ b/scene/resources/height_map_shape_3d.h @@ -54,7 +54,7 @@ public: void set_map_data(PackedFloat32Array p_new); PackedFloat32Array get_map_data() const; - virtual Vector<Vector3> get_debug_mesh_lines() override; + virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override; HeightMapShape3D(); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 1e95a35726..35c967ce27 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -30,7 +30,7 @@ #include "material.h" -#include "core/engine.h" +#include "core/config/engine.h" #ifdef TOOLS_ENABLED #include "editor/editor_settings.h" @@ -324,7 +324,6 @@ void BaseMaterial3D::init_shaders() { shader_names->rim_texture_channel = "rim_texture_channel"; shader_names->heightmap_texture_channel = "heightmap_texture_channel"; shader_names->refraction_texture_channel = "refraction_texture_channel"; - shader_names->alpha_scissor_threshold = "alpha_scissor_threshold"; shader_names->transmittance_color = "transmittance_color"; shader_names->transmittance_curve = "transmittance_curve"; @@ -349,6 +348,12 @@ void BaseMaterial3D::init_shaders() { shader_names->texture_names[TEXTURE_DETAIL_ALBEDO] = "texture_detail_albedo"; shader_names->texture_names[TEXTURE_DETAIL_NORMAL] = "texture_detail_normal"; shader_names->texture_names[TEXTURE_ORM] = "texture_orm"; + + shader_names->alpha_scissor_threshold = "alpha_scissor_threshold"; + shader_names->alpha_hash_scale = "alpha_hash_scale"; + + shader_names->alpha_antialiasing_edge = "alpha_antialiasing_edge"; + shader_names->albedo_texture_size = "albedo_texture_size"; } Ref<StandardMaterial3D> BaseMaterial3D::materials_for_2d[BaseMaterial3D::MAX_MATERIALS_FOR_2D]; @@ -435,6 +440,8 @@ void BaseMaterial3D::_update_shader() { case BLEND_MODE_MUL: code += "blend_mul"; break; + case BLEND_MODE_MAX: + break; // Internal value, skip. } DepthDrawMode ddm = depth_draw_mode; @@ -452,10 +459,8 @@ void BaseMaterial3D::_update_shader() { case DEPTH_DRAW_DISABLED: code += ",depth_draw_never"; break; - } - - if (transparency == TRANSPARENCY_ALPHA_DEPTH_PRE_PASS) { - code += ",depth_prepass_alpha"; + case DEPTH_DRAW_MAX: + break; // Internal value, skip. } switch (cull_mode) { @@ -468,6 +473,8 @@ void BaseMaterial3D::_update_shader() { case CULL_DISABLED: code += ",cull_disabled"; break; + case CULL_MAX: + break; // Internal value, skip. } switch (diffuse_mode) { case DIFFUSE_BURLEY: @@ -485,6 +492,8 @@ void BaseMaterial3D::_update_shader() { case DIFFUSE_TOON: code += ",diffuse_toon"; break; + case DIFFUSE_MAX: + break; // Internal value, skip. } switch (specular_mode) { case SPECULAR_SCHLICK_GGX: @@ -502,6 +511,8 @@ void BaseMaterial3D::_update_shader() { case SPECULAR_DISABLED: code += ",specular_disabled"; break; + case SPECULAR_MAX: + break; // Internal value, skip. } if (features[FEATURE_SUBSURFACE_SCATTERING] && flags[FLAG_SUBSURFACE_MODE_SKIN]) { code += ",sss_mode_skin"; @@ -525,6 +536,23 @@ void BaseMaterial3D::_update_shader() { if (flags[FLAG_USE_SHADOW_TO_OPACITY]) { code += ",shadow_to_opacity"; } + + if (transparency == TRANSPARENCY_ALPHA_DEPTH_PRE_PASS) { + code += ",depth_prepass_alpha"; + } + + // Although its technically possible to do alpha antialiasing without using alpha hash or alpha scissor, + // it is restricted in the base material because it has no use, and abusing it with regular Alpha blending can + // saturate the MSAA mask + if (transparency == TRANSPARENCY_ALPHA_HASH || transparency == TRANSPARENCY_ALPHA_SCISSOR) { + // alpha antialiasing is only useful in ALPHA_HASH or ALPHA_SCISSOR + if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) { + code += ",alpha_to_coverage"; + } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) { + code += ",alpha_to_coverage_and_one"; + } + } + code += ";\n"; code += "uniform vec4 albedo : hint_color;\n"; @@ -541,8 +569,18 @@ void BaseMaterial3D::_update_shader() { code += "uniform float distance_fade_max;\n"; } + // alpha scissor is only valid if there is not antialiasing edge + // alpha hash is valid whenever, but not with alpha scissor if (transparency == TRANSPARENCY_ALPHA_SCISSOR) { code += "uniform float alpha_scissor_threshold;\n"; + } else if (transparency == TRANSPARENCY_ALPHA_HASH) { + code += "uniform float alpha_hash_scale;\n"; + } + // if alpha antialiasing isn't off, add in the edge variable + if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF && + (transparency == TRANSPARENCY_ALPHA_SCISSOR || transparency == TRANSPARENCY_ALPHA_HASH)) { + code += "uniform float alpha_antialiasing_edge;\n"; + code += "uniform ivec2 albedo_texture_size;\n"; } code += "uniform float point_size : hint_range(0,128);\n"; @@ -568,6 +606,8 @@ void BaseMaterial3D::_update_shader() { case TEXTURE_CHANNEL_GRAYSCALE: { code += "uniform sampler2D texture_roughness : hint_roughness_gray," + texfilter_str + ";\n"; } break; + case TEXTURE_CHANNEL_MAX: + break; // Internal value, skip. } code += "uniform float specular;\n"; @@ -731,6 +771,8 @@ void BaseMaterial3D::_update_shader() { code += "\tUV /= vec2(h_frames, v_frames);\n"; code += "\tUV += vec2(mod(particle_frame, h_frames) / h_frames, floor(particle_frame / h_frames) / v_frames);\n"; } break; + case BILLBOARD_MAX: + break; // Internal value, skip. } if (flags[FLAG_FIXED_SIZE]) { @@ -903,6 +945,8 @@ void BaseMaterial3D::_update_shader() { case TEXTURE_CHANNEL_GRAYSCALE: { code += "\tvec4 roughness_texture_channel = vec4(0.333333,0.333333,0.333333,0.0);\n"; } break; + case TEXTURE_CHANNEL_MAX: + break; // Internal value, skip. } if (flags[FLAG_UV1_USE_TRIPLANAR]) { @@ -970,10 +1014,17 @@ void BaseMaterial3D::_update_shader() { code += "\tALBEDO *= 1.0 - ref_amount;\n"; code += "\tALPHA = 1.0;\n"; - } else if (transparency == TRANSPARENCY_ALPHA || transparency == TRANSPARENCY_ALPHA_DEPTH_PRE_PASS || flags[FLAG_USE_SHADOW_TO_OPACITY] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) { + } else if (transparency != TRANSPARENCY_DISABLED || flags[FLAG_USE_SHADOW_TO_OPACITY] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) { code += "\tALPHA = albedo.a * albedo_tex.a;\n"; + } + if (transparency == TRANSPARENCY_ALPHA_HASH) { + code += "\tALPHA_HASH_SCALE = alpha_hash_scale;\n"; } else if (transparency == TRANSPARENCY_ALPHA_SCISSOR) { - code += "\tif (albedo.a * albedo_tex.a < alpha_scissor_threshold) discard;\n"; + code += "\tALPHA_SCISSOR_THRESHOLD = alpha_scissor_threshold;\n"; + } + if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF && (transparency == TRANSPARENCY_ALPHA_HASH || transparency == TRANSPARENCY_ALPHA_SCISSOR)) { + code += "\tALPHA_ANTIALIASING_EDGE = alpha_antialiasing_edge;\n"; + code += "\tALPHA_TEXTURE_COORDINATE = UV * vec2(albedo_texture_size);\n"; } if (proximity_fade_enabled) { @@ -1143,6 +1194,8 @@ void BaseMaterial3D::_update_shader() { case BLEND_MODE_MUL: { code += "\tvec3 detail = mix(ALBEDO.rgb,ALBEDO.rgb*detail_tex.rgb,detail_tex.a);\n"; } break; + case BLEND_MODE_MAX: + break; // Internal value, skip. } code += "\tvec3 detail_norm = mix(NORMALMAP,detail_norm_tex.rgb,detail_tex.a);\n"; @@ -1424,6 +1477,20 @@ BaseMaterial3D::Transparency BaseMaterial3D::get_transparency() const { return transparency; } +void BaseMaterial3D::set_alpha_antialiasing(AlphaAntiAliasing p_alpha_aa) { + if (alpha_antialiasing_mode == p_alpha_aa) { + return; + } + + alpha_antialiasing_mode = p_alpha_aa; + _queue_shader_change(); + _change_notify(); +} + +BaseMaterial3D::AlphaAntiAliasing BaseMaterial3D::get_alpha_antialiasing() const { + return alpha_antialiasing_mode; +} + void BaseMaterial3D::set_shading_mode(ShadingMode p_shading_mode) { if (shading_mode == p_shading_mode) { return; @@ -1530,6 +1597,10 @@ void BaseMaterial3D::set_texture(TextureParam p_param, const Ref<Texture2D> &p_t textures[p_param] = p_texture; RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); RS::get_singleton()->material_set_param(_get_material(), shader_names->texture_names[p_param], rid); + if (p_texture.is_valid() && p_param == TEXTURE_ALBEDO) { + RS::get_singleton()->material_set_param(_get_material(), shader_names->albedo_texture_size, + Vector2i(p_texture->get_width(), p_texture->get_height())); + } _change_notify(); _queue_shader_change(); } @@ -1605,10 +1676,34 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { property.usage = 0; } + // you can only enable anti-aliasing (in mataerials) on alpha scissor and alpha hash + const bool can_select_aa = (transparency == TRANSPARENCY_ALPHA_SCISSOR || transparency == TRANSPARENCY_ALPHA_HASH); + // alpha anti aliasiasing is only enabled when you can select aa + const bool alpha_aa_enabled = (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) && can_select_aa; + + // alpha scissor slider isn't needed when alpha antialiasing is enabled if (property.name == "alpha_scissor_threshold" && transparency != TRANSPARENCY_ALPHA_SCISSOR) { property.usage = 0; } + // alpha hash scale slider is only needed if transparency is alpha hash + if (property.name == "alpha_hash_scale" && transparency != TRANSPARENCY_ALPHA_HASH) { + property.usage = 0; + } + + if (property.name == "alpha_antialiasing_mode" && !can_select_aa) { + property.usage = 0; + } + + // we cant choose an antialiasing mode if alpha isnt possible + if (property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) { + property.usage = 0; + } + + if (property.name == "blend_mode" && alpha_aa_enabled) { + property.usage = 0; + } + if ((property.name == "heightmap_min_layers" || property.name == "heightmap_max_layers") && !deep_parallax) { property.usage = 0; } @@ -1845,6 +1940,24 @@ float BaseMaterial3D::get_alpha_scissor_threshold() const { return alpha_scissor_threshold; } +void BaseMaterial3D::set_alpha_hash_scale(float p_scale) { + alpha_hash_scale = p_scale; + RS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_hash_scale, p_scale); +} + +float BaseMaterial3D::get_alpha_hash_scale() const { + return alpha_hash_scale; +} + +void BaseMaterial3D::set_alpha_antialiasing_edge(float p_edge) { + alpha_antialiasing_edge = p_edge; + RS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_antialiasing_edge, p_edge); +} + +float BaseMaterial3D::get_alpha_antialiasing_edge() const { + return alpha_antialiasing_edge; +} + void BaseMaterial3D::set_grow(float p_grow) { grow = p_grow; RS::get_singleton()->material_set_param(_get_material(), shader_names->grow, p_grow); @@ -2033,6 +2146,12 @@ void BaseMaterial3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transparency", "transparency"), &BaseMaterial3D::set_transparency); ClassDB::bind_method(D_METHOD("get_transparency"), &BaseMaterial3D::get_transparency); + ClassDB::bind_method(D_METHOD("set_alpha_antialiasing", "alpha_aa"), &BaseMaterial3D::set_alpha_antialiasing); + ClassDB::bind_method(D_METHOD("get_alpha_antialiasing"), &BaseMaterial3D::get_alpha_antialiasing); + + ClassDB::bind_method(D_METHOD("set_alpha_antialiasing_edge", "edge"), &BaseMaterial3D::set_alpha_antialiasing_edge); + ClassDB::bind_method(D_METHOD("get_alpha_antialiasing_edge"), &BaseMaterial3D::get_alpha_antialiasing_edge); + ClassDB::bind_method(D_METHOD("set_shading_mode", "shading_mode"), &BaseMaterial3D::set_shading_mode); ClassDB::bind_method(D_METHOD("get_shading_mode"), &BaseMaterial3D::get_shading_mode); @@ -2186,6 +2305,9 @@ void BaseMaterial3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_alpha_scissor_threshold", "threshold"), &BaseMaterial3D::set_alpha_scissor_threshold); ClassDB::bind_method(D_METHOD("get_alpha_scissor_threshold"), &BaseMaterial3D::get_alpha_scissor_threshold); + ClassDB::bind_method(D_METHOD("set_alpha_hash_scale", "threshold"), &BaseMaterial3D::set_alpha_hash_scale); + ClassDB::bind_method(D_METHOD("get_alpha_hash_scale"), &BaseMaterial3D::get_alpha_hash_scale); + ClassDB::bind_method(D_METHOD("set_grow_enabled", "enable"), &BaseMaterial3D::set_grow_enabled); ClassDB::bind_method(D_METHOD("is_grow_enabled"), &BaseMaterial3D::is_grow_enabled); @@ -2217,8 +2339,11 @@ void BaseMaterial3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_distance_fade_min_distance"), &BaseMaterial3D::get_distance_fade_min_distance); ADD_GROUP("Transparency", ""); - ADD_PROPERTY(PropertyInfo(Variant::INT, "transparency", PROPERTY_HINT_ENUM, "Disabled,Alpha,AlphaScissor,DepthPrePass"), "set_transparency", "get_transparency"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "transparency", PROPERTY_HINT_ENUM, "Disabled,Alpha,Alpha Scissor,Alpha Hash,Depth PrePass"), "set_transparency", "get_transparency"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_hash_scale", PROPERTY_HINT_RANGE, "0,2,0.01"), "set_alpha_hash_scale", "get_alpha_hash_scale"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_antialiasing_mode", PROPERTY_HINT_ENUM, "Disabled,Alpha Edge Blend,Alpha Edge Clip"), "set_alpha_antialiasing", "get_alpha_antialiasing"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_antialiasing_edge", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_antialiasing_edge", "get_alpha_antialiasing_edge"); ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul"), "set_blend_mode", "get_blend_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mode", PROPERTY_HINT_ENUM, "Back,Front,Disabled"), "set_cull_mode", "get_cull_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "depth_draw_mode", PROPERTY_HINT_ENUM, "Opaque Only,Always,Never"), "set_depth_draw_mode", "get_depth_draw_mode"); @@ -2414,6 +2539,7 @@ void BaseMaterial3D::_bind_methods() { BIND_ENUM_CONSTANT(TRANSPARENCY_DISABLED); BIND_ENUM_CONSTANT(TRANSPARENCY_ALPHA); BIND_ENUM_CONSTANT(TRANSPARENCY_ALPHA_SCISSOR); + BIND_ENUM_CONSTANT(TRANSPARENCY_ALPHA_HASH); BIND_ENUM_CONSTANT(TRANSPARENCY_ALPHA_DEPTH_PRE_PASS); BIND_ENUM_CONSTANT(TRANSPARENCY_MAX); @@ -2441,6 +2567,10 @@ void BaseMaterial3D::_bind_methods() { BIND_ENUM_CONSTANT(BLEND_MODE_SUB); BIND_ENUM_CONSTANT(BLEND_MODE_MUL); + BIND_ENUM_CONSTANT(ALPHA_ANTIALIASING_OFF); + BIND_ENUM_CONSTANT(ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE); + BIND_ENUM_CONSTANT(ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE); + BIND_ENUM_CONSTANT(DEPTH_DRAW_OPAQUE_ONLY); BIND_ENUM_CONSTANT(DEPTH_DRAW_ALWAYS); BIND_ENUM_CONSTANT(DEPTH_DRAW_DISABLED); @@ -2506,8 +2636,9 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : element(this) { orm = p_orm; // Initialize to the same values as the shader - transparency = TRANSPARENCY_DISABLED; shading_mode = SHADING_MODE_PER_PIXEL; + transparency = TRANSPARENCY_DISABLED; + alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF; set_albedo(Color(1.0, 1.0, 1.0, 1.0)); set_specular(0.5); set_roughness(1.0); @@ -2539,9 +2670,14 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_particles_anim_h_frames(1); set_particles_anim_v_frames(1); set_particles_anim_loop(false); - set_alpha_scissor_threshold(0.98); emission_op = EMISSION_OP_ADD; + set_transparency(TRANSPARENCY_DISABLED); + set_alpha_antialiasing(ALPHA_ANTIALIASING_OFF); + set_alpha_scissor_threshold(0.05); + set_alpha_hash_scale(1.0); + set_alpha_antialiasing_edge(0.3); + proximity_fade_enabled = false; distance_fade = DISTANCE_FADE_DISABLED; set_proximity_fade_distance(1); @@ -2582,10 +2718,8 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : features[i] = false; } - current_key.key0 = 0; - current_key.key1 = 0; - current_key.invalid_key = 1; texture_filter = TEXTURE_FILTER_LINEAR_WITH_MIPMAPS; + _queue_shader_change(); } @@ -2633,6 +2767,12 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value) set_transparency(TRANSPARENCY_ALPHA_SCISSOR); } return true; + } else if (p_name == "params_use_alpha_hash") { + bool use_hash = p_value; + if (use_hash) { + set_transparency(TRANSPARENCY_ALPHA_HASH); + } + return true; } else if (p_name == "params_depth_draw_mode") { int mode = p_value; if (mode == 3) { @@ -2667,6 +2807,8 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value) { "params_grow", "grow" }, { "params_grow_amount", "grow_amount" }, { "params_alpha_scissor_threshold", "alpha_scissor_threshold" }, + { "params_alpha_hash_scale", "alpha_hash_scale" }, + { "params_alpha_antialiasing_edge", "alpha_antialiasing_edge" }, { "depth_scale", "heightmap_scale" }, { "depth_deep_parallax", "heightmap_deep_parallax" }, diff --git a/scene/resources/material.h b/scene/resources/material.h index b5bdd77eb5..caf28eea18 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -31,8 +31,8 @@ #ifndef MATERIAL_H #define MATERIAL_H -#include "core/resource.h" -#include "core/self_list.h" +#include "core/io/resource.h" +#include "core/templates/self_list.h" #include "scene/resources/shader.h" #include "scene/resources/texture.h" #include "servers/rendering/shader_language.h" @@ -145,17 +145,26 @@ public: enum DetailUV { DETAIL_UV_1, - DETAIL_UV_2 + DETAIL_UV_2, + DETAIL_UV_MAX }; enum Transparency { TRANSPARENCY_DISABLED, TRANSPARENCY_ALPHA, TRANSPARENCY_ALPHA_SCISSOR, + TRANSPARENCY_ALPHA_HASH, TRANSPARENCY_ALPHA_DEPTH_PRE_PASS, TRANSPARENCY_MAX, }; + enum AlphaAntiAliasing { + ALPHA_ANTIALIASING_OFF, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE, + ALPHA_ANTIALIASING_MAX + }; + enum ShadingMode { SHADING_MODE_UNSHADED, SHADING_MODE_PER_PIXEL, @@ -184,18 +193,21 @@ public: BLEND_MODE_ADD, BLEND_MODE_SUB, BLEND_MODE_MUL, + BLEND_MODE_MAX }; enum DepthDrawMode { DEPTH_DRAW_OPAQUE_ONLY, DEPTH_DRAW_ALWAYS, DEPTH_DRAW_DISABLED, + DEPTH_DRAW_MAX }; enum CullMode { CULL_BACK, CULL_FRONT, - CULL_DISABLED + CULL_DISABLED, + CULL_MAX }; enum Flags { @@ -227,6 +239,7 @@ public: DIFFUSE_LAMBERT_WRAP, DIFFUSE_OREN_NAYAR, DIFFUSE_TOON, + DIFFUSE_MAX }; enum SpecularMode { @@ -235,6 +248,7 @@ public: SPECULAR_PHONG, SPECULAR_TOON, SPECULAR_DISABLED, + SPECULAR_MAX }; enum BillboardMode { @@ -242,6 +256,7 @@ public: BILLBOARD_ENABLED, BILLBOARD_FIXED_Y, BILLBOARD_PARTICLES, + BILLBOARD_MAX }; enum TextureChannel { @@ -249,12 +264,14 @@ public: TEXTURE_CHANNEL_GREEN, TEXTURE_CHANNEL_BLUE, TEXTURE_CHANNEL_ALPHA, - TEXTURE_CHANNEL_GRAYSCALE + TEXTURE_CHANNEL_GRAYSCALE, + TEXTURE_CHANNEL_MAX }; enum EmissionOperator { EMISSION_OP_ADD, - EMISSION_OP_MULTIPLY + EMISSION_OP_MULTIPLY, + EMISSION_OP_MAX }; enum DistanceFadeMode { @@ -262,43 +279,47 @@ public: DISTANCE_FADE_PIXEL_ALPHA, DISTANCE_FADE_PIXEL_DITHER, DISTANCE_FADE_OBJECT_DITHER, + DISTANCE_FADE_MAX }; private: - union MaterialKey { - struct { - uint64_t feature_mask : FEATURE_MAX; - uint64_t detail_uv : 1; - uint64_t blend_mode : 2; - uint64_t depth_draw_mode : 2; - uint64_t cull_mode : 2; - uint64_t flags : FLAG_MAX; - uint64_t detail_blend_mode : 2; - uint64_t diffuse_mode : 3; - uint64_t specular_mode : 3; - uint64_t invalid_key : 1; - uint64_t deep_parallax : 1; - uint64_t billboard_mode : 2; - uint64_t grow : 1; - uint64_t proximity_fade : 1; - uint64_t distance_fade : 2; - uint64_t emission_op : 1; - uint64_t texture_filter : 3; - uint64_t transparency : 2; - uint64_t shading_mode : 2; - uint64_t roughness_channel : 3; - }; - - struct { - uint64_t key0; - uint64_t key1; - }; + struct MaterialKey { + // enum values + uint64_t texture_filter : get_num_bits(TEXTURE_FILTER_MAX - 1); + uint64_t detail_uv : get_num_bits(DETAIL_UV_MAX - 1); + uint64_t transparency : get_num_bits(TRANSPARENCY_MAX - 1); + uint64_t alpha_antialiasing_mode : get_num_bits(ALPHA_ANTIALIASING_MAX - 1); + uint64_t shading_mode : get_num_bits(SHADING_MODE_MAX - 1); + uint64_t blend_mode : get_num_bits(BLEND_MODE_MAX - 1); + uint64_t depth_draw_mode : get_num_bits(DEPTH_DRAW_MAX - 1); + uint64_t cull_mode : get_num_bits(CULL_MAX - 1); + uint64_t diffuse_mode : get_num_bits(DIFFUSE_MAX - 1); + uint64_t specular_mode : get_num_bits(SPECULAR_MAX - 1); + uint64_t billboard_mode : get_num_bits(BILLBOARD_MAX - 1); + uint64_t detail_blend_mode : get_num_bits(BLEND_MODE_MAX - 1); + uint64_t roughness_channel : get_num_bits(TEXTURE_CHANNEL_MAX - 1); + uint64_t emission_op : get_num_bits(EMISSION_OP_MAX - 1); + uint64_t distance_fade : get_num_bits(DISTANCE_FADE_MAX - 1); + + // flag bitfield + uint64_t feature_mask : FEATURE_MAX - 1; + uint64_t flags : FLAG_MAX - 1; + + // booleans + uint64_t deep_parallax : 1; + uint64_t grow : 1; + uint64_t proximity_fade : 1; + + MaterialKey() { + memset(this, 0, sizeof(MaterialKey)); + } bool operator==(const MaterialKey &p_key) const { - return (key0 == p_key.key0) && (key1 == p_key.key1); + return memcmp(this, &p_key, sizeof(MaterialKey)) == 0; } + bool operator<(const MaterialKey &p_key) const { - return (key0 == p_key.key0) ? (key1 < p_key.key1) : (key0 < p_key.key0); + return memcmp(this, &p_key, sizeof(MaterialKey)) < 0; } }; @@ -313,13 +334,7 @@ private: _FORCE_INLINE_ MaterialKey _compute_key() const { MaterialKey mk; - mk.key0 = 0; - mk.key1 = 0; - for (int i = 0; i < FEATURE_MAX; i++) { - if (features[i]) { - mk.feature_mask |= ((uint64_t)1 << i); - } - } + mk.detail_uv = detail_uv; mk.blend_mode = blend_mode; mk.depth_draw_mode = depth_draw_mode; @@ -328,20 +343,28 @@ private: mk.transparency = transparency; mk.shading_mode = shading_mode; mk.roughness_channel = roughness_texture_channel; - for (int i = 0; i < FLAG_MAX; i++) { - if (flags[i]) { - mk.flags |= ((uint64_t)1 << i); - } - } mk.detail_blend_mode = detail_blend_mode; mk.diffuse_mode = diffuse_mode; mk.specular_mode = specular_mode; mk.billboard_mode = billboard_mode; - mk.deep_parallax = deep_parallax ? 1 : 0; + mk.deep_parallax = deep_parallax; mk.grow = grow_enabled; mk.proximity_fade = proximity_fade_enabled; mk.distance_fade = distance_fade; mk.emission_op = emission_op; + mk.alpha_antialiasing_mode = alpha_antialiasing_mode; + + for (int i = 0; i < FEATURE_MAX; i++) { + if (features[i]) { + mk.feature_mask |= ((uint64_t)1 << i); + } + } + + for (int i = 0; i < FLAG_MAX; i++) { + if (flags[i]) { + mk.flags |= ((uint64_t)1 << i); + } + } return mk; } @@ -392,9 +415,14 @@ private: StringName rim_texture_channel; StringName heightmap_texture_channel; StringName refraction_texture_channel; - StringName alpha_scissor_threshold; StringName texture_names[TEXTURE_MAX]; + + StringName alpha_scissor_threshold; + StringName alpha_hash_scale; + + StringName alpha_antialiasing_edge; + StringName albedo_texture_size; }; static Mutex material_mutex; @@ -433,6 +461,8 @@ private: float refraction; float point_size; float alpha_scissor_threshold; + float alpha_hash_scale; + float alpha_antialiasing_edge; bool grow_enabled; float ao_light_affect; float grow; @@ -482,6 +512,8 @@ private: TextureChannel ao_texture_channel; TextureChannel refraction_texture_channel; + AlphaAntiAliasing alpha_antialiasing_mode; + bool features[FEATURE_MAX]; Ref<Texture2D> textures[TEXTURE_MAX]; @@ -584,6 +616,12 @@ public: void set_transparency(Transparency p_transparency); Transparency get_transparency() const; + void set_alpha_antialiasing(AlphaAntiAliasing p_alpha_aa); + AlphaAntiAliasing get_alpha_antialiasing() const; + + void set_alpha_antialiasing_edge(float p_edge); + float get_alpha_antialiasing_edge() const; + void set_shading_mode(ShadingMode p_shading_mode); ShadingMode get_shading_mode() const; @@ -660,6 +698,9 @@ public: void set_alpha_scissor_threshold(float p_threshold); float get_alpha_scissor_threshold() const; + void set_alpha_hash_scale(float p_scale); + float get_alpha_hash_scale() const; + void set_on_top_of_alpha(); void set_proximity_fade(bool p_enable); @@ -707,6 +748,7 @@ VARIANT_ENUM_CAST(BaseMaterial3D::TextureParam) VARIANT_ENUM_CAST(BaseMaterial3D::TextureFilter) VARIANT_ENUM_CAST(BaseMaterial3D::ShadingMode) VARIANT_ENUM_CAST(BaseMaterial3D::Transparency) +VARIANT_ENUM_CAST(BaseMaterial3D::AlphaAntiAliasing) VARIANT_ENUM_CAST(BaseMaterial3D::DetailUV) VARIANT_ENUM_CAST(BaseMaterial3D::Feature) VARIANT_ENUM_CAST(BaseMaterial3D::BlendMode) diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 10f0a040d0..060846d5b6 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -30,7 +30,7 @@ #include "mesh.h" -#include "core/pair.h" +#include "core/templates/pair.h" #include "scene/resources/concave_polygon_shape_3d.h" #include "scene/resources/convex_polygon_shape_3d.h" #include "surface_tool.h" @@ -872,7 +872,6 @@ Array ArrayMesh::_get_surfaces() const { ret.push_back(data); } - print_line("Saving surfaces: " + itos(ret.size())); return ret; } diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index fd1fa1b48f..81c18eea2d 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -31,9 +31,9 @@ #ifndef MESH_H #define MESH_H +#include "core/io/resource.h" #include "core/math/face3.h" #include "core/math/triangle_mesh.h" -#include "core/resource.h" #include "scene/resources/material.h" #include "scene/resources/shape_3d.h" #include "servers/rendering_server.h" @@ -209,7 +209,6 @@ public: void surface_update_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data); int get_surface_count() const override; - void surface_remove(int p_idx); void clear_surfaces(); diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h index 7b78398669..0d5fb3005b 100644 --- a/scene/resources/mesh_library.h +++ b/scene/resources/mesh_library.h @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GRID_THEME_H -#define GRID_THEME_H +#ifndef MESH_LIBRARY_H +#define MESH_LIBRARY_H -#include "core/map.h" -#include "core/resource.h" +#include "core/io/resource.h" +#include "core/templates/map.h" #include "mesh.h" #include "scene/3d/navigation_region_3d.h" #include "shape_3d.h" @@ -96,4 +96,4 @@ public: ~MeshLibrary(); }; -#endif // CUBE_GRID_THEME_H +#endif // MESH_LIBRARY_H diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index cb201bc539..5ce253f970 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -30,10 +30,10 @@ #include "packed_scene.h" +#include "core/config/engine.h" +#include "core/config/project_settings.h" #include "core/core_string_names.h" -#include "core/engine.h" #include "core/io/resource_loader.h" -#include "core/project_settings.h" #include "scene/2d/node_2d.h" #include "scene/3d/node_3d.h" #include "scene/gui/control.h" @@ -848,7 +848,7 @@ Error SceneState::pack(Node *p_scene) { Map<Node *, int> node_map; Map<Node *, int> nodepath_map; - //if using scene inheritance, pack the scene it inherits from + // If using scene inheritance, pack the scene it inherits from. if (scene->get_scene_inherited_state().is_valid()) { String path = scene->get_scene_inherited_state()->get_path(); Ref<PackedScene> instance = ResourceLoader::load(path); @@ -856,8 +856,8 @@ Error SceneState::pack(Node *p_scene) { base_scene_idx = _vm_get_variant(instance, variant_map); } } - //instanced, only direct sub-scnes are supported of course + // Instanced, only direct sub-scenes are supported of course. Error err = _parse_node(scene, scene, -1, name_map, variant_map, node_map, nodepath_map); if (err) { clear(); diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 004758afa5..b8b3f84ecc 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -31,7 +31,7 @@ #ifndef PACKED_SCENE_H #define PACKED_SCENE_H -#include "core/resource.h" +#include "core/io/resource.h" #include "scene/main/node.h" class SceneState : public Reference { diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index fc92a721db..a286184aee 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -91,13 +91,16 @@ void ParticlesMaterial::init_shaders() { shader_names->emission_texture_normal = "emission_texture_normal"; shader_names->emission_texture_color = "emission_texture_color"; - shader_names->trail_divisor = "trail_divisor"; - shader_names->trail_size_modifier = "trail_size_modifier"; - shader_names->trail_color_modifier = "trail_color_modifier"; - shader_names->gravity = "gravity"; shader_names->lifetime_randomness = "lifetime_randomness"; + + shader_names->sub_emitter_frequency = "sub_emitter_frequency"; + shader_names->sub_emitter_amount_at_end = "sub_emitter_amount_at_end"; + shader_names->sub_emitter_keep_velocity = "sub_emitter_keep_velocity"; + + shader_names->collision_friction = "collision_friction"; + shader_names->collision_bounce = "collision_bounce"; } void ParticlesMaterial::finish_shaders() { @@ -136,6 +139,10 @@ void ParticlesMaterial::_update_shader() { String code = "shader_type particles;\n"; + if (collision_scale) { + code += "render_mode collision_use_scale;\n"; + } + code += "uniform vec3 direction;\n"; code += "uniform float spread;\n"; code += "uniform float flatness;\n"; @@ -192,9 +199,17 @@ void ParticlesMaterial::_update_shader() { } } - code += "uniform vec4 color_value : hint_color;\n"; + if (sub_emitter_mode != SUB_EMITTER_DISABLED) { + if (sub_emitter_mode == SUB_EMITTER_CONSTANT) { + code += "uniform float sub_emitter_frequency;\n"; + } + if (sub_emitter_mode == SUB_EMITTER_AT_END) { + code += "uniform int sub_emitter_amount_at_end;\n"; + } + code += "uniform bool sub_emitter_keep_velocity;\n"; + } - code += "uniform int trail_divisor;\n"; + code += "uniform vec4 color_value : hint_color;\n"; code += "uniform vec3 gravity;\n"; @@ -239,12 +254,9 @@ void ParticlesMaterial::_update_shader() { code += "uniform sampler2D anim_offset_texture;\n"; } - if (trail_size_modifier.is_valid()) { - code += "uniform sampler2D trail_size_modifier;\n"; - } - - if (trail_color_modifier.is_valid()) { - code += "uniform sampler2D trail_color_modifier;\n"; + if (collision_enabled) { + code += "uniform float collision_friction;\n"; + code += "uniform float collision_bounce;\n"; } //need a random function @@ -277,8 +289,8 @@ void ParticlesMaterial::_update_shader() { code += "}\n"; code += "\n"; - code += "void vertex() {\n"; - code += " uint base_number = NUMBER / uint(trail_divisor);\n"; + code += "void compute() {\n"; + code += " uint base_number = NUMBER;\n"; code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n"; code += " float angle_rand = rand_from_seed(alt_seed);\n"; code += " float scale_rand = rand_from_seed(alt_seed);\n"; @@ -293,17 +305,7 @@ void ParticlesMaterial::_update_shader() { code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n"; code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n"; } - code += " bool restart = false;\n"; - code += " if (CUSTOM.y > CUSTOM.w) {\n"; - code += " restart = true;\n"; - code += " }\n\n"; - code += " if (RESTART || restart) {\n"; - - if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n"; - } else { - code += " float tex_linear_velocity = 0.0;\n"; - } + code += " if (RESTART) {\n"; if (tex_parameters[PARAM_ANGLE].is_valid()) { code += " float tex_angle = textureLod(angle_texture, vec2(0.0, 0.0), 0.0).r;\n"; @@ -319,25 +321,34 @@ void ParticlesMaterial::_update_shader() { code += " float spread_rad = spread * degree_to_rad;\n"; + code += " if (RESTART_VELOCITY) {\n"; + + if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { + code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n"; + } else { + code += " float tex_linear_velocity = 0.0;\n"; + } + if (flags[FLAG_DISABLE_Z]) { - code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; - code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n"; - code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n"; - code += " VELOCITY = rot * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; + code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; + code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n"; + code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n"; + code += " VELOCITY = rot * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; } else { //initiate velocity spread in 3D - code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; - code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n"; - code += " angle1_rad += direction.z != 0.0 ? atan(direction.x, direction.z) : sign(direction.x) * (pi / 2.0);\n"; - code += " angle2_rad += direction.z != 0.0 ? atan(direction.y, abs(direction.z)) : (direction.x != 0.0 ? atan(direction.y, abs(direction.x)) : sign(direction.y) * (pi / 2.0));\n"; - code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n"; - code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n"; - code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n"; - code += " vec3 vec_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; - code += " vec_direction = normalize(vec_direction);\n"; - code += " VELOCITY = vec_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; + code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; + code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n"; + code += " angle1_rad += direction.z != 0.0 ? atan(direction.x, direction.z) : sign(direction.x) * (pi / 2.0);\n"; + code += " angle2_rad += direction.z != 0.0 ? atan(direction.y, abs(direction.z)) : (direction.x != 0.0 ? atan(direction.y, abs(direction.x)) : sign(direction.y) * (pi / 2.0));\n"; + code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n"; + code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n"; + code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n"; + code += " vec3 vec_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; + code += " vec_direction = normalize(vec_direction);\n"; + code += " VELOCITY = vec_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; } + code += " }\n"; code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n"; code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle @@ -345,35 +356,38 @@ void ParticlesMaterial::_update_shader() { code += " CUSTOM.w = (1.0 - lifetime_randomness * rand_from_seed(alt_seed));\n"; code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random);\n"; // animation offset (0-1) + code += " if (RESTART_POSITION) {\n"; + switch (emission_shape) { case EMISSION_SHAPE_POINT: { - //do none + //do none, identity (will later be multiplied by emission transform) + code += " TRANSFORM = mat4(vec4(1,0,0,0),vec4(0,1,0,0),vec4(0,0,1,0),vec4(0,0,0,1));\n"; } break; case EMISSION_SHAPE_SPHERE: { - code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n"; - code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n"; - code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n"; - code += " TRANSFORM[3].xyz = vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s);\n"; + code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n"; + code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n"; + code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n"; + code += " TRANSFORM[3].xyz = vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s);\n"; } break; case EMISSION_SHAPE_BOX: { - code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0) * emission_box_extents;\n"; + code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0) * emission_box_extents;\n"; } break; case EMISSION_SHAPE_POINTS: case EMISSION_SHAPE_DIRECTED_POINTS: { - code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n"; + code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n"; if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { if (flags[FLAG_DISABLE_Z]) { - code += " mat2 rotm;"; - code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n"; - code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n"; - code += " VELOCITY.xy = rotm * VELOCITY.xy;\n"; + code += " mat2 rotm;"; + code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n"; + code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n"; + code += " if (RESTART_VELOCITY) VELOCITY.xy = rotm * VELOCITY.xy;\n"; } else { - code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xyz;\n"; - code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);\n"; - code += " vec3 tangent = normalize(cross(v0, normal));\n"; - code += " vec3 bitangent = normalize(cross(tangent, normal));\n"; - code += " VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n"; + code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xyz;\n"; + code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);\n"; + code += " vec3 tangent = normalize(cross(v0, normal));\n"; + code += " vec3 bitangent = normalize(cross(tangent, normal));\n"; + code += " if (RESTART_VELOCITY) VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n"; } } } break; @@ -381,12 +395,14 @@ void ParticlesMaterial::_update_shader() { break; } } - code += " VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n"; - code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; + + code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n"; + code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; if (flags[FLAG_DISABLE_Z]) { - code += " VELOCITY.z = 0.0;\n"; - code += " TRANSFORM[3].z = 0.0;\n"; + code += " VELOCITY.z = 0.0;\n"; + code += " TRANSFORM[3].z = 0.0;\n"; } + code += " }\n"; code += " } else {\n"; @@ -472,6 +488,10 @@ void ParticlesMaterial::_update_shader() { code += " vec3 crossDiff = cross(normalize(diff), normalize(gravity));\n"; code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n"; } + if (attractor_interaction_enabled) { + code += " force += ATTRACTOR_FORCE;\n\n"; + } + code += " // apply attractor forces\n"; code += " VELOCITY += force * DELTA;\n"; code += " // orbit velocity\n"; @@ -540,11 +560,6 @@ void ParticlesMaterial::_update_shader() { if (emission_color_texture.is_valid() && (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS)) { code += " COLOR *= texelFetch(emission_texture_color, emission_tex_ofs, 0);\n"; } - if (trail_color_modifier.is_valid()) { - code += " if (trail_divisor > 1) {\n"; - code += " COLOR *= textureLod(trail_color_modifier, vec2(float(int(NUMBER) % trail_divisor) / float(trail_divisor - 1), 0.0), 0.0);\n"; - code += " }\n"; - } code += "\n"; if (flags[FLAG_DISABLE_Z]) { @@ -592,11 +607,6 @@ void ParticlesMaterial::_update_shader() { code += " if (base_scale < 0.000001) {\n"; code += " base_scale = 0.000001;\n"; code += " }\n"; - if (trail_size_modifier.is_valid()) { - code += " if (trail_divisor > 1) {\n"; - code += " base_scale *= textureLod(trail_size_modifier, vec2(float(int(NUMBER) % trail_divisor) / float(trail_divisor - 1), 0.0), 0.0).r;\n"; - code += " }\n"; - } code += " TRANSFORM[0].xyz *= base_scale;\n"; code += " TRANSFORM[1].xyz *= base_scale;\n"; @@ -605,6 +615,41 @@ void ParticlesMaterial::_update_shader() { code += " VELOCITY.z = 0.0;\n"; code += " TRANSFORM[3].z = 0.0;\n"; } + if (collision_enabled) { + code += " if (COLLIDED) {\n"; + code += " TRANSFORM[3].xyz+=COLLISION_NORMAL * COLLISION_DEPTH;\n"; + code += " VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n"; + code += " VELOCITY = mix(VELOCITY,vec3(0.0),collision_friction * DELTA * 100.0);\n"; + code += " }\n"; + } + if (sub_emitter_mode != SUB_EMITTER_DISABLED) { + code += " int emit_count = 0;\n"; + switch (sub_emitter_mode) { + case SUB_EMITTER_CONSTANT: { + code += " float interval_from = CUSTOM.y * LIFETIME - DELTA;\n"; + code += " float interval_rem = sub_emitter_frequency - mod(interval_from,sub_emitter_frequency);\n"; + code += " if (DELTA >= interval_rem) emit_count = 1;\n"; + } break; + case SUB_EMITTER_AT_COLLISION: { + //not implemented yet + code += " if (COLLIDED) emit_count = 1;\n"; + } break; + case SUB_EMITTER_AT_END: { + //not implemented yet + code += " float unit_delta = DELTA/LIFETIME;\n"; + code += " float end_time = CUSTOM.w * 0.95;\n"; // if we do at the end we might miss it, as it can just get deactivated by emitter + code += " if (CUSTOM.y < end_time && (CUSTOM.y + unit_delta) >= end_time) emit_count = sub_emitter_amount_at_end;\n"; + } break; + default: { + } + } + code += " for(int i=0;i<emit_count;i++) {\n"; + code += " uint flags = FLAG_EMIT_POSITION|FLAG_EMIT_ROT_SCALE;\n"; + code += " if (sub_emitter_keep_velocity) flags|=FLAG_EMIT_VELOCITY;\n"; + code += " emit_particle(TRANSFORM,VELOCITY,vec4(0.0),vec4(0.0),flags);\n"; + code += " }"; + } + code += " if (CUSTOM.y > CUSTOM.w) {"; code += " ACTIVE = false;\n"; code += " }\n"; @@ -951,41 +996,6 @@ int ParticlesMaterial::get_emission_point_count() const { return emission_point_count; } -void ParticlesMaterial::set_trail_divisor(int p_divisor) { - trail_divisor = p_divisor; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_divisor, p_divisor); -} - -int ParticlesMaterial::get_trail_divisor() const { - return trail_divisor; -} - -void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier) { - trail_size_modifier = p_trail_size_modifier; - - Ref<CurveTexture> curve = trail_size_modifier; - if (curve.is_valid()) { - curve->ensure_default_setup(); - } - - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, curve); - _queue_shader_change(); -} - -Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const { - return trail_size_modifier; -} - -void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) { - trail_color_modifier = p_trail_color_modifier; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, p_trail_color_modifier); - _queue_shader_change(); -} - -Ref<GradientTexture> ParticlesMaterial::get_trail_color_modifier() const { - return trail_color_modifier; -} - void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) { gravity = p_gravity; Vector3 gset = gravity; @@ -1038,11 +1048,99 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const { property.usage = 0; } + if (property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) { + property.usage = 0; + } + + if (property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) { + property.usage = 0; + } + if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) { property.usage = 0; } } +void ParticlesMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) { + sub_emitter_mode = p_sub_emitter_mode; + _queue_shader_change(); + _change_notify(); +} + +ParticlesMaterial::SubEmitterMode ParticlesMaterial::get_sub_emitter_mode() const { + return sub_emitter_mode; +} + +void ParticlesMaterial::set_sub_emitter_frequency(float p_frequency) { + sub_emitter_frequency = p_frequency; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_frequency, 1.0 / p_frequency); //pas delta instead of frequency, since its easier to compute +} +float ParticlesMaterial::get_sub_emitter_frequency() const { + return sub_emitter_frequency; +} + +void ParticlesMaterial::set_sub_emitter_amount_at_end(int p_amount) { + sub_emitter_amount_at_end = p_amount; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_amount_at_end, p_amount); +} + +int ParticlesMaterial::get_sub_emitter_amount_at_end() const { + return sub_emitter_amount_at_end; +} + +void ParticlesMaterial::set_sub_emitter_keep_velocity(bool p_enable) { + sub_emitter_keep_velocity = p_enable; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_keep_velocity, p_enable); +} +bool ParticlesMaterial::get_sub_emitter_keep_velocity() const { + return sub_emitter_keep_velocity; +} + +void ParticlesMaterial::set_attractor_interaction_enabled(bool p_enable) { + attractor_interaction_enabled = p_enable; + _queue_shader_change(); +} + +bool ParticlesMaterial::is_attractor_interaction_enabled() const { + return attractor_interaction_enabled; +} + +void ParticlesMaterial::set_collision_enabled(bool p_enabled) { + collision_enabled = p_enabled; + _queue_shader_change(); +} + +bool ParticlesMaterial::is_collision_enabled() const { + return collision_enabled; +} + +void ParticlesMaterial::set_collision_use_scale(bool p_scale) { + collision_scale = p_scale; + _queue_shader_change(); +} + +bool ParticlesMaterial::is_collision_using_scale() const { + return collision_scale; +} + +void ParticlesMaterial::set_collision_friction(float p_friction) { + collision_friction = p_friction; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_friction, p_friction); +} + +float ParticlesMaterial::get_collision_friction() const { + return collision_friction; +} + +void ParticlesMaterial::set_collision_bounce(float p_bounce) { + collision_bounce = p_bounce; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_bounce, p_bounce); +} + +float ParticlesMaterial::get_collision_bounce() const { + return collision_bounce; +} + Shader::Mode ParticlesMaterial::get_shader_mode() const { return Shader::MODE_PARTICLES; } @@ -1096,27 +1194,42 @@ void ParticlesMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count); ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count); - ClassDB::bind_method(D_METHOD("set_trail_divisor", "divisor"), &ParticlesMaterial::set_trail_divisor); - ClassDB::bind_method(D_METHOD("get_trail_divisor"), &ParticlesMaterial::get_trail_divisor); - - ClassDB::bind_method(D_METHOD("set_trail_size_modifier", "texture"), &ParticlesMaterial::set_trail_size_modifier); - ClassDB::bind_method(D_METHOD("get_trail_size_modifier"), &ParticlesMaterial::get_trail_size_modifier); - - ClassDB::bind_method(D_METHOD("set_trail_color_modifier", "texture"), &ParticlesMaterial::set_trail_color_modifier); - ClassDB::bind_method(D_METHOD("get_trail_color_modifier"), &ParticlesMaterial::get_trail_color_modifier); - ClassDB::bind_method(D_METHOD("get_gravity"), &ParticlesMaterial::get_gravity); ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticlesMaterial::set_gravity); ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "randomness"), &ParticlesMaterial::set_lifetime_randomness); ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &ParticlesMaterial::get_lifetime_randomness); + ClassDB::bind_method(D_METHOD("get_sub_emitter_mode"), &ParticlesMaterial::get_sub_emitter_mode); + ClassDB::bind_method(D_METHOD("set_sub_emitter_mode", "mode"), &ParticlesMaterial::set_sub_emitter_mode); + + ClassDB::bind_method(D_METHOD("get_sub_emitter_frequency"), &ParticlesMaterial::get_sub_emitter_frequency); + ClassDB::bind_method(D_METHOD("set_sub_emitter_frequency", "hz"), &ParticlesMaterial::set_sub_emitter_frequency); + + ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_end"), &ParticlesMaterial::get_sub_emitter_amount_at_end); + ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticlesMaterial::set_sub_emitter_amount_at_end); + + ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticlesMaterial::get_sub_emitter_keep_velocity); + ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticlesMaterial::set_sub_emitter_keep_velocity); + + ClassDB::bind_method(D_METHOD("set_attractor_interaction_enabled", "enabled"), &ParticlesMaterial::set_attractor_interaction_enabled); + ClassDB::bind_method(D_METHOD("is_attractor_interaction_enabled"), &ParticlesMaterial::is_attractor_interaction_enabled); + + ClassDB::bind_method(D_METHOD("set_collision_enabled", "enabled"), &ParticlesMaterial::set_collision_enabled); + ClassDB::bind_method(D_METHOD("is_collision_enabled"), &ParticlesMaterial::is_collision_enabled); + + ClassDB::bind_method(D_METHOD("set_collision_use_scale", "radius"), &ParticlesMaterial::set_collision_use_scale); + ClassDB::bind_method(D_METHOD("is_collision_using_scale"), &ParticlesMaterial::is_collision_using_scale); + + ClassDB::bind_method(D_METHOD("set_collision_friction", "friction"), &ParticlesMaterial::set_collision_friction); + ClassDB::bind_method(D_METHOD("get_collision_friction"), &ParticlesMaterial::get_collision_friction); + + ClassDB::bind_method(D_METHOD("set_collision_bounce", "bounce"), &ParticlesMaterial::set_collision_bounce); + ClassDB::bind_method(D_METHOD("get_collision_bounce"), &ParticlesMaterial::get_collision_bounce); + ADD_GROUP("Time", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness"); - ADD_GROUP("Trail", "trail_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_divisor", PROPERTY_HINT_RANGE, "1,1000000,1"), "set_trail_divisor", "get_trail_divisor"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_size_modifier", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_trail_size_modifier", "get_trail_size_modifier"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_color_modifier", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_trail_color_modifier", "get_trail_color_modifier"); + ADD_GROUP("Emission Shape", "emission_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,or_greater"), "set_emission_sphere_radius", "get_emission_sphere_radius"); @@ -1186,6 +1299,20 @@ void ParticlesMaterial::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET); + ADD_GROUP("Sub Emitter", "sub_emitter_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,AtEnd,AtCollision"), "set_sub_emitter_mode", "get_sub_emitter_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_sub_emitter_frequency", "get_sub_emitter_frequency"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_end", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_end", "get_sub_emitter_amount_at_end"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sub_emitter_keep_velocity"), "set_sub_emitter_keep_velocity", "get_sub_emitter_keep_velocity"); + + ADD_GROUP("Attractor Interaction", "attractor_interaction_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "attractor_interaction_enabled"), "set_attractor_interaction_enabled", "is_attractor_interaction_enabled"); + ADD_GROUP("Collision", "collision_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_enabled"), "set_collision_enabled", "is_collision_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_friction", "get_collision_friction"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_bounce", "get_collision_bounce"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_scale"), "set_collision_use_scale", "is_collision_using_scale"); + BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY); BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY); @@ -1211,6 +1338,12 @@ void ParticlesMaterial::_bind_methods() { BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS); BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS); BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX); + + BIND_ENUM_CONSTANT(SUB_EMITTER_DISABLED); + BIND_ENUM_CONSTANT(SUB_EMITTER_CONSTANT); + BIND_ENUM_CONSTANT(SUB_EMITTER_AT_END); + BIND_ENUM_CONSTANT(SUB_EMITTER_AT_COLLISION); + BIND_ENUM_CONSTANT(SUB_EMITTER_MAX); } ParticlesMaterial::ParticlesMaterial() : @@ -1233,11 +1366,21 @@ ParticlesMaterial::ParticlesMaterial() : set_emission_shape(EMISSION_SHAPE_POINT); set_emission_sphere_radius(1); set_emission_box_extents(Vector3(1, 1, 1)); - set_trail_divisor(1); set_gravity(Vector3(0, -9.8, 0)); set_lifetime_randomness(0); emission_point_count = 1; + set_sub_emitter_mode(SUB_EMITTER_DISABLED); + set_sub_emitter_frequency(4); + set_sub_emitter_amount_at_end(1); + set_sub_emitter_keep_velocity(false); + + set_attractor_interaction_enabled(true); + set_collision_enabled(true); + set_collision_bounce(0.0); + set_collision_friction(0.0); + set_collision_use_scale(false); + for (int i = 0; i < PARAM_MAX; i++) { set_param_randomness(Parameter(i), 0); } diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h index 1c1b6c92f9..12fa53ef29 100644 --- a/scene/resources/particles_material.h +++ b/scene/resources/particles_material.h @@ -28,18 +28,24 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "core/rid.h" +#include "core/templates/rid.h" #include "scene/resources/material.h" #ifndef PARTICLES_MATERIAL_H #define PARTICLES_MATERIAL_H +/* + TODO: +-Path following +-Emitter positions deformable by bones +-Proper trails +*/ + class ParticlesMaterial : public Material { GDCLASS(ParticlesMaterial, Material); public: enum Parameter { - PARAM_INITIAL_LINEAR_VELOCITY, PARAM_ANGULAR_VELOCITY, PARAM_ORBIT_VELOCITY, @@ -71,6 +77,14 @@ public: EMISSION_SHAPE_MAX }; + enum SubEmitterMode { + SUB_EMITTER_DISABLED, + SUB_EMITTER_CONSTANT, + SUB_EMITTER_AT_END, + SUB_EMITTER_AT_COLLISION, + SUB_EMITTER_MAX + }; + private: union MaterialKey { struct { @@ -78,10 +92,12 @@ private: uint32_t texture_color : 1; uint32_t flags : 4; uint32_t emission_shape : 2; - uint32_t trail_size_texture : 1; - uint32_t trail_color_texture : 1; uint32_t invalid_key : 1; uint32_t has_emission_color : 1; + uint32_t sub_emitter : 2; + uint32_t attractor_enabled : 1; + uint32_t collision_enabled : 1; + uint32_t collision_scale : 1; }; uint32_t key; @@ -116,9 +132,11 @@ private: mk.texture_color = color_ramp.is_valid() ? 1 : 0; mk.emission_shape = emission_shape; - mk.trail_color_texture = trail_color_modifier.is_valid() ? 1 : 0; - mk.trail_size_texture = trail_size_modifier.is_valid() ? 1 : 0; mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid(); + mk.sub_emitter = sub_emitter_mode; + mk.collision_enabled = collision_enabled; + mk.attractor_enabled = attractor_interaction_enabled; + mk.collision_scale = collision_scale; return mk; } @@ -178,13 +196,16 @@ private: StringName emission_texture_normal; StringName emission_texture_color; - StringName trail_divisor; - StringName trail_size_modifier; - StringName trail_color_modifier; - StringName gravity; StringName lifetime_randomness; + + StringName sub_emitter_frequency; + StringName sub_emitter_amount_at_end; + StringName sub_emitter_keep_velocity; + + StringName collision_friction; + StringName collision_bounce; }; static ShaderNames *shader_names; @@ -218,17 +239,22 @@ private: bool anim_loop; - int trail_divisor; - - Ref<CurveTexture> trail_size_modifier; - Ref<GradientTexture> trail_color_modifier; - Vector3 gravity; float lifetime_randomness; + SubEmitterMode sub_emitter_mode; + float sub_emitter_frequency; + int sub_emitter_amount_at_end; + bool sub_emitter_keep_velocity; //do not save emission points here + bool attractor_interaction_enabled; + bool collision_enabled; + bool collision_scale; + float collision_friction; + float collision_bounce; + protected: static void _bind_methods(); virtual void _validate_property(PropertyInfo &property) const override; @@ -277,25 +303,43 @@ public: Ref<Texture2D> get_emission_color_texture() const; int get_emission_point_count() const; - void set_trail_divisor(int p_divisor); - int get_trail_divisor() const; - - void set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier); - Ref<CurveTexture> get_trail_size_modifier() const; - - void set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier); - Ref<GradientTexture> get_trail_color_modifier() const; - void set_gravity(const Vector3 &p_gravity); Vector3 get_gravity() const; void set_lifetime_randomness(float p_lifetime); float get_lifetime_randomness() const; + void set_attractor_interaction_enabled(bool p_enable); + bool is_attractor_interaction_enabled() const; + + void set_collision_enabled(bool p_enabled); + bool is_collision_enabled() const; + + void set_collision_use_scale(bool p_scale); + bool is_collision_using_scale() const; + + void set_collision_friction(float p_friction); + float get_collision_friction() const; + + void set_collision_bounce(float p_bounce); + float get_collision_bounce() const; + static void init_shaders(); static void finish_shaders(); static void flush_changes(); + void set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode); + SubEmitterMode get_sub_emitter_mode() const; + + void set_sub_emitter_frequency(float p_frequency); + float get_sub_emitter_frequency() const; + + void set_sub_emitter_amount_at_end(int p_amount); + int get_sub_emitter_amount_at_end() const; + + void set_sub_emitter_keep_velocity(bool p_enable); + bool get_sub_emitter_keep_velocity() const; + RID get_shader_rid() const; virtual Shader::Mode get_shader_mode() const override; @@ -307,5 +351,6 @@ public: VARIANT_ENUM_CAST(ParticlesMaterial::Parameter) VARIANT_ENUM_CAST(ParticlesMaterial::Flags) VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape) +VARIANT_ENUM_CAST(ParticlesMaterial::SubEmitterMode) #endif // PARTICLES_MATERIAL_H diff --git a/scene/resources/physics_material.cpp b/scene/resources/physics_material.cpp index 2a5cd1101a..59bf8c0e13 100644 --- a/scene/resources/physics_material.cpp +++ b/scene/resources/physics_material.cpp @@ -43,9 +43,9 @@ void PhysicsMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_absorbent", "absorbent"), &PhysicsMaterial::set_absorbent); ClassDB::bind_method(D_METHOD("is_absorbent"), &PhysicsMaterial::is_absorbent); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction"), "set_friction", "get_friction"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rough"), "set_rough", "is_rough"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce"), "set_bounce", "get_bounce"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "absorbent"), "set_absorbent", "is_absorbent"); } diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h index 34aa7066df..e9222ffa1b 100644 --- a/scene/resources/physics_material.h +++ b/scene/resources/physics_material.h @@ -31,7 +31,7 @@ #ifndef PHYSICS_MATERIAL_H #define PHYSICS_MATERIAL_H -#include "core/resource.h" +#include "core/io/resource.h" #include "servers/physics_server_3d.h" class PhysicsMaterial : public Resource { diff --git a/scene/resources/polygon_path_finder.h b/scene/resources/polygon_path_finder.h index baee4dc20d..44a97b4294 100644 --- a/scene/resources/polygon_path_finder.h +++ b/scene/resources/polygon_path_finder.h @@ -31,7 +31,7 @@ #ifndef POLYGON_PATH_FINDER_H #define POLYGON_PATH_FINDER_H -#include "core/resource.h" +#include "core/io/resource.h" class PolygonPathFinder : public Resource { GDCLASS(PolygonPathFinder, Resource); diff --git a/scene/resources/ray_shape_3d.cpp b/scene/resources/ray_shape_3d.cpp index 17205a500a..39df4c22f9 100644 --- a/scene/resources/ray_shape_3d.cpp +++ b/scene/resources/ray_shape_3d.cpp @@ -32,7 +32,7 @@ #include "servers/physics_server_3d.h" -Vector<Vector3> RayShape3D::get_debug_mesh_lines() { +Vector<Vector3> RayShape3D::get_debug_mesh_lines() const { Vector<Vector3> points; points.push_back(Vector3()); points.push_back(Vector3(0, 0, get_length())); diff --git a/scene/resources/ray_shape_3d.h b/scene/resources/ray_shape_3d.h index 6d974a0a4c..a1a6702564 100644 --- a/scene/resources/ray_shape_3d.h +++ b/scene/resources/ray_shape_3d.h @@ -48,7 +48,7 @@ public: void set_slips_on_slope(bool p_active); bool get_slips_on_slope() const; - virtual Vector<Vector3> get_debug_mesh_lines() override; + virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override; RayShape3D(); diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 93db8b725f..1d5f29ab14 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -30,9 +30,9 @@ #include "resource_format_text.h" +#include "core/config/project_settings.h" #include "core/io/resource_format_binary.h" #include "core/os/dir_access.h" -#include "core/project_settings.h" #include "core/version.h" //version 2: changed names for basis, aabb, Vectors, etc. @@ -572,7 +572,7 @@ Error ResourceLoaderText::load() { } } - if (progress) { + if (progress && resources_total > 0) { *progress = resource_current / float(resources_total); } } @@ -640,7 +640,7 @@ Error ResourceLoaderText::load() { return error; } else { error = OK; - if (progress) { + if (progress && resources_total > 0) { *progress = resource_current / float(resources_total); } @@ -674,7 +674,7 @@ Error ResourceLoaderText::load() { resource_current++; - if (progress) { + if (progress && resources_total > 0) { *progress = resource_current / float(resources_total); } @@ -1763,6 +1763,10 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r } for (int i = 0; i < state->get_connection_count(); i++) { + if (i == 0) { + f->store_line(""); + } + String connstr = "[connection"; connstr += " signal=\"" + String(state->get_connection_signal(i)) + "\""; connstr += " from=\"" + String(state->get_connection_source(i).simplified()) + "\""; @@ -1786,7 +1790,10 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r Vector<NodePath> editable_instances = state->get_editable_instances(); for (int i = 0; i < editable_instances.size(); i++) { - f->store_line("\n[editable path=\"" + editable_instances[i].operator String() + "\"]"); + if (i == 0) { + f->store_line(""); + } + f->store_line("[editable path=\"" + editable_instances[i].operator String() + "\"]"); } } diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h index cf522c9364..ca7b0b021f 100644 --- a/scene/resources/resource_format_text.h +++ b/scene/resources/resource_format_text.h @@ -34,7 +34,7 @@ #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/os/file_access.h" -#include "core/variant_parser.h" +#include "core/variant/variant_parser.h" #include "scene/resources/packed_scene.h" class ResourceLoaderText { diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 4249542567..76d37eaa71 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "shader.h" + #include "core/os/file_access.h" #include "scene/scene_string_names.h" #include "servers/rendering/shader_language.h" @@ -80,7 +81,7 @@ void Shader::get_param_list(List<PropertyInfo> *p_params) const { params_cache[pi.name] = E->get().name; if (p_params) { //small little hack - if (pi.type == Variant::_RID) { + if (pi.type == Variant::RID) { pi.type = Variant::OBJECT; } p_params->push_back(pi); @@ -142,8 +143,6 @@ void Shader::_bind_methods() { ClassDB::bind_method(D_METHOD("has_param", "name"), &Shader::has_param); - //ClassDB::bind_method(D_METHOD("get_param_list"),&Shader::get_fragment_code); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_code", "get_code"); BIND_ENUM_CONSTANT(MODE_SPATIAL); diff --git a/scene/resources/shader.h b/scene/resources/shader.h index 7dcec7811a..f2ea582ff0 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -31,9 +31,9 @@ #ifndef SHADER_H #define SHADER_H +#include "core/io/resource.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/resource.h" #include "scene/resources/texture.h" class Shader : public Resource { diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h index bb4688a02d..495ffdd38b 100644 --- a/scene/resources/shape_2d.h +++ b/scene/resources/shape_2d.h @@ -31,7 +31,7 @@ #ifndef SHAPE_2D_H #define SHAPE_2D_H -#include "core/resource.h" +#include "core/io/resource.h" class Shape2D : public Resource { GDCLASS(Shape2D, Resource); diff --git a/scene/resources/shape_3d.h b/scene/resources/shape_3d.h index 8a78b41461..5a9c2e3b9c 100644 --- a/scene/resources/shape_3d.h +++ b/scene/resources/shape_3d.h @@ -31,7 +31,7 @@ #ifndef SHAPE_3D_H #define SHAPE_3D_H -#include "core/resource.h" +#include "core/io/resource.h" class ArrayMesh; @@ -56,7 +56,7 @@ public: virtual RID get_rid() const override { return shape; } Ref<ArrayMesh> get_debug_mesh(); - virtual Vector<Vector3> get_debug_mesh_lines() = 0; // { return Vector<Vector3>(); } + virtual Vector<Vector3> get_debug_mesh_lines() const = 0; // { return Vector<Vector3>(); } /// Returns the radius of a sphere that fully enclose this shape virtual real_t get_enclosing_radius() const = 0; diff --git a/scene/resources/skin.h b/scene/resources/skin.h index 57aaf1afd4..e6ed4f1768 100644 --- a/scene/resources/skin.h +++ b/scene/resources/skin.h @@ -31,7 +31,7 @@ #ifndef SKIN_H #define SKIN_H -#include "core/resource.h" +#include "core/io/resource.h" class Skin : public Resource { GDCLASS(Skin, Resource) diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h index 5e23020d66..5411994b7d 100644 --- a/scene/resources/sky_material.h +++ b/scene/resources/sky_material.h @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "core/rid.h" +#include "core/templates/rid.h" #include "scene/resources/material.h" #ifndef SKY_MATERIAL_H diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp index d24998ff18..fd33387df6 100644 --- a/scene/resources/sphere_shape_3d.cpp +++ b/scene/resources/sphere_shape_3d.cpp @@ -31,7 +31,7 @@ #include "sphere_shape_3d.h" #include "servers/physics_server_3d.h" -Vector<Vector3> SphereShape3D::get_debug_mesh_lines() { +Vector<Vector3> SphereShape3D::get_debug_mesh_lines() const { float r = get_radius(); Vector<Vector3> points; diff --git a/scene/resources/sphere_shape_3d.h b/scene/resources/sphere_shape_3d.h index 78d45b5058..5cad67aea5 100644 --- a/scene/resources/sphere_shape_3d.h +++ b/scene/resources/sphere_shape_3d.h @@ -46,7 +46,7 @@ public: void set_radius(float p_radius); float get_radius() const; - virtual Vector<Vector3> get_debug_mesh_lines() override; + virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override; SphereShape3D(); diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index eb65f10ec9..a8bf44c5c0 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -130,18 +130,6 @@ Ref<Texture2D> StyleBoxTexture::get_texture() const { return texture; } -void StyleBoxTexture::set_normal_map(Ref<Texture2D> p_normal_map) { - if (normal_map == p_normal_map) { - return; - } - normal_map = p_normal_map; - emit_changed(); -} - -Ref<Texture2D> StyleBoxTexture::get_normal_map() const { - return normal_map; -} - void StyleBoxTexture::set_margin_size(Margin p_margin, float p_size) { ERR_FAIL_INDEX((int)p_margin, 4); @@ -187,12 +175,7 @@ void StyleBoxTexture::draw(RID p_canvas_item, const Rect2 &p_rect) const { rect.size.x += expand_margin[MARGIN_LEFT] + expand_margin[MARGIN_RIGHT]; rect.size.y += expand_margin[MARGIN_TOP] + expand_margin[MARGIN_BOTTOM]; - RID normal_rid; - if (normal_map.is_valid()) { - normal_rid = normal_map->get_rid(); - } - - RenderingServer::get_singleton()->canvas_item_add_nine_patch(p_canvas_item, rect, src_rect, texture->get_rid(), Vector2(margin[MARGIN_LEFT], margin[MARGIN_TOP]), Vector2(margin[MARGIN_RIGHT], margin[MARGIN_BOTTOM]), RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center, modulate, normal_rid); + RenderingServer::get_singleton()->canvas_item_add_nine_patch(p_canvas_item, rect, src_rect, texture->get_rid(), Vector2(margin[MARGIN_LEFT], margin[MARGIN_TOP]), Vector2(margin[MARGIN_RIGHT], margin[MARGIN_BOTTOM]), RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center, modulate); } void StyleBoxTexture::set_draw_center(bool p_enabled) { @@ -245,6 +228,7 @@ void StyleBoxTexture::set_region_rect(const Rect2 &p_region_rect) { region_rect = p_region_rect; emit_changed(); + _change_notify("region"); } Rect2 StyleBoxTexture::get_region_rect() const { @@ -287,9 +271,6 @@ void StyleBoxTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture", "texture"), &StyleBoxTexture::set_texture); ClassDB::bind_method(D_METHOD("get_texture"), &StyleBoxTexture::get_texture); - ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &StyleBoxTexture::set_normal_map); - ClassDB::bind_method(D_METHOD("get_normal_map"), &StyleBoxTexture::get_normal_map); - ClassDB::bind_method(D_METHOD("set_margin_size", "margin", "size"), &StyleBoxTexture::set_margin_size); ClassDB::bind_method(D_METHOD("get_margin_size", "margin"), &StyleBoxTexture::get_margin_size); @@ -316,7 +297,6 @@ void StyleBoxTexture::_bind_methods() { ADD_SIGNAL(MethodInfo("texture_changed")); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map"); 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", MARGIN_LEFT); @@ -910,7 +890,7 @@ void StyleBoxFlat::_bind_methods() { ADD_GROUP("Shadow", "shadow_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size"), "set_shadow_size", "get_shadow_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_shadow_size", "get_shadow_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset"), "set_shadow_offset", "get_shadow_offset"); ADD_GROUP("Anti Aliasing", "anti_aliasing_"); diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index 3d29e3bd0f..a1237776c6 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -31,7 +31,7 @@ #ifndef STYLE_BOX_H #define STYLE_BOX_H -#include "core/resource.h" +#include "core/io/resource.h" #include "scene/resources/texture.h" #include "servers/rendering_server.h" @@ -90,7 +90,6 @@ private: float margin[4]; Rect2 region_rect; Ref<Texture2D> texture; - Ref<Texture2D> normal_map; bool draw_center; Color modulate; AxisStretchMode axis_h; @@ -115,9 +114,6 @@ public: void set_texture(Ref<Texture2D> p_texture); Ref<Texture2D> get_texture() const; - void set_normal_map(Ref<Texture2D> p_normal_map); - Ref<Texture2D> get_normal_map() const; - void set_draw_center(bool p_enabled); bool is_draw_center_enabled() const; virtual Size2 get_center_size() const override; diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 1a2dcc84bb..ff14a5a292 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -30,8 +30,6 @@ #include "surface_tool.h" -#include "core/method_bind_ext.gen.inc" - #define _VERTEX_SNAP 0.0001 #define EQ_VERTEX_DIST 0.00001 diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp index 9c8f9334a9..e3e4373fa9 100644 --- a/scene/resources/syntax_highlighter.cpp +++ b/scene/resources/syntax_highlighter.cpp @@ -30,7 +30,7 @@ #include "syntax_highlighter.h" -#include "core/script_language.h" +#include "core/object/script_language.h" #include "scene/gui/text_edit.h" Dictionary SyntaxHighlighter::get_line_syntax_highlighting(int p_line) { @@ -53,13 +53,13 @@ Dictionary SyntaxHighlighter::get_line_syntax_highlighting(int p_line) { return color_map; } -void SyntaxHighlighter::_line_edited_from(int p_line) { +void SyntaxHighlighter::_lines_edited_from(int p_from_line, int p_to_line) { if (highlighting_cache.size() < 1) { return; } int cache_size = highlighting_cache.back()->key(); - for (int i = p_line - 1; i <= cache_size; i++) { + for (int i = MIN(p_from_line, p_to_line) - 1; i <= cache_size; i++) { if (highlighting_cache.has(i)) { highlighting_cache.erase(i); } @@ -93,7 +93,7 @@ void SyntaxHighlighter::update_cache() { void SyntaxHighlighter::set_text_edit(TextEdit *p_text_edit) { if (text_edit && ObjectDB::get_instance(text_edit_instance_id)) { - text_edit->disconnect("line_edited_from", callable_mp(this, &SyntaxHighlighter::_line_edited_from)); + text_edit->disconnect("lines_edited_from", callable_mp(this, &SyntaxHighlighter::_lines_edited_from)); } text_edit = p_text_edit; @@ -101,7 +101,7 @@ void SyntaxHighlighter::set_text_edit(TextEdit *p_text_edit) { return; } text_edit_instance_id = text_edit->get_instance_id(); - text_edit->connect("line_edited_from", callable_mp(this, &SyntaxHighlighter::_line_edited_from)); + text_edit->connect("lines_edited_from", callable_mp(this, &SyntaxHighlighter::_lines_edited_from)); update_cache(); } @@ -125,11 +125,11 @@ void SyntaxHighlighter::_bind_methods() { //////////////////////////////////////////////////////////////////////////////// -static bool _is_char(CharType c) { +static bool _is_char(char32_t c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; } -static bool _is_hex_symbol(CharType c) { +static bool _is_hex_symbol(char32_t c) { return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); } @@ -149,6 +149,13 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) { color_region_cache[p_line] = -1; int in_region = -1; if (p_line != 0) { + int prev_region_line = p_line - 1; + while (prev_region_line > 0 && !color_region_cache.has(prev_region_line)) { + prev_region_line--; + } + for (int i = prev_region_line; i < p_line - 1; i++) { + get_line_syntax_highlighting(i); + } if (!color_region_cache.has(p_line - 1)) { get_line_syntax_highlighting(p_line - 1); } @@ -158,6 +165,10 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) { const String &str = text_edit->get_line(p_line); const int line_length = str.length(); Color prev_color; + + if (in_region != -1 && str.length() == 0) { + color_region_cache[p_line] = in_region; + } for (int j = 0; j < line_length; j++) { Dictionary highlighter_info; @@ -191,7 +202,7 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) { /* search the line */ bool match = true; - const CharType *start_key = color_regions[c].start_key.c_str(); + const char32_t *start_key = color_regions[c].start_key.get_data(); for (int k = 0; k < start_key_length; k++) { if (start_key[k] != str[from + k]) { match = false; @@ -225,18 +236,16 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) { /* if we are in one find the end key */ if (in_region != -1) { - /* check there is enough room */ - int chars_left = line_length - from; - int end_key_length = color_regions[in_region].end_key.length(); - if (chars_left < end_key_length) { - continue; - } - /* search the line */ int region_end_index = -1; - const CharType *end_key = color_regions[in_region].start_key.c_str(); + int end_key_length = color_regions[in_region].end_key.length(); + const char32_t *end_key = color_regions[in_region].end_key.get_data(); for (; from < line_length; from++) { - if (!is_a_symbol) { + if (line_length - from < end_key_length) { + break; + } + + if (!is_symbol(str[from])) { continue; } @@ -245,9 +254,10 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) { continue; } + region_end_index = from; for (int k = 0; k < end_key_length; k++) { - if (end_key[k] == str[from + k]) { - region_end_index = from; + if (end_key[k] != str[from + k]) { + region_end_index = -1; break; } } @@ -261,7 +271,7 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) { highlighter_info["color"] = color_regions[in_region].color; color_map[j] = highlighter_info; - j = from; + j = from + (end_key_length - 1); if (region_end_index == -1) { color_region_cache[p_line] = in_region; } @@ -480,8 +490,12 @@ void CodeHighlighter::add_color_region(const String &p_start_key, const String & } } + int at = 0; for (int i = 0; i < color_regions.size(); i++) { ERR_FAIL_COND_MSG(color_regions[i].start_key == p_start_key, "color region with start key '" + p_start_key + "' already exists."); + if (p_start_key.length() < color_regions[i].start_key.length()) { + at++; + } } ColorRegion color_region; @@ -489,7 +503,7 @@ void CodeHighlighter::add_color_region(const String &p_start_key, const String & color_region.start_key = p_start_key; color_region.end_key = p_end_key; color_region.line_only = p_line_only || p_end_key == ""; - color_regions.push_back(color_region); + color_regions.insert(at, color_region); clear_highlighting_cache(); } diff --git a/scene/resources/syntax_highlighter.h b/scene/resources/syntax_highlighter.h index 40a8870b45..62865920d3 100644 --- a/scene/resources/syntax_highlighter.h +++ b/scene/resources/syntax_highlighter.h @@ -31,7 +31,7 @@ #ifndef SYNTAX_HIGHLIGHTER_H #define SYNTAX_HIGHLIGHTER_H -#include "core/resource.h" +#include "core/io/resource.h" class TextEdit; @@ -40,7 +40,7 @@ class SyntaxHighlighter : public Resource { private: Map<int, Dictionary> highlighting_cache; - void _line_edited_from(int p_line); + void _lines_edited_from(int p_from_line, int p_to_line); protected: ObjectID text_edit_instance_id; // For validity check diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 5681613c04..07de202cc8 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -32,7 +32,6 @@ #include "core/core_string_names.h" #include "core/io/image_loader.h" -#include "core/method_bind_ext.gen.inc" #include "core/os/os.h" #include "mesh.h" #include "scene/resources/bit_map.h" @@ -46,28 +45,21 @@ bool Texture2D::is_pixel_opaque(int p_x, int p_y) const { return true; } -void Texture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, get_size()), get_rid(), false, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); +void Texture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { + RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, get_size()), get_rid(), false, p_modulate, p_transpose); } -void Texture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, get_rid(), p_tile, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); +void Texture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { + RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, get_rid(), p_tile, p_modulate, p_transpose); } -void Texture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, get_rid(), p_src_rect, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_clip_uv, p_texture_filter, p_texture_repeat); +void Texture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, get_rid(), p_src_rect, p_modulate, p_transpose, p_clip_uv); } bool Texture2D::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const { r_rect = p_rect; r_src_rect = p_src_rect; - return true; } @@ -76,9 +68,9 @@ void Texture2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_height"), &Texture2D::get_height); ClassDB::bind_method(D_METHOD("get_size"), &Texture2D::get_size); ClassDB::bind_method(D_METHOD("has_alpha"), &Texture2D::has_alpha); - ClassDB::bind_method(D_METHOD("draw", "canvas_item", "position", "modulate", "transpose", "normal_map", "specular_map", "specular_color_shininess", "texture_filter", "texture_repeat"), &Texture2D::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT), DEFVAL(RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT)); - ClassDB::bind_method(D_METHOD("draw_rect", "canvas_item", "rect", "tile", "modulate", "transpose", "normal_map", "specular_map", "specular_color_shininess", "texture_filter", "texture_repeat"), &Texture2D::draw_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT), DEFVAL(RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT)); - ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "normal_map", "specular_map", "specular_color_shininess", "texture_filter", "texture_repeat", "clip_uv"), &Texture2D::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT), DEFVAL(RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("draw", "canvas_item", "position", "modulate", "transpose"), &Texture2D::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_rect", "canvas_item", "rect", "tile", "modulate", "transpose"), &Texture2D::draw_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &Texture2D::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("get_data"), &Texture2D::get_data); ADD_GROUP("", ""); @@ -233,31 +225,25 @@ bool ImageTexture::has_alpha() const { return (format == Image::FORMAT_LA8 || format == Image::FORMAT_RGBA8); } -void ImageTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void ImageTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { if ((w | h) == 0) { return; } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose); } -void ImageTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void ImageTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { if ((w | h) == 0) { return; } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose); } -void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { +void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { if ((w | h) == 0) { return; } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_clip_uv, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv); } bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const { @@ -512,7 +498,7 @@ Error StreamTexture2D::_load_data(const String &p_path, int &tw, int &th, int &t ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER); FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); uint8_t header[4]; f->get_buffer(header, 4); @@ -652,31 +638,25 @@ RID StreamTexture2D::get_rid() const { return texture; } -void StreamTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void StreamTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { if ((w | h) == 0) { return; } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose); } -void StreamTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void StreamTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { if ((w | h) == 0) { return; } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose); } -void StreamTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { +void StreamTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { if ((w | h) == 0) { return; } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_clip_uv, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv); } bool StreamTexture2D::has_alpha() const { @@ -791,8 +771,312 @@ String ResourceFormatLoaderStreamTexture2D::get_resource_type(const String &p_pa return ""; } +//////////////////////////////////// + +TypedArray<Image> Texture3D::_get_data() const { + Vector<Ref<Image>> data = get_data(); + + TypedArray<Image> ret; + ret.resize(data.size()); + for (int i = 0; i < data.size(); i++) { + ret[i] = data[i]; + } + return ret; +} + +void Texture3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_format"), &Texture3D::get_format); + ClassDB::bind_method(D_METHOD("get_width"), &Texture3D::get_width); + ClassDB::bind_method(D_METHOD("get_height"), &Texture3D::get_height); + ClassDB::bind_method(D_METHOD("get_depth"), &Texture3D::get_depth); + ClassDB::bind_method(D_METHOD("has_mipmaps"), &Texture3D::has_mipmaps); + ClassDB::bind_method(D_METHOD("get_data"), &Texture3D::_get_data); +} ////////////////////////////////////////// +Image::Format ImageTexture3D::get_format() const { + return format; +} +int ImageTexture3D::get_width() const { + return width; +} +int ImageTexture3D::get_height() const { + return height; +} +int ImageTexture3D::get_depth() const { + return depth; +} +bool ImageTexture3D::has_mipmaps() const { + return mipmaps; +} + +Error ImageTexture3D::_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const TypedArray<Image> &p_data) { + Vector<Ref<Image>> images; + images.resize(p_data.size()); + for (int i = 0; i < images.size(); i++) { + images.write[i] = p_data[i]; + } + return create(p_format, p_width, p_height, p_depth, p_mipmaps, images); +} + +void ImageTexture3D::_update(const TypedArray<Image> &p_data) { + Vector<Ref<Image>> images; + images.resize(p_data.size()); + for (int i = 0; i < images.size(); i++) { + images.write[i] = p_data[i]; + } + return update(images); +} + +Error ImageTexture3D::create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) { + RID tex = RenderingServer::get_singleton()->texture_3d_create(p_format, p_width, p_height, p_depth, p_mipmaps, p_data); + ERR_FAIL_COND_V(tex.is_null(), ERR_CANT_CREATE); + + if (texture.is_valid()) { + RenderingServer::get_singleton()->texture_replace(texture, tex); + } + + return OK; +} + +void ImageTexture3D::update(const Vector<Ref<Image>> &p_data) { + ERR_FAIL_COND(!texture.is_valid()); + RenderingServer::get_singleton()->texture_3d_update(texture, p_data); +} + +Vector<Ref<Image>> ImageTexture3D::get_data() const { + ERR_FAIL_COND_V(!texture.is_valid(), Vector<Ref<Image>>()); + return RS::get_singleton()->texture_3d_get(texture); +} + +RID ImageTexture3D::get_rid() const { + if (!texture.is_valid()) { + texture = RS::get_singleton()->texture_3d_placeholder_create(); + } + return texture; +} +void ImageTexture3D::set_path(const String &p_path, bool p_take_over) { + if (texture.is_valid()) { + RenderingServer::get_singleton()->texture_set_path(texture, p_path); + } + + Resource::set_path(p_path, p_take_over); +} + +void ImageTexture3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("create", "format", "width", "height", "depth", "use_mipmaps", "data"), &ImageTexture3D::_create); + ClassDB::bind_method(D_METHOD("update", "data"), &ImageTexture3D::_update); +} + +ImageTexture3D::ImageTexture3D() { +} + +ImageTexture3D::~ImageTexture3D() { + if (texture.is_valid()) { + RS::get_singleton()->free(texture); + } +} + +//////////////////////////////////////////// + +void StreamTexture3D::set_path(const String &p_path, bool p_take_over) { + if (texture.is_valid()) { + RenderingServer::get_singleton()->texture_set_path(texture, p_path); + } + + Resource::set_path(p_path, p_take_over); +} + +Image::Format StreamTexture3D::get_format() const { + return format; +} + +Error StreamTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps) { + FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); + + uint8_t header[4]; + f->get_buffer(header, 4); + ERR_FAIL_COND_V(header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != 'L', ERR_FILE_UNRECOGNIZED); + + //stored as stream textures (used for lossless and lossy compression) + uint32_t version = f->get_32(); + + if (version > FORMAT_VERSION) { + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Stream texture file is too new."); + } + + r_depth = f->get_32(); //depth + f->get_32(); //ignored (mode) + f->get_32(); // ignored (data format) + + f->get_32(); //ignored + int mipmaps = f->get_32(); + f->get_32(); //ignored + f->get_32(); //ignored + + r_mipmaps = mipmaps != 0; + + r_data.clear(); + + for (int i = 0; i < (r_depth + mipmaps); i++) { + Ref<Image> image = StreamTexture2D::load_image_from_file(f, 0); + ERR_FAIL_COND_V(image.is_null() || image->empty(), ERR_CANT_OPEN); + if (i == 0) { + r_format = image->get_format(); + r_width = image->get_width(); + r_height = image->get_height(); + } + r_data.push_back(image); + } + + return OK; +} + +Error StreamTexture3D::load(const String &p_path) { + Vector<Ref<Image>> data; + + int tw, th, td; + Image::Format tfmt; + bool tmm; + + Error err = _load_data(p_path, data, tfmt, tw, th, td, tmm); + if (err) { + return err; + } + + if (texture.is_valid()) { + RID new_texture = RS::get_singleton()->texture_3d_create(tfmt, tw, th, td, tmm, data); + RS::get_singleton()->texture_replace(texture, new_texture); + } else { + texture = RS::get_singleton()->texture_3d_create(tfmt, tw, th, td, tmm, data); + } + + w = tw; + h = th; + d = td; + mipmaps = tmm; + format = tfmt; + + path_to_file = p_path; + + if (get_path() == String()) { + //temporarily set path if no path set for resource, helps find errors + RenderingServer::get_singleton()->texture_set_path(texture, p_path); + } + + _change_notify(); + emit_changed(); + return OK; +} + +String StreamTexture3D::get_load_path() const { + return path_to_file; +} + +int StreamTexture3D::get_width() const { + return w; +} + +int StreamTexture3D::get_height() const { + return h; +} + +int StreamTexture3D::get_depth() const { + return d; +} + +bool StreamTexture3D::has_mipmaps() const { + return mipmaps; +} + +RID StreamTexture3D::get_rid() const { + if (!texture.is_valid()) { + texture = RS::get_singleton()->texture_3d_placeholder_create(); + } + return texture; +} + +Vector<Ref<Image>> StreamTexture3D::get_data() const { + if (texture.is_valid()) { + return RS::get_singleton()->texture_3d_get(texture); + } else { + return Vector<Ref<Image>>(); + } +} + +void StreamTexture3D::reload_from_file() { + String path = get_path(); + if (!path.is_resource_file()) { + return; + } + + path = ResourceLoader::path_remap(path); //remap for translation + path = ResourceLoader::import_remap(path); //remap for import + if (!path.is_resource_file()) { + return; + } + + load(path); +} + +void StreamTexture3D::_validate_property(PropertyInfo &property) const { +} + +void StreamTexture3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("load", "path"), &StreamTexture3D::load); + ClassDB::bind_method(D_METHOD("get_load_path"), &StreamTexture3D::get_load_path); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path"); +} + +StreamTexture3D::StreamTexture3D() { + format = Image::FORMAT_MAX; + w = 0; + h = 0; + d = 0; + mipmaps = false; +} + +StreamTexture3D::~StreamTexture3D() { + if (texture.is_valid()) { + RS::get_singleton()->free(texture); + } +} + +///////////////////////////// + +RES ResourceFormatLoaderStreamTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { + Ref<StreamTexture3D> st; + st.instance(); + Error err = st->load(p_path); + if (r_error) { + *r_error = err; + } + if (err != OK) { + return RES(); + } + + return st; +} + +void ResourceFormatLoaderStreamTexture3D::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("stex3d"); +} + +bool ResourceFormatLoaderStreamTexture3D::handles_type(const String &p_type) const { + return p_type == "StreamTexture3D"; +} + +String ResourceFormatLoaderStreamTexture3D::get_resource_type(const String &p_path) const { + if (p_path.get_extension().to_lower() == "stex3d") { + return "StreamTexture3D"; + } + return ""; +} + +//////////////////////////////////////////// + int AtlasTexture::get_width() const { if (region.size.width == 0) { if (atlas.is_valid()) { @@ -900,7 +1184,7 @@ void AtlasTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_clip"), "set_filter_clip", "has_filter_clip"); } -void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { if (!atlas.is_valid()) { return; } @@ -915,12 +1199,10 @@ void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_m rc.size.height = atlas->get_height(); } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(p_pos + margin.position, rc.size), atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, filter_clip, p_texture_filter, p_texture_repeat); + RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(p_pos + margin.position, rc.size), atlas->get_rid(), rc, p_modulate, p_transpose, filter_clip); } -void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { if (!atlas.is_valid()) { return; } @@ -938,12 +1220,10 @@ void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile Vector2 scale = p_rect.size / (region.size + margin.size); Rect2 dr(p_rect.position + margin.position * scale, rc.size * scale); - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, filter_clip, p_texture_filter, p_texture_repeat); + RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), rc, p_modulate, p_transpose, filter_clip); } -void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { +void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { //this might not necessarily work well if using a rect, needs to be fixed properly if (!atlas.is_valid()) { return; @@ -953,9 +1233,7 @@ void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons Rect2 src_c; get_rect_region(p_rect, p_src_rect, dr, src_c); - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, filter_clip, p_texture_filter, p_texture_repeat); + RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose, filter_clip); } bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const { @@ -1060,7 +1338,7 @@ Ref<Texture2D> MeshTexture::get_base_texture() const { return base_texture; } -void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { if (mesh.is_null() || base_texture.is_null()) { return; } @@ -1070,12 +1348,10 @@ void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_mo SWAP(xform.elements[0][1], xform.elements[1][0]); SWAP(xform.elements[0][0], xform.elements[1][1]); } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid()); } -void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { if (mesh.is_null() || base_texture.is_null()) { return; } @@ -1094,12 +1370,10 @@ void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, SWAP(xform.elements[0][1], xform.elements[1][0]); SWAP(xform.elements[0][0], xform.elements[1][1]); } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid()); } -void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { +void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { if (mesh.is_null() || base_texture.is_null()) { return; } @@ -1118,9 +1392,7 @@ void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const SWAP(xform.elements[0][1], xform.elements[1][0]); SWAP(xform.elements[0][0], xform.elements[1][1]); } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid()); } bool MeshTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const { @@ -1265,14 +1537,14 @@ void LargeTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); } -void LargeTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void LargeTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { for (int i = 0; i < pieces.size(); i++) { // TODO - pieces[i].texture->draw(p_canvas_item, pieces[i].offset + p_pos, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + pieces[i].texture->draw(p_canvas_item, pieces[i].offset + p_pos, p_modulate, p_transpose); } } -void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { //tiling not supported for this if (size.x == 0 || size.y == 0) { return; @@ -1282,11 +1554,11 @@ void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile for (int i = 0; i < pieces.size(); i++) { // TODO - pieces[i].texture->draw_rect(p_canvas_item, Rect2(pieces[i].offset * scale + p_rect.position, pieces[i].texture->get_size() * scale), false, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + pieces[i].texture->draw_rect(p_canvas_item, Rect2(pieces[i].offset * scale + p_rect.position, pieces[i].texture->get_size() * scale), false, p_modulate, p_transpose); } } -void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { +void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { //tiling not supported for this if (p_src_rect.size.x == 0 || p_src_rect.size.y == 0) { return; @@ -1305,7 +1577,7 @@ void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons target.size *= scale; target.position = p_rect.position + (p_src_rect.position + rect.position) * scale; local.position -= rect.position; - pieces[i].texture->draw_rect_region(p_canvas_item, target, local, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, p_texture_filter, p_texture_repeat, false); + pieces[i].texture->draw_rect_region(p_canvas_item, target, local, p_modulate, p_transpose, false); } } @@ -1435,12 +1707,6 @@ CurveTexture::~CurveTexture() { ////////////////// -//setter and getter names for property serialization -#define COLOR_RAMP_GET_OFFSETS "get_offsets" -#define COLOR_RAMP_GET_COLORS "get_colors" -#define COLOR_RAMP_SET_OFFSETS "set_offsets" -#define COLOR_RAMP_SET_COLORS "set_colors" - GradientTexture::GradientTexture() { update_pending = false; width = 2048; @@ -2059,7 +2325,7 @@ Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> ERR_FAIL_COND_V(images.size() != 0, ERR_INVALID_PARAMETER); FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); uint8_t header[4]; f->get_buffer(header, 4); diff --git a/scene/resources/texture.h b/scene/resources/texture.h index d439d34c95..3bc1ca8463 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -31,13 +31,13 @@ #ifndef TEXTURE_H #define TEXTURE_H +#include "core/io/resource.h" #include "core/io/resource_loader.h" #include "core/math/rect2.h" #include "core/os/file_access.h" #include "core/os/mutex.h" #include "core/os/rw_lock.h" #include "core/os/thread_safe.h" -#include "core/resource.h" #include "scene/resources/curve.h" #include "scene/resources/gradient.h" #include "servers/camera_server.h" @@ -66,9 +66,9 @@ public: virtual bool has_alpha() const = 0; - virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const; - virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const; - virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) const; + virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const; + virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const; + virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const; virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const; virtual Ref<Image> get_data() const { return Ref<Image>(); } @@ -115,9 +115,9 @@ public: virtual RID get_rid() const override; bool has_alpha() const override; - virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const override; - virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const override; - virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) const override; + virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override; + virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override; + virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override; bool is_pixel_opaque(int p_x, int p_y) const override; @@ -194,9 +194,9 @@ public: virtual void set_path(const String &p_path, bool p_take_over) override; - virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const override; - virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const override; - virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) const override; + virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override; + virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override; + virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override; virtual bool has_alpha() const override; bool is_pixel_opaque(int p_x, int p_y) const override; @@ -246,9 +246,9 @@ public: void set_filter_clip(const bool p_enable); bool has_filter_clip() const; - virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const override; - virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const override; - virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) const override; + virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override; + virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override; + virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override; virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const override; bool is_pixel_opaque(int p_x, int p_y) const override; @@ -285,9 +285,9 @@ public: void set_base_texture(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_base_texture() const; - virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const override; - virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const override; - virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) const override; + virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override; + virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override; + virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override; virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const override; bool is_pixel_opaque(int p_x, int p_y) const override; @@ -331,9 +331,9 @@ public: Ref<Texture2D> get_piece_texture(int p_idx) const; Ref<Image> to_image() const; - virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const override; - virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const override; - virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) const override; + virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override; + virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override; + virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override; bool is_pixel_opaque(int p_x, int p_y) const override; @@ -515,6 +515,122 @@ public: virtual String get_resource_type(const String &p_path) const; }; +class Texture3D : public Texture { + GDCLASS(Texture3D, Texture); + +protected: + static void _bind_methods(); + + TypedArray<Image> _get_data() const; + +public: + virtual Image::Format get_format() const = 0; + virtual int get_width() const = 0; + virtual int get_height() const = 0; + virtual int get_depth() const = 0; + virtual bool has_mipmaps() const = 0; + virtual Vector<Ref<Image>> get_data() const = 0; +}; + +class ImageTexture3D : public Texture3D { + GDCLASS(ImageTexture3D, Texture3D); + + mutable RID texture; + + Image::Format format = Image::FORMAT_MAX; + int width = 1; + int height = 1; + int depth = 1; + bool mipmaps = false; + +protected: + static void _bind_methods(); + + Error _create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const TypedArray<Image> &p_data); + void _update(const TypedArray<Image> &p_data); + +public: + 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; + + Error create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data); + void update(const Vector<Ref<Image>> &p_data); + virtual Vector<Ref<Image>> get_data() const override; + + virtual RID get_rid() const override; + virtual void set_path(const String &p_path, bool p_take_over = false) override; + + ImageTexture3D(); + ~ImageTexture3D(); +}; + +class StreamTexture3D : public Texture3D { + GDCLASS(StreamTexture3D, Texture3D); + +public: + enum DataFormat { + DATA_FORMAT_IMAGE, + DATA_FORMAT_LOSSLESS, + DATA_FORMAT_LOSSY, + DATA_FORMAT_BASIS_UNIVERSAL, + }; + + enum { + FORMAT_VERSION = 1 + }; + + enum FormatBits { + FORMAT_MASK_IMAGE_FORMAT = (1 << 20) - 1, + FORMAT_BIT_LOSSLESS = 1 << 20, + FORMAT_BIT_LOSSY = 1 << 21, + FORMAT_BIT_STREAM = 1 << 22, + FORMAT_BIT_HAS_MIPMAPS = 1 << 23, + }; + +private: + Error _load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps); + String path_to_file; + mutable RID texture; + Image::Format format; + int w, h, d; + bool mipmaps; + + virtual void reload_from_file() override; + +protected: + static void _bind_methods(); + void _validate_property(PropertyInfo &property) const override; + +public: + Image::Format get_format() const override; + Error load(const String &p_path); + String get_load_path() const; + + int get_width() const override; + int get_height() const override; + int get_depth() const override; + virtual bool has_mipmaps() const override; + virtual RID get_rid() const override; + + virtual void set_path(const String &p_path, bool p_take_over) override; + + virtual Vector<Ref<Image>> get_data() const override; + + StreamTexture3D(); + ~StreamTexture3D(); +}; + +class ResourceFormatLoaderStreamTexture3D : 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, bool p_no_cache = false); + 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; +}; + class CurveTexture : public Texture2D { GDCLASS(CurveTexture, Texture2D); RES_BASE_EXTENSION("curvetex") @@ -632,11 +748,12 @@ class AnimatedTexture : public Texture2D { //use readers writers lock for this, since its far more times read than written to RWLock *rw_lock; -private: +public: enum { MAX_FRAMES = 256 }; +private: RID proxy_ph; RID proxy; diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index 6a85d357ff..ccff49829e 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -30,17 +30,17 @@ #include "theme.h" #include "core/os/file_access.h" -#include "core/print_string.h" +#include "core/string/print_string.h" void Theme::_emit_theme_changed() { emit_changed(); } -Vector<String> Theme::_get_icon_list(const String &p_type) const { +Vector<String> Theme::_get_icon_list(const String &p_node_type) const { Vector<String> ilret; List<StringName> il; - get_icon_list(p_type, &il); + get_icon_list(p_node_type, &il); ilret.resize(il.size()); int i = 0; @@ -51,11 +51,11 @@ Vector<String> Theme::_get_icon_list(const String &p_type) const { return ilret; } -Vector<String> Theme::_get_stylebox_list(const String &p_type) const { +Vector<String> Theme::_get_stylebox_list(const String &p_node_type) const { Vector<String> ilret; List<StringName> il; - get_stylebox_list(p_type, &il); + get_stylebox_list(p_node_type, &il); ilret.resize(il.size()); int i = 0; @@ -81,11 +81,11 @@ Vector<String> Theme::_get_stylebox_types() const { return ilret; } -Vector<String> Theme::_get_font_list(const String &p_type) const { +Vector<String> Theme::_get_font_list(const String &p_node_type) const { Vector<String> ilret; List<StringName> il; - get_font_list(p_type, &il); + get_font_list(p_node_type, &il); ilret.resize(il.size()); int i = 0; @@ -96,11 +96,11 @@ Vector<String> Theme::_get_font_list(const String &p_type) const { return ilret; } -Vector<String> Theme::_get_color_list(const String &p_type) const { +Vector<String> Theme::_get_color_list(const String &p_node_type) const { Vector<String> ilret; List<StringName> il; - get_color_list(p_type, &il); + get_color_list(p_node_type, &il); ilret.resize(il.size()); int i = 0; @@ -111,11 +111,11 @@ Vector<String> Theme::_get_color_list(const String &p_type) const { return ilret; } -Vector<String> Theme::_get_constant_list(const String &p_type) const { +Vector<String> Theme::_get_constant_list(const String &p_node_type) const { Vector<String> ilret; List<StringName> il; - get_constant_list(p_type, &il); + get_constant_list(p_node_type, &il); ilret.resize(il.size()); int i = 0; @@ -126,7 +126,7 @@ Vector<String> Theme::_get_constant_list(const String &p_type) const { return ilret; } -Vector<String> Theme::_get_type_list(const String &p_type) const { +Vector<String> Theme::_get_type_list(const String &p_node_type) const { Vector<String> ilret; List<StringName> il; @@ -325,19 +325,19 @@ void Theme::set_default_font(const Ref<Font> &p_font) { default_font = p_font; } -void Theme::set_icon(const StringName &p_name, const StringName &p_type, const Ref<Texture2D> &p_icon) { +void Theme::set_icon(const StringName &p_name, const StringName &p_node_type, const Ref<Texture2D> &p_icon) { //ERR_FAIL_COND(p_icon.is_null()); - bool new_value = !icon_map.has(p_type) || !icon_map[p_type].has(p_name); + bool new_value = !icon_map.has(p_node_type) || !icon_map[p_node_type].has(p_name); - if (icon_map[p_type].has(p_name) && icon_map[p_type][p_name].is_valid()) { - icon_map[p_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + if (icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid()) { + icon_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } - icon_map[p_type][p_name] = p_icon; + icon_map[p_node_type][p_name] = p_icon; if (p_icon.is_valid()) { - icon_map[p_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); + icon_map[p_node_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } if (new_value) { @@ -346,50 +346,50 @@ void Theme::set_icon(const StringName &p_name, const StringName &p_type, const R } } -Ref<Texture2D> Theme::get_icon(const StringName &p_name, const StringName &p_type) const { - if (icon_map.has(p_type) && icon_map[p_type].has(p_name) && icon_map[p_type][p_name].is_valid()) { - return icon_map[p_type][p_name]; +Ref<Texture2D> Theme::get_icon(const StringName &p_name, const StringName &p_node_type) const { + if (icon_map.has(p_node_type) && icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid()) { + return icon_map[p_node_type][p_name]; } else { return default_icon; } } -bool Theme::has_icon(const StringName &p_name, const StringName &p_type) const { - return (icon_map.has(p_type) && icon_map[p_type].has(p_name) && icon_map[p_type][p_name].is_valid()); +bool Theme::has_icon(const StringName &p_name, const StringName &p_node_type) const { + return (icon_map.has(p_node_type) && icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid()); } -void Theme::clear_icon(const StringName &p_name, const StringName &p_type) { - ERR_FAIL_COND(!icon_map.has(p_type)); - ERR_FAIL_COND(!icon_map[p_type].has(p_name)); +void Theme::clear_icon(const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND(!icon_map.has(p_node_type)); + ERR_FAIL_COND(!icon_map[p_node_type].has(p_name)); - if (icon_map[p_type][p_name].is_valid()) { - icon_map[p_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + if (icon_map[p_node_type][p_name].is_valid()) { + icon_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } - icon_map[p_type].erase(p_name); + icon_map[p_node_type].erase(p_name); _change_notify(); emit_changed(); } -void Theme::get_icon_list(StringName p_type, List<StringName> *p_list) const { +void Theme::get_icon_list(StringName p_node_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); - if (!icon_map.has(p_type)) { + if (!icon_map.has(p_node_type)) { return; } const StringName *key = nullptr; - while ((key = icon_map[p_type].next(key))) { + while ((key = icon_map[p_node_type].next(key))) { p_list->push_back(*key); } } -void Theme::set_shader(const StringName &p_name, const StringName &p_type, const Ref<Shader> &p_shader) { - bool new_value = !shader_map.has(p_type) || !shader_map[p_type].has(p_name); +void Theme::set_shader(const StringName &p_name, const StringName &p_node_type, const Ref<Shader> &p_shader) { + bool new_value = !shader_map.has(p_node_type) || !shader_map[p_node_type].has(p_name); - shader_map[p_type][p_name] = p_shader; + shader_map[p_node_type][p_name] = p_shader; if (new_value) { _change_notify(); @@ -397,54 +397,54 @@ void Theme::set_shader(const StringName &p_name, const StringName &p_type, const } } -Ref<Shader> Theme::get_shader(const StringName &p_name, const StringName &p_type) const { - if (shader_map.has(p_type) && shader_map[p_type].has(p_name) && shader_map[p_type][p_name].is_valid()) { - return shader_map[p_type][p_name]; +Ref<Shader> Theme::get_shader(const StringName &p_name, const StringName &p_node_type) const { + if (shader_map.has(p_node_type) && shader_map[p_node_type].has(p_name) && shader_map[p_node_type][p_name].is_valid()) { + return shader_map[p_node_type][p_name]; } else { return nullptr; } } -bool Theme::has_shader(const StringName &p_name, const StringName &p_type) const { - return (shader_map.has(p_type) && shader_map[p_type].has(p_name) && shader_map[p_type][p_name].is_valid()); +bool Theme::has_shader(const StringName &p_name, const StringName &p_node_type) const { + return (shader_map.has(p_node_type) && shader_map[p_node_type].has(p_name) && shader_map[p_node_type][p_name].is_valid()); } -void Theme::clear_shader(const StringName &p_name, const StringName &p_type) { - ERR_FAIL_COND(!shader_map.has(p_type)); - ERR_FAIL_COND(!shader_map[p_type].has(p_name)); +void Theme::clear_shader(const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND(!shader_map.has(p_node_type)); + ERR_FAIL_COND(!shader_map[p_node_type].has(p_name)); - shader_map[p_type].erase(p_name); + shader_map[p_node_type].erase(p_name); _change_notify(); emit_changed(); } -void Theme::get_shader_list(const StringName &p_type, List<StringName> *p_list) const { +void Theme::get_shader_list(const StringName &p_node_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); - if (!shader_map.has(p_type)) { + if (!shader_map.has(p_node_type)) { return; } const StringName *key = nullptr; - while ((key = shader_map[p_type].next(key))) { + while ((key = shader_map[p_node_type].next(key))) { p_list->push_back(*key); } } -void Theme::set_stylebox(const StringName &p_name, const StringName &p_type, const Ref<StyleBox> &p_style) { +void Theme::set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style) { //ERR_FAIL_COND(p_style.is_null()); - bool new_value = !style_map.has(p_type) || !style_map[p_type].has(p_name); + bool new_value = !style_map.has(p_node_type) || !style_map[p_node_type].has(p_name); - if (style_map[p_type].has(p_name) && style_map[p_type][p_name].is_valid()) { - style_map[p_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + if (style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid()) { + style_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } - style_map[p_type][p_name] = p_style; + style_map[p_node_type][p_name] = p_style; if (p_style.is_valid()) { - style_map[p_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); + style_map[p_node_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } if (new_value) { @@ -453,42 +453,42 @@ void Theme::set_stylebox(const StringName &p_name, const StringName &p_type, con emit_changed(); } -Ref<StyleBox> Theme::get_stylebox(const StringName &p_name, const StringName &p_type) const { - if (style_map.has(p_type) && style_map[p_type].has(p_name) && style_map[p_type][p_name].is_valid()) { - return style_map[p_type][p_name]; +Ref<StyleBox> Theme::get_stylebox(const StringName &p_name, const StringName &p_node_type) const { + if (style_map.has(p_node_type) && style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid()) { + return style_map[p_node_type][p_name]; } else { return default_style; } } -bool Theme::has_stylebox(const StringName &p_name, const StringName &p_type) const { - return (style_map.has(p_type) && style_map[p_type].has(p_name) && style_map[p_type][p_name].is_valid()); +bool Theme::has_stylebox(const StringName &p_name, const StringName &p_node_type) const { + return (style_map.has(p_node_type) && style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid()); } -void Theme::clear_stylebox(const StringName &p_name, const StringName &p_type) { - ERR_FAIL_COND(!style_map.has(p_type)); - ERR_FAIL_COND(!style_map[p_type].has(p_name)); +void Theme::clear_stylebox(const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND(!style_map.has(p_node_type)); + ERR_FAIL_COND(!style_map[p_node_type].has(p_name)); - if (style_map[p_type][p_name].is_valid()) { - style_map[p_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + if (style_map[p_node_type][p_name].is_valid()) { + style_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } - style_map[p_type].erase(p_name); + style_map[p_node_type].erase(p_name); _change_notify(); emit_changed(); } -void Theme::get_stylebox_list(StringName p_type, List<StringName> *p_list) const { +void Theme::get_stylebox_list(StringName p_node_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); - if (!style_map.has(p_type)) { + if (!style_map.has(p_node_type)) { return; } const StringName *key = nullptr; - while ((key = style_map[p_type].next(key))) { + while ((key = style_map[p_node_type].next(key))) { p_list->push_back(*key); } } @@ -502,19 +502,19 @@ void Theme::get_stylebox_types(List<StringName> *p_list) const { } } -void Theme::set_font(const StringName &p_name, const StringName &p_type, const Ref<Font> &p_font) { +void Theme::set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font) { //ERR_FAIL_COND(p_font.is_null()); - bool new_value = !font_map.has(p_type) || !font_map[p_type].has(p_name); + bool new_value = !font_map.has(p_node_type) || !font_map[p_node_type].has(p_name); - if (font_map[p_type][p_name].is_valid()) { - font_map[p_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + if (font_map[p_node_type][p_name].is_valid()) { + font_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } - font_map[p_type][p_name] = p_font; + font_map[p_node_type][p_name] = p_font; if (p_font.is_valid()) { - font_map[p_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); + font_map[p_node_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } if (new_value) { @@ -523,9 +523,9 @@ void Theme::set_font(const StringName &p_name, const StringName &p_type, const R } } -Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_type) const { - if (font_map.has(p_type) && font_map[p_type].has(p_name) && font_map[p_type][p_name].is_valid()) { - return font_map[p_type][p_name]; +Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_node_type) const { + if (font_map.has(p_node_type) && font_map[p_node_type].has(p_name) && font_map[p_node_type][p_name].is_valid()) { + return font_map[p_node_type][p_name]; } else if (default_theme_font.is_valid()) { return default_theme_font; } else { @@ -533,41 +533,41 @@ Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_type) co } } -bool Theme::has_font(const StringName &p_name, const StringName &p_type) const { - return (font_map.has(p_type) && font_map[p_type].has(p_name) && font_map[p_type][p_name].is_valid()); +bool Theme::has_font(const StringName &p_name, const StringName &p_node_type) const { + return (font_map.has(p_node_type) && font_map[p_node_type].has(p_name) && font_map[p_node_type][p_name].is_valid()); } -void Theme::clear_font(const StringName &p_name, const StringName &p_type) { - ERR_FAIL_COND(!font_map.has(p_type)); - ERR_FAIL_COND(!font_map[p_type].has(p_name)); +void Theme::clear_font(const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND(!font_map.has(p_node_type)); + ERR_FAIL_COND(!font_map[p_node_type].has(p_name)); - if (font_map[p_type][p_name].is_valid()) { - font_map[p_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + if (font_map[p_node_type][p_name].is_valid()) { + font_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } - font_map[p_type].erase(p_name); + font_map[p_node_type].erase(p_name); _change_notify(); emit_changed(); } -void Theme::get_font_list(StringName p_type, List<StringName> *p_list) const { +void Theme::get_font_list(StringName p_node_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); - if (!font_map.has(p_type)) { + if (!font_map.has(p_node_type)) { return; } const StringName *key = nullptr; - while ((key = font_map[p_type].next(key))) { + while ((key = font_map[p_node_type].next(key))) { p_list->push_back(*key); } } -void Theme::set_color(const StringName &p_name, const StringName &p_type, const Color &p_color) { - bool new_value = !color_map.has(p_type) || !color_map[p_type].has(p_name); +void Theme::set_color(const StringName &p_name, const StringName &p_node_type, const Color &p_color) { + bool new_value = !color_map.has(p_node_type) || !color_map[p_node_type].has(p_name); - color_map[p_type][p_name] = p_color; + color_map[p_node_type][p_name] = p_color; if (new_value) { _change_notify(); @@ -575,44 +575,44 @@ void Theme::set_color(const StringName &p_name, const StringName &p_type, const } } -Color Theme::get_color(const StringName &p_name, const StringName &p_type) const { - if (color_map.has(p_type) && color_map[p_type].has(p_name)) { - return color_map[p_type][p_name]; +Color Theme::get_color(const StringName &p_name, const StringName &p_node_type) const { + if (color_map.has(p_node_type) && color_map[p_node_type].has(p_name)) { + return color_map[p_node_type][p_name]; } else { return Color(); } } -bool Theme::has_color(const StringName &p_name, const StringName &p_type) const { - return (color_map.has(p_type) && color_map[p_type].has(p_name)); +bool Theme::has_color(const StringName &p_name, const StringName &p_node_type) const { + return (color_map.has(p_node_type) && color_map[p_node_type].has(p_name)); } -void Theme::clear_color(const StringName &p_name, const StringName &p_type) { - ERR_FAIL_COND(!color_map.has(p_type)); - ERR_FAIL_COND(!color_map[p_type].has(p_name)); +void Theme::clear_color(const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND(!color_map.has(p_node_type)); + ERR_FAIL_COND(!color_map[p_node_type].has(p_name)); - color_map[p_type].erase(p_name); + color_map[p_node_type].erase(p_name); _change_notify(); emit_changed(); } -void Theme::get_color_list(StringName p_type, List<StringName> *p_list) const { +void Theme::get_color_list(StringName p_node_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); - if (!color_map.has(p_type)) { + if (!color_map.has(p_node_type)) { return; } const StringName *key = nullptr; - while ((key = color_map[p_type].next(key))) { + while ((key = color_map[p_node_type].next(key))) { p_list->push_back(*key); } } -void Theme::set_constant(const StringName &p_name, const StringName &p_type, int p_constant) { - bool new_value = !constant_map.has(p_type) || !constant_map[p_type].has(p_name); - constant_map[p_type][p_name] = p_constant; +void Theme::set_constant(const StringName &p_name, const StringName &p_node_type, int p_constant) { + bool new_value = !constant_map.has(p_node_type) || !constant_map[p_node_type].has(p_name); + constant_map[p_node_type][p_name] = p_constant; if (new_value) { _change_notify(); @@ -620,37 +620,37 @@ void Theme::set_constant(const StringName &p_name, const StringName &p_type, int } } -int Theme::get_constant(const StringName &p_name, const StringName &p_type) const { - if (constant_map.has(p_type) && constant_map[p_type].has(p_name)) { - return constant_map[p_type][p_name]; +int Theme::get_constant(const StringName &p_name, const StringName &p_node_type) const { + if (constant_map.has(p_node_type) && constant_map[p_node_type].has(p_name)) { + return constant_map[p_node_type][p_name]; } else { return 0; } } -bool Theme::has_constant(const StringName &p_name, const StringName &p_type) const { - return (constant_map.has(p_type) && constant_map[p_type].has(p_name)); +bool Theme::has_constant(const StringName &p_name, const StringName &p_node_type) const { + return (constant_map.has(p_node_type) && constant_map[p_node_type].has(p_name)); } -void Theme::clear_constant(const StringName &p_name, const StringName &p_type) { - ERR_FAIL_COND(!constant_map.has(p_type)); - ERR_FAIL_COND(!constant_map[p_type].has(p_name)); +void Theme::clear_constant(const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND(!constant_map.has(p_node_type)); + ERR_FAIL_COND(!constant_map[p_node_type].has(p_name)); - constant_map[p_type].erase(p_name); + constant_map[p_node_type].erase(p_name); _change_notify(); emit_changed(); } -void Theme::get_constant_list(StringName p_type, List<StringName> *p_list) const { +void Theme::get_constant_list(StringName p_node_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); - if (!constant_map.has(p_type)) { + if (!constant_map.has(p_node_type)) { return; } const StringName *key = nullptr; - while ((key = constant_map[p_type].next(key))) { + while ((key = constant_map[p_node_type].next(key))) { p_list->push_back(*key); } } @@ -800,43 +800,43 @@ void Theme::get_type_list(List<StringName> *p_list) const { } void Theme::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_icon", "name", "type", "texture"), &Theme::set_icon); - ClassDB::bind_method(D_METHOD("get_icon", "name", "type"), &Theme::get_icon); - ClassDB::bind_method(D_METHOD("has_icon", "name", "type"), &Theme::has_icon); - ClassDB::bind_method(D_METHOD("clear_icon", "name", "type"), &Theme::clear_icon); - ClassDB::bind_method(D_METHOD("get_icon_list", "type"), &Theme::_get_icon_list); - - ClassDB::bind_method(D_METHOD("set_stylebox", "name", "type", "texture"), &Theme::set_stylebox); - ClassDB::bind_method(D_METHOD("get_stylebox", "name", "type"), &Theme::get_stylebox); - ClassDB::bind_method(D_METHOD("has_stylebox", "name", "type"), &Theme::has_stylebox); - ClassDB::bind_method(D_METHOD("clear_stylebox", "name", "type"), &Theme::clear_stylebox); - ClassDB::bind_method(D_METHOD("get_stylebox_list", "type"), &Theme::_get_stylebox_list); + ClassDB::bind_method(D_METHOD("set_icon", "name", "node_type", "texture"), &Theme::set_icon); + ClassDB::bind_method(D_METHOD("get_icon", "name", "node_type"), &Theme::get_icon); + ClassDB::bind_method(D_METHOD("has_icon", "name", "node_type"), &Theme::has_icon); + ClassDB::bind_method(D_METHOD("clear_icon", "name", "node_type"), &Theme::clear_icon); + ClassDB::bind_method(D_METHOD("get_icon_list", "node_type"), &Theme::_get_icon_list); + + ClassDB::bind_method(D_METHOD("set_stylebox", "name", "node_type", "texture"), &Theme::set_stylebox); + ClassDB::bind_method(D_METHOD("get_stylebox", "name", "node_type"), &Theme::get_stylebox); + ClassDB::bind_method(D_METHOD("has_stylebox", "name", "node_type"), &Theme::has_stylebox); + ClassDB::bind_method(D_METHOD("clear_stylebox", "name", "node_type"), &Theme::clear_stylebox); + ClassDB::bind_method(D_METHOD("get_stylebox_list", "node_type"), &Theme::_get_stylebox_list); ClassDB::bind_method(D_METHOD("get_stylebox_types"), &Theme::_get_stylebox_types); - ClassDB::bind_method(D_METHOD("set_font", "name", "type", "font"), &Theme::set_font); - ClassDB::bind_method(D_METHOD("get_font", "name", "type"), &Theme::get_font); - ClassDB::bind_method(D_METHOD("has_font", "name", "type"), &Theme::has_font); - ClassDB::bind_method(D_METHOD("clear_font", "name", "type"), &Theme::clear_font); - ClassDB::bind_method(D_METHOD("get_font_list", "type"), &Theme::_get_font_list); + ClassDB::bind_method(D_METHOD("set_font", "name", "node_type", "font"), &Theme::set_font); + ClassDB::bind_method(D_METHOD("get_font", "name", "node_type"), &Theme::get_font); + ClassDB::bind_method(D_METHOD("has_font", "name", "node_type"), &Theme::has_font); + ClassDB::bind_method(D_METHOD("clear_font", "name", "node_type"), &Theme::clear_font); + ClassDB::bind_method(D_METHOD("get_font_list", "node_type"), &Theme::_get_font_list); - ClassDB::bind_method(D_METHOD("set_color", "name", "type", "color"), &Theme::set_color); - ClassDB::bind_method(D_METHOD("get_color", "name", "type"), &Theme::get_color); - ClassDB::bind_method(D_METHOD("has_color", "name", "type"), &Theme::has_color); - ClassDB::bind_method(D_METHOD("clear_color", "name", "type"), &Theme::clear_color); - ClassDB::bind_method(D_METHOD("get_color_list", "type"), &Theme::_get_color_list); + ClassDB::bind_method(D_METHOD("set_color", "name", "node_type", "color"), &Theme::set_color); + ClassDB::bind_method(D_METHOD("get_color", "name", "node_type"), &Theme::get_color); + ClassDB::bind_method(D_METHOD("has_color", "name", "node_type"), &Theme::has_color); + ClassDB::bind_method(D_METHOD("clear_color", "name", "node_type"), &Theme::clear_color); + ClassDB::bind_method(D_METHOD("get_color_list", "node_type"), &Theme::_get_color_list); - ClassDB::bind_method(D_METHOD("set_constant", "name", "type", "constant"), &Theme::set_constant); - ClassDB::bind_method(D_METHOD("get_constant", "name", "type"), &Theme::get_constant); - ClassDB::bind_method(D_METHOD("has_constant", "name", "type"), &Theme::has_constant); - ClassDB::bind_method(D_METHOD("clear_constant", "name", "type"), &Theme::clear_constant); - ClassDB::bind_method(D_METHOD("get_constant_list", "type"), &Theme::_get_constant_list); + ClassDB::bind_method(D_METHOD("set_constant", "name", "node_type", "constant"), &Theme::set_constant); + ClassDB::bind_method(D_METHOD("get_constant", "name", "node_type"), &Theme::get_constant); + ClassDB::bind_method(D_METHOD("has_constant", "name", "node_type"), &Theme::has_constant); + ClassDB::bind_method(D_METHOD("clear_constant", "name", "node_type"), &Theme::clear_constant); + ClassDB::bind_method(D_METHOD("get_constant_list", "node_type"), &Theme::_get_constant_list); ClassDB::bind_method(D_METHOD("clear"), &Theme::clear); ClassDB::bind_method(D_METHOD("set_default_font", "font"), &Theme::set_default_theme_font); ClassDB::bind_method(D_METHOD("get_default_font"), &Theme::get_default_theme_font); - ClassDB::bind_method(D_METHOD("get_type_list", "type"), &Theme::_get_type_list); + ClassDB::bind_method(D_METHOD("get_type_list", "node_type"), &Theme::_get_type_list); ClassDB::bind_method("copy_default_theme", &Theme::copy_default_theme); ClassDB::bind_method(D_METHOD("copy_theme", "other"), &Theme::copy_theme); diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 3c72ddd8a2..9c17a69e5d 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -31,8 +31,8 @@ #ifndef THEME_H #define THEME_H +#include "core/io/resource.h" #include "core/io/resource_loader.h" -#include "core/resource.h" #include "scene/resources/font.h" #include "scene/resources/shader.h" #include "scene/resources/style_box.h" @@ -51,13 +51,13 @@ class Theme : public Resource { HashMap<StringName, HashMap<StringName, Color>> color_map; HashMap<StringName, HashMap<StringName, int>> constant_map; - Vector<String> _get_icon_list(const String &p_type) const; - Vector<String> _get_stylebox_list(const String &p_type) const; + Vector<String> _get_icon_list(const String &p_node_type) const; + Vector<String> _get_stylebox_list(const String &p_node_type) const; Vector<String> _get_stylebox_types() const; - Vector<String> _get_font_list(const String &p_type) const; - Vector<String> _get_color_list(const String &p_type) const; - Vector<String> _get_constant_list(const String &p_type) const; - Vector<String> _get_type_list(const String &p_type) const; + Vector<String> _get_font_list(const String &p_node_type) const; + Vector<String> _get_color_list(const String &p_node_type) const; + Vector<String> _get_constant_list(const String &p_node_type) const; + Vector<String> _get_type_list(const String &p_node_type) const; protected: bool _set(const StringName &p_name, const Variant &p_value); @@ -88,42 +88,42 @@ public: void set_default_theme_font(const Ref<Font> &p_default_font); Ref<Font> get_default_theme_font() const; - void set_icon(const StringName &p_name, const StringName &p_type, const Ref<Texture2D> &p_icon); - Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_type) const; - bool has_icon(const StringName &p_name, const StringName &p_type) const; - void clear_icon(const StringName &p_name, const StringName &p_type); - void get_icon_list(StringName p_type, List<StringName> *p_list) const; - - void set_shader(const StringName &p_name, const StringName &p_type, const Ref<Shader> &p_shader); - Ref<Shader> get_shader(const StringName &p_name, const StringName &p_type) const; - bool has_shader(const StringName &p_name, const StringName &p_type) const; - void clear_shader(const StringName &p_name, const StringName &p_type); - void get_shader_list(const StringName &p_type, List<StringName> *p_list) const; - - void set_stylebox(const StringName &p_name, const StringName &p_type, const Ref<StyleBox> &p_style); - Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_type) const; - bool has_stylebox(const StringName &p_name, const StringName &p_type) const; - void clear_stylebox(const StringName &p_name, const StringName &p_type); - void get_stylebox_list(StringName p_type, List<StringName> *p_list) const; + void set_icon(const StringName &p_name, const StringName &p_node_type, const Ref<Texture2D> &p_icon); + Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_node_type) const; + bool has_icon(const StringName &p_name, const StringName &p_node_type) const; + void clear_icon(const StringName &p_name, const StringName &p_node_type); + void get_icon_list(StringName p_node_type, List<StringName> *p_list) const; + + void set_shader(const StringName &p_name, const StringName &p_node_type, const Ref<Shader> &p_shader); + Ref<Shader> get_shader(const StringName &p_name, const StringName &p_node_type) const; + bool has_shader(const StringName &p_name, const StringName &p_node_type) const; + void clear_shader(const StringName &p_name, const StringName &p_node_type); + void get_shader_list(const StringName &p_node_type, List<StringName> *p_list) const; + + void set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style); + Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_node_type) const; + bool has_stylebox(const StringName &p_name, const StringName &p_node_type) const; + void clear_stylebox(const StringName &p_name, const StringName &p_node_type); + void get_stylebox_list(StringName p_node_type, List<StringName> *p_list) const; void get_stylebox_types(List<StringName> *p_list) const; - void set_font(const StringName &p_name, const StringName &p_type, const Ref<Font> &p_font); - Ref<Font> get_font(const StringName &p_name, const StringName &p_type) const; - bool has_font(const StringName &p_name, const StringName &p_type) const; - void clear_font(const StringName &p_name, const StringName &p_type); - void get_font_list(StringName p_type, List<StringName> *p_list) const; - - void set_color(const StringName &p_name, const StringName &p_type, const Color &p_color); - Color get_color(const StringName &p_name, const StringName &p_type) const; - bool has_color(const StringName &p_name, const StringName &p_type) const; - void clear_color(const StringName &p_name, const StringName &p_type); - void get_color_list(StringName p_type, List<StringName> *p_list) const; - - void set_constant(const StringName &p_name, const StringName &p_type, int p_constant); - int get_constant(const StringName &p_name, const StringName &p_type) const; - bool has_constant(const StringName &p_name, const StringName &p_type) const; - void clear_constant(const StringName &p_name, const StringName &p_type); - void get_constant_list(StringName p_type, List<StringName> *p_list) const; + void set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font); + Ref<Font> get_font(const StringName &p_name, const StringName &p_node_type) const; + bool has_font(const StringName &p_name, const StringName &p_node_type) const; + void clear_font(const StringName &p_name, const StringName &p_node_type); + void get_font_list(StringName p_node_type, List<StringName> *p_list) const; + + void set_color(const StringName &p_name, const StringName &p_node_type, const Color &p_color); + Color get_color(const StringName &p_name, const StringName &p_node_type) const; + bool has_color(const StringName &p_name, const StringName &p_node_type) const; + void clear_color(const StringName &p_name, const StringName &p_node_type); + void get_color_list(StringName p_node_type, List<StringName> *p_list) const; + + void set_constant(const StringName &p_name, const StringName &p_node_type, int p_constant); + int get_constant(const StringName &p_name, const StringName &p_node_type) const; + bool has_constant(const StringName &p_name, const StringName &p_node_type) const; + void clear_constant(const StringName &p_name, const StringName &p_node_type); + void get_constant_list(StringName p_node_type, List<StringName> *p_list) const; void get_type_list(List<StringName> *p_list) const; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 6992360df7..4581763e9c 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -30,9 +30,9 @@ #include "tile_set.h" -#include "core/array.h" -#include "core/engine.h" +#include "core/config/engine.h" #include "core/math/geometry_2d.h" +#include "core/variant/array.h" bool TileSet::_set(const StringName &p_name, const Variant &p_value) { String n = p_name; @@ -40,7 +40,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { if (slash == -1) { return false; } - int id = String::to_int(n.c_str(), slash); + int id = String::to_int(n.get_data(), slash); if (!tile_map.has(id)) { create_tile(id); @@ -51,8 +51,6 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { tile_set_name(id, p_value); } else if (what == "texture") { tile_set_texture(id, p_value); - } else if (what == "normal_map") { - tile_set_normal_map(id, p_value); } else if (what == "tex_offset") { tile_set_texture_offset(id, p_value); } else if (what == "material") { @@ -216,7 +214,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { if (slash == -1) { return false; } - int id = String::to_int(n.c_str(), slash); + int id = String::to_int(n.get_data(), slash); ERR_FAIL_COND_V(!tile_map.has(id), false); @@ -226,8 +224,6 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { r_ret = tile_get_name(id); } else if (what == "texture") { r_ret = tile_get_texture(id); - } else if (what == "normal_map") { - r_ret = tile_get_normal_map(id); } else if (what == "tex_offset") { r_ret = tile_get_texture_offset(id); } else if (what == "material") { @@ -331,7 +327,6 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const { String pre = itos(id) + "/"; p_list->push_back(PropertyInfo(Variant::STRING, pre + "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "tex_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::COLOR, pre + "modulate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); @@ -402,17 +397,6 @@ Ref<Texture2D> TileSet::tile_get_texture(int p_id) const { return tile_map[p_id].texture; } -void TileSet::tile_set_normal_map(int p_id, const Ref<Texture2D> &p_normal_map) { - ERR_FAIL_COND(!tile_map.has(p_id)); - tile_map[p_id].normal_map = p_normal_map; - emit_changed(); -} - -Ref<Texture2D> TileSet::tile_get_normal_map(int p_id) const { - ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<Texture2D>()); - return tile_map[p_id].normal_map; -} - void TileSet::tile_set_material(int p_id, const Ref<ShaderMaterial> &p_material) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].material = p_material; @@ -1128,8 +1112,6 @@ void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("tile_get_name", "id"), &TileSet::tile_get_name); ClassDB::bind_method(D_METHOD("tile_set_texture", "id", "texture"), &TileSet::tile_set_texture); ClassDB::bind_method(D_METHOD("tile_get_texture", "id"), &TileSet::tile_get_texture); - ClassDB::bind_method(D_METHOD("tile_set_normal_map", "id", "normal_map"), &TileSet::tile_set_normal_map); - ClassDB::bind_method(D_METHOD("tile_get_normal_map", "id"), &TileSet::tile_get_normal_map); ClassDB::bind_method(D_METHOD("tile_set_material", "id", "material"), &TileSet::tile_set_material); ClassDB::bind_method(D_METHOD("tile_get_material", "id"), &TileSet::tile_get_material); ClassDB::bind_method(D_METHOD("tile_set_modulate", "id", "color"), &TileSet::tile_set_modulate); diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 78f34e46ce..79f1b4aa95 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -31,8 +31,8 @@ #ifndef TILE_SET_H #define TILE_SET_H -#include "core/array.h" -#include "core/resource.h" +#include "core/io/resource.h" +#include "core/variant/array.h" #include "scene/2d/light_occluder_2d.h" #include "scene/2d/navigation_region_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" @@ -106,7 +106,6 @@ private: struct TileData { String name; Ref<Texture2D> texture; - Ref<Texture2D> normal_map; Vector2 offset; Rect2i region; Vector<ShapeData> shapes_data; @@ -149,9 +148,6 @@ public: void tile_set_texture(int p_id, const Ref<Texture2D> &p_texture); Ref<Texture2D> tile_get_texture(int p_id) const; - void tile_set_normal_map(int p_id, const Ref<Texture2D> &p_normal_map); - Ref<Texture2D> tile_get_normal_map(int p_id) const; - void tile_set_texture_offset(int p_id, const Vector2 &p_offset); Vector2 tile_get_texture_offset(int p_id) const; diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index e4851ad9f7..141d4b09f5 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -30,7 +30,7 @@ #include "visual_shader.h" -#include "core/vmap.h" +#include "core/templates/vmap.h" #include "servers/rendering/shader_types.h" #include "visual_shader_nodes.h" @@ -65,20 +65,16 @@ bool VisualShaderNode::is_port_separator(int p_index) const { bool VisualShaderNode::is_output_port_connected(int p_port) const { if (connected_output_ports.has(p_port)) { - return connected_output_ports[p_port]; + return connected_output_ports[p_port] > 0; } return false; } void VisualShaderNode::set_output_port_connected(int p_port, bool p_connected) { if (p_connected) { - connected_output_ports[p_port] = true; - ++connected_output_count; + connected_output_ports[p_port]++; } else { - --connected_output_count; - if (connected_output_count == 0) { - connected_output_ports[p_port] = false; - } + connected_output_ports[p_port]--; } } @@ -101,6 +97,14 @@ bool VisualShaderNode::is_code_generated() const { return true; } +bool VisualShaderNode::is_show_prop_names() const { + return false; +} + +bool VisualShaderNode::is_use_prop_slots() const { + return false; +} + Vector<VisualShader::DefaultTextureParam> VisualShaderNode::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { return Vector<VisualShader::DefaultTextureParam>(); } @@ -172,8 +176,6 @@ void VisualShaderNode::_bind_methods() { } VisualShaderNode::VisualShaderNode() { - port_preview = -1; - simple_decl = true; } ///////////////////////////////////////////////////////// @@ -319,6 +321,14 @@ VisualShaderNodeCustom::VisualShaderNodeCustom() { ///////////////////////////////////////////////////////// +void VisualShader::set_shader_type(Type p_type) { + current_type = p_type; +} + +VisualShader::Type VisualShader::get_shader_type() const { + return current_type; +} + void VisualShader::set_version(const String &p_version) { version = p_version; } @@ -920,8 +930,12 @@ VisualShader::RenderModeEnums VisualShader::render_mode_enums[] = { static const char *type_string[VisualShader::TYPE_MAX] = { "vertex", "fragment", - "light" + "light", + "emit", + "process", + "end" }; + bool VisualShader::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; if (name == "mode") { @@ -978,7 +992,7 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) { set_node_position(type, id, p_value); return true; } else if (what == "size") { - ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_size(p_value); + ((VisualShaderNodeResizableBase *)get_node(type, id).ptr())->set_size(p_value); return true; } else if (what == "input_ports") { ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_inputs(p_value); @@ -1045,7 +1059,7 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const { r_ret = get_node_position(type, id); return true; } else if (what == "size") { - r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_size(); + r_ret = ((VisualShaderNodeResizableBase *)get_node(type, id).ptr())->get_size(); return true; } else if (what == "input_ports") { r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_inputs(); @@ -1229,9 +1243,9 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui } else if (in_type == VisualShaderNode::PORT_TYPE_BOOLEAN && out_type == VisualShaderNode::PORT_TYPE_SCALAR_INT) { inputs[i] = src_var + " > 0 ? true : false"; } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR && out_type == VisualShaderNode::PORT_TYPE_BOOLEAN) { - inputs[i] = src_var + " ? 1.0 : 0.0"; + inputs[i] = "(" + src_var + " ? 1.0 : 0.0)"; } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR_INT && out_type == VisualShaderNode::PORT_TYPE_BOOLEAN) { - inputs[i] = src_var + " ? 1 : 0"; + inputs[i] = "(" + src_var + " ? 1 : 0)"; } else if (in_type == VisualShaderNode::PORT_TYPE_VECTOR && out_type == VisualShaderNode::PORT_TYPE_BOOLEAN) { inputs[i] = "vec3(" + src_var + " ? 1.0 : 0.0)"; } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR && out_type == VisualShaderNode::PORT_TYPE_SCALAR_INT) { @@ -1344,6 +1358,19 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui return OK; } +bool VisualShader::has_func_name(RenderingServer::ShaderMode p_mode, const String &p_func_name) const { + if (!ShaderTypes::get_singleton()->get_functions(p_mode).has(p_func_name)) { + if (p_mode == RenderingServer::ShaderMode::SHADER_PARTICLES) { + if (p_func_name == "emit" || p_func_name == "process" || p_func_name == "end") { + return true; + } + } + return false; + } + + return true; +} + void VisualShader::_update_shader() const { if (!dirty) { return; @@ -1367,10 +1394,19 @@ void VisualShader::_update_shader() const { { //fill render mode enums int idx = 0; + bool specular = false; while (render_mode_enums[idx].string) { if (shader_mode == render_mode_enums[idx].mode) { - if (modes.has(render_mode_enums[idx].string)) { - int which = modes[render_mode_enums[idx].string]; + if (shader_mode == Shader::MODE_SPATIAL) { + if (String(render_mode_enums[idx].string) == "specular") { + specular = true; + } + } + if (modes.has(render_mode_enums[idx].string) || specular) { + int which = 0; + if (modes.has(render_mode_enums[idx].string)) { + which = modes[render_mode_enums[idx].string]; + } int count = 0; for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode)).size(); i++) { String mode = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode))[i]; @@ -1406,14 +1442,14 @@ void VisualShader::_update_shader() const { global_code += "render_mode " + render_mode + ";\n\n"; } - static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light" }; + static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "emit", "process", "end" }; String global_expressions; Set<String> used_uniform_names; List<VisualShaderNodeUniform *> uniforms; for (int i = 0, index = 0; i < TYPE_MAX; i++) { - if (!ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader_mode)).has(func_name[i])) { + if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) { continue; } @@ -1448,8 +1484,10 @@ void VisualShader::_update_shader() const { } } + Map<int, String> code_map; + for (int i = 0; i < TYPE_MAX; i++) { - if (!ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader_mode)).has(func_name[i])) { + if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) { continue; } @@ -1457,6 +1495,8 @@ void VisualShader::_update_shader() const { VMap<ConnectionKey, const List<Connection>::Element *> input_connections; VMap<ConnectionKey, const List<Connection>::Element *> output_connections; + StringBuilder func_code; + for (const List<Connection>::Element *E = graph[i].connections.front(); E; E = E->next()) { ConnectionKey from_key; from_key.node = E->get().from_node; @@ -1470,14 +1510,30 @@ void VisualShader::_update_shader() const { input_connections.insert(to_key, E); } - - code += "\nvoid " + String(func_name[i]) + "() {\n"; + if (shader_mode != Shader::MODE_PARTICLES) { + func_code += "\nvoid " + String(func_name[i]) + "() {\n"; + } + insertion_pos.insert(i, code.get_string_length() + func_code.get_string_length()); Set<int> processed; - Error err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes); + Error err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, func_code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes); ERR_FAIL_COND(err != OK); - insertion_pos.insert(i, code.get_string_length()); + if (shader_mode == Shader::MODE_PARTICLES) { + code_map.insert(i, func_code); + } else { + func_code += "}\n"; + code += func_code; + } + } + + if (shader_mode == Shader::MODE_PARTICLES) { + code += "\nvoid compute() {\n"; + code += "\tif (RESTART) {\n"; + code += code_map[TYPE_EMIT]; + code += "\t} else {\n"; + code += code_map[TYPE_PROCESS]; + code += "\t}\n"; code += "}\n"; } @@ -1488,7 +1544,7 @@ void VisualShader::_update_shader() const { final_code += global_expressions; String tcode = code; for (int i = 0; i < TYPE_MAX; i++) { - if (!ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader_mode)).has(func_name[i])) { + if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) { continue; } tcode = tcode.insert(insertion_pos[i], global_code_per_func[Type(i)]); @@ -1567,9 +1623,14 @@ void VisualShader::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_graph_offset", "get_graph_offset"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "version", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_version", "get_version"); + ADD_PROPERTY_DEFAULT("code", ""); // Inherited from Shader, prevents showing default code as override in docs. + BIND_ENUM_CONSTANT(TYPE_VERTEX); BIND_ENUM_CONSTANT(TYPE_FRAGMENT); BIND_ENUM_CONSTANT(TYPE_LIGHT); + BIND_ENUM_CONSTANT(TYPE_EMIT); + BIND_ENUM_CONSTANT(TYPE_PROCESS); + BIND_ENUM_CONSTANT(TYPE_END); BIND_ENUM_CONSTANT(TYPE_MAX); BIND_CONSTANT(NODE_ID_INVALID); @@ -1577,8 +1638,6 @@ void VisualShader::_bind_methods() { } VisualShader::VisualShader() { - shader_mode = Shader::MODE_SPATIAL; - for (int i = 0; i < TYPE_MAX; i++) { Ref<VisualShaderNodeOutput> output; output.instance(); @@ -1587,8 +1646,6 @@ VisualShader::VisualShader() { graph[i].nodes[NODE_ID_OUTPUT].node = output; graph[i].nodes[NODE_ID_OUTPUT].position = Vector2(400, 150); } - - dirty = true; } /////////////////////////////////////////////////////////// @@ -1655,6 +1712,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "diffuse", "DIFFUSE_LIGHT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "specular", "SPECULAR_LIGHT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "metallic", "METALLIC" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" }, @@ -1711,22 +1769,50 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" }, - // Particles, Vertex - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, - - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, - - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Particles, Emit + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + + // Particles, Process + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + + // Particles, End + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Sky, Fragment { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_cubemap_pass", "AT_CUBEMAP_PASS" }, @@ -2028,10 +2114,6 @@ void VisualShaderNodeInput::_bind_methods() { } VisualShaderNodeInput::VisualShaderNodeInput() { - input_name = "[None]"; - // changed when set - shader_type = VisualShader::TYPE_MAX; - shader_mode = Shader::MODE_MAX; } ////////////// UniformRef @@ -2046,6 +2128,15 @@ void VisualShaderNodeUniformRef::clear_uniforms() { uniforms.clear(); } +bool VisualShaderNodeUniformRef::has_uniform(const String &p_name) { + for (List<VisualShaderNodeUniformRef::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + if (E->get().name == p_name) { + return true; + } + } + return false; +} + String VisualShaderNodeUniformRef::get_caption() const { return "UniformRef"; } @@ -2063,10 +2154,6 @@ String VisualShaderNodeUniformRef::get_input_port_name(int p_port) const { } int VisualShaderNodeUniformRef::get_output_port_count() const { - if (uniform_name == "[None]") { - return 0; - } - switch (uniform_type) { case UniformType::UNIFORM_TYPE_FLOAT: return 1; @@ -2085,7 +2172,7 @@ int VisualShaderNodeUniformRef::get_output_port_count() const { default: break; } - return 0; + return 1; } VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port_type(int p_port) const { @@ -2145,8 +2232,8 @@ String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const { void VisualShaderNodeUniformRef::set_uniform_name(const String &p_name) { uniform_name = p_name; - if (p_name != "[None]") { - uniform_type = get_uniform_type_by_name(p_name); + if (uniform_name != "[None]") { + uniform_type = get_uniform_type_by_name(uniform_name); } else { uniform_type = UniformType::UNIFORM_TYPE_FLOAT; } @@ -2187,6 +2274,9 @@ VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_ String VisualShaderNodeUniformRef::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 { switch (uniform_type) { case UniformType::UNIFORM_TYPE_FLOAT: + if (uniform_name == "[None]") { + return "\t" + p_output_vars[0] + " = 0.0;\n"; + } return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; case UniformType::UNIFORM_TYPE_INT: return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; @@ -2209,22 +2299,33 @@ String VisualShaderNodeUniformRef::generate_code(Shader::Mode p_mode, VisualShad return ""; } +void VisualShaderNodeUniformRef::_set_uniform_type(int p_uniform_type) { + uniform_type = (UniformType)p_uniform_type; +} + +int VisualShaderNodeUniformRef::_get_uniform_type() const { + return (int)uniform_type; +} + void VisualShaderNodeUniformRef::_bind_methods() { ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniformRef::set_uniform_name); ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniformRef::get_uniform_name); + ClassDB::bind_method(D_METHOD("_set_uniform_type", "type"), &VisualShaderNodeUniformRef::_set_uniform_type); + ClassDB::bind_method(D_METHOD("_get_uniform_type"), &VisualShaderNodeUniformRef::_get_uniform_type); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name", PROPERTY_HINT_ENUM, ""), "set_uniform_name", "get_uniform_name"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "uniform_type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_uniform_type", "_get_uniform_type"); } Vector<StringName> VisualShaderNodeUniformRef::get_editable_properties() const { Vector<StringName> props; props.push_back("uniform_name"); + props.push_back("uniform_type"); return props; } VisualShaderNodeUniformRef::VisualShaderNodeUniformRef() { - uniform_name = "[None]"; - uniform_type = UniformType::UNIFORM_TYPE_FLOAT; } //////////////////////////////////////////// @@ -2283,13 +2384,30 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { // Canvas Item, Light { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.a" }, - // Particles, Vertex - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + // Particles, Emit + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, + // Particles, Process + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, + // Particles, End + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, // Sky, Fragment { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR" }, { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" }, @@ -2477,23 +2595,39 @@ Vector<StringName> VisualShaderNodeUniform::get_editable_properties() const { } VisualShaderNodeUniform::VisualShaderNodeUniform() { - qualifier = QUAL_NONE; } -////////////// GroupBase - -String VisualShaderNodeGroupBase::get_caption() const { - return "Group"; -} +////////////// ResizeableBase -void VisualShaderNodeGroupBase::set_size(const Vector2 &p_size) { +void VisualShaderNodeResizableBase::set_size(const Vector2 &p_size) { size = p_size; } -Vector2 VisualShaderNodeGroupBase::get_size() const { +Vector2 VisualShaderNodeResizableBase::get_size() const { return size; } +void VisualShaderNodeResizableBase::set_allow_v_resize(bool p_enabled) { + allow_v_resize = p_enabled; +} + +bool VisualShaderNodeResizableBase::is_allow_v_resize() const { + return allow_v_resize; +} + +void VisualShaderNodeResizableBase::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualShaderNodeResizableBase::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &VisualShaderNodeResizableBase::get_size); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); +} + +VisualShaderNodeResizableBase::VisualShaderNodeResizableBase() { + set_allow_v_resize(true); +} + +////////////// GroupBase + void VisualShaderNodeGroupBase::set_inputs(const String &p_inputs) { if (inputs == p_inputs) { return; @@ -2609,6 +2743,7 @@ void VisualShaderNodeGroupBase::add_input_port(int p_id, int p_type, const Strin } _apply_port_changes(); + emit_changed(); } void VisualShaderNodeGroupBase::remove_input_port(int p_id) { @@ -2633,6 +2768,7 @@ void VisualShaderNodeGroupBase::remove_input_port(int p_id) { } _apply_port_changes(); + emit_changed(); } int VisualShaderNodeGroupBase::get_input_port_count() const { @@ -2677,6 +2813,7 @@ void VisualShaderNodeGroupBase::add_output_port(int p_id, int p_type, const Stri } _apply_port_changes(); + emit_changed(); } void VisualShaderNodeGroupBase::remove_output_port(int p_id) { @@ -2701,6 +2838,7 @@ void VisualShaderNodeGroupBase::remove_output_port(int p_id) { } _apply_port_changes(); + emit_changed(); } int VisualShaderNodeGroupBase::get_output_port_count() const { @@ -2747,6 +2885,7 @@ void VisualShaderNodeGroupBase::set_input_port_type(int p_id, int p_type) { inputs = inputs.insert(index, itos(p_type)); _apply_port_changes(); + emit_changed(); } VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_input_port_type(int p_id) const { @@ -2782,6 +2921,7 @@ void VisualShaderNodeGroupBase::set_input_port_name(int p_id, const String &p_na inputs = inputs.insert(index, p_name); _apply_port_changes(); + emit_changed(); } String VisualShaderNodeGroupBase::get_input_port_name(int p_id) const { @@ -2817,6 +2957,7 @@ void VisualShaderNodeGroupBase::set_output_port_type(int p_id, int p_type) { outputs = outputs.insert(index, itos(p_type)); _apply_port_changes(); + emit_changed(); } VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_output_port_type(int p_id) const { @@ -2852,6 +2993,7 @@ void VisualShaderNodeGroupBase::set_output_port_name(int p_id, const String &p_n outputs = outputs.insert(index, p_name); _apply_port_changes(); + emit_changed(); } String VisualShaderNodeGroupBase::get_output_port_name(int p_id) const { @@ -2912,9 +3054,6 @@ bool VisualShaderNodeGroupBase::is_editable() const { } void VisualShaderNodeGroupBase::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualShaderNodeGroupBase::set_size); - ClassDB::bind_method(D_METHOD("get_size"), &VisualShaderNodeGroupBase::get_size); - ClassDB::bind_method(D_METHOD("set_inputs", "inputs"), &VisualShaderNodeGroupBase::set_inputs); ClassDB::bind_method(D_METHOD("get_inputs"), &VisualShaderNodeGroupBase::get_inputs); @@ -2942,8 +3081,6 @@ void VisualShaderNodeGroupBase::_bind_methods() { ClassDB::bind_method(D_METHOD("get_free_input_port_id"), &VisualShaderNodeGroupBase::get_free_input_port_id); ClassDB::bind_method(D_METHOD("get_free_output_port_id"), &VisualShaderNodeGroupBase::get_free_output_port_id); - - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); } String VisualShaderNodeGroupBase::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 { @@ -2951,10 +3088,6 @@ String VisualShaderNodeGroupBase::generate_code(Shader::Mode p_mode, VisualShade } VisualShaderNodeGroupBase::VisualShaderNodeGroupBase() { - size = Size2(0, 0); - inputs = ""; - outputs = ""; - editable = false; simple_decl = false; } @@ -2966,6 +3099,7 @@ String VisualShaderNodeExpression::get_caption() const { void VisualShaderNodeExpression::set_expression(const String &p_expression) { expression = p_expression; + emit_changed(); } String VisualShaderNodeExpression::get_expression() const { @@ -3079,7 +3213,6 @@ void VisualShaderNodeExpression::_bind_methods() { } VisualShaderNodeExpression::VisualShaderNodeExpression() { - expression = ""; set_editable(true); } diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 05d8950be9..41c4642ee3 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -31,7 +31,7 @@ #ifndef VISUAL_SHADER_H #define VISUAL_SHADER_H -#include "core/string_builder.h" +#include "core/string/string_builder.h" #include "scene/gui/control.h" #include "scene/resources/shader.h" @@ -50,6 +50,9 @@ public: TYPE_VERTEX, TYPE_FRAGMENT, TYPE_LIGHT, + TYPE_EMIT, + TYPE_PROCESS, + TYPE_END, TYPE_MAX }; @@ -66,6 +69,8 @@ public: }; private: + Type current_type; + struct Node { Ref<VisualShaderNode> node; Vector2 position; @@ -77,7 +82,7 @@ private: List<Connection> connections; } graph[TYPE_MAX]; - Shader::Mode shader_mode; + Shader::Mode shader_mode = Shader::MODE_SPATIAL; mutable String previous_code; Array _get_node_connections(Type p_type) const; @@ -94,7 +99,7 @@ private: static RenderModeEnums render_mode_enums[]; - volatile mutable bool dirty; + volatile mutable bool dirty = true; void _queue_update(); union ConnectionKey { @@ -111,6 +116,7 @@ private: Error _write_node(Type p_type, StringBuilder &global_code, StringBuilder &global_code_per_node, Map<Type, StringBuilder> &global_code_per_func, StringBuilder &code, Vector<DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const; void _input_type_changed(Type p_type, int p_id); + bool has_func_name(RenderingServer::ShaderMode p_mode, const String &p_func_name) const; protected: virtual void _update_shader() const override; @@ -120,6 +126,10 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; +public: // internal methods + void set_shader_type(Type p_type); + Type get_shader_type() const; + public: void set_version(const String &p_version); String get_version() const; @@ -179,15 +189,14 @@ VARIANT_ENUM_CAST(VisualShader::Type) class VisualShaderNode : public Resource { GDCLASS(VisualShaderNode, Resource); - int port_preview; + int port_preview = -1; Map<int, Variant> default_input_values; Map<int, bool> connected_input_ports; - Map<int, bool> connected_output_ports; - int connected_output_count = 0; + Map<int, int> connected_output_ports; protected: - bool simple_decl; + bool simple_decl = true; static void _bind_methods(); public: @@ -232,6 +241,8 @@ public: virtual bool is_generate_input_var(int p_port) const; virtual bool is_code_generated() const; + virtual bool is_show_prop_names() const; + virtual bool is_use_prop_slots() const; virtual Vector<StringName> get_editable_properties() const; @@ -289,8 +300,8 @@ class VisualShaderNodeInput : public VisualShaderNode { GDCLASS(VisualShaderNodeInput, VisualShaderNode); friend class VisualShader; - VisualShader::Type shader_type; - Shader::Mode shader_mode; + VisualShader::Type shader_type = VisualShader::TYPE_MAX; + Shader::Mode shader_mode = Shader::MODE_MAX; struct Port { Shader::Mode mode; @@ -303,7 +314,7 @@ class VisualShaderNodeInput : public VisualShaderNode { static const Port ports[]; static const Port preview_ports[]; - String input_name; + String input_name = "[None]"; protected: static void _bind_methods(); @@ -387,8 +398,8 @@ public: }; private: - String uniform_name; - Qualifier qualifier; + String uniform_name = ""; + Qualifier qualifier = QUAL_NONE; bool global_code_generated = false; protected: @@ -435,8 +446,8 @@ public: }; private: - String uniform_name; - UniformType uniform_type; + String uniform_name = "[None]"; + UniformType uniform_type = UniformType::UNIFORM_TYPE_FLOAT; protected: static void _bind_methods(); @@ -444,6 +455,7 @@ protected: public: static void add_uniform(const String &p_name, UniformType p_type); static void clear_uniforms(); + static bool has_uniform(const String &p_name); public: virtual String get_caption() const override; @@ -459,6 +471,9 @@ public: void set_uniform_name(const String &p_name); String get_uniform_name() const; + void _set_uniform_type(int p_uniform_type); + int _get_uniform_type() const; + int get_uniforms_count() const; String get_uniform_name_by_index(int p_idx) const; UniformType get_uniform_type_by_name(const String &p_name) const; @@ -471,17 +486,36 @@ public: VisualShaderNodeUniformRef(); }; -class VisualShaderNodeGroupBase : public VisualShaderNode { - GDCLASS(VisualShaderNodeGroupBase, VisualShaderNode); +class VisualShaderNodeResizableBase : public VisualShaderNode { + GDCLASS(VisualShaderNodeResizableBase, VisualShaderNode); + +protected: + Vector2 size = Size2(0, 0); + bool allow_v_resize = true; + +protected: + static void _bind_methods(); + +public: + void set_size(const Vector2 &p_size); + Vector2 get_size() const; + + bool is_allow_v_resize() const; + void set_allow_v_resize(bool p_enabled); + + VisualShaderNodeResizableBase(); +}; + +class VisualShaderNodeGroupBase : public VisualShaderNodeResizableBase { + GDCLASS(VisualShaderNodeGroupBase, VisualShaderNodeResizableBase); private: void _apply_port_changes(); protected: - Vector2 size; - String inputs; - String outputs; - bool editable; + String inputs = ""; + String outputs = ""; + bool editable = false; struct Port { PortType type; @@ -496,11 +530,6 @@ protected: static void _bind_methods(); public: - virtual String get_caption() const override; - - void set_size(const Vector2 &p_size); - Vector2 get_size() const; - void set_inputs(const String &p_inputs); String get_inputs() const; @@ -549,7 +578,7 @@ class VisualShaderNodeExpression : public VisualShaderNodeGroupBase { GDCLASS(VisualShaderNodeExpression, VisualShaderNodeGroupBase); protected: - String expression; + String expression = ""; static void _bind_methods(); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index b0c871bc71..704d1b2ea8 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -87,7 +87,6 @@ void VisualShaderNodeFloatConstant::_bind_methods() { } VisualShaderNodeFloatConstant::VisualShaderNodeFloatConstant() { - constant = 0.0; } ////////////// Scalar(Int) @@ -147,7 +146,6 @@ void VisualShaderNodeIntConstant::_bind_methods() { } VisualShaderNodeIntConstant::VisualShaderNodeIntConstant() { - constant = 0; } ////////////// Boolean @@ -207,7 +205,6 @@ void VisualShaderNodeBooleanConstant::_bind_methods() { } VisualShaderNodeBooleanConstant::VisualShaderNodeBooleanConstant() { - constant = false; } ////////////// Color @@ -271,7 +268,6 @@ void VisualShaderNodeColorConstant::_bind_methods() { } VisualShaderNodeColorConstant::VisualShaderNodeColorConstant() { - constant = Color(1, 1, 1, 1); } ////////////// Vector @@ -456,7 +452,7 @@ String VisualShaderNodeTexture::get_output_port_name(int p_port) const { String VisualShaderNodeTexture::get_input_port_default_hint(int p_port) const { if (p_port == 0) { - return "UV.xy"; + return "default"; } return ""; } @@ -495,15 +491,22 @@ String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShade } String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String default_uv; + if (p_mode != Shader::MODE_PARTICLES && p_mode != Shader::MODE_SKY) { + default_uv = "UV.xy"; + } else { + default_uv = "vec2(0.0)"; + } + if (source == SOURCE_TEXTURE) { String id = make_unique_id(p_type, p_id, "tex"); String code; if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\tvec4 " + id + "_read = texture(" + id + ", UV.xy);\n"; + code += "\tvec4 " + id + "_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\tvec4 " + id + "_read = textureLod(" + id + ", UV.xy, " + p_input_vars[1] + ");\n"; + code += "\tvec4 " + id + "_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { @@ -529,9 +532,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 " + id + "_tex_read = texture(" + id + ", UV.xy);\n"; + code += "\t\tvec4 " + id + "_tex_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\t\tvec4 " + id + "_tex_read = textureLod(" + id + ", UV.xy, " + p_input_vars[1] + ");\n"; + code += "\t\tvec4 " + id + "_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { @@ -553,9 +556,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (p_input_vars[0] == String() || p_for_preview) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 _tex_read = textureLod(SCREEN_TEXTURE, UV.xy, 0.0 );\n"; + code += "\t\tvec4 _tex_read = textureLod(SCREEN_TEXTURE, " + default_uv + ", 0.0 );\n"; } else { - code += "\t\tvec4 _tex_read = textureLod(SCREEN_TEXTURE, UV.xy, " + p_input_vars[1] + ");\n"; + code += "\t\tvec4 _tex_read = textureLod(SCREEN_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { @@ -576,9 +579,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 _tex_read = texture(TEXTURE , UV.xy);\n"; + code += "\t\tvec4 _tex_read = texture(TEXTURE, " + default_uv + ");\n"; } else { - code += "\t\tvec4 _tex_read = textureLod(TEXTURE, UV.xy, " + p_input_vars[1] + ");\n"; + code += "\t\tvec4 _tex_read = textureLod(TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { @@ -599,9 +602,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 _tex_read = texture(NORMAL_TEXTURE, UV.xy);\n"; + code += "\t\tvec4 _tex_read = texture(NORMAL_TEXTURE, " + default_uv + ");\n"; } else { - code += "\t\tvec4 _tex_read = textureLod(NORMAL_TEXTURE, UV.xy, " + p_input_vars[1] + ");\n"; + code += "\t\tvec4 _tex_read = textureLod(NORMAL_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { @@ -632,9 +635,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tfloat _depth = texture(DEPTH_TEXTURE, UV.xy).r;\n"; + code += "\t\tfloat _depth = texture(DEPTH_TEXTURE, " + default_uv + ").r;\n"; } else { - code += "\t\tfloat _depth = textureLod(DEPTH_TEXTURE, UV.xy, " + p_input_vars[1] + ").r;\n"; + code += "\t\tfloat _depth = textureLod(DEPTH_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ").r;\n"; } } else if (p_input_vars[1] == String()) { @@ -777,8 +780,90 @@ void VisualShaderNodeTexture::_bind_methods() { } VisualShaderNodeTexture::VisualShaderNodeTexture() { - texture_type = TYPE_DATA; - source = SOURCE_TEXTURE; +} + +////////////// Curve + +String VisualShaderNodeCurveTexture::get_caption() const { + return "CurveTexture"; +} + +int VisualShaderNodeCurveTexture::get_input_port_count() const { + return 1; +} + +VisualShaderNodeCurveTexture::PortType VisualShaderNodeCurveTexture::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeCurveTexture::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeCurveTexture::get_output_port_count() const { + return 1; +} + +VisualShaderNodeCurveTexture::PortType VisualShaderNodeCurveTexture::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeCurveTexture::get_output_port_name(int p_port) const { + return String(); +} + +void VisualShaderNodeCurveTexture::set_texture(Ref<CurveTexture> p_texture) { + texture = p_texture; + emit_changed(); +} + +Ref<CurveTexture> VisualShaderNodeCurveTexture::get_texture() const { + return texture; +} + +Vector<StringName> VisualShaderNodeCurveTexture::get_editable_properties() const { + Vector<StringName> props; + props.push_back("texture"); + return props; +} + +String VisualShaderNodeCurveTexture::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return "uniform sampler2D " + make_unique_id(p_type, p_id, "curve") + ";\n"; +} + +String VisualShaderNodeCurveTexture::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + if (p_input_vars[0] == String()) { + return "\t" + p_output_vars[0] + " = 0.0;\n"; + } + String id = make_unique_id(p_type, p_id, "curve"); + String code; + code += "\t" + p_output_vars[0] + " = texture(" + id + ", vec2(" + p_input_vars[0] + ", 0.0)).r;\n"; + return code; +} + +Vector<VisualShader::DefaultTextureParam> VisualShaderNodeCurveTexture::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "curve"); + dtp.param = texture; + Vector<VisualShader::DefaultTextureParam> ret; + ret.push_back(dtp); + return ret; +} + +void VisualShaderNodeCurveTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_texture", "texture"), &VisualShaderNodeCurveTexture::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &VisualShaderNodeCurveTexture::get_texture); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_texture", "get_texture"); +} + +bool VisualShaderNodeCurveTexture::is_use_prop_slots() const { + return true; +} + +VisualShaderNodeCurveTexture::VisualShaderNodeCurveTexture() { + simple_decl = true; + allow_v_resize = false; } ////////////// Sample3D @@ -825,12 +910,19 @@ String VisualShaderNodeSample3D::get_output_port_name(int p_port) const { String VisualShaderNodeSample3D::get_input_port_default_hint(int p_port) const { if (p_port == 0) { - return "vec3(UV.xy, 0.0)"; + return "default"; } return ""; } String VisualShaderNodeSample3D::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String default_uv; + if (p_mode != Shader::MODE_PARTICLES && p_mode != Shader::MODE_SKY) { + default_uv = "vec3(UV, 0.0)"; + } else { + default_uv = "vec3(0.0)"; + } + String code; if (source == SOURCE_TEXTURE || source == SOURCE_PORT) { String id; @@ -843,9 +935,9 @@ String VisualShaderNodeSample3D::generate_code(Shader::Mode p_mode, VisualShader if (id != String()) { if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 " + id + "_tex_read = texture(" + id + ", vec3(UV.xy, 0.0));\n"; + code += "\t\tvec4 " + id + "_tex_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\t\tvec4 " + id + "_tex_read = textureLod(" + id + ", vec3(UV.xy, 0.0), " + p_input_vars[1] + ");\n"; + code += "\t\tvec4 " + id + "_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { //no lod @@ -898,7 +990,6 @@ String VisualShaderNodeSample3D::get_warning(Shader::Mode p_mode, VisualShader:: } VisualShaderNodeSample3D::VisualShaderNodeSample3D() { - source = SOURCE_TEXTURE; simple_decl = false; } @@ -958,6 +1049,64 @@ void VisualShaderNodeTexture2DArray::_bind_methods() { VisualShaderNodeTexture2DArray::VisualShaderNodeTexture2DArray() { } + +////////////// Texture3D + +String VisualShaderNodeTexture3D::get_caption() const { + return "Texture3D"; +} + +String VisualShaderNodeTexture3D::get_input_port_name(int p_port) const { + if (p_port == 2) { + return "sampler3D"; + } + return VisualShaderNodeSample3D::get_input_port_name(p_port); +} + +Vector<VisualShader::DefaultTextureParam> VisualShaderNodeTexture3D::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "tex3d"); + dtp.param = texture; + Vector<VisualShader::DefaultTextureParam> ret; + ret.push_back(dtp); + return ret; +} + +String VisualShaderNodeTexture3D::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + if (source == SOURCE_TEXTURE) { + return "uniform sampler3D " + make_unique_id(p_type, p_id, "tex3d") + ";\n"; + } + return String(); +} + +void VisualShaderNodeTexture3D::set_texture(Ref<Texture3D> p_value) { + texture = p_value; + emit_changed(); +} + +Ref<Texture3D> VisualShaderNodeTexture3D::get_texture() const { + return texture; +} + +Vector<StringName> VisualShaderNodeTexture3D::get_editable_properties() const { + Vector<StringName> props; + props.push_back("source"); + if (source == SOURCE_TEXTURE) { + props.push_back("texture"); + } + return props; +} + +void VisualShaderNodeTexture3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_texture", "value"), &VisualShaderNodeTexture3D::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &VisualShaderNodeTexture3D::get_texture); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture"); +} + +VisualShaderNodeTexture3D::VisualShaderNodeTexture3D() { +} + ////////////// Cubemap String VisualShaderNodeCubemap::get_caption() const { @@ -1034,6 +1183,13 @@ String VisualShaderNodeCubemap::generate_global(Shader::Mode p_mode, VisualShade } String VisualShaderNodeCubemap::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String default_uv; + if (p_mode != Shader::MODE_PARTICLES && p_mode != Shader::MODE_SKY) { + default_uv = "vec3(UV, 0.0)"; + } else { + default_uv = "vec3(0.0)"; + } + String code; String id; if (source == SOURCE_TEXTURE) { @@ -1057,9 +1213,9 @@ String VisualShaderNodeCubemap::generate_code(Shader::Mode p_mode, VisualShader: if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 " + id + "_read = texture(" + id + " , vec3(UV, 0.0));\n"; + code += "\t\tvec4 " + id + "_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\t\tvec4 " + id + "_read = textureLod(" + id + " , vec3(UV, 0.0)" + " , " + p_input_vars[1] + " );\n"; + code += "\t\tvec4 " + id + "_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + " );\n"; } } else if (p_input_vars[1] == String()) { @@ -1077,7 +1233,7 @@ String VisualShaderNodeCubemap::generate_code(Shader::Mode p_mode, VisualShader: String VisualShaderNodeCubemap::get_input_port_default_hint(int p_port) const { if (p_port == 0) { - return "vec3(UV, 0.0)"; + return "default"; } return ""; } @@ -1143,8 +1299,6 @@ void VisualShaderNodeCubemap::_bind_methods() { } VisualShaderNodeCubemap::VisualShaderNodeCubemap() { - texture_type = TYPE_DATA; - source = SOURCE_TEXTURE; simple_decl = false; } @@ -1250,7 +1404,6 @@ void VisualShaderNodeFloatOp::_bind_methods() { } VisualShaderNodeFloatOp::VisualShaderNodeFloatOp() { - op = OP_ADD; set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 0.0); } @@ -1345,7 +1498,6 @@ void VisualShaderNodeIntOp::_bind_methods() { } VisualShaderNodeIntOp::VisualShaderNodeIntOp() { - op = OP_ADD; set_input_port_default_value(0, 0); set_input_port_default_value(1, 0); } @@ -1460,7 +1612,6 @@ void VisualShaderNodeVectorOp::_bind_methods() { } VisualShaderNodeVectorOp::VisualShaderNodeVectorOp() { - op = OP_ADD; set_input_port_default_value(0, Vector3()); set_input_port_default_value(1, Vector3()); } @@ -1628,7 +1779,6 @@ void VisualShaderNodeColorOp::_bind_methods() { } VisualShaderNodeColorOp::VisualShaderNodeColorOp() { - op = OP_SCREEN; set_input_port_default_value(0, Vector3()); set_input_port_default_value(1, Vector3()); } @@ -1703,7 +1853,6 @@ void VisualShaderNodeTransformMult::_bind_methods() { } VisualShaderNodeTransformMult::VisualShaderNodeTransformMult() { - op = OP_AxB; set_input_port_default_value(0, Transform()); set_input_port_default_value(1, Transform()); } @@ -1778,7 +1927,6 @@ void VisualShaderNodeTransformVecMult::_bind_methods() { } VisualShaderNodeTransformVecMult::VisualShaderNodeTransformVecMult() { - op = OP_AxB; set_input_port_default_value(0, Transform()); set_input_port_default_value(1, Vector3()); } @@ -1908,7 +2056,6 @@ void VisualShaderNodeFloatFunc::_bind_methods() { } VisualShaderNodeFloatFunc::VisualShaderNodeFloatFunc() { - func = FUNC_SIGN; set_input_port_default_value(0, 0.0); } @@ -2003,7 +2150,6 @@ void VisualShaderNodeIntFunc::_bind_methods() { } VisualShaderNodeIntFunc::VisualShaderNodeIntFunc() { - func = FUNC_SIGN; set_input_port_default_value(0, 0); } @@ -2169,7 +2315,6 @@ void VisualShaderNodeVectorFunc::_bind_methods() { } VisualShaderNodeVectorFunc::VisualShaderNodeVectorFunc() { - func = FUNC_NORMALIZE; set_input_port_default_value(0, Vector3()); } @@ -2256,9 +2401,8 @@ void VisualShaderNodeColorFunc::_bind_methods() { } VisualShaderNodeColorFunc::VisualShaderNodeColorFunc() { - func = FUNC_GRAYSCALE; - set_input_port_default_value(0, Vector3()); simple_decl = false; + set_input_port_default_value(0, Vector3()); } ////////////// Transform Func @@ -2328,7 +2472,6 @@ void VisualShaderNodeTransformFunc::_bind_methods() { } VisualShaderNodeTransformFunc::VisualShaderNodeTransformFunc() { - func = FUNC_INVERSE; set_input_port_default_value(0, Transform()); } @@ -2516,7 +2659,6 @@ void VisualShaderNodeScalarDerivativeFunc::_bind_methods() { } VisualShaderNodeScalarDerivativeFunc::VisualShaderNodeScalarDerivativeFunc() { - func = FUNC_SUM; set_input_port_default_value(0, 0.0); } @@ -2589,7 +2731,6 @@ void VisualShaderNodeVectorDerivativeFunc::_bind_methods() { } VisualShaderNodeVectorDerivativeFunc::VisualShaderNodeVectorDerivativeFunc() { - func = FUNC_SUM; set_input_port_default_value(0, Vector3()); } @@ -3454,6 +3595,14 @@ String VisualShaderNodeFloatUniform::generate_code(Shader::Mode p_mode, VisualSh return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } +bool VisualShaderNodeFloatUniform::is_show_prop_names() const { + return true; +} + +bool VisualShaderNodeFloatUniform::is_use_prop_slots() const { + return true; +} + void VisualShaderNodeFloatUniform::set_hint(Hint p_hint) { hint = p_hint; emit_changed(); @@ -3561,12 +3710,6 @@ Vector<StringName> VisualShaderNodeFloatUniform::get_editable_properties() const } VisualShaderNodeFloatUniform::VisualShaderNodeFloatUniform() { - hint = HINT_NONE; - hint_range_min = 0.0; - hint_range_max = 1.0; - hint_range_step = 0.1; - default_value_enabled = false; - default_value = 0.0; } ////////////// Integer Uniform @@ -3619,6 +3762,14 @@ String VisualShaderNodeIntUniform::generate_code(Shader::Mode p_mode, VisualShad return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } +bool VisualShaderNodeIntUniform::is_show_prop_names() const { + return true; +} + +bool VisualShaderNodeIntUniform::is_use_prop_slots() const { + return true; +} + void VisualShaderNodeIntUniform::set_hint(Hint p_hint) { hint = p_hint; emit_changed(); @@ -3726,12 +3877,6 @@ Vector<StringName> VisualShaderNodeIntUniform::get_editable_properties() const { } VisualShaderNodeIntUniform::VisualShaderNodeIntUniform() { - hint = HINT_NONE; - hint_range_min = 0; - hint_range_max = 100; - hint_range_step = 1; - default_value_enabled = false; - default_value = 0; } ////////////// Boolean Uniform @@ -3799,6 +3944,14 @@ String VisualShaderNodeBooleanUniform::generate_code(Shader::Mode p_mode, Visual return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } +bool VisualShaderNodeBooleanUniform::is_show_prop_names() const { + return true; +} + +bool VisualShaderNodeBooleanUniform::is_use_prop_slots() const { + return true; +} + void VisualShaderNodeBooleanUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeBooleanUniform::set_default_value_enabled); ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeBooleanUniform::is_default_value_enabled); @@ -3824,8 +3977,6 @@ Vector<StringName> VisualShaderNodeBooleanUniform::get_editable_properties() con } VisualShaderNodeBooleanUniform::VisualShaderNodeBooleanUniform() { - default_value_enabled = false; - default_value = false; } ////////////// Color Uniform @@ -3891,6 +4042,10 @@ String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualSh return code; } +bool VisualShaderNodeColorUniform::is_show_prop_names() const { + return true; +} + void VisualShaderNodeColorUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeColorUniform::set_default_value_enabled); ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeColorUniform::is_default_value_enabled); @@ -3916,8 +4071,6 @@ Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const } VisualShaderNodeColorUniform::VisualShaderNodeColorUniform() { - default_value_enabled = false; - default_value = Color(1.0, 1.0, 1.0, 1.0); } ////////////// Vector Uniform @@ -3992,6 +4145,14 @@ void VisualShaderNodeVec3Uniform::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "default_value"), "set_default_value", "get_default_value"); } +bool VisualShaderNodeVec3Uniform::is_show_prop_names() const { + return true; +} + +bool VisualShaderNodeVec3Uniform::is_use_prop_slots() const { + return true; +} + bool VisualShaderNodeVec3Uniform::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } @@ -4006,8 +4167,6 @@ Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const } VisualShaderNodeVec3Uniform::VisualShaderNodeVec3Uniform() { - default_value_enabled = false; - default_value = Vector3(0.0, 0.0, 0.0); } ////////////// Transform Uniform @@ -4086,6 +4245,14 @@ void VisualShaderNodeTransformUniform::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "default_value"), "set_default_value", "get_default_value"); } +bool VisualShaderNodeTransformUniform::is_show_prop_names() const { + return true; +} + +bool VisualShaderNodeTransformUniform::is_use_prop_slots() const { + return true; +} + bool VisualShaderNodeTransformUniform::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } @@ -4100,8 +4267,6 @@ Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() c } VisualShaderNodeTransformUniform::VisualShaderNodeTransformUniform() { - default_value_enabled = false; - default_value = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0); } ////////////// Texture Uniform @@ -4186,13 +4351,20 @@ bool VisualShaderNodeTextureUniform::is_code_generated() const { } String VisualShaderNodeTextureUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String default_uv; + if (p_mode != Shader::MODE_PARTICLES && p_mode != Shader::MODE_SKY) { + default_uv = "UV.xy"; + } else { + default_uv = "vec2(0.0)"; + } + String id = get_uniform_name(); String code = "\t{\n"; if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 n_tex_read = texture(" + id + ", UV.xy);\n"; + code += "\t\tvec4 n_tex_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\t\tvec4 n_tex_read = textureLod(" + id + ", UV.xy, " + p_input_vars[1] + ");\n"; + code += "\t\tvec4 n_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { //no lod @@ -4253,7 +4425,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() { String VisualShaderNodeTextureUniform::get_input_port_default_hint(int p_port) const { if (p_port == 0) { - return "UV.xy"; + return "default"; } return ""; } @@ -4271,8 +4443,6 @@ bool VisualShaderNodeTextureUniform::is_qualifier_supported(Qualifier p_qual) co } VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() { - texture_type = TYPE_DATA; - color_default = COLOR_DEFAULT_WHITE; simple_decl = false; } @@ -4345,13 +4515,13 @@ String VisualShaderNodeTextureUniformTriplanar::generate_code(Shader::Mode p_mod String code = "\t{\n"; if (p_input_vars[0] == String() && p_input_vars[1] == String()) { - code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", triplanar_power_normal, triplanar_pos );\n"; + code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", triplanar_power_normal, triplanar_pos);\n"; } else if (p_input_vars[0] != String() && p_input_vars[1] == String()) { - code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", " + p_input_vars[0] + ", triplanar_pos );\n"; + code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", " + p_input_vars[0] + ", triplanar_pos);\n"; } else if (p_input_vars[0] == String() && p_input_vars[1] != String()) { - code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", triplanar_power_normal," + p_input_vars[1] + " );\n"; + code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", triplanar_power_normal, " + p_input_vars[1] + ");\n"; } else { - code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + " );\n"; + code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } code += "\t\t" + p_output_vars[0] + " = n_tex_read.rgb;\n"; @@ -4441,6 +4611,74 @@ String VisualShaderNodeTexture2DArrayUniform::generate_code(Shader::Mode p_mode, VisualShaderNodeTexture2DArrayUniform::VisualShaderNodeTexture2DArrayUniform() { } +////////////// Texture3D Uniform + +String VisualShaderNodeTexture3DUniform::get_caption() const { + return "Texture3DUniform"; +} + +int VisualShaderNodeTexture3DUniform::get_output_port_count() const { + return 1; +} + +VisualShaderNodeTexture3DUniform::PortType VisualShaderNodeTexture3DUniform::get_output_port_type(int p_port) const { + return PORT_TYPE_SAMPLER; +} + +String VisualShaderNodeTexture3DUniform::get_output_port_name(int p_port) const { + return "sampler3D"; +} + +int VisualShaderNodeTexture3DUniform::get_input_port_count() const { + return 0; +} + +VisualShaderNodeTexture3DUniform::PortType VisualShaderNodeTexture3DUniform::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeTexture3DUniform::get_input_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeTexture3DUniform::get_input_port_default_hint(int p_port) const { + return ""; +} + +String VisualShaderNodeTexture3DUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform sampler3D " + get_uniform_name(); + + switch (texture_type) { + case TYPE_DATA: + if (color_default == COLOR_DEFAULT_BLACK) + code += " : hint_black;\n"; + else + code += ";\n"; + break; + case TYPE_COLOR: + if (color_default == COLOR_DEFAULT_BLACK) + code += " : hint_black_albedo;\n"; + else + code += " : hint_albedo;\n"; + break; + case TYPE_NORMALMAP: + code += " : hint_normal;\n"; + break; + case TYPE_ANISO: + code += " : hint_aniso;\n"; + break; + } + + return code; +} + +String VisualShaderNodeTexture3DUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + return String(); +} + +VisualShaderNodeTexture3DUniform::VisualShaderNodeTexture3DUniform() { +} + ////////////// Cubemap Uniform String VisualShaderNodeCubemapUniform::get_caption() const { @@ -4577,13 +4815,13 @@ String VisualShaderNodeIf::generate_code(Shader::Mode p_mode, VisualShader::Type } VisualShaderNodeIf::VisualShaderNodeIf() { + simple_decl = false; set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 0.0); set_input_port_default_value(2, CMP_EPSILON); set_input_port_default_value(3, Vector3(0.0, 0.0, 0.0)); set_input_port_default_value(4, Vector3(0.0, 0.0, 0.0)); set_input_port_default_value(5, Vector3(0.0, 0.0, 0.0)); - simple_decl = false; } ////////////// Switch @@ -4642,10 +4880,10 @@ String VisualShaderNodeSwitch::generate_code(Shader::Mode p_mode, VisualShader:: } VisualShaderNodeSwitch::VisualShaderNodeSwitch() { + simple_decl = false; set_input_port_default_value(0, false); set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); - simple_decl = false; } ////////////// Switch(scalar) @@ -4836,7 +5074,6 @@ void VisualShaderNodeIs::_bind_methods() { } VisualShaderNodeIs::VisualShaderNodeIs() { - func = FUNC_IS_INF; set_input_port_default_value(0, 0.0); } @@ -5072,9 +5309,6 @@ void VisualShaderNodeCompare::_bind_methods() { } VisualShaderNodeCompare::VisualShaderNodeCompare() { - ctype = CTYPE_SCALAR; - func = FUNC_EQUAL; - condition = COND_ALL; set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 0.0); set_input_port_default_value(2, CMP_EPSILON); @@ -5091,7 +5325,7 @@ int VisualShaderNodeMultiplyAdd::get_input_port_count() const { } VisualShaderNodeMultiplyAdd::PortType VisualShaderNodeMultiplyAdd::get_input_port_type(int p_port) const { - if (type == TYPE_SCALAR) { + if (op_type == OP_TYPE_SCALAR) { return PORT_TYPE_SCALAR; } return PORT_TYPE_VECTOR; @@ -5113,7 +5347,7 @@ int VisualShaderNodeMultiplyAdd::get_output_port_count() const { } VisualShaderNodeMultiplyAdd::PortType VisualShaderNodeMultiplyAdd::get_output_port_type(int p_port) const { - if (type == TYPE_SCALAR) { + if (op_type == OP_TYPE_SCALAR) { return PORT_TYPE_SCALAR; } else { return PORT_TYPE_VECTOR; @@ -5128,10 +5362,10 @@ String VisualShaderNodeMultiplyAdd::generate_code(Shader::Mode p_mode, VisualSha return "\t" + p_output_vars[0] + " = fma(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } -void VisualShaderNodeMultiplyAdd::set_type(Type p_type) { - ERR_FAIL_INDEX((int)p_type, TYPE_MAX); - if (p_type != type) { - if (p_type == TYPE_SCALAR) { +void VisualShaderNodeMultiplyAdd::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (p_op_type != op_type) { + if (p_op_type == OP_TYPE_SCALAR) { set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 0.0); set_input_port_default_value(2, 0.0); @@ -5141,33 +5375,32 @@ void VisualShaderNodeMultiplyAdd::set_type(Type p_type) { set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); } } - type = p_type; + op_type = p_op_type; emit_changed(); } -VisualShaderNodeMultiplyAdd::Type VisualShaderNodeMultiplyAdd::get_type() const { - return type; +VisualShaderNodeMultiplyAdd::OpType VisualShaderNodeMultiplyAdd::get_op_type() const { + return op_type; } Vector<StringName> VisualShaderNodeMultiplyAdd::get_editable_properties() const { Vector<StringName> props; - props.push_back("type"); + props.push_back("op_type"); return props; } void VisualShaderNodeMultiplyAdd::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_type", "type"), &VisualShaderNodeMultiplyAdd::set_type); - ClassDB::bind_method(D_METHOD("get_type"), &VisualShaderNodeMultiplyAdd::get_type); + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeMultiplyAdd::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeMultiplyAdd::get_op_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, "Scalar,Vector"), "set_type", "get_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector"), "set_op_type", "get_op_type"); - BIND_ENUM_CONSTANT(TYPE_SCALAR); - BIND_ENUM_CONSTANT(TYPE_VECTOR); - BIND_ENUM_CONSTANT(TYPE_MAX); + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); } VisualShaderNodeMultiplyAdd::VisualShaderNodeMultiplyAdd() { - type = TYPE_SCALAR; set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 0.0); set_input_port_default_value(2, 0.0); diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index b9c40d0521..d4d6540baf 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -39,7 +39,7 @@ class VisualShaderNodeFloatConstant : public VisualShaderNode { GDCLASS(VisualShaderNodeFloatConstant, VisualShaderNode); - float constant; + float constant = 0.0f; protected: static void _bind_methods(); @@ -69,7 +69,7 @@ public: class VisualShaderNodeIntConstant : public VisualShaderNode { GDCLASS(VisualShaderNodeIntConstant, VisualShaderNode); - int constant; + int constant = 0; protected: static void _bind_methods(); @@ -99,7 +99,7 @@ public: class VisualShaderNodeBooleanConstant : public VisualShaderNode { GDCLASS(VisualShaderNodeBooleanConstant, VisualShaderNode); - bool constant; + bool constant = false; protected: static void _bind_methods(); @@ -129,7 +129,7 @@ public: class VisualShaderNodeColorConstant : public VisualShaderNode { GDCLASS(VisualShaderNodeColorConstant, VisualShaderNode); - Color constant; + Color constant = Color(1, 1, 1, 1); protected: static void _bind_methods(); @@ -240,8 +240,8 @@ public: }; private: - Source source; - TextureType texture_type; + Source source = SOURCE_TEXTURE; + TextureType texture_type = TYPE_DATA; protected: static void _bind_methods(); @@ -284,6 +284,39 @@ VARIANT_ENUM_CAST(VisualShaderNodeTexture::Source) /////////////////////////////////////// +class VisualShaderNodeCurveTexture : public VisualShaderNodeResizableBase { + GDCLASS(VisualShaderNodeCurveTexture, VisualShaderNodeResizableBase); + Ref<CurveTexture> texture; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) 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; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + void set_texture(Ref<CurveTexture> p_value); + Ref<CurveTexture> get_texture() const; + + virtual Vector<StringName> get_editable_properties() const override; + virtual bool is_use_prop_slots() const override; + + VisualShaderNodeCurveTexture(); +}; + +/////////////////////////////////////// + class VisualShaderNodeSample3D : public VisualShaderNode { GDCLASS(VisualShaderNodeSample3D, VisualShaderNode); @@ -294,7 +327,7 @@ public: }; protected: - Source source; + Source source = SOURCE_TEXTURE; static void _bind_methods(); @@ -343,6 +376,29 @@ public: VisualShaderNodeTexture2DArray(); }; +class VisualShaderNodeTexture3D : public VisualShaderNodeSample3D { + GDCLASS(VisualShaderNodeTexture3D, VisualShaderNodeSample3D); + Ref<Texture3D> texture; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const override; + + virtual String get_input_port_name(int p_port) const override; + + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + + void set_texture(Ref<Texture3D> p_value); + Ref<Texture3D> get_texture() const; + + virtual Vector<StringName> get_editable_properties() const override; + + VisualShaderNodeTexture3D(); +}; + class VisualShaderNodeCubemap : public VisualShaderNode { GDCLASS(VisualShaderNodeCubemap, VisualShaderNode); Ref<Cubemap> cube_map; @@ -360,8 +416,8 @@ public: }; private: - Source source; - TextureType texture_type; + Source source = SOURCE_TEXTURE; + TextureType texture_type = TYPE_DATA; protected: static void _bind_methods(); @@ -421,7 +477,7 @@ public: }; protected: - Operator op; + Operator op = OP_ADD; static void _bind_methods(); @@ -463,7 +519,7 @@ public: }; protected: - Operator op; + Operator op = OP_ADD; static void _bind_methods(); @@ -510,7 +566,7 @@ public: }; protected: - Operator op; + Operator op = OP_ADD; static void _bind_methods(); @@ -556,7 +612,7 @@ public: }; protected: - Operator op; + Operator op = OP_SCREEN; static void _bind_methods(); @@ -599,7 +655,7 @@ public: }; protected: - Operator op; + Operator op = OP_AxB; static void _bind_methods(); @@ -642,7 +698,7 @@ public: }; protected: - Operator op; + Operator op = OP_AxB; static void _bind_methods(); @@ -713,7 +769,7 @@ public: }; protected: - Function func; + Function func = FUNC_SIGN; static void _bind_methods(); @@ -756,7 +812,7 @@ public: }; protected: - Function func; + Function func = FUNC_SIGN; static void _bind_methods(); @@ -830,7 +886,7 @@ public: }; protected: - Function func; + Function func = FUNC_NORMALIZE; static void _bind_methods(); @@ -871,7 +927,7 @@ public: }; protected: - Function func; + Function func = FUNC_GRAYSCALE; static void _bind_methods(); @@ -912,7 +968,7 @@ public: }; protected: - Function func; + Function func = FUNC_INVERSE; static void _bind_methods(); @@ -1067,7 +1123,7 @@ public: }; protected: - Function func; + Function func = FUNC_SUM; static void _bind_methods(); @@ -1107,7 +1163,7 @@ public: }; protected: - Function func; + Function func = FUNC_SUM; static void _bind_methods(); @@ -1482,12 +1538,12 @@ public: }; private: - Hint hint; - float hint_range_min; - float hint_range_max; - float hint_range_step; - bool default_value_enabled; - float default_value; + Hint hint = HINT_NONE; + float hint_range_min = 0.0f; + float hint_range_max = 1.0f; + float hint_range_step = 0.1f; + bool default_value_enabled = false; + float default_value = 0.0f; protected: static void _bind_methods(); @@ -1506,6 +1562,9 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + virtual bool is_show_prop_names() const override; + virtual bool is_use_prop_slots() const override; + void set_hint(Hint p_hint); Hint get_hint() const; @@ -1544,12 +1603,12 @@ public: }; private: - Hint hint; - int hint_range_min; - int hint_range_max; - int hint_range_step; - bool default_value_enabled; - int default_value; + Hint hint = HINT_NONE; + int hint_range_min = 0; + int hint_range_max = 100; + int hint_range_step = 1; + bool default_value_enabled = false; + int default_value = 0; protected: static void _bind_methods(); @@ -1568,6 +1627,9 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + virtual bool is_show_prop_names() const override; + virtual bool is_use_prop_slots() const override; + void set_hint(Hint p_hint); Hint get_hint() const; @@ -1601,8 +1663,8 @@ class VisualShaderNodeBooleanUniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeBooleanUniform, VisualShaderNodeUniform); private: - bool default_value_enabled; - bool default_value; + bool default_value_enabled = false; + bool default_value = false; protected: static void _bind_methods(); @@ -1621,6 +1683,9 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + virtual bool is_show_prop_names() const override; + virtual bool is_use_prop_slots() const override; + void set_default_value_enabled(bool p_enabled); bool is_default_value_enabled() const; @@ -1640,8 +1705,8 @@ class VisualShaderNodeColorUniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeColorUniform, VisualShaderNodeUniform); private: - bool default_value_enabled; - Color default_value; + bool default_value_enabled = false; + Color default_value = Color(1.0, 1.0, 1.0, 1.0); protected: static void _bind_methods(); @@ -1660,6 +1725,8 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + virtual bool is_show_prop_names() const override; + void set_default_value_enabled(bool p_enabled); bool is_default_value_enabled() const; @@ -1679,7 +1746,7 @@ class VisualShaderNodeVec3Uniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform); private: - bool default_value_enabled; + bool default_value_enabled = false; Vector3 default_value; protected: @@ -1699,6 +1766,9 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + virtual bool is_show_prop_names() const override; + virtual bool is_use_prop_slots() const override; + void set_default_value_enabled(bool p_enabled); bool is_default_value_enabled() const; @@ -1718,8 +1788,8 @@ class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform); private: - bool default_value_enabled; - Transform default_value; + bool default_value_enabled = false; + Transform default_value = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0); protected: static void _bind_methods(); @@ -1738,6 +1808,9 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + virtual bool is_show_prop_names() const override; + virtual bool is_use_prop_slots() const override; + void set_default_value_enabled(bool p_enabled); bool is_default_value_enabled() const; @@ -1770,8 +1843,8 @@ public: }; protected: - TextureType texture_type; - ColorDefault color_default; + TextureType texture_type = TYPE_DATA; + ColorDefault color_default = COLOR_DEFAULT_WHITE; protected: static void _bind_methods(); @@ -1855,6 +1928,29 @@ public: /////////////////////////////////////// +class VisualShaderNodeTexture3DUniform : public VisualShaderNodeTextureUniform { + GDCLASS(VisualShaderNodeTexture3DUniform, VisualShaderNodeTextureUniform); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String get_input_port_default_hint(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; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeTexture3DUniform(); +}; + +/////////////////////////////////////// + class VisualShaderNodeCubemapUniform : public VisualShaderNodeTextureUniform { GDCLASS(VisualShaderNodeCubemapUniform, VisualShaderNodeTextureUniform); @@ -1973,7 +2069,7 @@ public: }; protected: - Function func; + Function func = FUNC_IS_INF; protected: static void _bind_methods(); @@ -2032,9 +2128,9 @@ public: }; protected: - ComparisonType ctype; - Function func; - Condition condition; + ComparisonType ctype = CTYPE_SCALAR; + Function func = FUNC_EQUAL; + Condition condition = COND_ALL; protected: static void _bind_methods(); @@ -2075,14 +2171,14 @@ class VisualShaderNodeMultiplyAdd : public VisualShaderNode { GDCLASS(VisualShaderNodeMultiplyAdd, VisualShaderNode); public: - enum Type { - TYPE_SCALAR, - TYPE_VECTOR, - TYPE_MAX, + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR, + OP_TYPE_MAX, }; protected: - Type type; + OpType op_type = OP_TYPE_SCALAR; protected: static void _bind_methods(); @@ -2100,14 +2196,14 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty - void set_type(Type p_type); - Type get_type() const; + void set_op_type(OpType p_type); + OpType get_op_type() const; virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeMultiplyAdd(); }; -VARIANT_ENUM_CAST(VisualShaderNodeMultiplyAdd::Type) +VARIANT_ENUM_CAST(VisualShaderNodeMultiplyAdd::OpType) #endif // VISUAL_SHADER_NODES_H diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index d2bc2bea31..41d3fe20be 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -30,7 +30,7 @@ #include "world_2d.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" #include "scene/2d/camera_2d.h" #include "scene/2d/visibility_notifier_2d.h" #include "scene/main/window.h" @@ -341,8 +341,8 @@ void World2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World2D::get_direct_space_state); - ADD_PROPERTY(PropertyInfo(Variant::_RID, "canvas", PROPERTY_HINT_NONE, "", 0), "", "get_canvas"); - ADD_PROPERTY(PropertyInfo(Variant::_RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "canvas", PROPERTY_HINT_NONE, "", 0), "", "get_canvas"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState2D", 0), "", "get_direct_space_state"); } diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h index c330719104..11614f9aa4 100644 --- a/scene/resources/world_2d.h +++ b/scene/resources/world_2d.h @@ -31,8 +31,8 @@ #ifndef WORLD_2D_H #define WORLD_2D_H -#include "core/project_settings.h" -#include "core/resource.h" +#include "core/config/project_settings.h" +#include "core/io/resource.h" #include "servers/physics_server_2d.h" class VisibilityNotifier2D; diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp index 8100f150ef..b8fb3825ce 100644 --- a/scene/resources/world_3d.cpp +++ b/scene/resources/world_3d.cpp @@ -321,8 +321,8 @@ void World3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_fallback_environment", "get_fallback_environment"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_camera_effects", "get_camera_effects"); - ADD_PROPERTY(PropertyInfo(Variant::_RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space"); - ADD_PROPERTY(PropertyInfo(Variant::_RID, "scenario", PROPERTY_HINT_NONE, "", 0), "", "get_scenario"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "scenario", PROPERTY_HINT_NONE, "", 0), "", "get_scenario"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState3D", 0), "", "get_direct_space_state"); } diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h index 02a821637f..93e9c72e59 100644 --- a/scene/resources/world_3d.h +++ b/scene/resources/world_3d.h @@ -31,7 +31,7 @@ #ifndef WORLD_3D_H #define WORLD_3D_H -#include "core/resource.h" +#include "core/io/resource.h" #include "scene/resources/camera_effects.h" #include "scene/resources/environment.h" #include "servers/physics_server_3d.h" diff --git a/scene/resources/world_margin_shape_3d.cpp b/scene/resources/world_margin_shape_3d.cpp index d613413b33..0936fcc657 100644 --- a/scene/resources/world_margin_shape_3d.cpp +++ b/scene/resources/world_margin_shape_3d.cpp @@ -32,7 +32,7 @@ #include "servers/physics_server_3d.h" -Vector<Vector3> WorldMarginShape3D::get_debug_mesh_lines() { +Vector<Vector3> WorldMarginShape3D::get_debug_mesh_lines() const { Plane p = get_plane(); Vector<Vector3> points; diff --git a/scene/resources/world_margin_shape_3d.h b/scene/resources/world_margin_shape_3d.h index c920dc513c..8099592d80 100644 --- a/scene/resources/world_margin_shape_3d.h +++ b/scene/resources/world_margin_shape_3d.h @@ -45,7 +45,7 @@ public: void set_plane(Plane p_plane); Plane get_plane() const; - virtual Vector<Vector3> get_debug_mesh_lines() override; + virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override { // Should be infinite? return 0; diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 1ae244492e..b1168c84b9 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -31,8 +31,8 @@ #ifndef SCENE_STRING_NAMES_H #define SCENE_STRING_NAMES_H -#include "core/node_path.h" -#include "core/string_name.h" +#include "core/string/node_path.h" +#include "core/string/string_name.h" class SceneStringNames { friend void register_scene_types(); |